1 //===- CIRGenModule.cpp - Per-Module state for CIR generation -------------===// 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 is the internal per-translation-unit state used for CIR translation. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "CIRGenModule.h" 14 15 #include "clang/AST/ASTContext.h" 16 #include "clang/AST/DeclBase.h" 17 #include "clang/AST/GlobalDecl.h" 18 #include "clang/Basic/SourceManager.h" 19 #include "clang/CIR/Dialect/IR/CIRDialect.h" 20 21 #include "mlir/IR/BuiltinOps.h" 22 #include "mlir/IR/Location.h" 23 #include "mlir/IR/MLIRContext.h" 24 25 using namespace clang; 26 using namespace clang::CIRGen; 27 28 CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext, 29 clang::ASTContext &astContext, 30 const clang::CodeGenOptions &cgo, 31 DiagnosticsEngine &diags) 32 : builder(mlirContext, *this), astContext(astContext), 33 langOpts(astContext.getLangOpts()), 34 theModule{mlir::ModuleOp::create(mlir::UnknownLoc::get(&mlirContext))}, 35 diags(diags), target(astContext.getTargetInfo()), genTypes(*this) { 36 37 // Initialize cached types 38 VoidTy = cir::VoidType::get(&getMLIRContext()); 39 SInt8Ty = cir::IntType::get(&getMLIRContext(), 8, /*isSigned=*/true); 40 SInt16Ty = cir::IntType::get(&getMLIRContext(), 16, /*isSigned=*/true); 41 SInt32Ty = cir::IntType::get(&getMLIRContext(), 32, /*isSigned=*/true); 42 SInt64Ty = cir::IntType::get(&getMLIRContext(), 64, /*isSigned=*/true); 43 SInt128Ty = cir::IntType::get(&getMLIRContext(), 128, /*isSigned=*/true); 44 UInt8Ty = cir::IntType::get(&getMLIRContext(), 8, /*isSigned=*/false); 45 UInt16Ty = cir::IntType::get(&getMLIRContext(), 16, /*isSigned=*/false); 46 UInt32Ty = cir::IntType::get(&getMLIRContext(), 32, /*isSigned=*/false); 47 UInt64Ty = cir::IntType::get(&getMLIRContext(), 64, /*isSigned=*/false); 48 UInt128Ty = cir::IntType::get(&getMLIRContext(), 128, /*isSigned=*/false); 49 FP16Ty = cir::FP16Type::get(&getMLIRContext()); 50 BFloat16Ty = cir::BF16Type::get(&getMLIRContext()); 51 FloatTy = cir::SingleType::get(&getMLIRContext()); 52 DoubleTy = cir::DoubleType::get(&getMLIRContext()); 53 FP80Ty = cir::FP80Type::get(&getMLIRContext()); 54 FP128Ty = cir::FP128Type::get(&getMLIRContext()); 55 } 56 57 mlir::Location CIRGenModule::getLoc(SourceLocation cLoc) { 58 assert(cLoc.isValid() && "expected valid source location"); 59 const SourceManager &sm = astContext.getSourceManager(); 60 PresumedLoc pLoc = sm.getPresumedLoc(cLoc); 61 StringRef filename = pLoc.getFilename(); 62 return mlir::FileLineColLoc::get(builder.getStringAttr(filename), 63 pLoc.getLine(), pLoc.getColumn()); 64 } 65 66 mlir::Location CIRGenModule::getLoc(SourceRange cRange) { 67 assert(cRange.isValid() && "expected a valid source range"); 68 mlir::Location begin = getLoc(cRange.getBegin()); 69 mlir::Location end = getLoc(cRange.getEnd()); 70 mlir::Attribute metadata; 71 return mlir::FusedLoc::get({begin, end}, metadata, builder.getContext()); 72 } 73 74 void CIRGenModule::emitGlobal(clang::GlobalDecl gd) { 75 const auto *global = cast<ValueDecl>(gd.getDecl()); 76 77 if (const auto *fd = dyn_cast<FunctionDecl>(global)) { 78 // Update deferred annotations with the latest declaration if the function 79 // was already used or defined. 80 if (fd->hasAttr<AnnotateAttr>()) 81 errorNYI(fd->getSourceRange(), "deferredAnnotations"); 82 if (!fd->doesThisDeclarationHaveABody()) { 83 if (!fd->doesDeclarationForceExternallyVisibleDefinition()) 84 return; 85 86 errorNYI(fd->getSourceRange(), 87 "function declaration that forces code gen"); 88 return; 89 } 90 } else { 91 assert(cast<VarDecl>(global)->isFileVarDecl() && 92 "Cannot emit local var decl as global"); 93 } 94 95 // TODO(CIR): Defer emitting some global definitions until later 96 emitGlobalDefinition(gd); 97 } 98 99 void CIRGenModule::emitGlobalFunctionDefinition(clang::GlobalDecl gd, 100 mlir::Operation *op) { 101 auto const *funcDecl = cast<FunctionDecl>(gd.getDecl()); 102 if (clang::IdentifierInfo *identifier = funcDecl->getIdentifier()) { 103 auto funcOp = builder.create<cir::FuncOp>( 104 getLoc(funcDecl->getSourceRange()), identifier->getName()); 105 theModule.push_back(funcOp); 106 } else { 107 errorNYI(funcDecl->getSourceRange().getBegin(), 108 "function definition with a non-identifier for a name"); 109 } 110 } 111 112 void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd, 113 bool isTentative) { 114 mlir::Type type = getTypes().convertType(vd->getType()); 115 if (clang::IdentifierInfo *identifier = vd->getIdentifier()) { 116 auto varOp = builder.create<cir::GlobalOp>(getLoc(vd->getSourceRange()), 117 identifier->getName(), type); 118 // TODO(CIR): This code for processing initial values is a placeholder 119 // until class ConstantEmitter is upstreamed and the code for processing 120 // constant expressions is filled out. Only the most basic handling of 121 // certain constant expressions is implemented for now. 122 const VarDecl *initDecl; 123 const Expr *initExpr = vd->getAnyInitializer(initDecl); 124 if (initExpr) { 125 mlir::Attribute initializer; 126 if (APValue *value = initDecl->evaluateValue()) { 127 switch (value->getKind()) { 128 case APValue::Int: { 129 initializer = builder.getAttr<cir::IntAttr>(type, value->getInt()); 130 break; 131 } 132 case APValue::Float: { 133 initializer = builder.getAttr<cir::FPAttr>(type, value->getFloat()); 134 break; 135 } 136 case APValue::LValue: { 137 if (value->getLValueBase()) { 138 errorNYI(initExpr->getSourceRange(), 139 "non-null pointer initialization"); 140 } else { 141 if (auto ptrType = mlir::dyn_cast<cir::PointerType>(type)) { 142 initializer = builder.getConstPtrAttr( 143 ptrType, value->getLValueOffset().getQuantity()); 144 } else { 145 llvm_unreachable( 146 "non-pointer variable initialized with a pointer"); 147 } 148 } 149 break; 150 } 151 default: 152 errorNYI(initExpr->getSourceRange(), "unsupported initializer kind"); 153 break; 154 } 155 } else { 156 errorNYI(initExpr->getSourceRange(), "non-constant initializer"); 157 } 158 varOp.setInitialValueAttr(initializer); 159 } 160 theModule.push_back(varOp); 161 } else { 162 errorNYI(vd->getSourceRange().getBegin(), 163 "variable definition with a non-identifier for a name"); 164 } 165 } 166 167 void CIRGenModule::emitGlobalDefinition(clang::GlobalDecl gd, 168 mlir::Operation *op) { 169 const auto *decl = cast<ValueDecl>(gd.getDecl()); 170 if (const auto *fd = dyn_cast<FunctionDecl>(decl)) { 171 // TODO(CIR): Skip generation of CIR for functions with available_externally 172 // linkage at -O0. 173 174 if (const auto *method = dyn_cast<CXXMethodDecl>(decl)) { 175 // Make sure to emit the definition(s) before we emit the thunks. This is 176 // necessary for the generation of certain thunks. 177 (void)method; 178 errorNYI(method->getSourceRange(), "member function"); 179 return; 180 } 181 182 if (fd->isMultiVersion()) 183 errorNYI(fd->getSourceRange(), "multiversion functions"); 184 emitGlobalFunctionDefinition(gd, op); 185 return; 186 } 187 188 if (const auto *vd = dyn_cast<VarDecl>(decl)) 189 return emitGlobalVarDefinition(vd, !vd->hasDefinition()); 190 191 llvm_unreachable("Invalid argument to CIRGenModule::emitGlobalDefinition"); 192 } 193 194 // Emit code for a single top level declaration. 195 void CIRGenModule::emitTopLevelDecl(Decl *decl) { 196 197 // Ignore dependent declarations. 198 if (decl->isTemplated()) 199 return; 200 201 switch (decl->getKind()) { 202 default: 203 errorNYI(decl->getBeginLoc(), "declaration of kind", 204 decl->getDeclKindName()); 205 break; 206 207 case Decl::Function: { 208 auto *fd = cast<FunctionDecl>(decl); 209 // Consteval functions shouldn't be emitted. 210 if (!fd->isConsteval()) 211 emitGlobal(fd); 212 break; 213 } 214 215 case Decl::Var: { 216 auto *vd = cast<VarDecl>(decl); 217 emitGlobal(vd); 218 break; 219 } 220 } 221 } 222 223 DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc, 224 llvm::StringRef feature) { 225 unsigned diagID = diags.getCustomDiagID( 226 DiagnosticsEngine::Error, "ClangIR code gen Not Yet Implemented: %0"); 227 return diags.Report(loc, diagID) << feature; 228 } 229 230 DiagnosticBuilder CIRGenModule::errorNYI(SourceRange loc, 231 llvm::StringRef feature) { 232 return errorNYI(loc.getBegin(), feature) << loc; 233 } 234