Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(545)

Unified Diff: lib/Transforms/NaCl/RewritePNaClLibraryCalls.cpp

Issue 939073008: Rebased PNaCl localmods in LLVM to 223109 (Closed)
Patch Set: undo localmod Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/Transforms/NaCl/RewriteLLVMIntrinsics.cpp ('k') | lib/Transforms/NaCl/SimplifyAllocas.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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();
+}
« no previous file with comments | « lib/Transforms/NaCl/RewriteLLVMIntrinsics.cpp ('k') | lib/Transforms/NaCl/SimplifyAllocas.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698