[AIX][Frontend] Static init implementation for AIX considering no priority

1. Provides no piroirity supoort && disables three priority related
   attributes: init_priority, ctor attr, dtor attr;
2. '-qunique' in XL compiler equivalent behavior of emitting sinit
    and sterm functions name using getUniqueModuleId() util function
    in LLVM (currently no support for InternalLinkage and WeakODRLinkage
    symbols);
3. Add testcases to emit IR sample with __sinit80000000, __dtor, and
    __sterm80000000;
4. Temporarily side-steps the need to implement the functionality of
   llvm.global_ctors and llvm.global_dtors arrays. The uses of that
   functionality in this patch (with respect to the name of the functions
   involved) are not representative of how the functionality will be used
   once implemented.

Differential Revision: https://reviews.llvm.org/D74166
This commit is contained in:
Xiangling Liao 2020-05-27 17:04:43 -04:00
parent c3b4486a57
commit 22337bfe7d
16 changed files with 516 additions and 78 deletions

View File

@ -175,6 +175,8 @@ public:
virtual void mangleLambdaSig(const CXXRecordDecl *Lambda, raw_ostream &) = 0;
virtual void mangleDynamicStermFinalizer(const VarDecl *D, raw_ostream &) = 0;
bool isUniqueNameMangler() { return IsUniqueNameMangler; }
static bool classof(const MangleContext *C) {

View File

@ -160,6 +160,7 @@ public:
void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) override;
void mangleDynamicAtExitDestructor(const VarDecl *D,
raw_ostream &Out) override;
void mangleDynamicStermFinalizer(const VarDecl *D, raw_ostream &Out) override;
void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
raw_ostream &Out) override;
void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl,
@ -5230,6 +5231,18 @@ void ItaniumMangleContextImpl::mangleDynamicAtExitDestructor(const VarDecl *D,
Mangler.getStream() << D->getName();
}
void ItaniumMangleContextImpl::mangleDynamicStermFinalizer(const VarDecl *D,
raw_ostream &Out) {
// Clang generates these internal-linkage functions as part of its
// implementation of the XL ABI.
CXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "__finalize_";
if (shouldMangleDeclName(D))
Mangler.mangle(D);
else
Mangler.getStream() << D->getName();
}
void ItaniumMangleContextImpl::mangleSEHFilterExpression(
const NamedDecl *EnclosingDecl, raw_ostream &Out) {
CXXNameMangler Mangler(*this, Out);

View File

@ -108,6 +108,8 @@ public:
virtual bool hasMostDerivedReturn(GlobalDecl GD) const { return false; }
virtual bool useSinitAndSterm() const { return false; }
/// Returns true if the target allows calling a function through a pointer
/// with a different signature than the actual function (or equivalently,
/// bitcasting a function or function pointer to a different function type).

View File

@ -21,6 +21,7 @@
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/Support/Path.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
using namespace clang;
using namespace CodeGen;
@ -239,7 +240,7 @@ llvm::Function *CodeGenFunction::createAtExitStub(const VarDecl &VD,
}
const CGFunctionInfo &FI = CGM.getTypes().arrangeNullaryFunction();
llvm::Function *fn = CGM.CreateGlobalInitOrDestructFunction(
llvm::Function *fn = CGM.CreateGlobalInitOrCleanUpFunction(
ty, FnName.str(), FI, VD.getLocation());
CodeGenFunction CGF(CGM);
@ -249,7 +250,7 @@ llvm::Function *CodeGenFunction::createAtExitStub(const VarDecl &VD,
llvm::CallInst *call = CGF.Builder.CreateCall(dtor, addr);
// Make sure the call and the callee agree on calling convention.
// Make sure the call and the callee agree on calling convention.
if (auto *dtorFn = dyn_cast<llvm::Function>(
dtor.getCallee()->stripPointerCastsAndAliases()))
call->setCallingConv(dtorFn->getCallingConv());
@ -270,8 +271,12 @@ void CodeGenFunction::registerGlobalDtorWithAtExit(const VarDecl &VD,
void CodeGenFunction::registerGlobalDtorWithAtExit(llvm::Constant *dtorStub) {
// extern "C" int atexit(void (*f)(void));
assert(cast<llvm::Function>(dtorStub)->getFunctionType() ==
llvm::FunctionType::get(CGM.VoidTy, false) &&
"Argument to atexit has a wrong type.");
llvm::FunctionType *atexitTy =
llvm::FunctionType::get(IntTy, dtorStub->getType(), false);
llvm::FunctionType::get(IntTy, dtorStub->getType(), false);
llvm::FunctionCallee atexit =
CGM.CreateRuntimeFunction(atexitTy, "atexit", llvm::AttributeList(),
@ -282,6 +287,30 @@ void CodeGenFunction::registerGlobalDtorWithAtExit(llvm::Constant *dtorStub) {
EmitNounwindRuntimeCall(atexit, dtorStub);
}
llvm::Value *
CodeGenFunction::unregisterGlobalDtorWithUnAtExit(llvm::Function *dtorStub) {
// The unatexit subroutine unregisters __dtor functions that were previously
// registered by the atexit subroutine. If the referenced function is found,
// it is removed from the list of functions that are called at normal program
// termination and the unatexit returns a value of 0, otherwise a non-zero
// value is returned.
//
// extern "C" int unatexit(void (*f)(void));
assert(dtorStub->getFunctionType() ==
llvm::FunctionType::get(CGM.VoidTy, false) &&
"Argument to unatexit has a wrong type.");
llvm::FunctionType *unatexitTy =
llvm::FunctionType::get(IntTy, {dtorStub->getType()}, /*isVarArg=*/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) {
@ -333,19 +362,23 @@ void CodeGenFunction::EmitCXXGuardedInitBranch(llvm::Value *NeedsInit,
Builder.CreateCondBr(NeedsInit, InitBlock, NoInitBlock, Weights);
}
llvm::Function *CodeGenModule::CreateGlobalInitOrDestructFunction(
llvm::Function *CodeGenModule::CreateGlobalInitOrCleanUpFunction(
llvm::FunctionType *FTy, const Twine &Name, const CGFunctionInfo &FI,
SourceLocation Loc, bool TLS) {
llvm::Function *Fn =
llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
Name, &getModule());
SourceLocation Loc, bool TLS, bool IsExternalLinkage) {
llvm::Function *Fn = llvm::Function::Create(
FTy,
IsExternalLinkage ? llvm::GlobalValue::ExternalLinkage
: llvm::GlobalValue::InternalLinkage,
Name, &getModule());
if (!getLangOpts().AppleKext && !TLS) {
// Set the section if needed.
if (const char *Section = getTarget().getStaticInitSectionSpecifier())
Fn->setSection(Section);
}
SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
if (Fn->hasInternalLinkage())
SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
Fn->setCallingConv(getRuntimeCC());
@ -461,10 +494,8 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
}
// Create a variable initialization function.
llvm::Function *Fn =
CreateGlobalInitOrDestructFunction(FTy, FnName.str(),
getTypes().arrangeNullaryFunction(),
D->getLocation());
llvm::Function *Fn = CreateGlobalInitOrCleanUpFunction(
FTy, FnName.str(), getTypes().arrangeNullaryFunction(), D->getLocation());
auto *ISA = D->getAttr<InitSegAttr>();
CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr,
@ -557,11 +588,27 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
if (CXXGlobalInits.empty() && PrioritizedCXXGlobalInits.empty())
return;
const bool UseSinitAndSterm = getCXXABI().useSinitAndSterm();
if (UseSinitAndSterm) {
GlobalUniqueModuleId = getUniqueModuleId(&getModule());
// FIXME: We need to figure out what to hash on or encode into the unique ID
// we need.
if (GlobalUniqueModuleId.compare("") == 0)
llvm::report_fatal_error(
"cannot produce a unique identifier for this module"
" based on strong external symbols");
GlobalUniqueModuleId = GlobalUniqueModuleId.substr(1);
}
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
const CGFunctionInfo &FI = getTypes().arrangeNullaryFunction();
// Create our global initialization function.
// Create our global prioritized initialization function.
if (!PrioritizedCXXGlobalInits.empty()) {
assert(!UseSinitAndSterm && "Prioritized sinit and sterm functions are not"
" supported yet.");
SmallVector<llvm::Function *, 8> LocalCXXGlobalInits;
llvm::array_pod_sort(PrioritizedCXXGlobalInits.begin(),
PrioritizedCXXGlobalInits.end());
@ -581,7 +628,7 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
std::string PrioritySuffix = llvm::utostr(Priority);
// Priority is always <= 65535 (enforced by sema).
PrioritySuffix = std::string(6-PrioritySuffix.size(), '0')+PrioritySuffix;
llvm::Function *Fn = CreateGlobalInitOrDestructFunction(
llvm::Function *Fn = CreateGlobalInitOrCleanUpFunction(
FTy, "_GLOBAL__I_" + PrioritySuffix, FI);
for (; I < PrioE; ++I)
@ -593,12 +640,27 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
PrioritizedCXXGlobalInits.clear();
}
// Include the filename in the symbol name. Including "sub_" matches gcc
// and makes sure these symbols appear lexicographically behind the symbols
// with priority emitted above.
llvm::Function *Fn = CreateGlobalInitOrDestructFunction(
FTy,
llvm::Twine("_GLOBAL__sub_I_", getTransformedFileName(getModule())), FI);
if (UseSinitAndSterm && CXXGlobalInits.empty())
return;
// Create our global initialization function.
SmallString<128> FuncName;
bool IsExternalLinkage = false;
if (UseSinitAndSterm) {
llvm::Twine("__sinit80000000_clang_", GlobalUniqueModuleId)
.toVector(FuncName);
IsExternalLinkage = true;
} else {
// Include the filename in the symbol name. Including "sub_" matches gcc
// and makes sure these symbols appear lexicographically behind the symbols
// with priority emitted above.
llvm::Twine("_GLOBAL__sub_I_", getTransformedFileName(getModule()))
.toVector(FuncName);
}
llvm::Function *Fn = CreateGlobalInitOrCleanUpFunction(
FTy, FuncName, FI, SourceLocation(), false /* TLS */,
IsExternalLinkage);
CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, CXXGlobalInits);
AddGlobalCtor(Fn);
@ -624,20 +686,38 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
CXXGlobalInits.clear();
}
void CodeGenModule::EmitCXXGlobalDtorFunc() {
if (CXXGlobalDtors.empty())
void CodeGenModule::EmitCXXGlobalCleanUpFunc() {
if (CXXGlobalDtorsOrStermFinalizers.empty())
return;
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
// Create our global destructor function.
const CGFunctionInfo &FI = getTypes().arrangeNullaryFunction();
llvm::Function *Fn =
CreateGlobalInitOrDestructFunction(FTy, "_GLOBAL__D_a", FI);
CodeGenFunction(*this).GenerateCXXGlobalDtorsFunc(Fn, CXXGlobalDtors);
// Create our global cleanup function.
llvm::Function *Fn = nullptr;
if (getCXXABI().useSinitAndSterm()) {
if (GlobalUniqueModuleId.empty()) {
GlobalUniqueModuleId = getUniqueModuleId(&getModule());
// FIXME: We need to figure out what to hash on or encode into the unique
// ID we need.
if (GlobalUniqueModuleId.compare("") == 0)
llvm::report_fatal_error(
"cannot produce a unique identifier for this module"
" based on strong external symbols");
GlobalUniqueModuleId = GlobalUniqueModuleId.substr(1);
}
Fn = CreateGlobalInitOrCleanUpFunction(
FTy, llvm::Twine("__sterm80000000_clang_", GlobalUniqueModuleId), FI,
SourceLocation(), false /* TLS */, true /* IsExternalLinkage */);
} else {
Fn = CreateGlobalInitOrCleanUpFunction(FTy, "_GLOBAL__D_a", FI);
}
CodeGenFunction(*this).GenerateCXXGlobalCleanUpFunc(
Fn, CXXGlobalDtorsOrStermFinalizers);
AddGlobalDtor(Fn);
CXXGlobalDtors.clear();
CXXGlobalDtorsOrStermFinalizers.clear();
}
/// Emit the code necessary to initialize the given global variable.
@ -733,10 +813,10 @@ CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
FinishFunction();
}
void CodeGenFunction::GenerateCXXGlobalDtorsFunc(
void CodeGenFunction::GenerateCXXGlobalCleanUpFunc(
llvm::Function *Fn,
const std::vector<std::tuple<llvm::FunctionType *, llvm::WeakTrackingVH,
llvm::Constant *>> &DtorsAndObjects) {
llvm::Constant *>> &DtorsOrStermFinalizers) {
{
auto NL = ApplyDebugLocation::CreateEmpty(*this);
StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
@ -744,13 +824,22 @@ void CodeGenFunction::GenerateCXXGlobalDtorsFunc(
// Emit an artificial location for this function.
auto AL = ApplyDebugLocation::CreateArtificial(*this);
// Emit the dtors, in reverse order from construction.
for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i) {
// Emit the cleanups, in reverse order from construction.
for (unsigned i = 0, e = DtorsOrStermFinalizers.size(); i != e; ++i) {
llvm::FunctionType *CalleeTy;
llvm::Value *Callee;
llvm::Constant *Arg;
std::tie(CalleeTy, Callee, Arg) = DtorsAndObjects[e - i - 1];
llvm::CallInst *CI = Builder.CreateCall(CalleeTy, Callee, 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);
// Make sure the call and the callee agree on calling convention.
if (llvm::Function *F = dyn_cast<llvm::Function>(Callee))
CI->setCallingConv(F->getCallingConv());
@ -774,7 +863,7 @@ llvm::Function *CodeGenFunction::generateDestroyHelper(
const CGFunctionInfo &FI =
CGM.getTypes().arrangeBuiltinFunctionDeclaration(getContext().VoidTy, args);
llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *fn = CGM.CreateGlobalInitOrDestructFunction(
llvm::Function *fn = CGM.CreateGlobalInitOrCleanUpFunction(
FTy, "__cxx_global_array_dtor", FI, VD->getLocation());
CurEHLocation = VD->getBeginLoc();

View File

@ -1837,7 +1837,7 @@ llvm::Function *CGOpenMPRuntime::emitThreadPrivateVarDefinition(
llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
std::string Name = getName({"__kmpc_global_ctor_", ""});
llvm::Function *Fn =
CGM.CreateGlobalInitOrDestructFunction(FTy, Name, FI, Loc);
CGM.CreateGlobalInitOrCleanUpFunction(FTy, Name, FI, Loc);
CtorCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidPtrTy, Fn, FI,
Args, Loc, Loc);
llvm::Value *ArgVal = CtorCGF.EmitLoadOfScalar(
@ -1870,7 +1870,7 @@ llvm::Function *CGOpenMPRuntime::emitThreadPrivateVarDefinition(
llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
std::string Name = getName({"__kmpc_global_dtor_", ""});
llvm::Function *Fn =
CGM.CreateGlobalInitOrDestructFunction(FTy, Name, FI, Loc);
CGM.CreateGlobalInitOrCleanUpFunction(FTy, Name, FI, Loc);
auto NL = ApplyDebugLocation::CreateEmpty(DtorCGF);
DtorCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, Fn, FI, Args,
Loc, Loc);
@ -1913,7 +1913,7 @@ llvm::Function *CGOpenMPRuntime::emitThreadPrivateVarDefinition(
auto *InitFunctionTy =
llvm::FunctionType::get(CGM.VoidTy, /*isVarArg*/ false);
std::string Name = getName({"__omp_threadprivate_init_", ""});
llvm::Function *InitFunction = CGM.CreateGlobalInitOrDestructFunction(
llvm::Function *InitFunction = CGM.CreateGlobalInitOrCleanUpFunction(
InitFunctionTy, Name, CGM.getTypes().arrangeNullaryFunction());
CodeGenFunction InitCGF(CGM);
FunctionArgList ArgList;
@ -1975,7 +1975,7 @@ bool CGOpenMPRuntime::emitDeclareTargetVarDefinition(const VarDecl *VD,
const CGFunctionInfo &FI = CGM.getTypes().arrangeNullaryFunction();
llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *Fn = CGM.CreateGlobalInitOrDestructFunction(
llvm::Function *Fn = CGM.CreateGlobalInitOrCleanUpFunction(
FTy, Twine(Buffer, "_ctor"), FI, Loc);
auto NL = ApplyDebugLocation::CreateEmpty(CtorCGF);
CtorCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, Fn, FI,
@ -2013,7 +2013,7 @@ bool CGOpenMPRuntime::emitDeclareTargetVarDefinition(const VarDecl *VD,
const CGFunctionInfo &FI = CGM.getTypes().arrangeNullaryFunction();
llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *Fn = CGM.CreateGlobalInitOrDestructFunction(
llvm::Function *Fn = CGM.CreateGlobalInitOrCleanUpFunction(
FTy, Twine(Buffer, "_dtor"), FI, Loc);
auto NL = ApplyDebugLocation::CreateEmpty(DtorCGF);
DtorCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, Fn, FI,
@ -10039,7 +10039,7 @@ llvm::Function *CGOpenMPRuntime::emitRequiresDirectiveRegFun() {
const auto &FI = CGM.getTypes().arrangeNullaryFunction();
llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
std::string ReqName = getName({"omp_offloading", "requires_reg"});
RequiresRegFn = CGM.CreateGlobalInitOrDestructFunction(FTy, ReqName, FI);
RequiresRegFn = CGM.CreateGlobalInitOrCleanUpFunction(FTy, ReqName, FI);
CGF.StartFunction(GlobalDecl(), C.VoidTy, RequiresRegFn, FI, {});
OpenMPOffloadingRequiresDirFlags Flags = OMP_REQ_NONE;
// TODO: check for other requires clauses.

View File

@ -4197,6 +4197,9 @@ public:
/// Call atexit() with function dtorStub.
void registerGlobalDtorWithAtExit(llvm::Constant *dtorStub);
/// Call unatexit() with function dtorStub.
llvm::Value *unregisterGlobalDtorWithUnAtExit(llvm::Function *dtorStub);
/// Emit code in this function to perform a guarded variable
/// initialization. Guarded initializations are used when it's not
/// possible to prove that an initialization will be done exactly
@ -4220,12 +4223,12 @@ public:
ArrayRef<llvm::Function *> CXXThreadLocals,
ConstantAddress Guard = ConstantAddress::invalid());
/// GenerateCXXGlobalDtorsFunc - Generates code for destroying global
/// GenerateCXXGlobalCleanUpFunc - Generates code for cleaning up global
/// variables.
void GenerateCXXGlobalDtorsFunc(
void GenerateCXXGlobalCleanUpFunc(
llvm::Function *Fn,
const std::vector<std::tuple<llvm::FunctionType *, llvm::WeakTrackingVH,
llvm::Constant *>> &DtorsAndObjects);
llvm::Constant *>> &DtorsOrStermFinalizers);
void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
const VarDecl *D,

View File

@ -411,7 +411,7 @@ void CodeGenModule::Release() {
checkAliases();
emitMultiVersionFunctions();
EmitCXXGlobalInitFunc();
EmitCXXGlobalDtorFunc();
EmitCXXGlobalCleanUpFunc();
registerGlobalDtorsWithAtExit();
EmitCXXThreadLocalInitFunc();
if (ObjCRuntime)

View File

@ -397,6 +397,10 @@ private:
/// emitted when the translation unit is complete.
CtorList GlobalDtors;
/// A unique trailing identifier as a part of sinit/sterm function when
/// UseSinitAndSterm of CXXABI is set as true.
std::string GlobalUniqueModuleId;
/// An ordered map of canonical GlobalDecls to their mangled names.
llvm::MapVector<GlobalDecl, StringRef> MangledDeclNames;
llvm::StringMap<GlobalDecl, llvm::BumpPtrAllocator> Manglings;
@ -465,9 +469,11 @@ private:
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.
std::vector<
std::tuple<llvm::FunctionType *, llvm::WeakTrackingVH, llvm::Constant *>>
CXXGlobalDtors;
CXXGlobalDtorsOrStermFinalizers;
/// The complete set of modules that has been imported.
llvm::SetVector<clang::Module *> ImportedModules;
@ -815,11 +821,10 @@ public:
llvm::GlobalValue::LinkageTypes Linkage,
unsigned Alignment);
llvm::Function *
CreateGlobalInitOrDestructFunction(llvm::FunctionType *ty, const Twine &name,
const CGFunctionInfo &FI,
SourceLocation Loc = SourceLocation(),
bool TLS = false);
llvm::Function *CreateGlobalInitOrCleanUpFunction(
llvm::FunctionType *ty, const Twine &name, const CGFunctionInfo &FI,
SourceLocation Loc = SourceLocation(), bool TLS = false,
bool IsExternalLinkage = false);
/// 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
@ -1048,8 +1053,14 @@ public:
/// Add a destructor and object to add to the C++ global destructor function.
void AddCXXDtorEntry(llvm::FunctionCallee DtorFn, llvm::Constant *Object) {
CXXGlobalDtors.emplace_back(DtorFn.getFunctionType(), DtorFn.getCallee(),
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);
}
/// Create or return a runtime function declaration with the specified type
@ -1449,8 +1460,8 @@ private:
/// Emit the function that initializes C++ globals.
void EmitCXXGlobalInitFunc();
/// Emit the function that destroys C++ globals.
void EmitCXXGlobalDtorFunc();
/// 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.

View File

@ -526,6 +526,12 @@ public:
void registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
llvm::FunctionCallee dtor,
llvm::Constant *addr) override;
bool useSinitAndSterm() const override { return true; }
private:
void emitCXXStermFinalizer(const VarDecl &D, llvm::Function *dtorStub,
llvm::Constant *addr);
};
}
@ -2525,7 +2531,7 @@ void CodeGenModule::registerGlobalDtorsWithAtExit() {
std::string GlobalInitFnName =
std::string("__GLOBAL_init_") + llvm::to_string(Priority);
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
llvm::Function *GlobalInitFn = CreateGlobalInitOrDestructFunction(
llvm::Function *GlobalInitFn = CreateGlobalInitOrCleanUpFunction(
FTy, GlobalInitFnName, getTypes().arrangeNullaryFunction(),
SourceLocation());
ASTContext &Ctx = getContext();
@ -2679,9 +2685,9 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs(
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
const CGFunctionInfo &FI = CGM.getTypes().arrangeNullaryFunction();
InitFunc = CGM.CreateGlobalInitOrDestructFunction(FTy, "__tls_init", FI,
SourceLocation(),
/*TLS=*/true);
InitFunc = CGM.CreateGlobalInitOrCleanUpFunction(FTy, "__tls_init", FI,
SourceLocation(),
/*TLS=*/true);
llvm::GlobalVariable *Guard = new llvm::GlobalVariable(
CGM.getModule(), CGM.Int8Ty, /*isConstant=*/false,
llvm::GlobalVariable::InternalLinkage,
@ -4516,6 +4522,67 @@ void WebAssemblyCXXABI::emitBeginCatch(CodeGenFunction &CGF,
void XLCXXABI::registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
llvm::FunctionCallee dtor,
llvm::Constant *addr) {
llvm::report_fatal_error("Static initialization has not been implemented on"
" XL ABI yet.");
if (D.getTLSKind() != VarDecl::TLS_None)
llvm::report_fatal_error("thread local storage not yet implemented on AIX");
// Create __dtor function for the var decl.
llvm::Function *dtorStub = CGF.createAtExitStub(D, dtor, addr);
if (CGM.getCodeGenOpts().CXAAtExit)
llvm::report_fatal_error("using __cxa_atexit unsupported on AIX");
// Register above __dtor with atexit().
CGF.registerGlobalDtorWithAtExit(dtorStub);
// Emit __finalize function to unregister __dtor and (as appropriate) call
// __dtor.
emitCXXStermFinalizer(D, dtorStub, addr);
}
void XLCXXABI::emitCXXStermFinalizer(const VarDecl &D, llvm::Function *dtorStub,
llvm::Constant *addr) {
llvm::FunctionType *FTy = llvm::FunctionType::get(CGM.VoidTy, false);
SmallString<256> FnName;
{
llvm::raw_svector_ostream Out(FnName);
getMangleContext().mangleDynamicStermFinalizer(&D, Out);
}
// Create the finalization action associated with a variable.
const CGFunctionInfo &FI = CGM.getTypes().arrangeNullaryFunction();
llvm::Function *StermFinalizer = CGM.CreateGlobalInitOrCleanUpFunction(
FTy, FnName.str(), FI, D.getLocation());
CodeGenFunction CGF(CGM);
CGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, StermFinalizer, FI,
FunctionArgList());
// The unatexit subroutine unregisters __dtor functions that were previously
// registered by the atexit subroutine. If the referenced function is found,
// the unatexit returns a value of 0, meaning that the cleanup is still
// pending (and we should call the __dtor function).
llvm::Value *V = CGF.unregisterGlobalDtorWithUnAtExit(dtorStub);
llvm::Value *NeedsDestruct = CGF.Builder.CreateIsNull(V, "needs_destruct");
llvm::BasicBlock *DestructCallBlock = CGF.createBasicBlock("destruct.call");
llvm::BasicBlock *EndBlock = CGF.createBasicBlock("destruct.end");
// Check if unatexit returns a value of 0. If it does, jump to
// DestructCallBlock, otherwise jump to EndBlock directly.
CGF.Builder.CreateCondBr(NeedsDestruct, DestructCallBlock, EndBlock);
CGF.EmitBlock(DestructCallBlock);
// Emit the call to dtorStub.
llvm::CallInst *CI = CGF.Builder.CreateCall(dtorStub);
// Make sure the call and the callee agree on calling convention.
CI->setCallingConv(dtorStub->getCallingConv());
CGF.EmitBlock(EndBlock);
CGF.FinishFunction();
CGM.AddCXXStermFinalizerEntry(StermFinalizer);
}

View File

@ -2349,7 +2349,7 @@ void MicrosoftCXXABI::EmitThreadLocalInitFuncs(
if (!NonComdatInits.empty()) {
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
llvm::Function *InitFunc = CGM.CreateGlobalInitOrDestructFunction(
llvm::Function *InitFunc = CGM.CreateGlobalInitOrCleanUpFunction(
FTy, "__tls_init", CGM.getTypes().arrangeNullaryFunction(),
SourceLocation(), /*TLS=*/true);
CodeGenFunction(CGM).GenerateCXXGlobalInitFunc(InitFunc, NonComdatInits);

View File

@ -6939,13 +6939,20 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handlePassObjectSizeAttr(S, D, AL);
break;
case ParsedAttr::AT_Constructor:
handleConstructorAttr(S, D, AL);
if (S.Context.getTargetInfo().getTriple().isOSAIX())
llvm::report_fatal_error(
"'constructor' attribute is not yet supported on AIX");
else
handleConstructorAttr(S, D, AL);
break;
case ParsedAttr::AT_Deprecated:
handleDeprecatedAttr(S, D, AL);
break;
case ParsedAttr::AT_Destructor:
handleDestructorAttr(S, D, AL);
if (S.Context.getTargetInfo().getTriple().isOSAIX())
llvm::report_fatal_error("'destructor' attribute is not yet supported on AIX");
else
handleDestructorAttr(S, D, AL);
break;
case ParsedAttr::AT_EnableIf:
handleEnableIfAttr(S, D, AL);
@ -7139,7 +7146,11 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleVecTypeHint(S, D, AL);
break;
case ParsedAttr::AT_InitPriority:
handleInitPriorityAttr(S, D, AL);
if (S.Context.getTargetInfo().getTriple().isOSAIX())
llvm::report_fatal_error(
"'init_priority' attribute is not yet supported on AIX");
else
handleInitPriorityAttr(S, D, AL);
break;
case ParsedAttr::AT_Packed:
handlePackedAttr(S, D, AL);

View File

@ -0,0 +1,20 @@
// RUN: not %clang_cc1 -triple powerpc-ibm-aix-xcoff -x c++ -emit-llvm < %s \
// RUN: 2>&1 | \
// RUN: FileCheck %s
// RUN: not %clang_cc1 -triple powerpc64-ibm-aix-xcoff -x c++ -emit-llvm < %s \
// RUN: 2>&1 | \
// RUN: FileCheck %s
int foo() __attribute__((constructor(180)));
class test {
int a;
public:
test(int c) { a = c; }
~test() { a = 0; }
};
test t(1);
// CHECK: fatal error: error in backend: 'constructor' attribute is not yet supported on AIX

View File

@ -0,0 +1,20 @@
// RUN: not %clang_cc1 -triple powerpc-ibm-aix-xcoff -x c++ -emit-llvm < %s \
// RUN: 2>&1 | \
// RUN: FileCheck %s
// RUN: not %clang_cc1 -triple powerpc64-ibm-aix-xcoff -x c++ -emit-llvm < %s \
// RUN: 2>&1 | \
// RUN: FileCheck %s
int bar() __attribute__((destructor(180)));
class test {
int a;
public:
test(int c) { a = c; }
~test() { a = 0; }
};
test t(1);
// CHECK: fatal error: error in backend: 'destructor' attribute is not yet supported on AIX

View File

@ -0,0 +1,19 @@
// RUN: not %clang_cc1 -triple powerpc-ibm-aix-xcoff -x c++ -emit-llvm < %s \
// RUN: 2>&1 | \
// RUN: FileCheck %s
// RUN: not %clang_cc1 -triple powerpc64-ibm-aix-xcoff -x c++ -emit-llvm < %s \
// RUN: 2>&1 | \
// RUN: FileCheck %s
class test {
int a;
public:
test(int c) { a = c; }
~test() { a = 0; }
};
__attribute__((init_priority(2000)))
test t(1);
// CHECK: fatal error: error in backend: 'init_priority' attribute is not yet supported on AIX

View File

@ -1,12 +0,0 @@
// RUN: not %clang_cc1 -triple powerpc-ibm-aix-xcoff -S -emit-llvm -x c++ %s \
// RUN: -o /dev/null 2>&1 | FileCheck %s
// RUN: not %clang_cc1 -triple powerpc64-ibm-aix-xcoff -S -emit-llvm -x c++ %s \
// RUN: -o /dev/null 2>&1 | FileCheck %s
struct test {
test();
~test();
} t;
// CHECK: error in backend: Static initialization has not been implemented on XL ABI yet.

View File

@ -0,0 +1,193 @@
// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -S -emit-llvm -x c++ \
// RUN: -fno-use-cxa-atexit -std=c++2a < %s | \
// RUN: FileCheck --check-prefixes=CHECK,CHECK32 %s
// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -S -emit-llvm -x c++ \
// RUN: -fno-use-cxa-atexit -std=c++2a < %s | \
// RUN: FileCheck --check-prefixes=CHECK,CHECK64 %s
namespace test1 {
struct Test1 {
Test1();
~Test1();
} t1, t2;
} // namespace test1
namespace test2 {
int foo() { return 3; }
int x = foo();
} // namespace test2
namespace test3 {
struct Test3 {
constexpr Test3() {};
~Test3() {};
};
constinit Test3 t;
} // namespace test3
namespace test4 {
struct Test4 {
Test4();
~Test4();
};
void f() {
static Test4 staticLocal;
}
} // namespace test4
// CHECK: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @__sinit80000000_clang_1145401da454a7baad10bfe313c46638, i8* null }]
// CHECK: @llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @__sterm80000000_clang_1145401da454a7baad10bfe313c46638, i8* null }]
// CHECK: define internal void @__cxx_global_var_init() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: call void @_ZN5test15Test1C1Ev(%"struct.test1::Test1"* @_ZN5test12t1E)
// CHECK: %0 = call i32 @atexit(void ()* @__dtor__ZN5test12t1E)
// CHECK: ret void
// CHECK: }
// CHECK: define internal void @__dtor__ZN5test12t1E() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: call void @_ZN5test15Test1D1Ev(%"struct.test1::Test1"* @_ZN5test12t1E)
// CHECK: ret void
// CHECK: }
// CHECK: declare i32 @atexit(void ()*)
// CHECK: define internal void @__finalize__ZN5test12t1E() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: %0 = call i32 @unatexit(void ()* @__dtor__ZN5test12t1E)
// CHECK: %needs_destruct = icmp eq i32 %0, 0
// CHECK: br i1 %needs_destruct, label %destruct.call, label %destruct.end
// CHECK: destruct.call:
// CHECK: call void @__dtor__ZN5test12t1E()
// CHECK: br label %destruct.end
// CHECK: destruct.end:
// CHECK: ret void
// CHECK: }
// CHECK: declare i32 @unatexit(void ()*)
// CHECK: define internal void @__cxx_global_var_init.1() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: call void @_ZN5test15Test1C1Ev(%"struct.test1::Test1"* @_ZN5test12t2E)
// CHECK: %0 = call i32 @atexit(void ()* @__dtor__ZN5test12t2E)
// CHECK: ret void
// CHECK: }
// CHECK: define internal void @__dtor__ZN5test12t2E() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: call void @_ZN5test15Test1D1Ev(%"struct.test1::Test1"* @_ZN5test12t2E)
// CHECK: ret void
// CHECK: }
// CHECK: define internal void @__finalize__ZN5test12t2E() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: %0 = call i32 @unatexit(void ()* @__dtor__ZN5test12t2E)
// CHECK: %needs_destruct = icmp eq i32 %0, 0
// CHECK: br i1 %needs_destruct, label %destruct.call, label %destruct.end
// CHECK: destruct.call:
// CHECK: call void @__dtor__ZN5test12t2E()
// CHECK: br label %destruct.end
// CHECK: destruct.end:
// CHECK: ret void
// CHECK: }
// CHECK: define internal void @__cxx_global_var_init.2() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK32: %call = call i32 @_ZN5test23fooEv()
// CHECK64: %call = call signext i32 @_ZN5test23fooEv()
// CHECK: store i32 %call, i32* @_ZN5test21xE
// CHECK: ret void
// CHECK: }
// CHECK: define internal void @__cxx_global_var_init.3() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: %0 = call i32 @atexit(void ()* @__dtor__ZN5test31tE)
// CHECK: ret void
// CHECK: }
// CHECK: define internal void @__dtor__ZN5test31tE() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: call void @_ZN5test35Test3D1Ev(%"struct.test3::Test3"* @_ZN5test31tE)
// CHECK: ret void
// CHECK: }
// CHECK: define internal void @__finalize__ZN5test31tE() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: %0 = call i32 @unatexit(void ()* @__dtor__ZN5test31tE)
// CHECK: %needs_destruct = icmp eq i32 %0, 0
// CHECK: br i1 %needs_destruct, label %destruct.call, label %destruct.end
// CHECK: destruct.call:
// CHECK: call void @__dtor__ZN5test31tE()
// CHECK: br label %destruct.end
// CHECK: destruct.end:
// CHECK: ret void
// CHECK: }
// CHECK: define void @_ZN5test41fEv() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: %0 = load atomic i8, i8* bitcast (i64* @_ZGVZN5test41fEvE11staticLocal to i8*) acquire
// CHECK: %guard.uninitialized = icmp eq i8 %0, 0
// CHECK: br i1 %guard.uninitialized, label %init.check, label %init.end
// CHECK: init.check:
// CHECK: %1 = call i32 @__cxa_guard_acquire(i64* @_ZGVZN5test41fEvE11staticLocal)
// CHECK: %tobool = icmp ne i32 %1, 0
// CHECK: br i1 %tobool, label %init, label %init.end
// CHECK: init:
// CHECK: call void @_ZN5test45Test4C1Ev(%"struct.test4::Test4"* @_ZZN5test41fEvE11staticLocal)
// CHECK: %2 = call i32 @atexit(void ()* @__dtor__ZZN5test41fEvE11staticLocal)
// CHECK: call void @__cxa_guard_release(i64* @_ZGVZN5test41fEvE11staticLocal)
// CHECK: br label %init.end
// CHECK: init.end:
// CHECK: ret void
// CHECK: }
// CHECK: define internal void @__dtor__ZZN5test41fEvE11staticLocal() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: call void @_ZN5test45Test4D1Ev(%"struct.test4::Test4"* @_ZZN5test41fEvE11staticLocal)
// CHECK: ret void
// CHECK: }
// CHECK: define internal void @__finalize__ZZN5test41fEvE11staticLocal() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: %0 = call i32 @unatexit(void ()* @__dtor__ZZN5test41fEvE11staticLocal)
// CHECK: %needs_destruct = icmp eq i32 %0, 0
// CHECK: br i1 %needs_destruct, label %destruct.call, label %destruct.end
// CHECK: destruct.call:
// CHECK: call void @__dtor__ZZN5test41fEvE11staticLocal()
// CHECK: br label %destruct.end
// CHECK: destruct.end:
// CHECK: ret void
// CHECK: }
// CHECK: define void @__sinit80000000_clang_1145401da454a7baad10bfe313c46638() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: call void @__cxx_global_var_init()
// CHECK: call void @__cxx_global_var_init.1()
// CHECK: call void @__cxx_global_var_init.2()
// CHECK: call void @__cxx_global_var_init.3()
// CHECK: ret void
// CHECK: }
// CHECK: define void @__sterm80000000_clang_1145401da454a7baad10bfe313c46638() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: call void @__finalize__ZZN5test41fEvE11staticLocal()
// CHECK: call void @__finalize__ZN5test31tE()
// CHECK: call void @__finalize__ZN5test12t2E()
// CHECK: call void @__finalize__ZN5test12t1E()
// CHECK: ret void
// CHECK: }