blob: 1be8f3f6b32d907b96f03c5ec631ebe4bdce4324 [file] [log] [blame]
//===--- CIRGenModule.h - Per-Module state for CIR gen ----------*- C++ -*-===//
//
// 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.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_LIB_CODEGEN_CIRGENMODULE_H
#define LLVM_CLANG_LIB_CODEGEN_CIRGENMODULE_H
#include "CIRGenBuilder.h"
#include "CIRGenCall.h"
#include "CIRGenOpenCLRuntime.h"
#include "CIRGenTypeCache.h"
#include "CIRGenTypes.h"
#include "CIRGenVTables.h"
#include "CIRGenValue.h"
#include "clang/CIR/MissingFeatures.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
#include "clang/CIR/Dialect/IR/CIRDataLayout.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
#include "clang/CIR/Interfaces/CIROpInterfaces.h"
#include "llvm/ADT/ScopedHashTable.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/IR/Value.h"
using namespace clang;
namespace cir {
class CIRGenFunction;
class CIRGenCXXABI;
class TargetCIRGenInfo;
class CIRGenOpenMPRuntime;
enum ForDefinition_t : bool { NotForDefinition = false, ForDefinition = true };
/// Implementation of a CIR/MLIR emission from Clang AST.
///
/// This will emit operations that are specific to C(++)/ObjC(++) language,
/// preserving the semantics of the language and (hopefully) allow to perform
/// accurate analysis and transformation based on these high level semantics.
class CIRGenModule : public CIRGenTypeCache {
CIRGenModule(CIRGenModule &) = delete;
CIRGenModule &operator=(CIRGenModule &) = delete;
public:
CIRGenModule(mlir::MLIRContext &context, clang::ASTContext &astctx,
const clang::CodeGenOptions &CGO,
clang::DiagnosticsEngine &Diags);
~CIRGenModule();
const std::string &getModuleNameHash() const { return ModuleNameHash; }
private:
mutable std::unique_ptr<TargetCIRGenInfo> TheTargetCIRGenInfo;
/// The builder is a helper class to create IR inside a function. The
/// builder is stateful, in particular it keeps an "insertion point": this
/// is where the next operations will be introduced.
CIRGenBuilderTy builder;
/// Hold Clang AST information.
clang::ASTContext &astCtx;
const clang::LangOptions &langOpts;
const clang::CodeGenOptions &codeGenOpts;
/// A "module" matches a c/cpp source file: containing a list of functions.
mlir::ModuleOp theModule;
clang::DiagnosticsEngine &Diags;
const clang::TargetInfo &target;
std::unique_ptr<CIRGenCXXABI> ABI;
/// Used for `UniqueInternalLinkageNames` option
std::string ModuleNameHash = "";
/// Per-module type mapping from clang AST to CIR.
CIRGenTypes genTypes;
/// Holds information about C++ vtables.
CIRGenVTables VTables;
/// Holds the OpenCL runtime
std::unique_ptr<CIRGenOpenCLRuntime> openCLRuntime;
/// Holds the OpenMP runtime
std::unique_ptr<CIRGenOpenMPRuntime> openMPRuntime;
/// Per-function codegen information. Updated everytime buildCIR is called
/// for FunctionDecls's.
CIRGenFunction *CurCGF = nullptr;
// A set of references that have only been set via a weakref so far. This is
// used to remove the weak of the reference if we ever see a direct reference
// or a definition.
llvm::SmallPtrSet<mlir::Operation *, 10> WeakRefReferences;
/// -------
/// Declaring variables
/// -------
/// Set of global decls for which we already diagnosed mangled name conflict.
/// Required to not issue a warning (on a mangling conflict) multiple times
/// for the same decl.
llvm::DenseSet<clang::GlobalDecl> DiagnosedConflictingDefinitions;
public:
mlir::ModuleOp getModule() const { return theModule; }
CIRGenBuilderTy &getBuilder() { return builder; }
clang::ASTContext &getASTContext() const { return astCtx; }
const clang::TargetInfo &getTarget() const { return target; }
const clang::CodeGenOptions &getCodeGenOpts() const { return codeGenOpts; }
clang::DiagnosticsEngine &getDiags() const { return Diags; }
CIRGenTypes &getTypes() { return genTypes; }
const clang::LangOptions &getLangOpts() const { return langOpts; }
CIRGenFunction *getCurrCIRGenFun() const { return CurCGF; }
const CIRDataLayout getDataLayout() const {
// FIXME(cir): instead of creating a CIRDataLayout every time, set it as an
// attribute for the CIRModule class.
return {theModule};
}
CIRGenCXXABI &getCXXABI() const { return *ABI; }
/// -------
/// Handling globals
/// -------
// TODO(cir): does this really need to be a state for CIR emission?
GlobalDecl initializedGlobalDecl;
/// Global variables with initializers that need to run before main.
/// TODO(cir): for now track a generation operation, this is so far only
/// used to sync with DelayedCXXInitPosition. Improve it when we actually
/// use function calls for initialization
std::vector<mlir::Operation *> CXXGlobalInits;
/// Emit the function that initializes C++ globals.
void buildCXXGlobalInitFunc();
/// Track whether the CIRGenModule is currently building an initializer
/// for a global (e.g. as opposed to a regular cir.func).
mlir::cir::GlobalOp globalOpContext = nullptr;
/// When a C++ decl with an initializer is deferred, null is
/// appended to CXXGlobalInits, and the index of that null is placed
/// here so that the initializer will be performed in the correct
/// order. Once the decl is emitted, the index is replaced with ~0U to ensure
/// that we don't re-emit the initializer.
llvm::DenseMap<const Decl *, unsigned> DelayedCXXInitPosition;
/// Keep track of a map between lambda fields and names, this needs to be per
/// module since lambdas might get generated later as part of defered work,
/// and since the pointers are supposed to be uniqued, should be fine. Revisit
/// this if it ends up taking too much memory.
llvm::DenseMap<const clang::FieldDecl *, llvm::StringRef> LambdaFieldToName;
/// If the declaration has internal linkage but is inside an
/// extern "C" linkage specification, prepare to emit an alias for it
/// to the expected name.
template <typename SomeDecl>
void maybeHandleStaticInExternC(const SomeDecl *D, mlir::cir::GlobalOp GV);
/// Tell the consumer that this variable has been instantiated.
void HandleCXXStaticMemberVarInstantiation(VarDecl *VD);
llvm::DenseMap<const Decl *, mlir::cir::GlobalOp> StaticLocalDeclMap;
llvm::DenseMap<StringRef, mlir::Value> Globals;
mlir::Operation *getGlobalValue(StringRef Ref);
mlir::Value getGlobalValue(const clang::Decl *D);
/// If the specified mangled name is not in the module, create and return an
/// mlir::GlobalOp value
mlir::cir::GlobalOp
getOrCreateCIRGlobal(StringRef MangledName, mlir::Type Ty, LangAS AddrSpace,
const VarDecl *D,
ForDefinition_t IsForDefinition = NotForDefinition);
mlir::cir::GlobalOp getStaticLocalDeclAddress(const VarDecl *D) {
return StaticLocalDeclMap[D];
}
void setStaticLocalDeclAddress(const VarDecl *D, mlir::cir::GlobalOp C) {
StaticLocalDeclMap[D] = C;
}
mlir::cir::GlobalOp
getOrCreateStaticVarDecl(const VarDecl &D,
mlir::cir::GlobalLinkageKind Linkage);
mlir::cir::GlobalOp buildGlobal(const VarDecl *D, mlir::Type Ty,
ForDefinition_t IsForDefinition);
/// TODO(cir): once we have cir.module, add this as a convenience method
/// there instead of here.
///
/// Look up the specified global in the module symbol table.
/// 1. If it does not exist, add a declaration of the global and return it.
/// 2. Else, the global exists but has the wrong type: return the function
/// with a constantexpr cast to the right type.
/// 3. Finally, if the existing global is the correct declaration, return
/// the existing global.
mlir::cir::GlobalOp getOrInsertGlobal(
mlir::Location loc, StringRef Name, mlir::Type Ty,
llvm::function_ref<mlir::cir::GlobalOp()> CreateGlobalCallback);
// Overload to construct a global variable using its constructor's defaults.
mlir::cir::GlobalOp getOrInsertGlobal(mlir::Location loc, StringRef Name,
mlir::Type Ty);
static mlir::cir::GlobalOp
createGlobalOp(CIRGenModule &CGM, mlir::Location loc, StringRef name,
mlir::Type t, bool isCst = false,
mlir::cir::AddressSpaceAttr addrSpace = {},
mlir::Operation *insertPoint = nullptr);
// FIXME: Hardcoding priority here is gross.
void AddGlobalCtor(mlir::cir::FuncOp Ctor, int Priority = 65535);
void AddGlobalDtor(mlir::cir::FuncOp Dtor, int Priority = 65535,
bool IsDtorAttrFunc = false);
/// Return the mlir::Value for the address of the given global variable.
/// If Ty is non-null and if the global doesn't exist, then it will be created
/// with the specified type instead of whatever the normal requested type
/// would be. If IsForDefinition is true, it is guaranteed that an actual
/// global with type Ty will be returned, not conversion of a variable with
/// the same mangled name but some other type.
mlir::Value
getAddrOfGlobalVar(const VarDecl *D, mlir::Type Ty = {},
ForDefinition_t IsForDefinition = NotForDefinition);
/// Return the mlir::GlobalViewAttr for the address of the given global.
mlir::cir::GlobalViewAttr
getAddrOfGlobalVarAttr(const VarDecl *D, mlir::Type Ty = {},
ForDefinition_t IsForDefinition = NotForDefinition);
/// Get a reference to the target of VD.
mlir::Operation *getWeakRefReference(const ValueDecl *VD);
CharUnits
computeNonVirtualBaseClassOffset(const CXXRecordDecl *DerivedClass,
CastExpr::path_const_iterator Start,
CastExpr::path_const_iterator End);
/// Get the CIR attributes and calling convention to use for a particular
/// function type.
///
/// \param Name - The function name.
/// \param Info - The function type information.
/// \param CalleeInfo - The callee information these attributes are being
/// constructed for. If valid, the attributes applied to this decl may
/// contribute to the function attributes and calling convention.
/// \param Attrs [out] - On return, the attribute list to use.
void ConstructAttributeList(StringRef Name, const CIRGenFunctionInfo &Info,
CIRGenCalleeInfo CalleeInfo,
mlir::DictionaryAttr &Attrs, bool AttrOnCallSite,
bool IsThunk);
/// Will return a global variable of the given type. If a variable with a
/// different type already exists then a new variable with the right type
/// will be created and all uses of the old variable will be replaced with a
/// bitcast to the new variable.
mlir::cir::GlobalOp createOrReplaceCXXRuntimeVariable(
mlir::Location loc, StringRef Name, mlir::Type Ty,
mlir::cir::GlobalLinkageKind Linkage, clang::CharUnits Alignment);
/// Emit any vtables which we deferred and still have a use for.
void buildDeferredVTables();
bool shouldOpportunisticallyEmitVTables();
void setDSOLocal(mlir::cir::CIRGlobalValueInterface GV) const;
/// Return the appropriate linkage for the vtable, VTT, and type information
/// of the given class.
mlir::cir::GlobalLinkageKind getVTableLinkage(const CXXRecordDecl *RD);
/// Emit type metadata for the given vtable using the given layout.
void buildVTableTypeMetadata(const CXXRecordDecl *RD,
mlir::cir::GlobalOp VTable,
const VTableLayout &VTLayout);
/// Get the address of the RTTI descriptor for the given type.
mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc, QualType Ty,
bool ForEH = false);
/// TODO(cir): add CIR visibility bits.
static mlir::SymbolTable::Visibility getCIRVisibility(Visibility V) {
switch (V) {
case DefaultVisibility:
return mlir::SymbolTable::Visibility::Public;
case HiddenVisibility:
return mlir::SymbolTable::Visibility::Private;
case ProtectedVisibility:
llvm_unreachable("NYI");
}
llvm_unreachable("unknown visibility!");
}
llvm::DenseMap<mlir::Attribute, mlir::cir::GlobalOp> ConstantStringMap;
/// Return a constant array for the given string.
mlir::Attribute getConstantArrayFromStringLiteral(const StringLiteral *E);
/// Return a global symbol reference to a constant array for the given string
/// literal.
mlir::cir::GlobalViewAttr
getAddrOfConstantStringFromLiteral(const StringLiteral *S,
StringRef Name = ".str");
unsigned StringLiteralCnt = 0;
unsigned CompoundLitaralCnt = 0;
/// Return the unique name for global compound literal
std::string createGlobalCompoundLiteralName() {
return (Twine(".compoundLiteral.") + Twine(CompoundLitaralCnt++)).str();
}
/// Return the AST address space of the underlying global variable for D, as
/// determined by its declaration. Normally this is the same as the address
/// space of D's type, but in CUDA, address spaces are associated with
/// declarations, not types. If D is nullptr, return the default address
/// space for global variable.
///
/// For languages without explicit address spaces, if D has default address
/// space, target-specific global or constant address space may be returned.
LangAS getGlobalVarAddressSpace(const VarDecl *D);
/// Return the AST address space of constant literal, which is used to emit
/// the constant literal as global variable in LLVM IR.
/// Note: This is not necessarily the address space of the constant literal
/// in AST. For address space agnostic language, e.g. C++, constant literal
/// in AST is always in default address space.
LangAS getGlobalConstantAddressSpace() const;
/// Returns the address space for temporary allocations in the language. This
/// ensures that the allocated variable's address space matches the
/// expectations of the AST, rather than using the target's allocation address
/// space, which may lead to type mismatches in other parts of the IR.
LangAS getLangTempAllocaAddressSpace() const;
/// Set attributes which are common to any form of a global definition (alias,
/// Objective-C method, function, global variable).
///
/// NOTE: This should only be called for definitions.
void setCommonAttributes(GlobalDecl GD, mlir::Operation *GV);
// TODO: this obviously overlaps with
const TargetCIRGenInfo &getTargetCIRGenInfo();
/// Helpers to convert Clang's SourceLocation to a MLIR Location.
mlir::Location getLoc(clang::SourceLocation SLoc);
mlir::Location getLoc(clang::SourceRange SLoc);
mlir::Location getLoc(mlir::Location lhs, mlir::Location rhs);
/// Helper to convert Clang's alignment to CIR alignment
mlir::IntegerAttr getSize(CharUnits size);
/// Returns whether the given record has public LTO visibility (regardless of
/// -lto-whole-program-visibility) and therefore may not participate in
/// (single-module) CFI and whole-program vtable optimization.
bool AlwaysHasLTOVisibilityPublic(const CXXRecordDecl *RD);
/// Returns whether the given record has hidden LTO visibility and therefore
/// may participate in (single-module) CFI and whole-program vtable
/// optimization.
bool HasHiddenLTOVisibility(const CXXRecordDecl *RD);
/// Determine whether an object of this type can be emitted
/// as a constant.
///
/// If ExcludeCtor is true, the duration when the object's constructor runs
/// will not be considered. The caller will need to verify that the object is
/// not written to during its construction.
/// FIXME: in LLVM codegen path this is part of CGM, which doesn't seem
/// like necessary, since (1) it doesn't use CGM at all and (2) is AST type
/// query specific.
bool isTypeConstant(clang::QualType Ty, bool ExcludeCtor, bool ExcludeDtor);
/// FIXME: this could likely be a common helper and not necessarily related
/// with codegen.
/// Return the best known alignment for an unknown pointer to a
/// particular class.
clang::CharUnits getClassPointerAlignment(const clang::CXXRecordDecl *RD);
/// FIXME: this could likely be a common helper and not necessarily related
/// with codegen.
/// TODO: Add TBAAAccessInfo
clang::CharUnits getNaturalPointeeTypeAlignment(clang::QualType T,
LValueBaseInfo *BaseInfo);
/// FIXME: this could likely be a common helper and not necessarily related
/// with codegen.
/// TODO: Add TBAAAccessInfo
clang::CharUnits getNaturalTypeAlignment(clang::QualType T,
LValueBaseInfo *BaseInfo = nullptr,
bool forPointeeType = false);
/// TODO: Add TBAAAccessInfo
clang::CharUnits
getDynamicOffsetAlignment(clang::CharUnits actualBaseAlign,
const clang::CXXRecordDecl *baseDecl,
clang::CharUnits expectedTargetAlign);
mlir::cir::FuncOp getAddrOfCXXStructor(
clang::GlobalDecl GD, const CIRGenFunctionInfo *FnInfo = nullptr,
mlir::cir::FuncType FnType = nullptr, bool DontDefer = false,
ForDefinition_t IsForDefinition = NotForDefinition) {
return getAddrAndTypeOfCXXStructor(GD, FnInfo, FnType, DontDefer,
IsForDefinition)
.second;
}
/// A queue of (optional) vtables to consider emitting.
std::vector<const clang::CXXRecordDecl *> DeferredVTables;
mlir::Type getVTableComponentType();
CIRGenVTables &getVTables() { return VTables; }
ItaniumVTableContext &getItaniumVTableContext() {
return VTables.getItaniumVTableContext();
}
const ItaniumVTableContext &getItaniumVTableContext() const {
return VTables.getItaniumVTableContext();
}
/// This contains all the decls which have definitions but which are deferred
/// for emission and therefore should only be output if they are actually
/// used. If a decl is in this, then it is known to have not been referenced
/// yet.
std::map<llvm::StringRef, clang::GlobalDecl> DeferredDecls;
// This is a list of deferred decls which we have seen that *are* actually
// referenced. These get code generated when the module is done.
std::vector<clang::GlobalDecl> DeferredDeclsToEmit;
void addDeferredDeclToEmit(clang::GlobalDecl GD) {
DeferredDeclsToEmit.emplace_back(GD);
}
// After HandleTranslation finishes, differently from DeferredDeclsToEmit,
// DefaultMethodsToEmit is only called after a set of CIR passes run. See
// addDefaultMethodsToEmit usage for examples.
std::vector<clang::GlobalDecl> DefaultMethodsToEmit;
void addDefaultMethodsToEmit(clang::GlobalDecl GD) {
DefaultMethodsToEmit.emplace_back(GD);
}
std::pair<mlir::cir::FuncType, mlir::cir::FuncOp> getAddrAndTypeOfCXXStructor(
clang::GlobalDecl GD, const CIRGenFunctionInfo *FnInfo = nullptr,
mlir::cir::FuncType FnType = nullptr, bool Dontdefer = false,
ForDefinition_t IsForDefinition = NotForDefinition);
void buildTopLevelDecl(clang::Decl *decl);
void buildLinkageSpec(const LinkageSpecDecl *D);
/// Emit code for a single global function or var decl. Forward declarations
/// are emitted lazily.
void buildGlobal(clang::GlobalDecl D);
bool tryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D);
void buildAliasForGlobal(StringRef mangledName, mlir::Operation *op,
GlobalDecl aliasGD, mlir::cir::FuncOp aliasee,
mlir::cir::GlobalLinkageKind linkage);
mlir::Type getCIRType(const clang::QualType &type);
/// Set the visibility for the given global.
void setGlobalVisibility(mlir::Operation *Op, const NamedDecl *D) const;
void setDSOLocal(mlir::Operation *Op) const;
/// Set visibility, dllimport/dllexport and dso_local.
/// This must be called after dllimport/dllexport is set.
void setGVProperties(mlir::Operation *Op, const NamedDecl *D) const;
void setGVPropertiesAux(mlir::Operation *Op, const NamedDecl *D) const;
/// Set the TLS mode for the given global Op for the thread-local
/// variable declaration D.
void setTLSMode(mlir::Operation *Op, const VarDecl &D) const;
/// Get TLS mode from CodeGenOptions.
mlir::cir::TLS_Model GetDefaultCIRTLSModel() const;
/// Replace the present global `Old` with the given global `New`. Their symbol
/// names must match; their types can be different. Usages of the old global
/// will be automatically updated if their types mismatch.
///
/// This function will erase the old global. This function will NOT insert the
/// new global into the module.
void replaceGlobal(mlir::cir::GlobalOp Old, mlir::cir::GlobalOp New);
/// Determine whether the definition must be emitted; if this returns \c
/// false, the definition can be emitted lazily if it's used.
bool MustBeEmitted(const clang::ValueDecl *D);
/// Whether this function's return type has no side effects, and thus may be
/// trivially discared if it is unused.
bool MayDropFunctionReturn(const clang::ASTContext &Context,
clang::QualType ReturnType);
bool isInNoSanitizeList(clang::SanitizerMask Kind, mlir::cir::FuncOp Fn,
clang::SourceLocation) const;
/// Determine whether the definition can be emitted eagerly, or should be
/// delayed until the end of the translation unit. This is relevant for
/// definitions whose linkage can change, e.g. implicit function instantions
/// which may later be explicitly instantiated.
bool MayBeEmittedEagerly(const clang::ValueDecl *D);
bool verifyModule();
/// Return the address of the given function. If Ty is non-null, then this
/// function will use the specified type if it has to create it.
// TODO: this is a bit weird as `GetAddr` given we give back a FuncOp?
mlir::cir::FuncOp
GetAddrOfFunction(clang::GlobalDecl GD, mlir::Type Ty = nullptr,
bool ForVTable = false, bool Dontdefer = false,
ForDefinition_t IsForDefinition = NotForDefinition);
mlir::Operation *
GetAddrOfGlobal(clang::GlobalDecl GD,
ForDefinition_t IsForDefinition = NotForDefinition);
// Return whether RTTI information should be emitted for this target.
bool shouldEmitRTTI(bool ForEH = false) {
return (ForEH || getLangOpts().RTTI) && !getLangOpts().CUDAIsDevice &&
!(getLangOpts().OpenMP && getLangOpts().OpenMPIsTargetDevice &&
getTriple().isNVPTX());
}
// C++ related functions.
void buildDeclContext(const DeclContext *DC);
/// Return the result of value-initializing the given type, i.e. a null
/// expression of the given type. This is usually, but not always, an LLVM
/// null constant.
mlir::Value buildNullConstant(QualType T, mlir::Location loc);
mlir::Value buildMemberPointerConstant(const UnaryOperator *E);
llvm::StringRef getMangledName(clang::GlobalDecl GD);
void buildTentativeDefinition(const VarDecl *D);
// Make sure that this type is translated.
void UpdateCompletedType(const clang::TagDecl *TD);
/// Set function attributes for a function declaration.
void setFunctionAttributes(GlobalDecl GD, mlir::cir::FuncOp F,
bool IsIncompleteFunction, bool IsThunk);
/// Set the CIR function attributes (sext, zext, etc).
void setCIRFunctionAttributes(GlobalDecl GD, const CIRGenFunctionInfo &info,
mlir::cir::FuncOp func, bool isThunk);
void buildGlobalDefinition(clang::GlobalDecl D,
mlir::Operation *Op = nullptr);
void buildGlobalFunctionDefinition(clang::GlobalDecl D, mlir::Operation *Op);
void buildGlobalVarDefinition(const clang::VarDecl *D,
bool IsTentative = false);
/// Emit the function that initializes the specified global
void buildCXXGlobalVarDeclInit(const VarDecl *D, mlir::cir::GlobalOp Addr,
bool PerformInit);
void buildCXXGlobalVarDeclInitFunc(const VarDecl *D, mlir::cir::GlobalOp Addr,
bool PerformInit);
void addDeferredVTable(const CXXRecordDecl *RD) {
DeferredVTables.push_back(RD);
}
/// Stored a deferred empty coverage mapping for an unused and thus
/// uninstrumented top level declaration.
void AddDeferredUnusedCoverageMapping(clang::Decl *D);
std::nullptr_t getModuleDebugInfo() { return nullptr; }
/// Emit any needed decls for which code generation was deferred.
void buildDeferred(unsigned recursionLimit);
/// Helper for `buildDeferred` to apply actual codegen.
void buildGlobalDecl(clang::GlobalDecl &D);
/// Build default methods not emitted before this point.
void buildDefaultMethods();
const llvm::Triple &getTriple() const { return target.getTriple(); }
// Finalize CIR code generation.
void Release();
bool shouldEmitFunction(clang::GlobalDecl GD);
// Produce code for this constructor/destructor. This method doesn't try to
// apply any ABI rules about which other constructors/destructors are needed
// or if they are alias to each other.
mlir::cir::FuncOp codegenCXXStructor(clang::GlobalDecl GD);
// Produce code for this constructor/destructor for global initialzation.
void codegenGlobalInitCxxStructor(const clang::VarDecl *D,
mlir::cir::GlobalOp Addr, bool NeedsCtor,
bool NeedsDtor, bool isCstStorage);
bool lookupRepresentativeDecl(llvm::StringRef MangledName,
clang::GlobalDecl &Result) const;
bool supportsCOMDAT() const;
void maybeSetTrivialComdat(const clang::Decl &D, mlir::Operation *Op);
void emitError(const llvm::Twine &message) { theModule.emitError(message); }
/// -------
/// Visibility and Linkage
/// -------
static void setInitializer(mlir::cir::GlobalOp &op, mlir::Attribute value);
static mlir::SymbolTable::Visibility
getMLIRVisibilityFromCIRLinkage(mlir::cir::GlobalLinkageKind GLK);
static mlir::cir::VisibilityKind getGlobalVisibilityKindFromClangVisibility(
clang::VisibilityAttr::VisibilityType visibility);
mlir::cir::VisibilityAttr getGlobalVisibilityAttrFromDecl(const Decl *decl);
static mlir::SymbolTable::Visibility
getMLIRVisibility(mlir::cir::GlobalOp op);
mlir::cir::GlobalLinkageKind getFunctionLinkage(GlobalDecl GD);
mlir::cir::GlobalLinkageKind
getCIRLinkageForDeclarator(const DeclaratorDecl *D, GVALinkage Linkage,
bool IsConstantVariable);
void setFunctionLinkage(GlobalDecl GD, mlir::cir::FuncOp f) {
auto L = getFunctionLinkage(GD);
f.setLinkageAttr(
mlir::cir::GlobalLinkageKindAttr::get(builder.getContext(), L));
mlir::SymbolTable::setSymbolVisibility(f,
getMLIRVisibilityFromCIRLinkage(L));
}
mlir::cir::GlobalLinkageKind getCIRLinkageVarDefinition(const VarDecl *VD,
bool IsConstant);
void addReplacement(StringRef Name, mlir::Operation *Op);
mlir::Location getLocForFunction(const clang::FunctionDecl *FD);
void ReplaceUsesOfNonProtoTypeWithRealFunction(mlir::Operation *Old,
mlir::cir::FuncOp NewFn);
void setExtraAttributesForFunc(mlir::cir::FuncOp f,
const clang::FunctionDecl *FD);
// TODO: CodeGen also passes an AttributeList here. We'll have to match that
// in CIR
mlir::cir::FuncOp
GetOrCreateCIRFunction(llvm::StringRef MangledName, mlir::Type Ty,
clang::GlobalDecl D, bool ForVTable,
bool DontDefer = false, bool IsThunk = false,
ForDefinition_t IsForDefinition = NotForDefinition,
mlir::ArrayAttr ExtraAttrs = {});
// Effectively create the CIR instruction, properly handling insertion
// points.
mlir::cir::FuncOp createCIRFunction(mlir::Location loc, StringRef name,
mlir::cir::FuncType Ty,
const clang::FunctionDecl *FD);
mlir::cir::FuncOp createRuntimeFunction(mlir::cir::FuncType Ty,
StringRef Name, mlir::ArrayAttr = {},
bool Local = false,
bool AssumeConvergent = false);
/// Emit type info if type of an expression is a variably modified
/// type. Also emit proper debug info for cast types.
void buildExplicitCastExprType(const ExplicitCastExpr *E,
CIRGenFunction *CGF = nullptr);
static constexpr const char *builtinCoroId = "__builtin_coro_id";
static constexpr const char *builtinCoroAlloc = "__builtin_coro_alloc";
static constexpr const char *builtinCoroBegin = "__builtin_coro_begin";
static constexpr const char *builtinCoroEnd = "__builtin_coro_end";
/// Given a builtin id for a function like "__builtin_fabsf", return a
/// Function* for "fabsf".
mlir::cir::FuncOp getBuiltinLibFunction(const FunctionDecl *FD,
unsigned BuiltinID);
/// Emit a general error that something can't be done.
void Error(SourceLocation loc, StringRef error);
/// Print out an error that codegen doesn't support the specified stmt yet.
void ErrorUnsupported(const Stmt *S, const char *Type);
/// Print out an error that codegen doesn't support the specified decl yet.
void ErrorUnsupported(const Decl *D, const char *Type);
/// Return a reference to the configured OpenMP runtime.
CIRGenOpenCLRuntime &getOpenCLRuntime() {
assert(openCLRuntime != nullptr);
return *openCLRuntime;
}
void createOpenCLRuntime() {
openCLRuntime.reset(new CIRGenOpenCLRuntime(*this));
}
/// Return a reference to the configured OpenMP runtime.
CIRGenOpenMPRuntime &getOpenMPRuntime() {
assert(openMPRuntime != nullptr);
return *openMPRuntime;
}
/// OpenCL v1.2 s5.6.4.6 allows the compiler to store kernel argument
/// information in the program executable. The argument information stored
/// includes the argument name, its type, the address and access qualifiers
/// used. This helper can be used to generate metadata for source code kernel
/// function as well as generated implicitly kernels. If a kernel is generated
/// implicitly null value has to be passed to the last two parameters,
/// otherwise all parameters must have valid non-null values.
/// \param FN is a pointer to IR function being generated.
/// \param FD is a pointer to function declaration if any.
/// \param CGF is a pointer to CIRGenFunction that generates this function.
void genKernelArgMetadata(mlir::cir::FuncOp FN,
const FunctionDecl *FD = nullptr,
CIRGenFunction *CGF = nullptr);
/// Emits OpenCL specific Metadata e.g. OpenCL version.
void buildOpenCLMetadata();
private:
// An ordered map of canonical GlobalDecls to their mangled names.
llvm::MapVector<clang::GlobalDecl, llvm::StringRef> MangledDeclNames;
llvm::StringMap<clang::GlobalDecl, llvm::BumpPtrAllocator> Manglings;
// FIXME: should we use llvm::TrackingVH<mlir::Operation> here?
typedef llvm::StringMap<mlir::Operation *> ReplacementsTy;
ReplacementsTy Replacements;
/// Call replaceAllUsesWith on all pairs in Replacements.
void applyReplacements();
void setNonAliasAttributes(GlobalDecl GD, mlir::Operation *GV);
/// Map source language used to a CIR attribute.
mlir::cir::SourceLanguage getCIRSourceLanguage();
};
} // namespace cir
#endif // LLVM_CLANG_LIB_CODEGEN_CIRGENMODULE_H