[llvm] 9c542a5 - Lower `@llvm.global_dtors` using `__cxa_atexit` on MachO
Julian Lettner via llvm-commits
llvm-commits at lists.llvm.org
Mon Mar 14 17:51:44 PDT 2022
Author: Julian Lettner
Date: 2022-03-14T17:51:18-07:00
New Revision: 9c542a5a4e1ba36c24e48185712779df52b7f7a6
URL: https://github.com/llvm/llvm-project/commit/9c542a5a4e1ba36c24e48185712779df52b7f7a6
DIFF: https://github.com/llvm/llvm-project/commit/9c542a5a4e1ba36c24e48185712779df52b7f7a6.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/D121327
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/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 aa91367f65b80..4424db4aa2e41 100644
--- a/llvm/include/llvm/CodeGen/CommandFlags.h
+++ b/llvm/include/llvm/CodeGen/CommandFlags.h
@@ -95,6 +95,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 87758c4983cb2..0743b34eab5df 100644
--- a/llvm/lib/CodeGen/CommandFlags.cpp
+++ b/llvm/lib/CodeGen/CommandFlags.cpp
@@ -74,6 +74,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)
@@ -341,6 +342,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(
@@ -524,6 +531,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 af8c311b605ea..4c335392474c7 100644
--- a/llvm/lib/CodeGen/TargetPassConfig.cpp
+++ b/llvm/lib/CodeGen/TargetPassConfig.cpp
@@ -895,6 +895,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 86%
rename from llvm/lib/Target/WebAssembly/WebAssemblyLowerGlobalDtors.cpp
rename to llvm/lib/Transforms/Utils/LowerGlobalDtors.cpp
index ca6f3f194645d..8a945cf18d9e5 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,33 @@ class LowerGlobalDtors final : public ModulePass {
public:
static char ID;
- LowerGlobalDtors() : ModulePass(ID) {}
+ LowerGlobalDtorsLegacyPass() : ModulePass(ID) {}
};
} // 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/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 llvm-commits
mailing list