Files
TheRock/compiler/amd-llvm/clang/lib/CodeGen/CodeGenModule.h
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

2834 lines
114 KiB
C++

//===--- CodeGenModule.h - Per-Module state for LLVM CodeGen ----*- 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 llvm translation.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_LIB_CODEGEN_CODEGENMODULE_H
#define LLVM_CLANG_LIB_CODEGEN_CODEGENMODULE_H
#include "CGVTables.h"
#include "CodeGenTypeCache.h"
#include "CodeGenTypes.h"
#include "SanitizerMetadata.h"
#include "TrapReasonBuilder.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/GlobalDecl.h"
#include "clang/AST/Mangle.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/NoSanitizeList.h"
#include "clang/Basic/ProfileList.h"
#include "clang/Basic/StackExhaustionHandler.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/XRayLists.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Transforms/Utils/SanitizerStats.h"
#include <optional>
namespace llvm {
class Module;
class Constant;
class ConstantInt;
class Function;
class GlobalValue;
class DataLayout;
class FunctionType;
class LLVMContext;
class IndexedInstrProfReader;
namespace vfs {
class FileSystem;
}
namespace abi {
class ArgInfo;
class IRTypeMapper;
class TargetInfo;
class TypeBuilder;
} // namespace abi
}
namespace clang {
class ASTContext;
class AtomicType;
class FunctionDecl;
class IdentifierInfo;
class ObjCImplementationDecl;
class ObjCEncodeExpr;
class BlockExpr;
class CharUnits;
class Decl;
class Expr;
class Stmt;
class StringLiteral;
class NamedDecl;
class PointerAuthSchema;
class ValueDecl;
class VarDecl;
class LangOptions;
class CodeGenOptions;
class HeaderSearchOptions;
class DiagnosticsEngine;
class AnnotateAttr;
class CXXDestructorDecl;
class Module;
class CoverageSourceInfo;
class InitSegAttr;
namespace CodeGen {
class CodeGenFunction;
class CodeGenTBAA;
class CGCXXABI;
class CGDebugInfo;
class CGObjCRuntime;
class CGOpenCLRuntime;
class CGOpenMPRuntime;
class CGCUDARuntime;
class CGHLSLRuntime;
class CGFunctionInfo;
class CoverageMappingModuleGen;
class QualTypeMapper;
class TargetCodeGenInfo;
enum ForDefinition_t : bool {
NotForDefinition = false,
ForDefinition = true
};
/// The Counter with an optional additional Counter for
/// branches. `Skipped` counter can be calculated with `Executed` and
/// a common Counter (like `Parent`) as `(Parent-Executed)`.
///
/// In SingleByte mode, Counters are binary. Subtraction is not
/// applicable (but addition is capable). In this case, both
/// `Executed` and `Skipped` counters are required. `Skipped` is
/// `None` by default. It is allocated in the coverage mapping.
///
/// There might be cases that `Parent` could be induced with
/// `(Executed+Skipped)`. This is not always applicable.
class CounterPair {
public:
/// Optional value.
class ValueOpt {
private:
static constexpr uint32_t None = (1u << 31); /// None is allocated.
static constexpr uint32_t Mask = None - 1;
uint32_t Val;
public:
ValueOpt() : Val(None) {}
ValueOpt(unsigned InitVal) {
assert(!(InitVal & ~Mask));
Val = InitVal;
}
bool hasValue() const { return !(Val & None); }
operator uint32_t() const { return Val; }
};
ValueOpt Executed;
ValueOpt Skipped; /// May be None.
/// Initialized with Skipped=None.
CounterPair(unsigned Val) : Executed(Val) {}
// FIXME: Should work with {None, None}
CounterPair() : Executed(0) {}
};
struct OrderGlobalInitsOrStermFinalizers {
unsigned int priority;
unsigned int lex_order;
OrderGlobalInitsOrStermFinalizers(unsigned int p, unsigned int l)
: priority(p), lex_order(l) {}
bool operator==(const OrderGlobalInitsOrStermFinalizers &RHS) const {
return priority == RHS.priority && lex_order == RHS.lex_order;
}
bool operator<(const OrderGlobalInitsOrStermFinalizers &RHS) const {
return std::tie(priority, lex_order) <
std::tie(RHS.priority, RHS.lex_order);
}
};
struct ObjCEntrypoints {
ObjCEntrypoints() { memset(this, 0, sizeof(*this)); }
/// void objc_alloc(id);
llvm::FunctionCallee objc_alloc;
/// void objc_allocWithZone(id);
llvm::FunctionCallee objc_allocWithZone;
/// void objc_alloc_init(id);
llvm::FunctionCallee objc_alloc_init;
/// void objc_autoreleasePoolPop(void*);
llvm::FunctionCallee objc_autoreleasePoolPop;
/// void objc_autoreleasePoolPop(void*);
/// Note this method is used when we are using exception handling
llvm::FunctionCallee objc_autoreleasePoolPopInvoke;
/// void *objc_autoreleasePoolPush(void);
llvm::Function *objc_autoreleasePoolPush;
/// id objc_autorelease(id);
llvm::Function *objc_autorelease;
/// id objc_autorelease(id);
/// Note this is the runtime method not the intrinsic.
llvm::FunctionCallee objc_autoreleaseRuntimeFunction;
/// id objc_autoreleaseReturnValue(id);
llvm::Function *objc_autoreleaseReturnValue;
/// void objc_copyWeak(id *dest, id *src);
llvm::Function *objc_copyWeak;
/// void objc_destroyWeak(id*);
llvm::Function *objc_destroyWeak;
/// id objc_initWeak(id*, id);
llvm::Function *objc_initWeak;
/// id objc_loadWeak(id*);
llvm::Function *objc_loadWeak;
/// id objc_loadWeakRetained(id*);
llvm::Function *objc_loadWeakRetained;
/// void objc_moveWeak(id *dest, id *src);
llvm::Function *objc_moveWeak;
/// id objc_retain(id);
llvm::Function *objc_retain;
/// id objc_retain(id);
/// Note this is the runtime method not the intrinsic.
llvm::FunctionCallee objc_retainRuntimeFunction;
/// id objc_retainAutorelease(id);
llvm::Function *objc_retainAutorelease;
/// id objc_retainAutoreleaseReturnValue(id);
llvm::Function *objc_retainAutoreleaseReturnValue;
/// id objc_retainAutoreleasedReturnValue(id);
llvm::Function *objc_retainAutoreleasedReturnValue;
/// id objc_retainBlock(id);
llvm::Function *objc_retainBlock;
/// void objc_release(id);
llvm::Function *objc_release;
/// void objc_release(id);
/// Note this is the runtime method not the intrinsic.
llvm::FunctionCallee objc_releaseRuntimeFunction;
/// void objc_storeStrong(id*, id);
llvm::Function *objc_storeStrong;
/// id objc_storeWeak(id*, id);
llvm::Function *objc_storeWeak;
/// id objc_unsafeClaimAutoreleasedReturnValue(id);
llvm::Function *objc_unsafeClaimAutoreleasedReturnValue;
/// A void(void) inline asm to use to mark that the return value of
/// a call will be immediately retain.
llvm::InlineAsm *retainAutoreleasedReturnValueMarker;
/// void clang.arc.use(...);
llvm::Function *clang_arc_use;
/// void clang.arc.noop.use(...);
llvm::Function *clang_arc_noop_use;
};
/// This class records statistics on instrumentation based profiling.
class InstrProfStats {
uint32_t VisitedInMainFile = 0;
uint32_t MissingInMainFile = 0;
uint32_t Visited = 0;
uint32_t Missing = 0;
uint32_t Mismatched = 0;
public:
InstrProfStats() = default;
/// Record that we've visited a function and whether or not that function was
/// in the main source file.
void addVisited(bool MainFile) {
if (MainFile)
++VisitedInMainFile;
++Visited;
}
/// Record that a function we've visited has no profile data.
void addMissing(bool MainFile) {
if (MainFile)
++MissingInMainFile;
++Missing;
}
/// Record that a function we've visited has mismatched profile data.
void addMismatched(bool MainFile) { ++Mismatched; }
/// Whether or not the stats we've gathered indicate any potential problems.
bool hasDiagnostics() { return Missing || Mismatched; }
/// Report potential problems we've found to \c Diags.
void reportDiagnostics(DiagnosticsEngine &Diags, StringRef MainFile);
};
/// A pair of helper functions for a __block variable.
class BlockByrefHelpers : public llvm::FoldingSetNode {
// MSVC requires this type to be complete in order to process this
// header.
public:
llvm::Constant *CopyHelper;
llvm::Constant *DisposeHelper;
/// The alignment of the field. This is important because
/// different offsets to the field within the byref struct need to
/// have different helper functions.
CharUnits Alignment;
BlockByrefHelpers(CharUnits alignment)
: CopyHelper(nullptr), DisposeHelper(nullptr), Alignment(alignment) {}
BlockByrefHelpers(const BlockByrefHelpers &) = default;
virtual ~BlockByrefHelpers();
void Profile(llvm::FoldingSetNodeID &id) const {
id.AddInteger(Alignment.getQuantity());
profileImpl(id);
}
virtual void profileImpl(llvm::FoldingSetNodeID &id) const = 0;
virtual bool needsCopy() const { return true; }
virtual void emitCopy(CodeGenFunction &CGF, Address dest, Address src) = 0;
virtual bool needsDispose() const { return true; }
virtual void emitDispose(CodeGenFunction &CGF, Address field) = 0;
};
/// This class organizes the cross-function state that is used while generating
/// LLVM code.
class CodeGenModule : public CodeGenTypeCache {
CodeGenModule(const CodeGenModule &) = delete;
void operator=(const CodeGenModule &) = delete;
public:
struct Structor {
Structor()
: Priority(0), LexOrder(~0u), Initializer(nullptr),
AssociatedData(nullptr) {}
Structor(int Priority, unsigned LexOrder, llvm::Constant *Initializer,
llvm::Constant *AssociatedData)
: Priority(Priority), LexOrder(LexOrder), Initializer(Initializer),
AssociatedData(AssociatedData) {}
int Priority;
unsigned LexOrder;
llvm::Constant *Initializer;
llvm::Constant *AssociatedData;
};
typedef std::vector<Structor> CtorList;
enum NoLoopXteamErr {
NxSuccess,
NxNonSPMD,
NxOptionDisabled,
NxOptionDisabledOrHasCall,
NxUnsupportedDirective,
NxUnsupportedSplitDirective,
NxNoStmt,
NxUnsupportedTargetClause,
NxNotLoopDirective,
NxNotCapturedStmt,
NxNotExecutableStmt,
NxUnsupportedNestedSplitDirective,
NxSplitConstructImproperlyNested,
NxNestedOmpParallelDirective,
NxNestedOmpCall,
NxNoSingleForStmt,
NxUnsupportedLoopInit,
NxUnsupportedLoopStop,
NxUnsupportedLoopStep,
NxGuidedOrRuntimeSched,
NxNonUnitStaticChunk,
NxNonConcurrentOrder,
NxUnsupportedRedType,
NxUnsupportedRedIntSize,
NxNotScalarRed,
NxNotBinOpRed,
NxUnsupportedRedOp,
NxNoRedVar,
NxMultRedVar,
NxUnsupportedRedExpr,
NxUnsupportedXteamRedThreadLimit,
NxUnsupportedPseudoObject,
NxNotRedVarInBinOpRHS,
NxNotAddOpInBinOpRHs,
NxRhsOfAssignNotBinOpOrCall,
NxBinOpNotAddAssignOrAssign,
NxNotBinOpOrCallButAccessesRedVar,
NxNotArgScalarEval,
NxReductionOpNotBinAssign,
NxReductionOpRhsNotBinOrCond,
NxReductionOpRhsNotMinMaxSum,
NxNotBuiltinByNameInHostCompile,
NxNotBuiltinByNameInDeviceCompile,
NxPOExprCountNotOne,
NxPOSemanticExprNotCall,
NxChildOfCallIsNull,
NxMultiDeviceMinMaxNotSupported,
NxFastReductionMinMaxNotSupported,
NxScanMinMaxNotSupported,
NxAmbiguousRedKind
};
using Stmt2StmtMap = llvm::DenseMap<const Stmt *, const Stmt *>;
/// Top-level and nested OpenMP directives, used in optimized kernel codegen.
using OptKernelNestDirectives =
llvm::SmallVector<const OMPExecutableDirective *, 3>;
/// Metadata for NoLoop kernel codegen
struct NoLoopKernelInfo {
NoLoopKernelInfo(int BlkSz, OptKernelNestDirectives Dirs)
: BlockSize{BlkSz}, NoLoopNestDirs{Dirs} {}
int BlockSize; // Cached blocksize
OptKernelNestDirectives NoLoopNestDirs;
};
/// Map construct statement to corresponding metadata for a NoLoop kernel.
using NoLoopKernelMap = llvm::DenseMap<const Stmt *, NoLoopKernelInfo>;
/// Xteam reduction operators supported today.
enum XteamRedOpKind {
XR_OP_unknown = 0,
// Valid values must be power of 2.
XR_OP_add = 1,
XR_OP_min = 2,
XR_OP_max = 4
};
/// Map a reduction variable to the corresponding metadata. The metadata
/// contains
// the reduction expression, the coorresponding Xteam local aggregator var,
// and the start arg position in the offloading function signature.
struct XteamRedVarInfo {
XteamRedVarInfo(const Expr *E, Address A, size_t Pos)
: RedVarExpr(E), RedVarAddr(A), ArgPos(Pos), Opcode(XR_OP_unknown) {}
XteamRedVarInfo() = delete;
/// Reduction variable expression, populated during initial analysis
const Expr *RedVarExpr;
/// Address of local reduction variable used in device codegen.
Address RedVarAddr;
/// Argument position for the corresponding metadata in the outlined
/// signature, populated during signature generation. Used for device
/// codegen only.
size_t ArgPos;
/// Reduction operator type: currently one of add, min, and max.
XteamRedOpKind Opcode;
};
using XteamRedVarMap = llvm::DenseMap<const VarDecl *, XteamRedVarInfo>;
using XteamRedVarVecTy = llvm::SmallVector<const VarDecl *>;
struct XteamRedKernelInfo {
XteamRedKernelInfo(llvm::Value *TSI, llvm::Value *NT, int BlkSz,
OptKernelNestDirectives Dirs, XteamRedVarMap RVM,
XteamRedVarVecTy RVV, bool F)
: ThreadStartIndex{TSI}, NumTeams{NT}, BlockSize{BlkSz},
XteamNestDirs{Dirs}, XteamRedVars{RVM}, XteamOrderedRedVar{RVV},
IsFast{F} {}
/// Start index of every thread used in device codegen.
llvm::Value *ThreadStartIndex;
/// Number of teams used in device codegen.
llvm::Value *NumTeams;
/// Number of threads in a block, populated during device codegen.
int BlockSize;
/// A mask of the reduction operators found in this kernel, populated
/// according to XteamRedOpKind.
uint8_t OpKindsFound;
/// Nested directives, generated during analysis in both host/device
/// codegen.
OptKernelNestDirectives XteamNestDirs;
/// Map from reduction variable to metadata, populated during analysis.
XteamRedVarMap XteamRedVars;
/// Vector of reduction variables in the same order they appear in the AST
XteamRedVarVecTy XteamOrderedRedVar;
/// Can a fast-atomic-based-version be generated?
bool IsFast;
};
using XteamRedKernelMap = llvm::DenseMap<const Stmt *, XteamRedKernelInfo>;
struct XteamRedCollectionInfo {
XteamRedCollectionInfo(XteamRedVarMap VarMap, XteamRedVarVecTy VarVec,
uint8_t Ops)
: RedVarMap(VarMap), RedVarVector(VarVec), OpKindsFound(Ops) {}
XteamRedVarMap RedVarMap;
XteamRedVarVecTy RedVarVector;
uint8_t OpKindsFound;
};
/// Metadata for multi-device kernel codegen
struct MultiDeviceBoundsInfo {
MultiDeviceBoundsInfo(VarDecl *LBArg, VarDecl *UBArg)
: LBArg{LBArg}, UBArg{UBArg} {}
VarDecl *LBArg;
VarDecl *UBArg;
};
using MultiDeviceFunctionBoundsMap =
llvm::DenseMap<const llvm::Function *, MultiDeviceBoundsInfo>;
struct MultiDeviceKernelInfo {
MultiDeviceKernelInfo(OptKernelNestDirectives Dirs,
MultiDeviceFunctionBoundsMap FBM,
bool CanBeMultiDevice)
: MultiDeviceNestDirs{Dirs}, FunctionBoundsMap{FBM},
CanBeMultiDevice{CanBeMultiDevice} {}
OptKernelNestDirectives MultiDeviceNestDirs;
MultiDeviceFunctionBoundsMap FunctionBoundsMap;
bool CanBeMultiDevice;
bool NewBoundsHaveBeenUsed = false;
};
/// Map construct statement to corresponding metadata for a NoLoop kernel.
using MultiDeviceKernelMap =
llvm::DenseMap<const Stmt *, MultiDeviceKernelInfo>;
private:
ASTContext &Context;
const LangOptions &LangOpts;
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS; // Only used for debug info.
const HeaderSearchOptions &HeaderSearchOpts; // Only used for debug info.
const PreprocessorOptions &PreprocessorOpts; // Only used for debug info.
const CodeGenOptions &CodeGenOpts;
unsigned NumAutoVarInit = 0;
llvm::Module &TheModule;
DiagnosticsEngine &Diags;
const TargetInfo &Target;
std::unique_ptr<CGCXXABI> ABI;
llvm::LLVMContext &VMContext;
std::string ModuleNameHash;
bool CXX20ModuleInits = false;
std::unique_ptr<CodeGenTBAA> TBAA;
/// Used by emitParallelCall
bool isSPMDExecutionMode = false;
/// Used by Xteam Scan Codegen
bool isXteamScanCandidate = false;
mutable std::unique_ptr<TargetCodeGenInfo> TheTargetCodeGenInfo;
/// Cached LLVMABI target lowering info, lazily constructed when the
/// experimental ABI lowering path is taken.
mutable std::unique_ptr<llvm::abi::TargetInfo> TheLLVMABITargetInfo;
/// Allocator and mappers used by the experimental LLVMABI-based lowering
/// path (gated on -fexperimental-abi-lowering). Constructed unconditionally
/// so the path can be entered without re-checking initialization, but the
/// caches stay empty when the flag is off.
llvm::BumpPtrAllocator AbiAlloc;
std::unique_ptr<QualTypeMapper> AbiMapper;
std::unique_ptr<llvm::abi::IRTypeMapper> AbiReverseMapper;
// This should not be moved earlier, since its initialization depends on some
// of the previous reference members being already initialized and also checks
// if TheTargetCodeGenInfo is NULL
std::unique_ptr<CodeGenTypes> Types;
/// Holds information about C++ vtables.
CodeGenVTables VTables;
std::unique_ptr<CGObjCRuntime> ObjCRuntime;
std::unique_ptr<CGOpenCLRuntime> OpenCLRuntime;
std::unique_ptr<CGOpenMPRuntime> OpenMPRuntime;
std::unique_ptr<CGCUDARuntime> CUDARuntime;
std::unique_ptr<CGHLSLRuntime> HLSLRuntime;
std::unique_ptr<CGDebugInfo> DebugInfo;
std::unique_ptr<ObjCEntrypoints> ObjCData;
llvm::MDNode *NoObjCARCExceptionsMetadata = nullptr;
std::unique_ptr<llvm::IndexedInstrProfReader> PGOReader;
InstrProfStats PGOStats;
std::unique_ptr<llvm::SanitizerStatReport> SanStats;
StackExhaustionHandler StackHandler;
/// Statement for which Xteam reduction code is being generated currently
const Stmt *CurrentXteamRedStmt = nullptr;
// Map associated statement from top-level to innermost level for optimized
// kernels.
Stmt2StmtMap OptKernelNestMap;
NoLoopKernelMap NoLoopKernels;
NoLoopKernelMap BigJumpLoopKernels;
XteamRedKernelMap XteamRedKernels;
MultiDeviceKernelMap MultiDeviceKernels;
// A set of references that have only been seen 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<llvm::GlobalValue*, 10> WeakRefReferences;
/// 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.
llvm::DenseMap<StringRef, GlobalDecl> DeferredDecls;
llvm::StringSet<llvm::BumpPtrAllocator> DeferredResolversToEmit;
/// 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<GlobalDecl> DeferredDeclsToEmit;
void addDeferredDeclToEmit(GlobalDecl GD) {
DeferredDeclsToEmit.emplace_back(GD);
addEmittedDeferredDecl(GD);
}
/// Decls that were DeferredDecls and have now been emitted.
llvm::DenseMap<llvm::StringRef, GlobalDecl> EmittedDeferredDecls;
void addEmittedDeferredDecl(GlobalDecl GD) {
// Reemission is only needed in incremental mode.
if (!Context.getLangOpts().IncrementalExtensions)
return;
// Assume a linkage by default that does not need reemission.
auto L = llvm::GlobalValue::ExternalLinkage;
if (llvm::isa<FunctionDecl>(GD.getDecl()))
L = getFunctionLinkage(GD);
else if (auto *VD = llvm::dyn_cast<VarDecl>(GD.getDecl()))
L = getLLVMLinkageVarDefinition(VD);
if (llvm::GlobalValue::isInternalLinkage(L) ||
llvm::GlobalValue::isLinkOnceLinkage(L) ||
llvm::GlobalValue::isWeakLinkage(L)) {
EmittedDeferredDecls[getMangledName(GD)] = GD;
}
}
/// List of alias we have emitted. Used to make sure that what they point to
/// is defined once we get to the end of the of the translation unit.
std::vector<GlobalDecl> Aliases;
/// List of multiversion functions to be emitted. This list is processed in
/// conjunction with other deferred symbols and is used to ensure that
/// multiversion function resolvers and ifuncs are defined and emitted.
std::vector<GlobalDecl> MultiVersionFuncs;
llvm::MapVector<StringRef, llvm::TrackingVH<llvm::Constant>> Replacements;
/// List of global values to be replaced with something else. Used when we
/// want to replace a GlobalValue but can't identify it by its mangled name
/// anymore (because the name is already taken).
llvm::SmallVector<std::pair<llvm::GlobalValue *, llvm::Constant *>, 8>
GlobalValReplacements;
/// Variables for which we've emitted globals containing their constant
/// values along with the corresponding globals, for opportunistic reuse.
llvm::DenseMap<const VarDecl*, llvm::GlobalVariable*> InitializerConstants;
/// 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<GlobalDecl> DiagnosedConflictingDefinitions;
/// A queue of (optional) vtables to consider emitting.
std::vector<const CXXRecordDecl*> DeferredVTables;
/// In incremental compilation, the set of vtable classes whose vtable
/// definitions were emitted into a previous PTU's module. Carried forward
/// by moveLazyEmissionStates() so later PTUs skip re-defining them.
llvm::SmallPtrSet<const CXXRecordDecl *, 8> EmittedVTables;
/// A queue of (optional) vtables that may be emitted opportunistically.
std::vector<const CXXRecordDecl *> OpportunisticVTables;
/// List of global values which are required to be present in the object file;
/// bitcast to i8*. This is used for forcing visibility of symbols which may
/// otherwise be optimized out.
std::vector<llvm::WeakTrackingVH> LLVMUsed;
std::vector<llvm::WeakTrackingVH> LLVMCompilerUsed;
/// Store the list of global constructors and their respective priorities to
/// be emitted when the translation unit is complete.
CtorList GlobalCtors;
/// Store the list of global destructors and their respective priorities to be
/// emitted when the translation unit is complete.
CtorList GlobalDtors;
/// An ordered map of canonical GlobalDecls to their mangled names.
llvm::MapVector<GlobalDecl, StringRef> MangledDeclNames;
llvm::StringMap<GlobalDecl, llvm::BumpPtrAllocator> Manglings;
/// Global annotations.
std::vector<llvm::Constant*> Annotations;
// Store deferred function annotations so they can be emitted at the end with
// most up to date ValueDecl that will have all the inherited annotations.
llvm::MapVector<StringRef, const ValueDecl *> DeferredAnnotations;
/// Map used to get unique annotation strings.
llvm::StringMap<llvm::Constant*> AnnotationStrings;
/// Used for uniquing of annotation arguments.
llvm::DenseMap<unsigned, llvm::Constant *> AnnotationArgs;
llvm::StringMap<llvm::GlobalVariable *> CFConstantStringMap;
llvm::DenseMap<llvm::Constant *, llvm::GlobalVariable *> ConstantStringMap;
llvm::DenseMap<const UnnamedGlobalConstantDecl *, llvm::GlobalVariable *>
UnnamedGlobalConstantDeclMap;
llvm::DenseMap<const Decl*, llvm::Constant *> StaticLocalDeclMap;
llvm::DenseMap<const Decl*, llvm::GlobalVariable*> StaticLocalDeclGuardMap;
llvm::DenseMap<const Expr*, llvm::Constant *> MaterializedGlobalTemporaryMap;
llvm::DenseMap<QualType, llvm::Constant *> AtomicSetterHelperFnMap;
llvm::DenseMap<QualType, llvm::Constant *> AtomicGetterHelperFnMap;
/// Map used to get unique type descriptor constants for sanitizers.
llvm::DenseMap<QualType, llvm::Constant *> TypeDescriptorMap;
/// Map used to track internal linkage functions declared within
/// extern "C" regions.
typedef llvm::MapVector<IdentifierInfo *,
llvm::GlobalValue *> StaticExternCMap;
StaticExternCMap StaticExternCValues;
/// thread_local variables defined or used in this TU.
std::vector<const VarDecl *> CXXThreadLocals;
/// thread_local variables with initializers that need to run
/// before any thread_local variable in this TU is odr-used.
std::vector<llvm::Function *> CXXThreadLocalInits;
std::vector<const VarDecl *> CXXThreadLocalInitVars;
/// Global variables with initializers that need to run before main.
std::vector<llvm::Function *> CXXGlobalInits;
/// 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;
/// To remember which types did require a vector deleting destructor body.
/// This set basically contains classes that have virtual destructor and new[]
/// was emitted for the class.
llvm::SmallPtrSet<const CXXRecordDecl *, 16> RequireVectorDeletingDtor;
typedef std::pair<OrderGlobalInitsOrStermFinalizers, llvm::Function *>
GlobalInitData;
// When a tail call is performed on an "undefined" symbol, on PPC without pc
// relative feature, the tail call is not allowed. In "EmitCall" for such
// tail calls, the "undefined" symbols may be forward declarations, their
// definitions are provided in the module after the callsites. For such tail
// calls, diagnose message should not be emitted.
llvm::SmallSetVector<std::pair<const FunctionDecl *, SourceLocation>, 4>
MustTailCallUndefinedGlobals;
struct GlobalInitPriorityCmp {
bool operator()(const GlobalInitData &LHS,
const GlobalInitData &RHS) const {
return LHS.first.priority < RHS.first.priority;
}
};
/// Global variables with initializers whose order of initialization is set by
/// init_priority attribute.
SmallVector<GlobalInitData, 8> PrioritizedCXXGlobalInits;
/// Global destructor functions and arguments that need to run on termination.
/// When UseSinitAndSterm is set, it instead contains sterm finalizer
/// functions, which also run on unloading a shared library.
typedef std::tuple<llvm::FunctionType *, llvm::WeakTrackingVH,
llvm::Constant *>
CXXGlobalDtorsOrStermFinalizer_t;
SmallVector<CXXGlobalDtorsOrStermFinalizer_t, 8>
CXXGlobalDtorsOrStermFinalizers;
typedef std::pair<OrderGlobalInitsOrStermFinalizers, llvm::Function *>
StermFinalizerData;
struct StermFinalizerPriorityCmp {
bool operator()(const StermFinalizerData &LHS,
const StermFinalizerData &RHS) const {
return LHS.first.priority < RHS.first.priority;
}
};
/// Global variables with sterm finalizers whose order of initialization is
/// set by init_priority attribute.
SmallVector<StermFinalizerData, 8> PrioritizedCXXStermFinalizers;
/// The complete set of modules that has been imported.
llvm::SetVector<clang::Module *> ImportedModules;
/// The set of modules for which the module initializers
/// have been emitted.
llvm::SmallPtrSet<clang::Module *, 16> EmittedModuleInitializers;
/// A vector of metadata strings for linker options.
SmallVector<llvm::MDNode *, 16> LinkerOptionsMetadata;
/// A vector of metadata strings for dependent libraries for ELF.
SmallVector<llvm::MDNode *, 16> ELFDependentLibraries;
/// @name Cache for Objective-C runtime types
/// @{
/// Cached reference to the class for constant strings. This value has type
/// int * but is actually an Obj-C class pointer.
llvm::WeakTrackingVH CFConstantStringClassRef;
/// The type used to describe the state of a fast enumeration in
/// Objective-C's for..in loop.
QualType ObjCFastEnumerationStateType;
/// @}
/// Lazily create the Objective-C runtime
void createObjCRuntime();
void createOpenCLRuntime();
void createOpenMPRuntime();
void createCUDARuntime();
void createHLSLRuntime();
bool isTriviallyRecursive(const FunctionDecl *F);
bool shouldEmitFunction(GlobalDecl GD);
// Whether a global variable should be emitted by CUDA/HIP host/device
// related attributes.
bool shouldEmitCUDAGlobalVar(const VarDecl *VD) const;
bool shouldOpportunisticallyEmitVTables();
/// Map used to be sure we don't emit the same CompoundLiteral twice.
llvm::DenseMap<const CompoundLiteralExpr *, llvm::GlobalVariable *>
EmittedCompoundLiterals;
/// Map of the global blocks we've emitted, so that we don't have to re-emit
/// them if the constexpr evaluator gets aggressive.
llvm::DenseMap<const BlockExpr *, llvm::Constant *> EmittedGlobalBlocks;
/// @name Cache for Blocks Runtime Globals
/// @{
llvm::Constant *NSConcreteGlobalBlock = nullptr;
llvm::Constant *NSConcreteStackBlock = nullptr;
llvm::FunctionCallee BlockObjectAssign = nullptr;
llvm::FunctionCallee BlockObjectDispose = nullptr;
llvm::Type *BlockDescriptorType = nullptr;
llvm::Type *GenericBlockLiteralType = nullptr;
struct {
int GlobalUniqueCount;
} Block;
GlobalDecl initializedGlobalDecl;
/// @}
/// void @llvm.lifetime.start(i64 %size, i8* nocapture <ptr>)
llvm::Function *LifetimeStartFn = nullptr;
/// void @llvm.lifetime.end(i64 %size, i8* nocapture <ptr>)
llvm::Function *LifetimeEndFn = nullptr;
/// void @llvm.fake.use(...)
llvm::Function *FakeUseFn = nullptr;
std::unique_ptr<SanitizerMetadata> SanitizerMD;
llvm::MapVector<const Decl *, bool> DeferredEmptyCoverageMappingDecls;
std::unique_ptr<CoverageMappingModuleGen> CoverageMapping;
/// Mapping from canonical types to their metadata identifiers. We need to
/// maintain this mapping because identifiers may be formed from distinct
/// MDNodes.
typedef llvm::DenseMap<QualType, llvm::Metadata *> MetadataTypeMap;
MetadataTypeMap MetadataIdMap;
MetadataTypeMap VirtualMetadataIdMap;
MetadataTypeMap GeneralizedMetadataIdMap;
// Helps squashing blocks of TopLevelStmtDecl into a single llvm::Function
// when used with -fincremental-extensions.
std::pair<std::unique_ptr<CodeGenFunction>, const TopLevelStmtDecl *>
GlobalTopLevelStmtBlockInFlight;
llvm::DenseMap<GlobalDecl, uint16_t> PtrAuthDiscriminatorHashes;
llvm::DenseMap<const CXXRecordDecl *, std::optional<PointerAuthQualifier>>
VTablePtrAuthInfos;
std::optional<PointerAuthQualifier>
computeVTPointerAuthentication(const CXXRecordDecl *ThisClass);
AtomicOptions AtomicOpts;
// A set of functions which should be hot-patched; see
// -fms-hotpatch-functions-file (and -list). This will nearly always be empty.
// The list is sorted for binary-searching.
std::vector<std::string> MSHotPatchFunctions;
public:
CodeGenModule(ASTContext &C, IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
const HeaderSearchOptions &headersearchopts,
const PreprocessorOptions &ppopts,
const CodeGenOptions &CodeGenOpts, llvm::Module &M,
DiagnosticsEngine &Diags,
CoverageSourceInfo *CoverageInfo = nullptr);
~CodeGenModule();
void clear();
bool isXteamScanPhaseOne = true;
llvm::SmallVector<llvm::Value *, 8> ReductionVars;
const OMPExecutableDirective *OMPPresentScanDirective = nullptr;
/// Finalize LLVM code generation.
void Release();
/// Get the current Atomic options.
AtomicOptions getAtomicOpts() { return AtomicOpts; }
/// Set the current Atomic options.
void setAtomicOpts(AtomicOptions AO) { AtomicOpts = AO; }
/// Return true if we should emit location information for expressions.
bool getExpressionLocationsEnabled() const;
/// Return a reference to the configured Objective-C runtime.
CGObjCRuntime &getObjCRuntime() {
if (!ObjCRuntime) createObjCRuntime();
return *ObjCRuntime;
}
/// Return true iff an Objective-C runtime has been configured.
bool hasObjCRuntime() { return !!ObjCRuntime; }
/// Check if the precondition thunk optimization is enabled.
/// This checks runtime support and codegen options, but does NOT check
/// whether a specific method is eligible for thunks or inline preconditions.
///
/// TODO: Add support for GNUStep as well, currently only supports NeXT
/// family.
bool isObjCDirectPreconditionThunkEnabled() const {
return getLangOpts().ObjCRuntime.allowsDirectDispatch() &&
getLangOpts().ObjCRuntime.isNeXTFamily() &&
getCodeGenOpts().ObjCDirectPreconditionThunk;
}
/// Check if a direct method should use precondition thunks at call sites.
/// Returns false if OMD is null, not a direct method, or variadic.
///
/// Variadic methods use inline preconditions instead of thunks to avoid
/// musttail complexity across different architectures.
bool shouldHavePreconditionThunk(const ObjCMethodDecl *OMD) const {
return OMD && OMD->isDirectMethod() && !OMD->isVariadic() &&
isObjCDirectPreconditionThunkEnabled();
}
/// Check if a direct method should have inline precondition checks at call
/// sites.
/// Returns false if OMD is null, not a direct method, or not variadic.
///
/// Variadic direct methods use inline preconditions rather than thunks
/// to avoid musttail complexity across different architectures.
bool shouldHavePreconditionInline(const ObjCMethodDecl *OMD) const {
return OMD && OMD->isDirectMethod() && OMD->isVariadic() &&
isObjCDirectPreconditionThunkEnabled();
}
const std::string &getModuleNameHash() const { return ModuleNameHash; }
void setIsSPMDExecutionMode(bool isSPMD) { isSPMDExecutionMode = isSPMD; }
bool IsSPMDExecutionMode() { return isSPMDExecutionMode; }
/// Return a reference to the configured OpenCL runtime.
CGOpenCLRuntime &getOpenCLRuntime() {
assert(OpenCLRuntime != nullptr);
return *OpenCLRuntime;
}
/// Return a reference to the configured OpenMP runtime.
CGOpenMPRuntime &getOpenMPRuntime() {
assert(OpenMPRuntime != nullptr);
return *OpenMPRuntime;
}
/// Return a reference to the configured CUDA runtime.
CGCUDARuntime &getCUDARuntime() {
assert(CUDARuntime != nullptr);
return *CUDARuntime;
}
/// Return a reference to the configured HLSL runtime.
CGHLSLRuntime &getHLSLRuntime() {
assert(HLSLRuntime != nullptr);
return *HLSLRuntime;
}
ObjCEntrypoints &getObjCEntrypoints() const {
assert(ObjCData != nullptr);
return *ObjCData;
}
// Version checking functions, used to implement ObjC's @available:
// i32 @__isOSVersionAtLeast(i32, i32, i32)
llvm::FunctionCallee IsOSVersionAtLeastFn = nullptr;
// i32 @__isPlatformVersionAtLeast(i32, i32, i32, i32)
llvm::FunctionCallee IsPlatformVersionAtLeastFn = nullptr;
InstrProfStats &getPGOStats() { return PGOStats; }
llvm::IndexedInstrProfReader *getPGOReader() const { return PGOReader.get(); }
CoverageMappingModuleGen *getCoverageMapping() const {
return CoverageMapping.get();
}
llvm::Constant *getStaticLocalDeclAddress(const VarDecl *D) {
return StaticLocalDeclMap[D];
}
void setStaticLocalDeclAddress(const VarDecl *D,
llvm::Constant *C) {
StaticLocalDeclMap[D] = C;
}
llvm::Constant *
getOrCreateStaticVarDecl(const VarDecl &D,
llvm::GlobalValue::LinkageTypes Linkage);
llvm::GlobalVariable *getStaticLocalDeclGuardAddress(const VarDecl *D) {
return StaticLocalDeclGuardMap[D];
}
void setStaticLocalDeclGuardAddress(const VarDecl *D,
llvm::GlobalVariable *C) {
StaticLocalDeclGuardMap[D] = C;
}
Address createUnnamedGlobalFrom(const VarDecl &D, llvm::Constant *Constant,
CharUnits Align);
bool lookupRepresentativeDecl(StringRef MangledName,
GlobalDecl &Result) const;
llvm::Constant *getAtomicSetterHelperFnMap(QualType Ty) {
return AtomicSetterHelperFnMap[Ty];
}
void setAtomicSetterHelperFnMap(QualType Ty,
llvm::Constant *Fn) {
AtomicSetterHelperFnMap[Ty] = Fn;
}
llvm::Constant *getAtomicGetterHelperFnMap(QualType Ty) {
return AtomicGetterHelperFnMap[Ty];
}
void setAtomicGetterHelperFnMap(QualType Ty,
llvm::Constant *Fn) {
AtomicGetterHelperFnMap[Ty] = Fn;
}
llvm::Constant *getTypeDescriptorFromMap(QualType Ty) {
return TypeDescriptorMap[Ty];
}
void setTypeDescriptorInMap(QualType Ty, llvm::Constant *C) {
TypeDescriptorMap[Ty] = C;
}
CGDebugInfo *getModuleDebugInfo() { return DebugInfo.get(); }
llvm::MDNode *getNoObjCARCExceptionsMetadata() {
if (!NoObjCARCExceptionsMetadata)
NoObjCARCExceptionsMetadata = llvm::MDNode::get(getLLVMContext(), {});
return NoObjCARCExceptionsMetadata;
}
ASTContext &getContext() const { return Context; }
const LangOptions &getLangOpts() const { return LangOpts; }
const IntrusiveRefCntPtr<llvm::vfs::FileSystem> &getFileSystem() const {
return FS;
}
const HeaderSearchOptions &getHeaderSearchOpts()
const { return HeaderSearchOpts; }
const PreprocessorOptions &getPreprocessorOpts()
const { return PreprocessorOpts; }
const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; }
llvm::Module &getModule() const { return TheModule; }
DiagnosticsEngine &getDiags() const { return Diags; }
const llvm::DataLayout &getDataLayout() const {
return TheModule.getDataLayout();
}
const TargetInfo &getTarget() const { return Target; }
const llvm::Triple &getTriple() const { return Target.getTriple(); }
bool supportsCOMDAT() const;
void maybeSetTrivialComdat(const Decl &D, llvm::GlobalObject &GO);
const ABIInfo &getABIInfo();
/// Lazily build and return the LLVMABI library's TargetInfo for the current
/// target. Used by the experimental ABI lowering path
/// (-fexperimental-abi-lowering).
const llvm::abi::TargetInfo &getLLVMABITargetInfo(llvm::abi::TypeBuilder &TB);
/// True when -fexperimental-abi-lowering is in effect AND the active target
/// has an LLVMABI implementation we can route to.
bool shouldUseLLVMABILowering() const;
/// Drive the experimental LLVMABI-based lowering path: map argument and
/// return types into the LLVMABI library, ask its target lowering to fill
/// in classification, and write the results back into FI.
void computeABIInfoUsingLib(CGFunctionInfo &FI);
CGCXXABI &getCXXABI() const { return *ABI; }
llvm::LLVMContext &getLLVMContext() { return VMContext; }
bool shouldUseTBAA() const { return TBAA != nullptr; }
const TargetCodeGenInfo &getTargetCodeGenInfo();
CodeGenTypes &getTypes() { return *Types; }
CodeGenVTables &getVTables() { return VTables; }
ItaniumVTableContext &getItaniumVTableContext() {
return VTables.getItaniumVTableContext();
}
const ItaniumVTableContext &getItaniumVTableContext() const {
return VTables.getItaniumVTableContext();
}
MicrosoftVTableContext &getMicrosoftVTableContext() {
return VTables.getMicrosoftVTableContext();
}
CtorList &getGlobalCtors() { return GlobalCtors; }
CtorList &getGlobalDtors() { return GlobalDtors; }
/// getTBAATypeInfo - Get metadata used to describe accesses to objects of
/// the given type.
llvm::MDNode *getTBAATypeInfo(QualType QTy);
/// getTBAAAccessInfo - Get TBAA information that describes an access to
/// an object of the given type.
TBAAAccessInfo getTBAAAccessInfo(QualType AccessType);
/// getTBAAVTablePtrAccessInfo - Get the TBAA information that describes an
/// access to a virtual table pointer.
TBAAAccessInfo getTBAAVTablePtrAccessInfo(llvm::Type *VTablePtrType);
llvm::MDNode *getTBAAStructInfo(QualType QTy);
/// getTBAABaseTypeInfo - Get metadata that describes the given base access
/// type. Return null if the type is not suitable for use in TBAA access tags.
llvm::MDNode *getTBAABaseTypeInfo(QualType QTy);
/// getTBAAAccessTagInfo - Get TBAA tag for a given memory access.
llvm::MDNode *getTBAAAccessTagInfo(TBAAAccessInfo Info);
/// mergeTBAAInfoForCast - Get merged TBAA information for the purposes of
/// type casts.
TBAAAccessInfo mergeTBAAInfoForCast(TBAAAccessInfo SourceInfo,
TBAAAccessInfo TargetInfo);
/// mergeTBAAInfoForConditionalOperator - Get merged TBAA information for the
/// purposes of conditional operator.
TBAAAccessInfo mergeTBAAInfoForConditionalOperator(TBAAAccessInfo InfoA,
TBAAAccessInfo InfoB);
/// mergeTBAAInfoForMemoryTransfer - Get merged TBAA information for the
/// purposes of memory transfer calls.
TBAAAccessInfo mergeTBAAInfoForMemoryTransfer(TBAAAccessInfo DestInfo,
TBAAAccessInfo SrcInfo);
/// getTBAAInfoForSubobject - Get TBAA information for an access with a given
/// base lvalue.
TBAAAccessInfo getTBAAInfoForSubobject(LValue Base, QualType AccessType) {
if (Base.getTBAAInfo().isMayAlias())
return TBAAAccessInfo::getMayAliasInfo();
return getTBAAAccessInfo(AccessType);
}
bool isPaddedAtomicType(QualType type);
bool isPaddedAtomicType(const AtomicType *type);
/// DecorateInstructionWithTBAA - Decorate the instruction with a TBAA tag.
void DecorateInstructionWithTBAA(llvm::Instruction *Inst,
TBAAAccessInfo TBAAInfo);
/// Adds !invariant.barrier !tag to instruction
void DecorateInstructionWithInvariantGroup(llvm::Instruction *I,
const CXXRecordDecl *RD);
/// Emit the given number of characters as a value of type size_t.
llvm::ConstantInt *getSize(CharUnits numChars);
/// Set the visibility for the given LLVM GlobalValue.
void setGlobalVisibility(llvm::GlobalValue *GV, const NamedDecl *D) const;
void setDSOLocal(llvm::GlobalValue *GV) const;
bool shouldMapVisibilityToDLLExport(const NamedDecl *D) const {
return getLangOpts().hasDefaultVisibilityExportMapping() && D &&
(D->getLinkageAndVisibility().getVisibility() ==
DefaultVisibility) &&
(getLangOpts().isAllDefaultVisibilityExportMapping() ||
(getLangOpts().isExplicitDefaultVisibilityExportMapping() &&
D->getLinkageAndVisibility().isVisibilityExplicit()));
}
void setDLLImportDLLExport(llvm::GlobalValue *GV, GlobalDecl D) const;
void setDLLImportDLLExport(llvm::GlobalValue *GV, const NamedDecl *D) const;
/// Set visibility, dllimport/dllexport and dso_local.
/// This must be called after dllimport/dllexport is set.
void setGVProperties(llvm::GlobalValue *GV, GlobalDecl GD) const;
void setGVProperties(llvm::GlobalValue *GV, const NamedDecl *D) const;
void setGVPropertiesAux(llvm::GlobalValue *GV, const NamedDecl *D) const;
/// Set the TLS mode for the given LLVM GlobalValue for the thread-local
/// variable declaration D.
void setTLSMode(llvm::GlobalValue *GV, const VarDecl &D) const;
/// Get LLVM TLS mode from CodeGenOptions.
llvm::GlobalVariable::ThreadLocalMode GetDefaultLLVMTLSModel() const;
static llvm::GlobalValue::VisibilityTypes GetLLVMVisibility(Visibility V) {
switch (V) {
case DefaultVisibility: return llvm::GlobalValue::DefaultVisibility;
case HiddenVisibility: return llvm::GlobalValue::HiddenVisibility;
case ProtectedVisibility: return llvm::GlobalValue::ProtectedVisibility;
}
llvm_unreachable("unknown visibility!");
}
llvm::Constant *GetAddrOfGlobal(GlobalDecl GD,
ForDefinition_t IsForDefinition
= NotForDefinition);
/// 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.
llvm::GlobalVariable *
CreateOrReplaceCXXRuntimeVariable(StringRef Name, llvm::Type *Ty,
llvm::GlobalValue::LinkageTypes Linkage,
llvm::Align Alignment);
llvm::Function *CreateGlobalInitOrCleanUpFunction(
llvm::FunctionType *ty, const Twine &name, const CGFunctionInfo &FI,
SourceLocation Loc = SourceLocation(), bool TLS = false,
llvm::GlobalVariable::LinkageTypes Linkage =
llvm::GlobalVariable::InternalLinkage);
/// 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;
/// Return the llvm::Constant 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.
llvm::Constant *GetAddrOfGlobalVar(const VarDecl *D,
llvm::Type *Ty = nullptr,
ForDefinition_t IsForDefinition
= NotForDefinition);
/// 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.
llvm::Constant *GetAddrOfFunction(GlobalDecl GD, llvm::Type *Ty = nullptr,
bool ForVTable = false,
bool DontDefer = false,
ForDefinition_t IsForDefinition
= NotForDefinition);
// Return the function body address of the given function.
llvm::Constant *GetFunctionStart(const ValueDecl *Decl);
/// Return a function pointer for a reference to the given function.
/// This correctly handles weak references, but does not apply a
/// pointer signature.
llvm::Constant *getRawFunctionPointer(GlobalDecl GD,
llvm::Type *Ty = nullptr);
/// Return the ABI-correct function pointer value for a reference
/// to the given function. This will apply a pointer signature if
/// necessary, caching the result for the given function.
llvm::Constant *getFunctionPointer(GlobalDecl GD, llvm::Type *Ty = nullptr);
/// Return the ABI-correct function pointer value for a reference
/// to the given function. This will apply a pointer signature if
/// necessary.
llvm::Constant *getFunctionPointer(llvm::Constant *Pointer,
QualType FunctionType);
llvm::Constant *getMemberFunctionPointer(const FunctionDecl *FD,
llvm::Type *Ty = nullptr);
llvm::Constant *getMemberFunctionPointer(llvm::Constant *Pointer,
QualType FT);
CGPointerAuthInfo getFunctionPointerAuthInfo(QualType T);
CGPointerAuthInfo getMemberFunctionPointerAuthInfo(QualType FT);
CGPointerAuthInfo getPointerAuthInfoForPointeeType(QualType type);
CGPointerAuthInfo getPointerAuthInfoForType(QualType type);
bool shouldSignPointer(const PointerAuthSchema &Schema);
llvm::Constant *getConstantSignedPointer(llvm::Constant *Pointer,
const PointerAuthSchema &Schema,
llvm::Constant *StorageAddress,
GlobalDecl SchemaDecl,
QualType SchemaType);
llvm::Constant *
getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key,
llvm::Constant *StorageAddress,
llvm::ConstantInt *OtherDiscriminator);
llvm::ConstantInt *
getPointerAuthOtherDiscriminator(const PointerAuthSchema &Schema,
GlobalDecl SchemaDecl, QualType SchemaType);
uint16_t getPointerAuthDeclDiscriminator(GlobalDecl GD);
std::optional<CGPointerAuthInfo>
getVTablePointerAuthInfo(CodeGenFunction *Context,
const CXXRecordDecl *Record,
llvm::Value *StorageAddress);
std::optional<PointerAuthQualifier>
getVTablePointerAuthentication(const CXXRecordDecl *thisClass);
CGPointerAuthInfo EmitPointerAuthInfo(const RecordDecl *RD);
// Return whether RTTI information should be emitted for this target.
bool shouldEmitRTTI(bool ForEH = false) {
return (ForEH || getLangOpts().RTTI) &&
(!getLangOpts().isTargetDevice() || !getTriple().isGPU());
}
/// Get the address of the RTTI descriptor for the given type.
llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty, bool ForEH = false);
/// Get the address of a GUID.
ConstantAddress GetAddrOfMSGuidDecl(const MSGuidDecl *GD);
/// Get the address of a UnnamedGlobalConstant
ConstantAddress
GetAddrOfUnnamedGlobalConstantDecl(const UnnamedGlobalConstantDecl *GCD);
/// Get the address of a template parameter object.
ConstantAddress
GetAddrOfTemplateParamObject(const TemplateParamObjectDecl *TPO);
/// Get the address of the thunk for the given global decl.
llvm::Constant *GetAddrOfThunk(StringRef Name, llvm::Type *FnTy,
GlobalDecl GD);
/// Get a reference to the target of VD.
ConstantAddress GetWeakRefReference(const ValueDecl *VD);
/// Returns the assumed alignment of an opaque pointer to the given class.
CharUnits getClassPointerAlignment(const CXXRecordDecl *CD);
/// Returns the minimum object size for an object of the given class type
/// (or a class derived from it).
CharUnits getMinimumClassObjectSize(const CXXRecordDecl *CD);
/// Returns the minimum object size for an object of the given type.
CharUnits getMinimumObjectSize(QualType Ty) {
if (CXXRecordDecl *RD = Ty->getAsCXXRecordDecl())
return getMinimumClassObjectSize(RD);
return getContext().getTypeSizeInChars(Ty);
}
/// Returns the assumed alignment of a virtual base of a class.
CharUnits getVBaseAlignment(CharUnits DerivedAlign,
const CXXRecordDecl *Derived,
const CXXRecordDecl *VBase);
/// Given a class pointer with an actual known alignment, and the
/// expected alignment of an object at a dynamic offset w.r.t that
/// pointer, return the alignment to assume at the offset.
CharUnits getDynamicOffsetAlignment(CharUnits ActualAlign,
const CXXRecordDecl *Class,
CharUnits ExpectedTargetAlign);
CharUnits
computeNonVirtualBaseClassOffset(const CXXRecordDecl *DerivedClass,
CastExpr::path_const_iterator Start,
CastExpr::path_const_iterator End);
/// Returns the offset from a derived class to a class. Returns null if the
/// offset is 0.
llvm::Constant *
GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl,
CastExpr::path_const_iterator PathBegin,
CastExpr::path_const_iterator PathEnd);
llvm::FoldingSet<BlockByrefHelpers> ByrefHelpersCache;
/// Fetches the global unique block count.
int getUniqueBlockCount() { return ++Block.GlobalUniqueCount; }
/// Fetches the type of a generic block descriptor.
llvm::Type *getBlockDescriptorType();
/// The type of a generic block literal.
llvm::Type *getGenericBlockLiteralType();
/// Gets the address of a block which requires no captures.
llvm::Constant *GetAddrOfGlobalBlock(const BlockExpr *BE, StringRef Name);
/// Returns the address of a block which requires no caputres, or null if
/// we've yet to emit the block for BE.
llvm::Constant *getAddrOfGlobalBlockIfEmitted(const BlockExpr *BE) {
return EmittedGlobalBlocks.lookup(BE);
}
/// Notes that BE's global block is available via Addr. Asserts that BE
/// isn't already emitted.
void setAddrOfGlobalBlock(const BlockExpr *BE, llvm::Constant *Addr);
/// Return a pointer to a constant CFString object for the given string.
ConstantAddress GetAddrOfConstantCFString(const StringLiteral *Literal);
/// Return a constant array for the given string.
llvm::Constant *GetConstantArrayFromStringLiteral(const StringLiteral *E);
/// Return a pointer to a constant array for the given string literal.
ConstantAddress
GetAddrOfConstantStringFromLiteral(const StringLiteral *S,
StringRef Name = ".str");
/// Return a pointer to a constant array for the given ObjCEncodeExpr node.
ConstantAddress
GetAddrOfConstantStringFromObjCEncode(const ObjCEncodeExpr *);
/// Returns a pointer to a character array containing the literal and a
/// terminating '\0' character. The result has pointer to array type.
///
/// \param GlobalName If provided, the name to use for the global (if one is
/// created).
ConstantAddress GetAddrOfConstantCString(const std::string &Str,
StringRef GlobalName = ".str");
/// Returns a pointer to a constant global variable for the given file-scope
/// compound literal expression.
ConstantAddress GetAddrOfConstantCompoundLiteral(const CompoundLiteralExpr*E);
/// If it's been emitted already, returns the GlobalVariable corresponding to
/// a compound literal. Otherwise, returns null.
llvm::GlobalVariable *
getAddrOfConstantCompoundLiteralIfEmitted(const CompoundLiteralExpr *E);
/// Notes that CLE's GlobalVariable is GV. Asserts that CLE isn't already
/// emitted.
void setAddrOfConstantCompoundLiteral(const CompoundLiteralExpr *CLE,
llvm::GlobalVariable *GV);
/// Returns a pointer to a global variable representing a temporary
/// with static or thread storage duration.
ConstantAddress GetAddrOfGlobalTemporary(const MaterializeTemporaryExpr *E,
const Expr *Inner);
/// Retrieve the record type that describes the state of an
/// Objective-C fast enumeration loop (for..in).
QualType getObjCFastEnumerationStateType();
// 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.
llvm::Function *codegenCXXStructor(GlobalDecl GD);
/// Emit a trap stub body for functions in ASTContext::CUDADeviceInvalidFuncs.
bool tryEmitCUDADeviceInvalidFunctionBody(GlobalDecl GD, llvm::Function *Fn);
/// Return the address of the constructor/destructor of the given type.
llvm::Constant *
getAddrOfCXXStructor(GlobalDecl GD, const CGFunctionInfo *FnInfo = nullptr,
llvm::FunctionType *FnType = nullptr,
bool DontDefer = false,
ForDefinition_t IsForDefinition = NotForDefinition) {
return cast<llvm::Constant>(getAddrAndTypeOfCXXStructor(GD, FnInfo, FnType,
DontDefer,
IsForDefinition)
.getCallee());
}
llvm::FunctionCallee getAddrAndTypeOfCXXStructor(
GlobalDecl GD, const CGFunctionInfo *FnInfo = nullptr,
llvm::FunctionType *FnType = nullptr, bool DontDefer = false,
ForDefinition_t IsForDefinition = NotForDefinition);
/// Given a builtin id for a function like "__builtin_fabsf", return a
/// Function* for "fabsf".
llvm::Constant *getBuiltinLibFunction(const FunctionDecl *FD,
unsigned BuiltinID);
llvm::Function *getIntrinsic(unsigned IID, ArrayRef<llvm::Type *> Tys = {});
void AddCXXGlobalInit(llvm::Function *F) { CXXGlobalInits.push_back(F); }
/// Emit code for a single top level declaration.
void EmitTopLevelDecl(Decl *D);
/// Stored a deferred empty coverage mapping for an unused
/// and thus uninstrumented top level declaration.
void AddDeferredUnusedCoverageMapping(Decl *D);
/// Remove the deferred empty coverage mapping as this
/// declaration is actually instrumented.
void ClearUnusedCoverageMapping(const Decl *D);
/// Emit all the deferred coverage mappings
/// for the uninstrumented functions.
void EmitDeferredUnusedCoverageMappings();
/// Emit an alias for "main" if it has no arguments (needed for wasm).
void EmitMainVoidAlias();
/// Tell the consumer that this variable has been instantiated.
void HandleCXXStaticMemberVarInstantiation(VarDecl *VD);
/// 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, llvm::GlobalValue *GV);
/// Add a global to a list to be added to the llvm.used metadata.
void addUsedGlobal(llvm::GlobalValue *GV);
/// Add a global to a list to be added to the llvm.compiler.used metadata.
void addCompilerUsedGlobal(llvm::GlobalValue *GV);
/// Add a global to a list to be added to the llvm.compiler.used metadata.
void addUsedOrCompilerUsedGlobal(llvm::GlobalValue *GV);
/// Add a destructor and object to add to the C++ global destructor function.
void AddCXXDtorEntry(llvm::FunctionCallee DtorFn, llvm::Constant *Object) {
CXXGlobalDtorsOrStermFinalizers.emplace_back(DtorFn.getFunctionType(),
DtorFn.getCallee(), Object);
}
/// Add an sterm finalizer to the C++ global cleanup function.
void AddCXXStermFinalizerEntry(llvm::FunctionCallee DtorFn) {
CXXGlobalDtorsOrStermFinalizers.emplace_back(DtorFn.getFunctionType(),
DtorFn.getCallee(), nullptr);
}
/// Add an sterm finalizer to its own llvm.global_dtors entry.
void AddCXXStermFinalizerToGlobalDtor(llvm::Function *StermFinalizer,
int Priority) {
AddGlobalDtor(StermFinalizer, Priority);
}
void AddCXXPrioritizedStermFinalizerEntry(llvm::Function *StermFinalizer,
int Priority) {
OrderGlobalInitsOrStermFinalizers Key(Priority,
PrioritizedCXXStermFinalizers.size());
PrioritizedCXXStermFinalizers.push_back(
std::make_pair(Key, StermFinalizer));
}
/// Create or return a runtime function declaration with the specified type
/// and name. If \p AssumeConvergent is true, the call will have the
/// convergent attribute added.
///
/// For new code, please use the overload that takes a QualType; it sets
/// function attributes more accurately.
llvm::FunctionCallee
CreateRuntimeFunction(llvm::FunctionType *Ty, StringRef Name,
llvm::AttributeList ExtraAttrs = llvm::AttributeList(),
bool Local = false, bool AssumeConvergent = false);
/// Create or return a runtime function declaration with the specified type
/// and name. If \p AssumeConvergent is true, the call will have the
/// convergent attribute added.
llvm::FunctionCallee
CreateRuntimeFunction(QualType ReturnTy, ArrayRef<QualType> ArgTys,
StringRef Name,
llvm::AttributeList ExtraAttrs = llvm::AttributeList(),
bool Local = false, bool AssumeConvergent = false);
/// Create a new runtime global variable with the specified type and name.
llvm::Constant *CreateRuntimeVariable(llvm::Type *Ty,
StringRef Name);
///@name Custom Blocks Runtime Interfaces
///@{
llvm::Constant *getNSConcreteGlobalBlock();
llvm::Constant *getNSConcreteStackBlock();
llvm::FunctionCallee getBlockObjectAssign();
llvm::FunctionCallee getBlockObjectDispose();
///@}
llvm::Function *getLLVMLifetimeStartFn();
llvm::Function *getLLVMLifetimeEndFn();
llvm::Function *getLLVMFakeUseFn();
// Make sure that this type is translated.
void UpdateCompletedType(const TagDecl *TD);
llvm::Constant *getMemberPointerConstant(const UnaryOperator *e);
/// Emit type info if type of an expression is a variably modified
/// type. Also emit proper debug info for cast types.
void EmitExplicitCastExprType(const ExplicitCastExpr *E,
CodeGenFunction *CGF = nullptr);
/// 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.
llvm::Constant *EmitNullConstant(QualType T);
/// Return a null constant appropriate for zero-initializing a base class with
/// the given type. This is usually, but not always, an LLVM null constant.
llvm::Constant *EmitNullConstantForBase(const CXXRecordDecl *Record);
/// 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 stmt yet.
void ErrorUnsupported(const Stmt *S, llvm::StringRef Type);
/// Print out an error that codegen doesn't support the specified decl yet.
void ErrorUnsupported(const Decl *D, const char *Type);
/// Run some code with "sufficient" stack space. (Currently, at least 256K is
/// guaranteed). Produces a warning if we're low on stack space and allocates
/// more in that case. Use this in code that may recurse deeply to avoid stack
/// overflow.
void runWithSufficientStackSpace(SourceLocation Loc,
llvm::function_ref<void()> Fn);
/// Set the attributes on the LLVM function for the given decl and function
/// info. This applies attributes necessary for handling the ABI as well as
/// user specified attributes like section.
void SetInternalFunctionAttributes(GlobalDecl GD, llvm::Function *F,
const CGFunctionInfo &FI);
/// Set the LLVM function attributes (sext, zext, etc).
void SetLLVMFunctionAttributes(GlobalDecl GD, const CGFunctionInfo &Info,
llvm::Function *F, bool IsThunk);
/// Set the LLVM function attributes which only apply to a function
/// definition.
void SetLLVMFunctionAttributesForDefinition(const Decl *D, llvm::Function *F);
/// Set the LLVM function attributes that represent floating point
/// environment.
void setLLVMFunctionFEnvAttributes(const FunctionDecl *D, llvm::Function *F);
/// Return true iff the given type uses 'sret' when used as a return type.
bool ReturnTypeUsesSRet(const CGFunctionInfo &FI);
/// Return true iff the given type has `inreg` set.
bool ReturnTypeHasInReg(const CGFunctionInfo &FI);
/// Return true iff the given type uses an argument slot when 'sret' is used
/// as a return type.
bool ReturnSlotInterferesWithArgs(const CGFunctionInfo &FI);
/// Return true iff the given type uses 'fpret' when used as a return type.
bool ReturnTypeUsesFPRet(QualType ResultType);
/// Return true iff the given type uses 'fp2ret' when used as a return type.
bool ReturnTypeUsesFP2Ret(QualType ResultType);
/// Get the LLVM 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.
/// \param CallingConv [out] - On return, the LLVM calling convention to use.
void ConstructAttributeList(StringRef Name, const CGFunctionInfo &Info,
CGCalleeInfo CalleeInfo,
llvm::AttributeList &Attrs, unsigned &CallingConv,
bool AttrOnCallSite, bool IsThunk);
/// Adjust Memory attribute to ensure that the BE gets the right attribute
// in order to generate the library call or the intrinsic for the function
// name 'Name'.
void AdjustMemoryAttribute(StringRef Name, CGCalleeInfo CalleeInfo,
llvm::AttributeList &Attrs);
/// Like the overload taking a `Function &`, but intended specifically
/// for frontends that want to build on Clang's target-configuration logic.
void addDefaultFunctionDefinitionAttributes(llvm::AttrBuilder &attrs);
StringRef getMangledName(GlobalDecl GD);
StringRef getBlockMangledName(GlobalDecl GD, const BlockDecl *BD);
const GlobalDecl getMangledNameDecl(StringRef);
void EmitTentativeDefinition(const VarDecl *D);
void EmitExternalDeclaration(const DeclaratorDecl *D);
void EmitVTable(CXXRecordDecl *Class);
void RefreshTypeCacheForClass(const CXXRecordDecl *Class);
/// Appends Opts to the "llvm.linker.options" metadata value.
void AppendLinkerOptions(StringRef Opts);
/// Appends a detect mismatch command to the linker options.
void AddDetectMismatch(StringRef Name, StringRef Value);
/// Appends a dependent lib to the appropriate metadata value.
void AddDependentLib(StringRef Lib);
llvm::GlobalVariable::LinkageTypes getFunctionLinkage(GlobalDecl GD);
void setFunctionLinkage(GlobalDecl GD, llvm::Function *F) {
F->setLinkage(getFunctionLinkage(GD));
}
/// Return the appropriate linkage for the vtable, VTT, and type information
/// of the given class.
llvm::GlobalVariable::LinkageTypes getVTableLinkage(const CXXRecordDecl *RD);
/// Return the store size, in character units, of the given LLVM type.
CharUnits GetTargetTypeStoreSize(llvm::Type *Ty) const;
/// Returns LLVM linkage for a declarator.
llvm::GlobalValue::LinkageTypes
getLLVMLinkageForDeclarator(const DeclaratorDecl *D, GVALinkage Linkage);
/// Returns LLVM linkage for a declarator.
llvm::GlobalValue::LinkageTypes
getLLVMLinkageVarDefinition(const VarDecl *VD);
/// Emit all the global annotations.
void EmitGlobalAnnotations();
/// Emit an annotation string.
llvm::Constant *EmitAnnotationString(StringRef Str);
/// Emit the annotation's translation unit.
llvm::Constant *EmitAnnotationUnit(SourceLocation Loc);
/// Emit the annotation line number.
llvm::Constant *EmitAnnotationLineNo(SourceLocation L);
/// Emit additional args of the annotation.
llvm::Constant *EmitAnnotationArgs(const AnnotateAttr *Attr);
/// Generate the llvm::ConstantStruct which contains the annotation
/// information for a given GlobalValue. The annotation struct is
/// {i8 *, i8 *, i8 *, i32}. The first field is a constant expression, the
/// GlobalValue being annotated. The second field is the constant string
/// created from the AnnotateAttr's annotation. The third field is a constant
/// string containing the name of the translation unit. The fourth field is
/// the line number in the file of the annotated value declaration.
llvm::Constant *EmitAnnotateAttr(llvm::GlobalValue *GV,
const AnnotateAttr *AA,
SourceLocation L);
/// Add global annotations that are set on D, for the global GV. Those
/// annotations are emitted during finalization of the LLVM code.
void AddGlobalAnnotations(const ValueDecl *D, llvm::GlobalValue *GV);
bool isInNoSanitizeList(SanitizerMask Kind, llvm::Function *Fn,
SourceLocation Loc) const;
bool isInNoSanitizeList(SanitizerMask Kind, llvm::GlobalVariable *GV,
SourceLocation Loc, QualType Ty,
StringRef Category = StringRef()) const;
/// Imbue XRay attributes to a function, applying the always/never attribute
/// lists in the process. Returns true if we did imbue attributes this way,
/// false otherwise.
bool imbueXRayAttrs(llvm::Function *Fn, SourceLocation Loc,
StringRef Category = StringRef()) const;
/// \returns true if \p Fn at \p Loc should be excluded from profile
/// instrumentation by the SCL passed by \p -fprofile-list.
ProfileList::ExclusionType
isFunctionBlockedByProfileList(llvm::Function *Fn, SourceLocation Loc) const;
/// \returns true if \p Fn at \p Loc should be excluded from profile
/// instrumentation.
ProfileList::ExclusionType
isFunctionBlockedFromProfileInstr(llvm::Function *Fn,
SourceLocation Loc) const;
SanitizerMetadata *getSanitizerMetadata() {
return SanitizerMD.get();
}
void addDeferredVTable(const CXXRecordDecl *RD) {
DeferredVTables.push_back(RD);
}
/// Emit code for a single global function or var decl. Forward declarations
/// are emitted lazily.
void EmitGlobal(GlobalDecl D);
/// Record that new[] was called for the class, transform vector deleting
/// destructor definition in a form of alias to the actual definition.
void requireVectorDestructorDefinition(const CXXRecordDecl *RD);
/// Check that class need vector deleting destructor body.
bool classNeedsVectorDestructor(const CXXRecordDecl *RD);
bool TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D);
void EmitDefinitionAsAlias(GlobalDecl Alias, GlobalDecl Target);
llvm::GlobalValue *GetGlobalValue(StringRef Ref);
/// 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, llvm::GlobalValue *GV);
void addReplacement(StringRef Name, llvm::Constant *C);
void addGlobalValReplacement(llvm::GlobalValue *GV, llvm::Constant *C);
/// Emit a code for threadprivate directive.
/// \param D Threadprivate declaration.
void EmitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D);
/// Emit a code for declare reduction construct.
void EmitOMPDeclareReduction(const OMPDeclareReductionDecl *D,
CodeGenFunction *CGF = nullptr);
/// Emit a code for declare mapper construct.
void EmitOMPDeclareMapper(const OMPDeclareMapperDecl *D,
CodeGenFunction *CGF = nullptr);
// Emit code for the OpenACC Declare declaration.
void EmitOpenACCDeclare(const OpenACCDeclareDecl *D,
CodeGenFunction *CGF = nullptr);
// Emit code for the OpenACC Routine declaration.
void EmitOpenACCRoutine(const OpenACCRoutineDecl *D,
CodeGenFunction *CGF = nullptr);
/// Emit a code for requires directive.
/// \param D Requires declaration
void EmitOMPRequiresDecl(const OMPRequiresDecl *D);
/// Emit a code for the allocate directive.
/// \param D The allocate declaration
void EmitOMPAllocateDecl(const OMPAllocateDecl *D);
/// Return the alignment specified in an allocate directive, if present.
std::optional<CharUnits> getOMPAllocateAlignment(const VarDecl *VD);
/// 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);
/// 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 the vcall visibility of the given type. This is the scope in which
/// a virtual function call could be made which ends up being dispatched to a
/// member function of this class. This scope can be wider than the visibility
/// of the class itself when the class has a more-visible dynamic base class.
/// The client should pass in an empty Visited set, which is used to prevent
/// redundant recursive processing.
llvm::GlobalObject::VCallVisibility
GetVCallVisibilityLevel(const CXXRecordDecl *RD,
llvm::DenseSet<const CXXRecordDecl *> &Visited);
/// Emit type metadata for the given vtable using the given layout.
void EmitVTableTypeMetadata(const CXXRecordDecl *RD,
llvm::GlobalVariable *VTable,
const VTableLayout &VTLayout);
llvm::Type *getVTableComponentType() const;
/// Generate a cross-DSO type identifier for MD.
llvm::ConstantInt *CreateCrossDsoCfiTypeId(llvm::Metadata *MD);
/// Generate a KCFI type identifier for T.
llvm::ConstantInt *CreateKCFITypeId(QualType T, StringRef Salt);
/// Create a metadata identifier for the given function type.
llvm::Metadata *CreateMetadataIdentifierForFnType(QualType T);
/// Create a metadata identifier for the given type. This may either be an
/// MDString (for external identifiers) or a distinct unnamed MDNode (for
/// internal identifiers).
llvm::Metadata *CreateMetadataIdentifierForType(QualType T);
/// Create a metadata identifier that is intended to be used to check virtual
/// calls via a member function pointer.
llvm::Metadata *CreateMetadataIdentifierForVirtualMemPtrType(QualType T);
/// Create a metadata identifier for the generalization of the given type.
/// This may either be an MDString (for external identifiers) or a distinct
/// unnamed MDNode (for internal identifiers).
llvm::Metadata *CreateMetadataIdentifierGeneralized(QualType T);
/// Create and attach type metadata to the given function.
void createFunctionTypeMetadataForIcall(const FunctionDecl *FD,
llvm::Function *F);
/// Create and attach type metadata if the function is a potential indirect
/// call target to support call graph section.
void createIndirectFunctionTypeMD(const FunctionDecl *FD, llvm::Function *F);
/// Create and attach type metadata to the given call.
void createCalleeTypeMetadataForIcall(const QualType &QT, llvm::CallBase *CB);
/// Set type metadata to the given function.
void setKCFIType(const FunctionDecl *FD, llvm::Function *F);
/// Emit KCFI type identifier constants and remove unused identifiers.
void finalizeKCFITypes();
/// Whether this function's return type has no side effects, and thus may
/// be trivially discarded if it is unused.
bool MayDropFunctionReturn(const ASTContext &Context,
QualType ReturnType) const;
/// Returns whether this module needs the "all-vtables" type identifier.
bool NeedAllVtablesTypeId() const;
/// Create and attach type metadata for the given vtable.
void AddVTableTypeMetadata(llvm::GlobalVariable *VTable, CharUnits Offset,
const CXXRecordDecl *RD);
/// Return a vector of most-base classes for RD. This is used to implement
/// control flow integrity checks for member function pointers.
///
/// A most-base class of a class C is defined as a recursive base class of C,
/// including C itself, that does not have any bases.
SmallVector<const CXXRecordDecl *, 0>
getMostBaseClasses(const CXXRecordDecl *RD);
/// Get the declaration of std::terminate for the platform.
llvm::FunctionCallee getTerminateFn();
llvm::SanitizerStatReport &getSanStats();
llvm::Value *
createOpenCLIntToSamplerConversion(const Expr *E, CodeGenFunction &CGF);
/// 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 CodeGenFunction that generates this function.
void GenKernelArgMetadata(llvm::Function *FN,
const FunctionDecl *FD = nullptr,
CodeGenFunction *CGF = nullptr);
/// Get target specific null pointer.
/// \param T is the LLVM type of the null pointer.
/// \param QT is the clang QualType of the null pointer.
llvm::Constant *getNullPointer(llvm::PointerType *T, QualType QT);
CharUnits getNaturalTypeAlignment(QualType T,
LValueBaseInfo *BaseInfo = nullptr,
TBAAAccessInfo *TBAAInfo = nullptr,
bool forPointeeType = false);
CharUnits getNaturalPointeeTypeAlignment(QualType T,
LValueBaseInfo *BaseInfo = nullptr,
TBAAAccessInfo *TBAAInfo = nullptr);
bool stopAutoInit();
/// Print the postfix for externalized static variable or kernels for single
/// source offloading languages CUDA and HIP. The unique postfix is created
/// using either the CUID argument, or the file's UniqueID and active macros.
/// The fallback method without a CUID requires that the offloading toolchain
/// does not define separate macros via the -cc1 options.
void printPostfixForExternalizedDecl(llvm::raw_ostream &OS,
const Decl *D) const;
/// Under debug mode, print status of target teams loop transformation,
/// which should be either '#distribute' or '#parallel for'
void emitTargetTeamsLoopCodegenStatus(std::string StatusMsg,
const OMPExecutableDirective &D,
bool IsDevice);
/// Add metadata for all nested directives for optimized kernel codegen.
void addOptKernelNestMap(const OptKernelNestDirectives &NestDirs);
/// Given a directive, return the statement key used for maintaining metadata.
const Stmt *getOptKernelKey(const OMPExecutableDirective &D);
/// Given a captured statement, return the nested directives involved in
/// optimized kernel codegen.
const OptKernelNestDirectives &
getOptKernelDirectives(const ForStmt *CapturedForStmt,
llvm::omp::OMPTgtExecModeFlags OptKernelMode);
// Should be called under debug mode for printing analysis result.
void emitNxResult(std::string StatusMsg, const OMPExecutableDirective &D,
NoLoopXteamErr Status);
/// Given the schedule clause, can No-Loop code be generated?
NoLoopXteamErr getNoLoopCompatibleSchedStatus(const OMPLoopDirective &LD);
/// Given the order clause, can No-Loop code be generated?
NoLoopXteamErr getNoLoopCompatibleOrderStatus(const OMPLoopDirective &LD);
NoLoopXteamErr
getXteamRedCompatibleThreadLimitStatus(const OMPLoopDirective &LD);
/// Helper functions for generating a NoLoop kernel
/// For a captured statement, get the single For statement, if it exists,
/// otherwise return nullptr.
const ForStmt *getSingleForStmt(const Stmt *S);
/// Does the loop init qualify for a NoLoop kernel?
const VarDecl *checkLoopInit(const OMPLoopDirective &LD);
/// Does the loop increment qualify for a NoLoop kernel?
bool checkLoopStep(const Expr *Inc, const VarDecl *VD);
/// Does the loop condition qualify for a NoLoop kernel?
bool checkLoopStop(const OMPLoopDirective &, const ForStmt &);
/// If the step is a binary expression, extract and return the step.
/// If the step is a unary expression, return nullptr.
const Expr *getBinaryExprStep(const Expr *Inc, const VarDecl *VD);
/// Reset optimized kernel metadata.
void resetOptKernelMetadata(const Stmt *S);
void eraseOptKernelNestElem(const Stmt *S) { OptKernelNestMap.erase(S); }
/// Used in optimized kernel codegen.
const Stmt *getMappedInnermostStmt(const Stmt *S) {
auto nest_itr = OptKernelNestMap.find(S);
if (nest_itr == OptKernelNestMap.end())
return nullptr;
return nest_itr->second;
}
bool isFastXteamSumReduction() {
return getLangOpts().OpenMPTargetFastReduction;
}
bool isXteamScanKernel() {
return (getLangOpts().OpenMPTargetXteamScan ||
getLangOpts().OpenMPTargetXteamNoLoopScan) &&
isXteamScanCandidate;
}
bool isXteamSegmentedScanKernel() {
return isXteamScanKernel() && !getLangOpts().OpenMPTargetXteamNoLoopScan;
}
/// If we are able to generate a NoLoop kernel for this directive, return
/// true, otherwise return false. If successful, a map is created from the
/// top-level statement to the intermediate statements. For a combined
/// construct, there are no intermediate statements. Used for a combined
/// construct
NoLoopXteamErr checkAndSetNoLoopKernel(const OMPExecutableDirective &D);
/// Determine if 'teams loop' can be emitted using 'parallel for'.
bool TeamsLoopCanBeParallelFor(const OMPExecutableDirective &D);
/// Given a top-level target construct for no-loop codegen, get the
/// intermediate OpenMP constructs
const OptKernelNestDirectives &getNoLoopNestDirs(const Stmt *S) {
assert(isNoLoopKernel(S));
return NoLoopKernels.find(S)->second.NoLoopNestDirs;
}
/// Get the cached blocksize to be used for this NoLoop kernel.
int getNoLoopBlockSize(const Stmt *S) {
assert(isNoLoopKernel(S));
return NoLoopKernels.find(S)->second.BlockSize;
}
int getNoLoopBlockSize(const OMPExecutableDirective &D) {
assert(isNoLoopKernel(D) && "Expected a no-loop kernel");
const ForStmt *FStmt = getSingleForStmt(getOptKernelKey(D));
return getNoLoopBlockSize(FStmt);
}
/// Erase no-loop related metadata for the input statement
void resetNoLoopKernel(const Stmt *S) { NoLoopKernels.erase(S); }
/// Are we generating no-loop kernel for the input statement
bool isNoLoopKernel(const Stmt *S) {
return NoLoopKernels.find(S) != NoLoopKernels.end();
}
bool isNoLoopKernel(const OMPExecutableDirective &D);
/// Given a top-level target construct for BigJumpLoop codegen, get the
/// nested OpenMP constructs.
const OptKernelNestDirectives &getBigJumpLoopNestDirs(const Stmt *S) {
assert(isBigJumpLoopKernel(S));
return BigJumpLoopKernels.find(S)->second.NoLoopNestDirs;
}
void updateNoLoopKernel(const Stmt *S, int BlkSz) {
assert(isNoLoopKernel(S));
NoLoopKernels.find(S)->second.BlockSize = BlkSz;
}
/// Get the cached blocksize to be used for this BigJumpLoop kernel.
int getBigJumpLoopBlockSize(const Stmt *S) {
assert(isBigJumpLoopKernel(S));
return BigJumpLoopKernels.find(S)->second.BlockSize;
}
int getBigJumpLoopBlockSize(const OMPExecutableDirective &D) {
assert(isBigJumpLoopKernel(D) && "Expected a big-jump-loop kernel");
const ForStmt *FStmt = getSingleForStmt(getOptKernelKey(D));
return getBigJumpLoopBlockSize(FStmt);
}
/// Erase BigJumpLoop related metadata for the input statement.
void resetBigJumpLoopKernel(const Stmt *S) { BigJumpLoopKernels.erase(S); }
/// Is a BigJumpLoop kernel generated for the input statement?
bool isBigJumpLoopKernel(const Stmt *S) {
return BigJumpLoopKernels.find(S) != BigJumpLoopKernels.end();
}
bool isBigJumpLoopKernel(const OMPExecutableDirective &D);
void updateBigJumpLoopKernel(const Stmt *S, int BlkSz) {
assert(isBigJumpLoopKernel(S));
BigJumpLoopKernels.find(S)->second.BlockSize = BlkSz;
}
/// If we are able to generate a Xteam reduction kernel for this directive,
/// return true, otherwise return false. If successful, metadata for the
/// reduction variables are created for subsequent codegen phases to work on.
NoLoopXteamErr checkAndSetXteamRedKernel(const OMPExecutableDirective &D);
/// If we are able to generate a multi-device kernel for this directive,
/// return true, otherwise return false. If successful, metadata for the
/// argument variables is created for subsequent codegen phases to work on.
bool checkAndSetMultiDeviceKernel(const OMPExecutableDirective &D,
bool CanBeMultiDevice);
/// Compute the block size to be used for a kernel.
int getWorkGroupSizeSPMDHelper(const OMPExecutableDirective &D);
/// Used in optimized kernel codegen, compute the block size from the nested
/// directives.
int getOptKernelWorkGroupSize(const OptKernelNestDirectives &NestDirs,
bool isXteamRed);
/// Given a ForStmt for which Xteam codegen will be done, return the
/// intermediate statements for a split directive.
const OptKernelNestDirectives &getXteamRedNestDirs(const Stmt *S) {
assert(isXteamRedKernel(S));
return XteamRedKernels.find(S)->second.XteamNestDirs;
}
const OptKernelNestDirectives &
getXteamRedNestDirs(const OMPExecutableDirective &D) {
assert(isXteamRedKernel(D) && "Expected an Xteam reduction kernel");
const ForStmt *FStmt = getSingleForStmt(getOptKernelKey(D));
return getXteamRedNestDirs(FStmt);
}
/// Given a ForStmt for which Xteam codegen will be done, return the
/// corresponding metadata
XteamRedVarMap &getXteamRedVarMap(const Stmt *S) {
assert(isXteamRedKernel(S));
return XteamRedKernels.find(S)->second.XteamRedVars;
}
XteamRedVarVecTy &getXteamOrderedRedVar(const Stmt *S) {
assert(isXteamRedKernel(S));
return XteamRedKernels.find(S)->second.XteamOrderedRedVar;
}
llvm::Value *getXteamRedThreadStartIndex(const Stmt *S) {
assert(isXteamRedKernel(S));
return XteamRedKernels.find(S)->second.ThreadStartIndex;
}
/// Used during kernel codegen to retrieve the cached NumTeams.
llvm::Value *getXteamRedNumTeams(const Stmt *S) {
assert(isXteamRedKernel(S));
return XteamRedKernels.find(S)->second.NumTeams;
}
/// Used during host codegen to compute the number of teams from num_teams
/// clause.
int64_t getXteamRedNumTeamsFromClause(const OMPExecutableDirective &D);
/// Used during host codegen for traversing nested directives, looking for
/// num_teams clause.
int64_t
getXteamRedNumTeamsFromClause(const OptKernelNestDirectives &NestDirs);
bool isXteamRedFast(const Stmt *S) {
assert(isXteamRedKernel(S));
return XteamRedKernels.find(S)->second.IsFast;
}
/// Given a ForStmt for which Xteam codegen will be done, update the metadata.
/// \p VD is the reduction variable for which metadata is updated.
void updateXteamRedVarMap(const Stmt *S, const VarDecl *VD, const Expr *RVE,
Address AggVarAddr) {
assert(isXteamRedKernel(S));
XteamRedVarMap &RVM = getXteamRedVarMap(S);
assert(RVM.find(VD) != RVM.end() && "Expected reduction variable in map");
RVM.find(VD)->second.RedVarExpr = RVE;
RVM.find(VD)->second.RedVarAddr = AggVarAddr;
// Another API is used to set ArgPos
}
void updateXteamRedVarArgPos(XteamRedVarInfo *RVInfo, size_t ArgP) {
assert(RVInfo);
RVInfo->ArgPos = ArgP;
}
void updateXteamRedVarOpcode(const CallExpr *Call, const VarDecl *VD,
XteamRedVarMap *RedMap) {
XteamRedOpKind Opcode;
if (isOptKernelAMDGCNMax(Call))
Opcode = XR_OP_max;
else if (isOptKernelAMDGCNMin(Call))
Opcode = XR_OP_min;
else
llvm_unreachable("Expected either min or max");
updateXteamRedVarOpcode(VD, RedMap, Opcode);
}
void updateXteamRedVarOpcode(const VarDecl *VD, XteamRedVarMap *RedMap,
XteamRedOpKind Opcode) {
assert(RedMap->contains(VD) && "Expected reduction variable in map");
RedMap->find(VD)->second.Opcode = Opcode;
}
void updateXteamRedKernel(const Stmt *S, llvm::Value *ThdIndex,
llvm::Value *NTeams) {
assert(isXteamRedKernel(S));
auto &KernelInfo = XteamRedKernels.find(S)->second;
KernelInfo.ThreadStartIndex = ThdIndex;
KernelInfo.NumTeams = NTeams;
}
void updateXteamRedKernel(const Stmt *S, int BlkSz) {
assert(isXteamRedKernel(S));
XteamRedKernels.find(S)->second.BlockSize = BlkSz;
}
// Get the cached block size used by Xteam reduction
int getXteamRedBlockSize(const ForStmt *FStmt) {
assert(isXteamRedKernel(FStmt));
return XteamRedKernels.find(FStmt)->second.BlockSize;
}
int getXteamRedBlockSize(const OMPExecutableDirective &D) {
assert(isXteamRedKernel(D) && "Expected an Xteam reduction kernel");
const ForStmt *FStmt = getSingleForStmt(getOptKernelKey(D));
return getXteamRedBlockSize(FStmt);
}
/// Erase spec-red related metadata for the input statement
void resetXteamRedKernel(const Stmt *S) { XteamRedKernels.erase(S); }
/// Are we generating xteam reduction kernel for the statement
bool isXteamRedKernel(const Stmt *S) {
return XteamRedKernels.find(S) != XteamRedKernels.end();
}
bool isXteamRedKernel(const OMPExecutableDirective &D);
void setCurrentXteamRedStmt(const Stmt *S) { CurrentXteamRedStmt = S; }
const Stmt *getCurrentXteamRedStmt() { return CurrentXteamRedStmt; }
/// Return true if the provided expression accesses a variable in the provided
/// map, otherwise return false.
bool hasXteamRedVar(const Expr *E, const XteamRedVarMap &RedMap) const;
/// If present in the provided map, return the reduction variable accessed by
/// the provided expression, otherwise return nullptr.
const VarDecl *getXteamRedVarDecl(const Expr *E,
const XteamRedVarMap &RedMap) const;
/// Return true if the provided expression accesses the provided variable,
/// otherwise return false.
bool isXteamRedVarExpr(const Expr *E, const VarDecl *VD) const;
/// Return status indicating whether the call is an Xteam-supported host
/// builtin.
CodeGenModule::NoLoopXteamErr
getStatusOptKernelHostBuiltin(const CallExpr *C) const;
/// Is the callee in std namespace?
bool isStdNameSpace(const CallExpr *Call) const;
/// Is the function name recognized as a min builtin by the host compile?
bool isOptKernelHostMin(const CallExpr *Call) const {
std::string CallName = Call->getDirectCallee()->getNameInfo().getAsString();
if (isStdNameSpace(Call) && !CallName.compare("min"))
return true;
return (!CallName.compare("fmin") || !CallName.compare("fminf") ||
!CallName.compare("fminl") || !CallName.compare("__builtin_fmin") ||
!CallName.compare("__builtin_fminf") ||
!CallName.compare("__builtin_fminl"));
}
/// Is the function name recognized as a max builtin by the host compile?
bool isOptKernelHostMax(const CallExpr *Call) const {
std::string CallName = Call->getDirectCallee()->getNameInfo().getAsString();
if (isStdNameSpace(Call) && !CallName.compare("max"))
return true;
return (!CallName.compare("fmax") || !CallName.compare("fmaxf") ||
!CallName.compare("fmaxl") || !CallName.compare("__builtin_fmax") ||
!CallName.compare("__builtin_fmaxf") ||
!CallName.compare("__builtin_fmaxl"));
}
/// Return status indicating whether the amdgcn device function is supported
/// by Xteam.
CodeGenModule::NoLoopXteamErr
getStatusOptKernelAMDGCNBuiltin(const CallExpr *C) const;
/// Is the function name recognized as a min builtin by the device compile?
bool isOptKernelAMDGCNMin(const CallExpr *Call) const {
std::string CallName = Call->getDirectCallee()->getNameInfo().getAsString();
if (isStdNameSpace(Call) && !CallName.compare("min"))
return true;
return (!CallName.compare("fmin[device={arch(amdgcn)}]") ||
!CallName.compare("fminf[device={arch(amdgcn)}]") ||
!CallName.compare("fminl[device={arch(amdgcn)}]") ||
!CallName.compare("fmin") || !CallName.compare("fminf") ||
!CallName.compare("fminl") || !CallName.compare("__builtin_fmin") ||
!CallName.compare("__builtin_fminf") ||
!CallName.compare("__builtin_fminl"));
}
// Is the function name recognized as a max builtin by the device compile?
bool isOptKernelAMDGCNMax(const CallExpr *Call) const {
std::string CallName = Call->getDirectCallee()->getNameInfo().getAsString();
if (isStdNameSpace(Call) && !CallName.compare("max"))
return true;
return (!CallName.compare("fmax[device={arch(amdgcn)}]") ||
!CallName.compare("fmaxf[device={arch(amdgcn)}]") ||
!CallName.compare("fmaxl[device={arch(amdgcn)}]") ||
!CallName.compare("fmax") || !CallName.compare("fmaxf") ||
!CallName.compare("fmaxl") || !CallName.compare("__builtin_fmax") ||
!CallName.compare("__builtin_fmaxf") ||
!CallName.compare("__builtin_fmaxl"));
}
/// Return status indicating whether the call expression is supported by Xteam
/// as a builtin
CodeGenModule::NoLoopXteamErr getStatusOptKernelBuiltin(const CallExpr *C);
/// Return status indicating if the pseudo-object expression is supported by
/// Xteam
std::pair<CodeGenModule::NoLoopXteamErr, const Expr *>
getStatusXteamSupportedPseudoObject(const PseudoObjectExpr *PO);
/// Are we generating multi-device kernel for the statement
bool multiDeviceFStmtEntryExists(const Stmt *S) {
return MultiDeviceKernels.find(S) != MultiDeviceKernels.end();
}
bool isMultiDeviceKernel(const Stmt *S) {
if (MultiDeviceKernels.find(S) == MultiDeviceKernels.end())
return false;
MultiDeviceKernelInfo MDInfo = MultiDeviceKernels.find(S)->second;
return MDInfo.CanBeMultiDevice;
}
bool isMultiDeviceKernel(const OMPExecutableDirective &D);
/// Given a ForStmt for which Multi Device codegen will be done, save the
/// metadata for the LB and UB args.
void saveMultiDeviceArgs(const OMPExecutableDirective &D,
const llvm::Function *F, VarDecl *LBDecl,
VarDecl *UBDecl) {
assert(isMultiDeviceKernel(getSingleForStmt(getOptKernelKey(D))) &&
"Must be a multi-device kernel");
const ForStmt *FStmt = getSingleForStmt(getOptKernelKey(D));
assert((MultiDeviceKernels.find(FStmt) != MultiDeviceKernels.end()) &&
"FStmt not found");
MultiDeviceKernelInfo &MDInfo = MultiDeviceKernels.find(FStmt)->second;
MDInfo.FunctionBoundsMap.insert(
std::make_pair(F, MultiDeviceBoundsInfo(LBDecl, UBDecl)));
}
/// Retrieve the metadata for the LB arg.
MultiDeviceBoundsInfo getMultiDeviceBounds(const OMPExecutableDirective &D,
const llvm::Function *F) {
const ForStmt *FStmt = getSingleForStmt(getOptKernelKey(D));
assert((MultiDeviceKernels.find(FStmt) != MultiDeviceKernels.end()) &&
"FStmt not found");
MultiDeviceKernelInfo MDInfo = MultiDeviceKernels.find(FStmt)->second;
assert(MDInfo.FunctionBoundsMap.find(F) != MDInfo.FunctionBoundsMap.end() &&
"Function must exist");
return MDInfo.FunctionBoundsMap.find(F)->second;
}
/// Retrieve the metadata for the LB arg.
VarDecl *getMultiDeviceLBArg(const OMPExecutableDirective &D,
const llvm::Function *F) {
return getMultiDeviceBounds(D, F).LBArg;
}
/// Retrieve the metadata for the LB arg.
VarDecl *getMultiDeviceUBArg(const OMPExecutableDirective &D,
const llvm::Function *F) {
return getMultiDeviceBounds(D, F).UBArg;
}
/// Move some lazily-emitted states to the NewBuilder. This is especially
/// essential for the incremental parsing environment like Clang Interpreter,
/// because we'll lose all important information after each repl.
void moveLazyEmissionStates(CodeGenModule *NewBuilder);
/// Emit the IR encoding to attach the CUDA launch bounds attribute to \p F.
/// If \p MaxThreadsVal is not nullptr, the max threads value is stored in it,
/// if a valid one was found.
void handleCUDALaunchBoundsAttr(llvm::Function *F,
const CUDALaunchBoundsAttr *A,
int32_t *MaxThreadsVal = nullptr,
int32_t *MinBlocksVal = nullptr,
int32_t *MaxClusterRankVal = nullptr);
/// Emit the IR encoding to attach the AMD GPU flat-work-group-size attribute
/// to \p F. Alternatively, the work group size can be taken from a \p
/// ReqdWGS. If \p MinThreadsVal is not nullptr, the min threads value is
/// stored in it, if a valid one was found. If \p MaxThreadsVal is not
/// nullptr, the max threads value is stored in it, if a valid one was found.
void handleAMDGPUFlatWorkGroupSizeAttr(
llvm::Function *F, const AMDGPUFlatWorkGroupSizeAttr *A,
const ReqdWorkGroupSizeAttr *ReqdWGS = nullptr,
int32_t *MinThreadsVal = nullptr, int32_t *MaxThreadsVal = nullptr);
/// Emit the IR encoding to attach the AMD GPU waves-per-eu attribute to \p F.
void handleAMDGPUWavesPerEUAttr(llvm::Function *F,
const AMDGPUWavesPerEUAttr *A);
llvm::Constant *
GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty, LangAS AddrSpace,
const VarDecl *D,
ForDefinition_t IsForDefinition = NotForDefinition);
// FIXME: Hardcoding priority here is gross.
void AddGlobalCtor(llvm::Function *Ctor, int Priority = 65535,
unsigned LexOrder = ~0U,
llvm::Constant *AssociatedData = nullptr);
void AddGlobalDtor(llvm::Function *Dtor, int Priority = 65535,
bool IsDtorAttrFunc = false);
// Return whether structured convergence intrinsics should be generated for
// this target.
bool shouldEmitConvergenceTokens() const {
// TODO: this should probably become unconditional once the controlled
// convergence becomes the norm.
return getTriple().isSPIRVLogical() || getTriple().isDXIL();
}
void addUndefinedGlobalForTailCall(
std::pair<const FunctionDecl *, SourceLocation> Global) {
MustTailCallUndefinedGlobals.insert(Global);
}
bool shouldZeroInitPadding() const {
// In C23 (N3096) $6.7.10:
// """
// If any object is initialized with an empty iniitializer, then it is
// subject to default initialization:
// - if it is an aggregate, every member is initialized (recursively)
// according to these rules, and any padding is initialized to zero bits;
// - if it is a union, the first named member is initialized (recursively)
// according to these rules, and any padding is initialized to zero bits.
//
// If the aggregate or union contains elements or members that are
// aggregates or unions, these rules apply recursively to the subaggregates
// or contained unions.
//
// If there are fewer initializers in a brace-enclosed list than there are
// elements or members of an aggregate, or fewer characters in a string
// literal used to initialize an array of known size than there are elements
// in the array, the remainder of the aggregate is subject to default
// initialization.
// """
//
// From my understanding, the standard is ambiguous in the following two
// areas:
// 1. For a union type with empty initializer, if the first named member is
// not the largest member, then the bytes comes after the first named member
// but before padding are left unspecified. An example is:
// union U { int a; long long b;};
// union U u = {}; // The first 4 bytes are 0, but 4-8 bytes are left
// unspecified.
//
// 2. It only mentions padding for empty initializer, but doesn't mention
// padding for a non empty initialization list. And if the aggregation or
// union contains elements or members that are aggregates or unions, and
// some are non empty initializers, while others are empty initiailizers,
// the padding initialization is unclear. An example is:
// struct S1 { int a; long long b; };
// struct S2 { char c; struct S1 s1; };
// // The values for paddings between s2.c and s2.s1.a, between s2.s1.a
// and s2.s1.b are unclear.
// struct S2 s2 = { 'c' };
//
// Here we choose to zero initiailize left bytes of a union type. Because
// projects like the Linux kernel are relying on this behavior. If we don't
// explicitly zero initialize them, the undef values can be optimized to
// return gabage data. We also choose to zero initialize paddings for
// aggregates and unions, no matter they are initialized by empty
// initializers or non empty initializers. This can provide a consistent
// behavior. So projects like the Linux kernel can rely on it.
return !getLangOpts().CPlusPlus;
}
// Helper to get the alignment for a variable.
unsigned getVtableGlobalVarAlignment(const VarDecl *D = nullptr) {
LangAS AS = GetGlobalVarAddressSpace(D);
unsigned PAlign = Context.getLangOpts().RelativeCXXABIVTables
? 32
: getTarget().getPointerAlign(AS);
return PAlign;
}
/// Helper function to construct a TrapReasonBuilder
TrapReasonBuilder BuildTrapReason(unsigned DiagID, TrapReason &TR) {
return TrapReasonBuilder(&getDiags(), DiagID, TR);
}
llvm::Constant *performAddrSpaceCast(llvm::Constant *Src,
llvm::Type *DestTy) {
// Since target may map different address spaces in AST to the same address
// space, an address space conversion may end up as a bitcast.
return llvm::ConstantExpr::getPointerCast(Src, DestTy);
}
std::optional<llvm::Attribute::AttrKind>
StackProtectorAttribute(const Decl *D) const;
std::string getPFPFieldName(const FieldDecl *FD);
llvm::GlobalValue *getPFPDeactivationSymbol(const FieldDecl *FD);
private:
/// Translate an llvm::abi::ArgInfo (computed by the LLVMABI library) into
/// the clang ABIArgInfo consumed by the rest of CodeGen. Used by the
/// experimental ABI lowering path.
ABIArgInfo convertABIArgInfo(const llvm::abi::ArgInfo &AbiInfo,
QualType Type);
bool shouldDropDLLAttribute(const Decl *D, const llvm::GlobalValue *GV) const;
llvm::Constant *GetOrCreateLLVMFunction(
StringRef MangledName, llvm::Type *Ty, GlobalDecl D, bool ForVTable,
bool DontDefer = false, bool IsThunk = false,
llvm::AttributeList ExtraAttrs = llvm::AttributeList(),
ForDefinition_t IsForDefinition = NotForDefinition);
// Adds a declaration to the list of multi version functions if not present.
void AddDeferredMultiVersionResolverToEmit(GlobalDecl GD);
// References to multiversion functions are resolved through an implicitly
// defined resolver function. This function is responsible for creating
// the resolver symbol for the provided declaration. The value returned
// will be for an ifunc (llvm::GlobalIFunc) if the current target supports
// that feature and for a regular function (llvm::GlobalValue) otherwise.
llvm::Constant *GetOrCreateMultiVersionResolver(GlobalDecl GD);
// Set attributes to a resolver function generated by Clang.
// GD is either the cpu_dispatch declaration or an arbitrarily chosen
// function declaration that triggered the implicit generation of this
// resolver function.
//
/// NOTE: This should only be called for definitions.
void setMultiVersionResolverAttributes(llvm::Function *Resolver,
GlobalDecl GD);
// In scenarios where a function is not known to be a multiversion function
// until a later declaration, it is sometimes necessary to change the
// previously created mangled name to align with requirements of whatever
// multiversion function kind the function is now known to be. This function
// is responsible for performing such mangled name updates.
void UpdateMultiVersionNames(GlobalDecl GD, const FunctionDecl *FD,
StringRef &CurName);
bool GetCPUAndFeaturesAttributes(GlobalDecl GD,
llvm::AttrBuilder &AttrBuilder,
bool SetTargetFeatures = true);
void setNonAliasAttributes(GlobalDecl GD, llvm::GlobalObject *GO);
/// Set function attributes for a function declaration.
void SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
bool IsIncompleteFunction, bool IsThunk);
void EmitGlobalDefinition(GlobalDecl D, llvm::GlobalValue *GV = nullptr);
void EmitGlobalFunctionDefinition(GlobalDecl GD, llvm::GlobalValue *GV);
void EmitMultiVersionFunctionDefinition(GlobalDecl GD, llvm::GlobalValue *GV);
void EmitGlobalVarDefinition(const VarDecl *D, bool IsTentative = false);
void EmitAliasDefinition(GlobalDecl GD);
void emitIFuncDefinition(GlobalDecl GD);
void emitCPUDispatchDefinition(GlobalDecl GD);
void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D);
void EmitObjCIvarInitializations(ObjCImplementationDecl *D);
// C++ related functions.
void EmitDeclContext(const DeclContext *DC);
void EmitLinkageSpec(const LinkageSpecDecl *D);
void EmitTopLevelStmt(const TopLevelStmtDecl *D);
/// Emit the function that initializes C++ thread_local variables.
void EmitCXXThreadLocalInitFunc();
/// Emit the function that initializes global variables for a C++ Module.
void EmitCXXModuleInitFunc(clang::Module *Primary);
/// Emit the function that initializes C++ globals.
void EmitCXXGlobalInitFunc();
/// Emit the function that performs cleanup associated with C++ globals.
void EmitCXXGlobalCleanUpFunc();
/// Emit the function that initializes the specified global (if PerformInit is
/// true) and registers its destructor.
void EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
llvm::GlobalVariable *Addr,
bool PerformInit);
void EmitPointerToInitFunc(const VarDecl *VD, llvm::GlobalVariable *Addr,
llvm::Function *InitFunc, InitSegAttr *ISA);
/// EmitCtorList - Generates a global array of functions and priorities using
/// the given list and name. This array will have appending linkage and is
/// suitable for use as a LLVM constructor or destructor array. Clears Fns.
void EmitCtorList(CtorList &Fns, const char *GlobalName);
/// Emit any needed decls for which code generation was deferred.
void EmitDeferred();
/// Try to emit external vtables as available_externally if they have emitted
/// all inlined virtual functions. It runs after EmitDeferred() and therefore
/// is not allowed to create new references to things that need to be emitted
/// lazily.
void EmitVTablesOpportunistically();
/// Call replaceAllUsesWith on all pairs in Replacements.
void applyReplacements();
/// Call replaceAllUsesWith on all pairs in GlobalValReplacements.
void applyGlobalValReplacements();
void checkAliases();
std::map<int, llvm::TinyPtrVector<llvm::Function *>> DtorsUsingAtExit;
/// Register functions annotated with __attribute__((destructor)) using
/// __cxa_atexit, if it is available, or atexit otherwise.
void registerGlobalDtorsWithAtExit();
// When using sinit and sterm functions, unregister
// __attribute__((destructor)) annotated functions which were previously
// registered by the atexit subroutine using unatexit.
void unregisterGlobalDtorsWithUnAtExit();
/// Emit deferred multiversion function resolvers and associated variants.
void emitMultiVersionFunctions();
/// Emit any vtables which we deferred and still have a use for.
void EmitDeferredVTables();
/// Emit a dummy function that reference a CoreFoundation symbol when
/// @available is used on Darwin.
void emitAtAvailableLinkGuard();
/// Emit the llvm.used and llvm.compiler.used metadata.
void emitLLVMUsed();
/// For C++20 Itanium ABI, emit the initializers for the module.
void EmitModuleInitializers(clang::Module *Primary);
/// Emit the link options introduced by imported modules.
void EmitModuleLinkOptions();
/// Helper function for EmitStaticExternCAliases() to redirect ifuncs that
/// have a resolver name that matches 'Elem' to instead resolve to the name of
/// 'CppFunc'. This redirection is necessary in cases where 'Elem' has a name
/// that will be emitted as an alias of the name bound to 'CppFunc'; ifuncs
/// may not reference aliases. Redirection is only performed if 'Elem' is only
/// used by ifuncs in which case, 'Elem' is destroyed. 'true' is returned if
/// redirection is successful, and 'false' is returned otherwise.
bool CheckAndReplaceExternCIFuncs(llvm::GlobalValue *Elem,
llvm::GlobalValue *CppFunc);
/// Emit aliases for internal-linkage declarations inside "C" language
/// linkage specifications, giving them the "expected" name where possible.
void EmitStaticExternCAliases();
void EmitDeclMetadata();
/// Emit the Clang version as llvm.ident metadata.
void EmitVersionIdentMetadata();
/// Emit the Clang commandline as llvm.commandline metadata.
void EmitCommandLineMetadata();
/// Emit the module flag metadata used to pass options controlling the
/// the backend to LLVM.
void EmitBackendOptionsMetadata(const CodeGenOptions &CodeGenOpts);
/// Emits OpenCL specific Metadata e.g. OpenCL version.
void EmitOpenCLMetadata();
/// Emit the llvm.gcov metadata used to tell LLVM where to emit the .gcno and
/// .gcda files in a way that persists in .bc files.
void EmitCoverageFile();
/// Given a sycl_kernel_entry_point attributed function, emit the
/// corresponding SYCL kernel caller offload entry point function.
void EmitSYCLKernelCaller(const FunctionDecl *KernelEntryPointFn,
ASTContext &Ctx);
/// Attach the "sycl-module-id" function attribute to \p Fn, to record the
/// module ID for the translation unit. This attribute is applied to SYCL
/// kernel entry point functions and functions declared with the
/// sycl_external attribute to enable them to be identified as entry points
/// by clang-sycl-linker during device-code splitting.
void addSYCLModuleIdAttr(llvm::Function *Fn);
/// 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 ValueDecl *D);
/// 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 ValueDecl *D);
/// Check whether we can use a "simpler", more core exceptions personality
/// function.
void SimplifyPersonality();
/// Helper function for getDefaultFunctionAttributes. Builds a set of function
/// attributes which can be simply added to a function.
void getTrivialDefaultFunctionAttributes(StringRef Name, bool HasOptnone,
bool AttrOnCallSite,
llvm::AttrBuilder &FuncAttrs);
/// Helper function for ConstructAttributeList and
/// addDefaultFunctionDefinitionAttributes. Builds a set of function
/// attributes to add to a function with the given properties.
void getDefaultFunctionAttributes(StringRef Name, bool HasOptnone,
bool AttrOnCallSite,
llvm::AttrBuilder &FuncAttrs);
llvm::Metadata *CreateMetadataIdentifierImpl(QualType T, MetadataTypeMap &Map,
StringRef Suffix);
/// Return success if the directives are nested in a way appropriate for
/// specialized kernel generation. Track the component directives in
/// a vector. Otherwise return an error code.
NoLoopXteamErr checkNest(const OMPExecutableDirective &D,
OptKernelNestDirectives *NestDirs);
NoLoopXteamErr checkTargetNest(const OMPExecutableDirective &D,
OptKernelNestDirectives *NestDirs);
NoLoopXteamErr checkTargetTeamsNest(const OMPExecutableDirective &D,
OptKernelNestDirectives *NestDirs);
/// Top level checker for no-loop on the for statement
std::pair<NoLoopXteamErr, bool>
getNoLoopForStmtStatus(const OMPExecutableDirective &, const Stmt *);
// Compute the block size used by optimized kernels.
int computeOptKernelBlockSize(const OptKernelNestDirectives &NestDirs,
bool isXteamRed);
/// Top level checker for xteam reduction of the loop
std::pair<NoLoopXteamErr, bool>
getXteamRedForStmtStatus(const OMPExecutableDirective &, const Stmt *,
XteamRedVarMap *);
/// Are clauses on a combined OpenMP construct compatible with no-loop
/// codegen?
NoLoopXteamErr
getNoLoopStatusForClauses(const OptKernelNestDirectives &NestDirs);
/// Are clauses on a combined OpenMP construct compatible with xteam
/// reduction codegen?
NoLoopXteamErr
getXteamRedStatusForClauses(const OptKernelNestDirectives &NestDirs);
/// Collect the reduction variables that may satisfy Xteam criteria
std::pair<NoLoopXteamErr, XteamRedCollectionInfo>
collectXteamRedVars(const OptKernelNestDirectives &NestDirs);
/// Top level checker for multi device of the loop
NoLoopXteamErr getMultiDeviceForStmtStatus(const OMPExecutableDirective &,
const Stmt *);
/// Are clauses on a combined OpenMP construct compatible with multi-device
/// codegen?
NoLoopXteamErr
getMultiDeviceStatusForClauses(const OptKernelNestDirectives &NestDirs);
/// Emit deactivation symbols for any PFP fields whose offset is taken with
/// offsetof.
void emitPFPFieldsWithEvaluatedOffset();
};
} // end namespace CodeGen
} // end namespace clang
#endif // LLVM_CLANG_LIB_CODEGEN_CODEGENMODULE_H