tingwang updated this revision to Diff 442419.
tingwang added a comment.

Update according to comments:
(1) Merged cleanupAssoc() into genAssocMeta(), and renamed genAssocMeta() to 
EmitAssociatedMetadata().
(2) Removed "-debug-info-kind=limited" from all test cases.


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/CodeGen/PowerPC/aix-ref-tls_init.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

Index: llvm/docs/LangRef.rst
===================================================================
--- llvm/docs/LangRef.rst
+++ llvm/docs/LangRef.rst
@@ -7091,6 +7091,10 @@
     @b = internal global i32 2, comdat $a, section "abc", !associated !0
     !0 = !{i32* @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, 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 }]
@@ -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(%"struct.test1::Test1"* @_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(%"struct.test1::Test1"* @_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(%"struct.test3::Test3"* @_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(%"struct.test4::Test4"* @_ZZN5test41fEvE11staticLocal)
 // CHECK:   ret void
@@ -192,3 +196,7 @@
 // CHECK:   call void @__finalize__ZN5test12t1E()
 // CHECK:   ret void
 // CHECK: }
+
+// CHECK: ![[ASSOC0]] = !{void ()* @{{_GLOBAL__sub_I__|_GLOBAL__D_a}}, void ()* @{{_GLOBAL__sub_I__|_GLOBAL__D_a}}}
+// CHECK: ![[ASSOC1]] = !{void ()* @_GLOBAL__sub_I__}
+// CHECK: ![[ASSOC2]] = !{void ()* @_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, 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 }]
@@ -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(%"struct.test1::Test1"* @_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(%"struct.test1::Test1"* @_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(%"struct.test2::A"* @_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(%"struct.test2::A.0"* @_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(%"struct.test1::Test1"* @_ZN5test12t1IiEE)
 // CHECK:   ret void
@@ -233,3 +238,12 @@
 // CHECK:   call void @__finalize__ZN5test12t0E()
 // CHECK:   ret void
 // CHECK: }
+
+// CHECK: ![[ASSOC0]] = !{void ()* @{{_GLOBAL__sub_I__|_GLOBAL__D_a}}, void ()* @{{_GLOBAL__sub_I__|_GLOBAL__D_a}}}
+// CHECK: ![[ASSOC1]] = !{void ()* @{{__cxx_global_var_init.1|__finalize__ZN5test12t2E}}, void ()* @{{__cxx_global_var_init.1|__finalize__ZN5test12t2E}}}
+// CHECK: ![[ASSOC2]] = !{void ()* @{{__cxx_global_var_init.4|__finalize__ZN5test12t1IiEE}}, void ()* @{{__cxx_global_var_init.4|__finalize__ZN5test12t1IiEE}}}
+// CHECK: ![[ASSOC3]] = !{void ()* @{{__finalize__ZN5test21AIvE8instanceE|__cxx_global_var_init.2}}, void ()* @{{__finalize__ZN5test21AIvE8instanceE|__cxx_global_var_init.2}}}
+// CHECK: ![[ASSOC4]] = !{void ()* @_GLOBAL__D_a}
+// CHECK: ![[ASSOC5]] = !{void ()* @__finalize__ZN5test12t2E}
+// CHECK: ![[ASSOC6]] = !{void ()* @__finalize__ZN5test21AIvE8instanceE}
+// CHECK: ![[ASSOC7]] = !{void ()* @__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(%struct.X* {{[^,]*}} @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(%struct.X* @v), !dbg ![[DBGVAR21b:[0-9]+]]
 // CHECK:   ret void, !dbg ![[DBGVAR21:[0-9]+]]
@@ -52,10 +54,12 @@
 // CHECK:   ret void
 // CHECK: }
 
+// CHECK: ![[ASSOC1]] = !{void ()* @{{_GLOBAL__sub_I__|_GLOBAL__D_a}}, void ()* @{{_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]] = !{void ()* @_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-tls_init.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/PowerPC/aix-ref-tls_init.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -emit-llvm -x c++ < %s | \
+// RUN:   FileCheck %s
+
+int &f();
+thread_local int &r = f();
+int &g() { return r; }
+
+// CHECK: @r = thread_local global ptr null, align [[ALIGN:[0-9]+]], !associated ![[ASSOC0:[0-9]+]]
+// CHECK: ![[ASSOC0]] = !{ptr @__tls_init}
Index: clang/test/CodeGen/PowerPC/aix-ref-static-var.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/PowerPC/aix-ref-static-var.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -emit-llvm -x c++ < %s | \
+// RUN:   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 | \
+// RUN:   FileCheck %s
+
+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
@@ -2819,6 +2819,12 @@
     InitFunc = CGM.CreateGlobalInitOrCleanUpFunction(FTy, "__tls_init", FI,
                                                      SourceLocation(),
                                                      /*TLS=*/true);
+
+    if (CGM.getTriple().isOSAIX()) {
+      auto GetElem = [](auto &V, unsigned i) { return V[i]; };
+      CGM.updateInitTermAssociatedFunc(OrderedInits, GetElem, InitFunc);
+    }
+
     llvm::GlobalVariable *Guard = new llvm::GlobalVariable(
         CGM.getModule(), CGM.Int8Ty, /*isConstant=*/false,
         llvm::GlobalVariable::InternalLinkage,
@@ -4785,6 +4791,11 @@
   llvm::Function *StermFinalizer = CGM.CreateGlobalInitOrCleanUpFunction(
       FTy, FnName.str(), FI, D.getLocation());
 
+  if (CGM.getTriple().isOSAIX()) {
+    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
@@ -459,6 +459,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.
@@ -597,6 +606,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);
@@ -1615,6 +1660,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
@@ -518,6 +518,9 @@
   EmitCXXGlobalCleanUpFunc();
   registerGlobalDtorsWithAtExit();
   EmitCXXThreadLocalInitFunc();
+  if (getTriple().isOSAIX()) {
+    EmitAssociatedMetadata();
+  }
   if (ObjCRuntime)
     if (llvm::Function *ObjCInitFunction = ObjCRuntime->ModuleInitFunction())
       AddGlobalCtor(ObjCInitFunction);
@@ -4810,8 +4813,11 @@
   maybeSetTrivialComdat(*D, *GV);
 
   // Emit the initializer function if necessary.
-  if (NeedsGlobalCtor || NeedsGlobalDtor)
+  if (NeedsGlobalCtor || NeedsGlobalDtor) {
     EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor);
+    if (getTriple().isOSAIX())
+      addVarWithInitTerm(D, GV);
+  }
 
   SanitizerMD->reportGlobal(GV, *D, NeedsGlobalCtor);
 
Index: clang/lib/CodeGen/CGDeclCXX.cpp
===================================================================
--- clang/lib/CodeGen/CGDeclCXX.cpp
+++ clang/lib/CodeGen/CGDeclCXX.cpp
@@ -538,6 +538,9 @@
   llvm::Function *Fn = CreateGlobalInitOrCleanUpFunction(
       FTy, FnName.str(), getTypes().arrangeNullaryFunction(), D->getLocation());
 
+  if (getTriple().isOSAIX())
+    addVarTermAssoc(D, Fn);
+
   auto *ISA = D->getAttr<InitSegAttr>();
   CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr,
                                                           PerformInit);
@@ -679,6 +682,11 @@
       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);
     }
@@ -695,6 +703,11 @@
       FTy, llvm::Twine("_GLOBAL__sub_I_", getTransformedFileName(getModule())),
       FI);
 
+  if (getTriple().isOSAIX()) {
+    auto GetElem = [](auto &V, unsigned i) { return V[i]; };
+    updateAssociatedFunc(VFInitTermAssoc, CXXGlobalInits, GetElem, Fn);
+  }
+
   CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, CXXGlobalInits);
   AddGlobalCtor(Fn);
 
@@ -721,6 +734,39 @@
   CXXGlobalInits.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())
@@ -756,6 +802,14 @@
                                              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);
@@ -770,6 +824,14 @@
   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: clang/lib/CodeGen/CGDecl.cpp
===================================================================
--- clang/lib/CodeGen/CGDecl.cpp
+++ clang/lib/CodeGen/CGDecl.cpp
@@ -438,8 +438,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())
+      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

Reply via email to