#include "CGCXXABI.h"
#include "CGHLSLRuntime.h"
#include "CGObjCRuntime.h"
#include "CGOpenMPRuntime.h"
#include "CodeGenFunction.h"
#include "TargetInfo.h"
#include "clang/AST/Attr.h"
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/Support/Path.h"
using namespace clang;
using namespace CodeGen;
static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
ConstantAddress DeclPtr) {
assert(
(D.hasGlobalStorage() ||
(D.hasLocalStorage() && CGF.getContext().getLangOpts().OpenCLCPlusPlus)) &&
"VarDecl must have global or local (in the case of OpenCL) storage!");
assert(!D.getType()->isReferenceType() &&
"Should not call EmitDeclInit on a reference!");
QualType type = D.getType();
LValue lv = CGF.MakeAddrLValue(DeclPtr, type);
const Expr *Init = D.getInit();
switch (CGF.getEvaluationKind(type)) {
case TEK_Scalar: {
CodeGenModule &CGM = CGF.CGM;
if (lv.isObjCStrong())
CGM.getObjCRuntime().EmitObjCGlobalAssign(CGF, CGF.EmitScalarExpr(Init),
DeclPtr, D.getTLSKind());
else if (lv.isObjCWeak())
CGM.getObjCRuntime().EmitObjCWeakAssign(CGF, CGF.EmitScalarExpr(Init),
DeclPtr);
else
CGF.EmitScalarInit(Init, &D, lv, false);
return;
}
case TEK_Complex:
CGF.EmitComplexExprIntoLValue(Init, lv, true);
return;
case TEK_Aggregate:
CGF.EmitAggExpr(Init,
AggValueSlot::forLValue(lv, AggValueSlot::IsDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased,
AggValueSlot::DoesNotOverlap));
return;
}
llvm_unreachable("bad evaluation kind");
}
static void EmitDeclDestroy(CodeGenFunction &CGF, const VarDecl &D,
ConstantAddress Addr) {
QualType::DestructionKind DtorKind = D.needsDestruction(CGF.getContext());
switch (DtorKind) {
case QualType::DK_none:
return;
case QualType::DK_cxx_destructor:
break;
case QualType::DK_objc_strong_lifetime:
case QualType::DK_objc_weak_lifetime:
case QualType::DK_nontrivial_c_struct:
assert(!D.getTLSKind() && "should have rejected this");
return;
}
llvm::FunctionCallee Func;
llvm::Constant *Argument;
CodeGenModule &CGM = CGF.CGM;
QualType Type = D.getType();
const CXXRecordDecl *Record = Type->getAsCXXRecordDecl();
bool CanRegisterDestructor =
Record && (!CGM.getCXXABI().HasThisReturn(
GlobalDecl(Record->getDestructor(), Dtor_Complete)) ||
CGM.getCXXABI().canCallMismatchedFunctionType());
bool UsingExternalHelper = !CGM.getCodeGenOpts().CXAAtExit;
if (Record && (CanRegisterDestructor || UsingExternalHelper)) {
assert(!Record->hasTrivialDestructor());
CXXDestructorDecl *Dtor = Record->getDestructor();
Func = CGM.getAddrAndTypeOfCXXStructor(GlobalDecl(Dtor, Dtor_Complete));
if (CGF.getContext().getLangOpts().OpenCL) {
auto DestAS =
CGM.getTargetCodeGenInfo().getAddrSpaceOfCxaAtexitPtrParam();
auto DestTy = llvm::PointerType::get(
CGM.getLLVMContext(), CGM.getContext().getTargetAddressSpace(DestAS));
auto SrcAS = D.getType().getQualifiers().getAddressSpace();
if (DestAS == SrcAS)
Argument = Addr.getPointer();
else
Argument = llvm::ConstantPointerNull::get(DestTy);
} else {
Argument = Addr.getPointer();
}
} else {
Addr = Addr.withElementType(CGF.ConvertTypeForMem(Type));
Func = CodeGenFunction(CGM)
.generateDestroyHelper(Addr, Type, CGF.getDestroyer(DtorKind),
CGF.needsEHCleanup(DtorKind), &D);
Argument = llvm::Constant::getNullValue(CGF.Int8PtrTy);
}
CGM.getCXXABI().registerGlobalDtor(CGF, D, Func, Argument);
}
static void EmitDeclInvariant(CodeGenFunction &CGF, const VarDecl &D,
llvm::Constant *Addr) {
return CGF.EmitInvariantStart(
Addr, CGF.getContext().getTypeSizeInChars(D.getType()));
}
void CodeGenFunction::EmitInvariantStart(llvm::Constant *Addr, CharUnits Size) {
if (!CGM.getCodeGenOpts().OptimizationLevel)
return;
llvm::Intrinsic::ID InvStartID = llvm::Intrinsic::invariant_start;
assert(Addr->getType()->isPointerTy() && "Address must be a pointer");
llvm::Type *ObjectPtr[1] = {Addr->getType()};
llvm::Function *InvariantStart = CGM.getIntrinsic(InvStartID, ObjectPtr);
uint64_t Width = Size.getQuantity();
llvm::Value *Args[2] = {llvm::ConstantInt::getSigned(Int64Ty, Width), Addr};
Builder.CreateCall(InvariantStart, Args);
}
void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
llvm::GlobalVariable *GV,
bool PerformInit) {
const Expr *Init = D.getInit();
QualType T = D.getType();
unsigned ExpectedAddrSpace = getTypes().getTargetAddressSpace(T);
unsigned ActualAddrSpace = GV->getAddressSpace();
llvm::Constant *DeclPtr = GV;
if (ActualAddrSpace != ExpectedAddrSpace) {
llvm::PointerType *PTy =
llvm::PointerType::get(getLLVMContext(), ExpectedAddrSpace);
DeclPtr = llvm::ConstantExpr::getAddrSpaceCast(DeclPtr, PTy);
}
ConstantAddress DeclAddr(
DeclPtr, GV->getValueType(), getContext().getDeclAlign(&D));
if (!T->isReferenceType()) {
if (getLangOpts().OpenMP && !getLangOpts().OpenMPSimd &&
D.hasAttr<OMPThreadPrivateDeclAttr>()) {
(void)CGM.getOpenMPRuntime().emitThreadPrivateVarDefinition(
&D, DeclAddr, D.getAttr<OMPThreadPrivateDeclAttr>()->getLocation(),
PerformInit, this);
}
bool NeedsDtor =
D.needsDestruction(getContext()) == QualType::DK_cxx_destructor;
if (PerformInit)
EmitDeclInit(*this, D, DeclAddr);
if (D.getType().isConstantStorage(getContext(), true, !NeedsDtor))
EmitDeclInvariant(*this, D, DeclPtr);
else
EmitDeclDestroy(*this, D, DeclAddr);
return;
}
assert(PerformInit && "cannot have constant initializer which needs "
"destruction for reference");
RValue RV = EmitReferenceBindingToExpr(Init);
EmitStoreOfScalar(RV.getScalarVal(), DeclAddr, false, T);
}
llvm::Constant *CodeGenFunction::createAtExitStub(const VarDecl &VD,
llvm::FunctionCallee dtor,
llvm::Constant *addr) {
llvm::FunctionType *ty = llvm::FunctionType::get(CGM.VoidTy, false);
SmallString<256> FnName;
{
llvm::raw_svector_ostream Out(FnName);
CGM.getCXXABI().getMangleContext().mangleDynamicAtExitDestructor(&VD, Out);
}
const CGFunctionInfo &FI = CGM.getTypes().arrangeNullaryFunction();
llvm::Function *fn = CGM.CreateGlobalInitOrCleanUpFunction(
ty, FnName.str(), FI, VD.getLocation());
CodeGenFunction CGF(CGM);
CGF.StartFunction(GlobalDecl(&VD, DynamicInitKind::AtExit),
CGM.getContext().VoidTy, fn, FI, FunctionArgList(),
VD.getLocation(), VD.getInit()->getExprLoc());
auto AL = ApplyDebugLocation::CreateArtificial(CGF);
llvm::CallInst *call = CGF.Builder.CreateCall(dtor, addr);
if (auto *dtorFn = dyn_cast<llvm::Function>(
dtor.getCallee()->stripPointerCastsAndAliases()))
call->setCallingConv(dtorFn->getCallingConv());
CGF.FinishFunction();
FunctionProtoType::ExtProtoInfo EPI(getContext().getDefaultCallingConvention(
false, false));
QualType fnType = getContext().getFunctionType(getContext().VoidTy,
{getContext().VoidPtrTy}, EPI);
return CGM.getFunctionPointer(fn, fnType);
}
llvm::Function *CodeGenFunction::createTLSAtExitStub(
const VarDecl &D, llvm::FunctionCallee Dtor, llvm::Constant *Addr,
llvm::FunctionCallee &AtExit) {
SmallString<256> FnName;
{
llvm::raw_svector_ostream Out(FnName);
CGM.getCXXABI().getMangleContext().mangleDynamicAtExitDestructor(&D, Out);
}
const CGFunctionInfo &FI = CGM.getTypes().arrangeLLVMFunctionInfo(
getContext().IntTy, FnInfoOpts::None, {getContext().IntTy},
FunctionType::ExtInfo(), {}, RequiredArgs::All);
llvm::FunctionType *StubTy =
llvm::FunctionType::get(CGM.IntTy, {CGM.IntTy}, true);
llvm::Function *DtorStub = CGM.CreateGlobalInitOrCleanUpFunction(
StubTy, FnName.str(), FI, D.getLocation());
CodeGenFunction CGF(CGM);
FunctionArgList Args;
ImplicitParamDecl IPD(CGM.getContext(), CGM.getContext().IntTy,
ImplicitParamKind::Other);
Args.push_back(&IPD);
QualType ResTy = CGM.getContext().IntTy;
CGF.StartFunction(GlobalDecl(&D, DynamicInitKind::AtExit), ResTy, DtorStub,
FI, Args, D.getLocation(), D.getInit()->getExprLoc());
auto AL = ApplyDebugLocation::CreateArtificial(CGF);
llvm::CallInst *call = CGF.Builder.CreateCall(Dtor, Addr);
if (auto *DtorFn = dyn_cast<llvm::Function>(
Dtor.getCallee()->stripPointerCastsAndAliases()))
call->setCallingConv(DtorFn->getCallingConv());
CGF.Builder.CreateStore(llvm::Constant::getNullValue(CGM.IntTy),
CGF.ReturnValue);
CGF.FinishFunction();
return DtorStub;
}
void CodeGenFunction::registerGlobalDtorWithAtExit(const VarDecl &VD,
llvm::FunctionCallee dtor,
llvm::Constant *addr) {
llvm::Constant *dtorStub = createAtExitStub(VD, dtor, addr);
registerGlobalDtorWithAtExit(dtorStub);
}
void CodeGenFunction::registerGlobalDtorWithLLVM(const VarDecl &VD,
llvm::FunctionCallee Dtor,
llvm::Constant *Addr) {
llvm::Function *dtorStub =
cast<llvm::Function>(createAtExitStub(VD, Dtor, Addr));
CGM.AddGlobalDtor(dtorStub);
}
void CodeGenFunction::registerGlobalDtorWithAtExit(llvm::Constant *dtorStub) {
assert(dtorStub->getType() ==
llvm::PointerType::get(
llvm::FunctionType::get(CGM.VoidTy, false),
dtorStub->getType()->getPointerAddressSpace()) &&
"Argument to atexit has a wrong type.");
llvm::FunctionType *atexitTy =
llvm::FunctionType::get(IntTy, dtorStub->getType(), false);
llvm::FunctionCallee atexit =
CGM.CreateRuntimeFunction(atexitTy, "atexit", llvm::AttributeList(),
true);
if (llvm::Function *atexitFn = dyn_cast<llvm::Function>(atexit.getCallee()))
atexitFn->setDoesNotThrow();
EmitNounwindRuntimeCall(atexit, dtorStub);
}
llvm::Value *
CodeGenFunction::unregisterGlobalDtorWithUnAtExit(llvm::Constant *dtorStub) {
assert(dtorStub->getType() ==
llvm::PointerType::get(
llvm::FunctionType::get(CGM.VoidTy, false),
dtorStub->getType()->getPointerAddressSpace()) &&
"Argument to unatexit has a wrong type.");
llvm::FunctionType *unatexitTy =
llvm::FunctionType::get(IntTy, {dtorStub->getType()}, false);
llvm::FunctionCallee unatexit =
CGM.CreateRuntimeFunction(unatexitTy, "unatexit", llvm::AttributeList());
cast<llvm::Function>(unatexit.getCallee())->setDoesNotThrow();
return EmitNounwindRuntimeCall(unatexit, dtorStub);
}
void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D,
llvm::GlobalVariable *DeclPtr,
bool PerformInit) {
if (CGM.getCodeGenOpts().ForbidGuardVariables)
CGM.Error(D.getLocation(),
"this initialization requires a guard variable, which "
"the kernel does not support");
CGM.getCXXABI().EmitGuardedInit(*this, D, DeclPtr, PerformInit);
}
void CodeGenFunction::EmitCXXGuardedInitBranch(llvm::Value *NeedsInit,
llvm::BasicBlock *InitBlock,
llvm::BasicBlock *NoInitBlock,
GuardKind Kind,
const VarDecl *D) {
assert((Kind == GuardKind::TlsGuard || D) && "no guarded variable");
static const uint64_t InitsPerTLSVar = 1024;
static const uint64_t InitsPerLocalVar = 1024 * 1024;
llvm::MDNode *Weights;
if (Kind == GuardKind::VariableGuard && !D->isLocalVarDecl()) {
Weights = nullptr;
} else {
uint64_t NumInits;
if (Kind == GuardKind::TlsGuard || D->getTLSKind())
NumInits = InitsPerTLSVar;
else
NumInits = InitsPerLocalVar;
llvm::MDBuilder MDHelper(CGM.getLLVMContext());
Weights = MDHelper.createBranchWeights(1, NumInits - 1);
}
Builder.CreateCondBr(NeedsInit, InitBlock, NoInitBlock, Weights);
}
llvm::Function *CodeGenModule::CreateGlobalInitOrCleanUpFunction(
llvm::FunctionType *FTy, const Twine &Name, const CGFunctionInfo &FI,
SourceLocation Loc, bool TLS, llvm::GlobalVariable::LinkageTypes Linkage) {
llvm::Function *Fn = llvm::Function::Create(FTy, Linkage, Name, &getModule());
if (!getLangOpts().AppleKext && !TLS) {
if (const char *Section = getTarget().getStaticInitSectionSpecifier())
Fn->setSection(Section);
}
if (Linkage == llvm::GlobalVariable::InternalLinkage)
SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
Fn->setCallingConv(getRuntimeCC());
if (!getLangOpts().Exceptions)
Fn->setDoesNotThrow();
if (getLangOpts().Sanitize.has(SanitizerKind::Address) &&
!isInNoSanitizeList(SanitizerKind::Address, Fn, Loc))
Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
if (getLangOpts().Sanitize.has(SanitizerKind::KernelAddress) &&
!isInNoSanitizeList(SanitizerKind::KernelAddress, Fn, Loc))
Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
if (getLangOpts().Sanitize.has(SanitizerKind::HWAddress) &&
!isInNoSanitizeList(SanitizerKind::HWAddress, Fn, Loc))
Fn->addFnAttr(llvm::Attribute::SanitizeHWAddress);
if (getLangOpts().Sanitize.has(SanitizerKind::KernelHWAddress) &&
!isInNoSanitizeList(SanitizerKind::KernelHWAddress, Fn, Loc))
Fn->addFnAttr(llvm::Attribute::SanitizeHWAddress);
if (getLangOpts().Sanitize.has(SanitizerKind::MemtagStack) &&
!isInNoSanitizeList(SanitizerKind::MemtagStack, Fn, Loc))
Fn->addFnAttr(llvm::Attribute::SanitizeMemTag);
if (getLangOpts().Sanitize.has(SanitizerKind::Thread) &&
!isInNoSanitizeList(SanitizerKind::Thread, Fn, Loc))
Fn->addFnAttr(llvm::Attribute::SanitizeThread);
if (getLangOpts().Sanitize.has(SanitizerKind::NumericalStability) &&
!isInNoSanitizeList(SanitizerKind::NumericalStability, Fn, Loc))
Fn->addFnAttr(llvm::Attribute::SanitizeNumericalStability);
if (getLangOpts().Sanitize.has(SanitizerKind::Memory) &&
!isInNoSanitizeList(SanitizerKind::Memory, Fn, Loc))
Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
if (getLangOpts().Sanitize.has(SanitizerKind::KernelMemory) &&
!isInNoSanitizeList(SanitizerKind::KernelMemory, Fn, Loc))
Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
if (getLangOpts().Sanitize.has(SanitizerKind::SafeStack) &&
!isInNoSanitizeList(SanitizerKind::SafeStack, Fn, Loc))
Fn->addFnAttr(llvm::Attribute::SafeStack);
if (getLangOpts().Sanitize.has(SanitizerKind::ShadowCallStack) &&
!isInNoSanitizeList(SanitizerKind::ShadowCallStack, Fn, Loc))
Fn->addFnAttr(llvm::Attribute::ShadowCallStack);
return Fn;
}
void CodeGenModule::EmitPointerToInitFunc(const VarDecl *D,
llvm::GlobalVariable *GV,
llvm::Function *InitFunc,
InitSegAttr *ISA) {
llvm::GlobalVariable *PtrArray = new llvm::GlobalVariable(
TheModule, InitFunc->getType(), true,
llvm::GlobalValue::PrivateLinkage, InitFunc, "__cxx_init_fn_ptr");
PtrArray->setSection(ISA->getSection());
addUsedGlobal(PtrArray);
if (llvm::Comdat *C = GV->getComdat())
PtrArray->setComdat(C);
}
void
CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
llvm::GlobalVariable *Addr,
bool PerformInit) {
if (getLangOpts().CUDAIsDevice && !getLangOpts().GPUAllowDeviceInit &&
(D->hasAttr<CUDADeviceAttr>() || D->hasAttr<CUDAConstantAttr>() ||
D->hasAttr<CUDASharedAttr>()))
return;
auto I = DelayedCXXInitPosition.find(D);
if (I != DelayedCXXInitPosition.end() && I->second == ~0U)
return;
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
SmallString<256> FnName;
{
llvm::raw_svector_ostream Out(FnName);
getCXXABI().getMangleContext().mangleDynamicInitializer(D, Out);
}
llvm::Function *Fn = CreateGlobalInitOrCleanUpFunction(
FTy, FnName.str(), getTypes().arrangeNullaryFunction(), D->getLocation());
auto *ISA = D->getAttr<InitSegAttr>();
CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr,
PerformInit);
llvm::GlobalVariable *COMDATKey =
supportsCOMDAT() && D->isExternallyVisible() ? Addr : nullptr;
if (D->getTLSKind()) {
CXXThreadLocalInits.push_back(Fn);
CXXThreadLocalInitVars.push_back(D);
} else if (PerformInit && ISA) {
int Priority = -1;
if (ISA->getSection() == ".CRT$XCC")
Priority = 200;
else if (ISA->getSection() == ".CRT$XCL")
Priority = 400;
if (Priority != -1)
AddGlobalCtor(Fn, Priority, ~0U, COMDATKey);
else
EmitPointerToInitFunc(D, Addr, Fn, ISA);
} else if (auto *IPA = D->getAttr<InitPriorityAttr>()) {
OrderGlobalInitsOrStermFinalizers Key(IPA->getPriority(),
PrioritizedCXXGlobalInits.size());
PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn));
} else if (isTemplateInstantiation(D->getTemplateSpecializationKind()) ||
getContext().GetGVALinkageForVariable(D) == GVA_DiscardableODR ||
D->hasAttr<SelectAnyAttr>()) {
I = DelayedCXXInitPosition.find(D);
unsigned LexOrder =
I == DelayedCXXInitPosition.end() ? CXXGlobalInits.size() : I->second;
AddGlobalCtor(Fn, 65535, LexOrder, COMDATKey);
if (COMDATKey && (getTriple().isOSBinFormatELF() ||
getTarget().getCXXABI().isMicrosoft())) {
addUsedGlobal(COMDATKey);
}
llvm::Comdat *C = Addr->getComdat();
if (COMDATKey && C &&
(getTarget().getTriple().isOSBinFormatELF() ||
getTarget().getTriple().isOSBinFormatWasm())) {
Fn->setComdat(C);
}
} else {
I = DelayedCXXInitPosition.find(D);
if (I == DelayedCXXInitPosition.end()) {
CXXGlobalInits.push_back(Fn);
} else if (I->second != ~0U) {
assert(I->second < CXXGlobalInits.size() &&
CXXGlobalInits[I->second] == nullptr);
CXXGlobalInits[I->second] = Fn;
}
}
DelayedCXXInitPosition[D] = ~0U;
}
void CodeGenModule::EmitCXXThreadLocalInitFunc() {
getCXXABI().EmitThreadLocalInitFuncs(
*this, CXXThreadLocals, CXXThreadLocalInits, CXXThreadLocalInitVars);
CXXThreadLocalInits.clear();
CXXThreadLocalInitVars.clear();
CXXThreadLocals.clear();
}
This is arranged to be run only once regardless of how many times the module
might be included transitively. This arranged by using a guard variable.
If there are no initializers at all (and also no imported modules) we reduce
this to an empty function (since the Itanium ABI requires that this function
be available to a caller, which might be produced by a different
implementation).
First we call any initializers for imported modules.
We then call initializers for the Global Module Fragment (if present)
We then call initializers for the current module.
We then call initializers for the Private Module Fragment (if present)
*/
void CodeGenModule::EmitCXXModuleInitFunc(Module *Primary) {
assert(Primary->isInterfaceOrPartition() &&
"The function should only be called for C++20 named module interface"
" or partition.");
while (!CXXGlobalInits.empty() && !CXXGlobalInits.back())
CXXGlobalInits.pop_back();
llvm::SmallSetVector<Module *, 8> AllImports;
for (auto I : Primary->Exports)
AllImports.insert(I.getPointer());
for (Module *M : Primary->Imports)
AllImports.insert(M);
for (Module *SubM : Primary->submodules()) {
assert((SubM->isGlobalModule() || SubM->isPrivateModule()) &&
"The sub modules of C++20 module unit should only be global module "
"fragments or private module framents.");
assert(SubM->Exports.empty() &&
"The global mdoule fragments and the private module fragments are "
"not allowed to export import modules.");
for (Module *M : SubM->Imports)
AllImports.insert(M);
}
SmallVector<llvm::Function *, 8> ModuleInits;
for (Module *M : AllImports) {
if (M->isHeaderLikeModule())
continue;
if (!M->isNamedModuleInterfaceHasInit())
continue;
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
SmallString<256> FnName;
{
llvm::raw_svector_ostream Out(FnName);
cast<ItaniumMangleContext>(getCXXABI().getMangleContext())
.mangleModuleInitializer(M, Out);
}
assert(!GetGlobalValue(FnName.str()) &&
"We should only have one use of the initializer call");
llvm::Function *Fn = llvm::Function::Create(
FTy, llvm::Function::ExternalLinkage, FnName.str(), &getModule());
ModuleInits.push_back(Fn);
}
if (!PrioritizedCXXGlobalInits.empty()) {
SmallVector<llvm::Function *, 8> LocalCXXGlobalInits;
llvm::array_pod_sort(PrioritizedCXXGlobalInits.begin(),
PrioritizedCXXGlobalInits.end());
for (SmallVectorImpl<GlobalInitData>::iterator
I = PrioritizedCXXGlobalInits.begin(),
E = PrioritizedCXXGlobalInits.end();
I != E;) {
SmallVectorImpl<GlobalInitData>::iterator PrioE =
std::upper_bound(I + 1, E, *I, GlobalInitPriorityCmp());
for (; I < PrioE; ++I)
ModuleInits.push_back(I->second);
}
}
for (auto *F : CXXGlobalInits)
ModuleInits.push_back(F);
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
const CGFunctionInfo &FI = getTypes().arrangeNullaryFunction();
llvm::Function *Fn;
{
SmallString<256> InitFnName;
llvm::raw_svector_ostream Out(InitFnName);
cast<ItaniumMangleContext>(getCXXABI().getMangleContext())
.mangleModuleInitializer(Primary, Out);
Fn = CreateGlobalInitOrCleanUpFunction(
FTy, llvm::Twine(InitFnName), FI, SourceLocation(), false,
llvm::GlobalVariable::ExternalLinkage);
ConstantAddress GuardAddr = ConstantAddress::invalid();
if (!ModuleInits.empty()) {
llvm::GlobalVariable *Guard = new llvm::GlobalVariable(
getModule(), Int8Ty, false,
llvm::GlobalVariable::InternalLinkage,
llvm::ConstantInt::get(Int8Ty, 0), InitFnName.str() + "__in_chrg");
CharUnits GuardAlign = CharUnits::One();
Guard->setAlignment(GuardAlign.getAsAlign());
GuardAddr = ConstantAddress(Guard, Int8Ty, GuardAlign);
}
CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, ModuleInits,
GuardAddr);
}
AddGlobalCtor(Fn);
if (getLangOpts().OpenCL) {
GenKernelArgMetadata(Fn);
Fn->setCallingConv(llvm::CallingConv::SPIR_KERNEL);
}
assert(!getLangOpts().CUDA || !getLangOpts().CUDAIsDevice ||
getLangOpts().GPUAllowDeviceInit);
if (getLangOpts().HIP && getLangOpts().CUDAIsDevice) {
Fn->setCallingConv(llvm::CallingConv::AMDGPU_KERNEL);
Fn->addFnAttr("device-init");
}
AllImports.clear();
PrioritizedCXXGlobalInits.clear();
CXXGlobalInits.clear();
ModuleInits.clear();
}
static SmallString<128> getTransformedFileName(llvm::Module &M) {
SmallString<128> FileName = llvm::sys::path::filename(M.getName());
if (FileName.empty())
FileName = "<null>";
for (size_t i = 0; i < FileName.size(); ++i) {
if (!isPreprocessingNumberBody(FileName[i]))
FileName[i] = '_';
}
return FileName;
}
static std::string getPrioritySuffix(unsigned int Priority) {
assert(Priority <= 65535 && "Priority should always be <= 65535.");
std::string PrioritySuffix = llvm::utostr(Priority);
PrioritySuffix = std::string(6 - PrioritySuffix.size(), '0') + PrioritySuffix;
return PrioritySuffix;
}
void
CodeGenModule::EmitCXXGlobalInitFunc() {
while (!CXXGlobalInits.empty() && !CXXGlobalInits.back())
CXXGlobalInits.pop_back();
SmallVector<llvm::Function *, 8> ModuleInits;
if (CXX20ModuleInits)
for (Module *M : ImportedModules) {
if (M->isHeaderLikeModule())
continue;
if (!M->isNamedModuleInterfaceHasInit())
continue;
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
SmallString<256> FnName;
{
llvm::raw_svector_ostream Out(FnName);
cast<ItaniumMangleContext>(getCXXABI().getMangleContext())
.mangleModuleInitializer(M, Out);
}
assert(!GetGlobalValue(FnName.str()) &&
"We should only have one use of the initializer call");
llvm::Function *Fn = llvm::Function::Create(
FTy, llvm::Function::ExternalLinkage, FnName.str(), &getModule());
ModuleInits.push_back(Fn);
}
if (ModuleInits.empty() && CXXGlobalInits.empty() &&
PrioritizedCXXGlobalInits.empty())
return;
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
const CGFunctionInfo &FI = getTypes().arrangeNullaryFunction();
if (!PrioritizedCXXGlobalInits.empty()) {
SmallVector<llvm::Function *, 8> LocalCXXGlobalInits;
llvm::array_pod_sort(PrioritizedCXXGlobalInits.begin(),
PrioritizedCXXGlobalInits.end());
for (SmallVectorImpl<GlobalInitData >::iterator
I = PrioritizedCXXGlobalInits.begin(),
E = PrioritizedCXXGlobalInits.end(); I != E; ) {
SmallVectorImpl<GlobalInitData >::iterator
PrioE = std::upper_bound(I + 1, E, *I, GlobalInitPriorityCmp());
LocalCXXGlobalInits.clear();
unsigned int Priority = I->first.priority;
llvm::Function *Fn = CreateGlobalInitOrCleanUpFunction(
FTy, "_GLOBAL__I_" + getPrioritySuffix(Priority), FI);
if (!ModuleInits.empty()) {
for (auto *F : ModuleInits)
LocalCXXGlobalInits.push_back(F);
ModuleInits.clear();
}
for (; I < PrioE; ++I)
LocalCXXGlobalInits.push_back(I->second);
CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, LocalCXXGlobalInits);
AddGlobalCtor(Fn, Priority);
}
PrioritizedCXXGlobalInits.clear();
}
if (getCXXABI().useSinitAndSterm() && ModuleInits.empty() &&
CXXGlobalInits.empty())
return;
for (auto *F : CXXGlobalInits)
ModuleInits.push_back(F);
CXXGlobalInits.clear();
llvm::Function *Fn;
if (CXX20ModuleInits && getContext().getCurrentNamedModule() &&
!getContext().getCurrentNamedModule()->isModuleImplementation()) {
SmallString<256> InitFnName;
llvm::raw_svector_ostream Out(InitFnName);
cast<ItaniumMangleContext>(getCXXABI().getMangleContext())
.mangleModuleInitializer(getContext().getCurrentNamedModule(), Out);
Fn = CreateGlobalInitOrCleanUpFunction(
FTy, llvm::Twine(InitFnName), FI, SourceLocation(), false,
llvm::GlobalVariable::ExternalLinkage);
} else
Fn = CreateGlobalInitOrCleanUpFunction(
FTy,
llvm::Twine("_GLOBAL__sub_I_", getTransformedFileName(getModule())),
FI);
CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, ModuleInits);
AddGlobalCtor(Fn);
if (getLangOpts().OpenCL) {
GenKernelArgMetadata(Fn);
Fn->setCallingConv(llvm::CallingConv::SPIR_KERNEL);
}
assert(!getLangOpts().CUDA || !getLangOpts().CUDAIsDevice ||
getLangOpts().GPUAllowDeviceInit);
if (getLangOpts().HIP && getLangOpts().CUDAIsDevice) {
Fn->setCallingConv(llvm::CallingConv::AMDGPU_KERNEL);
Fn->addFnAttr("device-init");
}
ModuleInits.clear();
}
void CodeGenModule::EmitCXXGlobalCleanUpFunc() {
if (CXXGlobalDtorsOrStermFinalizers.empty() &&
PrioritizedCXXStermFinalizers.empty())
return;
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
const CGFunctionInfo &FI = getTypes().arrangeNullaryFunction();
if (!PrioritizedCXXStermFinalizers.empty()) {
SmallVector<CXXGlobalDtorsOrStermFinalizer_t, 8> LocalCXXStermFinalizers;
llvm::array_pod_sort(PrioritizedCXXStermFinalizers.begin(),
PrioritizedCXXStermFinalizers.end());
for (SmallVectorImpl<StermFinalizerData>::iterator
I = PrioritizedCXXStermFinalizers.begin(),
E = PrioritizedCXXStermFinalizers.end();
I != E;) {
SmallVectorImpl<StermFinalizerData>::iterator PrioE =
std::upper_bound(I + 1, E, *I, StermFinalizerPriorityCmp());
LocalCXXStermFinalizers.clear();
unsigned int Priority = I->first.priority;
llvm::Function *Fn = CreateGlobalInitOrCleanUpFunction(
FTy, "_GLOBAL__a_" + getPrioritySuffix(Priority), FI);
for (; I < PrioE; ++I) {
llvm::FunctionCallee DtorFn = I->second;
LocalCXXStermFinalizers.emplace_back(DtorFn.getFunctionType(),
DtorFn.getCallee(), nullptr);
}
CodeGenFunction(*this).GenerateCXXGlobalCleanUpFunc(
Fn, LocalCXXStermFinalizers);
AddGlobalDtor(Fn, Priority);
}
PrioritizedCXXStermFinalizers.clear();
}
if (CXXGlobalDtorsOrStermFinalizers.empty())
return;
llvm::Function *Fn =
CreateGlobalInitOrCleanUpFunction(FTy, "_GLOBAL__D_a", FI);
CodeGenFunction(*this).GenerateCXXGlobalCleanUpFunc(
Fn, CXXGlobalDtorsOrStermFinalizers);
AddGlobalDtor(Fn);
CXXGlobalDtorsOrStermFinalizers.clear();
}
void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
const VarDecl *D,
llvm::GlobalVariable *Addr,
bool PerformInit) {
if (D->hasAttr<NoDebugAttr>())
DebugInfo = nullptr;
CurEHLocation = D->getBeginLoc();
StartFunction(GlobalDecl(D, DynamicInitKind::Initializer),
getContext().VoidTy, Fn, getTypes().arrangeNullaryFunction(),
FunctionArgList());
auto AL = ApplyDebugLocation::CreateArtificial(*this);
if (Addr->hasWeakLinkage() || Addr->hasLinkOnceLinkage() ||
(D->getTLSKind() == VarDecl::TLS_Dynamic &&
isTemplateInstantiation(D->getTemplateSpecializationKind()))) {
EmitCXXGuardedInit(*D, Addr, PerformInit);
} else {
EmitCXXGlobalVarDeclInit(*D, Addr, PerformInit);
}
if (getLangOpts().HLSL)
CGM.getHLSLRuntime().annotateHLSLResource(D, Addr);
FinishFunction();
}
void
CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
ArrayRef<llvm::Function *> Decls,
ConstantAddress Guard) {
{
auto NL = ApplyDebugLocation::CreateEmpty(*this);
StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
getTypes().arrangeNullaryFunction(), FunctionArgList());
auto AL = ApplyDebugLocation::CreateArtificial(*this);
llvm::BasicBlock *ExitBlock = nullptr;
if (Guard.isValid()) {
llvm::Value *GuardVal = Builder.CreateLoad(Guard);
llvm::Value *Uninit = Builder.CreateIsNull(GuardVal,
"guard.uninitialized");
llvm::BasicBlock *InitBlock = createBasicBlock("init");
ExitBlock = createBasicBlock("exit");
EmitCXXGuardedInitBranch(Uninit, InitBlock, ExitBlock,
GuardKind::TlsGuard, nullptr);
EmitBlock(InitBlock);
Builder.CreateStore(llvm::ConstantInt::get(GuardVal->getType(),1), Guard);
EmitInvariantStart(
Guard.getPointer(),
CharUnits::fromQuantity(
CGM.getDataLayout().getTypeAllocSize(GuardVal->getType())));
}
RunCleanupsScope Scope(*this);
if (getLangOpts().ObjCAutoRefCount && getLangOpts().CPlusPlus) {
llvm::Value *token = EmitObjCAutoreleasePoolPush();
EmitObjCAutoreleasePoolCleanup(token);
}
for (unsigned i = 0, e = Decls.size(); i != e; ++i)
if (Decls[i])
EmitRuntimeCall(Decls[i]);
Scope.ForceCleanup();
if (ExitBlock) {
Builder.CreateBr(ExitBlock);
EmitBlock(ExitBlock);
}
}
FinishFunction();
}
void CodeGenFunction::GenerateCXXGlobalCleanUpFunc(
llvm::Function *Fn,
ArrayRef<std::tuple<llvm::FunctionType *, llvm::WeakTrackingVH,
llvm::Constant *>>
DtorsOrStermFinalizers) {
{
auto NL = ApplyDebugLocation::CreateEmpty(*this);
StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
getTypes().arrangeNullaryFunction(), FunctionArgList());
auto AL = ApplyDebugLocation::CreateArtificial(*this);
for (unsigned i = 0, e = DtorsOrStermFinalizers.size(); i != e; ++i) {
llvm::FunctionType *CalleeTy;
llvm::Value *Callee;
llvm::Constant *Arg;
std::tie(CalleeTy, Callee, Arg) = DtorsOrStermFinalizers[e - i - 1];
llvm::CallInst *CI = nullptr;
if (Arg == nullptr) {
assert(
CGM.getCXXABI().useSinitAndSterm() &&
"Arg could not be nullptr unless using sinit and sterm functions.");
CI = Builder.CreateCall(CalleeTy, Callee);
} else
CI = Builder.CreateCall(CalleeTy, Callee, Arg);
if (llvm::Function *F = dyn_cast<llvm::Function>(Callee))
CI->setCallingConv(F->getCallingConv());
}
}
FinishFunction();
}
llvm::Function *CodeGenFunction::generateDestroyHelper(
Address addr, QualType type, Destroyer *destroyer,
bool useEHCleanupForArray, const VarDecl *VD) {
FunctionArgList args;
ImplicitParamDecl Dst(getContext(), getContext().VoidPtrTy,
ImplicitParamKind::Other);
args.push_back(&Dst);
const CGFunctionInfo &FI =
CGM.getTypes().arrangeBuiltinFunctionDeclaration(getContext().VoidTy, args);
llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *fn = CGM.CreateGlobalInitOrCleanUpFunction(
FTy, "__cxx_global_array_dtor", FI, VD->getLocation());
CurEHLocation = VD->getBeginLoc();
StartFunction(GlobalDecl(VD, DynamicInitKind::GlobalArrayDestructor),
getContext().VoidTy, fn, FI, args);
auto AL = ApplyDebugLocation::CreateArtificial(*this);
emitDestroy(addr, type, destroyer, useEHCleanupForArray);
FinishFunction();
return fn;
}