1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Converts CIR directly to LLVM IR, similar to mlir-translate or LLVM llc.
10//
11//===----------------------------------------------------------------------===//
12
13#include "mlir/Dialect/DLTI/DLTI.h"
14#include "mlir/Dialect/Func/IR/FuncOps.h"
15#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
16#include "mlir/IR/BuiltinOps.h"
17#include "mlir/IR/MLIRContext.h"
18#include "mlir/InitAllTranslations.h"
19#include "mlir/Support/LogicalResult.h"
20#include "mlir/Target/LLVMIR/Dialect/All.h"
21#include "mlir/Target/LLVMIR/Import.h"
22#include "mlir/Tools/mlir-translate/MlirTranslateMain.h"
23#include "mlir/Tools/mlir-translate/Translation.h"
24
25#include "llvm/IR/Module.h"
26#include "llvm/TargetParser/Host.h"
27
28#include "clang/Basic/TargetInfo.h"
29#include "clang/CIR/Dialect/IR/CIRDialect.h"
30#include "clang/CIR/Dialect/Passes.h"
31#include "clang/CIR/LowerToLLVM.h"
32#include "clang/CIR/MissingFeatures.h"
33
34namespace cir {
35namespace direct {
36extern void registerCIRDialectTranslation(mlir::DialectRegistry &registry);
37} // namespace direct
38
39namespace {
40
41/// The goal of this option is to ensure that the triple and data layout specs
42/// are always available in the ClangIR module. With this requirement met, the
43/// behavior of this option is designed to be as intuitive as possible, as shown
44/// in the table below:
45///
46/// +--------+--------+-------------+-----------------+-----------------------+
47/// | Option | Triple | Data Layout | Behavior Triple | Behavior Data Layout |
48/// +========+========+=============+=================+=======================+
49/// | T | T | T | Overwrite | Derive from triple |
50/// | T | T | F | Overwrite | Derive from triple |
51/// | T | F | T | Overwrite | Derive from triple |
52/// | T | F | F | Overwrite | Derive from triple |
53/// | F | T | T | | |
54/// | F | T | F | | Derive from triple |
55/// | F | F | T | Set default | Derive from triple |
56/// | F | F | F | Set default | Derive from triple |
57/// +--------+--------+-------------+-----------------+-----------------------+
58llvm::cl::opt<std::string>
59 targetTripleOption("target",
60 llvm::cl::desc("Specify a default target triple when "
61 "it's not available in the module"),
62 llvm::cl::init(""));
63
64std::string prepareCIRModuleTriple(mlir::ModuleOp mod) {
65 std::string triple = targetTripleOption;
66
67 // Treat "" as the default target machine.
68 if (triple.empty()) {
69 triple = llvm::sys::getDefaultTargetTriple();
70
71 mod.emitWarning() << "no target triple provided, assuming " << triple;
72 }
73
74 mod->setAttr(cir::CIRDialect::getTripleAttrName(),
75 mlir::StringAttr::get(mod.getContext(), triple));
76 return triple;
77}
78
79llvm::LogicalResult prepareCIRModuleDataLayout(mlir::ModuleOp mod,
80 llvm::StringRef rawTriple) {
81 auto *context = mod.getContext();
82
83 // Data layout is fully determined by the target triple. Here we only pass the
84 // triple to get the data layout.
85 llvm::Triple triple(rawTriple);
86 clang::TargetOptions targetOptions;
87 targetOptions.Triple = rawTriple;
88 // FIXME: AllocateTarget is a big deal. Better make it a global state.
89 std::unique_ptr<clang::TargetInfo> targetInfo =
90 clang::targets::AllocateTarget(Triple: llvm::Triple(rawTriple), Opts: targetOptions);
91 if (!targetInfo) {
92 mod.emitError() << "error: invalid target triple '" << rawTriple << "'\n";
93 return llvm::failure();
94 }
95 std::string layoutString = targetInfo->getDataLayoutString();
96
97 // Registered dialects may not be loaded yet, ensure they are.
98 context->loadDialect<mlir::DLTIDialect, mlir::LLVM::LLVMDialect>();
99
100 mlir::DataLayoutSpecInterface dlSpec =
101 mlir::translateDataLayout(llvm::DataLayout(layoutString), context);
102 mod->setAttr(mlir::DLTIDialect::kDataLayoutAttrName, dlSpec);
103
104 return llvm::success();
105}
106
107/// Prepare requirements like cir.triple and data layout.
108llvm::LogicalResult prepareCIRModuleForTranslation(mlir::ModuleOp mod) {
109 auto modTriple = mod->getAttrOfType<mlir::StringAttr>(
110 cir::CIRDialect::getTripleAttrName());
111 auto modDataLayout = mod->getAttr(mlir::DLTIDialect::kDataLayoutAttrName);
112 bool hasTargetOption = targetTripleOption.getNumOccurrences() > 0;
113
114 // Skip the situation where nothing should be done.
115 if (!hasTargetOption && modTriple && modDataLayout)
116 return llvm::success();
117
118 std::string triple;
119
120 if (!hasTargetOption && modTriple) {
121 // Do nothing if it's already set.
122 triple = modTriple.getValue();
123 } else {
124 // Otherwise, overwrite or set default.
125 triple = prepareCIRModuleTriple(mod);
126 }
127
128 // If the data layout is not set, derive it from the triple.
129 return prepareCIRModuleDataLayout(mod, triple);
130}
131} // namespace
132} // namespace cir
133
134void registerToLLVMTranslation() {
135 static llvm::cl::opt<bool> disableCCLowering(
136 "disable-cc-lowering",
137 llvm::cl::desc("Disable calling convention lowering pass"),
138 llvm::cl::init(false));
139
140 mlir::TranslateFromMLIRRegistration registration(
141 "cir-to-llvmir", "Translate CIR to LLVMIR",
142 [](mlir::Operation *op, mlir::raw_ostream &output) {
143 auto cirModule = llvm::dyn_cast<mlir::ModuleOp>(op);
144
145 if (mlir::failed(cir::prepareCIRModuleForTranslation(cirModule)))
146 return mlir::failure();
147
148 llvm::LLVMContext llvmContext;
149 std::unique_ptr<llvm::Module> llvmModule =
150 cir::direct::lowerDirectlyFromCIRToLLVMIR(cirModule, llvmContext);
151 if (!llvmModule)
152 return mlir::failure();
153 llvmModule->print(output, nullptr);
154 return mlir::success();
155 },
156 [](mlir::DialectRegistry &registry) {
157 registry.insert<mlir::DLTIDialect, mlir::func::FuncDialect>();
158 mlir::registerAllToLLVMIRTranslations(registry);
159 cir::direct::registerCIRDialectTranslation(registry);
160 });
161}
162
163int main(int argc, char **argv) {
164 registerToLLVMTranslation();
165 return failed(mlir::mlirTranslateMain(argc, argv, "CIR Translation Tool"));
166}
167

source code of clang/tools/cir-translate/cir-translate.cpp