| 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 | |