Chromium Code Reviews| Index: lib/Transforms/NaCl/RewritePNaClLibraryCalls.cpp | 
| diff --git a/lib/Transforms/NaCl/RewritePNaClLibraryCalls.cpp b/lib/Transforms/NaCl/RewritePNaClLibraryCalls.cpp | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..76de0ef16d05375f9037d4e6720091873d0dc58c | 
| --- /dev/null | 
| +++ b/lib/Transforms/NaCl/RewritePNaClLibraryCalls.cpp | 
| @@ -0,0 +1,140 @@ | 
| +//===- RewritePNaClLibraryCalls.cpp - PNaCl library calls to intrinsics ---===// | 
| +// | 
| +// The LLVM Compiler Infrastructure | 
| +// | 
| +// This file is distributed under the University of Illinois Open Source | 
| +// License. See LICENSE.TXT for details. | 
| +// | 
| +//===----------------------------------------------------------------------===// | 
| +// | 
| +// This pass replaces calls to known library functions by calls to intrinsics | 
| 
 
Mark Seaborn
2013/05/10 16:34:36
'by' -> 'with'
 
eliben
2013/05/10 17:00:51
Done.
 
 | 
| +// that are part of the PNaCl stable bitcode ABI. | 
| +// | 
| +//===----------------------------------------------------------------------===// | 
| + | 
| +#include "llvm/ADT/Twine.h" | 
| +#include "llvm/IR/Instructions.h" | 
| +#include "llvm/IR/Intrinsics.h" | 
| +#include "llvm/IR/Module.h" | 
| +#include "llvm/Pass.h" | 
| +#include "llvm/Transforms/NaCl.h" | 
| + | 
| +using namespace llvm; | 
| + | 
| +namespace { | 
| + class RewritePNaClLibraryCalls : public ModulePass { | 
| 
 
Mark Seaborn
2013/05/10 16:34:36
Maybe comment why this is a ModulePass?  Does it n
 
eliben
2013/05/10 17:00:51
Done.
 
 | 
| + public: | 
| + static char ID; | 
| + RewritePNaClLibraryCalls() : ModulePass(ID) { | 
| + initializeExpandTlsPass(*PassRegistry::getPassRegistry()); | 
| + } | 
| + | 
| + virtual bool runOnModule(Module &M); | 
| + private: | 
| + /// Rewrite the given \p Call to setjmp | 
| + void rewriteSetjmp(CallInst *Call); | 
| + /// Rewrite the given \p Call to longjmp | 
| + void rewriteLongjmp(CallInst *Call); | 
| + | 
| + Module *TheModule; | 
| + }; | 
| +} | 
| + | 
| +char RewritePNaClLibraryCalls::ID = 0; | 
| +INITIALIZE_PASS(RewritePNaClLibraryCalls, "rewrite-pnacl-library-calls", | 
| + "Rewrite PNaCl library calls to stable intrinsics", | 
| + false, false) | 
| + | 
| +bool RewritePNaClLibraryCalls::runOnModule(Module &M) { | 
| + TheModule = &M; | 
| + bool Changed = false; | 
| + | 
| + for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) { | 
| 
 
Mark Seaborn
2013/05/10 16:34:36
Iterating through all calls is inefficient.  It wo
 
eliben
2013/05/10 17:00:51
Yeah, although given a larger amount of functions
 
eliben
2013/05/10 23:39:52
Done.
 
 | 
| + for (Function::iterator FI = MI->begin(), FE = MI->end(); FI != FE; ++FI) { | 
| + for (BasicBlock::iterator I = FI->begin(), E = FI->end(); I != E;) { | 
| + Instruction *Inst = I++; | 
| + | 
| + if (CallInst *Call = dyn_cast<CallInst>(Inst)) { | 
| + StringRef CalleeName = Call->getCalledFunction()->getName(); | 
| 
 
Mark Seaborn
2013/05/10 16:34:36
I think you need to check the linkage type too.  T
 
eliben
2013/05/10 23:39:52
Done.
 
 | 
| + | 
| + if (CalleeName == "setjmp") { | 
| + rewriteSetjmp(Call); | 
| + Changed = true; | 
| + } else if (CalleeName == "longjmp") { | 
| + rewriteLongjmp(Call); | 
| + Changed = true; | 
| + } | 
| + } | 
| + } | 
| + } | 
| + } | 
| + | 
| + return Changed; | 
| +} | 
| + | 
| +void RewritePNaClLibraryCalls::rewriteSetjmp(CallInst *Call) { | 
| + FunctionType *FTy = Call->getCalledFunction()->getFunctionType(); | 
| + | 
| + // Sanity check on the setjmp call. | 
| + if (FTy->getNumParams() != 1 || | 
| + !FTy->getReturnType()->isIntegerTy() || | 
| + !FTy->getParamType(0)->isPointerTy()) { | 
| + report_fatal_error(Twine("Wrong signature of function ") + | 
| + Call->getCalledFunction()->getName()); | 
| + } | 
| + const DebugLoc &DLoc = Call->getDebugLoc(); | 
| + | 
| + // Cast the jmp_buf argument to i8* since this is what the intrinsic expects. | 
| + Type *I8Ptr = Type::getInt8Ty(TheModule->getContext())->getPointerTo(); | 
| 
 
Mark Seaborn
2013/05/10 16:34:36
You could use:
NaclSetjmpFunc->getFunctionType()->
 
 | 
| + BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), I8Ptr, | 
| + "jmp_buf_i8", Call); | 
| + JmpBufCast->setDebugLoc(DLoc); | 
| + | 
| + // Find the intrinsic function and call it. | 
| + Function *NaclSetjmpFunc = Intrinsic::getDeclaration(TheModule, | 
| 
 
Mark Seaborn
2013/05/10 16:34:36
Maybe "Nacl" -> "NaCl"?
 
eliben
2013/05/10 23:39:52
Done.
 
 | 
| + Intrinsic::nacl_setjmp); | 
| + SmallVector<Value *, 2> Args; | 
| + Args.push_back(JmpBufCast); | 
| + CallInst *NaclSetjmpCall = CallInst::Create(NaclSetjmpFunc, Args, "", Call); | 
| + NaclSetjmpCall->setDebugLoc(DLoc); | 
| 
 
Mark Seaborn
2013/05/10 16:34:36
Use takeName() too
 
eliben
2013/05/10 23:39:52
Done.
 
 | 
| + | 
| + // Replace the original call. | 
| + Call->replaceAllUsesWith(NaclSetjmpCall); | 
| + Call->eraseFromParent(); | 
| +} | 
| + | 
| +void RewritePNaClLibraryCalls::rewriteLongjmp(CallInst *Call) { | 
| + FunctionType *FTy = Call->getCalledFunction()->getFunctionType(); | 
| + | 
| + // Sanity check on the longjmp call. | 
| + if (FTy->getNumParams() != 2 || | 
| + !FTy->getReturnType()->isVoidTy() || | 
| + !FTy->getParamType(0)->isPointerTy()) { | 
| + report_fatal_error(Twine("Wrong signature of function ") + | 
| + Call->getCalledFunction()->getName()); | 
| + } | 
| + const DebugLoc &DLoc = Call->getDebugLoc(); | 
| + | 
| + // Cast the jmp_buf argument to i8* since this is what the intrinsic expects. | 
| + Type *I8Ptr = Type::getInt8Ty(TheModule->getContext())->getPointerTo(); | 
| + BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), I8Ptr, | 
| + "jmp_buf_i8", Call); | 
| + JmpBufCast->setDebugLoc(DLoc); | 
| + | 
| + // Find the intrinsic function and call it. | 
| + Function *NaclLongjmpFunc = Intrinsic::getDeclaration(TheModule, | 
| + Intrinsic::nacl_longjmp); | 
| 
 
Mark Seaborn
2013/05/10 16:34:36
Line >80 chars
 
eliben
2013/05/10 23:39:52
Done.
 
 | 
| + SmallVector<Value *, 2> Args; | 
| + Args.push_back(JmpBufCast); | 
| + Args.push_back(Call->getArgOperand(1)); | 
| + CallInst *NaclLongjmpCall = CallInst::Create(NaclLongjmpFunc, Args, "", Call); | 
| + NaclLongjmpCall->setDebugLoc(DLoc); | 
| + | 
| + // Remove the original call. There's no need for RAUW because longjmp | 
| + // returns void. | 
| + Call->eraseFromParent(); | 
| +} | 
| + | 
| +ModulePass *llvm::createRewritePNaClLibraryCallsPass() { | 
| + return new RewritePNaClLibraryCalls(); | 
| +} |