Chromium Code Reviews| 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 /// The module this pass runs on. | |
| 49 Module *TheModule; | |
| 50 }; | |
| 51 } | |
| 52 | |
| 53 static const char *LONGJMP_NAME = "longjmp"; | |
|
Mark Seaborn
2013/05/13 23:39:58
I don't think LLVM uses NAMES_IN_CAPS for non-#def
eliben
2013/05/14 17:38:58
These constants are now just used in a single plac
| |
| 54 static const char *SETJMP_NAME = "setjmp"; | |
| 55 | |
| 56 char RewritePNaClLibraryCalls::ID = 0; | |
| 57 INITIALIZE_PASS(RewritePNaClLibraryCalls, "rewrite-pnacl-library-calls", | |
| 58 "Rewrite PNaCl library calls to stable intrinsics", | |
| 59 false, false) | |
| 60 | |
| 61 bool RewritePNaClLibraryCalls::runOnModule(Module &M) { | |
| 62 TheModule = &M; | |
| 63 bool Changed = false; | |
| 64 | |
| 65 // Iterate over all uses of the setjmp, if it exists in the module with | |
| 66 // external linkage. If it exists but the linkage is not external, this may | |
| 67 // come from code that defines its own function named setjmp and doesn't | |
| 68 // include <setjmp.h>. In such a case we leave the code as it is. | |
| 69 // | |
| 70 // The calls are replaced with intrinsics. All other uses | |
| 71 // of setjmp are disallowed (taking the address of setjmp is disallowed in | |
|
Mark Seaborn
2013/05/13 23:39:58
Re-wrap (partly fits on previous line)
eliben
2013/05/14 17:38:58
Done.
| |
| 72 // C and C++). | |
| 73 Function *SetjmpFunc = TheModule->getFunction(SETJMP_NAME); | |
| 74 if (SetjmpFunc && SetjmpFunc->hasExternalLinkage()) { | |
| 75 for (Value::use_iterator UI = SetjmpFunc->use_begin(), | |
| 76 UE = SetjmpFunc->use_end(); UI != UE;) { | |
| 77 Value *Use = *UI++; | |
| 78 if (CallInst *Call = dyn_cast<CallInst>(Use)) { | |
| 79 rewriteSetjmpCall(Call); | |
| 80 Changed = true; | |
| 81 } else { | |
| 82 report_fatal_error("Taking the address of setjmp is invalid"); | |
| 83 } | |
| 84 } | |
| 85 } | |
| 86 | |
| 87 // For longjmp things are a little more complicated, since longjmp's address | |
| 88 // can be taken. Therefore, longjmp can appear in a variety of Uses. The | |
| 89 // common case is still a direct call and we want that to be as efficient as | |
| 90 // possible, so we rewrite it into a direct intrinsic call. If there are other | |
| 91 // uses, the actual body of longjmp is populated with a wrapper that calls | |
| 92 // the intrinsic. | |
| 93 Function *LongjmpFunc = TheModule->getFunction(LONGJMP_NAME); | |
| 94 bool LongjmpHasNoncallUses = false; | |
| 95 | |
| 96 if (LongjmpFunc && LongjmpFunc->hasExternalLinkage()) { | |
| 97 for (Value::use_iterator UI = LongjmpFunc->use_begin(), | |
| 98 UE = LongjmpFunc->use_end(); UI != UE;) { | |
| 99 Value *Use = *UI++; | |
| 100 if (CallInst *Call = dyn_cast<CallInst>(Use)) { | |
| 101 rewriteLongjmpCall(Call); | |
| 102 Changed = true; | |
| 103 } else { | |
| 104 LongjmpHasNoncallUses = true; | |
| 105 } | |
| 106 } | |
| 107 } | |
| 108 | |
| 109 if (LongjmpHasNoncallUses) { | |
|
Mark Seaborn
2013/05/13 23:39:58
Could just do:
if (!LongjmpFunc->use_empty())
th
eliben
2013/05/14 17:38:58
Done.
| |
| 110 populateLongjmpWrapper(LongjmpFunc); | |
| 111 Changed = true; | |
| 112 } | |
| 113 | |
| 114 return Changed; | |
| 115 } | |
| 116 | |
| 117 void RewritePNaClLibraryCalls::rewriteSetjmpCall(CallInst *Call) { | |
| 118 FunctionType *FTy = Call->getCalledFunction()->getFunctionType(); | |
| 119 | |
| 120 // Sanity check on the setjmp call. | |
| 121 if (FTy->getNumParams() != 1 || | |
| 122 !FTy->getReturnType()->isIntegerTy() || | |
| 123 !FTy->getParamType(0)->isPointerTy()) { | |
| 124 report_fatal_error(Twine("Wrong signature of function ") + | |
| 125 Call->getCalledFunction()->getName()); | |
| 126 } | |
| 127 const DebugLoc &DLoc = Call->getDebugLoc(); | |
| 128 | |
| 129 // Find the intrinsic function. | |
| 130 Function *NaClSetjmpFunc = Intrinsic::getDeclaration(TheModule, | |
| 131 Intrinsic::nacl_setjmp); | |
| 132 // Cast the jmp_buf argument to the type NaClSetjmpCall expects. | |
| 133 Type *PtrTy = NaClSetjmpFunc->getFunctionType()->getParamType(0); | |
| 134 BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy, | |
| 135 "jmp_buf_i8", Call); | |
| 136 JmpBufCast->setDebugLoc(DLoc); | |
| 137 | |
| 138 // Emit the updated call. | |
| 139 SmallVector<Value *, 1> Args; | |
| 140 Args.push_back(JmpBufCast); | |
| 141 CallInst *NaClSetjmpCall = CallInst::Create(NaClSetjmpFunc, Args, "", Call); | |
| 142 NaClSetjmpCall->setDebugLoc(DLoc); | |
| 143 NaClSetjmpCall->takeName(Call); | |
| 144 | |
| 145 // Replace the original call. | |
| 146 Call->replaceAllUsesWith(NaClSetjmpCall); | |
| 147 Call->eraseFromParent(); | |
| 148 } | |
| 149 | |
| 150 void RewritePNaClLibraryCalls::rewriteLongjmpCall(CallInst *Call) { | |
| 151 FunctionType *FTy = Call->getCalledFunction()->getFunctionType(); | |
| 152 | |
| 153 // Sanity check on the longjmp call. | |
| 154 if (FTy->getNumParams() != 2 || | |
| 155 !FTy->getReturnType()->isVoidTy() || | |
| 156 !FTy->getParamType(0)->isPointerTy()) { | |
| 157 report_fatal_error(Twine("Wrong signature of function ") + | |
| 158 Call->getCalledFunction()->getName()); | |
| 159 } | |
| 160 const DebugLoc &DLoc = Call->getDebugLoc(); | |
| 161 | |
| 162 // Find the intrinsic function. | |
| 163 Function *NaClLongjmpFunc = Intrinsic::getDeclaration( | |
| 164 TheModule, Intrinsic::nacl_longjmp); | |
| 165 // Cast the jmp_buf argument to the type NaClLongjmpCall expects. | |
| 166 Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0); | |
| 167 BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy, | |
| 168 "jmp_buf_i8", Call); | |
| 169 JmpBufCast->setDebugLoc(DLoc); | |
| 170 | |
| 171 // Emit the call. | |
| 172 SmallVector<Value *, 2> Args; | |
| 173 Args.push_back(JmpBufCast); | |
| 174 Args.push_back(Call->getArgOperand(1)); | |
| 175 CallInst *NaClLongjmpCall = CallInst::Create(NaClLongjmpFunc, Args, "", Call); | |
| 176 NaClLongjmpCall->setDebugLoc(DLoc); | |
| 177 // No takeName here since longjmp is a void call that does not get assigned to | |
| 178 // a value. | |
| 179 | |
| 180 // Remove the original call. There's no need for RAUW because longjmp | |
| 181 // returns void. | |
| 182 Call->eraseFromParent(); | |
| 183 } | |
| 184 | |
| 185 void RewritePNaClLibraryCalls::populateLongjmpWrapper(Function *LongjmpFunc) { | |
| 186 assert(LongjmpFunc->size() == 0 && | |
| 187 "Expected to be called when longjmp has an empty body"); | |
| 188 | |
| 189 // Populate longjmp with code. | |
| 190 LLVMContext &Context = TheModule->getContext(); | |
| 191 BasicBlock *BB = BasicBlock::Create(Context, "entry", LongjmpFunc); | |
| 192 | |
| 193 Function::arg_iterator LongjmpArgs = LongjmpFunc->arg_begin(); | |
|
Mark Seaborn
2013/05/13 23:39:58
Also do a sanity check on this function's args, as
eliben
2013/05/14 17:38:58
Refactored
| |
| 194 Value *EnvArg = LongjmpArgs++; | |
| 195 EnvArg->setName("env"); | |
| 196 Value *ValArg = LongjmpArgs++; | |
| 197 ValArg->setName("val"); | |
| 198 | |
| 199 // Insert an unreachable instruction to terminate this function since longjmp | |
| 200 // does not return. | |
| 201 Instruction *End = new UnreachableInst(Context, BB); | |
|
Mark Seaborn
2013/05/13 23:39:58
Nit: It would be a little more obvious to add the
eliben
2013/05/14 17:38:58
Done.
| |
| 202 | |
| 203 // Find the intrinsic function. | |
| 204 Function *NaClLongjmpFunc = Intrinsic::getDeclaration( | |
| 205 TheModule, Intrinsic::nacl_longjmp); | |
| 206 // Cast the jmp_buf argument to the type NaClLongjmpCall expects. | |
| 207 Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0); | |
| 208 BitCastInst *JmpBufCast = new BitCastInst(EnvArg, PtrTy, "jmp_buf_i8", End); | |
| 209 | |
| 210 // Emit the call. | |
| 211 SmallVector<Value *, 2> Args; | |
| 212 Args.push_back(JmpBufCast); | |
| 213 Args.push_back(ValArg); | |
| 214 CallInst::Create(NaClLongjmpFunc, Args, "", End); | |
| 215 | |
| 216 // Finally, set the linkage to internal | |
| 217 LongjmpFunc->setLinkage(Function::InternalLinkage); | |
| 218 } | |
| 219 | |
| 220 ModulePass *llvm::createRewritePNaClLibraryCallsPass() { | |
| 221 return new RewritePNaClLibraryCalls(); | |
| 222 } | |
| 223 | |
|
Mark Seaborn
2013/05/13 23:39:58
Nit: don't put empty lines at the end of the file
eliben
2013/05/14 17:38:58
Done.
| |
| OLD | NEW |