| //===- CIRGenModule.cpp - Per-Module state for CIR generation -------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This is the internal per-translation-unit state used for CIR translation. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "CIRGenModule.h" |
| |
| #include "clang/AST/ASTContext.h" |
| #include "clang/AST/DeclBase.h" |
| #include "clang/AST/GlobalDecl.h" |
| #include "clang/Basic/SourceManager.h" |
| #include "clang/CIR/Dialect/IR/CIRDialect.h" |
| |
| #include "mlir/IR/BuiltinOps.h" |
| #include "mlir/IR/Location.h" |
| #include "mlir/IR/MLIRContext.h" |
| |
| using namespace clang; |
| using namespace clang::CIRGen; |
| |
| CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext, |
| clang::ASTContext &astContext, |
| const clang::CodeGenOptions &cgo, |
| DiagnosticsEngine &diags) |
| : builder(mlirContext, *this), astContext(astContext), |
| langOpts(astContext.getLangOpts()), |
| theModule{mlir::ModuleOp::create(mlir::UnknownLoc::get(&mlirContext))}, |
| diags(diags), target(astContext.getTargetInfo()), genTypes(*this) { |
| |
| // Initialize cached types |
| SInt8Ty = cir::IntType::get(&getMLIRContext(), 8, /*isSigned=*/true); |
| SInt16Ty = cir::IntType::get(&getMLIRContext(), 16, /*isSigned=*/true); |
| SInt32Ty = cir::IntType::get(&getMLIRContext(), 32, /*isSigned=*/true); |
| SInt64Ty = cir::IntType::get(&getMLIRContext(), 64, /*isSigned=*/true); |
| SInt128Ty = cir::IntType::get(&getMLIRContext(), 128, /*isSigned=*/true); |
| UInt8Ty = cir::IntType::get(&getMLIRContext(), 8, /*isSigned=*/false); |
| UInt16Ty = cir::IntType::get(&getMLIRContext(), 16, /*isSigned=*/false); |
| UInt32Ty = cir::IntType::get(&getMLIRContext(), 32, /*isSigned=*/false); |
| UInt64Ty = cir::IntType::get(&getMLIRContext(), 64, /*isSigned=*/false); |
| UInt128Ty = cir::IntType::get(&getMLIRContext(), 128, /*isSigned=*/false); |
| } |
| |
| mlir::Location CIRGenModule::getLoc(SourceLocation cLoc) { |
| assert(cLoc.isValid() && "expected valid source location"); |
| const SourceManager &sm = astContext.getSourceManager(); |
| PresumedLoc pLoc = sm.getPresumedLoc(cLoc); |
| StringRef filename = pLoc.getFilename(); |
| return mlir::FileLineColLoc::get(builder.getStringAttr(filename), |
| pLoc.getLine(), pLoc.getColumn()); |
| } |
| |
| mlir::Location CIRGenModule::getLoc(SourceRange cRange) { |
| assert(cRange.isValid() && "expected a valid source range"); |
| mlir::Location begin = getLoc(cRange.getBegin()); |
| mlir::Location end = getLoc(cRange.getEnd()); |
| mlir::Attribute metadata; |
| return mlir::FusedLoc::get({begin, end}, metadata, builder.getContext()); |
| } |
| |
| void CIRGenModule::emitGlobal(clang::GlobalDecl gd) { |
| const auto *global = cast<ValueDecl>(gd.getDecl()); |
| |
| if (const auto *fd = dyn_cast<FunctionDecl>(global)) { |
| // Update deferred annotations with the latest declaration if the function |
| // was already used or defined. |
| if (fd->hasAttr<AnnotateAttr>()) |
| errorNYI(fd->getSourceRange(), "deferredAnnotations"); |
| if (!fd->doesThisDeclarationHaveABody()) { |
| if (!fd->doesDeclarationForceExternallyVisibleDefinition()) |
| return; |
| |
| errorNYI(fd->getSourceRange(), |
| "function declaration that forces code gen"); |
| return; |
| } |
| } else { |
| assert(cast<VarDecl>(global)->isFileVarDecl() && |
| "Cannot emit local var decl as global"); |
| } |
| |
| // TODO(CIR): Defer emitting some global definitions until later |
| emitGlobalDefinition(gd); |
| } |
| |
| void CIRGenModule::emitGlobalFunctionDefinition(clang::GlobalDecl gd, |
| mlir::Operation *op) { |
| auto const *funcDecl = cast<FunctionDecl>(gd.getDecl()); |
| if (clang::IdentifierInfo *identifier = funcDecl->getIdentifier()) { |
| auto funcOp = builder.create<cir::FuncOp>( |
| getLoc(funcDecl->getSourceRange()), identifier->getName()); |
| theModule.push_back(funcOp); |
| } else { |
| errorNYI(funcDecl->getSourceRange().getBegin(), |
| "function definition with a non-identifier for a name"); |
| } |
| } |
| |
| void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd, |
| bool isTentative) { |
| mlir::Type type = getTypes().convertType(vd->getType()); |
| if (clang::IdentifierInfo *identifier = vd->getIdentifier()) { |
| auto varOp = builder.create<cir::GlobalOp>(getLoc(vd->getSourceRange()), |
| identifier->getName(), type); |
| theModule.push_back(varOp); |
| } else { |
| errorNYI(vd->getSourceRange().getBegin(), |
| "variable definition with a non-identifier for a name"); |
| } |
| } |
| |
| void CIRGenModule::emitGlobalDefinition(clang::GlobalDecl gd, |
| mlir::Operation *op) { |
| const auto *decl = cast<ValueDecl>(gd.getDecl()); |
| if (const auto *fd = dyn_cast<FunctionDecl>(decl)) { |
| // TODO(CIR): Skip generation of CIR for functions with available_externally |
| // linkage at -O0. |
| |
| if (const auto *method = dyn_cast<CXXMethodDecl>(decl)) { |
| // Make sure to emit the definition(s) before we emit the thunks. This is |
| // necessary for the generation of certain thunks. |
| (void)method; |
| errorNYI(method->getSourceRange(), "member function"); |
| return; |
| } |
| |
| if (fd->isMultiVersion()) |
| errorNYI(fd->getSourceRange(), "multiversion functions"); |
| emitGlobalFunctionDefinition(gd, op); |
| return; |
| } |
| |
| if (const auto *vd = dyn_cast<VarDecl>(decl)) |
| return emitGlobalVarDefinition(vd, !vd->hasDefinition()); |
| |
| llvm_unreachable("Invalid argument to CIRGenModule::emitGlobalDefinition"); |
| } |
| |
| // Emit code for a single top level declaration. |
| void CIRGenModule::emitTopLevelDecl(Decl *decl) { |
| |
| // Ignore dependent declarations. |
| if (decl->isTemplated()) |
| return; |
| |
| switch (decl->getKind()) { |
| default: |
| errorNYI(decl->getBeginLoc(), "declaration of kind", |
| decl->getDeclKindName()); |
| break; |
| |
| case Decl::Function: { |
| auto *fd = cast<FunctionDecl>(decl); |
| // Consteval functions shouldn't be emitted. |
| if (!fd->isConsteval()) |
| emitGlobal(fd); |
| break; |
| } |
| |
| case Decl::Var: { |
| auto *vd = cast<VarDecl>(decl); |
| emitGlobal(vd); |
| break; |
| } |
| } |
| } |
| |
| DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc, |
| llvm::StringRef feature) { |
| unsigned diagID = diags.getCustomDiagID( |
| DiagnosticsEngine::Error, "ClangIR code gen Not Yet Implemented: %0"); |
| return diags.Report(loc, diagID) << feature; |
| } |
| |
| DiagnosticBuilder CIRGenModule::errorNYI(SourceRange loc, |
| llvm::StringRef feature) { |
| return errorNYI(loc.getBegin(), feature) << loc; |
| } |