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); 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 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(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(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