[clang] 22570ba - Lower `@llvm.global_dtors` using `__cxa_atexit` on MachO

Julian Lettner via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 17 10:47:21 PDT 2022


Author: Julian Lettner
Date: 2022-03-17T10:47:13-07:00
New Revision: 22570bac694396514fff18dec926558951643fa6

URL: https://github.com/llvm/llvm-project/commit/22570bac694396514fff18dec926558951643fa6
DIFF: https://github.com/llvm/llvm-project/commit/22570bac694396514fff18dec926558951643fa6.diff

LOG: Lower `@llvm.global_dtors` using `__cxa_atexit` on MachO

For MachO, lower `@llvm.global_dtors` into `@llvm_global_ctors` with
`__cxa_atexit` calls to avoid emitting the deprecated `__mod_term_func`.

Reuse the existing `WebAssemblyLowerGlobalDtors.cpp` to accomplish this.

Enable fallback to the old behavior via Clang driver flag
(`-fregister-global-dtors-with-atexit`) or llc / code generation flag
(`-lower-global-dtors-via-cxa-atexit`).  This escape hatch will be
removed in the future.

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

Added: 
    llvm/include/llvm/Transforms/Utils/LowerGlobalDtors.h
    llvm/lib/Transforms/Utils/LowerGlobalDtors.cpp
    llvm/test/Transforms/LowerGlobalDestructors/lower-global-dtors.ll

Modified: 
    clang/lib/CodeGen/BackendUtil.cpp
    llvm/docs/Passes.rst
    llvm/include/llvm/CodeGen/CommandFlags.h
    llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
    llvm/include/llvm/InitializePasses.h
    llvm/include/llvm/LinkAllPasses.h
    llvm/include/llvm/Target/TargetOptions.h
    llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerOptions.h
    llvm/include/llvm/Transforms/Utils.h
    llvm/lib/CodeGen/CodeGen.cpp
    llvm/lib/CodeGen/CommandFlags.cpp
    llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
    llvm/lib/CodeGen/TargetPassConfig.cpp
    llvm/lib/Passes/PassBuilder.cpp
    llvm/lib/Passes/PassRegistry.def
    llvm/lib/Target/WebAssembly/CMakeLists.txt
    llvm/lib/Target/WebAssembly/WebAssembly.h
    llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
    llvm/lib/Transforms/Utils/CMakeLists.txt
    llvm/lib/Transforms/Utils/Utils.cpp
    llvm/test/CodeGen/ARM/ctors_dtors.ll
    llvm/test/CodeGen/X86/2011-08-29-InitOrder.ll

Removed: 
    llvm/lib/Target/WebAssembly/WebAssemblyLowerGlobalDtors.cpp


################################################################################
diff  --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 490f5b3de1ff3..716a565ee7871 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -546,6 +546,8 @@ static bool initTargetOptions(DiagnosticsEngine &Diags,
   Options.BinutilsVersion =
       llvm::TargetMachine::parseBinutilsVersion(CodeGenOpts.BinutilsVersion);
   Options.UseInitArray = CodeGenOpts.UseInitArray;
+  Options.LowerGlobalDtorsViaCxaAtExit =
+      CodeGenOpts.RegisterGlobalDtorsWithAtExit;
   Options.DisableIntegratedAS = CodeGenOpts.DisableIntegratedAS;
   Options.CompressDebugSections = CodeGenOpts.getCompressDebugSections();
   Options.RelaxELFRelocations = CodeGenOpts.RelaxELFRelocations;

diff  --git a/llvm/docs/Passes.rst b/llvm/docs/Passes.rst
index 92f06496b4ef9..7c0666992e8f5 100644
--- a/llvm/docs/Passes.rst
+++ b/llvm/docs/Passes.rst
@@ -876,6 +876,14 @@ This pass expects :ref:`LICM <passes-licm>` to be run before it to hoist
 invariant conditions out of the loop, to make the unswitching opportunity
 obvious.
 
+``-lower-global-dtors``: Lower global destructors
+------------------------------------------------------------
+
+This pass lowers global module destructors (``llvm.global_dtors``) by creating
+wrapper functions that are registered as global constructors in
+``llvm.global_ctors`` and which contain a call to ``__cxa_atexit`` to register
+their destructor functions.
+
 ``-loweratomic``: Lower atomic intrinsics to non-atomic form
 ------------------------------------------------------------
 

diff  --git a/llvm/include/llvm/CodeGen/CommandFlags.h b/llvm/include/llvm/CodeGen/CommandFlags.h
index feb5de5415269..9281ed723854c 100644
--- a/llvm/include/llvm/CodeGen/CommandFlags.h
+++ b/llvm/include/llvm/CodeGen/CommandFlags.h
@@ -93,6 +93,8 @@ std::string getTrapFuncName();
 
 bool getUseCtors();
 
+bool getLowerGlobalDtorsViaCxaAtExit();
+
 bool getRelaxELFRelocations();
 
 bool getDataSections();

diff  --git a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
index 2a35987507446..26bda8d5d239d 100644
--- a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
+++ b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
@@ -119,6 +119,9 @@ class TargetLoweringObjectFileMachO : public TargetLoweringObjectFile {
 
   void Initialize(MCContext &Ctx, const TargetMachine &TM) override;
 
+  MCSection *getStaticDtorSection(unsigned Priority,
+                                  const MCSymbol *KeySym) const override;
+
   /// Emit the module flags that specify the garbage collection information.
   void emitModuleMetadata(MCStreamer &Streamer, Module &M) const override;
 

diff  --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h
index 3a98bacef81d0..82aafe2744184 100644
--- a/llvm/include/llvm/InitializePasses.h
+++ b/llvm/include/llvm/InitializePasses.h
@@ -274,6 +274,7 @@ void initializeLowerAtomicLegacyPassPass(PassRegistry&);
 void initializeLowerConstantIntrinsicsPass(PassRegistry&);
 void initializeLowerEmuTLSPass(PassRegistry&);
 void initializeLowerExpectIntrinsicPass(PassRegistry&);
+void initializeLowerGlobalDtorsLegacyPassPass(PassRegistry &);
 void initializeLowerGuardIntrinsicLegacyPassPass(PassRegistry&);
 void initializeLowerWidenableConditionLegacyPassPass(PassRegistry&);
 void initializeLowerIntrinsicsPass(PassRegistry&);

diff  --git a/llvm/include/llvm/LinkAllPasses.h b/llvm/include/llvm/LinkAllPasses.h
index bd8bea6b99a06..df832d5da05a3 100644
--- a/llvm/include/llvm/LinkAllPasses.h
+++ b/llvm/include/llvm/LinkAllPasses.h
@@ -145,6 +145,7 @@ namespace {
       (void) llvm::createLoopRotatePass();
       (void) llvm::createLowerConstantIntrinsicsPass();
       (void) llvm::createLowerExpectIntrinsicPass();
+      (void) llvm::createLowerGlobalDtorsLegacyPass();
       (void) llvm::createLowerInvokePass();
       (void) llvm::createLowerSwitchPass();
       (void) llvm::createNaryReassociatePass();

diff  --git a/llvm/include/llvm/Target/TargetOptions.h b/llvm/include/llvm/Target/TargetOptions.h
index 4ced520a16a24..8017e39c941ba 100644
--- a/llvm/include/llvm/Target/TargetOptions.h
+++ b/llvm/include/llvm/Target/TargetOptions.h
@@ -130,12 +130,13 @@ namespace llvm {
           HonorSignDependentRoundingFPMathOption(false), NoZerosInBSS(false),
           GuaranteedTailCallOpt(false), StackSymbolOrdering(true),
           EnableFastISel(false), EnableGlobalISel(false), UseInitArray(false),
-          DisableIntegratedAS(false), RelaxELFRelocations(false),
-          FunctionSections(false), DataSections(false),
-          IgnoreXCOFFVisibility(false), XCOFFTracebackTable(true),
-          UniqueSectionNames(true), UniqueBasicBlockSectionNames(false),
-          TrapUnreachable(false), NoTrapAfterNoreturn(false), TLSSize(0),
-          EmulatedTLS(false), ExplicitEmulatedTLS(false), EnableIPRA(false),
+          LowerGlobalDtorsViaCxaAtExit(false), DisableIntegratedAS(false),
+          RelaxELFRelocations(false), FunctionSections(false),
+          DataSections(false), IgnoreXCOFFVisibility(false),
+          XCOFFTracebackTable(true), UniqueSectionNames(true),
+          UniqueBasicBlockSectionNames(false), TrapUnreachable(false),
+          NoTrapAfterNoreturn(false), TLSSize(0), EmulatedTLS(false),
+          ExplicitEmulatedTLS(false), EnableIPRA(false),
           EmitStackSizeSection(false), EnableMachineOutliner(false),
           EnableMachineFunctionSplitter(false), SupportsDefaultOutlining(false),
           EmitAddrsig(false), EmitCallSiteInfo(false),
@@ -245,6 +246,10 @@ namespace llvm {
     /// constructors.
     unsigned UseInitArray : 1;
 
+    /// Use __cxa_atexit to register global destructors; determines how
+    /// llvm.global_dtors is lowered.
+    unsigned LowerGlobalDtorsViaCxaAtExit : 1;
+
     /// Disable the integrated assembler.
     unsigned DisableIntegratedAS : 1;
 

diff  --git a/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerOptions.h b/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerOptions.h
index f019d1c00a358..107f5af3eebaa 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerOptions.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerOptions.h
@@ -17,7 +17,6 @@ enum class AsanDtorKind {
   None,    ///< Do not emit any destructors for ASan
   Global,  ///< Append to llvm.global_dtors
   Invalid, ///< Not a valid destructor Kind.
-  // TODO(dliew): Add more more kinds.
 };
 
 /// Mode of ASan detect stack use after return

diff  --git a/llvm/include/llvm/Transforms/Utils.h b/llvm/include/llvm/Transforms/Utils.h
index 1e9c0a040ad2b..ebd4bd3185733 100644
--- a/llvm/include/llvm/Transforms/Utils.h
+++ b/llvm/include/llvm/Transforms/Utils.h
@@ -155,6 +155,12 @@ FunctionPass *createAssumeSimplifyPass();
 // don't block SCEV.
 //
 Pass *createCanonicalizeFreezeInLoopsPass();
+
+//===----------------------------------------------------------------------===//
+// LowerGlobalDtorsLegacy - Lower @llvm.global_dtors by creating wrapper
+// functions that are registered in @llvm.global_ctors and which contain a call
+// to `__cxa_atexit` to register their destructor functions.
+ModulePass *createLowerGlobalDtorsLegacyPass();
 } // namespace llvm
 
 #endif

diff  --git a/llvm/include/llvm/Transforms/Utils/LowerGlobalDtors.h b/llvm/include/llvm/Transforms/Utils/LowerGlobalDtors.h
new file mode 100644
index 0000000000000..993a6f57361cc
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Utils/LowerGlobalDtors.h
@@ -0,0 +1,28 @@
+//===- LowerGlobalDtors.h - Lower @llvm.global_dtors ----------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass lowers @llvm.global_dtors by creating wrapper functions that are
+// registered in @llvm.global_ctors and which contain a call to `__cxa_atexit`
+// to register their destructor functions.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_TRANSFORMS_UTILS_LOWERGLOBALDTORS_H
+#define LLVM_TRANSFORMS_UTILS_LOWERGLOBALDTORS_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+class LowerGlobalDtorsPass : public PassInfoMixin<LowerGlobalDtorsPass> {
+public:
+  PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
+};
+
+} // namespace llvm
+
+#endif // LLVM_TRANSFORMS_UTILS_LOWERGLOBALDTORS_H

diff  --git a/llvm/lib/CodeGen/CodeGen.cpp b/llvm/lib/CodeGen/CodeGen.cpp
index 7e7fb420e3153..d501838d01456 100644
--- a/llvm/lib/CodeGen/CodeGen.cpp
+++ b/llvm/lib/CodeGen/CodeGen.cpp
@@ -58,6 +58,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
   initializeLiveStacksPass(Registry);
   initializeLiveVariablesPass(Registry);
   initializeLocalStackSlotPassPass(Registry);
+  initializeLowerGlobalDtorsLegacyPassPass(Registry);
   initializeLowerIntrinsicsPass(Registry);
   initializeMIRAddFSDiscriminatorsPass(Registry);
   initializeMIRCanonicalizerPass(Registry);

diff  --git a/llvm/lib/CodeGen/CommandFlags.cpp b/llvm/lib/CodeGen/CommandFlags.cpp
index 761e79eee141b..cdf160db0f022 100644
--- a/llvm/lib/CodeGen/CommandFlags.cpp
+++ b/llvm/lib/CodeGen/CommandFlags.cpp
@@ -79,6 +79,7 @@ CGOPT(bool, StackSymbolOrdering)
 CGOPT(bool, StackRealign)
 CGOPT(std::string, TrapFuncName)
 CGOPT(bool, UseCtors)
+CGOPT(bool, LowerGlobalDtorsViaCxaAtExit)
 CGOPT(bool, RelaxELFRelocations)
 CGOPT_EXP(bool, DataSections)
 CGOPT_EXP(bool, FunctionSections)
@@ -346,6 +347,12 @@ codegen::RegisterCodeGenFlags::RegisterCodeGenFlags() {
                                 cl::init(false));
   CGBINDOPT(UseCtors);
 
+  static cl::opt<bool> LowerGlobalDtorsViaCxaAtExit(
+      "lower-global-dtors-via-cxa-atexit",
+      cl::desc("Lower llvm.global_dtors (global destructors) via __cxa_atexit"),
+      cl::init(true));
+  CGBINDOPT(LowerGlobalDtorsViaCxaAtExit);
+
   static cl::opt<bool> RelaxELFRelocations(
       "relax-elf-relocations",
       cl::desc(
@@ -529,6 +536,7 @@ codegen::InitTargetOptionsFromCodeGenFlags(const Triple &TheTriple) {
   Options.GuaranteedTailCallOpt = getEnableGuaranteedTailCallOpt();
   Options.StackSymbolOrdering = getStackSymbolOrdering();
   Options.UseInitArray = !getUseCtors();
+  Options.LowerGlobalDtorsViaCxaAtExit = getLowerGlobalDtorsViaCxaAtExit();
   Options.RelaxELFRelocations = getRelaxELFRelocations();
   Options.DataSections =
       getExplicitDataSections().getValueOr(TheTriple.hasDefaultDataSections());

diff  --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index 0853c7a34354b..3b21e945d8def 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -1176,6 +1176,15 @@ void TargetLoweringObjectFileMachO::Initialize(MCContext &Ctx,
       dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4;
 }
 
+MCSection *TargetLoweringObjectFileMachO::getStaticDtorSection(
+    unsigned Priority, const MCSymbol *KeySym) const {
+  // TODO(yln): Remove -lower-global-dtors-via-cxa-atexit fallback flag
+  // (LowerGlobalDtorsViaCxaAtExit) and always issue a fatal error here.
+  if (TM->Options.LowerGlobalDtorsViaCxaAtExit)
+    report_fatal_error("@llvm.global_dtors should have been lowered already");
+  return StaticDtorSection;
+}
+
 void TargetLoweringObjectFileMachO::emitModuleMetadata(MCStreamer &Streamer,
                                                        Module &M) const {
   // Emit the linker options if present.
@@ -2175,8 +2184,7 @@ MCSection *TargetLoweringObjectFileWasm::getStaticCtorSection(
 
 MCSection *TargetLoweringObjectFileWasm::getStaticDtorSection(
     unsigned Priority, const MCSymbol *KeySym) const {
-  llvm_unreachable("@llvm.global_dtors should have been lowered already");
-  return nullptr;
+  report_fatal_error("@llvm.global_dtors should have been lowered already");
 }
 
 //===----------------------------------------------------------------------===//

diff  --git a/llvm/lib/CodeGen/TargetPassConfig.cpp b/llvm/lib/CodeGen/TargetPassConfig.cpp
index 4ccb96d49e0ad..1f3ef0e38996e 100644
--- a/llvm/lib/CodeGen/TargetPassConfig.cpp
+++ b/llvm/lib/CodeGen/TargetPassConfig.cpp
@@ -894,6 +894,12 @@ void TargetPassConfig::addIRPasses() {
   addPass(&ShadowStackGCLoweringID);
   addPass(createLowerConstantIntrinsicsPass());
 
+  // For MachO, lower @llvm.global_dtors into @llvm_global_ctors with
+  // __cxa_atexit() calls to avoid emitting the deprecated __mod_term_func.
+  if (TM->getTargetTriple().isOSBinFormatMachO() &&
+      TM->Options.LowerGlobalDtorsViaCxaAtExit)
+    addPass(createLowerGlobalDtorsLegacyPass());
+
   // Make sure that no unreachable blocks are instruction selected.
   addPass(createUnreachableBlockEliminationPass());
 

diff  --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 4f8cc62559345..05efe90846d13 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -230,6 +230,7 @@
 #include "llvm/Transforms/Utils/LibCallsShrinkWrap.h"
 #include "llvm/Transforms/Utils/LoopSimplify.h"
 #include "llvm/Transforms/Utils/LoopVersioning.h"
+#include "llvm/Transforms/Utils/LowerGlobalDtors.h"
 #include "llvm/Transforms/Utils/LowerInvoke.h"
 #include "llvm/Transforms/Utils/LowerSwitch.h"
 #include "llvm/Transforms/Utils/Mem2Reg.h"

diff  --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index dcdf99cea5cb5..e0780f5ee845f 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -76,6 +76,7 @@ MODULE_PASS("invalidate<all>", InvalidateAllAnalysesPass())
 MODULE_PASS("ipsccp", IPSCCPPass())
 MODULE_PASS("iroutliner", IROutlinerPass())
 MODULE_PASS("print-ir-similarity", IRSimilarityAnalysisPrinterPass(dbgs()))
+MODULE_PASS("lower-global-dtors", LowerGlobalDtorsPass())
 MODULE_PASS("lowertypetests", LowerTypeTestsPass())
 MODULE_PASS("metarenamer", MetaRenamerPass())
 MODULE_PASS("mergefunc", MergeFunctionsPass())

diff  --git a/llvm/lib/Target/WebAssembly/CMakeLists.txt b/llvm/lib/Target/WebAssembly/CMakeLists.txt
index c8216aacb59e8..e44ff54d04f96 100644
--- a/llvm/lib/Target/WebAssembly/CMakeLists.txt
+++ b/llvm/lib/Target/WebAssembly/CMakeLists.txt
@@ -35,7 +35,6 @@ add_llvm_target(WebAssemblyCodeGen
   WebAssemblyInstrInfo.cpp
   WebAssemblyLowerBrUnless.cpp
   WebAssemblyLowerEmscriptenEHSjLj.cpp
-  WebAssemblyLowerGlobalDtors.cpp
   WebAssemblyLowerRefTypesIntPtrConv.cpp
   WebAssemblyMachineFunctionInfo.cpp
   WebAssemblyMCInstLower.cpp

diff  --git a/llvm/lib/Target/WebAssembly/WebAssembly.h b/llvm/lib/Target/WebAssembly/WebAssembly.h
index 803786e0c9c25..d7cd6e6f6f000 100644
--- a/llvm/lib/Target/WebAssembly/WebAssembly.h
+++ b/llvm/lib/Target/WebAssembly/WebAssembly.h
@@ -26,7 +26,6 @@ class FunctionPass;
 
 // LLVM IR passes.
 ModulePass *createWebAssemblyLowerEmscriptenEHSjLj();
-ModulePass *createWebAssemblyLowerGlobalDtors();
 ModulePass *createWebAssemblyAddMissingPrototypes();
 ModulePass *createWebAssemblyFixFunctionBitcasts();
 FunctionPass *createWebAssemblyOptimizeReturned();
@@ -61,7 +60,6 @@ ModulePass *createWebAssemblyMCLowerPrePass();
 // PassRegistry initialization declarations.
 void initializeWebAssemblyAddMissingPrototypesPass(PassRegistry &);
 void initializeWebAssemblyLowerEmscriptenEHSjLjPass(PassRegistry &);
-void initializeLowerGlobalDtorsPass(PassRegistry &);
 void initializeFixFunctionBitcastsPass(PassRegistry &);
 void initializeOptimizeReturnedPass(PassRegistry &);
 void initializeWebAssemblyArgumentMovePass(PassRegistry &);

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
index 85014b631a078..cd3b06b1eda6c 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
@@ -25,6 +25,7 @@
 #include "llvm/CodeGen/RegAllocRegistry.h"
 #include "llvm/CodeGen/TargetPassConfig.h"
 #include "llvm/IR/Function.h"
+#include "llvm/InitializePasses.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/Target/TargetOptions.h"
@@ -56,7 +57,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeWebAssemblyTarget() {
   auto &PR = *PassRegistry::getPassRegistry();
   initializeWebAssemblyAddMissingPrototypesPass(PR);
   initializeWebAssemblyLowerEmscriptenEHSjLjPass(PR);
-  initializeLowerGlobalDtorsPass(PR);
+  initializeLowerGlobalDtorsLegacyPassPass(PR);
   initializeFixFunctionBitcastsPass(PR);
   initializeOptimizeReturnedPass(PR);
   initializeWebAssemblyArgumentMovePass(PR);
@@ -412,7 +413,7 @@ void WebAssemblyPassConfig::addIRPasses() {
   addPass(createWebAssemblyAddMissingPrototypes());
 
   // Lower .llvm.global_dtors into .llvm_global_ctors with __cxa_atexit calls.
-  addPass(createWebAssemblyLowerGlobalDtors());
+  addPass(createLowerGlobalDtorsLegacyPass());
 
   // Fix function bitcasts, as WebAssembly requires caller and callee signatures
   // to match.

diff  --git a/llvm/lib/Transforms/Utils/CMakeLists.txt b/llvm/lib/Transforms/Utils/CMakeLists.txt
index ca442d89b9804..58eddb7dcbb8d 100644
--- a/llvm/lib/Transforms/Utils/CMakeLists.txt
+++ b/llvm/lib/Transforms/Utils/CMakeLists.txt
@@ -44,6 +44,7 @@ add_llvm_component_library(LLVMTransformUtils
   LoopUnrollRuntime.cpp
   LoopUtils.cpp
   LoopVersioning.cpp
+  LowerGlobalDtors.cpp
   LowerInvoke.cpp
   LowerMemIntrinsics.cpp
   LowerSwitch.cpp

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerGlobalDtors.cpp b/llvm/lib/Transforms/Utils/LowerGlobalDtors.cpp
similarity index 85%
rename from llvm/lib/Target/WebAssembly/WebAssemblyLowerGlobalDtors.cpp
rename to llvm/lib/Transforms/Utils/LowerGlobalDtors.cpp
index ca6f3f194645d..c4c09aaebac1a 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerGlobalDtors.cpp
+++ b/llvm/lib/Transforms/Utils/LowerGlobalDtors.cpp
@@ -1,4 +1,4 @@
-//===-- WebAssemblyLowerGlobalDtors.cpp - Lower @llvm.global_dtors --------===//
+//===-- LowerGlobalDtors.cpp - Lower @llvm.global_dtors -------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -9,33 +9,31 @@
 /// \file
 /// Lower @llvm.global_dtors.
 ///
-/// WebAssembly doesn't have a builtin way to invoke static destructors.
 /// Implement @llvm.global_dtors by creating wrapper functions that are
 /// registered in @llvm.global_ctors and which contain a call to
 /// `__cxa_atexit` to register their destructor functions.
 ///
 //===----------------------------------------------------------------------===//
 
-#include "WebAssembly.h"
-#include "llvm/ADT/MapVector.h"
+#include "llvm/Transforms/Utils/LowerGlobalDtors.h"
+
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/Intrinsics.h"
-#include "llvm/IR/Module.h"
+#include "llvm/InitializePasses.h"
 #include "llvm/Pass.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/Utils.h"
 #include "llvm/Transforms/Utils/ModuleUtils.h"
 #include <map>
 
 using namespace llvm;
 
-#define DEBUG_TYPE "wasm-lower-global-dtors"
+#define DEBUG_TYPE "lower-global-dtors"
 
 namespace {
-class LowerGlobalDtors final : public ModulePass {
+class LowerGlobalDtorsLegacyPass final : public ModulePass {
   StringRef getPassName() const override {
-    return "WebAssembly Lower @llvm.global_dtors";
+    return "Lower @llvm.global_dtors via `__cxa_atexit`";
   }
 
   void getAnalysisUsage(AnalysisUsage &AU) const override {
@@ -47,21 +45,35 @@ class LowerGlobalDtors final : public ModulePass {
 
 public:
   static char ID;
-  LowerGlobalDtors() : ModulePass(ID) {}
+  LowerGlobalDtorsLegacyPass() : ModulePass(ID) {
+    initializeLowerGlobalDtorsLegacyPassPass(*PassRegistry::getPassRegistry());
+  }
 };
 } // End anonymous namespace
 
-char LowerGlobalDtors::ID = 0;
-INITIALIZE_PASS(LowerGlobalDtors, DEBUG_TYPE,
-                "Lower @llvm.global_dtors for WebAssembly", false, false)
+char LowerGlobalDtorsLegacyPass::ID = 0;
+INITIALIZE_PASS(LowerGlobalDtorsLegacyPass, DEBUG_TYPE,
+                "Lower @llvm.global_dtors via `__cxa_atexit`", false, false)
 
-ModulePass *llvm::createWebAssemblyLowerGlobalDtors() {
-  return new LowerGlobalDtors();
+ModulePass *llvm::createLowerGlobalDtorsLegacyPass() {
+  return new LowerGlobalDtorsLegacyPass();
 }
 
-bool LowerGlobalDtors::runOnModule(Module &M) {
-  LLVM_DEBUG(dbgs() << "********** Lower Global Destructors **********\n");
+static bool runImpl(Module &M);
+bool LowerGlobalDtorsLegacyPass::runOnModule(Module &M) { return runImpl(M); }
+
+PreservedAnalyses LowerGlobalDtorsPass::run(Module &M,
+                                            ModuleAnalysisManager &AM) {
+  bool Changed = runImpl(M);
+  if (!Changed)
+    return PreservedAnalyses::all();
+
+  PreservedAnalyses PA;
+  PA.preserveSet<CFGAnalyses>();
+  return PA;
+}
 
+static bool runImpl(Module &M) {
   GlobalVariable *GV = M.getGlobalVariable("llvm.global_dtors");
   if (!GV || !GV->hasInitializer())
     return false;

diff  --git a/llvm/lib/Transforms/Utils/Utils.cpp b/llvm/lib/Transforms/Utils/Utils.cpp
index 43eb5c87aceed..f34f2df971b1b 100644
--- a/llvm/lib/Transforms/Utils/Utils.cpp
+++ b/llvm/lib/Transforms/Utils/Utils.cpp
@@ -34,6 +34,7 @@ void llvm::initializeTransformUtils(PassRegistry &Registry) {
   initializeLCSSAWrapperPassPass(Registry);
   initializeLibCallsShrinkWrapLegacyPassPass(Registry);
   initializeLoopSimplifyPass(Registry);
+  initializeLowerGlobalDtorsLegacyPassPass(Registry);
   initializeLowerInvokeLegacyPassPass(Registry);
   initializeLowerSwitchLegacyPassPass(Registry);
   initializeNameAnonGlobalLegacyPassPass(Registry);

diff  --git a/llvm/test/CodeGen/ARM/ctors_dtors.ll b/llvm/test/CodeGen/ARM/ctors_dtors.ll
index 1320ee2285140..5778d3634e27d 100644
--- a/llvm/test/CodeGen/ARM/ctors_dtors.ll
+++ b/llvm/test/CodeGen/ARM/ctors_dtors.ll
@@ -1,9 +1,15 @@
 ; RUN: llc < %s -mtriple=arm-apple-darwin  | FileCheck %s -check-prefix=DARWIN
+; RUN: llc < %s -mtriple=arm-apple-darwin -lower-global-dtors-via-cxa-atexit=false  | FileCheck %s -check-prefix=DARWIN-OLD
 ; RUN: llc < %s -mtriple=arm-linux-gnu -target-abi=apcs  | FileCheck %s -check-prefix=ELF
 ; RUN: llc < %s -mtriple=arm-linux-gnueabi | FileCheck %s -check-prefix=GNUEABI
 
+; DARWIN: l_register_call_dtors:
+; DARWIN: bl	___cxa_atexit
 ; DARWIN: .section	__DATA,__mod_init_func,mod_init_funcs
-; DARWIN: .section	__DATA,__mod_term_func,mod_term_funcs
+; DARWIN-NOT: __mod_term_func
+
+; DARWIN-OLD: .section	__DATA,__mod_init_func,mod_init_funcs
+; DARWIN-OLD: .section	__DATA,__mod_term_func,mod_term_funcs
 
 ; ELF: .section .ctors,"aw",%progbits
 ; ELF: .section .dtors,"aw",%progbits

diff  --git a/llvm/test/CodeGen/X86/2011-08-29-InitOrder.ll b/llvm/test/CodeGen/X86/2011-08-29-InitOrder.ll
index 8c0075da03065..6754ae9fb14a1 100644
--- a/llvm/test/CodeGen/X86/2011-08-29-InitOrder.ll
+++ b/llvm/test/CodeGen/X86/2011-08-29-InitOrder.ll
@@ -10,9 +10,13 @@
 ; CHECK-DEFAULT: .section        .ctors.64535,"aw", at progbits
 ; CHECK-DEFAULT: .long construct_1
 
-; CHECK-DARWIN: .long _construct_1
+; CHECK-DARWIN-LABEL: .section	__DATA,__mod_init_func,mod_init_funcs
+; CHECK-DARWIN:      .long _construct_1
+; CHECK-DARWIN-NEXT: .long l_register_call_dtors.1000
 ; CHECK-DARWIN-NEXT: .long _construct_2
+; CHECK-DARWIN-NEXT: .long l_register_call_dtors.2000
 ; CHECK-DARWIN-NEXT: .long _construct_3
+; CHECK-DARWIN-NEXT: .long l_register_call_dtors.3000
 
 @llvm.global_dtors = appending global [3 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 2000, void ()* @destruct_2, i8* null }, { i32, void ()*, i8* } { i32 1000, void ()* @destruct_1, i8* null }, { i32, void ()*, i8* } { i32 3000, void ()* @destruct_3, i8* null }]
 ; CHECK-DEFAULT: .section        .dtors.62535,"aw", at progbits
@@ -22,9 +26,7 @@
 ; CHECK-DEFAULT: .section        .dtors.64535,"aw", at progbits
 ; CHECK-DEFAULT: .long destruct_1
 
-; CHECK-DARWIN:      .long _destruct_1
-; CHECK-DARWIN-NEXT: .long _destruct_2
-; CHECK-DARWIN-NEXT: .long _destruct_3
+; CHECK-DARWIN-NOT: mod_term_func
 
 declare void @construct_1()
 declare void @construct_2()

diff  --git a/llvm/test/Transforms/LowerGlobalDestructors/lower-global-dtors.ll b/llvm/test/Transforms/LowerGlobalDestructors/lower-global-dtors.ll
new file mode 100644
index 0000000000000..b950fa1a91c11
--- /dev/null
+++ b/llvm/test/Transforms/LowerGlobalDestructors/lower-global-dtors.ll
@@ -0,0 +1,156 @@
+; RUN: opt        -lower-global-dtors -S < %s | FileCheck %s --implicit-check-not=llvm.global_dtors
+; RUN: opt -passes=lower-global-dtors -S < %s | FileCheck %s --implicit-check-not=llvm.global_dtors
+
+; Test that @llvm.global_dtors is properly lowered into @llvm.global_ctors,
+; grouping dtor calls by priority and associated symbol.
+
+declare void @orig_ctor()
+declare void @orig_dtor0()
+declare void @orig_dtor1a()
+declare void @orig_dtor1b()
+declare void @orig_dtor1c0()
+declare void @orig_dtor1c1a()
+declare void @orig_dtor1c1b()
+declare void @orig_dtor1c2a()
+declare void @orig_dtor1c2b()
+declare void @orig_dtor1c3()
+declare void @orig_dtor1d()
+declare void @orig_dtor65535()
+declare void @orig_dtor65535c0()
+declare void @after_the_null()
+
+ at associatedc0 = external global i8
+ at associatedc1 = external global i8
+ at associatedc2 = global i8 42
+ at associatedc3 = global i8 84
+
+ at llvm.global_ctors = appending global
+[1 x { i32, void ()*, i8* }]
+[
+  { i32, void ()*, i8* } { i32 200, void ()* @orig_ctor, i8* null }
+]
+
+ at llvm.global_dtors = appending global
+[14 x { i32, void ()*, i8* }]
+[
+  { i32, void ()*, i8* } { i32 0, void ()* @orig_dtor0, i8* null },
+  { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1a, i8* null },
+  { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1b, i8* null },
+  { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1c0, i8* @associatedc0 },
+  { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1c1a, i8* @associatedc1 },
+  { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1c1b, i8* @associatedc1 },
+  { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1c2a, i8* @associatedc2 },
+  { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1c2b, i8* @associatedc2 },
+  { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1c3, i8* @associatedc3 },
+  { i32, void ()*, i8* } { i32 1, void ()* @orig_dtor1d, i8* null },
+  { i32, void ()*, i8* } { i32 65535, void ()* @orig_dtor65535c0, i8* @associatedc0 },
+  { i32, void ()*, i8* } { i32 65535, void ()* @orig_dtor65535, i8* null },
+  { i32, void ()*, i8* } { i32 65535, void ()* null, i8* null },
+  { i32, void ()*, i8* } { i32 65535, void ()* @after_the_null, i8* null }
+]
+
+; CHECK: @associatedc0 = external global i8
+; CHECK: @associatedc1 = external global i8
+; CHECK: @associatedc2 = global i8 42
+; CHECK: @associatedc3 = global i8 84
+; CHECK: @__dso_handle = extern_weak hidden constant i8
+
+; CHECK-LABEL: @llvm.global_ctors = appending global [10 x { i32, void ()*, i8* }] [
+; CHECK-SAME:  { i32, void ()*, i8* } { i32 200, void ()* @orig_ctor, i8* null },
+; CHECK-SAME:  { i32, void ()*, i8* } { i32 0, void ()* @register_call_dtors.0, i8* null },
+; CHECK-SAME:  { i32, void ()*, i8* } { i32 1, void ()* @"register_call_dtors.1$0", i8* null },
+; CHECK-SAME:  { i32, void ()*, i8* } { i32 1, void ()* @"register_call_dtors.1$1.associatedc0", i8* @associatedc0 },
+; CHECK-SAME:  { i32, void ()*, i8* } { i32 1, void ()* @"register_call_dtors.1$2.associatedc1", i8* @associatedc1 },
+; CHECK-SAME:  { i32, void ()*, i8* } { i32 1, void ()* @"register_call_dtors.1$3.associatedc2", i8* @associatedc2 },
+; CHECK-SAME:  { i32, void ()*, i8* } { i32 1, void ()* @"register_call_dtors.1$4.associatedc3", i8* @associatedc3 },
+; CHECK-SAME:  { i32, void ()*, i8* } { i32 1, void ()* @"register_call_dtors.1$5", i8* null },
+; CHECK-SAME:  { i32, void ()*, i8* } { i32 65535, void ()* @"register_call_dtors$0.associatedc0", i8* @associatedc0 },
+; CHECK-SAME:  { i32, void ()*, i8* } { i32 65535, void ()* @"register_call_dtors$1", i8* null }]
+
+; CHECK: declare void @orig_ctor()
+; CHECK: declare void @orig_dtor0()
+; --- other dtors here ---
+; CHECK: declare void @after_the_null()
+
+; CHECK: declare i32 @__cxa_atexit(void (i8*)*, i8*, i8*)
+
+; CHECK-LABEL: define private void @call_dtors.0(i8* %0)
+; CHECK:       call void @orig_dtor0()
+; CHECK-NEXT:  ret void
+
+; CHECK-LABEL: define private void @register_call_dtors.0()
+; CHECK:       %call = call i32 @__cxa_atexit(void (i8*)* @call_dtors.0, i8* null, i8* @__dso_handle)
+; CHECK-NEXT:  %0 = icmp ne i32 %call, 0
+; CHECK-NEXT:  br i1 %0, label %fail, label %return
+; CHECK-EMPTY:
+; CHECK-NEXT:  fail:
+; CHECK-NEXT:    call void @llvm.trap()
+; CHECK-NEXT:    unreachable
+; CHECK-EMPTY:
+; CHECK-NEXT:  return:
+; CHECK-NEXT:    ret void
+
+; CHECK-LABEL: define private void @"call_dtors.1$0"(i8* %0)
+; CHECK:       call void @orig_dtor1b()
+; CHECK-NEXT:  call void @orig_dtor1a()
+; CHECK-NEXT:  ret void
+
+; CHECK-LABEL: define private void @"register_call_dtors.1$0"()
+; CHECK:       %call = call i32 @__cxa_atexit(void (i8*)* @"call_dtors.1$0", i8* null, i8* @__dso_handle)
+
+; CHECK-LABEL: define private void @"call_dtors.1$1.associatedc0"(i8* %0)
+; CHECK:       call void @orig_dtor1c0()
+; CHECK-NEXT:  ret void
+
+; CHECK-LABEL: define private void @"register_call_dtors.1$1.associatedc0"()
+; CHECK:       %call = call i32 @__cxa_atexit(void (i8*)* @"call_dtors.1$1.associatedc0", i8* null, i8* @__dso_handle)
+
+; CHECK-LABEL: define private void @"call_dtors.1$2.associatedc1"(i8* %0)
+; CHECK:       call void @orig_dtor1c1b()
+; CHECK-NEXT:  call void @orig_dtor1c1a()
+; CHECK-NEXT:  ret void
+
+; CHECK-LABEL: define private void @"register_call_dtors.1$2.associatedc1"()
+; CHECK:       %call = call i32 @__cxa_atexit(void (i8*)* @"call_dtors.1$2.associatedc1", i8* null, i8* @__dso_handle)
+
+; CHECK-LABEL: define private void @"call_dtors.1$3.associatedc2"(i8* %0)
+; CHECK:       call void @orig_dtor1c2b()
+; CHECK-NEXT:  call void @orig_dtor1c2a()
+; CHECK-NEXT:  ret void
+
+; CHECK-LABEL: define private void @"register_call_dtors.1$3.associatedc2"()
+; CHECK:       %call = call i32 @__cxa_atexit(void (i8*)* @"call_dtors.1$3.associatedc2", i8* null, i8* @__dso_handle)
+
+; CHECK-LABEL: define private void @"call_dtors.1$4.associatedc3"(i8* %0)
+; CHECK:       call void @orig_dtor1c3()
+; CHECK-NEXT:  ret void
+
+; CHECK-LABEL: define private void @"register_call_dtors.1$4.associatedc3"()
+; CHECK:       %call = call i32 @__cxa_atexit(void (i8*)* @"call_dtors.1$4.associatedc3", i8* null, i8* @__dso_handle)
+
+; CHECK-LABEL: define private void @"call_dtors.1$5"(i8* %0)
+; CHECK:       call void @orig_dtor1d()
+; CHECK-NEXT:  ret void
+
+; CHECK-LABEL: define private void @"register_call_dtors.1$5"()
+; CHECK:       %call = call i32 @__cxa_atexit(void (i8*)* @"call_dtors.1$5", i8* null, i8* @__dso_handle)
+
+; CHECK-LABEL: define private void @"call_dtors$0.associatedc0"(i8* %0)
+; CHECK:       call void @orig_dtor65535c0()
+; CHECK-NEXT:  ret void
+
+; CHECK-LABEL: define private void @"register_call_dtors$0.associatedc0"()
+; CHECK:       %call = call i32 @__cxa_atexit(void (i8*)* @"call_dtors$0.associatedc0", i8* null, i8* @__dso_handle)
+
+; CHECK-LABEL: define private void @"call_dtors$1"(i8* %0)
+; CHECK:       call void @orig_dtor65535()
+; CHECK-NEXT:  ret void
+
+; CHECK-LABEL: define private void @"register_call_dtors$1"()
+; CHECK:       %call = call i32 @__cxa_atexit(void (i8*)* @"call_dtors$1", i8* null, i8* @__dso_handle)
+
+
+; This function is listed after the null terminator, so it should
+; be excluded.
+
+; CHECK-NOT: after_the_null


        


More information about the cfe-commits mailing list