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
anchor()28 void CIRGenerator::anchor() {}
29
CIRGenerator(clang::DiagnosticsEngine & diags,llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs,const CodeGenOptions & cgo)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} {}
~CIRGenerator()35 CIRGenerator::~CIRGenerator() {
36 // There should normally not be any leftover inline method definitions.
37 assert(deferredInlineMemberFuncDefs.empty() || diags.hasErrorOccurred());
38 }
39
setMLIRDataLayout(mlir::ModuleOp & mod,const llvm::DataLayout & dl)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
Initialize(ASTContext & astContext)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);
60 mlirContext->appendDialectRegistry(registry);
61
62 cgm = std::make_unique<clang::CIRGen::CIRGenModule>(
63 *mlirContext.get(), astContext, codeGenOpts, diags);
64 mlir::ModuleOp mod = cgm->getModule();
65 llvm::DataLayout layout =
66 llvm::DataLayout(astContext.getTargetInfo().getDataLayoutString());
67 setMLIRDataLayout(mod, layout);
68 }
69
verifyModule() const70 bool CIRGenerator::verifyModule() const { return cgm->verifyModule(); }
71
getModule() const72 mlir::ModuleOp CIRGenerator::getModule() const { return cgm->getModule(); }
73
HandleTopLevelDecl(DeclGroupRef group)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
HandleTranslationUnit(ASTContext & astContext)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
HandleInlineFunctionDefinition(FunctionDecl * d)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(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
emitDeferredDecls()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).
HandleTagDeclDefinition(TagDecl * d)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(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
CompleteTentativeDefinition(VarDecl * d)155 void CIRGenerator::CompleteTentativeDefinition(VarDecl *d) {
156 if (diags.hasErrorOccurred())
157 return;
158
159 cgm->emitTentativeDefinition(d);
160 }
161