1 //===--- CIRGenModule.h - Per-Module state for CIR gen ----------*- C++ -*-===// 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 #ifndef LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENMODULE_H 14 #define LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENMODULE_H 15 16 #include "CIRGenBuilder.h" 17 #include "CIRGenCall.h" 18 #include "CIRGenTypeCache.h" 19 #include "CIRGenTypes.h" 20 #include "CIRGenValue.h" 21 22 #include "clang/AST/CharUnits.h" 23 #include "clang/CIR/Dialect/IR/CIRDataLayout.h" 24 #include "clang/CIR/Dialect/IR/CIRDialect.h" 25 26 #include "TargetInfo.h" 27 #include "mlir/IR/Builders.h" 28 #include "mlir/IR/BuiltinOps.h" 29 #include "mlir/IR/MLIRContext.h" 30 #include "clang/AST/Decl.h" 31 #include "clang/Basic/SourceManager.h" 32 #include "clang/Basic/TargetInfo.h" 33 #include "clang/CIR/Dialect/IR/CIROpsEnums.h" 34 #include "llvm/ADT/StringRef.h" 35 #include "llvm/TargetParser/Triple.h" 36 37 namespace clang { 38 class ASTContext; 39 class CodeGenOptions; 40 class Decl; 41 class GlobalDecl; 42 class LangOptions; 43 class TargetInfo; 44 class VarDecl; 45 46 namespace CIRGen { 47 48 class CIRGenFunction; 49 class CIRGenCXXABI; 50 51 enum ForDefinition_t : bool { NotForDefinition = false, ForDefinition = true }; 52 53 /// This class organizes the cross-function state that is used while generating 54 /// CIR code. 55 class CIRGenModule : public CIRGenTypeCache { 56 CIRGenModule(CIRGenModule &) = delete; 57 CIRGenModule &operator=(CIRGenModule &) = delete; 58 59 public: 60 CIRGenModule(mlir::MLIRContext &mlirContext, clang::ASTContext &astContext, 61 const clang::CodeGenOptions &cgo, 62 clang::DiagnosticsEngine &diags); 63 64 ~CIRGenModule(); 65 66 private: 67 mutable std::unique_ptr<TargetCIRGenInfo> theTargetCIRGenInfo; 68 69 CIRGenBuilderTy builder; 70 71 /// Hold Clang AST information. 72 clang::ASTContext &astContext; 73 74 const clang::LangOptions &langOpts; 75 76 const clang::CodeGenOptions &codeGenOpts; 77 78 /// A "module" matches a c/cpp source file: containing a list of functions. 79 mlir::ModuleOp theModule; 80 81 clang::DiagnosticsEngine &diags; 82 83 const clang::TargetInfo ⌖ 84 85 std::unique_ptr<CIRGenCXXABI> abi; 86 87 CIRGenTypes genTypes; 88 89 /// Per-function codegen information. Updated everytime emitCIR is called 90 /// for FunctionDecls's. 91 CIRGenFunction *curCGF = nullptr; 92 93 public: getModule()94 mlir::ModuleOp getModule() const { return theModule; } getBuilder()95 CIRGenBuilderTy &getBuilder() { return builder; } getASTContext()96 clang::ASTContext &getASTContext() const { return astContext; } getTarget()97 const clang::TargetInfo &getTarget() const { return target; } getCodeGenOpts()98 const clang::CodeGenOptions &getCodeGenOpts() const { return codeGenOpts; } getTypes()99 CIRGenTypes &getTypes() { return genTypes; } getLangOpts()100 const clang::LangOptions &getLangOpts() const { return langOpts; } 101 getCXXABI()102 CIRGenCXXABI &getCXXABI() const { return *abi; } getMLIRContext()103 mlir::MLIRContext &getMLIRContext() { return *builder.getContext(); } 104 getDataLayout()105 const cir::CIRDataLayout getDataLayout() const { 106 // FIXME(cir): instead of creating a CIRDataLayout every time, set it as an 107 // attribute for the CIRModule class. 108 return cir::CIRDataLayout(theModule); 109 } 110 111 /// ------- 112 /// Handling globals 113 /// ------- 114 115 mlir::Operation *lastGlobalOp = nullptr; 116 117 llvm::DenseMap<const Decl *, cir::GlobalOp> staticLocalDeclMap; 118 119 mlir::Operation *getGlobalValue(llvm::StringRef ref); 120 getStaticLocalDeclAddress(const VarDecl * d)121 cir::GlobalOp getStaticLocalDeclAddress(const VarDecl *d) { 122 return staticLocalDeclMap[d]; 123 } 124 setStaticLocalDeclAddress(const VarDecl * d,cir::GlobalOp c)125 void setStaticLocalDeclAddress(const VarDecl *d, cir::GlobalOp c) { 126 staticLocalDeclMap[d] = c; 127 } 128 129 cir::GlobalOp getOrCreateStaticVarDecl(const VarDecl &d, 130 cir::GlobalLinkageKind linkage); 131 132 /// If the specified mangled name is not in the module, create and return an 133 /// mlir::GlobalOp value 134 cir::GlobalOp getOrCreateCIRGlobal(llvm::StringRef mangledName, mlir::Type ty, 135 LangAS langAS, const VarDecl *d, 136 ForDefinition_t isForDefinition); 137 138 cir::GlobalOp getOrCreateCIRGlobal(const VarDecl *d, mlir::Type ty, 139 ForDefinition_t isForDefinition); 140 141 static cir::GlobalOp createGlobalOp(CIRGenModule &cgm, mlir::Location loc, 142 llvm::StringRef name, mlir::Type t, 143 mlir::Operation *insertPoint = nullptr); 144 145 llvm::StringMap<unsigned> cgGlobalNames; 146 std::string getUniqueGlobalName(const std::string &baseName); 147 148 /// Return the mlir::Value for the address of the given global variable. 149 /// If Ty is non-null and if the global doesn't exist, then it will be created 150 /// with the specified type instead of whatever the normal requested type 151 /// would be. If IsForDefinition is true, it is guaranteed that an actual 152 /// global with type Ty will be returned, not conversion of a variable with 153 /// the same mangled name but some other type. 154 mlir::Value 155 getAddrOfGlobalVar(const VarDecl *d, mlir::Type ty = {}, 156 ForDefinition_t isForDefinition = NotForDefinition); 157 158 CharUnits computeNonVirtualBaseClassOffset( 159 const CXXRecordDecl *derivedClass, 160 llvm::iterator_range<CastExpr::path_const_iterator> path); 161 162 /// Get the CIR attributes and calling convention to use for a particular 163 /// function type. 164 /// 165 /// \param calleeInfo - The callee information these attributes are being 166 /// constructed for. If valid, the attributes applied to this decl may 167 /// contribute to the function attributes and calling convention. 168 void constructAttributeList(CIRGenCalleeInfo calleeInfo, 169 mlir::NamedAttrList &attrs); 170 171 /// Return a constant array for the given string. 172 mlir::Attribute getConstantArrayFromStringLiteral(const StringLiteral *e); 173 174 /// Return a global symbol reference to a constant array for the given string 175 /// literal. 176 cir::GlobalOp getGlobalForStringLiteral(const StringLiteral *s, 177 llvm::StringRef name = ".str"); 178 179 /// Set attributes which are common to any form of a global definition (alias, 180 /// Objective-C method, function, global variable). 181 /// 182 /// NOTE: This should only be called for definitions. 183 void setCommonAttributes(GlobalDecl gd, mlir::Operation *op); 184 185 const TargetCIRGenInfo &getTargetCIRGenInfo(); 186 187 /// Helpers to convert the presumed location of Clang's SourceLocation to an 188 /// MLIR Location. 189 mlir::Location getLoc(clang::SourceLocation cLoc); 190 mlir::Location getLoc(clang::SourceRange cRange); 191 192 /// Return the best known alignment for an unknown pointer to a 193 /// particular class. 194 clang::CharUnits getClassPointerAlignment(const clang::CXXRecordDecl *rd); 195 196 /// FIXME: this could likely be a common helper and not necessarily related 197 /// with codegen. 198 clang::CharUnits getNaturalTypeAlignment(clang::QualType t, 199 LValueBaseInfo *baseInfo); 200 201 cir::FuncOp 202 getAddrOfCXXStructor(clang::GlobalDecl gd, 203 const CIRGenFunctionInfo *fnInfo = nullptr, 204 cir::FuncType fnType = nullptr, bool dontDefer = false, 205 ForDefinition_t isForDefinition = NotForDefinition) { 206 return getAddrAndTypeOfCXXStructor(gd, fnInfo, fnType, dontDefer, 207 isForDefinition) 208 .second; 209 } 210 211 std::pair<cir::FuncType, cir::FuncOp> getAddrAndTypeOfCXXStructor( 212 clang::GlobalDecl gd, const CIRGenFunctionInfo *fnInfo = nullptr, 213 cir::FuncType fnType = nullptr, bool dontDefer = false, 214 ForDefinition_t isForDefinition = NotForDefinition); 215 216 /// This contains all the decls which have definitions but which are deferred 217 /// for emission and therefore should only be output if they are actually 218 /// used. If a decl is in this, then it is known to have not been referenced 219 /// yet. 220 std::map<llvm::StringRef, clang::GlobalDecl> deferredDecls; 221 222 // This is a list of deferred decls which we have seen that *are* actually 223 // referenced. These get code generated when the module is done. 224 std::vector<clang::GlobalDecl> deferredDeclsToEmit; addDeferredDeclToEmit(clang::GlobalDecl GD)225 void addDeferredDeclToEmit(clang::GlobalDecl GD) { 226 deferredDeclsToEmit.emplace_back(GD); 227 } 228 229 void emitTopLevelDecl(clang::Decl *decl); 230 231 /// Determine whether the definition must be emitted; if this returns \c 232 /// false, the definition can be emitted lazily if it's used. 233 bool mustBeEmitted(const clang::ValueDecl *d); 234 235 /// Determine whether the definition can be emitted eagerly, or should be 236 /// delayed until the end of the translation unit. This is relevant for 237 /// definitions whose linkage can change, e.g. implicit function 238 /// instantiations which may later be explicitly instantiated. 239 bool mayBeEmittedEagerly(const clang::ValueDecl *d); 240 241 bool verifyModule() const; 242 243 /// Return the address of the given function. If funcType is non-null, then 244 /// this function will use the specified type if it has to create it. 245 // TODO: this is a bit weird as `GetAddr` given we give back a FuncOp? 246 cir::FuncOp 247 getAddrOfFunction(clang::GlobalDecl gd, mlir::Type funcType = nullptr, 248 bool forVTable = false, bool dontDefer = false, 249 ForDefinition_t isForDefinition = NotForDefinition); 250 251 mlir::Operation * 252 getAddrOfGlobal(clang::GlobalDecl gd, 253 ForDefinition_t isForDefinition = NotForDefinition); 254 255 /// Emit code for a single global function or variable declaration. Forward 256 /// declarations are emitted lazily. 257 void emitGlobal(clang::GlobalDecl gd); 258 259 void emitAliasForGlobal(llvm::StringRef mangledName, mlir::Operation *op, 260 GlobalDecl aliasGD, cir::FuncOp aliasee, 261 cir::GlobalLinkageKind linkage); 262 263 mlir::Type convertType(clang::QualType type); 264 265 /// Set the visibility for the given global. 266 void setGlobalVisibility(mlir::Operation *op, const NamedDecl *d) const; 267 void setDSOLocal(mlir::Operation *op) const; 268 void setDSOLocal(cir::CIRGlobalValueInterface gv) const; 269 270 /// Set visibility, dllimport/dllexport and dso_local. 271 /// This must be called after dllimport/dllexport is set. 272 void setGVProperties(mlir::Operation *op, const NamedDecl *d) const; 273 void setGVPropertiesAux(mlir::Operation *op, const NamedDecl *d) const; 274 275 /// Set function attributes for a function declaration. 276 void setFunctionAttributes(GlobalDecl gd, cir::FuncOp f, 277 bool isIncompleteFunction, bool isThunk); 278 279 void emitGlobalDefinition(clang::GlobalDecl gd, 280 mlir::Operation *op = nullptr); 281 void emitGlobalFunctionDefinition(clang::GlobalDecl gd, mlir::Operation *op); 282 void emitGlobalVarDefinition(const clang::VarDecl *vd, 283 bool isTentative = false); 284 285 void emitGlobalOpenACCDecl(const clang::OpenACCConstructDecl *cd); 286 287 // C++ related functions. 288 void emitDeclContext(const DeclContext *dc); 289 290 /// Return the result of value-initializing the given type, i.e. a null 291 /// expression of the given type. 292 mlir::Value emitNullConstant(QualType t, mlir::Location loc); 293 294 llvm::StringRef getMangledName(clang::GlobalDecl gd); 295 296 void emitTentativeDefinition(const VarDecl *d); 297 298 // Make sure that this type is translated. 299 void updateCompletedType(const clang::TagDecl *td); 300 301 // Produce code for this constructor/destructor. This method doesn't try to 302 // apply any ABI rules about which other constructors/destructors are needed 303 // or if they are alias to each other. 304 cir::FuncOp codegenCXXStructor(clang::GlobalDecl gd); 305 306 bool supportsCOMDAT() const; 307 void maybeSetTrivialComdat(const clang::Decl &d, mlir::Operation *op); 308 309 static void setInitializer(cir::GlobalOp &op, mlir::Attribute value); 310 311 cir::FuncOp 312 getOrCreateCIRFunction(llvm::StringRef mangledName, mlir::Type funcType, 313 clang::GlobalDecl gd, bool forVTable, 314 bool dontDefer = false, bool isThunk = false, 315 ForDefinition_t isForDefinition = NotForDefinition, 316 mlir::ArrayAttr extraAttrs = {}); 317 318 cir::FuncOp createCIRFunction(mlir::Location loc, llvm::StringRef name, 319 cir::FuncType funcType, 320 const clang::FunctionDecl *funcDecl); 321 322 /// Given a builtin id for a function like "__builtin_fabsf", return a 323 /// Function* for "fabsf". 324 cir::FuncOp getBuiltinLibFunction(const FunctionDecl *fd, unsigned builtinID); 325 getSize(CharUnits size)326 mlir::IntegerAttr getSize(CharUnits size) { 327 return builder.getSizeFromCharUnits(size); 328 } 329 330 /// Emit any needed decls for which code generation was deferred. 331 void emitDeferred(); 332 333 /// Helper for `emitDeferred` to apply actual codegen. 334 void emitGlobalDecl(const clang::GlobalDecl &d); 335 getTriple()336 const llvm::Triple &getTriple() const { return target.getTriple(); } 337 338 // Finalize CIR code generation. 339 void release(); 340 341 /// ------- 342 /// Visibility and Linkage 343 /// ------- 344 345 static mlir::SymbolTable::Visibility 346 getMLIRVisibilityFromCIRLinkage(cir::GlobalLinkageKind GLK); 347 static cir::VisibilityKind getGlobalVisibilityKindFromClangVisibility( 348 clang::VisibilityAttr::VisibilityType visibility); 349 cir::VisibilityAttr getGlobalVisibilityAttrFromDecl(const Decl *decl); 350 static mlir::SymbolTable::Visibility getMLIRVisibility(cir::GlobalOp op); 351 cir::GlobalLinkageKind getFunctionLinkage(GlobalDecl gd); 352 cir::GlobalLinkageKind getCIRLinkageForDeclarator(const DeclaratorDecl *dd, 353 GVALinkage linkage, 354 bool isConstantVariable); setFunctionLinkage(GlobalDecl gd,cir::FuncOp f)355 void setFunctionLinkage(GlobalDecl gd, cir::FuncOp f) { 356 cir::GlobalLinkageKind l = getFunctionLinkage(gd); 357 f.setLinkageAttr(cir::GlobalLinkageKindAttr::get(&getMLIRContext(), l)); 358 mlir::SymbolTable::setSymbolVisibility(f, 359 getMLIRVisibilityFromCIRLinkage(l)); 360 } 361 362 cir::GlobalLinkageKind getCIRLinkageVarDefinition(const VarDecl *vd, 363 bool isConstant); 364 365 void addReplacement(llvm::StringRef name, mlir::Operation *op); 366 367 /// Helpers to emit "not yet implemented" error diagnostics 368 DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef); 369 370 template <typename T> errorNYI(SourceLocation loc,llvm::StringRef feature,const T & name)371 DiagnosticBuilder errorNYI(SourceLocation loc, llvm::StringRef feature, 372 const T &name) { 373 unsigned diagID = 374 diags.getCustomDiagID(DiagnosticsEngine::Error, 375 "ClangIR code gen Not Yet Implemented: %0: %1"); 376 return diags.Report(loc, diagID) << feature << name; 377 } 378 errorNYI(mlir::Location loc,llvm::StringRef feature)379 DiagnosticBuilder errorNYI(mlir::Location loc, llvm::StringRef feature) { 380 // TODO: Convert the location to a SourceLocation 381 unsigned diagID = diags.getCustomDiagID( 382 DiagnosticsEngine::Error, "ClangIR code gen Not Yet Implemented: %0"); 383 return diags.Report(diagID) << feature; 384 } 385 errorNYI(llvm::StringRef feature)386 DiagnosticBuilder errorNYI(llvm::StringRef feature) const { 387 // TODO: Make a default location? currSrcLoc? 388 unsigned diagID = diags.getCustomDiagID( 389 DiagnosticsEngine::Error, "ClangIR code gen Not Yet Implemented: %0"); 390 return diags.Report(diagID) << feature; 391 } 392 393 DiagnosticBuilder errorNYI(SourceRange, llvm::StringRef); 394 395 template <typename T> errorNYI(SourceRange loc,llvm::StringRef feature,const T & name)396 DiagnosticBuilder errorNYI(SourceRange loc, llvm::StringRef feature, 397 const T &name) { 398 return errorNYI(loc.getBegin(), feature, name) << loc; 399 } 400 401 private: 402 // An ordered map of canonical GlobalDecls to their mangled names. 403 llvm::MapVector<clang::GlobalDecl, llvm::StringRef> mangledDeclNames; 404 llvm::StringMap<clang::GlobalDecl, llvm::BumpPtrAllocator> manglings; 405 406 // FIXME: should we use llvm::TrackingVH<mlir::Operation> here? 407 typedef llvm::StringMap<mlir::Operation *> ReplacementsTy; 408 ReplacementsTy replacements; 409 /// Call replaceAllUsesWith on all pairs in replacements. 410 void applyReplacements(); 411 412 /// A helper function to replace all uses of OldF to NewF that replace 413 /// the type of pointer arguments. This is not needed to tradtional 414 /// pipeline since LLVM has opaque pointers but CIR not. 415 void replacePointerTypeArgs(cir::FuncOp oldF, cir::FuncOp newF); 416 417 void setNonAliasAttributes(GlobalDecl gd, mlir::Operation *op); 418 }; 419 } // namespace CIRGen 420 421 } // namespace clang 422 423 #endif // LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENMODULE_H 424