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