LLVM  14.0.0git
WebAssemblyLowerGlobalDtors.cpp
Go to the documentation of this file.
1 //===-- WebAssemblyLowerGlobalDtors.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 /// WebAssembly doesn't have a builtin way to invoke static destructors.
13 /// Implement @llvm.global_dtors by creating wrapper functions that are
14 /// registered in @llvm.global_ctors and which contain a call to
15 /// `__cxa_atexit` to register their destructor functions.
16 ///
17 //===----------------------------------------------------------------------===//
18 
19 #include "WebAssembly.h"
20 #include "llvm/ADT/MapVector.h"
21 #include "llvm/IR/Constants.h"
22 #include "llvm/IR/Instructions.h"
23 #include "llvm/IR/Intrinsics.h"
24 #include "llvm/IR/Module.h"
25 #include "llvm/Pass.h"
26 #include "llvm/Support/Debug.h"
29 using namespace llvm;
30 
31 #define DEBUG_TYPE "wasm-lower-global-dtors"
32 
33 namespace {
34 class LowerGlobalDtors final : public ModulePass {
35  StringRef getPassName() const override {
36  return "WebAssembly Lower @llvm.global_dtors";
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  LowerGlobalDtors() : ModulePass(ID) {}
49 };
50 } // End anonymous namespace
51 
52 char LowerGlobalDtors::ID = 0;
53 INITIALIZE_PASS(LowerGlobalDtors, DEBUG_TYPE,
54  "Lower @llvm.global_dtors for WebAssembly", false, false)
55 
57  return new LowerGlobalDtors();
58 }
59 
60 bool LowerGlobalDtors::runOnModule(Module &M) {
61  LLVM_DEBUG(dbgs() << "********** Lower Global Destructors **********\n");
62 
63  GlobalVariable *GV = M.getGlobalVariable("llvm.global_dtors");
64  if (!GV || !GV->hasInitializer())
65  return false;
66 
67  const ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer());
68  if (!InitList)
69  return false;
70 
71  // Sanity-check @llvm.global_dtor's type.
72  auto *ETy = dyn_cast<StructType>(InitList->getType()->getElementType());
73  if (!ETy || ETy->getNumElements() != 3 ||
74  !ETy->getTypeAtIndex(0U)->isIntegerTy() ||
75  !ETy->getTypeAtIndex(1U)->isPointerTy() ||
76  !ETy->getTypeAtIndex(2U)->isPointerTy())
77  return false; // Not (int, ptr, ptr).
78 
79  // Collect the contents of @llvm.global_dtors, ordered by priority. Within a
80  // priority, sequences of destructors with the same associated object are
81  // recorded so that we can register them as a group.
82  std::map<
83  uint16_t,
84  std::vector<std::pair<Constant *, std::vector<Constant *>>>
85  > DtorFuncs;
86  for (Value *O : InitList->operands()) {
87  auto *CS = dyn_cast<ConstantStruct>(O);
88  if (!CS)
89  continue; // Malformed.
90 
91  auto *Priority = dyn_cast<ConstantInt>(CS->getOperand(0));
92  if (!Priority)
93  continue; // Malformed.
94  uint16_t PriorityValue = Priority->getLimitedValue(UINT16_MAX);
95 
96  Constant *DtorFunc = CS->getOperand(1);
97  if (DtorFunc->isNullValue())
98  break; // Found a null terminator, skip the rest.
99 
100  Constant *Associated = CS->getOperand(2);
101  Associated = cast<Constant>(Associated->stripPointerCasts());
102 
103  auto &AtThisPriority = DtorFuncs[PriorityValue];
104  if (AtThisPriority.empty() || AtThisPriority.back().first != Associated) {
105  std::vector<Constant *> NewList;
106  NewList.push_back(DtorFunc);
107  AtThisPriority.push_back(std::make_pair(Associated, NewList));
108  } else {
109  AtThisPriority.back().second.push_back(DtorFunc);
110  }
111  }
112  if (DtorFuncs.empty())
113  return false;
114 
115  // extern "C" int __cxa_atexit(void (*f)(void *), void *p, void *d);
116  LLVMContext &C = M.getContext();
117  PointerType *VoidStar = Type::getInt8PtrTy(C);
118  Type *AtExitFuncArgs[] = {VoidStar};
119  FunctionType *AtExitFuncTy =
120  FunctionType::get(Type::getVoidTy(C), AtExitFuncArgs,
121  /*isVarArg=*/false);
122 
123  FunctionCallee AtExit = M.getOrInsertFunction(
124  "__cxa_atexit",
126  {PointerType::get(AtExitFuncTy, 0), VoidStar, VoidStar},
127  /*isVarArg=*/false));
128 
129  // Declare __dso_local.
130  Constant *DsoHandle = M.getNamedValue("__dso_handle");
131  if (!DsoHandle) {
132  Type *DsoHandleTy = Type::getInt8Ty(C);
133  GlobalVariable *Handle = new GlobalVariable(
134  M, DsoHandleTy, /*isConstant=*/true,
135  GlobalVariable::ExternalWeakLinkage, nullptr, "__dso_handle");
137  DsoHandle = Handle;
138  }
139 
140  // For each unique priority level and associated symbol, generate a function
141  // to call all the destructors at that level, and a function to register the
142  // first function with __cxa_atexit.
143  for (auto &PriorityAndMore : DtorFuncs) {
144  uint16_t Priority = PriorityAndMore.first;
145  uint64_t Id = 0;
146  auto &AtThisPriority = PriorityAndMore.second;
147  for (auto &AssociatedAndMore : AtThisPriority) {
148  Constant *Associated = AssociatedAndMore.first;
149  auto ThisId = Id++;
150 
151  Function *CallDtors = Function::Create(
152  AtExitFuncTy, Function::PrivateLinkage,
153  "call_dtors" +
154  (Priority != UINT16_MAX ? (Twine(".") + Twine(Priority))
155  : Twine()) +
156  (AtThisPriority.size() > 1 ? Twine("$") + Twine(ThisId)
157  : Twine()) +
158  (!Associated->isNullValue() ? (Twine(".") + Associated->getName())
159  : Twine()),
160  &M);
161  BasicBlock *BB = BasicBlock::Create(C, "body", CallDtors);
163  /*isVarArg=*/false);
164 
165  for (auto Dtor : reverse(AssociatedAndMore.second))
166  CallInst::Create(VoidVoid, Dtor, "", BB);
168 
169  Function *RegisterCallDtors = Function::Create(
170  VoidVoid, Function::PrivateLinkage,
171  "register_call_dtors" +
172  (Priority != UINT16_MAX ? (Twine(".") + Twine(Priority))
173  : Twine()) +
174  (AtThisPriority.size() > 1 ? Twine("$") + Twine(ThisId)
175  : Twine()) +
176  (!Associated->isNullValue() ? (Twine(".") + Associated->getName())
177  : Twine()),
178  &M);
179  BasicBlock *EntryBB = BasicBlock::Create(C, "entry", RegisterCallDtors);
180  BasicBlock *FailBB = BasicBlock::Create(C, "fail", RegisterCallDtors);
181  BasicBlock *RetBB = BasicBlock::Create(C, "return", RegisterCallDtors);
182 
183  Value *Null = ConstantPointerNull::get(VoidStar);
184  Value *Args[] = {CallDtors, Null, DsoHandle};
185  Value *Res = CallInst::Create(AtExit, Args, "call", EntryBB);
186  Value *Cmp = new ICmpInst(*EntryBB, ICmpInst::ICMP_NE, Res,
188  BranchInst::Create(FailBB, RetBB, Cmp, EntryBB);
189 
190  // If `__cxa_atexit` hits out-of-memory, trap, so that we don't misbehave.
191  // This should be very rare, because if the process is running out of
192  // memory before main has even started, something is wrong.
193  CallInst::Create(Intrinsic::getDeclaration(&M, Intrinsic::trap), "",
194  FailBB);
195  new UnreachableInst(C, FailBB);
196 
197  ReturnInst::Create(C, RetBB);
198 
199  // Now register the registration function with @llvm.global_ctors.
200  appendToGlobalCtors(M, RegisterCallDtors, Priority, Associated);
201  }
202  }
203 
204  // Now that we've lowered everything, remove @llvm.global_dtors.
205  GV->eraseFromParent();
206 
207  return true;
208 }
llvm::GlobalVariable::eraseFromParent
void eraseFromParent()
eraseFromParent - This method unlinks 'this' from the containing module and deletes it.
Definition: Globals.cpp:385
llvm
This file implements support for optimizing divisions by a constant.
Definition: AllocatorList.h:23
WebAssembly.h
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::createWebAssemblyLowerGlobalDtors
ModulePass * createWebAssemblyLowerGlobalDtors()
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:1379
llvm::Type::getInt8PtrTy
static PointerType * getInt8PtrTy(LLVMContext &C, unsigned AS=0)
Definition: Type.cpp:293
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:238
llvm::GlobalValue::HiddenVisibility
@ HiddenVisibility
The GV is hidden.
Definition: GlobalValue.h:64
llvm::Function
Definition: Function.h:62
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:729
MapVector.h
llvm::GlobalVariable
Definition: GlobalVariable.h:40
llvm::CmpInst::ICMP_NE
@ ICMP_NE
not equal
Definition: InstrTypes.h:742
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:363
llvm::Type
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
Module.h
llvm::reverse
auto reverse(ContainerTy &&C, std::enable_if_t< has_rbegin< ContainerTy >::value > *=nullptr)
Definition: STLExtras.h:333
llvm::Type::getInt8Ty
static IntegerType * getInt8Ty(LLVMContext &C)
Definition: Type.cpp:239
llvm::Type::getInt32Ty
static IntegerType * getInt32Ty(LLVMContext &C)
Definition: Type.cpp:241
LLVM_DEBUG
#define LLVM_DEBUG(X)
Definition: Debug.h:101
llvm::GlobalVariable::hasInitializer
bool hasInitializer() const
Definitions have initializers, declarations don't.
Definition: GlobalVariable.h:92
llvm::BasicBlock
LLVM Basic Block Representation.
Definition: BasicBlock.h:58
llvm::dbgs
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
llvm::pdb::PDB_LocType::Null
@ Null
Constants.h
llvm::Constant::isNullValue
bool isNullValue() const
Return true if this is the value that would be returned by getNullValue.
Definition: Constants.cpp:74
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:1518
llvm::AnalysisUsage
Represent the analysis usage information of a pass.
Definition: PassAnalysisSupport.h:47
llvm::ConstantArray
ConstantArray - Constant Array Declarations.
Definition: Constants.h:409
INITIALIZE_PASS
INITIALIZE_PASS(LowerGlobalDtors, DEBUG_TYPE, "Lower @llvm.global_dtors for WebAssembly", false, false) ModulePass *llvm
Definition: WebAssemblyLowerGlobalDtors.cpp:53
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:428
llvm::RISCVFenceField::O
@ O
Definition: RISCVBaseInfo.h:197
llvm::GlobalVariable::getInitializer
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
Definition: GlobalVariable.h:136
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:1203
uint64_t
llvm::ConstantPointerNull::get
static ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
Definition: Constants.cpp:1782
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:3124
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:139
llvm::Module
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:67
llvm::AnalysisUsage::setPreservesCFG
void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition: Pass.cpp:253
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:58
llvm::Value::getType
Type * getType() const
All values are typed, get the type of this value.
Definition: Value.h:256
llvm::BasicBlock::Create
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition: BasicBlock.h:100
llvm::Value::getName
StringRef getName() const
Return a constant reference to the value's name.
Definition: Value.cpp:309
llvm::Constant::stripPointerCasts
const Constant * stripPointerCasts() const
Definition: Constant.h:207
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:348
uint16_t
DEBUG_TYPE
#define DEBUG_TYPE
Definition: WebAssemblyLowerGlobalDtors.cpp:31
llvm::X86::FirstMacroFusionInstKind::Cmp
@ Cmp
llvm::ReturnInst::Create
static ReturnInst * Create(LLVMContext &C, Value *retVal=nullptr, Instruction *InsertBefore=nullptr)
Definition: Instructions.h:3013
llvm::Type::getVoidTy
static Type * getVoidTy(LLVMContext &C)
Definition: Type.cpp:224
llvm::GlobalValue::PrivateLinkage
@ PrivateLinkage
Like Internal, but omit from symbol table.
Definition: GlobalValue.h:56
Instructions.h
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
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:93
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:4713
llvm::AMDGPU::HSAMD::Kernel::Key::Args
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
Definition: AMDGPUMetadata.h:389
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:66
llvm::User::getOperand
Value * getOperand(unsigned i) const
Definition: User.h:169
llvm::GlobalValue::ExternalWeakLinkage
@ ExternalWeakLinkage
ExternalWeak linkage description.
Definition: GlobalValue.h:57
raw_ostream.h
llvm::AMDGPU::VGPRIndexMode::Id
Id
Definition: SIDefines.h:231
llvm::GlobalValue::setVisibility
void setVisibility(VisibilityTypes V)
Definition: GlobalValue.h:235
llvm::Value
LLVM Value Representation.
Definition: Value.h:75
Debug.h
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:37