| 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();
|
| +}
|
|
|