[clang] 22337bf - [AIX][Frontend] Static init implementation for AIX considering no priority
Xiangling Liao via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 19 05:27:54 PDT 2020
Author: Xiangling Liao
Date: 2020-06-19T08:27:07-04:00
New Revision: 22337bfe7d87f9bf2b072ec7fe9165f7b9e2d793
URL: https://github.com/llvm/llvm-project/commit/22337bfe7d87f9bf2b072ec7fe9165f7b9e2d793
DIFF: https://github.com/llvm/llvm-project/commit/22337bfe7d87f9bf2b072ec7fe9165f7b9e2d793.diff
LOG: [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
Added:
clang/test/CodeGen/aix-constructor-attribute.cpp
clang/test/CodeGen/aix-destructor-attribute.cpp
clang/test/CodeGen/aix-init-priority-attribute.cpp
clang/test/CodeGenCXX/aix-static-init.cpp
Modified:
clang/include/clang/AST/Mangle.h
clang/lib/AST/ItaniumMangle.cpp
clang/lib/CodeGen/CGCXXABI.h
clang/lib/CodeGen/CGDeclCXX.cpp
clang/lib/CodeGen/CGOpenMPRuntime.cpp
clang/lib/CodeGen/CodeGenFunction.h
clang/lib/CodeGen/CodeGenModule.cpp
clang/lib/CodeGen/CodeGenModule.h
clang/lib/CodeGen/ItaniumCXXABI.cpp
clang/lib/CodeGen/MicrosoftCXXABI.cpp
clang/lib/Sema/SemaDeclAttr.cpp
Removed:
clang/test/CodeGen/static-init.cpp
################################################################################
diff --git a/clang/include/clang/AST/Mangle.h b/clang/include/clang/AST/Mangle.h
index b39a81462efd..011d1faab8ea 100644
--- a/clang/include/clang/AST/Mangle.h
+++ b/clang/include/clang/AST/Mangle.h
@@ -175,6 +175,8 @@ class ItaniumMangleContext : public MangleContext {
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) {
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index ad4ecad151f5..ddfbe9f86499 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -160,6 +160,7 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext {
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);
diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h
index f5f378510950..2b7f45fcab98 100644
--- a/clang/lib/CodeGen/CGCXXABI.h
+++ b/clang/lib/CodeGen/CGCXXABI.h
@@ -108,6 +108,8 @@ class CGCXXABI {
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
diff erent signature than the actual function (or equivalently,
/// bitcasting a function or function pointer to a
diff erent function type).
diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp
index b4a8d551a5ae..5a8500364295 100644
--- a/clang/lib/CodeGen/CGDeclCXX.cpp
+++ b/clang/lib/CodeGen/CGDeclCXX.cpp
@@ -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();
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
index d1b1d5c0d911..1ff62fd5894a 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -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.
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index d52fb52e325a..37a322567f51 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4197,6 +4197,9 @@ class CodeGenFunction : public CodeGenTypeCache {
/// 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 @@ class CodeGenFunction : public CodeGenTypeCache {
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,
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 79bc51e43f7a..7a9df700581e 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -411,7 +411,7 @@ void CodeGenModule::Release() {
checkAliases();
emitMultiVersionFunctions();
EmitCXXGlobalInitFunc();
- EmitCXXGlobalDtorFunc();
+ EmitCXXGlobalCleanUpFunc();
registerGlobalDtorsWithAtExit();
EmitCXXThreadLocalInitFunc();
if (ObjCRuntime)
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index d17d652b32f6..59b27fa32a1b 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -397,6 +397,10 @@ class CodeGenModule : public CodeGenTypeCache {
/// 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 @@ class CodeGenModule : public CodeGenTypeCache {
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 @@ class CodeGenModule : public CodeGenTypeCache {
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 @@ class CodeGenModule : public CodeGenTypeCache {
/// 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 @@ class CodeGenModule : public CodeGenTypeCache {
/// 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.
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index f79de5db2d39..18aff757f7b5 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -526,6 +526,12 @@ class XLCXXABI final : public ItaniumCXXABI {
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);
}
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index 6f6295a17158..08e30527af47 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -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);
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 763db5b41bb8..1a0594512a60 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -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);
diff --git a/clang/test/CodeGen/aix-constructor-attribute.cpp b/clang/test/CodeGen/aix-constructor-attribute.cpp
new file mode 100644
index 000000000000..008a92483361
--- /dev/null
+++ b/clang/test/CodeGen/aix-constructor-attribute.cpp
@@ -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
diff --git a/clang/test/CodeGen/aix-destructor-attribute.cpp b/clang/test/CodeGen/aix-destructor-attribute.cpp
new file mode 100644
index 000000000000..27200d392b87
--- /dev/null
+++ b/clang/test/CodeGen/aix-destructor-attribute.cpp
@@ -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
diff --git a/clang/test/CodeGen/aix-init-priority-attribute.cpp b/clang/test/CodeGen/aix-init-priority-attribute.cpp
new file mode 100644
index 000000000000..a19a54247e69
--- /dev/null
+++ b/clang/test/CodeGen/aix-init-priority-attribute.cpp
@@ -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
diff --git a/clang/test/CodeGen/static-init.cpp b/clang/test/CodeGen/static-init.cpp
deleted file mode 100644
index e336b55a0483..000000000000
--- a/clang/test/CodeGen/static-init.cpp
+++ /dev/null
@@ -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.
diff --git a/clang/test/CodeGenCXX/aix-static-init.cpp b/clang/test/CodeGenCXX/aix-static-init.cpp
new file mode 100644
index 000000000000..7307d3d448f1
--- /dev/null
+++ b/clang/test/CodeGenCXX/aix-static-init.cpp
@@ -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: }
More information about the cfe-commits
mailing list