| 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..2373343f59afe6daf6a09e1c07d69ff75029653a
 | 
| --- /dev/null
 | 
| +++ b/lib/Transforms/NaCl/RewritePNaClLibraryCalls.cpp
 | 
| @@ -0,0 +1,225 @@
 | 
| +//===- 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 with calls to intrinsics
 | 
| +// that are part of the PNaCl stable bitcode ABI.
 | 
| +//
 | 
| +//===----------------------------------------------------------------------===//
 | 
| +
 | 
| +#include "llvm/ADT/SmallString.h"
 | 
| +#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 {
 | 
| +  public:
 | 
| +    static char ID;
 | 
| +    RewritePNaClLibraryCalls() :
 | 
| +        ModulePass(ID), TheModule(NULL) {
 | 
| +      // This is a module pass because it may have to introduce
 | 
| +      // intrinsic declarations into the module and modify a global function.
 | 
| +      initializeRewritePNaClLibraryCallsPass(*PassRegistry::getPassRegistry());
 | 
| +    }
 | 
| +
 | 
| +    virtual bool runOnModule(Module &M);
 | 
| +  private:
 | 
| +    /// Rewrites the given \p Call of setjmp to a direct intrinsic call.
 | 
| +    void rewriteSetjmpCall(CallInst *Call);
 | 
| +
 | 
| +    /// Rewrites the given \p Call of longjmp to a direct intrinsic call.
 | 
| +    void rewriteLongjmpCall(CallInst *Call);
 | 
| +
 | 
| +    /// Populates the body of longjmp as a wrapper of the intrinsic call.
 | 
| +    /// Should only be called once. Modifies the given \p LongjmpFunc.
 | 
| +    void populateLongjmpWrapper(Function *LongjmpFunc);
 | 
| +
 | 
| +    /// Sanity check that the types of these functions are what we expect them
 | 
| +    /// to be.
 | 
| +    void sanityCheckSetjmpFunc(Function *SetjmpFunc);
 | 
| +    void sanityCheckLongjmpFunc(Function *LongjmpFunc);
 | 
| +
 | 
| +    /// The module this pass runs on.
 | 
| +    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;
 | 
| +
 | 
| +  // Iterate over all uses of the setjmp, if it exists in the module with
 | 
| +  // external linkage. If it exists but the linkage is not external, this may
 | 
| +  // come from code that defines its own function named setjmp and doesn't
 | 
| +  // include <setjmp.h>. In such a case we leave the code as it is.
 | 
| +  //
 | 
| +  // The calls are replaced with intrinsics. All other uses of setjmp are
 | 
| +  // disallowed (taking the address of setjmp is disallowed in C and C++).
 | 
| +  Function *SetjmpFunc = TheModule->getFunction("setjmp");
 | 
| +
 | 
| +  if (SetjmpFunc && SetjmpFunc->hasExternalLinkage()) {
 | 
| +    sanityCheckSetjmpFunc(SetjmpFunc);
 | 
| +
 | 
| +    for (Value::use_iterator UI = SetjmpFunc->use_begin(),
 | 
| +                             UE = SetjmpFunc->use_end(); UI != UE;) {
 | 
| +      Value *Use = *UI++;
 | 
| +      if (CallInst *Call = dyn_cast<CallInst>(Use)) {
 | 
| +        rewriteSetjmpCall(Call);
 | 
| +        Changed = true;
 | 
| +      } else {
 | 
| +        report_fatal_error("Taking the address of setjmp is invalid");
 | 
| +      }
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  // For longjmp things are a little more complicated, since longjmp's address
 | 
| +  // can be taken. Therefore, longjmp can appear in a variety of Uses. The
 | 
| +  // common case is still a direct call and we want that to be as efficient as
 | 
| +  // possible, so we rewrite it into a direct intrinsic call. If there are other
 | 
| +  // uses, the actual body of longjmp is populated with a wrapper that calls
 | 
| +  // the intrinsic.
 | 
| +  Function *LongjmpFunc = TheModule->getFunction("longjmp");
 | 
| +
 | 
| +  if (LongjmpFunc && LongjmpFunc->hasExternalLinkage()) {
 | 
| +    sanityCheckLongjmpFunc(LongjmpFunc);
 | 
| +
 | 
| +    for (Value::use_iterator UI = LongjmpFunc->use_begin(),
 | 
| +                             UE = LongjmpFunc->use_end(); UI != UE;) {
 | 
| +      Value *Use = *UI++;
 | 
| +      if (CallInst *Call = dyn_cast<CallInst>(Use)) {
 | 
| +        rewriteLongjmpCall(Call);
 | 
| +        Changed = true;
 | 
| +      }
 | 
| +    }
 | 
| +
 | 
| +    // If additional uses remain, these aren't calls; populate the wrapper.
 | 
| +    if (!LongjmpFunc->use_empty()) {
 | 
| +      populateLongjmpWrapper(LongjmpFunc);
 | 
| +      Changed = true;
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  return Changed;
 | 
| +}
 | 
| +
 | 
| +void RewritePNaClLibraryCalls::rewriteSetjmpCall(CallInst *Call) {
 | 
| +  // Find the intrinsic function.
 | 
| +  Function *NaClSetjmpFunc = Intrinsic::getDeclaration(TheModule,
 | 
| +                                                       Intrinsic::nacl_setjmp);
 | 
| +  // Cast the jmp_buf argument to the type NaClSetjmpCall expects.
 | 
| +  Type *PtrTy = NaClSetjmpFunc->getFunctionType()->getParamType(0);
 | 
| +  BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy,
 | 
| +                                            "jmp_buf_i8", Call);
 | 
| +  const DebugLoc &DLoc = Call->getDebugLoc();
 | 
| +  JmpBufCast->setDebugLoc(DLoc);
 | 
| +
 | 
| +  // Emit the updated call.
 | 
| +  SmallVector<Value *, 1> Args;
 | 
| +  Args.push_back(JmpBufCast);
 | 
| +  CallInst *NaClSetjmpCall = CallInst::Create(NaClSetjmpFunc, Args, "", Call);
 | 
| +  NaClSetjmpCall->setDebugLoc(DLoc);
 | 
| +  NaClSetjmpCall->takeName(Call);
 | 
| +
 | 
| +  // Replace the original call.
 | 
| +  Call->replaceAllUsesWith(NaClSetjmpCall);
 | 
| +  Call->eraseFromParent();
 | 
| +}
 | 
| +
 | 
| +void RewritePNaClLibraryCalls::sanityCheckLongjmpFunc(Function *LongjmpFunc) {
 | 
| +  FunctionType *FTy = LongjmpFunc->getFunctionType();
 | 
| +  if (!(FTy->getNumParams() == 2 &&
 | 
| +        FTy->getReturnType()->isVoidTy() &&
 | 
| +        FTy->getParamType(0)->isPointerTy() &&
 | 
| +        FTy->getParamType(1)->isIntegerTy())) {
 | 
| +    report_fatal_error("Wrong signature of longjmp");
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +void RewritePNaClLibraryCalls::sanityCheckSetjmpFunc(Function *SetjmpFunc) {
 | 
| +  FunctionType *FTy = SetjmpFunc->getFunctionType();
 | 
| +  if (!(FTy->getNumParams() == 1 &&
 | 
| +        FTy->getReturnType()->isIntegerTy() &&
 | 
| +        FTy->getParamType(0)->isPointerTy())) {
 | 
| +    report_fatal_error("Wrong signature of setjmp");
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +void RewritePNaClLibraryCalls::rewriteLongjmpCall(CallInst *Call) {
 | 
| +  // Find the intrinsic function.
 | 
| +  Function *NaClLongjmpFunc = Intrinsic::getDeclaration(
 | 
| +      TheModule, Intrinsic::nacl_longjmp);
 | 
| +  // Cast the jmp_buf argument to the type NaClLongjmpCall expects.
 | 
| +  Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0);
 | 
| +  BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy,
 | 
| +                                            "jmp_buf_i8", Call);
 | 
| +  const DebugLoc &DLoc = Call->getDebugLoc();
 | 
| +  JmpBufCast->setDebugLoc(DLoc);
 | 
| +
 | 
| +  // Emit the call.
 | 
| +  SmallVector<Value *, 2> Args;
 | 
| +  Args.push_back(JmpBufCast);
 | 
| +  Args.push_back(Call->getArgOperand(1));
 | 
| +  CallInst *NaClLongjmpCall = CallInst::Create(NaClLongjmpFunc, Args, "", Call);
 | 
| +  NaClLongjmpCall->setDebugLoc(DLoc);
 | 
| +  // No takeName here since longjmp is a void call that does not get assigned to
 | 
| +  // a value.
 | 
| +
 | 
| +  // Remove the original call. There's no need for RAUW because longjmp
 | 
| +  // returns void.
 | 
| +  Call->eraseFromParent();
 | 
| +}
 | 
| +
 | 
| +void RewritePNaClLibraryCalls::populateLongjmpWrapper(Function *LongjmpFunc) {
 | 
| +  assert(LongjmpFunc->size() == 0 &&
 | 
| +      "Expected to be called when longjmp has an empty body");
 | 
| +
 | 
| +  // Populate longjmp with code.
 | 
| +  LLVMContext &Context = TheModule->getContext();
 | 
| +  BasicBlock *BB = BasicBlock::Create(Context, "entry", LongjmpFunc);
 | 
| +
 | 
| +  Function::arg_iterator LongjmpArgs = LongjmpFunc->arg_begin();
 | 
| +  Value *EnvArg = LongjmpArgs++;
 | 
| +  EnvArg->setName("env");
 | 
| +  Value *ValArg = LongjmpArgs++;
 | 
| +  ValArg->setName("val");
 | 
| +
 | 
| +  // Find the intrinsic function.
 | 
| +  Function *NaClLongjmpFunc = Intrinsic::getDeclaration(
 | 
| +      TheModule, Intrinsic::nacl_longjmp);
 | 
| +  // Cast the jmp_buf argument to the type NaClLongjmpCall expects.
 | 
| +  Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0);
 | 
| +  BitCastInst *JmpBufCast = new BitCastInst(EnvArg,  PtrTy, "jmp_buf_i8", BB);
 | 
| +
 | 
| +  // Emit the call.
 | 
| +  SmallVector<Value *, 2> Args;
 | 
| +  Args.push_back(JmpBufCast);
 | 
| +  Args.push_back(ValArg);
 | 
| +  CallInst::Create(NaClLongjmpFunc, Args, "", BB);
 | 
| +
 | 
| +  // Insert an unreachable instruction to terminate this function since longjmp
 | 
| +  // does not return.
 | 
| +  new UnreachableInst(Context, BB);
 | 
| +
 | 
| +  // Finally, set the linkage to internal
 | 
| +  LongjmpFunc->setLinkage(Function::InternalLinkage);
 | 
| +}
 | 
| +
 | 
| +ModulePass *llvm::createRewritePNaClLibraryCallsPass() {
 | 
| +  return new RewritePNaClLibraryCalls();
 | 
| +}
 | 
| 
 |