tingwang updated this revision to Diff 504031. tingwang added a comment. Herald added a subscriber: hiraditya.
Rebase and update patch (1) Update verifier check on associated metadata to allow multiple operands for AIX. (2) Update test cases to use opaque pointer. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D125095/new/ https://reviews.llvm.org/D125095 Files: clang/lib/CodeGen/CGDecl.cpp clang/lib/CodeGen/CGDeclCXX.cpp clang/lib/CodeGen/CodeGenModule.cpp clang/lib/CodeGen/CodeGenModule.h clang/lib/CodeGen/ItaniumCXXABI.cpp clang/test/CodeGen/PowerPC/aix-init-ref-null.cpp clang/test/CodeGen/PowerPC/aix-ref-static-var.cpp clang/test/CodeGenCXX/aix-static-init-debug-info.cpp clang/test/CodeGenCXX/aix-static-init-temp-spec-and-inline-var.cpp clang/test/CodeGenCXX/aix-static-init.cpp llvm/docs/LangRef.rst llvm/lib/IR/Verifier.cpp
Index: llvm/docs/LangRef.rst =================================================================== --- llvm/docs/LangRef.rst +++ llvm/docs/LangRef.rst @@ -7329,6 +7329,10 @@ @b = internal global i32 2, comdat $a, section "abc", !associated !0 !0 = !{ptr @a} +On 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. '``prof``' Metadata ^^^^^^^^^^^^^^^^^^^ Index: clang/test/CodeGenCXX/aix-static-init.cpp =================================================================== --- clang/test/CodeGenCXX/aix-static-init.cpp +++ clang/test/CodeGenCXX/aix-static-init.cpp @@ -38,6 +38,10 @@ } } // namespace test4 +// 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 }] @@ -49,7 +53,7 @@ // CHECK: ret void // CHECK: } -// CHECK: define internal void @__dtor__ZN5test12t1E() [[ATTR:#[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 @@ -80,7 +84,7 @@ // CHECK: ret void // CHECK: } -// CHECK: define internal void @__dtor__ZN5test12t2E() [[ATTR:#[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 @@ -114,7 +118,7 @@ // CHECK: ret void // CHECK: } -// CHECK: define internal void @__dtor__ZN5test31tE() [[ATTR:#[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 @@ -155,7 +159,7 @@ // CHECK: ret void // CHECK: } -// CHECK: define internal void @__dtor__ZZN5test41fEvE11staticLocal() [[ATTR:#[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 @@ -192,3 +196,7 @@ // CHECK: call void @__finalize__ZN5test12t1E() // CHECK: ret void // CHECK: } + +// 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} Index: clang/test/CodeGenCXX/aix-static-init-temp-spec-and-inline-var.cpp =================================================================== --- clang/test/CodeGenCXX/aix-static-init-temp-spec-and-inline-var.cpp +++ clang/test/CodeGenCXX/aix-static-init-temp-spec-and-inline-var.cpp @@ -44,8 +44,13 @@ A<int> A<int>::instance = bar(); } // namespace test2 +// 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 +// 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 +// 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 }] @@ -58,7 +63,7 @@ // CHECK: ret void // CHECK: } -// CHECK: define internal void @__dtor__ZN5test12t0E() [[ATTR:#[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 @@ -100,7 +105,7 @@ // CHECK: ret void // CHECK: } -// CHECK: define internal void @__dtor__ZN5test12t2E() [[ATTR:#[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 @@ -136,7 +141,7 @@ // CHECK: ret void // CHECK: } -// CHECK: define internal void @__dtor__ZN5test21AIvE8instanceE() [[ATTR:#[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 @@ -163,7 +168,7 @@ // CHECK: ret void // CHECK: } -// CHECK: define internal void @__dtor__ZN5test21AIiE8instanceE() [[ATTR:#[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 @@ -200,7 +205,7 @@ // CHECK: ret void // CHECK: } -// CHECK: define internal void @__dtor__ZN5test12t1IiEE() [[ATTR:#[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 @@ -233,3 +238,12 @@ // CHECK: call void @__finalize__ZN5test12t0E() // CHECK: ret void // CHECK: } + +// 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} 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 @@ -13,6 +13,8 @@ X v; +// 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: // CHECK: call void @_ZN1XC1Ev(ptr {{[^,]*}} @v), !dbg ![[DBGVAR19:[0-9]+]] @@ -20,7 +22,7 @@ // CHECK: ret void, !dbg ![[DBGVAR19]] // CHECK: } -// CHECK: define internal void @__dtor_v() [[ATTR:#[0-9]+]] !dbg ![[DBGVAR20:[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]+]] @@ -52,10 +54,12 @@ // CHECK: ret void // CHECK: } +// 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]+}}) +// 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]+}}) Index: clang/test/CodeGen/PowerPC/aix-ref-static-var.cpp =================================================================== --- /dev/null +++ clang/test/CodeGen/PowerPC/aix-ref-static-var.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -emit-llvm -x c++ < %s | FileCheck %s + +struct S { + ~S(); +}; +void f() { + static S s; +} + +// 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} Index: clang/test/CodeGen/PowerPC/aix-init-ref-null.cpp =================================================================== --- /dev/null +++ clang/test/CodeGen/PowerPC/aix-init-ref-null.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -emit-llvm -O3 -x c++ < %s | FileCheck %s + +// Global Ctors present at -O0, removed by -O3 +typedef enum { + A, B +} E; + +class base { +protected: + base(E v): m(v) { } +private: + E m; +}; + +struct ext: base { + ext():base(A){} +}; + +ext base_rview; + +// 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 +// CHECK: ![[ASSOC0]] = distinct !{null} Index: clang/lib/CodeGen/ItaniumCXXABI.cpp =================================================================== --- clang/lib/CodeGen/ItaniumCXXABI.cpp +++ 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, Index: clang/lib/CodeGen/CodeGenModule.h =================================================================== --- clang/lib/CodeGen/CodeGenModule.h +++ clang/lib/CodeGen/CodeGenModule.h @@ -482,6 +482,15 @@ /// init_priority attribute. SmallVector<GlobalInitData, 8> 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<std::pair<const Decl *, llvm::Constant *>, 8> + VFInitTermAssoc; + llvm::SmallVector<std::pair<llvm::Function *, llvm::Constant *>, 8> + FFDtorTermAssoc; + llvm::DenseMap<const Decl *, llvm::Constant *> 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 <typename TA, typename TB, typename F> + void updateAssociatedFunc( + llvm::SmallVector<std::pair<TA, llvm::Constant *>, 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 <typename T, typename F> + 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<int, llvm::TinyPtrVector<llvm::Function *>> DtorsUsingAtExit; Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ 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); @@ -5075,8 +5078,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); Index: clang/lib/CodeGen/CGDeclCXX.cpp =================================================================== --- clang/lib/CodeGen/CGDeclCXX.cpp +++ 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<InitSegAttr>(); 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<llvm::Metadata *, 2> 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<llvm::GlobalObject>(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); Index: llvm/lib/IR/Verifier.cpp =================================================================== --- llvm/lib/IR/Verifier.cpp +++ llvm/lib/IR/Verifier.cpp @@ -661,11 +661,17 @@ if (const MDNode *Associated = GO->getMetadata(LLVMContext::MD_associated)) { - Check(Associated->getNumOperands() == 1, + // Associated metadata is used by AIX to indicate connection among static + // variables and static init/term functions, there can be multiple + // operands. + Check(Associated->getNumOperands() == 1 || TT.isOSAIX(), "associated metadata must have one operand", &GV, Associated); auto CheckAssocOperand = [this, &GV, GO, Associated](const Metadata *Op) { - Check(Op, "associated metadata must have a global value", GO, - Associated); + Check(Op || TT.isOSAIX(), + "associated metadata must have a global value", GO, Associated); + // On AIX associated global value could be optimized away. + if (!Op) + return; const auto *VM = dyn_cast_or_null<ValueAsMetadata>(Op); Check(VM, "associated metadata must be ValueAsMetadata", GO, Index: clang/lib/CodeGen/CGDecl.cpp =================================================================== --- clang/lib/CodeGen/CGDecl.cpp +++ clang/lib/CodeGen/CGDecl.cpp @@ -442,8 +442,11 @@ bool isCudaSharedVar = getLangOpts().CUDA && getLangOpts().CUDAIsDevice && D.hasAttr<CUDASharedAttr>(); // 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());
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits