[llvm] 6ef801a - [AIX] Static init frontend recovery and backend support

Xiangling Liao via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 10 07:11:12 PDT 2020


Author: Xiangling Liao
Date: 2020-08-10T10:10:49-04:00
New Revision: 6ef801aa6bc01fc49a8e83ddb217470b5e2337dd

URL: https://github.com/llvm/llvm-project/commit/6ef801aa6bc01fc49a8e83ddb217470b5e2337dd
DIFF: https://github.com/llvm/llvm-project/commit/6ef801aa6bc01fc49a8e83ddb217470b5e2337dd.diff

LOG: [AIX] Static init frontend recovery and backend support

On the frontend side, this patch recovers AIX static init implementation to
use the linkage type and function names Clang chooses for sinit related function.

On the backend side, this patch sets correct linkage and function names on aliases
created for sinit/sterm functions.

Differential Revision: https://reviews.llvm.org/D84534

Added: 
    clang/test/CodeGenCXX/aix-static-init-temp-spec-and-inline-var.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

Modified: 
    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.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

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp
index 4e941021daa3..bfefd7956157 100644
--- a/clang/lib/CodeGen/CGDeclCXX.cpp
+++ b/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 @@ void CodeGenFunction::EmitCXXGuardedInitBranch(llvm::Value *NeedsInit,
 
 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 @@ llvm::Function *CodeGenModule::CreateGlobalInitOrCleanUpFunction(
       Fn->setSection(Section);
   }
 
-  if (Fn->hasInternalLinkage())
-    SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
+  SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
 
   Fn->setCallingConv(getRuntimeCC());
 
@@ -589,22 +584,10 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
   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 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
   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 @@ void CodeGenModule::EmitCXXGlobalCleanUpFunc() {
   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);

diff  --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index a6c4a1f7b278..19085b582f5a 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -396,10 +396,6 @@ class CodeGenModule : public CodeGenTypeCache {
   /// 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 @@ class CodeGenModule : public CodeGenTypeCache {
 
   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 @@ class CodeGenModule : public CodeGenTypeCache {
                                                  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.

diff  --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 12d00c7d59a3..3b752d306055 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -4597,5 +4597,16 @@ void XLCXXABI::emitCXXStermFinalizer(const VarDecl &D, llvm::Function *dtorStub,
 
   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);
 }

diff  --git a/clang/test/CodeGenCXX/aix-static-init-debug-info.cpp b/clang/test/CodeGenCXX/aix-static-init-debug-info.cpp
index 39de0cdd513a..161350409a0a 100644
--- a/clang/test/CodeGenCXX/aix-static-init-debug-info.cpp
+++ b/clang/test/CodeGenCXX/aix-static-init-debug-info.cpp
@@ -40,13 +40,13 @@ X v;
 // 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 @@ X v;
 // 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]])

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
new file mode 100644
index 000000000000..7ef2dc18f2a7
--- /dev/null
+++ b/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: }

diff  --git a/clang/test/CodeGenCXX/aix-static-init.cpp b/clang/test/CodeGenCXX/aix-static-init.cpp
index 606e51328ffb..41873910681d 100644
--- a/clang/test/CodeGenCXX/aix-static-init.cpp
+++ b/clang/test/CodeGenCXX/aix-static-init.cpp
@@ -38,8 +38,8 @@ namespace test4 {
   }
 } // 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 @@ namespace test4 {
 // 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 @@ namespace test4 {
 // 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()

diff  --git a/clang/unittests/CodeGen/IncrementalProcessingTest.cpp b/clang/unittests/CodeGen/IncrementalProcessingTest.cpp
index d1d921bb03c6..045ed9bbc760 100644
--- a/clang/unittests/CodeGen/IncrementalProcessingTest.cpp
+++ b/clang/unittests/CodeGen/IncrementalProcessingTest.cpp
@@ -159,11 +159,6 @@ TEST(IncrementalProcessing, EmitCXXGlobalInitFunc) {
     // 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);

diff  --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index 0eb950861af6..eab6eb52b86c 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -369,6 +369,32 @@ class AsmPrinter : public MachineFunctionPass {
   /// 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 @@ class AsmPrinter : public MachineFunctionPass {
   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.

diff  --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index ae7bea9c97cc..a5d83ab11d2b 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -2094,47 +2094,50 @@ void AsmPrinter::emitLLVMUsedList(const ConstantArray *InitList) {
   }
 }
 
-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();
@@ -2150,8 +2153,9 @@ void AsmPrinter::emitXXStructorList(const DataLayout &DL, const Constant *List,
 
       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())

diff  --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index fc08fb95123b..317166096f1b 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -2122,13 +2122,13 @@ void TargetLoweringObjectFileXCOFF::Initialize(MCContext &Ctx,
 }
 
 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(

diff  --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 10962df7b872..f7a0b607e61f 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/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 @@ class PPCAIXAsmPrinter : public PPCAsmPrinter {
   /// 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 @@ class PPCAIXAsmPrinter : public PPCAsmPrinter {
 
   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 @@ void PPCAIXAsmPrinter::ValidateGV(const GlobalVariable *GV) {
 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 @@ static bool isSpecialLLVMGlobalArrayToSkip(const GlobalVariable *GV) {
              .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 @@ bool PPCAIXAsmPrinter::doInitialization(Module &M) {
   for (const auto &G : M.globals()) {
     if (isSpecialLLVMGlobalArrayToSkip(&G))
       continue;
+
+    if (isSpecialLLVMGlobalArrayForStaticInit(&G)) {
+      // Generate a unique module id which is a part of sinit and sterm function
+      // names.
+      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 @@ bool PPCAIXAsmPrinter::doFinalization(Module &M) {
   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.

diff  --git a/llvm/test/CodeGen/PowerPC/aix-static-init-default-priority.ll b/llvm/test/CodeGen/PowerPC/aix-static-init-default-priority.ll
new file mode 100644
index 000000000000..0833ec6fab50
--- /dev/null
+++ b/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
+
+ at 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 }]
+ at 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

diff  --git a/llvm/test/CodeGen/PowerPC/aix-static-init-key-object.ll b/llvm/test/CodeGen/PowerPC/aix-static-init-key-object.ll
new file mode 100644
index 000000000000..18657465449d
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/aix-static-init-key-object.ll
@@ -0,0 +1,12 @@
+; RUN: not --crash llc -mtriple powerpc-ibm-aix-xcoff < %s 2>&1 | FileCheck %s
+; RUN: not --crash llc -mtriple powerpc64-ibm-aix-xcoff < %s 2>&1 | FileCheck %s
+
+ at v = global i8 0
+
+ at 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

diff  --git a/llvm/test/CodeGen/PowerPC/aix-static-init-no-unique-module-id.ll b/llvm/test/CodeGen/PowerPC/aix-static-init-no-unique-module-id.ll
new file mode 100644
index 000000000000..eb49085b9781
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/aix-static-init-no-unique-module-id.ll
@@ -0,0 +1,10 @@
+; RUN: not --crash llc -mtriple powerpc-ibm-aix-xcoff %s 2>&1 | FileCheck %s
+; RUN: not --crash llc -mtriple powerpc64-ibm-aix-xcoff %s 2>&1 | FileCheck %s
+
+ at llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @foo, i8* null }]
+
+define internal void @foo() {
+  ret void
+}
+
+; CHECK: LLVM ERROR: cannot produce a unique identifier for this module based on strong external symbols

diff  --git a/llvm/test/CodeGen/PowerPC/aix-static-init-non-default-priority.ll b/llvm/test/CodeGen/PowerPC/aix-static-init-non-default-priority.ll
new file mode 100644
index 000000000000..96566a912bb8
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/aix-static-init-non-default-priority.ll
@@ -0,0 +1,10 @@
+; RUN: not --crash llc -mtriple powerpc-ibm-aix-xcoff < %s 2>&1 | FileCheck %s
+; RUN: not --crash llc -mtriple powerpc64-ibm-aix-xcoff < %s 2>&1 | FileCheck %s
+
+ at 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


        


More information about the llvm-commits mailing list