diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -442,8 +442,11 @@ bool isCudaSharedVar = getLangOpts().CUDA && getLangOpts().CUDAIsDevice && D.hasAttr(); // If this value has an initializer, emit it. - if (D.getInit() && !isCudaSharedVar) + if (D.getInit() && !isCudaSharedVar) { var = AddInitializerToStaticVarDecl(D, var); + if (CGM.getTriple().isOSAIX() && D.getTLSKind() == VarDecl::TLS_None) + CGM.addVarWithInitTerm(&D, var); + } var->setAlignment(alignment.getAsAlign()); diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -539,6 +539,8 @@ llvm::Function *Fn = CreateGlobalInitOrCleanUpFunction( FTy, FnName.str(), getTypes().arrangeNullaryFunction(), D->getLocation()); + if (getTriple().isOSAIX() && D->getTLSKind() == VarDecl::TLS_None) + addVarTermAssoc(D, Fn); auto *ISA = D->getAttr(); CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr, PerformInit); @@ -862,6 +864,10 @@ for (; I < PrioE; ++I) LocalCXXGlobalInits.push_back(I->second); + if (getTriple().isOSAIX()) { + auto GetElem = [](auto &V, unsigned i) { return V[i]; }; + updateAssociatedFunc(VFInitTermAssoc, LocalCXXGlobalInits, GetElem, Fn); + } CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, LocalCXXGlobalInits); AddGlobalCtor(Fn, Priority); } @@ -894,6 +900,10 @@ llvm::Twine("_GLOBAL__sub_I_", getTransformedFileName(getModule())), FI); + if (getTriple().isOSAIX()) { + auto GetElem = [](auto &V, unsigned i) { return V[i]; }; + updateAssociatedFunc(VFInitTermAssoc, ModuleInits, GetElem, Fn); + } CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, ModuleInits); AddGlobalCtor(Fn); @@ -920,6 +930,39 @@ ModuleInits.clear(); } +void CodeGenModule::EmitAssociatedMetadata() { + auto AddMeta = [this](auto &Assoc, auto &LA) { + for (auto I = Assoc.begin(), E = Assoc.end(); I != E;) { + llvm::SmallVector Metas; + auto Src = I->first; + + for (; I < E && I->first == Src; ++I) + Metas.push_back(llvm::ValueAsMetadata::get(I->second)); + + llvm::MDNode *MD = llvm::MDNode::get(getLLVMContext(), Metas); + if (auto *GO = dyn_cast(LA(Src))) + GO->addMetadata(llvm::LLVMContext::MD_associated, *MD); + } + }; + // Generate dtor to term .ref + auto LM1 = [](llvm::Function *C) { return C; }; + AddMeta(FFDtorTermAssoc, LM1); + + // Generate var to init/term .ref + auto LM2 = [this](const Decl *C) { + assert((VarsWithInitTerm.find(C) != VarsWithInitTerm.end()) && + "EmitAssociatedMetadata does not have var info"); + return VarsWithInitTerm[C]; + }; + llvm::array_pod_sort(VFInitTermAssoc.begin(), VFInitTermAssoc.end()); + AddMeta(VFInitTermAssoc, LM2); + + // Cleanup + VFInitTermAssoc.clear(); + FFDtorTermAssoc.clear(); + VarsWithInitTerm.clear(); +} + void CodeGenModule::EmitCXXGlobalCleanUpFunc() { if (CXXGlobalDtorsOrStermFinalizers.empty() && PrioritizedCXXStermFinalizers.empty()) @@ -955,6 +998,13 @@ DtorFn.getCallee(), nullptr); } + if (getTriple().isOSAIX()) { + auto GetElem = [](auto &V, unsigned i) { return std::get<1>(V[i]); }; + updateAssociatedFunc(VFInitTermAssoc, LocalCXXStermFinalizers, GetElem, + Fn); + updateAssociatedFunc(FFDtorTermAssoc, LocalCXXStermFinalizers, GetElem, + Fn); + } CodeGenFunction(*this).GenerateCXXGlobalCleanUpFunc( Fn, LocalCXXStermFinalizers); AddGlobalDtor(Fn, Priority); @@ -969,6 +1019,13 @@ llvm::Function *Fn = CreateGlobalInitOrCleanUpFunction(FTy, "_GLOBAL__D_a", FI); + if (getTriple().isOSAIX()) { + auto GetElem = [](auto &V, unsigned i) { return std::get<1>(V[i]); }; + updateAssociatedFunc(VFInitTermAssoc, CXXGlobalDtorsOrStermFinalizers, + GetElem, Fn); + updateAssociatedFunc(FFDtorTermAssoc, CXXGlobalDtorsOrStermFinalizers, + GetElem, Fn); + } CodeGenFunction(*this).GenerateCXXGlobalCleanUpFunc( Fn, CXXGlobalDtorsOrStermFinalizers); AddGlobalDtor(Fn); diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -482,6 +482,15 @@ /// init_priority attribute. SmallVector PrioritizedCXXGlobalInits; + /// To support `-bcdtors:csect` on AIX, we are adding .ref pseudo-op to + /// associate variable with init/term functions, and maintain the dependency + /// between dtor and term functions. + llvm::SmallVector, 8> + VFInitTermAssoc; + llvm::SmallVector, 8> + FFDtorTermAssoc; + llvm::DenseMap VarsWithInitTerm; + /// 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. @@ -626,6 +635,42 @@ const std::string &getModuleNameHash() const { return ModuleNameHash; } + /// As wrapper functions are generated, update .ref association point to the + /// wrapper + template + void updateAssociatedFunc( + llvm::SmallVector, 8> &Assoc, TB &Funcs, + F &GetElem, llvm::Function *Fn) { + for (auto I = Assoc.begin(), E = Assoc.end(); I != E; ++I) { + bool Found = false; + for (unsigned i = 0, e = Funcs.size(); i != e; ++i) + if (I->second == GetElem(Funcs, i)) { + Found = true; + break; + } + + if (Found) + *I = std::make_pair(I->first, Fn); + } + } + + template + void updateInitTermAssociatedFunc(T &Funcs, F &GetElem, llvm::Function *Fn) { + updateAssociatedFunc(VFInitTermAssoc, Funcs, GetElem, Fn); + } + + void addVarTermAssoc(const Decl *Src, llvm::Constant *Target) { + VFInitTermAssoc.push_back(std::make_pair(Src, Target)); + } + + void addDtorTermAssoc(llvm::Function *Src, llvm::Constant *Target) { + FFDtorTermAssoc.push_back(std::make_pair(Src, Target)); + } + + void addVarWithInitTerm(const Decl *Var, llvm::Constant *C) { + VarsWithInitTerm[Var] = C; + } + /// Return a reference to the configured OpenCL runtime. CGOpenCLRuntime &getOpenCLRuntime() { assert(OpenCLRuntime != nullptr); @@ -1655,6 +1700,9 @@ /// Call replaceAllUsesWith on all pairs in GlobalValReplacements. void applyGlobalValReplacements(); + /// Generate associated metadata for static init/term + void EmitAssociatedMetadata(); + void checkAliases(); std::map> DtorsUsingAtExit; diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -555,6 +555,9 @@ EmitCXXGlobalCleanUpFunc(); registerGlobalDtorsWithAtExit(); EmitCXXThreadLocalInitFunc(); + if (getTriple().isOSAIX()) { + EmitAssociatedMetadata(); + } if (ObjCRuntime) if (llvm::Function *ObjCInitFunction = ObjCRuntime->ModuleInitFunction()) AddGlobalCtor(ObjCInitFunction); @@ -5079,8 +5082,11 @@ maybeSetTrivialComdat(*D, *GV); // Emit the initializer function if necessary. - if (NeedsGlobalCtor || NeedsGlobalDtor) + if (NeedsGlobalCtor || NeedsGlobalDtor) { EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor); + if (getTriple().isOSAIX() && D->getTLSKind() == VarDecl::TLS_None) + addVarWithInitTerm(D, GV); + } SanitizerMD->reportGlobal(GV, *D, NeedsGlobalCtor); diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -4821,6 +4821,11 @@ llvm::Function *StermFinalizer = CGM.CreateGlobalInitOrCleanUpFunction( FTy, FnName.str(), FI, D.getLocation()); + if (CGM.getTriple().isOSAIX() && D.getTLSKind() == VarDecl::TLS_None) { + CGM.addVarTermAssoc(&D, StermFinalizer); + CGM.addDtorTermAssoc(dtorStub, StermFinalizer); + } + CodeGenFunction CGF(CGM); CGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, StermFinalizer, FI, diff --git a/clang/test/CodeGen/PowerPC/aix-init-ref-null.cpp b/clang/test/CodeGen/PowerPC/aix-init-ref-null.cpp --- a/clang/test/CodeGen/PowerPC/aix-init-ref-null.cpp +++ b/clang/test/CodeGen/PowerPC/aix-init-ref-null.cpp @@ -18,7 +18,6 @@ ext base_rview; -// CHECK: @base_rview = local_unnamed_addr global %struct.ext zeroinitializer, align [[ALIGN:[0-9]+]] -// XFAIL-CHECK: @base_rview = local_unnamed_addr global %struct.ext zeroinitializer, align [[ALIGN:[0-9]+]], !associated ![[ASSOC0:[0-9]+]] +// CHECK: @base_rview = local_unnamed_addr global %struct.ext zeroinitializer, align [[ALIGN:[0-9]+]], !associated ![[ASSOC0:[0-9]+]] // CHECK: @llvm.global_ctors = appending global [0 x { i32, ptr, ptr }] zeroinitializer -// XFAIL-CHECK: ![[ASSOC0]] = distinct !{null} +// CHECK: ![[ASSOC0]] = distinct !{null} diff --git a/clang/test/CodeGen/PowerPC/aix-ref-static-var.cpp b/clang/test/CodeGen/PowerPC/aix-ref-static-var.cpp --- a/clang/test/CodeGen/PowerPC/aix-ref-static-var.cpp +++ b/clang/test/CodeGen/PowerPC/aix-ref-static-var.cpp @@ -7,8 +7,6 @@ static S s; } -// CHECK: @_ZZ1fvE1s = internal global %struct.S zeroinitializer, align [[ALIGN:[0-9]+]] -// XFAIL-CHECK: @_ZZ1fvE1s = internal global %struct.S zeroinitializer, align [[ALIGN:[0-9]+]], !associated ![[ASSOC0:[0-9]+]] -// CHECK: define internal void @__dtor__ZZ1fvE1s() [[ATTR:#[0-9]+]] { -// XFAIL-CHECK: define internal void @__dtor__ZZ1fvE1s() [[ATTR:#[0-9]+]] !associated ![[ASSOC0:[0-9]+]] { -// XFAIL-CHECK: ![[ASSOC0]] = !{ptr @_GLOBAL__D_a} +// CHECK: @_ZZ1fvE1s = internal global %struct.S zeroinitializer, align [[ALIGN:[0-9]+]], !associated ![[ASSOC0:[0-9]+]] +// CHECK: define internal void @__dtor__ZZ1fvE1s() [[ATTR:#[0-9]+]] !associated ![[ASSOC0:[0-9]+]] { +// CHECK: ![[ASSOC0]] = !{ptr @_GLOBAL__D_a} diff --git a/clang/test/CodeGenCXX/aix-static-init-debug-info.cpp b/clang/test/CodeGenCXX/aix-static-init-debug-info.cpp --- a/clang/test/CodeGenCXX/aix-static-init-debug-info.cpp +++ b/clang/test/CodeGenCXX/aix-static-init-debug-info.cpp @@ -13,7 +13,7 @@ X v; -// XFAIL-CHECK: @v = global %struct.X zeroinitializer, align {{[0-9]+}}, !dbg !{{[0-9]+}}, !associated ![[ASSOC1:[0-9]+]] +// CHECK: @v = global %struct.X zeroinitializer, align {{[0-9]+}}, !dbg !{{[0-9]+}}, !associated ![[ASSOC1:[0-9]+]] // CHECK: define internal void @__cxx_global_var_init() [[ATTR:#[0-9]+]] !dbg ![[DBGVAR16:[0-9]+]] { // CHECK: entry: @@ -22,8 +22,7 @@ // CHECK: ret void, !dbg ![[DBGVAR19]] // CHECK: } -// CHECK: define internal void @__dtor_v() [[ATTR:#[0-9]+]] !dbg ![[DBGVAR20:[0-9]+]] { -// XFAIL-CHECK: define internal void @__dtor_v() [[ATTR:#[0-9]+]] !dbg ![[DBGVAR20:[0-9]+]] !associated ![[ASSOC2:[0-9]+]] { +// CHECK: define internal void @__dtor_v() [[ATTR:#[0-9]+]] !dbg ![[DBGVAR20:[0-9]+]] !associated ![[ASSOC2:[0-9]+]] { // CHECK: entry: // CHECK: call void @_ZN1XD1Ev(ptr @v), !dbg ![[DBGVAR21b:[0-9]+]] // CHECK: ret void, !dbg ![[DBGVAR21:[0-9]+]] @@ -55,12 +54,12 @@ // CHECK: ret void // CHECK: } -// XFAIL-CHECK: ![[ASSOC1]] = !{ptr @{{_GLOBAL__sub_I__|_GLOBAL__D_a}}, ptr @{{_GLOBAL__sub_I__|_GLOBAL__D_a}}} +// CHECK: ![[ASSOC1]] = !{ptr @{{_GLOBAL__sub_I__|_GLOBAL__D_a}}, ptr @{{_GLOBAL__sub_I__|_GLOBAL__D_a}}} // CHECK: ![[DBGVAR16]] = distinct !DISubprogram(name: "__cxx_global_var_init", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, type: !{{[0-9]+}}, flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !{{[0-9]+}}, retainedNodes: !{{[0-9]+}}) // CHECK: ![[DBGVAR19]] = !DILocation(line: 14, column: 3, scope: ![[DBGVAR16]]) // CHECK: ![[DBGVAR19b]] = !DILocation(line: 0, scope: ![[DBGVAR16]]) // CHECK: ![[DBGVAR20]] = distinct !DISubprogram(name: "__dtor_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]+}}) -// XFAIL-CHECK: ![[ASSOC2]] = !{ptr @_GLOBAL__D_a} +// CHECK: ![[ASSOC2]] = !{ptr @_GLOBAL__D_a} // CHECK: ![[DBGVAR21b]] = !DILocation(line: 0, scope: ![[DBGVAR20]]) // 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]+}}) diff --git a/clang/test/CodeGenCXX/aix-static-init-temp-spec-and-inline-var.cpp b/clang/test/CodeGenCXX/aix-static-init-temp-spec-and-inline-var.cpp --- a/clang/test/CodeGenCXX/aix-static-init-temp-spec-and-inline-var.cpp +++ b/clang/test/CodeGenCXX/aix-static-init-temp-spec-and-inline-var.cpp @@ -44,13 +44,13 @@ A A::instance = bar(); } // namespace test2 -// XFAIL-CHECK: @_ZN5test12t0E = global %"struct.test1::Test1" zeroinitializer, align {{[0-9]+}}, !associated ![[ASSOC0:[0-9]+]] -// XFAIL-CHECK: @_ZN5test12t2E = linkonce_odr global %"struct.test1::Test1" zeroinitializer, align {{[0-9]+}}, !associated ![[ASSOC1:[0-9]+]] +// CHECK: @_ZN5test12t0E = global %"struct.test1::Test1" zeroinitializer, align {{[0-9]+}}, !associated ![[ASSOC0:[0-9]+]] +// CHECK: @_ZN5test12t2E = linkonce_odr global %"struct.test1::Test1" zeroinitializer, align {{[0-9]+}}, !associated ![[ASSOC1:[0-9]+]] // CHECK: @_ZGVN5test12t2E = linkonce_odr global i64 0, align 8 -// XFAIL-CHECK: @_ZN5test12t1IiEE = linkonce_odr global %"struct.test1::Test1" zeroinitializer, align {{[0-9]+}}, !associated ![[ASSOC2:[0-9]+]] -// XFAIL-CHECK: @_ZN5test21AIvE8instanceE = weak_odr global %"struct.test2::A" zeroinitializer, align {{[0-9]+}}, !associated ![[ASSOC3:[0-9]+]] +// CHECK: @_ZN5test12t1IiEE = linkonce_odr global %"struct.test1::Test1" zeroinitializer, align {{[0-9]+}}, !associated ![[ASSOC2:[0-9]+]] +// CHECK: @_ZN5test21AIvE8instanceE = weak_odr global %"struct.test2::A" zeroinitializer, align {{[0-9]+}}, !associated ![[ASSOC3:[0-9]+]] // CHECK: @_ZGVN5test21AIvE8instanceE = weak_odr global i64 0, align 8 -// XFAIL-CHECK: @_ZN5test21AIiE8instanceE = global %"struct.test2::A.0" zeroinitializer, align {{[0-9]+}}, !associated ![[ASSOC0:[0-9]+]] +// CHECK: @_ZN5test21AIiE8instanceE = global %"struct.test2::A.0" zeroinitializer, align {{[0-9]+}}, !associated ![[ASSOC0:[0-9]+]] // CHECK: @_ZGVN5test12t1IiEE = linkonce_odr global i64 0, align 8 // CHECK: @llvm.global_ctors = appending global [4 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @__cxx_global_var_init.1, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @__cxx_global_var_init.2, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @__cxx_global_var_init.4, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I__, ptr null }] // CHECK: @llvm.global_dtors = appending global [4 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @__finalize__ZN5test12t2E, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @__finalize__ZN5test21AIvE8instanceE, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @__finalize__ZN5test12t1IiEE, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__D_a, ptr null }] @@ -63,8 +63,7 @@ // CHECK: ret void // CHECK: } -// CHECK: define internal void @__dtor__ZN5test12t0E() [[ATTR:#[0-9]+]] { -// XFAIL-CHECK: define internal void @__dtor__ZN5test12t0E() [[ATTR:#[0-9]+]] !associated ![[ASSOC4:[0-9]+]] { +// CHECK: define internal void @__dtor__ZN5test12t0E() [[ATTR:#[0-9]+]] !associated ![[ASSOC4:[0-9]+]] { // CHECK: entry: // CHECK: call void @_ZN5test15Test1D1Ev(ptr @_ZN5test12t0E) // CHECK: ret void @@ -106,8 +105,7 @@ // CHECK: ret void // CHECK: } -// CHECK: define internal void @__dtor__ZN5test12t2E() [[ATTR:#[0-9]+]] { -// XFAIL-CHECK: define internal void @__dtor__ZN5test12t2E() [[ATTR:#[0-9]+]] !associated ![[ASSOC5:[0-9]+]] { +// CHECK: define internal void @__dtor__ZN5test12t2E() [[ATTR:#[0-9]+]] !associated ![[ASSOC5:[0-9]+]] { // CHECK: entry: // CHECK: call void @_ZN5test15Test1D1Ev(ptr @_ZN5test12t2E) // CHECK: ret void @@ -143,8 +141,7 @@ // CHECK: ret void // CHECK: } -// CHECK: define internal void @__dtor__ZN5test21AIvE8instanceE() [[ATTR:#[0-9]+]] { -// XFAIL-CHECK: define internal void @__dtor__ZN5test21AIvE8instanceE() [[ATTR:#[0-9]+]] !associated ![[ASSOC6:[0-9]+]] { +// CHECK: define internal void @__dtor__ZN5test21AIvE8instanceE() [[ATTR:#[0-9]+]] !associated ![[ASSOC6:[0-9]+]] { // CHECK: entry: // CHECK: call void @_ZN5test21AIvED1Ev(ptr @_ZN5test21AIvE8instanceE) // CHECK: ret void @@ -171,8 +168,7 @@ // CHECK: ret void // CHECK: } -// CHECK: define internal void @__dtor__ZN5test21AIiE8instanceE() [[ATTR:#[0-9]+]] { -// XFAIL-CHECK: define internal void @__dtor__ZN5test21AIiE8instanceE() [[ATTR:#[0-9]+]] !associated ![[ASSOC4:[0-9]+]] { +// CHECK: define internal void @__dtor__ZN5test21AIiE8instanceE() [[ATTR:#[0-9]+]] !associated ![[ASSOC4:[0-9]+]] { // CHECK: entry: // CHECK: call void @_ZN5test21AIiED1Ev(ptr @_ZN5test21AIiE8instanceE) // CHECK: ret void @@ -209,8 +205,7 @@ // CHECK: ret void // CHECK: } -// CHECK: define internal void @__dtor__ZN5test12t1IiEE() [[ATTR:#[0-9]+]] { -// XFAIL-CHECK: define internal void @__dtor__ZN5test12t1IiEE() [[ATTR:#[0-9]+]] !associated ![[ASSOC7:[0-9]+]] { +// CHECK: define internal void @__dtor__ZN5test12t1IiEE() [[ATTR:#[0-9]+]] !associated ![[ASSOC7:[0-9]+]] { // CHECK: entry: // CHECK: call void @_ZN5test15Test1D1Ev(ptr @_ZN5test12t1IiEE) // CHECK: ret void @@ -244,11 +239,11 @@ // CHECK: ret void // CHECK: } -// XFAIL-CHECK: ![[ASSOC0]] = !{ptr @{{_GLOBAL__sub_I__|_GLOBAL__D_a}}, ptr @{{_GLOBAL__sub_I__|_GLOBAL__D_a}}} -// XFAIL-CHECK: ![[ASSOC1]] = !{ptr @{{__cxx_global_var_init.1|__finalize__ZN5test12t2E}}, ptr @{{__cxx_global_var_init.1|__finalize__ZN5test12t2E}}} -// XFAIL-CHECK: ![[ASSOC2]] = !{ptr @{{__cxx_global_var_init.4|__finalize__ZN5test12t1IiEE}}, ptr @{{__cxx_global_var_init.4|__finalize__ZN5test12t1IiEE}}} -// XFAIL-CHECK: ![[ASSOC3]] = !{ptr @{{__finalize__ZN5test21AIvE8instanceE|__cxx_global_var_init.2}}, ptr @{{__finalize__ZN5test21AIvE8instanceE|__cxx_global_var_init.2}}} -// XFAIL-CHECK: ![[ASSOC4]] = !{ptr @_GLOBAL__D_a} -// XFAIL-CHECK: ![[ASSOC5]] = !{ptr @__finalize__ZN5test12t2E} -// XFAIL-CHECK: ![[ASSOC6]] = !{ptr @__finalize__ZN5test21AIvE8instanceE} -// XFAIL-CHECK: ![[ASSOC7]] = !{ptr @__finalize__ZN5test12t1IiEE} +// CHECK: ![[ASSOC0]] = !{ptr @{{_GLOBAL__sub_I__|_GLOBAL__D_a}}, ptr @{{_GLOBAL__sub_I__|_GLOBAL__D_a}}} +// CHECK: ![[ASSOC1]] = !{ptr @{{__cxx_global_var_init.1|__finalize__ZN5test12t2E}}, ptr @{{__cxx_global_var_init.1|__finalize__ZN5test12t2E}}} +// CHECK: ![[ASSOC2]] = !{ptr @{{__cxx_global_var_init.4|__finalize__ZN5test12t1IiEE}}, ptr @{{__cxx_global_var_init.4|__finalize__ZN5test12t1IiEE}}} +// CHECK: ![[ASSOC3]] = !{ptr @{{__finalize__ZN5test21AIvE8instanceE|__cxx_global_var_init.2}}, ptr @{{__finalize__ZN5test21AIvE8instanceE|__cxx_global_var_init.2}}} +// CHECK: ![[ASSOC4]] = !{ptr @_GLOBAL__D_a} +// CHECK: ![[ASSOC5]] = !{ptr @__finalize__ZN5test12t2E} +// CHECK: ![[ASSOC6]] = !{ptr @__finalize__ZN5test21AIvE8instanceE} +// CHECK: ![[ASSOC7]] = !{ptr @__finalize__ZN5test12t1IiEE} diff --git a/clang/test/CodeGenCXX/aix-static-init.cpp b/clang/test/CodeGenCXX/aix-static-init.cpp --- a/clang/test/CodeGenCXX/aix-static-init.cpp +++ b/clang/test/CodeGenCXX/aix-static-init.cpp @@ -38,10 +38,10 @@ } } // namespace test4 -// XFAIL-CHECK: @_ZN5test12t1E = global %"struct.test1::Test1" zeroinitializer, align {{[0-9]+}}, !associated ![[ASSOC0:[0-9]+]] -// XFAIL-CHECK: @_ZN5test12t2E = global %"struct.test1::Test1" zeroinitializer, align {{[0-9]+}}, !associated ![[ASSOC0:[0-9]+]] -// XFAIL-CHECK: @_ZN5test21xE = global i32 0, align {{[0-9]+}}, !associated ![[ASSOC1:[0-9]+]] -// XFAIL-CHECK: @_ZN5test31tE = global %"struct.test3::Test3" undef, align {{[0-9]+}}, !associated ![[ASSOC0:[0-9]+]] +// CHECK: @_ZN5test12t1E = global %"struct.test1::Test1" zeroinitializer, align {{[0-9]+}}, !associated ![[ASSOC0:[0-9]+]] +// CHECK: @_ZN5test12t2E = global %"struct.test1::Test1" zeroinitializer, align {{[0-9]+}}, !associated ![[ASSOC0:[0-9]+]] +// CHECK: @_ZN5test21xE = global i32 0, align {{[0-9]+}}, !associated ![[ASSOC1:[0-9]+]] +// CHECK: @_ZN5test31tE = global %"struct.test3::Test3" undef, align {{[0-9]+}}, !associated ![[ASSOC0:[0-9]+]] // CHECK: @_ZGVZN5test41fEvE11staticLocal = internal global i64 0, align 8 // CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I__, ptr null }] // CHECK: @llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__D_a, ptr null }] @@ -53,8 +53,7 @@ // CHECK: ret void // CHECK: } -// CHECK: define internal void @__dtor__ZN5test12t1E() [[ATTR:#[0-9]+]] { -// XFAIL-CHECK: define internal void @__dtor__ZN5test12t1E() [[ATTR:#[0-9]+]] !associated ![[ASSOC2:[0-9]+]] { +// CHECK: define internal void @__dtor__ZN5test12t1E() [[ATTR:#[0-9]+]] !associated ![[ASSOC2:[0-9]+]] { // CHECK: entry: // CHECK: call void @_ZN5test15Test1D1Ev(ptr @_ZN5test12t1E) // CHECK: ret void @@ -85,8 +84,7 @@ // CHECK: ret void // CHECK: } -// CHECK: define internal void @__dtor__ZN5test12t2E() [[ATTR:#[0-9]+]] { -// XFAIL-CHECK: define internal void @__dtor__ZN5test12t2E() [[ATTR:#[0-9]+]] !associated ![[ASSOC2:[0-9]+]] { +// CHECK: define internal void @__dtor__ZN5test12t2E() [[ATTR:#[0-9]+]] !associated ![[ASSOC2:[0-9]+]] { // CHECK: entry: // CHECK: call void @_ZN5test15Test1D1Ev(ptr @_ZN5test12t2E) // CHECK: ret void @@ -120,8 +118,7 @@ // CHECK: ret void // CHECK: } -// CHECK: define internal void @__dtor__ZN5test31tE() [[ATTR:#[0-9]+]] { -// XFAIL-CHECK: define internal void @__dtor__ZN5test31tE() [[ATTR:#[0-9]+]] !associated ![[ASSOC2:[0-9]+]] { +// CHECK: define internal void @__dtor__ZN5test31tE() [[ATTR:#[0-9]+]] !associated ![[ASSOC2:[0-9]+]] { // CHECK: entry: // CHECK: call void @_ZN5test35Test3D1Ev(ptr @_ZN5test31tE) // CHECK: ret void @@ -162,8 +159,7 @@ // CHECK: ret void // CHECK: } -// CHECK: define internal void @__dtor__ZZN5test41fEvE11staticLocal() [[ATTR:#[0-9]+]] { -// XFAIL-CHECK: define internal void @__dtor__ZZN5test41fEvE11staticLocal() [[ATTR:#[0-9]+]] !associated ![[ASSOC2:[0-9]+]] { +// CHECK: define internal void @__dtor__ZZN5test41fEvE11staticLocal() [[ATTR:#[0-9]+]] !associated ![[ASSOC2:[0-9]+]] { // CHECK: entry: // CHECK: call void @_ZN5test45Test4D1Ev(ptr @_ZZN5test41fEvE11staticLocal) // CHECK: ret void @@ -201,6 +197,6 @@ // CHECK: ret void // CHECK: } -// XFAIL-CHECK: ![[ASSOC0]] = !{ptr @{{_GLOBAL__sub_I__|_GLOBAL__D_a}}, ptr @{{_GLOBAL__sub_I__|_GLOBAL__D_a}}} -// XFAIL-CHECK: ![[ASSOC1]] = !{ptr @_GLOBAL__sub_I__} -// XFAIL-CHECK: ![[ASSOC2]] = !{ptr @_GLOBAL__D_a} +// CHECK: ![[ASSOC0]] = !{ptr @{{_GLOBAL__sub_I__|_GLOBAL__D_a}}, ptr @{{_GLOBAL__sub_I__|_GLOBAL__D_a}}} +// CHECK: ![[ASSOC1]] = !{ptr @_GLOBAL__sub_I__} +// CHECK: ![[ASSOC2]] = !{ptr @_GLOBAL__D_a} diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -7330,11 +7330,12 @@ @b = internal global i32 2, comdat $a, section "abc", !associated !0 !0 = !{ptr @a} -It does not have any effect on non-ELF targets. Non-ELF target may use -``associated`` metadata for its own purpose. For example, on AIX XCOFF target, -the ``associated`` metadata may indicate connection among static variables -(static global variable, static class member etc.) and static init/term -functions. This kind of association can be one-to-many. +On AIX XCOFF target, the ``associated`` metadata indicates connection among +static variables (static global variable, static class member etc.) and static +init/term functions. This metadata lowers to ``.ref`` assembler pseudo- +operation which prevents discarding of the functions in linker GC. + +It does not have any effect on other non-ELF targets. '``prof``' Metadata ^^^^^^^^^^^^^^^^^^^