Xiangling_L updated this revision to Diff 283712.
Xiangling_L marked an inline comment as done.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D84534/new/

https://reviews.llvm.org/D84534

Files:
  clang/lib/CodeGen/CGDeclCXX.cpp
  clang/lib/CodeGen/CodeGenModule.h
  clang/lib/CodeGen/ItaniumCXXABI.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
  clang/unittests/CodeGen/IncrementalProcessingTest.cpp
  llvm/include/llvm/CodeGen/AsmPrinter.h
  llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
  llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
  llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
  llvm/test/CodeGen/PowerPC/aix-static-init-default-priority.ll
  llvm/test/CodeGen/PowerPC/aix-static-init-key-object.ll
  llvm/test/CodeGen/PowerPC/aix-static-init-no-unique-module-id.ll
  llvm/test/CodeGen/PowerPC/aix-static-init-non-default-priority.ll

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
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-key-object.ll
===================================================================
--- /dev/null
+++ llvm/test/CodeGen/PowerPC/aix-static-init-key-object.ll
@@ -0,0 +1,12 @@
+; 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
+
+@v = global i8 0
+
+@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @foo, i8* @v}]
+
+define void @foo() {
+  ret void
+}
+
+// CHECK: LLVM ERROR: associated data of XXStructor list is not yet supported on AIX
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/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 <algorithm>
 #include <cassert>
 #include <cstdint>
@@ -153,6 +154,9 @@
   /// linkage for them in AIX.
   SmallPtrSet<MCSymbol *, 8> 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 emitXXStructorList(const DataLayout &DL, const Constant *List,
+                          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<bool>(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<bool>(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,25 @@
   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 +1944,28 @@
   return Ret;
 }
 
+void PPCAIXAsmPrinter::emitXXStructorList(const DataLayout &DL,
+                                          const Constant *List, bool IsCtor) {
+  SmallVector<Structor, 8> Structors;
+  preprocessXXStructorList(DL, List, Structors);
+  if (Structors.empty())
+    return;
+
+  unsigned Index = 0;
+  for (Structor &S : Structors) {
+    if (S.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<Function>(S.Func));
+  }
+}
+
 /// 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/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
===================================================================
--- llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -2115,13 +2115,13 @@
 }
 
 MCSection *TargetLoweringObjectFileXCOFF::getStaticCtorSection(
-    unsigned Priority, const MCSymbol *KeySym) const {
-  report_fatal_error("XCOFF ctor section not yet implemented.");
+	unsigned Priority, const MCSymbol *KeySym) const {
+  report_fatal_error("no static constructor section on AIX");
 }
 
 MCSection *TargetLoweringObjectFileXCOFF::getStaticDtorSection(
-    unsigned Priority, const MCSymbol *KeySym) const {
-  report_fatal_error("XCOFF dtor section not yet implemented.");
+	unsigned Priority, const MCSymbol *KeySym) const {
+  report_fatal_error("no static destructor section on AIX");
 }
 
 const MCExpr *TargetLoweringObjectFileXCOFF::lowerRelativeReference(
Index: llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
===================================================================
--- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -2098,47 +2098,50 @@
   }
 }
 
-namespace {
-
-struct Structor {
-  int Priority = 0;
-  Constant *Func = nullptr;
-  GlobalValue *ComdatKey = nullptr;
-
-  Structor() = default;
-};
-
-} // end anonymous namespace
-
-/// EmitXXStructorList - Emit the ctor or dtor list taking into account the init
-/// priority.
-void AsmPrinter::emitXXStructorList(const DataLayout &DL, const Constant *List,
-                                    bool isCtor) {
-  // Should be an array of '{ i32, void ()*, i8* }' structs.  The first value is the
-  // init priority.
-  if (!isa<ConstantArray>(List)) return;
+void AsmPrinter::preprocessXXStructorList(const DataLayout &DL,
+                                          const Constant *List,
+                                          SmallVector<Structor, 8> &Structors) {
+  // Should be an array of '{ i32, void ()*, i8* }' structs.  The first value is
+  // the init priority.
+  if (!isa<ConstantArray>(List))
+    return;
 
   // Gather the structors in a form that's convenient for sorting by priority.
-  SmallVector<Structor, 8> Structors;
   for (Value *O : cast<ConstantArray>(List)->operands()) {
     auto *CS = cast<ConstantStruct>(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<ConstantInt>(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()) {
+      if (TM.getTargetTriple().isOSAIX())
+        llvm::report_fatal_error(
+            "associated data of XXStructor list is not yet supported on AIX");
       S.ComdatKey =
           dyn_cast<GlobalValue>(CS->getOperand(2)->stripPointerCasts());
+    }
   }
 
   // Emit the function pointers in the target-specific order
   llvm::stable_sort(Structors, [](const Structor &L, const Structor &R) {
     return L.Priority < R.Priority;
   });
+}
+
+/// EmitXXStructorList - Emit the ctor or dtor list taking into account the init
+/// priority.
+void AsmPrinter::emitXXStructorList(const DataLayout &DL, const Constant *List,
+                                    bool IsCtor) {
+  SmallVector<Structor, 8> Structors;
+  preprocessXXStructorList(DL, List, Structors);
+  if (Structors.empty())
+    return;
+
   const Align Align = DL.getPointerPrefAlignment();
   for (Structor &S : Structors) {
     const TargetLoweringObjectFile &Obj = getObjFileLowering();
@@ -2154,8 +2157,9 @@
 
       KeySym = getSymbol(GV);
     }
+
     MCSection *OutputSection =
-        (isCtor ? Obj.getStaticCtorSection(S.Priority, KeySym)
+        (IsCtor ? Obj.getStaticCtorSection(S.Priority, KeySym)
                 : Obj.getStaticDtorSection(S.Priority, KeySym));
     OutStreamer->SwitchSection(OutputSection);
     if (OutStreamer->getCurrentSection() != OutStreamer->getPreviousSection())
Index: llvm/include/llvm/CodeGen/AsmPrinter.h
===================================================================
--- llvm/include/llvm/CodeGen/AsmPrinter.h
+++ llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -369,6 +369,32 @@
   /// so, emit it and return true, otherwise do nothing and return false.
   bool emitSpecialLLVMGlobal(const GlobalVariable *GV);
 
+  /// `llvm.global_ctors` and `llvm.global_dtors` are arrays of Structor
+  /// structs.
+  ///
+  /// Priority - init priority
+  /// Func - global initialization or global clean-up function
+  /// ComdatKey - associated data
+  struct Structor {
+    int Priority = 0;
+    Constant *Func = nullptr;
+    GlobalValue *ComdatKey = nullptr;
+
+    Structor() = default;
+  };
+
+  /// This method gathers an array of Structors and then sorts them out by
+  /// Priority.
+  /// @param List The initializer of `llvm.global_ctors` or `llvm.global_dtors`
+  /// array.
+  /// @param[out] Structors Sorted Structor structs by Priority.
+  void preprocessXXStructorList(const DataLayout &DL, const Constant *List,
+                                SmallVector<Structor, 8> &Structors);
+
+  /// This method emits `llvm.global_ctors` or `llvm.global_dtors` list.
+  virtual void emitXXStructorList(const DataLayout &DL, const Constant *List,
+                                  bool IsCtor);
+
   /// Emit an alignment directive to the specified power of two boundary. If a
   /// global value is specified, and if that global has an explicit alignment
   /// requested, it will override the alignment request if required for
@@ -713,8 +739,6 @@
   void emitModuleIdents(Module &M);
   /// Emit bytes for llvm.commandline metadata.
   void emitModuleCommandLines(Module &M);
-  void emitXXStructorList(const DataLayout &DL, const Constant *List,
-                          bool isCtor);
 
   GCMetadataPrinter *GetOrCreateGCPrinter(GCStrategy &S);
   /// Emit GlobalAlias or GlobalIFunc.
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: 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/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 <typename T>
+Test1 t1 = 2;
+
+inline Test1 t2 = 2;
+
+void foo() {
+  (void)&t1<int>;
+}
+} // namespace test1
+
+namespace test2 {
+template <typename = void>
+struct A {
+  A() {}
+  ~A() {}
+  static A instance;
+};
+
+template <typename T>
+A<T> A<T>::instance;
+template A<> A<>::instance;
+
+A<int> &bar() {
+  A<int> *a = new A<int>;
+  return *a;
+}
+template <>
+A<int> A<int>::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-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/lib/CodeGen/ItaniumCXXABI.cpp
===================================================================
--- clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -4597,5 +4597,16 @@
 
   CGF.FinishFunction();
 
-  CGM.AddCXXStermFinalizerEntry(StermFinalizer);
+  assert(!D.getAttr<InitPriorityAttr>() &&
+         "Prioritized sinit and sterm functions are not yet supported.");
+
+  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/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<GlobalDecl, StringRef> MangledDeclNames;
   llvm::StringMap<GlobalDecl, llvm::BumpPtrAllocator> 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/CGDeclCXX.cpp
===================================================================
--- clang/lib/CodeGen/CGDeclCXX.cpp
+++ clang/lib/CodeGen/CGDeclCXX.cpp
@@ -21,7 +21,6 @@
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/MDBuilder.h"
 #include "llvm/Support/Path.h"
-#include "llvm/Transforms/Utils/ModuleUtils.h"
 
 using namespace clang;
 using namespace CodeGen;
@@ -365,12 +364,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 +374,7 @@
       Fn->setSection(Section);
   }
 
-  if (Fn->hasInternalLinkage())
-    SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
+  SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
 
   Fn->setCallingConv(getRuntimeCC());
 
@@ -589,22 +584,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 +627,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 +666,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);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to