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), | |
|
Mark Seaborn
2013/05/13 20:09:00
Indent by 2 more spaces so that this is more inden
eliben
2013/05/13 22:07:18
Done.
| |
| 33 LongjmpFunc(0), LongjmpWrapperFunc(0) { | |
|
Mark Seaborn
2013/05/13 20:09:00
0 -> NULL?
eliben
2013/05/13 22:07:18
Done.
| |
| 34 // This is a module pass because it may have to introduce | |
| 35 // intrinsic declarations into the module, and rewrite global | |
| 36 // initializers. | |
| 37 initializeRewritePNaClLibraryCallsPass(*PassRegistry::getPassRegistry()); | |
| 38 } | |
| 39 | |
| 40 virtual bool runOnModule(Module &M); | |
| 41 private: | |
| 42 /// Rewrites the given \p Call to setjmp. | |
| 43 void rewriteSetjmpCall(CallInst *Call); | |
| 44 | |
| 45 /// Rewrites the given \p Call to longjmp. | |
| 46 void rewriteLongjmpCall(CallInst *Call); | |
| 47 | |
| 48 /// Rewrites the given \p Store instruction that stores a pointer to | |
|
Mark Seaborn
2013/05/13 20:09:00
Why are you checking specifically for Store instru
| |
| 49 /// longjmp. | |
| 50 void rewriteLongjmpStore(StoreInst *Store); | |
| 51 | |
| 52 void rewriteAddrOfLongjmpInGlobal(GlobalVariable *Global); | |
|
Mark Seaborn
2013/05/13 20:09:00
This also doesn't make sense. You should handle a
| |
| 53 | |
| 54 /// Creates the longjmp wrapper on-demand. | |
| 55 Function *getOrCreateLongjmpWrapper(); | |
| 56 | |
| 57 /// The module this pass runs on. | |
| 58 Module *TheModule; | |
| 59 | |
| 60 /// Global longjmp function the original code calls. NULL if it's not in | |
| 61 /// the module. | |
| 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 | |
| 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 Function *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); | |
| 96 Changed = true; | |
| 97 } else if (isa<StoreInst>(Use) || isa<GlobalVariable>(Use)) { | |
| 98 report_fatal_error("Taking the address of setjmp is invalid"); | |
| 99 } else { | |
| 100 report_fatal_error("Invalid use of setjmp"); | |
| 101 } | |
| 102 } | |
| 103 } | |
| 104 | |
| 105 LongjmpFunc = TheModule->getFunction(LONGJMP_NAME); | |
| 106 if (LongjmpFunc && LongjmpFunc->hasExternalLinkage()) { | |
| 107 for (Value::use_iterator UI = LongjmpFunc->use_begin(), | |
| 108 UE = LongjmpFunc->use_end(); UI != UE;) { | |
| 109 Value *Use = *UI++; | |
| 110 if (CallInst *Call = dyn_cast<CallInst>(Use)) { | |
| 111 rewriteLongjmpCall(Call); | |
| 112 Changed = true; | |
| 113 } else if (StoreInst *Store = dyn_cast<StoreInst>(Use)) { | |
| 114 rewriteLongjmpStore(Store); | |
| 115 Changed = true; | |
| 116 } else if (GlobalVariable *Global = dyn_cast<GlobalVariable>(Use)) { | |
| 117 rewriteAddrOfLongjmpInGlobal(Global); | |
| 118 Changed = true; | |
| 119 } else { | |
| 120 report_fatal_error("Invalid use of longjmp"); | |
| 121 } | |
| 122 } | |
| 123 } | |
| 124 | |
| 125 return Changed; | |
| 126 } | |
| 127 | |
| 128 void RewritePNaClLibraryCalls::rewriteSetjmpCall(CallInst *Call) { | |
| 129 FunctionType *FTy = Call->getCalledFunction()->getFunctionType(); | |
| 130 | |
| 131 // Sanity check on the setjmp call. | |
| 132 if (FTy->getNumParams() != 1 || | |
| 133 !FTy->getReturnType()->isIntegerTy() || | |
| 134 !FTy->getParamType(0)->isPointerTy()) { | |
| 135 report_fatal_error(Twine("Wrong signature of function ") + | |
| 136 Call->getCalledFunction()->getName()); | |
| 137 } | |
| 138 const DebugLoc &DLoc = Call->getDebugLoc(); | |
| 139 | |
| 140 // Find the intrinsic function. | |
| 141 Function *NaClSetjmpFunc = Intrinsic::getDeclaration(TheModule, | |
| 142 Intrinsic::nacl_setjmp); | |
| 143 // Cast the jmp_buf argument to the type NaClSetjmpCall expects. | |
| 144 Type *PtrTy = NaClSetjmpFunc->getFunctionType()->getParamType(0); | |
| 145 BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy, | |
| 146 "jmp_buf_i8", Call); | |
| 147 JmpBufCast->setDebugLoc(DLoc); | |
| 148 | |
| 149 // Emit the updated call. | |
| 150 SmallVector<Value *, 2> Args; | |
|
Mark Seaborn
2013/05/13 20:20:42
Nit: 1 will do here instead of 2
eliben
2013/05/13 22:07:18
Done.
| |
| 151 Args.push_back(JmpBufCast); | |
| 152 CallInst *NaClSetjmpCall = CallInst::Create(NaClSetjmpFunc, Args, "", Call); | |
| 153 NaClSetjmpCall->setDebugLoc(DLoc); | |
| 154 NaClSetjmpCall->takeName(Call); | |
| 155 | |
| 156 // Replace the original call. | |
| 157 Call->replaceAllUsesWith(NaClSetjmpCall); | |
| 158 Call->eraseFromParent(); | |
| 159 } | |
| 160 | |
| 161 void RewritePNaClLibraryCalls::rewriteLongjmpCall(CallInst *Call) { | |
| 162 FunctionType *FTy = Call->getCalledFunction()->getFunctionType(); | |
| 163 | |
| 164 // Sanity check on the longjmp call. | |
| 165 if (FTy->getNumParams() != 2 || | |
| 166 !FTy->getReturnType()->isVoidTy() || | |
| 167 !FTy->getParamType(0)->isPointerTy()) { | |
| 168 report_fatal_error(Twine("Wrong signature of function ") + | |
| 169 Call->getCalledFunction()->getName()); | |
| 170 } | |
| 171 const DebugLoc &DLoc = Call->getDebugLoc(); | |
| 172 | |
| 173 // Find the intrinsic function. | |
| 174 Function *NaClLongjmpFunc = Intrinsic::getDeclaration( | |
| 175 TheModule, Intrinsic::nacl_longjmp); | |
| 176 // Cast the jmp_buf argument to the type NaClLongjmpCall expects. | |
| 177 Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0); | |
| 178 BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy, | |
| 179 "jmp_buf_i8", Call); | |
| 180 JmpBufCast->setDebugLoc(DLoc); | |
| 181 | |
| 182 // Emit the call. | |
| 183 SmallVector<Value *, 2> Args; | |
| 184 Args.push_back(JmpBufCast); | |
| 185 Args.push_back(Call->getArgOperand(1)); | |
| 186 CallInst *NaClLongjmpCall = CallInst::Create(NaClLongjmpFunc, Args, "", Call); | |
| 187 NaClLongjmpCall->setDebugLoc(DLoc); | |
| 188 // No takeName here since longjmp is a void call that does not get assigned to | |
| 189 // a value. | |
| 190 | |
| 191 // Remove the original call. There's no need for RAUW because longjmp | |
| 192 // returns void. | |
| 193 Call->eraseFromParent(); | |
| 194 } | |
| 195 | |
| 196 void RewritePNaClLibraryCalls::rewriteLongjmpStore(StoreInst *Store) { | |
| 197 // Sanity check: this method was called for a store that uses a function | |
| 198 // pointer to setjmp. | |
| 199 Function *CalledFunc = dyn_cast_or_null<Function>(Store->getValueOperand()); | |
| 200 if (CalledFunc != LongjmpFunc) { | |
| 201 report_fatal_error(Twine("Badly formed store of ") + | |
| 202 LongjmpFunc->getName()); | |
| 203 } | |
| 204 | |
| 205 Function *LongjmpWrapperFunc = getOrCreateLongjmpWrapper(); | |
| 206 | |
| 207 // Replace Store by a new store that stores a pointer to the wrapper. | |
|
Mark Seaborn
2013/05/13 20:20:42
You should bitcast your wrapper function rather th
| |
| 208 StoreInst *WrapperStore = new StoreInst(LongjmpWrapperFunc, | |
| 209 Store->getPointerOperand(), | |
| 210 Store); | |
| 211 WrapperStore->setDebugLoc(Store->getDebugLoc()); | |
| 212 WrapperStore->takeName(Store); | |
| 213 Store->replaceAllUsesWith(WrapperStore); | |
| 214 Store->eraseFromParent(); | |
| 215 } | |
| 216 | |
| 217 void RewritePNaClLibraryCalls::rewriteAddrOfLongjmpInGlobal( | |
| 218 GlobalVariable *Global) { | |
| 219 if (!Global->hasUniqueInitializer()) { | |
| 220 report_fatal_error(Twine("Badly formed assignment to global ") + | |
| 221 Global->getName()); | |
| 222 } | |
| 223 | |
| 224 Function *LongjmpWrapperFunc = getOrCreateLongjmpWrapper(); | |
| 225 | |
| 226 GlobalVariable *NewGlobal = new GlobalVariable( | |
| 227 /* M */ *TheModule, | |
| 228 /* Ty */ LongjmpWrapperFunc->getType(), | |
| 229 /* isConstant */ Global->isConstant(), | |
| 230 /* Linkage */ GlobalValue::PrivateLinkage, | |
| 231 /* Initializer */ LongjmpWrapperFunc, | |
| 232 /* Name */ "", | |
| 233 /* InsertBefore */ Global, | |
| 234 /* ThreadLocalMode */ Global->getThreadLocalMode()); | |
| 235 NewGlobal->setAlignment(Global->getAlignment()); | |
| 236 // Using takeName instead of assigning Name in the constructor of | |
| 237 // GlobalVariable because otherwise a numeric suffix is added to the name, | |
| 238 // while we want it to stay exactly the same. | |
| 239 NewGlobal->takeName(Global); | |
| 240 Global->eraseFromParent(); | |
| 241 } | |
| 242 | |
| 243 Function *RewritePNaClLibraryCalls::getOrCreateLongjmpWrapper() { | |
| 244 if (LongjmpWrapperFunc) | |
| 245 return LongjmpWrapperFunc; | |
| 246 | |
| 247 // A wrapper function is created that has the same type as longjmp; it | |
|
Mark Seaborn
2013/05/13 20:20:42
You actually don't need to create a new function.
eliben
2013/05/13 22:07:18
Done.
| |
| 248 // redirects the call to the intrinsic after casting pointer argument. | |
| 249 FunctionType *WrapFuncTy = LongjmpFunc->getFunctionType(); | |
| 250 SmallString<32> Name(WRAP_FUNC_PREFIX); Name.append(LONGJMP_NAME); | |
|
Mark Seaborn
2013/05/13 20:20:42
Split onto separate lines.
eliben
2013/05/13 22:07:18
Function removed.
| |
| 251 Function *LongjmpWrapperFunc = dyn_cast<Function>( | |
| 252 TheModule->getOrInsertFunction(Name, WrapFuncTy)); | |
| 253 LongjmpWrapperFunc->setLinkage(Function::PrivateLinkage); | |
| 254 | |
| 255 // This function has just been created. Fill its contents. | |
| 256 LLVMContext &Context = TheModule->getContext(); | |
| 257 BasicBlock *BB = BasicBlock::Create(Context, "entry", LongjmpWrapperFunc); | |
| 258 | |
| 259 Function::arg_iterator LongjmpArgs = LongjmpWrapperFunc->arg_begin(); | |
| 260 Value *EnvArg = LongjmpArgs++; | |
| 261 EnvArg->setName("env"); | |
| 262 Value *ValArg = LongjmpArgs++; | |
| 263 ValArg->setName("val"); | |
| 264 | |
| 265 // Insert a return instruction | |
|
Mark Seaborn
2013/05/13 20:20:42
Nit: could insert 'unreachable' instead
eliben
2013/05/13 22:07:18
Done.
| |
| 266 Instruction *Ret = ReturnInst::Create(Context, 0, BB); | |
| 267 | |
| 268 // Find the intrinsic function. | |
| 269 Function *NaClLongjmpFunc = Intrinsic::getDeclaration( | |
| 270 TheModule, Intrinsic::nacl_longjmp); | |
| 271 // Cast the jmp_buf argument to the type NaClLongjmpCall expects. | |
| 272 Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0); | |
| 273 BitCastInst *JmpBufCast = new BitCastInst(EnvArg, PtrTy, "jmp_buf_i8", Ret); | |
| 274 | |
| 275 // Emit the call. | |
| 276 SmallVector<Value *, 2> Args; | |
| 277 Args.push_back(JmpBufCast); | |
| 278 Args.push_back(ValArg); | |
| 279 CallInst::Create(NaClLongjmpFunc, Args, "", Ret); | |
| 280 | |
| 281 return LongjmpWrapperFunc; | |
| 282 } | |
| 283 | |
| 284 ModulePass *llvm::createRewritePNaClLibraryCallsPass() { | |
| 285 return new RewritePNaClLibraryCalls(); | |
| 286 } | |
| 287 | |
| OLD | NEW |