Xiangling_L updated this revision to Diff 270548.
Xiangling_L marked 35 inline comments as done.
Xiangling_L edited the summary of this revision.
Xiangling_L added a comment.
Address another round of reviews;
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D74166/new/
https://reviews.llvm.org/D74166
Files:
clang/include/clang/AST/Mangle.h
clang/lib/AST/ItaniumMangle.cpp
clang/lib/CodeGen/CGCXXABI.h
clang/lib/CodeGen/CGDeclCXX.cpp
clang/lib/CodeGen/CodeGenFunction.h
clang/lib/CodeGen/CodeGenModule.cpp
clang/lib/CodeGen/CodeGenModule.h
clang/lib/CodeGen/ItaniumCXXABI.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/test/CodeGen/aix-constructor-attribute.cpp
clang/test/CodeGen/aix-destructor-attribute.cpp
clang/test/CodeGen/aix-init-priority-attribute.cpp
clang/test/CodeGen/static-init.cpp
Index: clang/test/CodeGen/static-init.cpp
===================================================================
--- clang/test/CodeGen/static-init.cpp
+++ clang/test/CodeGen/static-init.cpp
@@ -1,12 +1,139 @@
-// RUN: not %clang_cc1 -triple powerpc-ibm-aix-xcoff -S -emit-llvm -x c++ %s \
-// RUN: -o /dev/null 2>&1 | FileCheck %s
+// 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: not %clang_cc1 -triple powerpc64-ibm-aix-xcoff -S -emit-llvm -x c++ %s \
-// RUN: -o /dev/null 2>&1 | FileCheck %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
-struct test {
- test();
- ~test();
-} t;
+namespace test1 {
+ struct Test1 {
+ Test1();
+ ~Test1();
+ } t1, t2;
+}; // namespace test1
-// CHECK: error in backend: Static initialization has not been implemented on XL ABI yet.
+namespace test2 {
+ int foo() { return 3; }
+ int x = foo();
+}; // namespace test2
+
+namespace test3 {
+ struct Test {
+ constexpr Test() {};
+ ~Test() {};
+ };
+
+ constinit Test t;
+}; // namespace test3
+
+// CHECK: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @__sinit80000000_clang_510e898aa8d263cac999dd03eeed5b51, i8* null }]
+// CHECK: @llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @__sterm80000000_clang_510e898aa8d263cac999dd03eeed5b51, i8* null }]
+
+// CHECK: define internal void @__cxx_global_var_init() #0 {
+// 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() #0 {
+// 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() #0 {
+// CHECK: entry:
+// CHECK: %0 = call i32 @unatexit(void ()* @__dtor__ZN5test12t1E)
+// CHECK: %needsDestruct = icmp eq i32 %0, 0
+// CHECK: br i1 %needsDestruct, 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() #0 {
+// 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() #0 {
+// CHECK: entry:
+// CHECK: call void @_ZN5test15Test1D1Ev(%"struct.test1::Test1"* @_ZN5test12t2E)
+// CHECK: ret void
+// CHECK: }
+
+// CHECK: define internal void @__finalize__ZN5test12t2E() #0 {
+// CHECK: entry:
+// CHECK: %0 = call i32 @unatexit(void ()* @__dtor__ZN5test12t2E)
+// CHECK: %needsDestruct = icmp eq i32 %0, 0
+// CHECK: br i1 %needsDestruct, 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() #0 {
+// 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() #0 {
+// CHECK: entry:
+// CHECK: %0 = call i32 @atexit(void ()* @__dtor__ZN5test31tE)
+// CHECK: ret void
+// CHECK: }
+
+// CHECK: define internal void @__dtor__ZN5test31tE() #0 {
+// CHECK: entry:
+// CHECK: call void @_ZN5test34TestD1Ev(%"struct.test3::Test"* @_ZN5test31tE)
+// CHECK: ret void
+// CHECK: }
+
+// CHECK: define internal void @__finalize__ZN5test31tE() #0 {
+// CHECK: entry:
+// CHECK: %0 = call i32 @unatexit(void ()* @__dtor__ZN5test31tE)
+// CHECK: %needsDestruct = icmp eq i32 %0, 0
+// CHECK: br i1 %needsDestruct, 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 dso_local void @__sinit80000000_clang_510e898aa8d263cac999dd03eeed5b51() #0 {
+// 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 dso_local void @__sterm80000000_clang_510e898aa8d263cac999dd03eeed5b51() #0 {
+// CHECK: entry:
+// CHECK: call void @__finalize__ZN5test31tE()
+// CHECK: call void @__finalize__ZN5test12t2E()
+// CHECK: call void @__finalize__ZN5test12t1E()
+// CHECK: ret void
+// CHECK: }
Index: clang/test/CodeGen/aix-init-priority-attribute.cpp
===================================================================
--- /dev/null
+++ 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 unsupported on AIX yet
Index: clang/test/CodeGen/aix-destructor-attribute.cpp
===================================================================
--- /dev/null
+++ 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 unsupported on AIX yet
Index: clang/test/CodeGen/aix-constructor-attribute.cpp
===================================================================
--- /dev/null
+++ 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 unsupported on AIX yet
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -6939,13 +6939,20 @@
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 unsupported on AIX yet");
+ 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 unsupported on AIX yet");
+ else
+ handleDestructorAttr(S, D, AL);
break;
case ParsedAttr::AT_EnableIf:
handleEnableIfAttr(S, D, AL);
@@ -7139,7 +7146,11 @@
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 unsupported on AIX yet");
+ else
+ handleInitPriorityAttr(S, D, AL);
break;
case ParsedAttr::AT_Packed:
handlePackedAttr(S, D, AL);
Index: clang/lib/CodeGen/ItaniumCXXABI.cpp
===================================================================
--- clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -526,6 +526,12 @@
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);
};
}
@@ -4432,6 +4438,68 @@
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 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 a variable destruction function.
+ const CGFunctionInfo &FI = CGM.getTypes().arrangeNullaryFunction();
+ llvm::Function *StermFinalizer = CGM.CreateGlobalInitOrDestructFunction(
+ 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 and the related __dtor function will be
+ // called to destruct the object. Otherwise, a non-zero value is returned.
+ llvm::Value *V = CGF.unregisterGlobalDtorWithUnAtExit(dtorStub);
+
+ llvm::Value *NeedsDestruct =
+ CGF.Builder.CreateIsNull(V, "needsDestruct");
+
+ 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.EmitCXXGuardedInitBranch(NeedsDestruct, DestructCallBlock, EndBlock,
+ CodeGenFunction::GuardKind::VariableGuard, &D);
+
+ 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.AddCXXDtorEntry(StermFinalizer);
}
Index: clang/lib/CodeGen/CodeGenModule.h
===================================================================
--- clang/lib/CodeGen/CodeGenModule.h
+++ clang/lib/CodeGen/CodeGenModule.h
@@ -397,6 +397,10 @@
/// 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,12 @@
SmallVector<GlobalInitData, 8> PrioritizedCXXGlobalInits;
/// Global destructor functions and arguments that need to run on termination.
+ /// Global destructor functions and arguments that need to run on termination;
+ /// When UseSinitAndSterm is set, it contains sterm finalizers functions
+ /// instead that need to 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;
@@ -1045,8 +1052,14 @@
/// 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 a destructor to the C++ global destructor function.
+ void AddCXXDtorEntry(llvm::FunctionCallee DtorFn) {
+ CXXGlobalDtorsOrStermFinalizers.emplace_back(DtorFn.getFunctionType(),
+ DtorFn.getCallee(), nullptr);
}
/// Create or return a runtime function declaration with the specified type
@@ -1446,8 +1459,8 @@
/// Emit the function that initializes C++ globals.
void EmitCXXGlobalInitFunc();
- /// Emit the function that destroys C++ globals.
- void EmitCXXGlobalDtorFunc();
+ /// Emit the function that destructs C++ globals.
+ void EmitCXXGlobalDestructFunc();
/// Emit the function that initializes the specified global (if PerformInit is
/// true) and registers its destructor.
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -411,7 +411,7 @@
checkAliases();
emitMultiVersionFunctions();
EmitCXXGlobalInitFunc();
- EmitCXXGlobalDtorFunc();
+ EmitCXXGlobalDestructFunc();
registerGlobalDtorsWithAtExit();
EmitCXXThreadLocalInitFunc();
if (ObjCRuntime)
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -4171,6 +4171,9 @@
/// 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
@@ -4194,12 +4197,12 @@
ArrayRef<llvm::Function *> CXXThreadLocals,
ConstantAddress Guard = ConstantAddress::invalid());
- /// GenerateCXXGlobalDtorsFunc - Generates code for destroying global
+ /// GenerateCXXGlobalDestructFunc - Generates code for destroying global
/// variables.
- void GenerateCXXGlobalDtorsFunc(
+ void GenerateCXXGlobalDestructFunc(
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,
Index: clang/lib/CodeGen/CGDeclCXX.cpp
===================================================================
--- clang/lib/CodeGen/CGDeclCXX.cpp
+++ clang/lib/CodeGen/CGDeclCXX.cpp
@@ -20,7 +20,9 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/MDBuilder.h"
+#include "llvm/Support/Format.h"
#include "llvm/Support/Path.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
using namespace clang;
using namespace CodeGen;
@@ -249,7 +251,7 @@
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 +272,12 @@
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) &&
+ "atexit has wrong parameter 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 +288,30 @@
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) &&
+ "unatexit has wrong parameter 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) {
@@ -533,6 +563,22 @@
CXXThreadLocals.clear();
}
+static StringRef getTransformedFileName(llvm::Module &M, SmallString<128> &FileName) {
+ FileName = llvm::sys::path::filename(M.getName());
+
+ if (FileName.empty())
+ FileName = "<null>";
+
+ for (size_t i = 0; i < FileName.size(); ++i) {
+ // Replace everything that's not [a-zA-Z0-9._] with a _. This set happens
+ // to be the set of C preprocessing numbers.
+ if (!isPreprocessingNumberBody(FileName[i]))
+ FileName[i] = '_';
+ }
+
+ return FileName;
+}
+
void
CodeGenModule::EmitCXXGlobalInitFunc() {
while (!CXXGlobalInits.empty() && !CXXGlobalInits.back())
@@ -541,11 +587,27 @@
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());
@@ -577,22 +639,29 @@
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.
- SmallString<128> FileName = llvm::sys::path::filename(getModule().getName());
- if (FileName.empty())
- FileName = "<null>";
+ // Create our global initialization function.
+ if (CXXGlobalInits.empty())
+ return;
- for (size_t i = 0; i < FileName.size(); ++i) {
- // Replace everything that's not [a-zA-Z0-9._] with a _. This set happens
- // to be the set of C preprocessing numbers.
- if (!isPreprocessingNumberBody(FileName[i]))
- FileName[i] = '_';
+ SmallString<128> FuncName;
+ if (UseSinitAndSterm)
+ FuncName = llvm::Twine("__sinit80000000_clang_", GlobalUniqueModuleId)
+ .toNullTerminatedStringRef(FuncName);
+ 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.
+ SmallString<128> Storage;
+ FuncName = llvm::Twine("_GLOBAL__sub_I_",
+ getTransformedFileName(getModule(), Storage))
+ .toNullTerminatedStringRef(FuncName);
}
- llvm::Function *Fn = CreateGlobalInitOrDestructFunction(
- FTy, llvm::Twine("_GLOBAL__sub_I_", FileName), FI);
+ llvm::Function *Fn =
+ CreateGlobalInitOrDestructFunction(FTy, FuncName, FI, SourceLocation());
+
+ if (getCXXABI().useSinitAndSterm())
+ Fn->setLinkage(llvm::Function::ExternalLinkage);
CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, CXXGlobalInits);
AddGlobalCtor(Fn);
@@ -618,19 +687,32 @@
CXXGlobalInits.clear();
}
-void CodeGenModule::EmitCXXGlobalDtorFunc() {
- if (CXXGlobalDtors.empty())
+void CodeGenModule::EmitCXXGlobalDestructFunc() {
+ if (CXXGlobalDtorsOrStermFinalizers.empty())
return;
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
+ const CGFunctionInfo &FI = getTypes().arrangeNullaryFunction();
// Create our global destructor function.
- const CGFunctionInfo &FI = getTypes().arrangeNullaryFunction();
- llvm::Function *Fn =
- CreateGlobalInitOrDestructFunction(FTy, "_GLOBAL__D_a", FI);
+ llvm::Function *Fn = nullptr;
+ if (getCXXABI().useSinitAndSterm()) {
+ assert(!GlobalUniqueModuleId.empty() &&
+ "Invalid empty GlobalUniqueModuleId.");
+
+ Fn = CreateGlobalInitOrDestructFunction(
+ FTy, llvm::Twine("__sterm80000000_clang_", GlobalUniqueModuleId), FI,
+ SourceLocation());
- CodeGenFunction(*this).GenerateCXXGlobalDtorsFunc(Fn, CXXGlobalDtors);
+ Fn->setLinkage(llvm::Function::ExternalLinkage);
+ } else {
+ Fn = CreateGlobalInitOrDestructFunction(FTy, "_GLOBAL__D_a", FI);
+ }
+
+ CodeGenFunction(*this).GenerateCXXGlobalDestructFunc(
+ Fn, CXXGlobalDtorsOrStermFinalizers);
AddGlobalDtor(Fn);
+ CXXGlobalDtorsOrStermFinalizers.clear();
}
/// Emit the code necessary to initialize the given global variable.
@@ -726,10 +808,10 @@
FinishFunction();
}
-void CodeGenFunction::GenerateCXXGlobalDtorsFunc(
+void CodeGenFunction::GenerateCXXGlobalDestructFunc(
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,
@@ -738,12 +820,21 @@
auto AL = ApplyDebugLocation::CreateArtificial(*this);
// Emit the dtors, in reverse order from construction.
- for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i) {
+ 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());
Index: clang/lib/CodeGen/CGCXXABI.h
===================================================================
--- clang/lib/CodeGen/CGCXXABI.h
+++ clang/lib/CodeGen/CGCXXABI.h
@@ -108,6 +108,8 @@
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).
Index: clang/lib/AST/ItaniumMangle.cpp
===================================================================
--- clang/lib/AST/ItaniumMangle.cpp
+++ clang/lib/AST/ItaniumMangle.cpp
@@ -160,6 +160,7 @@
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,
@@ -5222,6 +5223,18 @@
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);
Index: clang/include/clang/AST/Mangle.h
===================================================================
--- clang/include/clang/AST/Mangle.h
+++ clang/include/clang/AST/Mangle.h
@@ -175,6 +175,8 @@
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) {
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits