LLVM  10.0.0svn
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, collated by priority and
80  // associated symbol.
81  std::map<uint16_t, MapVector<Constant *, std::vector<Constant *>>> DtorFuncs;
82  for (Value *O : InitList->operands()) {
83  auto *CS = dyn_cast<ConstantStruct>(O);
84  if (!CS)
85  continue; // Malformed.
86 
87  auto *Priority = dyn_cast<ConstantInt>(CS->getOperand(0));
88  if (!Priority)
89  continue; // Malformed.
90  uint16_t PriorityValue = Priority->getLimitedValue(UINT16_MAX);
91 
92  Constant *DtorFunc = CS->getOperand(1);
93  if (DtorFunc->isNullValue())
94  break; // Found a null terminator, skip the rest.
95 
96  Constant *Associated = CS->getOperand(2);
97  Associated = cast<Constant>(Associated->stripPointerCasts());
98 
99  DtorFuncs[PriorityValue][Associated].push_back(DtorFunc);
100  }
101  if (DtorFuncs.empty())
102  return false;
103 
104  // extern "C" int __cxa_atexit(void (*f)(void *), void *p, void *d);
105  LLVMContext &C = M.getContext();
106  PointerType *VoidStar = Type::getInt8PtrTy(C);
107  Type *AtExitFuncArgs[] = {VoidStar};
108  FunctionType *AtExitFuncTy =
109  FunctionType::get(Type::getVoidTy(C), AtExitFuncArgs,
110  /*isVarArg=*/false);
111 
113  "__cxa_atexit",
115  {PointerType::get(AtExitFuncTy, 0), VoidStar, VoidStar},
116  /*isVarArg=*/false));
117 
118  // Declare __dso_local.
119  Constant *DsoHandle = M.getNamedValue("__dso_handle");
120  if (!DsoHandle) {
121  Type *DsoHandleTy = Type::getInt8Ty(C);
122  GlobalVariable *Handle = new GlobalVariable(
123  M, DsoHandleTy, /*isConstant=*/true,
124  GlobalVariable::ExternalWeakLinkage, nullptr, "__dso_handle");
126  DsoHandle = Handle;
127  }
128 
129  // For each unique priority level and associated symbol, generate a function
130  // to call all the destructors at that level, and a function to register the
131  // first function with __cxa_atexit.
132  for (auto &PriorityAndMore : DtorFuncs) {
133  uint16_t Priority = PriorityAndMore.first;
134  for (auto &AssociatedAndMore : PriorityAndMore.second) {
135  Constant *Associated = AssociatedAndMore.first;
136 
137  Function *CallDtors = Function::Create(
138  AtExitFuncTy, Function::PrivateLinkage,
139  "call_dtors" +
140  (Priority != UINT16_MAX ? (Twine(".") + Twine(Priority))
141  : Twine()) +
142  (!Associated->isNullValue() ? (Twine(".") + Associated->getName())
143  : Twine()),
144  &M);
145  BasicBlock *BB = BasicBlock::Create(C, "body", CallDtors);
147  /*isVarArg=*/false);
148 
149  for (auto Dtor : AssociatedAndMore.second)
150  CallInst::Create(VoidVoid, Dtor, "", BB);
151  ReturnInst::Create(C, BB);
152 
153  Function *RegisterCallDtors = Function::Create(
154  VoidVoid, Function::PrivateLinkage,
155  "register_call_dtors" +
156  (Priority != UINT16_MAX ? (Twine(".") + Twine(Priority))
157  : Twine()) +
158  (!Associated->isNullValue() ? (Twine(".") + Associated->getName())
159  : Twine()),
160  &M);
161  BasicBlock *EntryBB = BasicBlock::Create(C, "entry", RegisterCallDtors);
162  BasicBlock *FailBB = BasicBlock::Create(C, "fail", RegisterCallDtors);
163  BasicBlock *RetBB = BasicBlock::Create(C, "return", RegisterCallDtors);
164 
165  Value *Null = ConstantPointerNull::get(VoidStar);
166  Value *Args[] = {CallDtors, Null, DsoHandle};
167  Value *Res = CallInst::Create(AtExit, Args, "call", EntryBB);
168  Value *Cmp = new ICmpInst(*EntryBB, ICmpInst::ICMP_NE, Res,
170  BranchInst::Create(FailBB, RetBB, Cmp, EntryBB);
171 
172  // If `__cxa_atexit` hits out-of-memory, trap, so that we don't misbehave.
173  // This should be very rare, because if the process is running out of
174  // memory before main has even started, something is wrong.
175  CallInst::Create(Intrinsic::getDeclaration(&M, Intrinsic::trap), "",
176  FailBB);
177  new UnreachableInst(C, FailBB);
178 
179  ReturnInst::Create(C, RetBB);
180 
181  // Now register the registration function with @llvm.global_ctors.
182  appendToGlobalCtors(M, RegisterCallDtors, Priority, Associated);
183  }
184  }
185 
186  // Now that we've lowered everything, remove @llvm.global_dtors.
187  GV->eraseFromParent();
188 
189  return true;
190 }
void setVisibility(VisibilityTypes V)
Definition: GlobalValue.h:242
uint64_t CallInst * C
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
This class represents lattice values for constants.
Definition: AllocatorList.h:23
A Module instance is used to store all the information related to an LLVM module. ...
Definition: Module.h:66
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", Instruction *InsertBefore=nullptr)
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
Definition: DerivedTypes.h:170
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:637
Like Internal, but omit from symbol table.
Definition: GlobalValue.h:56
GlobalVariable * getGlobalVariable(StringRef Name) const
Look up the specified global variable in the module symbol table.
Definition: Module.h:391
This file contains the entry points for global functions defined in the LLVM WebAssembly back-end...
static Constant * getNullValue(Type *Ty)
Constructor to create a &#39;0&#39; constant of arbitrary type.
Definition: Constants.cpp:289
static ReturnInst * Create(LLVMContext &C, Value *retVal=nullptr, Instruction *InsertBefore=nullptr)
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:80
Class to represent struct types.
Definition: DerivedTypes.h:238
LLVMContext & getContext() const
Get the global data context.
Definition: Module.h:245
bool isNullValue() const
Return true if this is the value that would be returned by getNullValue.
Definition: Constants.cpp:85
Class to represent function types.
Definition: DerivedTypes.h:108
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
Definition: Pass.cpp:96
Type * getType() const
All values are typed, get the type of this value.
Definition: Value.h:246
GlobalValue * getNamedValue(StringRef Name) const
Return the global value in the module with the specified name, of arbitrary type. ...
Definition: Module.cpp:113
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:1093
Value * getOperand(unsigned i) const
Definition: User.h:169
Class to represent pointers.
Definition: DerivedTypes.h:579
ExternalWeak linkage description.
Definition: GlobalValue.h:57
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
Definition: Function.h:135
static ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
Definition: Constants.cpp:1432
LLVM Basic Block Representation.
Definition: BasicBlock.h:57
The instances of the Type class are immutable: once they are created, they are never changed...
Definition: Type.h:46
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:64
This function has undefined behavior.
This is an important base class in LLVM.
Definition: Constant.h:41
ModulePass * createWebAssemblyLowerGlobalDtors()
This file contains the declarations for the subclasses of Constant, which represent the different fla...
void eraseFromParent()
eraseFromParent - This method unlinks &#39;this&#39; from the containing module and deletes it...
Definition: Globals.cpp:384
Represent the analysis usage information of a pass.
static Type * getVoidTy(LLVMContext &C)
Definition: Type.cpp:165
This instruction compares its operands according to the predicate given to the constructor.
static FunctionType * get(Type *Result, ArrayRef< Type *> Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
Definition: Type.cpp:301
op_range operands()
Definition: User.h:237
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition: BasicBlock.h:99
const Constant * stripPointerCasts() const
Definition: Constant.h:183
static PointerType * getInt8PtrTy(LLVMContext &C, unsigned AS=0)
Definition: Type.cpp:224
uint64_t getLimitedValue(uint64_t Limit=~0ULL) const
getLimitedValue - If the value is smaller than the specified limit, return it, otherwise return the l...
Definition: Constants.h:250
This is the shared class of boolean and integer constants.
Definition: Constants.h:83
Module.h This file contains the declarations for the Module class.
#define DEBUG_TYPE
static BranchInst * Create(BasicBlock *IfTrue, Instruction *InsertBefore=nullptr)
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:63
void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition: Pass.cpp:301
FunctionCallee getOrInsertFunction(StringRef Name, FunctionType *T, AttributeList AttributeList)
Look up the specified function in the module symbol table.
Definition: Module.cpp:143
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:132
ConstantArray - Constant Array Declarations.
Definition: Constants.h:413
INITIALIZE_PASS(LowerGlobalDtors, DEBUG_TYPE, "Lower @llvm.global_dtors for WebAssembly", false, false) ModulePass *llvm
ArrayType * getType() const
Specialize the getType() method to always return an ArrayType, which reduces the amount of casting ne...
Definition: Constants.h:432
static IntegerType * getInt32Ty(LLVMContext &C)
Definition: Type.cpp:180
StringRef getName() const
Return a constant reference to the value&#39;s name.
Definition: Value.cpp:214
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition: Pass.h:224
LLVM_NODISCARD std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
Definition: Casting.h:332
LLVM Value Representation.
Definition: Value.h:74
bool hasInitializer() const
Definitions have initializers, declarations don&#39;t.
Type * getElementType() const
Definition: DerivedTypes.h:399
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
#define LLVM_DEBUG(X)
Definition: Debug.h:122
static IntegerType * getInt8Ty(LLVMContext &C)
Definition: Type.cpp:178
constexpr char Args[]
Key for Kernel::Metadata::mArgs.