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/Diagnostic.h"
29#include "clang/Basic/DiagnosticIDs.h"
30#include "clang/Basic/DiagnosticOptions.h"
31#include "clang/Basic/TargetInfo.h"
32#include "clang/CIR/Dialect/IR/CIRDialect.h"
33#include "clang/CIR/Dialect/Passes.h"
34#include "clang/CIR/LowerToLLVM.h"
35#include "clang/CIR/MissingFeatures.h"
36
37namespace cir {
38namespace direct {
39extern void registerCIRDialectTranslation(mlir::DialectRegistry &registry);
40} // namespace direct
41
42namespace {
43
44/// The goal of this option is to ensure that the triple and data layout specs
45/// are always available in the ClangIR module. With this requirement met, the
46/// behavior of this option is designed to be as intuitive as possible, as shown
47/// in the table below:
48///
49/// +--------+--------+-------------+-----------------+-----------------------+
50/// | Option | Triple | Data Layout | Behavior Triple | Behavior Data Layout |
51/// +========+========+=============+=================+=======================+
52/// | T | T | T | Overwrite | Derive from triple |
53/// | T | T | F | Overwrite | Derive from triple |
54/// | T | F | T | Overwrite | Derive from triple |
55/// | T | F | F | Overwrite | Derive from triple |
56/// | F | T | T | | |
57/// | F | T | F | | Derive from triple |
58/// | F | F | T | Set default | Derive from triple |
59/// | F | F | F | Set default | Derive from triple |
60/// +--------+--------+-------------+-----------------+-----------------------+
61llvm::cl::opt<std::string>
62 targetTripleOption("target",
63 llvm::cl::desc("Specify a default target triple when "
64 "it's not available in the module"),
65 llvm::cl::init(""));
66
67std::string prepareCIRModuleTriple(mlir::ModuleOp mod) {
68 std::string triple = targetTripleOption;
69
70 // Treat "" as the default target machine.
71 if (triple.empty()) {
72 triple = llvm::sys::getDefaultTargetTriple();
73
74 mod.emitWarning() << "no target triple provided, assuming " << triple;
75 }
76
77 mod->setAttr(cir::CIRDialect::getTripleAttrName(),
78 mlir::StringAttr::get(mod.getContext(), triple));
79 return triple;
80}
81
82llvm::LogicalResult prepareCIRModuleDataLayout(mlir::ModuleOp mod,
83 llvm::StringRef rawTriple) {
84 auto *context = mod.getContext();
85
86 // Data layout is fully determined by the target triple. Here we only pass the
87 // triple to get the data layout.
88 llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagID(
89 new clang::DiagnosticIDs);
90 clang::DiagnosticOptions diagOpts;
91 llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics =
92 new clang::DiagnosticsEngine(diagID, diagOpts,
93 new clang::IgnoringDiagConsumer());
94 llvm::Triple triple(rawTriple);
95 // TODO: Need to set various target options later to populate
96 // 'TargetInfo' properly.
97 clang::TargetOptions targetOptions;
98 targetOptions.Triple = rawTriple;
99 llvm::IntrusiveRefCntPtr<clang::TargetInfo> targetInfo =
100 clang::TargetInfo::CreateTargetInfo(Diags&: *diagnostics, Opts&: targetOptions);
101 if (!targetInfo) {
102 mod.emitError() << "error: invalid target triple '" << rawTriple << "'\n";
103 return llvm::failure();
104 }
105 std::string layoutString = targetInfo->getDataLayoutString();
106
107 // Registered dialects may not be loaded yet, ensure they are.
108 context->loadDialect<mlir::DLTIDialect, mlir::LLVM::LLVMDialect>();
109
110 mlir::DataLayoutSpecInterface dlSpec =
111 mlir::translateDataLayout(llvm::DataLayout(layoutString), context);
112 mod->setAttr(mlir::DLTIDialect::kDataLayoutAttrName, dlSpec);
113
114 return llvm::success();
115}
116
117/// Prepare requirements like cir.triple and data layout.
118llvm::LogicalResult prepareCIRModuleForTranslation(mlir::ModuleOp mod) {
119 auto modTriple = mod->getAttrOfType<mlir::StringAttr>(
120 cir::CIRDialect::getTripleAttrName());
121 auto modDataLayout = mod->getAttr(mlir::DLTIDialect::kDataLayoutAttrName);
122 bool hasTargetOption = targetTripleOption.getNumOccurrences() > 0;
123
124 // Skip the situation where nothing should be done.
125 if (!hasTargetOption && modTriple && modDataLayout)
126 return llvm::success();
127
128 std::string triple;
129
130 if (!hasTargetOption && modTriple) {
131 // Do nothing if it's already set.
132 triple = modTriple.getValue();
133 } else {
134 // Otherwise, overwrite or set default.
135 triple = prepareCIRModuleTriple(mod);
136 }
137
138 // If the data layout is not set, derive it from the triple.
139 return prepareCIRModuleDataLayout(mod, triple);
140}
141} // namespace
142} // namespace cir
143
144void registerToLLVMTranslation() {
145 static llvm::cl::opt<bool> disableCCLowering(
146 "disable-cc-lowering",
147 llvm::cl::desc("Disable calling convention lowering pass"),
148 llvm::cl::init(false));
149
150 mlir::TranslateFromMLIRRegistration registration(
151 "cir-to-llvmir", "Translate CIR to LLVMIR",
152 [](mlir::Operation *op, mlir::raw_ostream &output) {
153 auto cirModule = llvm::dyn_cast<mlir::ModuleOp>(op);
154
155 if (mlir::failed(cir::prepareCIRModuleForTranslation(cirModule)))
156 return mlir::failure();
157
158 llvm::LLVMContext llvmContext;
159 std::unique_ptr<llvm::Module> llvmModule =
160 cir::direct::lowerDirectlyFromCIRToLLVMIR(cirModule, llvmContext);
161 if (!llvmModule)
162 return mlir::failure();
163 llvmModule->print(output, nullptr);
164 return mlir::success();
165 },
166 [](mlir::DialectRegistry &registry) {
167 registry.insert<mlir::DLTIDialect, mlir::func::FuncDialect>();
168 mlir::registerAllToLLVMIRTranslations(registry);
169 cir::direct::registerCIRDialectTranslation(registry);
170 });
171}
172
173int main(int argc, char **argv) {
174 registerToLLVMTranslation();
175 return failed(mlir::mlirTranslateMain(argc, argv, "CIR Translation Tool"));
176}
177

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