LLVM  15.0.0git
LowerGlobalDtors.cpp
Go to the documentation of this file.
1 //===-- LowerGlobalDtors.cpp - Lower @llvm.global_dtors -------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// Lower @llvm.global_dtors.
11 ///
12 /// Implement @llvm.global_dtors by creating wrapper functions that are
13 /// registered in @llvm.global_ctors and which contain a call to
14 /// `__cxa_atexit` to register their destructor functions.
15 ///
16 //===----------------------------------------------------------------------===//
17 
19 
20 #include "llvm/IR/Constants.h"
21 #include "llvm/IR/Instructions.h"
22 #include "llvm/IR/Intrinsics.h"
23 #include "llvm/InitializePasses.h"
24 #include "llvm/Pass.h"
25 #include "llvm/Transforms/Utils.h"
27 #include <map>
28 
29 using namespace llvm;
30 
31 #define DEBUG_TYPE "lower-global-dtors"
32 
33 namespace {
34 class LowerGlobalDtorsLegacyPass final : public ModulePass {
35  StringRef getPassName() const override {
36  return "Lower @llvm.global_dtors via `__cxa_atexit`";
37  }
38 
39  void getAnalysisUsage(AnalysisUsage &AU) const override {
40  AU.setPreservesCFG();
42  }
43 
44  bool runOnModule(Module &M) override;
45 
46 public:
47  static char ID;
48  LowerGlobalDtorsLegacyPass() : ModulePass(ID) {
50  }
51 };
52 } // End anonymous namespace
53 
55 INITIALIZE_PASS(LowerGlobalDtorsLegacyPass, DEBUG_TYPE,
56  "Lower @llvm.global_dtors via `__cxa_atexit`", false, false)
57 
59  return new LowerGlobalDtorsLegacyPass();
60 }
61 
62 static bool runImpl(Module &M);
63 bool LowerGlobalDtorsLegacyPass::runOnModule(Module &M) { return runImpl(M); }
64 
67  bool Changed = runImpl(M);
68  if (!Changed)
69  return PreservedAnalyses::all();
70 
73  return PA;
74 }
75 
76 static bool runImpl(Module &M) {
77  GlobalVariable *GV = M.getGlobalVariable("llvm.global_dtors");
78  if (!GV || !GV->hasInitializer())
79  return false;
80 
81  const ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer());
82  if (!InitList)
83  return false;
84 
85  // Validate @llvm.global_dtor's type.
86  auto *ETy = dyn_cast<StructType>(InitList->getType()->getElementType());
87  if (!ETy || ETy->getNumElements() != 3 ||
88  !ETy->getTypeAtIndex(0U)->isIntegerTy() ||
89  !ETy->getTypeAtIndex(1U)->isPointerTy() ||
90  !ETy->getTypeAtIndex(2U)->isPointerTy())
91  return false; // Not (int, ptr, ptr).
92 
93  // Collect the contents of @llvm.global_dtors, ordered by priority. Within a
94  // priority, sequences of destructors with the same associated object are
95  // recorded so that we can register them as a group.
96  std::map<
97  uint16_t,
98  std::vector<std::pair<Constant *, std::vector<Constant *>>>
99  > DtorFuncs;
100  for (Value *O : InitList->operands()) {
101  auto *CS = dyn_cast<ConstantStruct>(O);
102  if (!CS)
103  continue; // Malformed.
104 
105  auto *Priority = dyn_cast<ConstantInt>(CS->getOperand(0));
106  if (!Priority)
107  continue; // Malformed.
108  uint16_t PriorityValue = Priority->getLimitedValue(UINT16_MAX);
109 
110  Constant *DtorFunc = CS->getOperand(1);
111  if (DtorFunc->isNullValue())
112  break; // Found a null terminator, skip the rest.
113 
114  Constant *Associated = CS->getOperand(2);
115  Associated = cast<Constant>(Associated->stripPointerCasts());
116 
117  auto &AtThisPriority = DtorFuncs[PriorityValue];
118  if (AtThisPriority.empty() || AtThisPriority.back().first != Associated) {
119  std::vector<Constant *> NewList;
120  NewList.push_back(DtorFunc);
121  AtThisPriority.push_back(std::make_pair(Associated, NewList));
122  } else {
123  AtThisPriority.back().second.push_back(DtorFunc);
124  }
125  }
126  if (DtorFuncs.empty())
127  return false;
128 
129  // extern "C" int __cxa_atexit(void (*f)(void *), void *p, void *d);
130  LLVMContext &C = M.getContext();
131  PointerType *VoidStar = Type::getInt8PtrTy(C);
132  Type *AtExitFuncArgs[] = {VoidStar};
133  FunctionType *AtExitFuncTy =
134  FunctionType::get(Type::getVoidTy(C), AtExitFuncArgs,
135  /*isVarArg=*/false);
136 
137  FunctionCallee AtExit = M.getOrInsertFunction(
138  "__cxa_atexit",
140  {PointerType::get(AtExitFuncTy, 0), VoidStar, VoidStar},
141  /*isVarArg=*/false));
142 
143  // Declare __dso_local.
144  Type *DsoHandleTy = Type::getInt8Ty(C);
145  Constant *DsoHandle = M.getOrInsertGlobal("__dso_handle", DsoHandleTy, [&] {
146  auto *GV = new GlobalVariable(M, DsoHandleTy, /*isConstant=*/true,
148  "__dso_handle");
150  return GV;
151  });
152 
153  // For each unique priority level and associated symbol, generate a function
154  // to call all the destructors at that level, and a function to register the
155  // first function with __cxa_atexit.
156  for (auto &PriorityAndMore : DtorFuncs) {
157  uint16_t Priority = PriorityAndMore.first;
158  uint64_t Id = 0;
159  auto &AtThisPriority = PriorityAndMore.second;
160  for (auto &AssociatedAndMore : AtThisPriority) {
161  Constant *Associated = AssociatedAndMore.first;
162  auto ThisId = Id++;
163 
164  Function *CallDtors = Function::Create(
165  AtExitFuncTy, Function::PrivateLinkage,
166  "call_dtors" +
167  (Priority != UINT16_MAX ? (Twine(".") + Twine(Priority))
168  : Twine()) +
169  (AtThisPriority.size() > 1 ? Twine("$") + Twine(ThisId)
170  : Twine()) +
171  (!Associated->isNullValue() ? (Twine(".") + Associated->getName())
172  : Twine()),
173  &M);
174  BasicBlock *BB = BasicBlock::Create(C, "body", CallDtors);
176  /*isVarArg=*/false);
177 
178  for (auto Dtor : reverse(AssociatedAndMore.second))
179  CallInst::Create(VoidVoid, Dtor, "", BB);
181 
182  Function *RegisterCallDtors = Function::Create(
183  VoidVoid, Function::PrivateLinkage,
184  "register_call_dtors" +
185  (Priority != UINT16_MAX ? (Twine(".") + Twine(Priority))
186  : Twine()) +
187  (AtThisPriority.size() > 1 ? Twine("$") + Twine(ThisId)
188  : Twine()) +
189  (!Associated->isNullValue() ? (Twine(".") + Associated->getName())
190  : Twine()),
191  &M);
192  BasicBlock *EntryBB = BasicBlock::Create(C, "entry", RegisterCallDtors);
193  BasicBlock *FailBB = BasicBlock::Create(C, "fail", RegisterCallDtors);
194  BasicBlock *RetBB = BasicBlock::Create(C, "return", RegisterCallDtors);
195 
196  Value *Null = ConstantPointerNull::get(VoidStar);
197  Value *Args[] = {CallDtors, Null, DsoHandle};
198  Value *Res = CallInst::Create(AtExit, Args, "call", EntryBB);
199  Value *Cmp = new ICmpInst(*EntryBB, ICmpInst::ICMP_NE, Res,
201  BranchInst::Create(FailBB, RetBB, Cmp, EntryBB);
202 
203  // If `__cxa_atexit` hits out-of-memory, trap, so that we don't misbehave.
204  // This should be very rare, because if the process is running out of
205  // memory before main has even started, something is wrong.
206  CallInst::Create(Intrinsic::getDeclaration(&M, Intrinsic::trap), "",
207  FailBB);
208  new UnreachableInst(C, FailBB);
209 
210  ReturnInst::Create(C, RetBB);
211 
212  // Now register the registration function with @llvm.global_ctors.
213  appendToGlobalCtors(M, RegisterCallDtors, Priority, Associated);
214  }
215  }
216 
217  // Now that we've lowered everything, remove @llvm.global_dtors.
218  GV->eraseFromParent();
219 
220  return true;
221 }
llvm::PreservedAnalyses
A set of analyses that are preserved following a run of a transformation pass.
Definition: PassManager.h:152
llvm::GlobalVariable::eraseFromParent
void eraseFromParent()
eraseFromParent - This method unlinks 'this' from the containing module and deletes it.
Definition: Globals.cpp:451
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:17
M
We currently emits eax Perhaps this is what we really should generate is Is imull three or four cycles eax eax The current instruction priority is based on pattern complexity The former is more complex because it folds a load so the latter will not be emitted Perhaps we should use AddedComplexity to give LEA32r a higher priority We should always try to match LEA first since the LEA matching code does some estimate to determine whether the match is profitable if we care more about code then imull is better It s two bytes shorter than movl leal On a Pentium M
Definition: README.txt:252
llvm::Intrinsic::getDeclaration
Function * getDeclaration(Module *M, ID id, ArrayRef< Type * > Tys=None)
Create or insert an LLVM Function declaration for an intrinsic, and return it.
Definition: Function.cpp:1418
llvm::Type::getInt8PtrTy
static PointerType * getInt8PtrTy(LLVMContext &C, unsigned AS=0)
Definition: Type.cpp:291
llvm::User::operands
op_range operands()
Definition: User.h:242
llvm::ModulePass
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition: Pass.h:248
llvm::GlobalValue::HiddenVisibility
@ HiddenVisibility
The GV is hidden.
Definition: GlobalValue.h:64
llvm::Function
Definition: Function.h:60
Pass.h
llvm::PointerType::get
static PointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
Definition: Type.cpp:727
llvm::initializeLowerGlobalDtorsLegacyPassPass
void initializeLowerGlobalDtorsLegacyPassPass(PassRegistry &)
llvm::GlobalVariable
Definition: GlobalVariable.h:39
llvm::CmpInst::ICMP_NE
@ ICMP_NE
not equal
Definition: InstrTypes.h:741
llvm::FunctionType::get
static FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
Definition: Type.cpp:361
llvm::Type
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
llvm::reverse
auto reverse(ContainerTy &&C, std::enable_if_t< has_rbegin< ContainerTy >::value > *=nullptr)
Definition: STLExtras.h:380
llvm::createLowerGlobalDtorsLegacyPass
ModulePass * createLowerGlobalDtorsLegacyPass()
llvm::Type::getInt8Ty
static IntegerType * getInt8Ty(LLVMContext &C)
Definition: Type.cpp:237
llvm::Type::getInt32Ty
static IntegerType * getInt32Ty(LLVMContext &C)
Definition: Type.cpp:239
llvm::GlobalVariable::hasInitializer
bool hasInitializer() const
Definitions have initializers, declarations don't.
Definition: GlobalVariable.h:91
llvm::BasicBlock
LLVM Basic Block Representation.
Definition: BasicBlock.h:55
llvm::LowerGlobalDtorsPass::run
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
Definition: LowerGlobalDtors.cpp:65
llvm::PassRegistry::getPassRegistry
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
Definition: PassRegistry.cpp:31
Constants.h
llvm::Constant::isNullValue
bool isNullValue() const
Return true if this is the value that would be returned by getNullValue.
Definition: Constants.cpp:76
Intrinsics.h
C
(vector float) vec_cmpeq(*A, *B) C
Definition: README_ALTIVEC.txt:86
llvm::CallInst::Create
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", Instruction *InsertBefore=nullptr)
Definition: Instructions.h:1504
llvm::AnalysisUsage
Represent the analysis usage information of a pass.
Definition: PassAnalysisSupport.h:47
llvm::ConstantArray
ConstantArray - Constant Array Declarations.
Definition: Constants.h:410
Utils.h
llvm::CallingConv::ID
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
llvm::ConstantArray::getType
ArrayType * getType() const
Specialize the getType() method to always return an ArrayType, which reduces the amount of casting ne...
Definition: Constants.h:429
llvm::RISCVFenceField::O
@ O
Definition: RISCVBaseInfo.h:239
LowerGlobalDtors.h
llvm::GlobalVariable::getInitializer
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
Definition: GlobalVariable.h:135
llvm::Constant
This is an important base class in LLVM.
Definition: Constant.h:41
llvm::ICmpInst
This instruction compares its operands according to the predicate given to the constructor.
Definition: Instructions.h:1173
uint64_t
llvm::ConstantPointerNull::get
static ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
Definition: Constants.cpp:1763
llvm::LLVMContext
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:68
llvm::BranchInst::Create
static BranchInst * Create(BasicBlock *IfTrue, Instruction *InsertBefore=nullptr)
Definition: Instructions.h:3142
llvm::PointerType
Class to represent pointers.
Definition: DerivedTypes.h:632
llvm::Function::Create
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
Definition: Function.h:137
llvm::Module
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
INITIALIZE_PASS
INITIALIZE_PASS(LowerGlobalDtorsLegacyPass, DEBUG_TYPE, "Lower @llvm.global_dtors via `__cxa_atexit`", false, false) ModulePass *llvm
Definition: LowerGlobalDtors.cpp:55
llvm::AnalysisUsage::setPreservesCFG
void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition: Pass.cpp:263
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:58
DEBUG_TYPE
#define DEBUG_TYPE
Definition: LowerGlobalDtors.cpp:31
llvm::Value::getType
Type * getType() const
All values are typed, get the type of this value.
Definition: Value.h:255
llvm::CFGAnalyses
Represents analyses that only rely on functions' control flow.
Definition: PassManager.h:113
llvm::BasicBlock::Create
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition: BasicBlock.h:97
llvm::Value::getName
StringRef getName() const
Return a constant reference to the value's name.
Definition: Value.cpp:305
llvm::Constant::stripPointerCasts
const Constant * stripPointerCasts() const
Definition: Constant.h:213
llvm::Twine
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:83
llvm::Constant::getNullValue
static Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
Definition: Constants.cpp:350
uint16_t
llvm::PreservedAnalyses::all
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition: PassManager.h:158
llvm::ReturnInst::Create
static ReturnInst * Create(LLVMContext &C, Value *retVal=nullptr, Instruction *InsertBefore=nullptr)
Definition: Instructions.h:3031
llvm::Type::getVoidTy
static Type * getVoidTy(LLVMContext &C)
Definition: Type.cpp:222
llvm::GlobalValue::PrivateLinkage
@ PrivateLinkage
Like Internal, but omit from symbol table.
Definition: GlobalValue.h:56
Instructions.h
llvm::PreservedAnalyses::preserveSet
void preserveSet()
Mark an analysis set as preserved.
Definition: PassManager.h:188
ModuleUtils.h
llvm::FunctionCallee
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
Definition: DerivedTypes.h:165
runImpl
static bool runImpl(Module &M)
Definition: LowerGlobalDtors.cpp:76
llvm::Pass::getAnalysisUsage
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
Definition: Pass.cpp:97
llvm::AnalysisManager
A container for analyses that lazily runs them and caches their results.
Definition: InstructionSimplify.h:42
BB
Common register allocation spilling lr str ldr sxth r3 ldr mla r4 can lr mov lr str ldr sxth r3 mla r4 and then merge mul and lr str ldr sxth r3 mla r4 It also increase the likelihood the store may become dead bb27 Successors according to LLVM BB
Definition: README.txt:39
llvm::UnreachableInst
This function has undefined behavior.
Definition: Instructions.h:4727
llvm::AMDGPU::HSAMD::Kernel::Key::Args
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
Definition: AMDGPUMetadata.h:394
llvm::appendToGlobalCtors
void appendToGlobalCtors(Module &M, Function *F, int Priority, Constant *Data=nullptr)
Append F to the list of global ctors of module M with the given Priority.
Definition: ModuleUtils.cpp:65
llvm::User::getOperand
Value * getOperand(unsigned i) const
Definition: User.h:169
llvm::GlobalValue::ExternalWeakLinkage
@ ExternalWeakLinkage
ExternalWeak linkage description.
Definition: GlobalValue.h:57
llvm::AMDGPU::VGPRIndexMode::Id
Id
Definition: SIDefines.h:238
llvm::GlobalValue::setVisibility
void setVisibility(VisibilityTypes V)
Definition: GlobalValue.h:240
InitializePasses.h
llvm::Value
LLVM Value Representation.
Definition: Value.h:74
llvm::ArrayType::getElementType
Type * getElementType() const
Definition: DerivedTypes.h:370
llvm::FunctionType
Class to represent function types.
Definition: DerivedTypes.h:103
llvm::Intrinsic::ID
unsigned ID
Definition: TargetTransformInfo.h:38