1 | //===--- CIRGenerator.cpp - Emit CIR from ASTs ----------------------------===// |
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 | // This builds an AST and converts it to CIR. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "CIRGenModule.h" |
14 | |
15 | #include "mlir/Dialect/OpenACC/OpenACC.h" |
16 | #include "mlir/IR/MLIRContext.h" |
17 | #include "mlir/Target/LLVMIR/Import.h" |
18 | |
19 | #include "clang/AST/DeclGroup.h" |
20 | #include "clang/CIR/CIRGenerator.h" |
21 | #include "clang/CIR/Dialect/IR/CIRDialect.h" |
22 | #include "clang/CIR/Dialect/OpenACC/RegisterOpenACCExtensions.h" |
23 | #include "llvm/IR/DataLayout.h" |
24 | |
25 | using namespace cir; |
26 | using namespace clang; |
27 | |
28 | void CIRGenerator::anchor() {} |
29 | |
30 | CIRGenerator::CIRGenerator(clang::DiagnosticsEngine &diags, |
31 | llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs, |
32 | const CodeGenOptions &cgo) |
33 | : diags(diags), fs(std::move(vfs)), codeGenOpts{cgo}, |
34 | handlingTopLevelDecls{0} {} |
35 | CIRGenerator::~CIRGenerator() { |
36 | // There should normally not be any leftover inline method definitions. |
37 | assert(deferredInlineMemberFuncDefs.empty() || diags.hasErrorOccurred()); |
38 | } |
39 | |
40 | static void setMLIRDataLayout(mlir::ModuleOp &mod, const llvm::DataLayout &dl) { |
41 | mlir::MLIRContext *mlirContext = mod.getContext(); |
42 | mlir::DataLayoutSpecInterface dlSpec = |
43 | mlir::translateDataLayout(dl, mlirContext); |
44 | mod->setAttr(mlir::DLTIDialect::kDataLayoutAttrName, dlSpec); |
45 | } |
46 | |
47 | void CIRGenerator::Initialize(ASTContext &astContext) { |
48 | using namespace llvm; |
49 | |
50 | this->astContext = &astContext; |
51 | |
52 | mlirContext = std::make_unique<mlir::MLIRContext>(); |
53 | mlirContext->loadDialect<mlir::DLTIDialect>(); |
54 | mlirContext->loadDialect<cir::CIRDialect>(); |
55 | mlirContext->getOrLoadDialect<mlir::acc::OpenACCDialect>(); |
56 | |
57 | // Register extensions to integrate CIR types with OpenACC. |
58 | mlir::DialectRegistry registry; |
59 | cir::acc::registerOpenACCExtensions(registry&: registry); |
60 | mlirContext->appendDialectRegistry(registry); |
61 | |
62 | cgm = std::make_unique<clang::CIRGen::CIRGenModule>( |
63 | args&: *mlirContext.get(), args&: astContext, args: codeGenOpts, args&: diags); |
64 | mlir::ModuleOp mod = cgm->getModule(); |
65 | llvm::DataLayout layout = |
66 | llvm::DataLayout(astContext.getTargetInfo().getDataLayoutString()); |
67 | setMLIRDataLayout(mod, layout); |
68 | } |
69 | |
70 | bool CIRGenerator::verifyModule() const { return cgm->verifyModule(); } |
71 | |
72 | mlir::ModuleOp CIRGenerator::getModule() const { return cgm->getModule(); } |
73 | |
74 | bool CIRGenerator::HandleTopLevelDecl(DeclGroupRef group) { |
75 | if (diags.hasUnrecoverableErrorOccurred()) |
76 | return true; |
77 | |
78 | HandlingTopLevelDeclRAII handlingDecl(*this); |
79 | |
80 | for (Decl *decl : group) |
81 | cgm->emitTopLevelDecl(decl); |
82 | |
83 | return true; |
84 | } |
85 | |
86 | void CIRGenerator::HandleTranslationUnit(ASTContext &astContext) { |
87 | // Release the Builder when there is no error. |
88 | if (!diags.hasErrorOccurred() && cgm) |
89 | cgm->release(); |
90 | |
91 | // If there are errors before or when releasing the cgm, reset the module to |
92 | // stop here before invoking the backend. |
93 | assert(!cir::MissingFeatures::cleanupAfterErrorDiags()); |
94 | } |
95 | |
96 | void CIRGenerator::HandleInlineFunctionDefinition(FunctionDecl *d) { |
97 | if (diags.hasErrorOccurred()) |
98 | return; |
99 | |
100 | assert(d->doesThisDeclarationHaveABody()); |
101 | |
102 | // We may want to emit this definition. However, that decision might be |
103 | // based on computing the linkage, and we have to defer that in case we are |
104 | // inside of something that will chagne the method's final linkage, e.g. |
105 | // typedef struct { |
106 | // void bar(); |
107 | // void foo() { bar(); } |
108 | // } A; |
109 | deferredInlineMemberFuncDefs.push_back(Elt: d); |
110 | |
111 | // Provide some coverage mapping even for methods that aren't emitted. |
112 | // Don't do this for templated classes though, as they may not be |
113 | // instantiable. |
114 | assert(!cir::MissingFeatures::coverageMapping()); |
115 | } |
116 | |
117 | void CIRGenerator::emitDeferredDecls() { |
118 | if (deferredInlineMemberFuncDefs.empty()) |
119 | return; |
120 | |
121 | // Emit any deferred inline method definitions. Note that more deferred |
122 | // methods may be added during this loop, since ASTConsumer callbacks can be |
123 | // invoked if AST inspection results in declarations being added. Therefore, |
124 | // we use an index to loop over the deferredInlineMemberFuncDefs rather than |
125 | // a range. |
126 | HandlingTopLevelDeclRAII handlingDecls(*this); |
127 | for (unsigned i = 0; i != deferredInlineMemberFuncDefs.size(); ++i) |
128 | cgm->emitTopLevelDecl(deferredInlineMemberFuncDefs[i]); |
129 | deferredInlineMemberFuncDefs.clear(); |
130 | } |
131 | |
132 | /// HandleTagDeclDefinition - This callback is invoked each time a TagDecl to |
133 | /// (e.g. struct, union, enum, class) is completed. This allows the client to |
134 | /// hack on the type, which can occur at any point in the file (because these |
135 | /// can be defined in declspecs). |
136 | void CIRGenerator::HandleTagDeclDefinition(TagDecl *d) { |
137 | if (diags.hasErrorOccurred()) |
138 | return; |
139 | |
140 | // Don't allow re-entrant calls to CIRGen triggered by PCH deserialization to |
141 | // emit deferred decls. |
142 | HandlingTopLevelDeclRAII handlingDecl(*this, /*EmitDeferred=*/false); |
143 | |
144 | cgm->updateCompletedType(td: d); |
145 | |
146 | // For MSVC compatibility, treat declarations of static data members with |
147 | // inline initializers as definitions. |
148 | if (astContext->getTargetInfo().getCXXABI().isMicrosoft()) |
149 | cgm->errorNYI(d->getSourceRange(), "HandleTagDeclDefinition: MSABI" ); |
150 | // For OpenMP emit declare reduction functions, if required. |
151 | if (astContext->getLangOpts().OpenMP) |
152 | cgm->errorNYI(d->getSourceRange(), "HandleTagDeclDefinition: OpenMP" ); |
153 | } |
154 | |
155 | void CIRGenerator::CompleteTentativeDefinition(VarDecl *d) { |
156 | if (diags.hasErrorOccurred()) |
157 | return; |
158 | |
159 | cgm->emitTentativeDefinition(d); |
160 | } |
161 | |