forked from OSchip/llvm-project
Reland "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
This commit is contained in:
parent
39aa202aff
commit
64902d335c
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -93,6 +93,8 @@ std::string getTrapFuncName();
|
|||
|
||||
bool getUseCtors();
|
||||
|
||||
bool getLowerGlobalDtorsViaCxaAtExit();
|
||||
|
||||
bool getRelaxELFRelocations();
|
||||
|
||||
bool getDataSections();
|
||||
|
|
|
@ -119,6 +119,9 @@ public:
|
|||
|
||||
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;
|
||||
|
||||
|
|
|
@ -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&);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -58,6 +58,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
|
|||
initializeLiveStacksPass(Registry);
|
||||
initializeLiveVariablesPass(Registry);
|
||||
initializeLocalStackSlotPassPass(Registry);
|
||||
initializeLowerGlobalDtorsLegacyPassPass(Registry);
|
||||
initializeLowerIntrinsicsPass(Registry);
|
||||
initializeMIRAddFSDiscriminatorsPass(Registry);
|
||||
initializeMIRCanonicalizerPass(Registry);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -35,7 +35,6 @@ add_llvm_target(WebAssemblyCodeGen
|
|||
WebAssemblyInstrInfo.cpp
|
||||
WebAssemblyLowerBrUnless.cpp
|
||||
WebAssemblyLowerEmscriptenEHSjLj.cpp
|
||||
WebAssemblyLowerGlobalDtors.cpp
|
||||
WebAssemblyLowerRefTypesIntPtrConv.cpp
|
||||
WebAssemblyMachineFunctionInfo.cpp
|
||||
WebAssemblyMCInstLower.cpp
|
||||
|
|
|
@ -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 &);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -44,6 +44,7 @@ add_llvm_component_library(LLVMTransformUtils
|
|||
LoopUnrollRuntime.cpp
|
||||
LoopUtils.cpp
|
||||
LoopVersioning.cpp
|
||||
LowerGlobalDtors.cpp
|
||||
LowerInvoke.cpp
|
||||
LowerMemIntrinsics.cpp
|
||||
LowerSwitch.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;
|
||||
|
@ -129,15 +141,14 @@ bool LowerGlobalDtors::runOnModule(Module &M) {
|
|||
/*isVarArg=*/false));
|
||||
|
||||
// Declare __dso_local.
|
||||
Constant *DsoHandle = M.getNamedValue("__dso_handle");
|
||||
if (!DsoHandle) {
|
||||
Type *DsoHandleTy = Type::getInt8Ty(C);
|
||||
GlobalVariable *Handle = new GlobalVariable(
|
||||
M, DsoHandleTy, /*isConstant=*/true,
|
||||
GlobalVariable::ExternalWeakLinkage, nullptr, "__dso_handle");
|
||||
Handle->setVisibility(GlobalVariable::HiddenVisibility);
|
||||
DsoHandle = Handle;
|
||||
}
|
||||
Type *DsoHandleTy = Type::getInt8Ty(C);
|
||||
Constant *DsoHandle = M.getOrInsertGlobal("__dso_handle", DsoHandleTy, [&] {
|
||||
auto *GV = new GlobalVariable(M, DsoHandleTy, /*isConstant=*/true,
|
||||
GlobalVariable::ExternalWeakLinkage, nullptr,
|
||||
"__dso_handle");
|
||||
GV->setVisibility(GlobalVariable::HiddenVisibility);
|
||||
return GV;
|
||||
});
|
||||
|
||||
// For each unique priority level and associated symbol, generate a function
|
||||
// to call all the destructors at that level, and a function to register the
|
|
@ -34,6 +34,7 @@ void llvm::initializeTransformUtils(PassRegistry &Registry) {
|
|||
initializeLCSSAWrapperPassPass(Registry);
|
||||
initializeLibCallsShrinkWrapLegacyPassPass(Registry);
|
||||
initializeLoopSimplifyPass(Registry);
|
||||
initializeLowerGlobalDtorsLegacyPassPass(Registry);
|
||||
initializeLowerInvokeLegacyPassPass(Registry);
|
||||
initializeLowerSwitchLegacyPassPass(Registry);
|
||||
initializeNameAnonGlobalLegacyPassPass(Registry);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -10,9 +10,13 @@
|
|||
; CHECK-DEFAULT: .section .ctors.64535,"aw",@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",@progbits
|
||||
|
@ -22,9 +26,7 @@
|
|||
; CHECK-DEFAULT: .section .dtors.64535,"aw",@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()
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
; RUN: opt -passes=lower-global-dtors -S < %s | FileCheck %s
|
||||
|
||||
; Test we do not crash when reusing a pre-existing @__dso_handle global with a
|
||||
; type other than i8, instead make sure we cast it.
|
||||
|
||||
%struct.mach_header = type { i32, i32, i32, i32, i32, i32, i32 }
|
||||
@__dso_handle = external global %struct.mach_header
|
||||
|
||||
declare void @foo()
|
||||
|
||||
@llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [
|
||||
{ i32, void ()*, i8* } { i32 0, void ()* @foo, i8* null }
|
||||
]
|
||||
|
||||
; CHECK: call i32 @__cxa_atexit(void (i8*)* @call_dtors.0, i8* null, i8* bitcast (%struct.mach_header* @__dso_handle to i8*))
|
|
@ -0,0 +1,152 @@
|
|||
; 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()
|
||||
|
||||
@associatedc0 = external global i8
|
||||
@associatedc1 = external global i8
|
||||
@associatedc2 = global i8 42
|
||||
@associatedc3 = global i8 84
|
||||
|
||||
@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [
|
||||
{ i32, void ()*, i8* } { i32 200, void ()* @orig_ctor, i8* null }
|
||||
]
|
||||
|
||||
@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
|
Loading…
Reference in New Issue