Xiangling_L updated this revision to Diff 271664.
Xiangling_L marked an inline comment as done.
Xiangling_L added a comment.

Adjust the patch corresponding to D81972 <https://reviews.llvm.org/D81972>;


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

https://reviews.llvm.org/D74166

Files:
  clang/include/clang/AST/Mangle.h
  clang/lib/AST/ItaniumMangle.cpp
  clang/lib/CodeGen/CGCXXABI.h
  clang/lib/CodeGen/CGDeclCXX.cpp
  clang/lib/CodeGen/CGOpenMPRuntime.cpp
  clang/lib/CodeGen/CodeGenFunction.h
  clang/lib/CodeGen/CodeGenModule.cpp
  clang/lib/CodeGen/CodeGenModule.h
  clang/lib/CodeGen/ItaniumCXXABI.cpp
  clang/lib/CodeGen/MicrosoftCXXABI.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/test/CodeGen/aix-constructor-attribute.cpp
  clang/test/CodeGen/aix-destructor-attribute.cpp
  clang/test/CodeGen/aix-init-priority-attribute.cpp
  clang/test/CodeGen/static-init.cpp
  clang/test/CodeGenCXX/aix-static-init.cpp

Index: clang/test/CodeGenCXX/aix-static-init.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/aix-static-init.cpp
@@ -0,0 +1,193 @@
+// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -S -emit-llvm -x c++ \
+// RUN:     -fno-use-cxa-atexit -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:     -fno-use-cxa-atexit -std=c++2a < %s | \
+// RUN:   FileCheck --check-prefixes=CHECK,CHECK64 %s
+
+namespace test1 {
+  struct Test1 {
+    Test1();
+    ~Test1();
+  } t1, t2;
+} // namespace test1
+
+namespace test2 {
+  int foo() { return 3; }
+  int x = foo();
+} // namespace test2
+
+namespace test3 {
+  struct Test3 {
+    constexpr Test3() {};
+    ~Test3() {};
+  };
+
+  constinit Test3 t;
+} // namespace test3
+
+namespace test4 {
+  struct Test4 {
+    Test4();
+    ~Test4();
+  };
+
+  void f() {
+    static Test4 staticLocal;
+  }
+} // 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: define internal void @__cxx_global_var_init() [[ATTR:#[0-9]+]] {
+// CHECK: entry:
+// CHECK:   call void @_ZN5test15Test1C1Ev(%"struct.test1::Test1"* @_ZN5test12t1E)
+// CHECK:   %0 = call i32 @atexit(void ()* @__dtor__ZN5test12t1E)
+// CHECK:   ret void
+// CHECK: }
+
+// CHECK: define internal void @__dtor__ZN5test12t1E() [[ATTR:#[0-9]+]] {
+// CHECK: entry:
+// CHECK:   call void @_ZN5test15Test1D1Ev(%"struct.test1::Test1"* @_ZN5test12t1E)
+// CHECK:   ret void
+// CHECK: }
+
+// CHECK: declare i32 @atexit(void ()*)
+
+// CHECK: define internal void @__finalize__ZN5test12t1E() [[ATTR:#[0-9]+]] {
+// CHECK: entry:
+// CHECK:   %0 = call i32 @unatexit(void ()* @__dtor__ZN5test12t1E)
+// 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__ZN5test12t1E()
+// CHECK:   br label %destruct.end
+
+// CHECK: destruct.end:
+// CHECK:   ret void
+// CHECK: }
+
+// CHECK: declare i32 @unatexit(void ()*)
+
+// CHECK: define internal void @__cxx_global_var_init.1() [[ATTR:#[0-9]+]] {
+// CHECK: entry:
+// CHECK:   call void @_ZN5test15Test1C1Ev(%"struct.test1::Test1"* @_ZN5test12t2E)
+// CHECK:   %0 = call i32 @atexit(void ()* @__dtor__ZN5test12t2E)
+// 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:
+// CHECK32: %call = call i32 @_ZN5test23fooEv()
+// CHECK64: %call = call signext i32 @_ZN5test23fooEv()
+// CHECK:   store i32 %call, i32* @_ZN5test21xE
+// CHECK:   ret void
+// CHECK: }
+
+// CHECK: define internal void @__cxx_global_var_init.3() [[ATTR:#[0-9]+]] {
+// CHECK: entry:
+// CHECK:   %0 = call i32 @atexit(void ()* @__dtor__ZN5test31tE)
+// CHECK:   ret void
+// CHECK: }
+
+// CHECK: define internal void @__dtor__ZN5test31tE() [[ATTR:#[0-9]+]] {
+// CHECK: entry:
+// CHECK:   call void @_ZN5test35Test3D1Ev(%"struct.test3::Test3"* @_ZN5test31tE)
+// CHECK:   ret void
+// CHECK: }
+
+// CHECK: define internal void @__finalize__ZN5test31tE() [[ATTR:#[0-9]+]] {
+// CHECK: entry:
+// CHECK:   %0 = call i32 @unatexit(void ()* @__dtor__ZN5test31tE)
+// 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__ZN5test31tE()
+// CHECK:   br label %destruct.end
+
+// CHECK: destruct.end:
+// CHECK:   ret void
+// CHECK: }
+
+// CHECK: define void @_ZN5test41fEv() [[ATTR:#[0-9]+]] {
+// CHECK: entry:
+// CHECK:   %0 = load atomic i8, i8* bitcast (i64* @_ZGVZN5test41fEvE11staticLocal 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* @_ZGVZN5test41fEvE11staticLocal)
+// CHECK:   %tobool = icmp ne i32 %1, 0
+// CHECK:   br i1 %tobool, label %init, label %init.end
+
+// CHECK: init:
+// CHECK:   call void @_ZN5test45Test4C1Ev(%"struct.test4::Test4"* @_ZZN5test41fEvE11staticLocal)
+// CHECK:   %2 = call i32 @atexit(void ()* @__dtor__ZZN5test41fEvE11staticLocal)
+// CHECK:   call void @__cxa_guard_release(i64* @_ZGVZN5test41fEvE11staticLocal)
+// CHECK:   br label %init.end
+
+// CHECK: init.end:
+// CHECK:   ret void
+// CHECK: }
+
+// CHECK: define internal void @__dtor__ZZN5test41fEvE11staticLocal() [[ATTR:#[0-9]+]] {
+// CHECK: entry:
+// CHECK:   call void @_ZN5test45Test4D1Ev(%"struct.test4::Test4"* @_ZZN5test41fEvE11staticLocal)
+// CHECK:   ret void
+// CHECK: }
+
+// CHECK: define internal void @__finalize__ZZN5test41fEvE11staticLocal() [[ATTR:#[0-9]+]] {
+// CHECK: entry:
+// CHECK:   %0 = call i32 @unatexit(void ()* @__dtor__ZZN5test41fEvE11staticLocal)
+// 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__ZZN5test41fEvE11staticLocal()
+// CHECK:   br label %destruct.end
+
+// CHECK: destruct.end:
+// CHECK:   ret void
+// CHECK: }
+
+// CHECK: define void @__sinit80000000_clang_1145401da454a7baad10bfe313c46638() [[ATTR:#[0-9]+]] {
+// CHECK: entry:
+// CHECK:   call void @__cxx_global_var_init()
+// CHECK:   call void @__cxx_global_var_init.1()
+// CHECK:   call void @__cxx_global_var_init.2()
+// CHECK:   call void @__cxx_global_var_init.3()
+// CHECK:   ret void
+// CHECK: }
+
+// CHECK: define void @__sterm80000000_clang_1145401da454a7baad10bfe313c46638() [[ATTR:#[0-9]+]] {
+// CHECK: entry:
+// CHECK:   call void @__finalize__ZZN5test41fEvE11staticLocal()
+// CHECK:   call void @__finalize__ZN5test31tE()
+// CHECK:   call void @__finalize__ZN5test12t2E()
+// CHECK:   call void @__finalize__ZN5test12t1E()
+// CHECK:   ret void
+// CHECK: }
Index: clang/test/CodeGen/static-init.cpp
===================================================================
--- clang/test/CodeGen/static-init.cpp
+++ /dev/null
@@ -1,12 +0,0 @@
-// RUN: not %clang_cc1 -triple powerpc-ibm-aix-xcoff -S -emit-llvm -x c++ %s \
-// RUN: -o /dev/null 2>&1 | FileCheck %s
-
-// RUN: not %clang_cc1 -triple powerpc64-ibm-aix-xcoff -S -emit-llvm -x c++ %s \
-// RUN: -o /dev/null 2>&1 | FileCheck %s
-
-struct test {
-  test();
-  ~test();
-} t;
-
-// CHECK: error in backend: Static initialization has not been implemented on XL ABI yet.
Index: clang/test/CodeGen/aix-init-priority-attribute.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/aix-init-priority-attribute.cpp
@@ -0,0 +1,19 @@
+// RUN: not %clang_cc1 -triple powerpc-ibm-aix-xcoff -x c++ -emit-llvm < %s \
+// RUN:     2>&1 | \
+// RUN:   FileCheck %s
+// RUN: not %clang_cc1 -triple powerpc64-ibm-aix-xcoff -x c++ -emit-llvm < %s \
+// RUN:     2>&1 | \
+// RUN:   FileCheck %s
+
+class test {
+  int a;
+
+public:
+  test(int c) { a = c; }
+  ~test() { a = 0; }
+};
+
+__attribute__((init_priority(2000)))
+test t(1);
+
+// CHECK: fatal error: error in backend: 'init_priority' attribute is not yet supported on AIX
Index: clang/test/CodeGen/aix-destructor-attribute.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/aix-destructor-attribute.cpp
@@ -0,0 +1,20 @@
+// RUN: not %clang_cc1 -triple powerpc-ibm-aix-xcoff -x c++ -emit-llvm < %s \
+// RUN:     2>&1 | \
+// RUN:   FileCheck %s
+// RUN: not %clang_cc1 -triple powerpc64-ibm-aix-xcoff -x c++ -emit-llvm < %s \
+// RUN:     2>&1 | \
+// RUN:   FileCheck %s
+
+int bar() __attribute__((destructor(180)));
+
+class test {
+  int a;
+
+public:
+  test(int c) { a = c; }
+  ~test() { a = 0; }
+};
+
+test t(1);
+
+// CHECK: fatal error: error in backend: 'destructor' attribute is not yet supported on AIX
Index: clang/test/CodeGen/aix-constructor-attribute.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/aix-constructor-attribute.cpp
@@ -0,0 +1,20 @@
+// RUN: not %clang_cc1 -triple powerpc-ibm-aix-xcoff -x c++ -emit-llvm < %s \
+// RUN:     2>&1 | \
+// RUN:   FileCheck %s
+// RUN: not %clang_cc1 -triple powerpc64-ibm-aix-xcoff -x c++ -emit-llvm < %s \
+// RUN:     2>&1 | \
+// RUN:   FileCheck %s
+
+int foo() __attribute__((constructor(180)));
+
+class test {
+  int a;
+
+public:
+  test(int c) { a = c; }
+  ~test() { a = 0; }
+};
+
+test t(1);
+
+// CHECK: fatal error: error in backend: 'constructor' attribute is not yet supported on AIX
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -6939,13 +6939,20 @@
     handlePassObjectSizeAttr(S, D, AL);
     break;
   case ParsedAttr::AT_Constructor:
-    handleConstructorAttr(S, D, AL);
+    if (S.Context.getTargetInfo().getTriple().isOSAIX())
+      llvm::report_fatal_error(
+          "'constructor' attribute is not yet supported on AIX");
+    else
+      handleConstructorAttr(S, D, AL);
     break;
   case ParsedAttr::AT_Deprecated:
     handleDeprecatedAttr(S, D, AL);
     break;
   case ParsedAttr::AT_Destructor:
-    handleDestructorAttr(S, D, AL);
+    if (S.Context.getTargetInfo().getTriple().isOSAIX())
+      llvm::report_fatal_error("'destructor' attribute is not yet supported on AIX");
+    else
+      handleDestructorAttr(S, D, AL);
     break;
   case ParsedAttr::AT_EnableIf:
     handleEnableIfAttr(S, D, AL);
@@ -7139,7 +7146,11 @@
     handleVecTypeHint(S, D, AL);
     break;
   case ParsedAttr::AT_InitPriority:
-    handleInitPriorityAttr(S, D, AL);
+    if (S.Context.getTargetInfo().getTriple().isOSAIX())
+      llvm::report_fatal_error(
+          "'init_priority' attribute is not yet supported on AIX");
+    else
+      handleInitPriorityAttr(S, D, AL);
     break;
   case ParsedAttr::AT_Packed:
     handlePackedAttr(S, D, AL);
Index: clang/lib/CodeGen/MicrosoftCXXABI.cpp
===================================================================
--- clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -2349,7 +2349,7 @@
   if (!NonComdatInits.empty()) {
     llvm::FunctionType *FTy =
         llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
-    llvm::Function *InitFunc = CGM.CreateGlobalInitOrDestructFunction(
+    llvm::Function *InitFunc = CGM.CreateGlobalInitOrCleanUpFunction(
         FTy, "__tls_init", CGM.getTypes().arrangeNullaryFunction(),
         SourceLocation(), /*TLS=*/true);
     CodeGenFunction(CGM).GenerateCXXGlobalInitFunc(InitFunc, NonComdatInits);
@@ -2547,8 +2547,9 @@
         Builder.CreateICmpEQ(Builder.CreateAnd(LI, Bit), Zero);
     llvm::BasicBlock *InitBlock = CGF.createBasicBlock("init");
     llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end");
-    CGF.EmitCXXGuardedInitBranch(NeedsInit, InitBlock, EndBlock,
-                                 CodeGenFunction::GuardKind::VariableGuard, &D);
+    CGF.EmitCXXGuardedInitOrDestructBranch(
+        NeedsInit, InitBlock, EndBlock,
+        CodeGenFunction::GuardKind::VariableGuard, &D);
 
     // Set our bit in the guard variable and emit the initializer and add a global
     // destructor if appropriate.
@@ -2583,8 +2584,9 @@
         Builder.CreateICmpSGT(FirstGuardLoad, InitThreadEpoch);
     llvm::BasicBlock *AttemptInitBlock = CGF.createBasicBlock("init.attempt");
     llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end");
-    CGF.EmitCXXGuardedInitBranch(IsUninitialized, AttemptInitBlock, EndBlock,
-                                 CodeGenFunction::GuardKind::VariableGuard, &D);
+    CGF.EmitCXXGuardedInitOrDestructBranch(
+        IsUninitialized, AttemptInitBlock, EndBlock,
+        CodeGenFunction::GuardKind::VariableGuard, &D);
 
     // This BasicBlock attempts to determine whether or not this thread is
     // responsible for doing the initialization.
Index: clang/lib/CodeGen/ItaniumCXXABI.cpp
===================================================================
--- clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -526,6 +526,12 @@
   void registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
                           llvm::FunctionCallee dtor,
                           llvm::Constant *addr) override;
+
+  bool useSinitAndSterm() const override { return true; }
+
+private:
+  void emitCXXStermFinalizer(const VarDecl &D, llvm::Function *dtorStub,
+                             llvm::Constant *addr);
 };
 }
 
@@ -2417,8 +2423,9 @@
   llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end");
 
   // Check if the first byte of the guard variable is zero.
-  CGF.EmitCXXGuardedInitBranch(NeedsInit, InitCheckBlock, EndBlock,
-                               CodeGenFunction::GuardKind::VariableGuard, &D);
+  CGF.EmitCXXGuardedInitOrDestructBranch(
+      NeedsInit, InitCheckBlock, EndBlock,
+      CodeGenFunction::GuardKind::VariableGuard, &D);
 
   CGF.EmitBlock(InitCheckBlock);
 
@@ -2525,7 +2532,7 @@
     std::string GlobalInitFnName =
         std::string("__GLOBAL_init_") + llvm::to_string(Priority);
     llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
-    llvm::Function *GlobalInitFn = CreateGlobalInitOrDestructFunction(
+    llvm::Function *GlobalInitFn = CreateGlobalInitOrCleanUpFunction(
         FTy, GlobalInitFnName, getTypes().arrangeNullaryFunction(),
         SourceLocation());
     ASTContext &Ctx = getContext();
@@ -2679,9 +2686,9 @@
     llvm::FunctionType *FTy =
         llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
     const CGFunctionInfo &FI = CGM.getTypes().arrangeNullaryFunction();
-    InitFunc = CGM.CreateGlobalInitOrDestructFunction(FTy, "__tls_init", FI,
-                                                      SourceLocation(),
-                                                      /*TLS=*/true);
+    InitFunc = CGM.CreateGlobalInitOrCleanUpFunction(FTy, "__tls_init", FI,
+                                                     SourceLocation(),
+                                                     /*TLS=*/true);
     llvm::GlobalVariable *Guard = new llvm::GlobalVariable(
         CGM.getModule(), CGM.Int8Ty, /*isConstant=*/false,
         llvm::GlobalVariable::InternalLinkage,
@@ -4516,6 +4523,69 @@
 void XLCXXABI::registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
                                   llvm::FunctionCallee dtor,
                                   llvm::Constant *addr) {
-  llvm::report_fatal_error("Static initialization has not been implemented on"
-                           " XL ABI yet.");
+  if (D.getTLSKind() != VarDecl::TLS_None)
+    llvm::report_fatal_error("thread local storage not yet implemented on AIX");
+
+  // Create __dtor function for the var decl.
+  llvm::Function *dtorStub = CGF.createAtExitStub(D, dtor, addr);
+
+  if (CGM.getCodeGenOpts().CXAAtExit)
+    llvm::report_fatal_error("using __cxa_atexit unsupported on AIX");
+  // Register above __dtor with atexit().
+  CGF.registerGlobalDtorWithAtExit(dtorStub);
+
+  // Emit __finalize function to unregister __dtor and (as appropriate) call
+  // __dtor.
+  emitCXXStermFinalizer(D, dtorStub, addr);
+}
+
+void XLCXXABI::emitCXXStermFinalizer(const VarDecl &D, llvm::Function *dtorStub,
+                                     llvm::Constant *addr) {
+  llvm::FunctionType *FTy = llvm::FunctionType::get(CGM.VoidTy, false);
+  SmallString<256> FnName;
+  {
+    llvm::raw_svector_ostream Out(FnName);
+    getMangleContext().mangleDynamicStermFinalizer(&D, Out);
+  }
+
+  // Create the finalization action associated with a variable.
+  const CGFunctionInfo &FI = CGM.getTypes().arrangeNullaryFunction();
+  llvm::Function *StermFinalizer = CGM.CreateGlobalInitOrCleanUpFunction(
+      FTy, FnName.str(), FI, D.getLocation());
+
+  CodeGenFunction CGF(CGM);
+
+  CGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, StermFinalizer, FI,
+                    FunctionArgList());
+
+  // The unatexit subroutine unregisters __dtor functions that were previously
+  // registered by the atexit subroutine. If the referenced function is found,
+  // the unatexit returns a value of 0, meaning that the cleanup is still
+  // pending (and we should call the __dtor function).
+  llvm::Value *V = CGF.unregisterGlobalDtorWithUnAtExit(dtorStub);
+
+  llvm::Value *NeedsDestruct = CGF.Builder.CreateIsNull(V, "needs_destruct");
+
+  llvm::BasicBlock *DestructCallBlock = CGF.createBasicBlock("destruct.call");
+  llvm::BasicBlock *EndBlock = CGF.createBasicBlock("destruct.end");
+
+  // Check if unatexit returns a value of 0. If it does, jump to
+  // DestructCallBlock, otherwise jump to EndBlock directly.
+  CGF.EmitCXXGuardedInitOrDestructBranch(
+      NeedsDestruct, DestructCallBlock, EndBlock,
+      CodeGenFunction::GuardKind::VariableGuard, &D, true);
+
+  CGF.EmitBlock(DestructCallBlock);
+
+  // Emit the call to dtorStub.
+  llvm::CallInst *CI = CGF.Builder.CreateCall(dtorStub);
+
+  // Make sure the call and the callee agree on calling convention.
+  CI->setCallingConv(dtorStub->getCallingConv());
+
+  CGF.EmitBlock(EndBlock);
+
+  CGF.FinishFunction();
+
+  CGM.AddCXXStermFinalizerEntry(StermFinalizer);
 }
Index: clang/lib/CodeGen/CodeGenModule.h
===================================================================
--- clang/lib/CodeGen/CodeGenModule.h
+++ clang/lib/CodeGen/CodeGenModule.h
@@ -397,6 +397,10 @@
   /// 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;
@@ -465,9 +469,11 @@
   SmallVector<GlobalInitData, 8> PrioritizedCXXGlobalInits;
 
   /// 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.
   std::vector<
       std::tuple<llvm::FunctionType *, llvm::WeakTrackingVH, llvm::Constant *>>
-      CXXGlobalDtors;
+      CXXGlobalDtorsOrStermFinalizers;
 
   /// The complete set of modules that has been imported.
   llvm::SetVector<clang::Module *> ImportedModules;
@@ -815,11 +821,10 @@
                                     llvm::GlobalValue::LinkageTypes Linkage,
                                     unsigned Alignment);
 
-  llvm::Function *
-  CreateGlobalInitOrDestructFunction(llvm::FunctionType *ty, const Twine &name,
-                                     const CGFunctionInfo &FI,
-                                     SourceLocation Loc = SourceLocation(),
-                                     bool TLS = false);
+  llvm::Function *CreateGlobalInitOrCleanUpFunction(
+      llvm::FunctionType *ty, const Twine &name, const CGFunctionInfo &FI,
+      SourceLocation Loc = SourceLocation(), bool TLS = false,
+      bool IsExternalLinkage = 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
@@ -1048,8 +1053,14 @@
 
   /// Add a destructor and object to add to the C++ global destructor function.
   void AddCXXDtorEntry(llvm::FunctionCallee DtorFn, llvm::Constant *Object) {
-    CXXGlobalDtors.emplace_back(DtorFn.getFunctionType(), DtorFn.getCallee(),
-                                Object);
+    CXXGlobalDtorsOrStermFinalizers.emplace_back(DtorFn.getFunctionType(),
+                                                 DtorFn.getCallee(), Object);
+  }
+
+  /// Add a sterm finalizer to the C++ global cleanup function.
+  void AddCXXStermFinalizerEntry(llvm::FunctionCallee DtorFn) {
+    CXXGlobalDtorsOrStermFinalizers.emplace_back(DtorFn.getFunctionType(),
+                                                 DtorFn.getCallee(), nullptr);
   }
 
   /// Create or return a runtime function declaration with the specified type
@@ -1449,8 +1460,8 @@
   /// Emit the function that initializes C++ globals.
   void EmitCXXGlobalInitFunc();
 
-  /// Emit the function that destroys C++ globals.
-  void EmitCXXGlobalDtorFunc();
+  /// Emit the function that performs cleanup associated with C++ globals.
+  void EmitCXXGlobalCleanUpFunc();
 
   /// Emit the function that initializes the specified global (if PerformInit is
   /// true) and registers its destructor.
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -411,7 +411,7 @@
   checkAliases();
   emitMultiVersionFunctions();
   EmitCXXGlobalInitFunc();
-  EmitCXXGlobalDtorFunc();
+  EmitCXXGlobalCleanUpFunc();
   registerGlobalDtorsWithAtExit();
   EmitCXXThreadLocalInitFunc();
   if (ObjCRuntime)
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -4192,6 +4192,9 @@
   /// Call atexit() with function dtorStub.
   void registerGlobalDtorWithAtExit(llvm::Constant *dtorStub);
 
+  /// Call unatexit() with function dtorStub.
+  llvm::Value *unregisterGlobalDtorWithUnAtExit(llvm::Function *dtorStub);
+
   /// Emit code in this function to perform a guarded variable
   /// initialization.  Guarded initializations are used when it's not
   /// possible to prove that an initialization will be done exactly
@@ -4203,10 +4206,11 @@
   enum class GuardKind { VariableGuard, TlsGuard };
 
   /// Emit a branch to select whether or not to perform guarded initialization.
-  void EmitCXXGuardedInitBranch(llvm::Value *NeedsInit,
-                                llvm::BasicBlock *InitBlock,
-                                llvm::BasicBlock *NoInitBlock,
-                                GuardKind Kind, const VarDecl *D);
+  void EmitCXXGuardedInitOrDestructBranch(llvm::Value *NeedsInit,
+                                          llvm::BasicBlock *InitBlock,
+                                          llvm::BasicBlock *NoInitBlock,
+                                          GuardKind Kind, const VarDecl *D,
+                                          bool IsDestruct = false);
 
   /// GenerateCXXGlobalInitFunc - Generates code for initializing global
   /// variables.
@@ -4215,12 +4219,12 @@
                             ArrayRef<llvm::Function *> CXXThreadLocals,
                             ConstantAddress Guard = ConstantAddress::invalid());
 
-  /// GenerateCXXGlobalDtorsFunc - Generates code for destroying global
+  /// GenerateCXXGlobalCleanUpFunc - Generates code for cleaning up global
   /// variables.
-  void GenerateCXXGlobalDtorsFunc(
+  void GenerateCXXGlobalCleanUpFunc(
       llvm::Function *Fn,
       const std::vector<std::tuple<llvm::FunctionType *, llvm::WeakTrackingVH,
-                                   llvm::Constant *>> &DtorsAndObjects);
+                                   llvm::Constant *>> &DtorsOrStermFinalizers);
 
   void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
                                         const VarDecl *D,
Index: clang/lib/CodeGen/CGOpenMPRuntime.cpp
===================================================================
--- clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ clang/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -1837,7 +1837,7 @@
       llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
       std::string Name = getName({"__kmpc_global_ctor_", ""});
       llvm::Function *Fn =
-          CGM.CreateGlobalInitOrDestructFunction(FTy, Name, FI, Loc);
+          CGM.CreateGlobalInitOrCleanUpFunction(FTy, Name, FI, Loc);
       CtorCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidPtrTy, Fn, FI,
                             Args, Loc, Loc);
       llvm::Value *ArgVal = CtorCGF.EmitLoadOfScalar(
@@ -1870,7 +1870,7 @@
       llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
       std::string Name = getName({"__kmpc_global_dtor_", ""});
       llvm::Function *Fn =
-          CGM.CreateGlobalInitOrDestructFunction(FTy, Name, FI, Loc);
+          CGM.CreateGlobalInitOrCleanUpFunction(FTy, Name, FI, Loc);
       auto NL = ApplyDebugLocation::CreateEmpty(DtorCGF);
       DtorCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, Fn, FI, Args,
                             Loc, Loc);
@@ -1913,7 +1913,7 @@
       auto *InitFunctionTy =
           llvm::FunctionType::get(CGM.VoidTy, /*isVarArg*/ false);
       std::string Name = getName({"__omp_threadprivate_init_", ""});
-      llvm::Function *InitFunction = CGM.CreateGlobalInitOrDestructFunction(
+      llvm::Function *InitFunction = CGM.CreateGlobalInitOrCleanUpFunction(
           InitFunctionTy, Name, CGM.getTypes().arrangeNullaryFunction());
       CodeGenFunction InitCGF(CGM);
       FunctionArgList ArgList;
@@ -1975,7 +1975,7 @@
 
       const CGFunctionInfo &FI = CGM.getTypes().arrangeNullaryFunction();
       llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
-      llvm::Function *Fn = CGM.CreateGlobalInitOrDestructFunction(
+      llvm::Function *Fn = CGM.CreateGlobalInitOrCleanUpFunction(
           FTy, Twine(Buffer, "_ctor"), FI, Loc);
       auto NL = ApplyDebugLocation::CreateEmpty(CtorCGF);
       CtorCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, Fn, FI,
@@ -2013,7 +2013,7 @@
 
       const CGFunctionInfo &FI = CGM.getTypes().arrangeNullaryFunction();
       llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
-      llvm::Function *Fn = CGM.CreateGlobalInitOrDestructFunction(
+      llvm::Function *Fn = CGM.CreateGlobalInitOrCleanUpFunction(
           FTy, Twine(Buffer, "_dtor"), FI, Loc);
       auto NL = ApplyDebugLocation::CreateEmpty(DtorCGF);
       DtorCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, Fn, FI,
@@ -10039,7 +10039,7 @@
     const auto &FI = CGM.getTypes().arrangeNullaryFunction();
     llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
     std::string ReqName = getName({"omp_offloading", "requires_reg"});
-    RequiresRegFn = CGM.CreateGlobalInitOrDestructFunction(FTy, ReqName, FI);
+    RequiresRegFn = CGM.CreateGlobalInitOrCleanUpFunction(FTy, ReqName, FI);
     CGF.StartFunction(GlobalDecl(), C.VoidTy, RequiresRegFn, FI, {});
     OpenMPOffloadingRequiresDirFlags Flags = OMP_REQ_NONE;
     // TODO: check for other requires clauses.
Index: clang/lib/CodeGen/CGDeclCXX.cpp
===================================================================
--- clang/lib/CodeGen/CGDeclCXX.cpp
+++ clang/lib/CodeGen/CGDeclCXX.cpp
@@ -20,7 +20,9 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/MDBuilder.h"
+#include "llvm/Support/Format.h"
 #include "llvm/Support/Path.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
 
 using namespace clang;
 using namespace CodeGen;
@@ -239,7 +241,7 @@
   }
 
   const CGFunctionInfo &FI = CGM.getTypes().arrangeNullaryFunction();
-  llvm::Function *fn = CGM.CreateGlobalInitOrDestructFunction(
+  llvm::Function *fn = CGM.CreateGlobalInitOrCleanUpFunction(
       ty, FnName.str(), FI, VD.getLocation());
 
   CodeGenFunction CGF(CGM);
@@ -249,7 +251,7 @@
 
   llvm::CallInst *call = CGF.Builder.CreateCall(dtor, addr);
 
- // Make sure the call and the callee agree on calling convention.
+  // Make sure the call and the callee agree on calling convention.
   if (auto *dtorFn = dyn_cast<llvm::Function>(
           dtor.getCallee()->stripPointerCastsAndAliases()))
     call->setCallingConv(dtorFn->getCallingConv());
@@ -270,8 +272,12 @@
 
 void CodeGenFunction::registerGlobalDtorWithAtExit(llvm::Constant *dtorStub) {
   // extern "C" int atexit(void (*f)(void));
+  assert(cast<llvm::Function>(dtorStub)->getFunctionType() ==
+             llvm::FunctionType::get(CGM.VoidTy, false) &&
+         "Argument to atexit has a wrong type.");
+
   llvm::FunctionType *atexitTy =
-    llvm::FunctionType::get(IntTy, dtorStub->getType(), false);
+      llvm::FunctionType::get(IntTy, dtorStub->getType(), false);
 
   llvm::FunctionCallee atexit =
       CGM.CreateRuntimeFunction(atexitTy, "atexit", llvm::AttributeList(),
@@ -282,6 +288,30 @@
   EmitNounwindRuntimeCall(atexit, dtorStub);
 }
 
+llvm::Value *
+CodeGenFunction::unregisterGlobalDtorWithUnAtExit(llvm::Function *dtorStub) {
+  // The unatexit subroutine unregisters __dtor functions that were previously
+  // registered by the atexit subroutine. If the referenced function is found,
+  // it is removed from the list of functions that are called at normal program
+  // termination and the unatexit returns a value of 0, otherwise a non-zero
+  // value is returned.
+  //
+  // extern "C" int unatexit(void (*f)(void));
+  assert(dtorStub->getFunctionType() ==
+             llvm::FunctionType::get(CGM.VoidTy, false) &&
+         "Argument to unatexit has a wrong type.");
+
+  llvm::FunctionType *unatexitTy =
+      llvm::FunctionType::get(IntTy, {dtorStub->getType()}, /*isVarArg=*/false);
+
+  llvm::FunctionCallee unatexit =
+      CGM.CreateRuntimeFunction(unatexitTy, "unatexit", llvm::AttributeList());
+
+  cast<llvm::Function>(unatexit.getCallee())->setDoesNotThrow();
+
+  return EmitNounwindRuntimeCall(unatexit, dtorStub);
+}
+
 void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D,
                                          llvm::GlobalVariable *DeclPtr,
                                          bool PerformInit) {
@@ -296,11 +326,10 @@
   CGM.getCXXABI().EmitGuardedInit(*this, D, DeclPtr, PerformInit);
 }
 
-void CodeGenFunction::EmitCXXGuardedInitBranch(llvm::Value *NeedsInit,
-                                               llvm::BasicBlock *InitBlock,
-                                               llvm::BasicBlock *NoInitBlock,
-                                               GuardKind Kind,
-                                               const VarDecl *D) {
+void CodeGenFunction::EmitCXXGuardedInitOrDestructBranch(
+    llvm::Value *NeedsInit, llvm::BasicBlock *InitBlock,
+    llvm::BasicBlock *NoInitBlock, GuardKind Kind,
+    const VarDecl *D, bool IsDestruct) {
   assert((Kind == GuardKind::TlsGuard || D) && "no guarded variable");
 
   // A guess at how many times we will enter the initialization of a
@@ -309,7 +338,12 @@
   static const uint64_t InitsPerLocalVar = 1024 * 1024;
 
   llvm::MDNode *Weights;
-  if (Kind == GuardKind::VariableGuard && !D->isLocalVarDecl()) {
+  if (CGM.getCXXABI().useSinitAndSterm() && Kind == GuardKind::VariableGuard &&
+      IsDestruct) {
+    // Don't apply any weighting since we already expect __sterm to be called
+    // rarely.
+    Weights = nullptr;
+  } else if (Kind == GuardKind::VariableGuard && !D->isLocalVarDecl()) {
     // For non-local variables, don't apply any weighting for now. Due to our
     // use of COMDATs, we expect there to be at most one initialization of the
     // variable per DSO, but we have no way to know how many DSOs will try to
@@ -333,19 +367,23 @@
   Builder.CreateCondBr(NeedsInit, InitBlock, NoInitBlock, Weights);
 }
 
-llvm::Function *CodeGenModule::CreateGlobalInitOrDestructFunction(
+llvm::Function *CodeGenModule::CreateGlobalInitOrCleanUpFunction(
     llvm::FunctionType *FTy, const Twine &Name, const CGFunctionInfo &FI,
-    SourceLocation Loc, bool TLS) {
-  llvm::Function *Fn =
-    llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
-                           Name, &getModule());
+    SourceLocation Loc, bool TLS, bool IsExternalLinkage) {
+  llvm::Function *Fn = llvm::Function::Create(
+      FTy,
+      IsExternalLinkage ? llvm::GlobalValue::ExternalLinkage
+                        : llvm::GlobalValue::InternalLinkage,
+      Name, &getModule());
+
   if (!getLangOpts().AppleKext && !TLS) {
     // Set the section if needed.
     if (const char *Section = getTarget().getStaticInitSectionSpecifier())
       Fn->setSection(Section);
   }
 
-  SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
+  if (Fn->hasInternalLinkage())
+    SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
 
   Fn->setCallingConv(getRuntimeCC());
 
@@ -461,10 +499,8 @@
   }
 
   // Create a variable initialization function.
-  llvm::Function *Fn =
-      CreateGlobalInitOrDestructFunction(FTy, FnName.str(),
-                                         getTypes().arrangeNullaryFunction(),
-                                         D->getLocation());
+  llvm::Function *Fn = CreateGlobalInitOrCleanUpFunction(
+      FTy, FnName.str(), getTypes().arrangeNullaryFunction(), D->getLocation());
 
   auto *ISA = D->getAttr<InitSegAttr>();
   CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr,
@@ -533,6 +569,23 @@
   CXXThreadLocals.clear();
 }
 
+static StringRef getTransformedFileName(llvm::Module &M,
+                                        SmallString<128> &FileName) {
+  FileName = llvm::sys::path::filename(M.getName());
+
+  if (FileName.empty())
+    FileName = "<null>";
+
+  for (size_t i = 0; i < FileName.size(); ++i) {
+    // Replace everything that's not [a-zA-Z0-9._] with a _. This set happens
+    // to be the set of C preprocessing numbers.
+    if (!isPreprocessingNumberBody(FileName[i]))
+      FileName[i] = '_';
+  }
+
+  return FileName;
+}
+
 void
 CodeGenModule::EmitCXXGlobalInitFunc() {
   while (!CXXGlobalInits.empty() && !CXXGlobalInits.back())
@@ -541,11 +594,27 @@
   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();
 
-  // Create our global initialization function.
+  // Create our global prioritized initialization function.
   if (!PrioritizedCXXGlobalInits.empty()) {
+    assert(!UseSinitAndSterm && "Prioritized sinit and sterm functions are not"
+                                " supported yet.");
+
     SmallVector<llvm::Function *, 8> LocalCXXGlobalInits;
     llvm::array_pod_sort(PrioritizedCXXGlobalInits.begin(),
                          PrioritizedCXXGlobalInits.end());
@@ -565,7 +634,7 @@
       std::string PrioritySuffix = llvm::utostr(Priority);
       // Priority is always <= 65535 (enforced by sema).
       PrioritySuffix = std::string(6-PrioritySuffix.size(), '0')+PrioritySuffix;
-      llvm::Function *Fn = CreateGlobalInitOrDestructFunction(
+      llvm::Function *Fn = CreateGlobalInitOrCleanUpFunction(
           FTy, "_GLOBAL__I_" + PrioritySuffix, FI);
 
       for (; I < PrioE; ++I)
@@ -577,22 +646,28 @@
     PrioritizedCXXGlobalInits.clear();
   }
 
-  // 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.
-  SmallString<128> FileName = llvm::sys::path::filename(getModule().getName());
-  if (FileName.empty())
-    FileName = "<null>";
+  // Create our global initialization function.
+  if (UseSinitAndSterm && CXXGlobalInits.empty())
+    return;
 
-  for (size_t i = 0; i < FileName.size(); ++i) {
-    // Replace everything that's not [a-zA-Z0-9._] with a _. This set happens
-    // to be the set of C preprocessing numbers.
-    if (!isPreprocessingNumberBody(FileName[i]))
-      FileName[i] = '_';
+  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.
+    SmallString<128> Storage;
+    llvm::Twine("_GLOBAL__sub_I_", getTransformedFileName(getModule(), Storage))
+        .toVector(FuncName);
   }
 
-  llvm::Function *Fn = CreateGlobalInitOrDestructFunction(
-      FTy, llvm::Twine("_GLOBAL__sub_I_", FileName), FI);
+  llvm::Function *Fn = CreateGlobalInitOrCleanUpFunction(
+      FTy, FuncName, FI, SourceLocation(), false /* TLS */,
+      IsExternalLinkage);
 
   CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, CXXGlobalInits);
   AddGlobalCtor(Fn);
@@ -618,19 +693,38 @@
   CXXGlobalInits.clear();
 }
 
-void CodeGenModule::EmitCXXGlobalDtorFunc() {
-  if (CXXGlobalDtors.empty())
+void CodeGenModule::EmitCXXGlobalCleanUpFunc() {
+  if (CXXGlobalDtorsOrStermFinalizers.empty())
     return;
 
   llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
-
-  // Create our global destructor function.
   const CGFunctionInfo &FI = getTypes().arrangeNullaryFunction();
-  llvm::Function *Fn =
-      CreateGlobalInitOrDestructFunction(FTy, "_GLOBAL__D_a", FI);
 
-  CodeGenFunction(*this).GenerateCXXGlobalDtorsFunc(Fn, CXXGlobalDtors);
+  // 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);
+  }
+
+  CodeGenFunction(*this).GenerateCXXGlobalCleanUpFunc(
+      Fn, CXXGlobalDtorsOrStermFinalizers);
   AddGlobalDtor(Fn);
+  CXXGlobalDtorsOrStermFinalizers.clear();
 }
 
 /// Emit the code necessary to initialize the given global variable.
@@ -687,8 +781,8 @@
                                                  "guard.uninitialized");
       llvm::BasicBlock *InitBlock = createBasicBlock("init");
       ExitBlock = createBasicBlock("exit");
-      EmitCXXGuardedInitBranch(Uninit, InitBlock, ExitBlock,
-                               GuardKind::TlsGuard, nullptr);
+      EmitCXXGuardedInitOrDestructBranch(Uninit, InitBlock, ExitBlock,
+                                         GuardKind::TlsGuard, nullptr);
       EmitBlock(InitBlock);
       // Mark as initialized before initializing anything else. If the
       // initializers use previously-initialized thread_local vars, that's
@@ -726,10 +820,10 @@
   FinishFunction();
 }
 
-void CodeGenFunction::GenerateCXXGlobalDtorsFunc(
+void CodeGenFunction::GenerateCXXGlobalCleanUpFunc(
     llvm::Function *Fn,
     const std::vector<std::tuple<llvm::FunctionType *, llvm::WeakTrackingVH,
-                                 llvm::Constant *>> &DtorsAndObjects) {
+                                 llvm::Constant *>> &DtorsOrStermFinalizers) {
   {
     auto NL = ApplyDebugLocation::CreateEmpty(*this);
     StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
@@ -737,13 +831,22 @@
     // Emit an artificial location for this function.
     auto AL = ApplyDebugLocation::CreateArtificial(*this);
 
-    // Emit the dtors, in reverse order from construction.
-    for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i) {
+    // Emit the cleanups, in reverse order from construction.
+    for (unsigned i = 0, e = DtorsOrStermFinalizers.size(); i != e; ++i) {
       llvm::FunctionType *CalleeTy;
       llvm::Value *Callee;
       llvm::Constant *Arg;
-      std::tie(CalleeTy, Callee, Arg) = DtorsAndObjects[e - i - 1];
-      llvm::CallInst *CI = Builder.CreateCall(CalleeTy, Callee, Arg);
+      std::tie(CalleeTy, Callee, Arg) = DtorsOrStermFinalizers[e - i - 1];
+
+      llvm::CallInst *CI = nullptr;
+      if (Arg == nullptr) {
+        assert(
+            CGM.getCXXABI().useSinitAndSterm() &&
+            "Arg could not be nullptr unless using sinit and sterm functions.");
+        CI = Builder.CreateCall(CalleeTy, Callee);
+      } else
+        CI = Builder.CreateCall(CalleeTy, Callee, Arg);
+
       // Make sure the call and the callee agree on calling convention.
       if (llvm::Function *F = dyn_cast<llvm::Function>(Callee))
         CI->setCallingConv(F->getCallingConv());
@@ -767,7 +870,7 @@
   const CGFunctionInfo &FI =
     CGM.getTypes().arrangeBuiltinFunctionDeclaration(getContext().VoidTy, args);
   llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
-  llvm::Function *fn = CGM.CreateGlobalInitOrDestructFunction(
+  llvm::Function *fn = CGM.CreateGlobalInitOrCleanUpFunction(
       FTy, "__cxx_global_array_dtor", FI, VD->getLocation());
 
   CurEHLocation = VD->getBeginLoc();
Index: clang/lib/CodeGen/CGCXXABI.h
===================================================================
--- clang/lib/CodeGen/CGCXXABI.h
+++ clang/lib/CodeGen/CGCXXABI.h
@@ -108,6 +108,8 @@
 
   virtual bool hasMostDerivedReturn(GlobalDecl GD) const { return false; }
 
+  virtual bool useSinitAndSterm() const { return false; }
+
   /// Returns true if the target allows calling a function through a pointer
   /// with a different signature than the actual function (or equivalently,
   /// bitcasting a function or function pointer to a different function type).
Index: clang/lib/AST/ItaniumMangle.cpp
===================================================================
--- clang/lib/AST/ItaniumMangle.cpp
+++ clang/lib/AST/ItaniumMangle.cpp
@@ -160,6 +160,7 @@
   void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) override;
   void mangleDynamicAtExitDestructor(const VarDecl *D,
                                      raw_ostream &Out) override;
+  void mangleDynamicStermFinalizer(const VarDecl *D, raw_ostream &Out) override;
   void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
                                  raw_ostream &Out) override;
   void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl,
@@ -5230,6 +5231,18 @@
     Mangler.getStream() << D->getName();
 }
 
+void ItaniumMangleContextImpl::mangleDynamicStermFinalizer(const VarDecl *D,
+                                                           raw_ostream &Out) {
+  // Clang generates these internal-linkage functions as part of its
+  // implementation of the XL ABI.
+  CXXNameMangler Mangler(*this, Out);
+  Mangler.getStream() << "__finalize_";
+  if (shouldMangleDeclName(D))
+    Mangler.mangle(D);
+  else
+    Mangler.getStream() << D->getName();
+}
+
 void ItaniumMangleContextImpl::mangleSEHFilterExpression(
     const NamedDecl *EnclosingDecl, raw_ostream &Out) {
   CXXNameMangler Mangler(*this, Out);
Index: clang/include/clang/AST/Mangle.h
===================================================================
--- clang/include/clang/AST/Mangle.h
+++ clang/include/clang/AST/Mangle.h
@@ -175,6 +175,8 @@
 
   virtual void mangleLambdaSig(const CXXRecordDecl *Lambda, raw_ostream &) = 0;
 
+  virtual void mangleDynamicStermFinalizer(const VarDecl *D, raw_ostream &) = 0;
+
   bool isUniqueNameMangler() { return IsUniqueNameMangler; }
 
   static bool classof(const MangleContext *C) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to