Index: clang/lib/CodeGen/CGDeclCXX.cpp =================================================================== --- clang/lib/CodeGen/CGDeclCXX.cpp +++ clang/lib/CodeGen/CGDeclCXX.cpp @@ -365,12 +365,9 @@ llvm::Function *CodeGenModule::CreateGlobalInitOrCleanUpFunction( llvm::FunctionType *FTy, const Twine &Name, const CGFunctionInfo &FI, - SourceLocation Loc, bool TLS, bool IsExternalLinkage) { + SourceLocation Loc, bool TLS) { llvm::Function *Fn = llvm::Function::Create( - FTy, - IsExternalLinkage ? llvm::GlobalValue::ExternalLinkage - : llvm::GlobalValue::InternalLinkage, - Name, &getModule()); + FTy, llvm::GlobalValue::InternalLinkage, Name, &getModule()); if (!getLangOpts().AppleKext && !TLS) { // Set the section if needed. @@ -378,8 +375,7 @@ Fn->setSection(Section); } - if (Fn->hasInternalLinkage()) - SetInternalFunctionAttributes(GlobalDecl(), Fn, FI); + SetInternalFunctionAttributes(GlobalDecl(), Fn, FI); Fn->setCallingConv(getRuntimeCC()); @@ -589,22 +585,10 @@ 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(); + const bool UseSinitAndSterm = getCXXABI().useSinitAndSterm(); // Create our global prioritized initialization function. if (!PrioritizedCXXGlobalInits.empty()) { assert(!UseSinitAndSterm && "Prioritized sinit and sterm functions are not" @@ -644,24 +628,12 @@ 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); - } - + // 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 = CreateGlobalInitOrCleanUpFunction( - FTy, FuncName, FI, SourceLocation(), false /* TLS */, - IsExternalLinkage); + FTy, llvm::Twine("_GLOBAL__sub_I_", getTransformedFileName(getModule())), + FI); CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, CXXGlobalInits); AddGlobalCtor(Fn); @@ -695,25 +667,8 @@ const CGFunctionInfo &FI = getTypes().arrangeNullaryFunction(); // 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); - } + llvm::Function *Fn = + CreateGlobalInitOrCleanUpFunction(FTy, "_GLOBAL__D_a", FI); CodeGenFunction(*this).GenerateCXXGlobalCleanUpFunc( Fn, CXXGlobalDtorsOrStermFinalizers); Index: clang/lib/CodeGen/CodeGenModule.h =================================================================== --- clang/lib/CodeGen/CodeGenModule.h +++ clang/lib/CodeGen/CodeGenModule.h @@ -396,10 +396,6 @@ /// 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 MangledDeclNames; llvm::StringMap Manglings; @@ -819,8 +815,7 @@ llvm::Function *CreateGlobalInitOrCleanUpFunction( llvm::FunctionType *ty, const Twine &name, const CGFunctionInfo &FI, - SourceLocation Loc = SourceLocation(), bool TLS = false, - bool IsExternalLinkage = false); + SourceLocation Loc = SourceLocation(), bool TLS = 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 @@ -1059,6 +1054,12 @@ DtorFn.getCallee(), nullptr); } + /// Add an sterm finalizer to its own llvm.global_dtors entry. + void AddCXXStermFinalizerToGlobalDtor(llvm::Function *StermFinalizer, + int Priority) { + AddGlobalDtor(StermFinalizer, Priority); + } + /// Create or return a runtime function declaration with the specified type /// and name. If \p AssumeConvergent is true, the call will have the /// convergent attribute added. Index: clang/lib/CodeGen/ItaniumCXXABI.cpp =================================================================== --- clang/lib/CodeGen/ItaniumCXXABI.cpp +++ clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -4597,5 +4597,16 @@ CGF.FinishFunction(); - CGM.AddCXXStermFinalizerEntry(StermFinalizer); + if (D.getAttr()) + llvm::report_fatal_error( + "prioritized __sinit and __sterm functions are not yet supported"); + else if (isTemplateInstantiation(D.getTemplateSpecializationKind()) || + getContext().GetGVALinkageForVariable(&D) == GVA_DiscardableODR) + // According to C++ [basic.start.init]p2, class template static data + // members (i.e., implicitly or explicitly instantiated specializations) + // have unordered initialization. As a consequence, we can put them into + // their own llvm.global_dtors entry. + CGM.AddCXXStermFinalizerToGlobalDtor(StermFinalizer, 65535); + else + CGM.AddCXXStermFinalizerEntry(StermFinalizer); } Index: clang/test/CodeGenCXX/aix-static-init-debug-info.cpp =================================================================== --- clang/test/CodeGenCXX/aix-static-init-debug-info.cpp +++ clang/test/CodeGenCXX/aix-static-init-debug-info.cpp @@ -40,13 +40,13 @@ // CHECK: ret void, !dbg ![[DBGVAR24]] // CHECK: } -// CHECK: define void @__sinit80000000_clang_c3236cbaa79f2bae3a15e6379a05f625() [[ATTR:#[0-9]+]] !dbg ![[DBGVAR25:[0-9]+]] { +// CHECK: define internal void @_GLOBAL__sub_I__() [[ATTR:#[0-9]+]] !dbg ![[DBGVAR25:[0-9]+]] { // CHECK: entry: // CHECK: call void @__cxx_global_var_init(), !dbg ![[DBGVAR26:[0-9]+]] // CHECK: ret void // CHECK: } -// CHECK: define void @__sterm80000000_clang_c3236cbaa79f2bae3a15e6379a05f625() [[ATTR:#[0-9]+]] !dbg ![[DBGVAR27:[0-9]+]] { +// CHECK: define internal void @_GLOBAL__D_a() [[ATTR:#[0-9]+]] !dbg ![[DBGVAR27:[0-9]+]] { // CHECK: entry: // CHECK: call void @__finalize_v(), !dbg ![[DBGVAR28:[0-9]+]] // CHECK: ret void @@ -58,7 +58,7 @@ // CHECK: ![[DBGVAR21]] = !DILocation(line: 14, column: 3, scope: ![[DBGVAR20]]) // CHECK: ![[DBGVAR22]] = distinct !DISubprogram(linkageName: "__finalize_v", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 14, type: !{{[0-9]+}}, scopeLine: 14, flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !{{[0-9]+}}, retainedNodes: !{{[0-9]+}}) // CHECK: ![[DBGVAR24]] = !DILocation(line: 14, column: 3, scope: ![[DBGVAR22]]) -// CHECK: ![[DBGVAR25]] = distinct !DISubprogram(linkageName: "__sinit80000000_clang_c3236cbaa79f2bae3a15e6379a05f625", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, type: !{{[0-9]+}}, flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: !{{[0-9]+}}, retainedNodes: !{{[0-9]+}}) +// CHECK: ![[DBGVAR25]] = distinct !DISubprogram(linkageName: "_GLOBAL__sub_I__", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, type: !{{[0-9]+}}, flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !{{[0-9]+}}, retainedNodes: !{{[0-9]+}}) // CHECK: ![[DBGVAR26]] = !DILocation(line: 0, scope: ![[DBGVAR25]]) -// CHECK: ![[DBGVAR27]] = distinct !DISubprogram(linkageName: "__sterm80000000_clang_c3236cbaa79f2bae3a15e6379a05f625", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, type: !{{[0-9]+}}, flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: !{{[0-9]+}}, retainedNodes: !{{[0-9]+}}) +// CHECK: ![[DBGVAR27]] = distinct !DISubprogram(linkageName: "_GLOBAL__D_a", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, type: !{{[0-9]+}}, flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !{{[0-9]+}}, retainedNodes: !{{[0-9]+}}) // CHECK: ![[DBGVAR28]] = !DILocation(line: 0, scope: ![[DBGVAR27]]) Index: clang/test/CodeGenCXX/aix-static-init-temp-spec-and-inline-var.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/aix-static-init-temp-spec-and-inline-var.cpp @@ -0,0 +1,232 @@ +// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -S -emit-llvm -x c++ \ +// RUN: -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: -std=c++2a < %s | \ +// RUN: FileCheck --check-prefixes=CHECK,CHECK64 %s + +namespace test1 { +struct Test1 { + Test1(int) {} + ~Test1() {} +}; + +Test1 t0 = 2; + +template +Test1 t1 = 2; + +inline Test1 t2 = 2; + +void foo() { + (void)&t1; +} +} // namespace test1 + +namespace test2 { +template +struct A { + A() {} + ~A() {} + static A instance; +}; + +template +A A::instance; +template A<> A<>::instance; + +A &bar() { + A *a = new A; + return *a; +} +template <> +A A::instance = bar(); +} // namespace test2 + +// CHECK: @llvm.global_ctors = appending global [4 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @__cxx_global_var_init.1, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @__cxx_global_var_init.2, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @__cxx_global_var_init.4, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I__, i8* null }] +// CHECK: @llvm.global_dtors = appending global [4 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @__finalize__ZN5test12t2E, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @__finalize__ZN5test21AIvE8instanceE, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @__finalize__ZN5test12t1IiEE, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__D_a, i8* null }] + +// CHECK: define internal void @__cxx_global_var_init() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK32: call void @_ZN5test15Test1C1Ei(%"struct.test1::Test1"* @_ZN5test12t0E, i32 2) +// CHECK64: call void @_ZN5test15Test1C1Ei(%"struct.test1::Test1"* @_ZN5test12t0E, i32 signext 2) +// CHECK: %0 = call i32 @atexit(void ()* @__dtor__ZN5test12t0E) +// CHECK: ret void +// CHECK: } + +// CHECK: define internal void @__dtor__ZN5test12t0E() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: call void @_ZN5test15Test1D1Ev(%"struct.test1::Test1"* @_ZN5test12t0E) +// CHECK: ret void +// CHECK: } + +// CHECK: define internal void @__finalize__ZN5test12t0E() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: %0 = call i32 @unatexit(void ()* @__dtor__ZN5test12t0E) +// 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__ZN5test12t0E() +// CHECK: br label %destruct.end + +// CHECK: destruct.end: +// CHECK: ret void +// CHECK: } + +// CHECK: define internal void @__cxx_global_var_init.1() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: %0 = load atomic i8, i8* bitcast (i64* @_ZGVN5test12t2E 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* @_ZGVN5test12t2E) +// CHECK: %tobool = icmp ne i32 %1, 0 +// CHECK: br i1 %tobool, label %init, label %init.end + +// CHECK: init: +// CHECK32: call void @_ZN5test15Test1C1Ei(%"struct.test1::Test1"* @_ZN5test12t2E, i32 2) +// CHECK64: call void @_ZN5test15Test1C1Ei(%"struct.test1::Test1"* @_ZN5test12t2E, i32 signext 2) +// CHECK: %2 = call i32 @atexit(void ()* @__dtor__ZN5test12t2E) +// CHECK: call void @__cxa_guard_release(i64* @_ZGVN5test12t2E) +// CHECK: br label %init.end + +// CHECK: init.end: +// 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: +// CHECK: %0 = load i8, i8* bitcast (i64* @_ZGVN5test21AIvE8instanceE to i8*) +// CHECK: %guard.uninitialized = icmp eq i8 %0, 0 +// CHECK: br i1 %guard.uninitialized, label %init.check, label %init.end + +// CHECK: init.check: +// CHECK: call void @_ZN5test21AIvEC1Ev(%"struct.test2::A"* @_ZN5test21AIvE8instanceE) +// CHECK: %1 = call i32 @atexit(void ()* @__dtor__ZN5test21AIvE8instanceE) +// CHECK: store i64 1, i64* @_ZGVN5test21AIvE8instanceE +// CHECK: br label %init.end + +// CHECK: init.end: +// CHECK: ret void +// CHECK: } + +// CHECK: define internal void @__dtor__ZN5test21AIvE8instanceE() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: call void @_ZN5test21AIvED1Ev(%"struct.test2::A"* @_ZN5test21AIvE8instanceE) +// CHECK: ret void +// CHECK: } + +// CHECK: define internal void @__finalize__ZN5test21AIvE8instanceE() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: %0 = call i32 @unatexit(void ()* @__dtor__ZN5test21AIvE8instanceE) +// 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__ZN5test21AIvE8instanceE() +// CHECK: br label %destruct.end + +// CHECK: destruct.end: +// CHECK: ret void +// CHECK: } + +// CHECK: define internal void @__cxx_global_var_init.3() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: %call = call nonnull align 1 dereferenceable(1) %"struct.test2::A.0"* @_ZN5test23barEv() +// CHECK: %0 = call i32 @atexit(void ()* @__dtor__ZN5test21AIiE8instanceE) +// CHECK: ret void +// CHECK: } + +// CHECK: define internal void @__dtor__ZN5test21AIiE8instanceE() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: call void @_ZN5test21AIiED1Ev(%"struct.test2::A.0"* @_ZN5test21AIiE8instanceE) +// CHECK: ret void +// CHECK: } + +// CHECK: define internal void @__finalize__ZN5test21AIiE8instanceE() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: %0 = call i32 @unatexit(void ()* @__dtor__ZN5test21AIiE8instanceE) +// 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__ZN5test21AIiE8instanceE() +// CHECK: br label %destruct.end + +// CHECK: destruct.end: +// CHECK: ret void +// CHECK: } + +// CHECK: define internal void @__cxx_global_var_init.4() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: %0 = load i8, i8* bitcast (i64* @_ZGVN5test12t1IiEE to i8*) +// CHECK: %guard.uninitialized = icmp eq i8 %0, 0 +// CHECK: br i1 %guard.uninitialized, label %init.check, label %init.end + +// CHECK: init.check: +// CHECK32: call void @_ZN5test15Test1C1Ei(%"struct.test1::Test1"* @_ZN5test12t1IiEE, i32 2) +// CHECK64: call void @_ZN5test15Test1C1Ei(%"struct.test1::Test1"* @_ZN5test12t1IiEE, i32 signext 2) +// CHECK: %1 = call i32 @atexit(void ()* @__dtor__ZN5test12t1IiEE) +// CHECK: store i64 1, i64* @_ZGVN5test12t1IiEE +// CHECK: br label %init.end + +// CHECK: init.end: +// CHECK: ret void +// CHECK: } + +// CHECK: define internal void @__dtor__ZN5test12t1IiEE() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: call void @_ZN5test15Test1D1Ev(%"struct.test1::Test1"* @_ZN5test12t1IiEE) +// CHECK: ret void +// CHECK: } + +// CHECK: define internal void @__finalize__ZN5test12t1IiEE() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: %0 = call i32 @unatexit(void ()* @__dtor__ZN5test12t1IiEE) +// 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__ZN5test12t1IiEE() +// CHECK: br label %destruct.end + +// CHECK: destruct.end: +// CHECK: ret void +// CHECK: } + +// CHECK: define internal void @_GLOBAL__sub_I__() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: call void @__cxx_global_var_init() +// CHECK: call void @__cxx_global_var_init.3() +// CHECK: ret void +// CHECK: } + +// CHECK: define internal void @_GLOBAL__D_a() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: call void @__finalize__ZN5test21AIiE8instanceE() +// CHECK: call void @__finalize__ZN5test12t0E() +// CHECK: ret void +// CHECK: } Index: clang/test/CodeGenCXX/aix-static-init.cpp =================================================================== --- clang/test/CodeGenCXX/aix-static-init.cpp +++ clang/test/CodeGenCXX/aix-static-init.cpp @@ -38,8 +38,8 @@ } } // 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: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I__, i8* null }] +// CHECK: @llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__D_a, i8* null }] // CHECK: define internal void @__cxx_global_var_init() [[ATTR:#[0-9]+]] { // CHECK: entry: @@ -174,7 +174,7 @@ // CHECK: ret void // CHECK: } -// CHECK: define void @__sinit80000000_clang_1145401da454a7baad10bfe313c46638() [[ATTR:#[0-9]+]] { +// CHECK: define internal void @_GLOBAL__sub_I__() [[ATTR:#[0-9]+]] { // CHECK: entry: // CHECK: call void @__cxx_global_var_init() // CHECK: call void @__cxx_global_var_init.1() @@ -183,7 +183,7 @@ // CHECK: ret void // CHECK: } -// CHECK: define void @__sterm80000000_clang_1145401da454a7baad10bfe313c46638() [[ATTR:#[0-9]+]] { +// CHECK: define internal void @_GLOBAL__D_a() [[ATTR:#[0-9]+]] { // CHECK: entry: // CHECK: call void @__finalize__ZZN5test41fEvE11staticLocal() // CHECK: call void @__finalize__ZN5test31tE() Index: clang/unittests/CodeGen/IncrementalProcessingTest.cpp =================================================================== --- clang/unittests/CodeGen/IncrementalProcessingTest.cpp +++ clang/unittests/CodeGen/IncrementalProcessingTest.cpp @@ -159,11 +159,6 @@ // First code should not end up in second module: ASSERT_FALSE(M[2]->getFunction("funcForProg1")); - // TODO: Remove this after the static initialization frontend implementation - // is recovered on AIX. - if (compiler.getTarget().getTriple().isOSAIX()) - return; - // Make sure global inits exist and are unique: const Function* GlobalInit1 = getGlobalInit(*M[1]); ASSERT_TRUE(GlobalInit1); Index: llvm/include/llvm/CodeGen/AsmPrinter.h =================================================================== --- llvm/include/llvm/CodeGen/AsmPrinter.h +++ llvm/include/llvm/CodeGen/AsmPrinter.h @@ -453,6 +453,14 @@ emitGlobalConstant(DL, CV); } + /// Targets can override this to change how global constants and their + /// associated priority numbers that are part of a C++ static/global + /// constructor list are emitted. + virtual void emitXXStructor(const DataLayout &DL, int Priority, + unsigned Index, Constant *CV, bool IsCtor) { + llvm_unreachable("Emit CXXStructor with priority is target-specific."); + } + /// Return true if the basic block has exactly one predecessor and the control /// transfer mechanism between the predecessor and this block is a /// fall-through. Index: llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h =================================================================== --- llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h @@ -225,11 +225,6 @@ MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const override; - MCSection *getStaticCtorSection(unsigned Priority, - const MCSymbol *KeySym) const override; - MCSection *getStaticDtorSection(unsigned Priority, - const MCSymbol *KeySym) const override; - const MCExpr *lowerRelativeReference(const GlobalValue *LHS, const GlobalValue *RHS, const TargetMachine &TM) const override; Index: llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -2118,21 +2118,25 @@ // init priority. if (!isa(List)) return; + const bool IsAIX = TM.getTargetTriple().isOSAIX(); // Gather the structors in a form that's convenient for sorting by priority. SmallVector Structors; for (Value *O : cast(List)->operands()) { auto *CS = cast(O); if (CS->getOperand(1)->isNullValue()) - break; // Found a null terminator, skip the rest. + break; // Found a null terminator, skip the rest. ConstantInt *Priority = dyn_cast(CS->getOperand(0)); - if (!Priority) continue; // Malformed. + if (!Priority) + continue; // Malformed. Structors.push_back(Structor()); Structor &S = Structors.back(); S.Priority = Priority->getLimitedValue(65535); S.Func = CS->getOperand(1); - if (!CS->getOperand(2)->isNullValue()) + if (!CS->getOperand(2)->isNullValue()) { + assert(!IsAIX && "Directive .ref is not yet supported on AIX."); S.ComdatKey = dyn_cast(CS->getOperand(2)->stripPointerCasts()); + } } // Emit the function pointers in the target-specific order @@ -2140,6 +2144,7 @@ return L.Priority < R.Priority; }); const Align Align = DL.getPointerPrefAlignment(); + unsigned Index = 0; for (Structor &S : Structors) { const TargetLoweringObjectFile &Obj = getObjFileLowering(); const MCSymbol *KeySym = nullptr; @@ -2154,12 +2159,20 @@ KeySym = getSymbol(GV); } + + if (IsAIX) { + emitXXStructor(DL, S.Priority, Index, S.Func, isCtor); + ++Index; + continue; + } + MCSection *OutputSection = - (isCtor ? Obj.getStaticCtorSection(S.Priority, KeySym) - : Obj.getStaticDtorSection(S.Priority, KeySym)); + isCtor ? Obj.getStaticCtorSection(S.Priority, KeySym) + : Obj.getStaticDtorSection(S.Priority, KeySym); OutStreamer->SwitchSection(OutputSection); if (OutStreamer->getCurrentSection() != OutStreamer->getPreviousSection()) emitAlignment(Align); + emitXXStructor(DL, S.Func); } } Index: llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp =================================================================== --- llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -2114,16 +2114,6 @@ LSDAEncoding = 0; } -MCSection *TargetLoweringObjectFileXCOFF::getStaticCtorSection( - unsigned Priority, const MCSymbol *KeySym) const { - report_fatal_error("XCOFF ctor section not yet implemented."); -} - -MCSection *TargetLoweringObjectFileXCOFF::getStaticDtorSection( - unsigned Priority, const MCSymbol *KeySym) const { - report_fatal_error("XCOFF dtor section not yet implemented."); -} - const MCExpr *TargetLoweringObjectFileXCOFF::lowerRelativeReference( const GlobalValue *LHS, const GlobalValue *RHS, const TargetMachine &TM) const { Index: llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp =================================================================== --- llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -67,6 +67,7 @@ #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" +#include "llvm/Transforms/Utils/ModuleUtils.h" #include #include #include @@ -153,6 +154,9 @@ /// linkage for them in AIX. SmallPtrSet ExtSymSDNodeSymbols; + /// A unique trailing identifier as a part of sinit/sterm functions. + std::string GlobalUniqueModuleId; + static void ValidateGV(const GlobalVariable *GV); // Record a list of GlobalAlias associated with a GlobalObject. // This is used for AIX's extra-label-at-definition aliasing strategy. @@ -171,6 +175,9 @@ bool doInitialization(Module &M) override; + void emitXXStructor(const DataLayout &DL, const int Priority, + const unsigned Index, Constant *CV, bool IsCtor) override; + void SetupMachineFunction(MachineFunction &MF) override; void emitGlobalVariable(const GlobalVariable *GV) override; @@ -1678,11 +1685,6 @@ static bool isSpecialLLVMGlobalArrayToSkip(const GlobalVariable *GV) { return GV->hasAppendingLinkage() && StringSwitch(GV->getName()) - // TODO: Update the handling of global arrays for static init when - // we support the ".ref" directive. - // Otherwise, we can skip these arrays, because the AIX linker - // collects static init functions simply based on their name. - .Cases("llvm.global_ctors", "llvm.global_dtors", true) // TODO: Linker could still eliminate the GV if we just skip // handling llvm.used array. Skipping them for now until we or the // AIX OS team come up with a good solution. @@ -1692,8 +1694,15 @@ .Default(false); } +static bool isSpecialLLVMGlobalArrayForStaticInit(const GlobalVariable *GV) { + return StringSwitch(GV->getName()) + .Cases("llvm.global_ctors", "llvm.global_dtors", true) + .Default(false); +} + void PPCAIXAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) { - if (isSpecialLLVMGlobalArrayToSkip(GV)) + // Special LLVM global arrays have been handled at the initialization. + if (isSpecialLLVMGlobalArrayToSkip(GV) || isSpecialLLVMGlobalArrayForStaticInit(GV)) return; assert(!GV->getName().startswith("llvm.") && @@ -1849,6 +1858,24 @@ for (const auto &G : M.globals()) { if (isSpecialLLVMGlobalArrayToSkip(&G)) continue; + + // Set correct linkage and function names for sinit and sterm functions + // beforing emitting them. + if (isSpecialLLVMGlobalArrayForStaticInit(&G)) { + if (GlobalUniqueModuleId.empty()) { + GlobalUniqueModuleId = getUniqueModuleId(&M); + // 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); + } + emitSpecialLLVMGlobal(&G); + continue; + } + setCsectAlignment(&G); } @@ -1916,6 +1943,21 @@ return Ret; } +void PPCAIXAsmPrinter::emitXXStructor(const DataLayout &DL, const int Priority, + const unsigned Index, Constant *CV, + bool IsCtor) { + if (Priority != 65535) + report_fatal_error( + "prioritized sinit and sterm functions are not yet supported on AIX"); + + llvm::GlobalAlias::create( + GlobalValue::ExternalLinkage, + (IsCtor ? llvm::Twine("__sinit") : llvm::Twine("__sterm")) + + llvm::Twine("80000000_clang_", GlobalUniqueModuleId) + + llvm::Twine("_", llvm::utostr(Index)), + cast(CV)); +} + /// createPPCAsmPrinterPass - Returns a pass that prints the PPC assembly code /// for a MachineFunction to the given output stream, in a format that the /// Darwin assembler can deal with. Index: llvm/test/CodeGen/PowerPC/aix-static-init-default-priority.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/PowerPC/aix-static-init-default-priority.ll @@ -0,0 +1,60 @@ +; RUN: llc -mtriple powerpc-ibm-aix-xcoff < %s | FileCheck %s +; RUN: llc -mtriple powerpc64-ibm-aix-xcoff < %s | FileCheck %s + +@llvm.global_ctors = appending global [2 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @init1, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @init2, i8* null }] +@llvm.global_dtors = appending global [2 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @destruct1, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @destruct2, i8* null }] + +define i32 @extFunc() { +entry: + ret i32 3 +} + +define internal void @init1() { + ret void +} + +define internal void @destruct1() { + ret void +} + +define internal void @init2() { + ret void +} + +define internal void @destruct2() { + ret void +} + +; CHECK: .lglobl init1[DS] +; CHECK: .lglobl .init1 +; CHECK: .csect init1[DS] +; CHECK: __sinit80000000_clang_ac404299654d2af7eae71e75c17f7c9b_0: # @init1 +; CHECK: .init1: +; CHECK: .__sinit80000000_clang_ac404299654d2af7eae71e75c17f7c9b_0: +; CHECK: .lglobl destruct1[DS] +; CHECK: .lglobl .destruct1 +; CHECK: .csect destruct1[DS] +; CHECK: __sterm80000000_clang_ac404299654d2af7eae71e75c17f7c9b_0: # @destruct1 +; CHECK: .destruct1: +; CHECK: .__sterm80000000_clang_ac404299654d2af7eae71e75c17f7c9b_0: +; CHECK: .lglobl init2[DS] +; CHECK: .lglobl .init2 +; CHECK: .csect init2[DS] +; CHECK: __sinit80000000_clang_ac404299654d2af7eae71e75c17f7c9b_1: # @init2 +; CHECK: .init2: +; CHECK: .__sinit80000000_clang_ac404299654d2af7eae71e75c17f7c9b_1: +; CHECK: .lglobl destruct2[DS] +; CHECK: .lglobl .destruct2 +; CHECK: .csect destruct2[DS] +; CHECK: __sterm80000000_clang_ac404299654d2af7eae71e75c17f7c9b_1: # @destruct2 +; CHECK: .destruct2: +; CHECK: .__sterm80000000_clang_ac404299654d2af7eae71e75c17f7c9b_1: + +; CHECK: .globl __sinit80000000_clang_ac404299654d2af7eae71e75c17f7c9b_0 +; CHECK: .globl .__sinit80000000_clang_ac404299654d2af7eae71e75c17f7c9b_0 +; CHECK: .globl __sinit80000000_clang_ac404299654d2af7eae71e75c17f7c9b_1 +; CHECK: .globl .__sinit80000000_clang_ac404299654d2af7eae71e75c17f7c9b_1 +; CHECK: .globl __sterm80000000_clang_ac404299654d2af7eae71e75c17f7c9b_0 +; CHECK: .globl .__sterm80000000_clang_ac404299654d2af7eae71e75c17f7c9b_0 +; CHECK: .globl __sterm80000000_clang_ac404299654d2af7eae71e75c17f7c9b_1 +; CHECK: .globl .__sterm80000000_clang_ac404299654d2af7eae71e75c17f7c9b_1 Index: llvm/test/CodeGen/PowerPC/aix-static-init-no-unique-module-id.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/PowerPC/aix-static-init-no-unique-module-id.ll @@ -0,0 +1,7 @@ +; RUN: not llc -mtriple powerpc-ibm-aix-xcoff < %s 2>&1 | FileCheck %s +; RUN: not llc -mtriple powerpc64-ibm-aix-xcoff < %s 2>&1 | FileCheck %s + +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @foo, i8* null }] +@llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @bar, i8* null }] + +// CHECK: LLVM ERROR: cannot produce a unique identifier for this module based on strong external symbols Index: llvm/test/CodeGen/PowerPC/aix-static-init-non-default-priority.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/PowerPC/aix-static-init-non-default-priority.ll @@ -0,0 +1,10 @@ +; RUN: not llc -mtriple powerpc-ibm-aix-xcoff < %s 2>&1 | FileCheck %s +; RUN: not llc -mtriple powerpc64-ibm-aix-xcoff < %s 2>&1 | FileCheck %s + +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 655, void ()* @foo, i8* null }] + +define void @foo() { + ret void +} + +// CHECK: LLVM ERROR: prioritized sinit and sterm functions are not yet supported