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

Side by Side 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 unified diff | Download patch
« no previous file with comments | « lib/Transforms/NaCl/RewriteLLVMIntrinsics.cpp ('k') | lib/Transforms/NaCl/SimplifyAllocas.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 //===- RewritePNaClLibraryCalls.cpp - PNaCl library calls to intrinsics ---===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This pass replaces calls to known library functions with calls to intrinsics
11 // that are part of the PNaCl stable bitcode ABI.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "llvm/ADT/SmallString.h"
16 #include "llvm/ADT/Twine.h"
17 #include "llvm/IR/Constants.h"
18 #include "llvm/IR/Instructions.h"
19 #include "llvm/IR/Intrinsics.h"
20 #include "llvm/IR/Module.h"
21 #include "llvm/Pass.h"
22 #include "llvm/Transforms/NaCl.h"
23 #include <cstdarg>
24
25 using namespace llvm;
26
27 namespace {
28 class RewritePNaClLibraryCalls : public ModulePass {
29 public:
30 static char ID;
31 RewritePNaClLibraryCalls() :
32 ModulePass(ID), TheModule(NULL), Context(NULL), SetjmpIntrinsic(NULL),
33 LongjmpIntrinsic(NULL), MemcpyIntrinsic(NULL),
34 MemmoveIntrinsic(NULL), MemsetIntrinsic(NULL) {
35 // This is a module pass because it may have to introduce
36 // intrinsic declarations into the module and modify globals.
37 initializeRewritePNaClLibraryCallsPass(*PassRegistry::getPassRegistry());
38 }
39
40 virtual bool runOnModule(Module &M);
41 private:
42 typedef void (RewritePNaClLibraryCalls::*RewriteCallFunc)(CallInst *);
43 typedef void (RewritePNaClLibraryCalls::*PopulateWrapperFunc)(Function *);
44
45 /// Handles a certain pattern of library function -> intrinsic rewrites.
46 /// Currently all library functions this pass knows how to rewrite fall into
47 /// this pattern.
48 /// RewriteLibraryCall performs the rewrite for a single library function
49 /// and is customized by its arguments.
50 ///
51 /// \p LibraryFunctionName Name of the library function to look for.
52 /// \p CorrectFunctionType is the correct type of this library function.
53 /// \p CallRewriter Method that rewrites the library function call into an
54 /// intrinsic call.
55 /// \p OnlyCallsAllowed Only calls to this library function are allowed.
56 /// \p WrapperPopulator called to populate the body of the library function
57 /// with a wrapped intrinsic call.
58 bool RewriteLibraryCall(
59 const char *LibraryFunctionName,
60 FunctionType *CorrectFunctionType,
61 RewriteCallFunc CallRewriter,
62 bool OnlyCallsAllowed,
63 PopulateWrapperFunc WrapperPopulator);
64
65 /// Two function types are compatible if they have compatible return types
66 /// and the same number of compatible parameters. Return types and
67 /// parameters are compatible if they are exactly the same type or both are
68 /// pointer types.
69 static bool compatibleFunctionTypes(FunctionType *FTy1, FunctionType *FTy2);
70 static bool compatibleParamOrRetTypes(Type *Ty1, Type *Ty2);
71
72 void rewriteSetjmpCall(CallInst *Call);
73 void rewriteLongjmpCall(CallInst *Call);
74 void rewriteMemcpyCall(CallInst *Call);
75 void rewriteMemmoveCall(CallInst *Call);
76 void rewriteMemsetCall(CallInst *Call);
77
78 void populateSetjmpWrapper(Function *SetjmpFunc);
79 void populateLongjmpWrapper(Function *LongjmpFunc);
80 void populateMemcpyWrapper(Function *MemcpyFunc);
81 void populateMemmoveWrapper(Function *MemmoveFunc);
82 void populateMemsetWrapper(Function *MemsetFunc);
83
84 /// Generic implementation of populating a wrapper function.
85 /// Initially, the function exists in the module as a declaration with
86 /// unnamed arguments. This method is called with a NULL-terminated list
87 /// of argument names that get assigned in the generated IR for
88 /// readability.
89 void populateWrapperCommon(
90 Function *Func,
91 StringRef FuncName,
92 RewriteCallFunc CallRewriter,
93 bool CallCannotReturn,
94 ...);
95
96 /// Find and cache known intrinsics.
97 Function *findSetjmpIntrinsic();
98 Function *findLongjmpIntrinsic();
99 Function *findMemcpyIntrinsic();
100 Function *findMemmoveIntrinsic();
101 Function *findMemsetIntrinsic();
102
103 /// Cached data that remains the same throughout a module run.
104 Module *TheModule;
105 LLVMContext *Context;
106
107 /// These are cached but computed lazily.
108 Function *SetjmpIntrinsic;
109 Function *LongjmpIntrinsic;
110 Function *MemcpyIntrinsic;
111 Function *MemmoveIntrinsic;
112 Function *MemsetIntrinsic;
113 };
114 }
115
116 char RewritePNaClLibraryCalls::ID = 0;
117 INITIALIZE_PASS(RewritePNaClLibraryCalls, "rewrite-pnacl-library-calls",
118 "Rewrite PNaCl library calls to stable intrinsics",
119 false, false)
120
121 bool RewritePNaClLibraryCalls::RewriteLibraryCall(
122 const char *LibraryFunctionName,
123 FunctionType *CorrectFunctionType,
124 RewriteCallFunc CallRewriter,
125 bool OnlyCallsAllowed,
126 PopulateWrapperFunc WrapperPopulator) {
127 bool Changed = false;
128
129 Function *LibFunc = TheModule->getFunction(LibraryFunctionName);
130
131 // Iterate over all uses of this function, if it exists in the module with
132 // external linkage. If it exists but the linkage is not external, this may
133 // come from code that defines its own private function with the same name
134 // and doesn't actually include the standard libc header declaring it.
135 // In such a case we leave the code as it is.
136 //
137 // Another case we need to handle here is this function having the wrong
138 // prototype (incompatible with the C library function prototype, and hence
139 // incompatible with the intrinsic). In general, this is undefined behavior,
140 // but we can't fail compilation because some workflows rely on it
141 // compiling correctly (for example, autoconf). The solution is:
142 // When the declared type of the function in the module is not correct, we
143 // re-create the function with the correct prototype and replace all calls
144 // to this new function (casted to the old function type). Effectively this
145 // delays the undefined behavior until run-time.
146 if (LibFunc && LibFunc->hasExternalLinkage()) {
147 if (!compatibleFunctionTypes(LibFunc->getFunctionType(),
148 CorrectFunctionType)) {
149 // Use the RecreateFunction utility to create a new function with the
150 // correct prototype. RecreateFunction also RAUWs the function with
151 // proper bitcasts.
152 //
153 // One interesting case that may arise is when the original module had
154 // calls to both a correct and an incorrect version of the library
155 // function. Depending on the linking order, either version could be
156 // selected as the global declaration in the module, so even valid calls
157 // could end up being bitcast-ed from the incorrect to the correct
158 // function type. The RecreateFunction call below will eliminate such
159 // bitcasts (because the new type matches the call type), but dead
160 // constant expressions may be left behind.
161 // These are cleaned up with removeDeadConstantUsers.
162 Function *NewFunc = RecreateFunction(LibFunc, CorrectFunctionType);
163 LibFunc->eraseFromParent();
164 NewFunc->setLinkage(Function::InternalLinkage);
165 Changed = true;
166 NewFunc->removeDeadConstantUsers();
167 LibFunc = NewFunc;
168 }
169
170 // Handle all uses that are calls. These are simply replaced with
171 // equivalent intrinsic calls.
172 {
173 SmallVector<CallInst *, 32> Calls;
174 for (User *U : LibFunc->users())
175 // users() will also provide call instructions in which the used value
176 // is an argument, and not the value being called. Make sure we rewrite
177 // only actual calls to LibFunc here.
178 if (CallInst *Call = dyn_cast<CallInst>(U))
179 if (Call->getCalledValue() == LibFunc)
180 Calls.push_back(Call);
181
182 for (auto Call : Calls)
183 (this->*(CallRewriter))(Call);
184
185 Changed |= !Calls.empty();
186 }
187
188 if (LibFunc->use_empty()) {
189 LibFunc->eraseFromParent();
190 } else if (OnlyCallsAllowed) {
191 // If additional uses remain, these aren't calls.
192 report_fatal_error(Twine("Taking the address of ") +
193 LibraryFunctionName + " is invalid");
194 } else {
195 // If non-call uses remain and allowed for this function, populate it
196 // with a wrapper.
197 (this->*(WrapperPopulator))(LibFunc);
198 LibFunc->setLinkage(Function::InternalLinkage);
199 Changed = true;
200 }
201 }
202
203 return Changed;
204 }
205
206 bool RewritePNaClLibraryCalls::runOnModule(Module &M) {
207 TheModule = &M;
208 Context = &TheModule->getContext();
209 bool Changed = false;
210
211 Type *Int8PtrTy = Type::getInt8PtrTy(*Context);
212 Type *Int64PtrTy = Type::getInt64PtrTy(*Context);
213 Type *Int32Ty = Type::getInt32Ty(*Context);
214 Type *VoidTy = Type::getVoidTy(*Context);
215
216 Type *SetjmpParams[] = { Int64PtrTy };
217 FunctionType *SetjmpFunctionType = FunctionType::get(Int32Ty, SetjmpParams,
218 false);
219 Changed |= RewriteLibraryCall(
220 "setjmp",
221 SetjmpFunctionType,
222 &RewritePNaClLibraryCalls::rewriteSetjmpCall,
223 true,
224 &RewritePNaClLibraryCalls::populateSetjmpWrapper);
225
226 Type *LongjmpParams[] = { Int64PtrTy, Int32Ty };
227 FunctionType *LongjmpFunctionType = FunctionType::get(VoidTy, LongjmpParams,
228 false);
229 Changed |= RewriteLibraryCall(
230 "longjmp",
231 LongjmpFunctionType,
232 &RewritePNaClLibraryCalls::rewriteLongjmpCall,
233 false,
234 &RewritePNaClLibraryCalls::populateLongjmpWrapper);
235
236 Type *MemsetParams[] = { Int8PtrTy, Int32Ty, Int32Ty };
237 FunctionType *MemsetFunctionType = FunctionType::get(Int8PtrTy, MemsetParams,
238 false);
239 Changed |= RewriteLibraryCall(
240 "memset",
241 MemsetFunctionType,
242 &RewritePNaClLibraryCalls::rewriteMemsetCall,
243 false,
244 &RewritePNaClLibraryCalls::populateMemsetWrapper);
245
246 Type *MemcpyParams[] = { Int8PtrTy, Int8PtrTy, Int32Ty };
247 FunctionType *MemcpyFunctionType = FunctionType::get(Int8PtrTy, MemcpyParams,
248 false);
249 Changed |= RewriteLibraryCall(
250 "memcpy",
251 MemcpyFunctionType,
252 &RewritePNaClLibraryCalls::rewriteMemcpyCall,
253 false,
254 &RewritePNaClLibraryCalls::populateMemcpyWrapper);
255
256 Type *MemmoveParams[] = { Int8PtrTy, Int8PtrTy, Int32Ty };
257 FunctionType *MemmoveFunctionType = FunctionType::get(Int8PtrTy,
258 MemmoveParams,
259 false);
260 Changed |= RewriteLibraryCall(
261 "memmove",
262 MemmoveFunctionType,
263 &RewritePNaClLibraryCalls::rewriteMemmoveCall,
264 false,
265 &RewritePNaClLibraryCalls::populateMemmoveWrapper);
266
267 return Changed;
268 }
269
270 bool RewritePNaClLibraryCalls::compatibleFunctionTypes(FunctionType *FTy1,
271 FunctionType *FTy2) {
272 if (FTy1->getNumParams() != FTy2->getNumParams()) {
273 return false;
274 }
275
276 if (!compatibleParamOrRetTypes(FTy1->getReturnType(),
277 FTy2->getReturnType())) {
278 return false;
279 }
280
281 for (unsigned I = 0, End = FTy1->getNumParams(); I != End; ++I) {
282 if (!compatibleParamOrRetTypes(FTy1->getParamType(I),
283 FTy2->getParamType(I))) {
284 return false;
285 }
286 }
287
288 return true;
289 }
290
291 bool RewritePNaClLibraryCalls::compatibleParamOrRetTypes(Type *Ty1,
292 Type *Ty2) {
293 return (Ty1 == Ty2 || (Ty1->isPointerTy() && Ty2->isPointerTy()));
294 }
295
296 void RewritePNaClLibraryCalls::rewriteSetjmpCall(CallInst *Call) {
297 // Find the intrinsic function.
298 Function *NaClSetjmpFunc = findSetjmpIntrinsic();
299 // Cast the jmp_buf argument to the type NaClSetjmpCall expects.
300 Type *PtrTy = NaClSetjmpFunc->getFunctionType()->getParamType(0);
301 BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy,
302 "jmp_buf_i8", Call);
303 const DebugLoc &DLoc = Call->getDebugLoc();
304 JmpBufCast->setDebugLoc(DLoc);
305
306 // Emit the updated call.
307 Value *Args[] = { JmpBufCast };
308 CallInst *NaClSetjmpCall = CallInst::Create(NaClSetjmpFunc, Args, "", Call);
309 NaClSetjmpCall->setDebugLoc(DLoc);
310 NaClSetjmpCall->takeName(Call);
311
312 // Replace the original call.
313 Call->replaceAllUsesWith(NaClSetjmpCall);
314 Call->eraseFromParent();
315 }
316
317 void RewritePNaClLibraryCalls::rewriteLongjmpCall(CallInst *Call) {
318 // Find the intrinsic function.
319 Function *NaClLongjmpFunc = findLongjmpIntrinsic();
320 // Cast the jmp_buf argument to the type NaClLongjmpCall expects.
321 Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0);
322 BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy,
323 "jmp_buf_i8", Call);
324 const DebugLoc &DLoc = Call->getDebugLoc();
325 JmpBufCast->setDebugLoc(DLoc);
326
327 // Emit the call.
328 Value *Args[] = { JmpBufCast, Call->getArgOperand(1) };
329 CallInst *NaClLongjmpCall = CallInst::Create(NaClLongjmpFunc, Args, "", Call);
330 NaClLongjmpCall->setDebugLoc(DLoc);
331 // No takeName here since longjmp is a void call that does not get assigned to
332 // a value.
333
334 // Remove the original call. There's no need for RAUW because longjmp
335 // returns void.
336 Call->eraseFromParent();
337 }
338
339 void RewritePNaClLibraryCalls::rewriteMemcpyCall(CallInst *Call) {
340 Function *MemcpyIntrinsic = findMemcpyIntrinsic();
341 // dest, src, len, align, isvolatile
342 Value *Args[] = { Call->getArgOperand(0),
343 Call->getArgOperand(1),
344 Call->getArgOperand(2),
345 ConstantInt::get(Type::getInt32Ty(*Context), 1),
346 ConstantInt::get(Type::getInt1Ty(*Context), 0) };
347 CallInst *MemcpyIntrinsicCall = CallInst::Create(MemcpyIntrinsic,
348 Args, "", Call);
349 MemcpyIntrinsicCall->setDebugLoc(Call->getDebugLoc());
350
351 // libc memcpy returns the source pointer, but the LLVM intrinsic doesn't; if
352 // the return value has actual uses, just replace them with the dest
353 // argument itself.
354 Call->replaceAllUsesWith(Call->getArgOperand(0));
355 Call->eraseFromParent();
356 }
357
358 void RewritePNaClLibraryCalls::rewriteMemmoveCall(CallInst *Call) {
359 Function *MemmoveIntrinsic = findMemmoveIntrinsic();
360 // dest, src, len, align, isvolatile
361 Value *Args[] = { Call->getArgOperand(0),
362 Call->getArgOperand(1),
363 Call->getArgOperand(2),
364 ConstantInt::get(Type::getInt32Ty(*Context), 1),
365 ConstantInt::get(Type::getInt1Ty(*Context), 0) };
366 CallInst *MemmoveIntrinsicCall = CallInst::Create(MemmoveIntrinsic,
367 Args, "", Call);
368 MemmoveIntrinsicCall->setDebugLoc(Call->getDebugLoc());
369
370 // libc memmove returns the source pointer, but the LLVM intrinsic doesn't; if
371 // the return value has actual uses, just replace them with the dest
372 // argument itself.
373 Call->replaceAllUsesWith(Call->getArgOperand(0));
374 Call->eraseFromParent();
375 }
376
377 void RewritePNaClLibraryCalls::rewriteMemsetCall(CallInst *Call) {
378 Function *MemsetIntrinsic = findMemsetIntrinsic();
379 // libc memset has 'int c' for the filler byte, but the LLVM intrinsic uses
380 // a i8; truncation is required.
381 TruncInst *ByteTrunc = new TruncInst(Call->getArgOperand(1),
382 Type::getInt8Ty(*Context),
383 "trunc_byte", Call);
384
385 const DebugLoc &DLoc = Call->getDebugLoc();
386 ByteTrunc->setDebugLoc(DLoc);
387
388 // dest, val, len, align, isvolatile
389 Value *Args[] = { Call->getArgOperand(0),
390 ByteTrunc,
391 Call->getArgOperand(2),
392 ConstantInt::get(Type::getInt32Ty(*Context), 1),
393 ConstantInt::get(Type::getInt1Ty(*Context), 0) };
394 CallInst *MemsetIntrinsicCall = CallInst::Create(MemsetIntrinsic,
395 Args, "", Call);
396 MemsetIntrinsicCall->setDebugLoc(DLoc);
397
398 // libc memset returns the source pointer, but the LLVM intrinsic doesn't; if
399 // the return value has actual uses, just replace them with the dest
400 // argument itself.
401 Call->replaceAllUsesWith(Call->getArgOperand(0));
402 Call->eraseFromParent();
403 }
404
405 void RewritePNaClLibraryCalls::populateWrapperCommon(
406 Function *Func,
407 StringRef FuncName,
408 RewriteCallFunc CallRewriter,
409 bool CallCannotReturn,
410 ...) {
411 if (!Func->isDeclaration()) {
412 report_fatal_error(Twine("Expected ") + FuncName +
413 " to be declared, not defined");
414 }
415
416 // Populate the function body with code.
417 BasicBlock *BB = BasicBlock::Create(*Context, "entry", Func);
418
419 // Collect and name the function arguments.
420 Function::arg_iterator FuncArgs = Func->arg_begin();
421 SmallVector<Value *, 4> Args;
422 va_list ap;
423 va_start(ap, CallCannotReturn);
424 while (true) {
425 // Iterate over the varargs until a terminated NULL is encountered.
426 const char *ArgName = va_arg(ap, const char *);
427 if (!ArgName)
428 break;
429 Value *Arg = FuncArgs++;
430 Arg->setName(ArgName);
431 Args.push_back(Arg);
432 }
433 va_end(ap);
434
435 // Emit a call to self, and then call CallRewriter to rewrite it to the
436 // intrinsic. This is done in order to keep the call rewriting logic in a
437 // single place.
438 CallInst *SelfCall = CallInst::Create(Func, Args, "", BB);
439
440 if (CallCannotReturn) {
441 new UnreachableInst(*Context, BB);
442 } else if (Func->getReturnType()->isVoidTy()) {
443 ReturnInst::Create(*Context, BB);
444 } else {
445 ReturnInst::Create(*Context, SelfCall, BB);
446 }
447
448 (this->*(CallRewriter))(SelfCall);
449 }
450
451 void RewritePNaClLibraryCalls::populateSetjmpWrapper(Function *SetjmpFunc) {
452 populateWrapperCommon(
453 /* Func */ SetjmpFunc,
454 /* FuncName */ "setjmp",
455 /* CallRewriter */ &RewritePNaClLibraryCalls::rewriteSetjmpCall,
456 /* CallCannotReturn */ false,
457 /* ... */ "env", NULL);
458 }
459
460 void RewritePNaClLibraryCalls::populateLongjmpWrapper(Function *LongjmpFunc) {
461 populateWrapperCommon(
462 /* Func */ LongjmpFunc,
463 /* FuncName */ "longjmp",
464 /* CallRewriter */ &RewritePNaClLibraryCalls::rewriteLongjmpCall,
465 /* CallCannotReturn */ true,
466 /* ... */ "env", "val", NULL);
467 }
468
469 void RewritePNaClLibraryCalls::populateMemcpyWrapper(Function *MemcpyFunc) {
470 populateWrapperCommon(
471 /* Func */ MemcpyFunc,
472 /* FuncName */ "memcpy",
473 /* CallRewriter */ &RewritePNaClLibraryCalls::rewriteMemcpyCall,
474 /* CallCannotReturn */ false,
475 /* ... */ "dest", "src", "len", NULL);
476 }
477
478 void RewritePNaClLibraryCalls::populateMemmoveWrapper(Function *MemmoveFunc) {
479 populateWrapperCommon(
480 /* Func */ MemmoveFunc,
481 /* FuncName */ "memmove",
482 /* CallRewriter */ &RewritePNaClLibraryCalls::rewriteMemmoveCall,
483 /* CallCannotReturn */ false,
484 /* ... */ "dest", "src", "len", NULL);
485 }
486
487 void RewritePNaClLibraryCalls::populateMemsetWrapper(Function *MemsetFunc) {
488 populateWrapperCommon(
489 /* Func */ MemsetFunc,
490 /* FuncName */ "memset",
491 /* CallRewriter */ &RewritePNaClLibraryCalls::rewriteMemsetCall,
492 /* CallCannotReturn */ false,
493 /* ... */ "dest", "val", "len", NULL);
494 }
495
496 Function *RewritePNaClLibraryCalls::findSetjmpIntrinsic() {
497 if (!SetjmpIntrinsic) {
498 SetjmpIntrinsic = Intrinsic::getDeclaration(
499 TheModule, Intrinsic::nacl_setjmp);
500 }
501 return SetjmpIntrinsic;
502 }
503
504 Function *RewritePNaClLibraryCalls::findLongjmpIntrinsic() {
505 if (!LongjmpIntrinsic) {
506 LongjmpIntrinsic = Intrinsic::getDeclaration(
507 TheModule, Intrinsic::nacl_longjmp);
508 }
509 return LongjmpIntrinsic;
510 }
511
512 Function *RewritePNaClLibraryCalls::findMemcpyIntrinsic() {
513 if (!MemcpyIntrinsic) {
514 Type *Tys[] = { Type::getInt8PtrTy(*Context),
515 Type::getInt8PtrTy(*Context),
516 Type::getInt32Ty(*Context) };
517 MemcpyIntrinsic = Intrinsic::getDeclaration(
518 TheModule, Intrinsic::memcpy, Tys);
519 }
520 return MemcpyIntrinsic;
521 }
522
523 Function *RewritePNaClLibraryCalls::findMemmoveIntrinsic() {
524 if (!MemmoveIntrinsic) {
525 Type *Tys[] = { Type::getInt8PtrTy(*Context),
526 Type::getInt8PtrTy(*Context),
527 Type::getInt32Ty(*Context) };
528 MemmoveIntrinsic = Intrinsic::getDeclaration(
529 TheModule, Intrinsic::memmove, Tys);
530 }
531 return MemmoveIntrinsic;
532 }
533
534 Function *RewritePNaClLibraryCalls::findMemsetIntrinsic() {
535 if (!MemsetIntrinsic) {
536 Type *Tys[] = { Type::getInt8PtrTy(*Context), Type::getInt32Ty(*Context) };
537 MemsetIntrinsic = Intrinsic::getDeclaration(
538 TheModule, Intrinsic::memset, Tys);
539 }
540 return MemsetIntrinsic;
541 }
542
543 ModulePass *llvm::createRewritePNaClLibraryCallsPass() {
544 return new RewritePNaClLibraryCalls();
545 }
OLDNEW
« 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