| 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..fb44cfb51e9a26f11af31fdec5680ef30c0248c8
|
| --- /dev/null
|
| +++ b/lib/Transforms/NaCl/RewritePNaClLibraryCalls.cpp
|
| @@ -0,0 +1,545 @@
|
| +//===- 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/Constants.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"
|
| +#include <cstdarg>
|
| +
|
| +using namespace llvm;
|
| +
|
| +namespace {
|
| + class RewritePNaClLibraryCalls : public ModulePass {
|
| + public:
|
| + static char ID;
|
| + RewritePNaClLibraryCalls() :
|
| + ModulePass(ID), TheModule(NULL), Context(NULL), SetjmpIntrinsic(NULL),
|
| + LongjmpIntrinsic(NULL), MemcpyIntrinsic(NULL),
|
| + MemmoveIntrinsic(NULL), MemsetIntrinsic(NULL) {
|
| + // This is a module pass because it may have to introduce
|
| + // intrinsic declarations into the module and modify globals.
|
| + initializeRewritePNaClLibraryCallsPass(*PassRegistry::getPassRegistry());
|
| + }
|
| +
|
| + virtual bool runOnModule(Module &M);
|
| + private:
|
| + typedef void (RewritePNaClLibraryCalls::*RewriteCallFunc)(CallInst *);
|
| + typedef void (RewritePNaClLibraryCalls::*PopulateWrapperFunc)(Function *);
|
| +
|
| + /// Handles a certain pattern of library function -> intrinsic rewrites.
|
| + /// Currently all library functions this pass knows how to rewrite fall into
|
| + /// this pattern.
|
| + /// RewriteLibraryCall performs the rewrite for a single library function
|
| + /// and is customized by its arguments.
|
| + ///
|
| + /// \p LibraryFunctionName Name of the library function to look for.
|
| + /// \p CorrectFunctionType is the correct type of this library function.
|
| + /// \p CallRewriter Method that rewrites the library function call into an
|
| + /// intrinsic call.
|
| + /// \p OnlyCallsAllowed Only calls to this library function are allowed.
|
| + /// \p WrapperPopulator called to populate the body of the library function
|
| + /// with a wrapped intrinsic call.
|
| + bool RewriteLibraryCall(
|
| + const char *LibraryFunctionName,
|
| + FunctionType *CorrectFunctionType,
|
| + RewriteCallFunc CallRewriter,
|
| + bool OnlyCallsAllowed,
|
| + PopulateWrapperFunc WrapperPopulator);
|
| +
|
| + /// Two function types are compatible if they have compatible return types
|
| + /// and the same number of compatible parameters. Return types and
|
| + /// parameters are compatible if they are exactly the same type or both are
|
| + /// pointer types.
|
| + static bool compatibleFunctionTypes(FunctionType *FTy1, FunctionType *FTy2);
|
| + static bool compatibleParamOrRetTypes(Type *Ty1, Type *Ty2);
|
| +
|
| + void rewriteSetjmpCall(CallInst *Call);
|
| + void rewriteLongjmpCall(CallInst *Call);
|
| + void rewriteMemcpyCall(CallInst *Call);
|
| + void rewriteMemmoveCall(CallInst *Call);
|
| + void rewriteMemsetCall(CallInst *Call);
|
| +
|
| + void populateSetjmpWrapper(Function *SetjmpFunc);
|
| + void populateLongjmpWrapper(Function *LongjmpFunc);
|
| + void populateMemcpyWrapper(Function *MemcpyFunc);
|
| + void populateMemmoveWrapper(Function *MemmoveFunc);
|
| + void populateMemsetWrapper(Function *MemsetFunc);
|
| +
|
| + /// Generic implementation of populating a wrapper function.
|
| + /// Initially, the function exists in the module as a declaration with
|
| + /// unnamed arguments. This method is called with a NULL-terminated list
|
| + /// of argument names that get assigned in the generated IR for
|
| + /// readability.
|
| + void populateWrapperCommon(
|
| + Function *Func,
|
| + StringRef FuncName,
|
| + RewriteCallFunc CallRewriter,
|
| + bool CallCannotReturn,
|
| + ...);
|
| +
|
| + /// Find and cache known intrinsics.
|
| + Function *findSetjmpIntrinsic();
|
| + Function *findLongjmpIntrinsic();
|
| + Function *findMemcpyIntrinsic();
|
| + Function *findMemmoveIntrinsic();
|
| + Function *findMemsetIntrinsic();
|
| +
|
| + /// Cached data that remains the same throughout a module run.
|
| + Module *TheModule;
|
| + LLVMContext *Context;
|
| +
|
| + /// These are cached but computed lazily.
|
| + Function *SetjmpIntrinsic;
|
| + Function *LongjmpIntrinsic;
|
| + Function *MemcpyIntrinsic;
|
| + Function *MemmoveIntrinsic;
|
| + Function *MemsetIntrinsic;
|
| + };
|
| +}
|
| +
|
| +char RewritePNaClLibraryCalls::ID = 0;
|
| +INITIALIZE_PASS(RewritePNaClLibraryCalls, "rewrite-pnacl-library-calls",
|
| + "Rewrite PNaCl library calls to stable intrinsics",
|
| + false, false)
|
| +
|
| +bool RewritePNaClLibraryCalls::RewriteLibraryCall(
|
| + const char *LibraryFunctionName,
|
| + FunctionType *CorrectFunctionType,
|
| + RewriteCallFunc CallRewriter,
|
| + bool OnlyCallsAllowed,
|
| + PopulateWrapperFunc WrapperPopulator) {
|
| + bool Changed = false;
|
| +
|
| + Function *LibFunc = TheModule->getFunction(LibraryFunctionName);
|
| +
|
| + // Iterate over all uses of this function, 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 private function with the same name
|
| + // and doesn't actually include the standard libc header declaring it.
|
| + // In such a case we leave the code as it is.
|
| + //
|
| + // Another case we need to handle here is this function having the wrong
|
| + // prototype (incompatible with the C library function prototype, and hence
|
| + // incompatible with the intrinsic). In general, this is undefined behavior,
|
| + // but we can't fail compilation because some workflows rely on it
|
| + // compiling correctly (for example, autoconf). The solution is:
|
| + // When the declared type of the function in the module is not correct, we
|
| + // re-create the function with the correct prototype and replace all calls
|
| + // to this new function (casted to the old function type). Effectively this
|
| + // delays the undefined behavior until run-time.
|
| + if (LibFunc && LibFunc->hasExternalLinkage()) {
|
| + if (!compatibleFunctionTypes(LibFunc->getFunctionType(),
|
| + CorrectFunctionType)) {
|
| + // Use the RecreateFunction utility to create a new function with the
|
| + // correct prototype. RecreateFunction also RAUWs the function with
|
| + // proper bitcasts.
|
| + //
|
| + // One interesting case that may arise is when the original module had
|
| + // calls to both a correct and an incorrect version of the library
|
| + // function. Depending on the linking order, either version could be
|
| + // selected as the global declaration in the module, so even valid calls
|
| + // could end up being bitcast-ed from the incorrect to the correct
|
| + // function type. The RecreateFunction call below will eliminate such
|
| + // bitcasts (because the new type matches the call type), but dead
|
| + // constant expressions may be left behind.
|
| + // These are cleaned up with removeDeadConstantUsers.
|
| + Function *NewFunc = RecreateFunction(LibFunc, CorrectFunctionType);
|
| + LibFunc->eraseFromParent();
|
| + NewFunc->setLinkage(Function::InternalLinkage);
|
| + Changed = true;
|
| + NewFunc->removeDeadConstantUsers();
|
| + LibFunc = NewFunc;
|
| + }
|
| +
|
| + // Handle all uses that are calls. These are simply replaced with
|
| + // equivalent intrinsic calls.
|
| + {
|
| + SmallVector<CallInst *, 32> Calls;
|
| + for (User *U : LibFunc->users())
|
| + // users() will also provide call instructions in which the used value
|
| + // is an argument, and not the value being called. Make sure we rewrite
|
| + // only actual calls to LibFunc here.
|
| + if (CallInst *Call = dyn_cast<CallInst>(U))
|
| + if (Call->getCalledValue() == LibFunc)
|
| + Calls.push_back(Call);
|
| +
|
| + for (auto Call : Calls)
|
| + (this->*(CallRewriter))(Call);
|
| +
|
| + Changed |= !Calls.empty();
|
| + }
|
| +
|
| + if (LibFunc->use_empty()) {
|
| + LibFunc->eraseFromParent();
|
| + } else if (OnlyCallsAllowed) {
|
| + // If additional uses remain, these aren't calls.
|
| + report_fatal_error(Twine("Taking the address of ") +
|
| + LibraryFunctionName + " is invalid");
|
| + } else {
|
| + // If non-call uses remain and allowed for this function, populate it
|
| + // with a wrapper.
|
| + (this->*(WrapperPopulator))(LibFunc);
|
| + LibFunc->setLinkage(Function::InternalLinkage);
|
| + Changed = true;
|
| + }
|
| + }
|
| +
|
| + return Changed;
|
| +}
|
| +
|
| +bool RewritePNaClLibraryCalls::runOnModule(Module &M) {
|
| + TheModule = &M;
|
| + Context = &TheModule->getContext();
|
| + bool Changed = false;
|
| +
|
| + Type *Int8PtrTy = Type::getInt8PtrTy(*Context);
|
| + Type *Int64PtrTy = Type::getInt64PtrTy(*Context);
|
| + Type *Int32Ty = Type::getInt32Ty(*Context);
|
| + Type *VoidTy = Type::getVoidTy(*Context);
|
| +
|
| + Type *SetjmpParams[] = { Int64PtrTy };
|
| + FunctionType *SetjmpFunctionType = FunctionType::get(Int32Ty, SetjmpParams,
|
| + false);
|
| + Changed |= RewriteLibraryCall(
|
| + "setjmp",
|
| + SetjmpFunctionType,
|
| + &RewritePNaClLibraryCalls::rewriteSetjmpCall,
|
| + true,
|
| + &RewritePNaClLibraryCalls::populateSetjmpWrapper);
|
| +
|
| + Type *LongjmpParams[] = { Int64PtrTy, Int32Ty };
|
| + FunctionType *LongjmpFunctionType = FunctionType::get(VoidTy, LongjmpParams,
|
| + false);
|
| + Changed |= RewriteLibraryCall(
|
| + "longjmp",
|
| + LongjmpFunctionType,
|
| + &RewritePNaClLibraryCalls::rewriteLongjmpCall,
|
| + false,
|
| + &RewritePNaClLibraryCalls::populateLongjmpWrapper);
|
| +
|
| + Type *MemsetParams[] = { Int8PtrTy, Int32Ty, Int32Ty };
|
| + FunctionType *MemsetFunctionType = FunctionType::get(Int8PtrTy, MemsetParams,
|
| + false);
|
| + Changed |= RewriteLibraryCall(
|
| + "memset",
|
| + MemsetFunctionType,
|
| + &RewritePNaClLibraryCalls::rewriteMemsetCall,
|
| + false,
|
| + &RewritePNaClLibraryCalls::populateMemsetWrapper);
|
| +
|
| + Type *MemcpyParams[] = { Int8PtrTy, Int8PtrTy, Int32Ty };
|
| + FunctionType *MemcpyFunctionType = FunctionType::get(Int8PtrTy, MemcpyParams,
|
| + false);
|
| + Changed |= RewriteLibraryCall(
|
| + "memcpy",
|
| + MemcpyFunctionType,
|
| + &RewritePNaClLibraryCalls::rewriteMemcpyCall,
|
| + false,
|
| + &RewritePNaClLibraryCalls::populateMemcpyWrapper);
|
| +
|
| + Type *MemmoveParams[] = { Int8PtrTy, Int8PtrTy, Int32Ty };
|
| + FunctionType *MemmoveFunctionType = FunctionType::get(Int8PtrTy,
|
| + MemmoveParams,
|
| + false);
|
| + Changed |= RewriteLibraryCall(
|
| + "memmove",
|
| + MemmoveFunctionType,
|
| + &RewritePNaClLibraryCalls::rewriteMemmoveCall,
|
| + false,
|
| + &RewritePNaClLibraryCalls::populateMemmoveWrapper);
|
| +
|
| + return Changed;
|
| +}
|
| +
|
| +bool RewritePNaClLibraryCalls::compatibleFunctionTypes(FunctionType *FTy1,
|
| + FunctionType *FTy2) {
|
| + if (FTy1->getNumParams() != FTy2->getNumParams()) {
|
| + return false;
|
| + }
|
| +
|
| + if (!compatibleParamOrRetTypes(FTy1->getReturnType(),
|
| + FTy2->getReturnType())) {
|
| + return false;
|
| + }
|
| +
|
| + for (unsigned I = 0, End = FTy1->getNumParams(); I != End; ++I) {
|
| + if (!compatibleParamOrRetTypes(FTy1->getParamType(I),
|
| + FTy2->getParamType(I))) {
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool RewritePNaClLibraryCalls::compatibleParamOrRetTypes(Type *Ty1,
|
| + Type *Ty2) {
|
| + return (Ty1 == Ty2 || (Ty1->isPointerTy() && Ty2->isPointerTy()));
|
| +}
|
| +
|
| +void RewritePNaClLibraryCalls::rewriteSetjmpCall(CallInst *Call) {
|
| + // Find the intrinsic function.
|
| + Function *NaClSetjmpFunc = findSetjmpIntrinsic();
|
| + // 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.
|
| + Value *Args[] = { 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::rewriteLongjmpCall(CallInst *Call) {
|
| + // Find the intrinsic function.
|
| + Function *NaClLongjmpFunc = findLongjmpIntrinsic();
|
| + // 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.
|
| + Value *Args[] = { JmpBufCast, 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::rewriteMemcpyCall(CallInst *Call) {
|
| + Function *MemcpyIntrinsic = findMemcpyIntrinsic();
|
| + // dest, src, len, align, isvolatile
|
| + Value *Args[] = { Call->getArgOperand(0),
|
| + Call->getArgOperand(1),
|
| + Call->getArgOperand(2),
|
| + ConstantInt::get(Type::getInt32Ty(*Context), 1),
|
| + ConstantInt::get(Type::getInt1Ty(*Context), 0) };
|
| + CallInst *MemcpyIntrinsicCall = CallInst::Create(MemcpyIntrinsic,
|
| + Args, "", Call);
|
| + MemcpyIntrinsicCall->setDebugLoc(Call->getDebugLoc());
|
| +
|
| + // libc memcpy returns the source pointer, but the LLVM intrinsic doesn't; if
|
| + // the return value has actual uses, just replace them with the dest
|
| + // argument itself.
|
| + Call->replaceAllUsesWith(Call->getArgOperand(0));
|
| + Call->eraseFromParent();
|
| +}
|
| +
|
| +void RewritePNaClLibraryCalls::rewriteMemmoveCall(CallInst *Call) {
|
| + Function *MemmoveIntrinsic = findMemmoveIntrinsic();
|
| + // dest, src, len, align, isvolatile
|
| + Value *Args[] = { Call->getArgOperand(0),
|
| + Call->getArgOperand(1),
|
| + Call->getArgOperand(2),
|
| + ConstantInt::get(Type::getInt32Ty(*Context), 1),
|
| + ConstantInt::get(Type::getInt1Ty(*Context), 0) };
|
| + CallInst *MemmoveIntrinsicCall = CallInst::Create(MemmoveIntrinsic,
|
| + Args, "", Call);
|
| + MemmoveIntrinsicCall->setDebugLoc(Call->getDebugLoc());
|
| +
|
| + // libc memmove returns the source pointer, but the LLVM intrinsic doesn't; if
|
| + // the return value has actual uses, just replace them with the dest
|
| + // argument itself.
|
| + Call->replaceAllUsesWith(Call->getArgOperand(0));
|
| + Call->eraseFromParent();
|
| +}
|
| +
|
| +void RewritePNaClLibraryCalls::rewriteMemsetCall(CallInst *Call) {
|
| + Function *MemsetIntrinsic = findMemsetIntrinsic();
|
| + // libc memset has 'int c' for the filler byte, but the LLVM intrinsic uses
|
| + // a i8; truncation is required.
|
| + TruncInst *ByteTrunc = new TruncInst(Call->getArgOperand(1),
|
| + Type::getInt8Ty(*Context),
|
| + "trunc_byte", Call);
|
| +
|
| + const DebugLoc &DLoc = Call->getDebugLoc();
|
| + ByteTrunc->setDebugLoc(DLoc);
|
| +
|
| + // dest, val, len, align, isvolatile
|
| + Value *Args[] = { Call->getArgOperand(0),
|
| + ByteTrunc,
|
| + Call->getArgOperand(2),
|
| + ConstantInt::get(Type::getInt32Ty(*Context), 1),
|
| + ConstantInt::get(Type::getInt1Ty(*Context), 0) };
|
| + CallInst *MemsetIntrinsicCall = CallInst::Create(MemsetIntrinsic,
|
| + Args, "", Call);
|
| + MemsetIntrinsicCall->setDebugLoc(DLoc);
|
| +
|
| + // libc memset returns the source pointer, but the LLVM intrinsic doesn't; if
|
| + // the return value has actual uses, just replace them with the dest
|
| + // argument itself.
|
| + Call->replaceAllUsesWith(Call->getArgOperand(0));
|
| + Call->eraseFromParent();
|
| +}
|
| +
|
| +void RewritePNaClLibraryCalls::populateWrapperCommon(
|
| + Function *Func,
|
| + StringRef FuncName,
|
| + RewriteCallFunc CallRewriter,
|
| + bool CallCannotReturn,
|
| + ...) {
|
| + if (!Func->isDeclaration()) {
|
| + report_fatal_error(Twine("Expected ") + FuncName +
|
| + " to be declared, not defined");
|
| + }
|
| +
|
| + // Populate the function body with code.
|
| + BasicBlock *BB = BasicBlock::Create(*Context, "entry", Func);
|
| +
|
| + // Collect and name the function arguments.
|
| + Function::arg_iterator FuncArgs = Func->arg_begin();
|
| + SmallVector<Value *, 4> Args;
|
| + va_list ap;
|
| + va_start(ap, CallCannotReturn);
|
| + while (true) {
|
| + // Iterate over the varargs until a terminated NULL is encountered.
|
| + const char *ArgName = va_arg(ap, const char *);
|
| + if (!ArgName)
|
| + break;
|
| + Value *Arg = FuncArgs++;
|
| + Arg->setName(ArgName);
|
| + Args.push_back(Arg);
|
| + }
|
| + va_end(ap);
|
| +
|
| + // Emit a call to self, and then call CallRewriter to rewrite it to the
|
| + // intrinsic. This is done in order to keep the call rewriting logic in a
|
| + // single place.
|
| + CallInst *SelfCall = CallInst::Create(Func, Args, "", BB);
|
| +
|
| + if (CallCannotReturn) {
|
| + new UnreachableInst(*Context, BB);
|
| + } else if (Func->getReturnType()->isVoidTy()) {
|
| + ReturnInst::Create(*Context, BB);
|
| + } else {
|
| + ReturnInst::Create(*Context, SelfCall, BB);
|
| + }
|
| +
|
| + (this->*(CallRewriter))(SelfCall);
|
| +}
|
| +
|
| +void RewritePNaClLibraryCalls::populateSetjmpWrapper(Function *SetjmpFunc) {
|
| + populateWrapperCommon(
|
| + /* Func */ SetjmpFunc,
|
| + /* FuncName */ "setjmp",
|
| + /* CallRewriter */ &RewritePNaClLibraryCalls::rewriteSetjmpCall,
|
| + /* CallCannotReturn */ false,
|
| + /* ... */ "env", NULL);
|
| +}
|
| +
|
| +void RewritePNaClLibraryCalls::populateLongjmpWrapper(Function *LongjmpFunc) {
|
| + populateWrapperCommon(
|
| + /* Func */ LongjmpFunc,
|
| + /* FuncName */ "longjmp",
|
| + /* CallRewriter */ &RewritePNaClLibraryCalls::rewriteLongjmpCall,
|
| + /* CallCannotReturn */ true,
|
| + /* ... */ "env", "val", NULL);
|
| +}
|
| +
|
| +void RewritePNaClLibraryCalls::populateMemcpyWrapper(Function *MemcpyFunc) {
|
| + populateWrapperCommon(
|
| + /* Func */ MemcpyFunc,
|
| + /* FuncName */ "memcpy",
|
| + /* CallRewriter */ &RewritePNaClLibraryCalls::rewriteMemcpyCall,
|
| + /* CallCannotReturn */ false,
|
| + /* ... */ "dest", "src", "len", NULL);
|
| +}
|
| +
|
| +void RewritePNaClLibraryCalls::populateMemmoveWrapper(Function *MemmoveFunc) {
|
| + populateWrapperCommon(
|
| + /* Func */ MemmoveFunc,
|
| + /* FuncName */ "memmove",
|
| + /* CallRewriter */ &RewritePNaClLibraryCalls::rewriteMemmoveCall,
|
| + /* CallCannotReturn */ false,
|
| + /* ... */ "dest", "src", "len", NULL);
|
| +}
|
| +
|
| +void RewritePNaClLibraryCalls::populateMemsetWrapper(Function *MemsetFunc) {
|
| + populateWrapperCommon(
|
| + /* Func */ MemsetFunc,
|
| + /* FuncName */ "memset",
|
| + /* CallRewriter */ &RewritePNaClLibraryCalls::rewriteMemsetCall,
|
| + /* CallCannotReturn */ false,
|
| + /* ... */ "dest", "val", "len", NULL);
|
| +}
|
| +
|
| +Function *RewritePNaClLibraryCalls::findSetjmpIntrinsic() {
|
| + if (!SetjmpIntrinsic) {
|
| + SetjmpIntrinsic = Intrinsic::getDeclaration(
|
| + TheModule, Intrinsic::nacl_setjmp);
|
| + }
|
| + return SetjmpIntrinsic;
|
| +}
|
| +
|
| +Function *RewritePNaClLibraryCalls::findLongjmpIntrinsic() {
|
| + if (!LongjmpIntrinsic) {
|
| + LongjmpIntrinsic = Intrinsic::getDeclaration(
|
| + TheModule, Intrinsic::nacl_longjmp);
|
| + }
|
| + return LongjmpIntrinsic;
|
| +}
|
| +
|
| +Function *RewritePNaClLibraryCalls::findMemcpyIntrinsic() {
|
| + if (!MemcpyIntrinsic) {
|
| + Type *Tys[] = { Type::getInt8PtrTy(*Context),
|
| + Type::getInt8PtrTy(*Context),
|
| + Type::getInt32Ty(*Context) };
|
| + MemcpyIntrinsic = Intrinsic::getDeclaration(
|
| + TheModule, Intrinsic::memcpy, Tys);
|
| + }
|
| + return MemcpyIntrinsic;
|
| +}
|
| +
|
| +Function *RewritePNaClLibraryCalls::findMemmoveIntrinsic() {
|
| + if (!MemmoveIntrinsic) {
|
| + Type *Tys[] = { Type::getInt8PtrTy(*Context),
|
| + Type::getInt8PtrTy(*Context),
|
| + Type::getInt32Ty(*Context) };
|
| + MemmoveIntrinsic = Intrinsic::getDeclaration(
|
| + TheModule, Intrinsic::memmove, Tys);
|
| + }
|
| + return MemmoveIntrinsic;
|
| +}
|
| +
|
| +Function *RewritePNaClLibraryCalls::findMemsetIntrinsic() {
|
| + if (!MemsetIntrinsic) {
|
| + Type *Tys[] = { Type::getInt8PtrTy(*Context), Type::getInt32Ty(*Context) };
|
| + MemsetIntrinsic = Intrinsic::getDeclaration(
|
| + TheModule, Intrinsic::memset, Tys);
|
| + }
|
| + return MemsetIntrinsic;
|
| +}
|
| +
|
| +ModulePass *llvm::createRewritePNaClLibraryCallsPass() {
|
| + return new RewritePNaClLibraryCalls();
|
| +}
|
|
|