OLD | NEW |
(Empty) | |
| 1 //===- RewritePNaClLibraryCalls.cpp - PNaCl library calls to intrinsics ---===// |
| 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 // This pass replaces calls to known library functions with calls to intrinsics |
| 11 // that are part of the PNaCl stable bitcode ABI. |
| 12 // |
| 13 //===----------------------------------------------------------------------===// |
| 14 |
| 15 #include "llvm/ADT/SmallString.h" |
| 16 #include "llvm/ADT/Twine.h" |
| 17 #include "llvm/IR/Instructions.h" |
| 18 #include "llvm/IR/Intrinsics.h" |
| 19 #include "llvm/IR/Module.h" |
| 20 #include "llvm/Pass.h" |
| 21 #include "llvm/Transforms/NaCl.h" |
| 22 |
| 23 using namespace llvm; |
| 24 |
| 25 namespace { |
| 26 class RewritePNaClLibraryCalls : public ModulePass { |
| 27 public: |
| 28 static char ID; |
| 29 RewritePNaClLibraryCalls() : |
| 30 ModulePass(ID), TheModule(NULL) { |
| 31 // This is a module pass because it may have to introduce |
| 32 // intrinsic declarations into the module and modify a global function. |
| 33 initializeRewritePNaClLibraryCallsPass(*PassRegistry::getPassRegistry()); |
| 34 } |
| 35 |
| 36 virtual bool runOnModule(Module &M); |
| 37 private: |
| 38 /// Rewrites the given \p Call of setjmp to a direct intrinsic call. |
| 39 void rewriteSetjmpCall(CallInst *Call); |
| 40 |
| 41 /// Rewrites the given \p Call of longjmp to a direct intrinsic call. |
| 42 void rewriteLongjmpCall(CallInst *Call); |
| 43 |
| 44 /// Populates the body of longjmp as a wrapper of the intrinsic call. |
| 45 /// Should only be called once. Modifies the given \p LongjmpFunc. |
| 46 void populateLongjmpWrapper(Function *LongjmpFunc); |
| 47 |
| 48 /// Sanity check that the types of these functions are what we expect them |
| 49 /// to be. |
| 50 void sanityCheckSetjmpFunc(Function *SetjmpFunc); |
| 51 void sanityCheckLongjmpFunc(Function *LongjmpFunc); |
| 52 |
| 53 /// The module this pass runs on. |
| 54 Module *TheModule; |
| 55 }; |
| 56 } |
| 57 |
| 58 char RewritePNaClLibraryCalls::ID = 0; |
| 59 INITIALIZE_PASS(RewritePNaClLibraryCalls, "rewrite-pnacl-library-calls", |
| 60 "Rewrite PNaCl library calls to stable intrinsics", |
| 61 false, false) |
| 62 |
| 63 bool RewritePNaClLibraryCalls::runOnModule(Module &M) { |
| 64 TheModule = &M; |
| 65 bool Changed = false; |
| 66 |
| 67 // Iterate over all uses of the setjmp, if it exists in the module with |
| 68 // external linkage. If it exists but the linkage is not external, this may |
| 69 // come from code that defines its own function named setjmp and doesn't |
| 70 // include <setjmp.h>. In such a case we leave the code as it is. |
| 71 // |
| 72 // The calls are replaced with intrinsics. All other uses of setjmp are |
| 73 // disallowed (taking the address of setjmp is disallowed in C and C++). |
| 74 Function *SetjmpFunc = TheModule->getFunction("setjmp"); |
| 75 |
| 76 if (SetjmpFunc && SetjmpFunc->hasExternalLinkage()) { |
| 77 sanityCheckSetjmpFunc(SetjmpFunc); |
| 78 |
| 79 for (Value::use_iterator UI = SetjmpFunc->use_begin(), |
| 80 UE = SetjmpFunc->use_end(); UI != UE;) { |
| 81 Value *Use = *UI++; |
| 82 if (CallInst *Call = dyn_cast<CallInst>(Use)) { |
| 83 rewriteSetjmpCall(Call); |
| 84 Changed = true; |
| 85 } else { |
| 86 report_fatal_error("Taking the address of setjmp is invalid"); |
| 87 } |
| 88 } |
| 89 } |
| 90 |
| 91 // For longjmp things are a little more complicated, since longjmp's address |
| 92 // can be taken. Therefore, longjmp can appear in a variety of Uses. The |
| 93 // common case is still a direct call and we want that to be as efficient as |
| 94 // possible, so we rewrite it into a direct intrinsic call. If there are other |
| 95 // uses, the actual body of longjmp is populated with a wrapper that calls |
| 96 // the intrinsic. |
| 97 Function *LongjmpFunc = TheModule->getFunction("longjmp"); |
| 98 |
| 99 if (LongjmpFunc && LongjmpFunc->hasExternalLinkage()) { |
| 100 sanityCheckLongjmpFunc(LongjmpFunc); |
| 101 |
| 102 for (Value::use_iterator UI = LongjmpFunc->use_begin(), |
| 103 UE = LongjmpFunc->use_end(); UI != UE;) { |
| 104 Value *Use = *UI++; |
| 105 if (CallInst *Call = dyn_cast<CallInst>(Use)) { |
| 106 rewriteLongjmpCall(Call); |
| 107 Changed = true; |
| 108 } |
| 109 } |
| 110 |
| 111 // If additional uses remain, these aren't calls; populate the wrapper. |
| 112 if (!LongjmpFunc->use_empty()) { |
| 113 populateLongjmpWrapper(LongjmpFunc); |
| 114 Changed = true; |
| 115 } |
| 116 } |
| 117 |
| 118 return Changed; |
| 119 } |
| 120 |
| 121 void RewritePNaClLibraryCalls::rewriteSetjmpCall(CallInst *Call) { |
| 122 // Find the intrinsic function. |
| 123 Function *NaClSetjmpFunc = Intrinsic::getDeclaration(TheModule, |
| 124 Intrinsic::nacl_setjmp); |
| 125 // Cast the jmp_buf argument to the type NaClSetjmpCall expects. |
| 126 Type *PtrTy = NaClSetjmpFunc->getFunctionType()->getParamType(0); |
| 127 BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy, |
| 128 "jmp_buf_i8", Call); |
| 129 const DebugLoc &DLoc = Call->getDebugLoc(); |
| 130 JmpBufCast->setDebugLoc(DLoc); |
| 131 |
| 132 // Emit the updated call. |
| 133 SmallVector<Value *, 1> Args; |
| 134 Args.push_back(JmpBufCast); |
| 135 CallInst *NaClSetjmpCall = CallInst::Create(NaClSetjmpFunc, Args, "", Call); |
| 136 NaClSetjmpCall->setDebugLoc(DLoc); |
| 137 NaClSetjmpCall->takeName(Call); |
| 138 |
| 139 // Replace the original call. |
| 140 Call->replaceAllUsesWith(NaClSetjmpCall); |
| 141 Call->eraseFromParent(); |
| 142 } |
| 143 |
| 144 void RewritePNaClLibraryCalls::sanityCheckLongjmpFunc(Function *LongjmpFunc) { |
| 145 FunctionType *FTy = LongjmpFunc->getFunctionType(); |
| 146 if (!(FTy->getNumParams() == 2 && |
| 147 FTy->getReturnType()->isVoidTy() && |
| 148 FTy->getParamType(0)->isPointerTy() && |
| 149 FTy->getParamType(1)->isIntegerTy())) { |
| 150 report_fatal_error("Wrong signature of longjmp"); |
| 151 } |
| 152 } |
| 153 |
| 154 void RewritePNaClLibraryCalls::sanityCheckSetjmpFunc(Function *SetjmpFunc) { |
| 155 FunctionType *FTy = SetjmpFunc->getFunctionType(); |
| 156 if (!(FTy->getNumParams() == 1 && |
| 157 FTy->getReturnType()->isIntegerTy() && |
| 158 FTy->getParamType(0)->isPointerTy())) { |
| 159 report_fatal_error("Wrong signature of setjmp"); |
| 160 } |
| 161 } |
| 162 |
| 163 void RewritePNaClLibraryCalls::rewriteLongjmpCall(CallInst *Call) { |
| 164 // Find the intrinsic function. |
| 165 Function *NaClLongjmpFunc = Intrinsic::getDeclaration( |
| 166 TheModule, Intrinsic::nacl_longjmp); |
| 167 // Cast the jmp_buf argument to the type NaClLongjmpCall expects. |
| 168 Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0); |
| 169 BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy, |
| 170 "jmp_buf_i8", Call); |
| 171 const DebugLoc &DLoc = Call->getDebugLoc(); |
| 172 JmpBufCast->setDebugLoc(DLoc); |
| 173 |
| 174 // Emit the call. |
| 175 SmallVector<Value *, 2> Args; |
| 176 Args.push_back(JmpBufCast); |
| 177 Args.push_back(Call->getArgOperand(1)); |
| 178 CallInst *NaClLongjmpCall = CallInst::Create(NaClLongjmpFunc, Args, "", Call); |
| 179 NaClLongjmpCall->setDebugLoc(DLoc); |
| 180 // No takeName here since longjmp is a void call that does not get assigned to |
| 181 // a value. |
| 182 |
| 183 // Remove the original call. There's no need for RAUW because longjmp |
| 184 // returns void. |
| 185 Call->eraseFromParent(); |
| 186 } |
| 187 |
| 188 void RewritePNaClLibraryCalls::populateLongjmpWrapper(Function *LongjmpFunc) { |
| 189 assert(LongjmpFunc->size() == 0 && |
| 190 "Expected to be called when longjmp has an empty body"); |
| 191 |
| 192 // Populate longjmp with code. |
| 193 LLVMContext &Context = TheModule->getContext(); |
| 194 BasicBlock *BB = BasicBlock::Create(Context, "entry", LongjmpFunc); |
| 195 |
| 196 Function::arg_iterator LongjmpArgs = LongjmpFunc->arg_begin(); |
| 197 Value *EnvArg = LongjmpArgs++; |
| 198 EnvArg->setName("env"); |
| 199 Value *ValArg = LongjmpArgs++; |
| 200 ValArg->setName("val"); |
| 201 |
| 202 // Find the intrinsic function. |
| 203 Function *NaClLongjmpFunc = Intrinsic::getDeclaration( |
| 204 TheModule, Intrinsic::nacl_longjmp); |
| 205 // Cast the jmp_buf argument to the type NaClLongjmpCall expects. |
| 206 Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0); |
| 207 BitCastInst *JmpBufCast = new BitCastInst(EnvArg, PtrTy, "jmp_buf_i8", BB); |
| 208 |
| 209 // Emit the call. |
| 210 SmallVector<Value *, 2> Args; |
| 211 Args.push_back(JmpBufCast); |
| 212 Args.push_back(ValArg); |
| 213 CallInst::Create(NaClLongjmpFunc, Args, "", BB); |
| 214 |
| 215 // Insert an unreachable instruction to terminate this function since longjmp |
| 216 // does not return. |
| 217 new UnreachableInst(Context, BB); |
| 218 |
| 219 // Finally, set the linkage to internal |
| 220 LongjmpFunc->setLinkage(Function::InternalLinkage); |
| 221 } |
| 222 |
| 223 ModulePass *llvm::createRewritePNaClLibraryCallsPass() { |
| 224 return new RewritePNaClLibraryCalls(); |
| 225 } |
OLD | NEW |