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/GlobalVariable.h" | |
| 18 #include "llvm/IR/Instructions.h" | |
| 19 #include "llvm/IR/Intrinsics.h" | |
| 20 #include "llvm/IR/Module.h" | |
| 21 #include "llvm/Pass.h" | |
| 22 #include "llvm/Support/raw_ostream.h" | |
| 23 #include "llvm/Transforms/NaCl.h" | |
| 24 | |
| 25 using namespace llvm; | |
| 26 | |
| 27 namespace { | |
| 28 class RewritePNaClLibraryCalls : public ModulePass { | |
| 29 public: | |
| 30 static char ID; | |
| 31 RewritePNaClLibraryCalls() : | |
| 32 ModulePass(ID), TheModule(0), | |
| 33 SetjmpFunc(0), LongjmpFunc(0), LongjmpWrapperFunc(0) { | |
| 34 // This is a module pass because it may have to introduce | |
| 35 // intrindic declarations into the module. | |
|
jvoung (off chromium)
2013/05/13 18:12:30
intrindic -> intrinsic
Another reason (if you wan
eliben
2013/05/13 18:33:36
Done.
| |
| 36 initializeExpandTlsPass(*PassRegistry::getPassRegistry()); | |
|
jvoung (off chromium)
2013/05/13 18:12:30
initializeExpandTlsPass?
eliben
2013/05/13 18:33:36
Oops :-/
Thanks, fixed.
| |
| 37 } | |
| 38 | |
| 39 virtual bool runOnModule(Module &M); | |
| 40 private: | |
| 41 /// Rewrites the given \p Call to setjmp. | |
| 42 void rewriteSetjmpCall(CallInst *Call); | |
| 43 | |
| 44 /// Rewrites the given \p Call to longjmp. | |
| 45 void rewriteLongjmpCall(CallInst *Call); | |
| 46 | |
| 47 /// Rewrites the given \p Store instruction that stores a pointer to | |
| 48 /// longjmp. | |
| 49 void rewriteLongjmpStore(StoreInst *Store); | |
| 50 | |
| 51 void rewriteAddrOfLongjmpInGlobal(GlobalVariable *Global); | |
| 52 | |
| 53 /// Creates the longjmp wrapper on-demand. | |
| 54 Function *getOrCreateLongjmpWrapper(); | |
| 55 | |
| 56 /// The module this pass runs on. | |
| 57 Module *TheModule; | |
| 58 | |
| 59 /// Global setjmp/longjmp functions the original code calls. NULL if they | |
| 60 /// are not in the module. | |
| 61 Function *SetjmpFunc; | |
|
jvoung (off chromium)
2013/05/13 18:12:30
Does SetjmpFunc really need to be a field? It loo
eliben
2013/05/13 18:33:36
Yeah, SetjmpFunc is definitely a leftover from ref
| |
| 62 Function *LongjmpFunc; | |
| 63 | |
| 64 /// The wrapper for longjmp is created on-demand and cached here. | |
| 65 Function *LongjmpWrapperFunc; | |
| 66 }; | |
| 67 } | |
| 68 | |
| 69 static const char *LONGJMP_NAME = "longjmp"; | |
| 70 static const char *SETJMP_NAME = "setjmp"; | |
| 71 static const char *WRAP_FUNC_PREFIX = "__nacl_wrap_"; | |
| 72 | |
| 73 char RewritePNaClLibraryCalls::ID = 0; | |
| 74 INITIALIZE_PASS(RewritePNaClLibraryCalls, "rewrite-pnacl-library-calls", | |
| 75 "Rewrite PNaCl library calls to stable intrinsics", | |
| 76 false, false) | |
| 77 | |
| 78 bool RewritePNaClLibraryCalls::runOnModule(Module &M) { | |
| 79 TheModule = &M; | |
| 80 bool Changed = false; | |
| 81 | |
| 82 // Iterate over all uses of the setjmp and longjmp functions, if they exist | |
| 83 // in the module with external linkage. | |
| 84 // For setjmp, calls are replaced by calls to intrinsics. | |
| 85 // For longjmp calls are also replaced; however, longjmp can have its | |
|
jvoung (off chromium)
2013/05/13 18:12:30
no need for two spaces between ";" and "however"?
eliben
2013/05/13 18:33:36
Done.
| |
| 86 // address taken, so in these places an address of a wrapper function is | |
| 87 // stored instead (or used as an initializer in a global variable). | |
| 88 // The wrapper function calls the intrinsic with an appropriate cast. | |
| 89 SetjmpFunc = TheModule->getFunction(SETJMP_NAME); | |
| 90 if (SetjmpFunc && SetjmpFunc->hasExternalLinkage()) { | |
| 91 for (Value::use_iterator UI = SetjmpFunc->use_begin(), | |
| 92 UE = SetjmpFunc->use_end(); UI != UE;) { | |
| 93 Value *Use = *UI++; | |
| 94 if (CallInst *Call = dyn_cast<CallInst>(Use)) { | |
| 95 rewriteSetjmpCall(Call); | |
|
jvoung (off chromium)
2013/05/13 18:12:30
Now that you aren't checking "Call->getCalledFunct
eliben
2013/05/13 18:33:36
Not sure what you mean. Only going over the uses o
jvoung (off chromium)
2013/05/13 19:52:07
I was wondering if you had IL like this:
%call =
| |
| 96 Changed = true; | |
| 97 } else if (isa<StoreInst>(Use)) { | |
| 98 report_fatal_error("Invalid store of setjmp's address"); | |
| 99 } | |
|
jvoung (off chromium)
2013/05/13 18:12:30
Do we expect to see other uses of setjmp (else bra
eliben
2013/05/13 18:33:36
Done.
| |
| 100 } | |
| 101 } | |
| 102 | |
| 103 LongjmpFunc = TheModule->getFunction(LONGJMP_NAME); | |
| 104 if (LongjmpFunc && LongjmpFunc->hasExternalLinkage()) { | |
| 105 for (Value::use_iterator UI = LongjmpFunc->use_begin(), | |
| 106 UE = LongjmpFunc->use_end(); UI != UE;) { | |
| 107 Value *Use = *UI++; | |
| 108 if (CallInst *Call = dyn_cast<CallInst>(Use)) { | |
| 109 rewriteLongjmpCall(Call); | |
| 110 Changed = true; | |
| 111 } else if (StoreInst *Store = dyn_cast<StoreInst>(Use)) { | |
| 112 rewriteLongjmpStore(Store); | |
| 113 Changed = true; | |
| 114 } else if (GlobalVariable *Global = dyn_cast<GlobalVariable>(Use)) { | |
| 115 rewriteAddrOfLongjmpInGlobal(Global); | |
| 116 Changed = true; | |
| 117 } | |
| 118 } | |
| 119 } | |
| 120 | |
| 121 return Changed; | |
| 122 } | |
| 123 | |
| 124 void RewritePNaClLibraryCalls::rewriteSetjmpCall(CallInst *Call) { | |
| 125 FunctionType *FTy = Call->getCalledFunction()->getFunctionType(); | |
| 126 | |
| 127 // Sanity check on the setjmp call. | |
| 128 if (FTy->getNumParams() != 1 || | |
| 129 !FTy->getReturnType()->isIntegerTy() || | |
| 130 !FTy->getParamType(0)->isPointerTy()) { | |
| 131 report_fatal_error(Twine("Wrong signature of function ") + | |
| 132 Call->getCalledFunction()->getName()); | |
| 133 } | |
| 134 const DebugLoc &DLoc = Call->getDebugLoc(); | |
| 135 | |
| 136 // Find the intrinsic function. | |
| 137 Function *NaClSetjmpFunc = Intrinsic::getDeclaration(TheModule, | |
| 138 Intrinsic::nacl_setjmp); | |
| 139 // Cast the jmp_buf argument to the type NaClSetjmpCall expects. | |
| 140 Type *PtrTy = NaClSetjmpFunc->getFunctionType()->getParamType(0); | |
| 141 BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy, | |
| 142 "jmp_buf_i8", Call); | |
| 143 JmpBufCast->setDebugLoc(DLoc); | |
| 144 | |
| 145 // Emit the updated call. | |
| 146 SmallVector<Value *, 2> Args; | |
| 147 Args.push_back(JmpBufCast); | |
| 148 CallInst *NaClSetjmpCall = CallInst::Create(NaClSetjmpFunc, Args, "", Call); | |
| 149 NaClSetjmpCall->setDebugLoc(DLoc); | |
| 150 NaClSetjmpCall->takeName(Call); | |
| 151 | |
| 152 // Replace the original call. | |
| 153 Call->replaceAllUsesWith(NaClSetjmpCall); | |
| 154 Call->eraseFromParent(); | |
| 155 } | |
| 156 | |
| 157 void RewritePNaClLibraryCalls::rewriteLongjmpCall(CallInst *Call) { | |
| 158 FunctionType *FTy = Call->getCalledFunction()->getFunctionType(); | |
| 159 | |
| 160 // Sanity check on the longjmp call. | |
| 161 if (FTy->getNumParams() != 2 || | |
| 162 !FTy->getReturnType()->isVoidTy() || | |
| 163 !FTy->getParamType(0)->isPointerTy()) { | |
| 164 report_fatal_error(Twine("Wrong signature of function ") + | |
| 165 Call->getCalledFunction()->getName()); | |
| 166 } | |
| 167 const DebugLoc &DLoc = Call->getDebugLoc(); | |
| 168 | |
| 169 // Find the intrinsic function. | |
| 170 Function *NaClLongjmpFunc = Intrinsic::getDeclaration( | |
| 171 TheModule, Intrinsic::nacl_longjmp); | |
| 172 // Cast the jmp_buf argument to the type NaClLongjmpCall expects. | |
| 173 Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0); | |
| 174 BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy, | |
| 175 "jmp_buf_i8", Call); | |
| 176 JmpBufCast->setDebugLoc(DLoc); | |
| 177 | |
| 178 // Emit the call. | |
| 179 SmallVector<Value *, 2> Args; | |
| 180 Args.push_back(JmpBufCast); | |
| 181 Args.push_back(Call->getArgOperand(1)); | |
| 182 CallInst *NaClLongjmpCall = CallInst::Create(NaClLongjmpFunc, Args, "", Call); | |
| 183 NaClLongjmpCall->setDebugLoc(DLoc); | |
| 184 // No takeName here since longjmp is a void call that does not get assigned to | |
| 185 // a value. | |
| 186 | |
| 187 // Remove the original call. There's no need for RAUW because longjmp | |
| 188 // returns void. | |
| 189 Call->eraseFromParent(); | |
| 190 } | |
| 191 | |
| 192 void RewritePNaClLibraryCalls::rewriteLongjmpStore(StoreInst *Store) { | |
| 193 // Sanity check: this method was called for a store that uses a function | |
| 194 // pointer to setjmp. | |
| 195 Function *CalledFunc = dyn_cast_or_null<Function>(Store->getValueOperand()); | |
| 196 if (CalledFunc != LongjmpFunc) { | |
| 197 report_fatal_error(Twine("Badly formed store of ") + | |
| 198 LongjmpFunc->getName()); | |
| 199 } | |
| 200 | |
| 201 Function *LongjmpWrapperFunc = getOrCreateLongjmpWrapper(); | |
| 202 | |
| 203 // Replace Store by a new store that stores a pointer to the wrapper. | |
| 204 StoreInst *WrapperStore = new StoreInst(LongjmpWrapperFunc, | |
| 205 Store->getPointerOperand(), | |
| 206 Store); | |
| 207 WrapperStore->setDebugLoc(Store->getDebugLoc()); | |
| 208 WrapperStore->takeName(Store); | |
| 209 Store->replaceAllUsesWith(WrapperStore); | |
| 210 Store->eraseFromParent(); | |
| 211 } | |
| 212 | |
| 213 void RewritePNaClLibraryCalls::rewriteAddrOfLongjmpInGlobal( | |
| 214 GlobalVariable *Global) { | |
| 215 if (!Global->hasUniqueInitializer()) { | |
| 216 report_fatal_error(Twine("Badly formed assignment to global ") + | |
| 217 Global->getName()); | |
| 218 } | |
| 219 | |
| 220 Function *LongjmpWrapperFunc = getOrCreateLongjmpWrapper(); | |
| 221 | |
| 222 GlobalVariable *NewGlobal = new GlobalVariable( | |
| 223 /* M */ *TheModule, | |
| 224 /* Ty */ LongjmpWrapperFunc->getType(), | |
| 225 /* isConstant */ Global->isConstant(), | |
| 226 /* Linkage */ GlobalValue::PrivateLinkage, | |
| 227 /* Initializer */ LongjmpWrapperFunc, | |
| 228 /* Name */ "", | |
| 229 /* InsertBefore */ Global, | |
| 230 /* ThreadLocalMode */ Global->getThreadLocalMode()); | |
| 231 NewGlobal->setAlignment(Global->getAlignment()); | |
| 232 // Using takeName instead of assigning Name in the constructor of | |
| 233 // GlobalVariable because otherwise a numeric suffix is added to the name, | |
| 234 // while we want it to stay exactly the same. | |
| 235 NewGlobal->takeName(Global); | |
| 236 Global->eraseFromParent(); | |
| 237 } | |
| 238 | |
| 239 Function *RewritePNaClLibraryCalls::getOrCreateLongjmpWrapper() { | |
| 240 if (LongjmpWrapperFunc) | |
| 241 return LongjmpWrapperFunc; | |
| 242 | |
| 243 // A wrapper function is created that has the same type as longjmp; it | |
| 244 // redirects the call to the intrinsic after casting pointer argument. | |
| 245 FunctionType *WrapFuncTy = LongjmpFunc->getFunctionType(); | |
| 246 SmallString<32> Name(WRAP_FUNC_PREFIX); Name.append(LONGJMP_NAME); | |
| 247 Function *LongjmpWrapperFunc = dyn_cast<Function>( | |
| 248 TheModule->getOrInsertFunction(Name, WrapFuncTy)); | |
| 249 LongjmpWrapperFunc->setLinkage(Function::PrivateLinkage); | |
| 250 | |
| 251 // This function has just been created. Fill its contents. | |
| 252 LLVMContext &Context = TheModule->getContext(); | |
| 253 BasicBlock *BB = BasicBlock::Create(Context, "entry", LongjmpWrapperFunc); | |
| 254 | |
| 255 Function::arg_iterator LongjmpArgs = LongjmpWrapperFunc->arg_begin(); | |
| 256 Value *EnvArg = LongjmpArgs++; | |
| 257 EnvArg->setName("env"); | |
| 258 Value *ValArg = LongjmpArgs++; | |
| 259 ValArg->setName("val"); | |
| 260 | |
| 261 // Insert a return instruction | |
| 262 Instruction *Ret = ReturnInst::Create(Context, 0, BB); | |
| 263 | |
| 264 // Find the intrinsic function. | |
| 265 Function *NaClLongjmpFunc = Intrinsic::getDeclaration( | |
| 266 TheModule, Intrinsic::nacl_longjmp); | |
| 267 // Cast the jmp_buf argument to the type NaClLongjmpCall expects. | |
| 268 Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0); | |
| 269 BitCastInst *JmpBufCast = new BitCastInst(EnvArg, PtrTy, "jmp_buf_i8", Ret); | |
| 270 | |
| 271 // Emit the call. | |
| 272 SmallVector<Value *, 2> Args; | |
| 273 Args.push_back(JmpBufCast); | |
| 274 Args.push_back(ValArg); | |
| 275 CallInst::Create(NaClLongjmpFunc, Args, "", Ret); | |
| 276 | |
| 277 return LongjmpWrapperFunc; | |
| 278 } | |
| 279 | |
| 280 ModulePass *llvm::createRewritePNaClLibraryCallsPass() { | |
| 281 return new RewritePNaClLibraryCalls(); | |
| 282 } | |
| 283 | |
| OLD | NEW |