LLVM  8.0.1
WebAssemblyLowerGlobalDtors.cpp
Go to the documentation of this file.
1 //===-- WebAssemblyLowerGlobalDtors.cpp - Lower @llvm.global_dtors --------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// Lower @llvm.global_dtors.
12 ///
13 /// WebAssembly doesn't have a builtin way to invoke static destructors.
14 /// Implement @llvm.global_dtors by creating wrapper functions that are
15 /// registered in @llvm.global_ctors and which contain a call to
16 /// `__cxa_atexit` to register their destructor functions.
17 ///
18 //===----------------------------------------------------------------------===//
19 
20 #include "WebAssembly.h"
21 #include "llvm/ADT/MapVector.h"
22 #include "llvm/IR/Constants.h"
23 #include "llvm/IR/Instructions.h"
24 #include "llvm/IR/Intrinsics.h"
25 #include "llvm/IR/Module.h"
26 #include "llvm/Pass.h"
27 #include "llvm/Support/Debug.h"
30 using namespace llvm;
31 
32 #define DEBUG_TYPE "wasm-lower-global-dtors"
33 
34 namespace {
35 class LowerGlobalDtors final : public ModulePass {
36  StringRef getPassName() const override {
37  return "WebAssembly Lower @llvm.global_dtors";
38  }
39 
40  void getAnalysisUsage(AnalysisUsage &AU) const override {
41  AU.setPreservesCFG();
43  }
44 
45  bool runOnModule(Module &M) override;
46 
47 public:
48  static char ID;
49  LowerGlobalDtors() : ModulePass(ID) {}
50 };
51 } // End anonymous namespace
52 
53 char LowerGlobalDtors::ID = 0;
54 INITIALIZE_PASS(LowerGlobalDtors, DEBUG_TYPE,
55  "Lower @llvm.global_dtors for WebAssembly", false, false)
56 
58  return new LowerGlobalDtors();
59 }
60 
61 bool LowerGlobalDtors::runOnModule(Module &M) {
62  LLVM_DEBUG(dbgs() << "********** Lower Global Destructors **********\n");
63 
64  GlobalVariable *GV = M.getGlobalVariable("llvm.global_dtors");
65  if (!GV)
66  return false;
67 
68  const ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer());
69  if (!InitList)
70  return false;
71 
72  // Sanity-check @llvm.global_dtor's type.
73  StructType *ETy = dyn_cast<StructType>(InitList->getType()->getElementType());
74  if (!ETy || ETy->getNumElements() != 3 ||
75  !ETy->getTypeAtIndex(0U)->isIntegerTy() ||
76  !ETy->getTypeAtIndex(1U)->isPointerTy() ||
77  !ETy->getTypeAtIndex(2U)->isPointerTy())
78  return false; // Not (int, ptr, ptr).
79 
80  // Collect the contents of @llvm.global_dtors, collated by priority and
81  // associated symbol.
82  std::map<uint16_t, MapVector<Constant *, std::vector<Constant *>>> DtorFuncs;
83  for (Value *O : InitList->operands()) {
85  if (!CS)
86  continue; // Malformed.
87 
88  ConstantInt *Priority = dyn_cast<ConstantInt>(CS->getOperand(0));
89  if (!Priority)
90  continue; // Malformed.
91  uint16_t PriorityValue = Priority->getLimitedValue(UINT16_MAX);
92 
93  Constant *DtorFunc = CS->getOperand(1);
94  if (DtorFunc->isNullValue())
95  break; // Found a null terminator, skip the rest.
96 
97  Constant *Associated = CS->getOperand(2);
98  Associated = cast<Constant>(Associated->stripPointerCastsNoFollowAliases());
99 
100  DtorFuncs[PriorityValue][Associated].push_back(DtorFunc);
101  }
102  if (DtorFuncs.empty())
103  return false;
104 
105  // extern "C" int __cxa_atexit(void (*f)(void *), void *p, void *d);
106  LLVMContext &C = M.getContext();
107  PointerType *VoidStar = Type::getInt8PtrTy(C);
108  Type *AtExitFuncArgs[] = {VoidStar};
109  FunctionType *AtExitFuncTy =
110  FunctionType::get(Type::getVoidTy(C), AtExitFuncArgs,
111  /*isVarArg=*/false);
112 
113  Type *AtExitArgs[] = {PointerType::get(AtExitFuncTy, 0), VoidStar, VoidStar};
114  FunctionType *AtExitTy = FunctionType::get(Type::getInt32Ty(C), AtExitArgs,
115  /*isVarArg=*/false);
116  Constant *AtExit = M.getOrInsertFunction("__cxa_atexit", AtExitTy);
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);
146 
147  for (auto Dtor : AssociatedAndMore.second)
148  CallInst::Create(Dtor, "", BB);
149  ReturnInst::Create(C, BB);
150 
152  /*isVarArg=*/false);
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.
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:239
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:24
Constant * getOrInsertFunction(StringRef Name, FunctionType *T, AttributeList AttributeList)
Look up the specified function in the module symbol table.
Definition: Module.cpp:144
A Module instance is used to store all the information related to an LLVM module. ...
Definition: Module.h:65
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", Instruction *InsertBefore=nullptr)
unsigned getNumElements() const
Random access to the elements.
Definition: DerivedTypes.h:313
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:630
Like Internal, but omit from symbol table.
Definition: GlobalValue.h:57
GlobalVariable * getGlobalVariable(StringRef Name) const
Look up the specified global variable in the module symbol table.
Definition: Module.h:387
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:265
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:81
Class to represent struct types.
Definition: DerivedTypes.h:201
LLVMContext & getContext() const
Get the global data context.
Definition: Module.h:244
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition: Type.h:197
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:103
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
Definition: Pass.cpp:92
Type * getType() const
All values are typed, get the type of this value.
Definition: Value.h:245
GlobalValue * getNamedValue(StringRef Name) const
Return the global value in the module with the specified name, of arbitrary type. ...
Definition: Module.cpp:114
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:1020
Value * getOperand(unsigned i) const
Definition: User.h:170
Class to represent pointers.
Definition: DerivedTypes.h:467
ExternalWeak linkage description.
Definition: GlobalValue.h:58
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
Definition: Function.h:136
static ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
Definition: Constants.cpp:1401
LLVM Basic Block Representation.
Definition: BasicBlock.h:58
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:69
This function has undefined behavior.
This is an important base class in LLVM.
Definition: Constant.h:42
ModulePass * createWebAssemblyLowerGlobalDtors()
This file contains the declarations for the subclasses of Constant, which represent the different fla...
bool isPointerTy() const
True if this is an instance of PointerType.
Definition: Type.h:224
void eraseFromParent()
eraseFromParent - This method unlinks &#39;this&#39; from the containing module and deletes it...
Definition: Globals.cpp:359
Represent the analysis usage information of a pass.
static Type * getVoidTy(LLVMContext &C)
Definition: Type.cpp:161
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:297
op_range operands()
Definition: User.h:238
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition: BasicBlock.h:100
static PointerType * getInt8PtrTy(LLVMContext &C, unsigned AS=0)
Definition: Type.cpp:220
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:251
This is the shared class of boolean and integer constants.
Definition: Constants.h:84
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:84
void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition: Pass.cpp:286
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:133
ConstantArray - Constant Array Declarations.
Definition: Constants.h:414
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:433
static IntegerType * getInt32Ty(LLVMContext &C)
Definition: Type.cpp:176
const Value * stripPointerCastsNoFollowAliases() const
Strip off pointer casts and all-zero GEPs.
Definition: Value.cpp:533
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:225
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:323
LLVM Value Representation.
Definition: Value.h:73
Type * getElementType() const
Definition: DerivedTypes.h:360
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:49
#define LLVM_DEBUG(X)
Definition: Debug.h:123
static IntegerType * getInt8Ty(LLVMContext &C)
Definition: Type.cpp:174
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
Type * getTypeAtIndex(const Value *V) const
Given an index value into the type, return the type of the element.
Definition: Type.cpp:530