Xiangling_L created this revision.
Xiangling_L added reviewers: hubert.reinterpretcast, cebowleratibm, 
yusra.syeda, sfertile, jasonliu, xingxue, hfinkel.
Xiangling_L added a project: LLVM.
Herald added subscribers: llvm-commits, cfe-commits, dexonsmith.
Herald added a project: clang.
Xiangling_L added a parent revision: D74015: [AIX][Frontend] C++ ABI 
customizations for AIX boilerplate.
Xiangling_L planned changes to this revision.

Importantly, this patch provides context and shows where things are going of 
static init of AIX in LLVM. And hope it would help reviewers with its parent 
patch:  D74015 <https://reviews.llvm.org/D74015>.

- Provides no piroirity supoort && disables/ignores three priority related 
attributes: init_priority, ctor attr, dtor attr;
  - '-qunique' in XLC compiler equivalent behavior of emitting sinit and sterm 
functions name using `getUniqueModuleId()` function in LLVM;
  - Add a simple testcase to emit IR sample with sinit80000000, srterm, and 
sterm80000000


Repository:
  rG LLVM Github Monorepo

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/CodeGenFunction.h
  clang/lib/CodeGen/CodeGenModule.h
  clang/lib/CodeGen/ItaniumCXXABI.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/test/CodeGen/aix-priority-attribute.cpp
  clang/test/CodeGen/static-init.cpp
  llvm/include/llvm/ADT/Triple.h

Index: llvm/include/llvm/ADT/Triple.h
===================================================================
--- llvm/include/llvm/ADT/Triple.h
+++ llvm/include/llvm/ADT/Triple.h
@@ -743,7 +743,7 @@
 
   /// Tests whether the target supports comdat
   bool supportsCOMDAT() const {
-    return !isOSBinFormatMachO();
+    return !isOSBinFormatMachO() && !isOSBinFormatXCOFF();
   }
 
   /// Tests whether the target uses emulated TLS as default.
Index: clang/test/CodeGen/static-init.cpp
===================================================================
--- clang/test/CodeGen/static-init.cpp
+++ clang/test/CodeGen/static-init.cpp
@@ -1,8 +1,9 @@
-// RUN: not %clang_cc1 -triple powerpc-ibm-aix-xcoff -S -emit-llvm -x c++ %s \
-// RUN: 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -S -emit-llvm -x c++ < %s \
+// RUN: | FileCheck %s
+
+// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -S -emit-llvm -x c++ < %s \
+// RUN: | FileCheck %s
 
-// RUN: not %clang_cc1 -triple powerpc64-ibm-aix-xcoff -S -emit-llvm -x c++ %s \
-// RUN: 2>&1 | FileCheck %s
 class test {
    int a;
 public:
@@ -12,5 +13,47 @@
 
 test t(1);
 
+// CHECK: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @__sinit80000000_clang_b2e4830f1c9d2d063e5ea946868f3bfd, i8* null }]
+// CHECK: @llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @__sterm80000000_clang_b2e4830f1c9d2d063e5ea946868f3bfd, i8* null }]
+// CHECK: define dso_local void @__cxx_global_var_init() #0 {
+// CHECK: entry:
+// CHECK:   call void @_ZN4testC1Ei(%class.test* @t, i32 1)
+// CHECK:   %0 = call i32 @atexit(void ()* @__dtor_t)
+// CHECK:   ret void
+// CHECK: }
+
+// CHECK: define dso_local void @__dtor_t() #0 {
+// CHECK: entry:
+// CHECK:   call void @_ZN4testD1Ev(%class.test* @t)
+// CHECK:   ret void
+// CHECK: }
+
+// CHECK: declare i32 @atexit(void ()*) #2
+
+// CHECK: define dso_local void @__cxx_global_var_destruct_t() #0 {
+// CHECK: entry:
+// CHECK:   %0 = call i32 @unatexit(void ()* @__dtor_t)
+// CHECK:   %guard.hasSrterm = icmp eq i32 %0, 0
+// CHECK:   br i1 %guard.hasSrterm, label %destruct.check, label %destruct.end
+
+// CHECK: destruct.check:
+// CHECK:   call void @__dtor_t()
+// CHECK:   br label %destruct.end
+
+// CHECK: destruct.end:
+// CHECK:   ret void
+// CHECK: }
+
+// CHECK: declare i32 @unatexit(void ()*) #2
+
+// CHECK: define dso_local void @__sinit80000000_clang_b2e4830f1c9d2d063e5ea946868f3bfd() #0 {
+// CHECK: entry:
+// CHECK:   call void @__cxx_global_var_init()
+// CHECK:   ret void
+// CHECK: }
 
-; CHECK: error in backend: Static initialization has not been fully implemented on XL_Clang ABI yet.
+// CHECK: define dso_local void @__sterm80000000_clang_b2e4830f1c9d2d063e5ea946868f3bfd() #0 {
+// CHECK: entry:
+// CHECK:   call void @__cxx_global_var_destruct_t()
+// CHECK:   ret void
+// CHECK: }
Index: clang/test/CodeGen/aix-priority-attribute.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/aix-priority-attribute.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -x c++ -emit-llvm < %s 2>&1 | \
+// RUN: FileCheck %s
+// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -x c++ -emit-llvm < %s 2>&1 | \
+// RUN: FileCheck %s
+
+int foo() __attribute__((constructor(180)));
+int bar() __attribute__((destructor(180)));
+
+class test {
+   int a;
+public:
+    test(int c) {a = c;}
+    ~test() {a = 0;}
+};
+
+__attribute__ ((init_priority (2000)))
+test t(1);
+
+// CHECK: warning: 'constructor' attribute argument not supported:
+// CHECK: int foo() __attribute__((constructor(180)));
+ 
+// CHECK: warning: 'destructor' attribute argument not supported:
+// check: int bar() __attribute__((destructor(180)));
+
+// CHECK: warning: 'init_priority' attribute argument not supported:
+// CHECK: __attribute__ ((init_priority (2000)))
+
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -6820,7 +6820,11 @@
     handlePassObjectSizeAttr(S, D, AL);
     break;
   case ParsedAttr::AT_Constructor:
-    handleConstructorAttr(S, D, AL);
+    if (S.Context.getTargetInfo().getTriple().isOSAIX())
+      S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
+          << AL << "";
+    else
+      handleConstructorAttr(S, D, AL);
     break;
   case ParsedAttr::AT_CXX11NoReturn:
     handleSimpleAttribute<CXX11NoReturnAttr>(S, D, AL);
@@ -6829,7 +6833,11 @@
     handleDeprecatedAttr(S, D, AL);
     break;
   case ParsedAttr::AT_Destructor:
-    handleDestructorAttr(S, D, AL);
+    if (S.Context.getTargetInfo().getTriple().isOSAIX())
+      S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
+          << AL << "";
+    else
+      handleDestructorAttr(S, D, AL);
     break;
   case ParsedAttr::AT_EnableIf:
     handleEnableIfAttr(S, D, AL);
@@ -7056,7 +7064,11 @@
     handleSimpleAttribute<ConstInitAttr>(S, D, AL);
     break;
   case ParsedAttr::AT_InitPriority:
-    handleInitPriorityAttr(S, D, AL);
+    if (S.Context.getTargetInfo().getTriple().isOSAIX())
+      S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
+          << AL << "";
+    else
+      handleInitPriorityAttr(S, D, AL);
     break;
   case ParsedAttr::AT_Packed:
     handlePackedAttr(S, D, AL);
Index: clang/lib/CodeGen/ItaniumCXXABI.cpp
===================================================================
--- clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -524,7 +524,16 @@
 
   void registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
                           llvm::FunctionCallee dtor,
-                          llvm::Constant *addr) override;
+      			  llvm::Constant *addr) override;
+
+  bool useSinitAndSterm() const override { return true; }
+
+  bool isCXXGlobalInitAndDtorFuncInternal() const override { return false; }
+
+private:
+  void emitCXXGlobalVarDeclDestructFunc(const VarDecl &D,
+                                        llvm::Constant *dtorStub,
+                                        llvm::Constant *addr);
 };
 }
 
@@ -4425,6 +4434,64 @@
 void XLClangCXXABI::registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
                                    llvm::FunctionCallee dtor,
                                    llvm::Constant *addr) {
-  llvm::report_fatal_error("Static initialization has not been fully"
-                           " implemented on XL_Clang ABI yet.");
+  if (D.getTLSKind() != VarDecl::TLS_None)
+    llvm::report_fatal_error("Thread local storage unimplemented on AIX yet.");
+
+  // Create __srterm function for the var decl.
+  llvm::Constant *dtorStub = CGF.createAtExitStub(D, dtor, addr);
+
+  // Register above __srterm with atexit().
+  CGF.registerGlobalDtorWithAtExit(dtorStub);
+
+  // Emit __sterm function to unregister __srterm and call __srterm.
+  emitCXXGlobalVarDeclDestructFunc(D, dtorStub, addr);
+}
+
+void XLClangCXXABI::emitCXXGlobalVarDeclDestructFunc(const VarDecl &D,
+                                                     llvm::Constant *dtorStub,
+				                     llvm::Constant *addr) {
+  llvm::FunctionType *FTy = llvm::FunctionType::get(CGM.VoidTy, false);
+  SmallString<256> FnName;
+  {
+    llvm::raw_svector_ostream Out(FnName);
+    getMangleContext().mangleDynamicDestructor(&D, Out);
+  }
+
+  // Create a variable destruction function.
+  const CGFunctionInfo &FI = CGM.getTypes().arrangeNullaryFunction();
+  llvm::Function *StermFn =
+      CGM.CreateGlobalInitOrDestructFunction(FTy, FnName.str(), FI,
+                                             D.getLocation());
+
+  CodeGenFunction CGF(CGM);
+
+  CGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, StermFn, FI,
+                    FunctionArgList());
+
+  // Unregister the dtorStub.
+  llvm::Value *V = CGF.unregisterGlobalDtorWithUnAtExit(dtorStub);
+
+  llvm::Value *NeedsDestruct = CGF.Builder.CreateIsNull(V, "guard.hasSrterm");
+
+  llvm::BasicBlock *DestructCheckBlock = CGF.createBasicBlock("destruct.check");
+  llvm::BasicBlock *EndBlock = CGF.createBasicBlock("destruct.end");
+
+  // Check if the guard variable is zero.
+  CGF.EmitCXXGuardedInitBranch(NeedsDestruct, DestructCheckBlock, EndBlock,
+                               CodeGenFunction::GuardKind::VariableGuard, &D);
+
+  CGF.EmitBlock(DestructCheckBlock);
+
+  // Emit the call to dtorStub.
+  llvm::CallInst *CI = CGF.Builder.CreateCall(dtorStub);
+
+  // Make sure the call and the callee agree on calling convention.
+  if (llvm::Function *F = cast<llvm::Function>(dtorStub))
+    CI->setCallingConv(F->getCallingConv());
+
+  CGF.EmitBlock(EndBlock);
+
+  CGF.FinishFunction();
+
+  CGM.AddCXXDtorEntry(StermFn);
 }
Index: clang/lib/CodeGen/CodeGenModule.h
===================================================================
--- clang/lib/CodeGen/CodeGenModule.h
+++ clang/lib/CodeGen/CodeGenModule.h
@@ -17,6 +17,7 @@
 #include "CodeGenTypeCache.h"
 #include "CodeGenTypes.h"
 #include "SanitizerMetadata.h"
+#include "clang/AST/Attr.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclOpenMP.h"
@@ -395,6 +396,10 @@
   /// emitted when the translation unit is complete.
   CtorList GlobalDtors;
 
+  /// A unique trailing identifier as a part of sinit/sterm function when
+  /// UserSinitAndSterm 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;
@@ -1044,6 +1049,12 @@
                                 Object);
   }
 
+  /// Add a destructor to the C++ global destructor function.
+  void AddCXXDtorEntry(llvm::FunctionCallee DtorFn) {
+    CXXGlobalDtors.emplace_back(DtorFn.getFunctionType(), DtorFn.getCallee(),
+                                nullptr);
+  }
+
   /// 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/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -3977,6 +3977,9 @@
   /// Call atexit() with function dtorStub.
   void registerGlobalDtorWithAtExit(llvm::Constant *dtorStub);
 
+  /// Call unatexit() with function dtorStub.
+  llvm::Value *unregisterGlobalDtorWithUnAtExit(llvm::Constant *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
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;
@@ -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,18 +272,40 @@
 
 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) &&
+         "atexit has wrong parameter 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(),
-                                /*Local=*/true);
+      CGM.CreateRuntimeFunction(atexitTy, "atexit", llvm::AttributeList());
   if (llvm::Function *atexitFn = dyn_cast<llvm::Function>(atexit.getCallee()))
     atexitFn->setDoesNotThrow();
 
   EmitNounwindRuntimeCall(atexit, dtorStub);
 }
 
+llvm::Value *
+CodeGenFunction::unregisterGlobalDtorWithUnAtExit(llvm::Constant *dtorStub) {
+  // extern "C" int unatexit(void (*f)(void));
+  assert(cast<llvm::Function>(dtorStub)->getFunctionType() ==
+             llvm::FunctionType::get(CGM.VoidTy, false) &&
+         "unatexit has wrong parameter type.");
+
+  llvm::FunctionType *unatexitTy =
+      llvm::FunctionType::get(IntTy, {dtorStub->getType()}, /*isVarArg=*/false);
+
+  llvm::FunctionCallee unatexit =
+      CGM.CreateRuntimeFunction(unatexitTy, "unatexit", llvm::AttributeList());
+  if (llvm::Function *unatexitFn =
+          cast<llvm::Function>(unatexit.getCallee()))
+    unatexitFn->setDoesNotThrow();
+
+  return EmitNounwindRuntimeCall(unatexit, dtorStub);
+}
+
 void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D,
                                          llvm::GlobalVariable *DeclPtr,
                                          bool PerformInit) {
@@ -347,6 +371,9 @@
 
   SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
 
+  if (!getCXXABI().isCXXGlobalInitAndDtorFuncInternal())
+    Fn->setLinkage(llvm::Function::ExternalLinkage);
+
   Fn->setCallingConv(getRuntimeCC());
 
   if (!getLangOpts().Exceptions)
@@ -533,8 +560,28 @@
   CXXThreadLocals.clear();
 }
 
+static std::string getTransformedFileName(llvm::Module &M) {
+  SmallString<128> 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.c_str();
+}
+
 void
 CodeGenModule::EmitCXXGlobalInitFunc() {
+  bool UseSinitAndSterm = getCXXABI().useSinitAndSterm();
+  if (UseSinitAndSterm)
+    GlobalUniqueModuleId = getUniqueModuleId(&getModule()).substr(1);
+
   while (!CXXGlobalInits.empty() && !CXXGlobalInits.back())
     CXXGlobalInits.pop_back();
 
@@ -544,8 +591,11 @@
   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());
@@ -577,45 +627,43 @@
     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>";
-
-  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] = '_';
-  }
-
-  llvm::Function *Fn = CreateGlobalInitOrDestructFunction(
-      FTy, llvm::Twine("_GLOBAL__sub_I_", FileName), FI);
-
-  CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, CXXGlobalInits);
-  AddGlobalCtor(Fn);
-
-  // In OpenCL global init functions must be converted to kernels in order to
-  // be able to launch them from the host.
-  // FIXME: Some more work might be needed to handle destructors correctly.
-  // Current initialization function makes use of function pointers callbacks.
-  // We can't support function pointers especially between host and device.
-  // However it seems global destruction has little meaning without any
-  // dynamic resource allocation on the device and program scope variables are
-  // destroyed by the runtime when program is released.
-  if (getLangOpts().OpenCL) {
-    GenOpenCLArgMetadata(Fn);
-    Fn->setCallingConv(llvm::CallingConv::SPIR_KERNEL);
-  }
+    // Create our global initialization function.
+  if (!CXXGlobalInits.empty()) {
+    // Include the filename in the symbol name. When not using sinit and sterm
+    // functions, including "sub_" matches gcc and makes sure these symbols
+    // appear lexicographically behind the symbols with priority emitted above.
+    std::string FuncSuffix = UseSinitAndSterm
+                               ? GlobalUniqueModuleId
+                               : getTransformedFileName(getModule());
+
+    llvm::Function *Fn = CreateGlobalInitOrDestructFunction(
+        FTy,
+        (UseSinitAndSterm ? "__sinit80000000_clang_" : "_GLOBAL__sub_I_") +
+            FuncSuffix, FI, SourceLocation());
+
+    CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, CXXGlobalInits);
+    AddGlobalCtor(Fn);  
+
+    // In OpenCL global init functions must be converted to kernels in order to
+    // be able to launch them from the host.
+    // FIXME: Some more work might be needed to handle destructors correctly.
+    // Current initialization function makes use of function pointers callbacks.
+    // We can't support function pointers especially between host and device.
+    // However it seems global destruction has little meaning without any
+    // dynamic resource allocation on the device and program scope variables are
+    // destroyed by the runtime when program is released.
+    if (getLangOpts().OpenCL) {
+      GenOpenCLArgMetadata(Fn);
+      Fn->setCallingConv(llvm::CallingConv::SPIR_KERNEL);
+    }
 
-  if (getLangOpts().HIP) {
-    Fn->setCallingConv(llvm::CallingConv::AMDGPU_KERNEL);
-    Fn->addFnAttr("device-init");
-  }
+    if (getLangOpts().HIP) {
+      Fn->setCallingConv(llvm::CallingConv::AMDGPU_KERNEL);
+      Fn->addFnAttr("device-init");
+    }
 
-  CXXGlobalInits.clear();
+    CXXGlobalInits.clear();
+  }  
 }
 
 void CodeGenModule::EmitCXXGlobalDtorFunc() {
@@ -623,14 +671,23 @@
     return;
 
   llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
+  const CGFunctionInfo &FI = getTypes().arrangeNullaryFunction();
+  bool UseSinitAndSterm = getCXXABI().useSinitAndSterm();
 
   // Create our global destructor function.
-  const CGFunctionInfo &FI = getTypes().arrangeNullaryFunction();
-  llvm::Function *Fn =
-      CreateGlobalInitOrDestructFunction(FTy, "_GLOBAL__D_a", FI);
+  llvm::Function *Fn = nullptr;
+  if (UseSinitAndSterm) {
+    std::string FuncSuffix = GlobalUniqueModuleId;
+    Fn = CreateGlobalInitOrDestructFunction(
+        FTy, llvm::Twine("__sterm80000000_clang_") + FuncSuffix, FI,
+        SourceLocation());
+  } else {
+    Fn = CreateGlobalInitOrDestructFunction(FTy, "_GLOBAL__D_a", FI);
+  }
 
   CodeGenFunction(*this).GenerateCXXGlobalDtorsFunc(Fn, CXXGlobalDtors);
   AddGlobalDtor(Fn);
+  CXXGlobalDtors.clear();
 }
 
 /// Emit the code necessary to initialize the given global variable.
@@ -743,7 +800,9 @@
       llvm::Value *Callee;
       llvm::Constant *Arg;
       std::tie(CalleeTy, Callee, Arg) = DtorsAndObjects[e - i - 1];
-      llvm::CallInst *CI = Builder.CreateCall(CalleeTy, Callee, Arg);
+      llvm::CallInst *CI = (Arg == nullptr)
+                               ? Builder.CreateCall(CalleeTy, Callee)
+                               : 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());
Index: clang/lib/CodeGen/CGCXXABI.h
===================================================================
--- clang/lib/CodeGen/CGCXXABI.h
+++ clang/lib/CodeGen/CGCXXABI.h
@@ -107,6 +107,10 @@
 
   virtual bool hasMostDerivedReturn(GlobalDecl GD) const { return false; }
 
+  virtual bool useSinitAndSterm() const { return false; }
+
+  virtual bool isCXXGlobalInitAndDtorFuncInternal() const { return true; }
+
   /// 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
@@ -161,6 +161,7 @@
   void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) override;
   void mangleDynamicAtExitDestructor(const VarDecl *D,
                                      raw_ostream &Out) override;
+  void mangleDynamicDestructor(const VarDecl *D, raw_ostream &Out) override;
   void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
                                  raw_ostream &Out) override;
   void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl,
@@ -5059,6 +5060,13 @@
     Mangler.getStream() << D->getName();
 }
 
+void ItaniumMangleContextImpl::mangleDynamicDestructor(const VarDecl *D,
+                                                       raw_ostream &Out) {
+  // Clang generates these internal-linkage functions as part of its
+  // implementation of the XL_Clang ABI.
+  Out << "__cxx_global_var_destruct_" << *D;
+}
+
 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
@@ -172,6 +172,8 @@
 
   virtual void mangleLambdaSig(const CXXRecordDecl *Lambda, raw_ostream &) = 0;
 
+  virtual void mangleDynamicDestructor(const VarDecl *D, raw_ostream &Out) = 0;
+
   static bool classof(const MangleContext *C) {
     return C->getKind() == MK_Itanium;
   }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to