OLD | NEW |
---|---|
(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/Instructions.h" | |
18 #include "llvm/IR/Intrinsics.h" | |
19 #include "llvm/IR/Module.h" | |
20 #include "llvm/Pass.h" | |
21 #include "llvm/Transforms/NaCl.h" | |
22 | |
23 using namespace llvm; | |
24 | |
25 namespace { | |
26 class RewritePNaClLibraryCalls : public ModulePass { | |
27 public: | |
28 static char ID; | |
29 RewritePNaClLibraryCalls() : | |
30 ModulePass(ID), TheModule(NULL) { | |
31 // This is a module pass because it may have to introduce | |
32 // intrinsic declarations into the module and modify a global function. | |
33 initializeRewritePNaClLibraryCallsPass(*PassRegistry::getPassRegistry()); | |
34 } | |
35 | |
36 virtual bool runOnModule(Module &M); | |
37 private: | |
38 /// Rewrites the given \p Call of setjmp to a direct intrinsic call. | |
39 void rewriteSetjmpCall(CallInst *Call); | |
40 | |
41 /// Rewrites the given \p Call of longjmp to a direct intrinsic call. | |
42 void rewriteLongjmpCall(CallInst *Call); | |
43 | |
44 /// Populates the body of longjmp as a wrapper of the intrinsic call. | |
45 /// Should only be called once. Modifies the given \p LongjmpFunc. | |
46 void populateLongjmpWrapper(Function *LongjmpFunc); | |
47 | |
48 /// The module this pass runs on. | |
49 Module *TheModule; | |
50 }; | |
51 } | |
52 | |
53 static const char *LONGJMP_NAME = "longjmp"; | |
Mark Seaborn
2013/05/13 23:39:58
I don't think LLVM uses NAMES_IN_CAPS for non-#def
eliben
2013/05/14 17:38:58
These constants are now just used in a single plac
| |
54 static const char *SETJMP_NAME = "setjmp"; | |
55 | |
56 char RewritePNaClLibraryCalls::ID = 0; | |
57 INITIALIZE_PASS(RewritePNaClLibraryCalls, "rewrite-pnacl-library-calls", | |
58 "Rewrite PNaCl library calls to stable intrinsics", | |
59 false, false) | |
60 | |
61 bool RewritePNaClLibraryCalls::runOnModule(Module &M) { | |
62 TheModule = &M; | |
63 bool Changed = false; | |
64 | |
65 // Iterate over all uses of the setjmp, if it exists in the module with | |
66 // external linkage. If it exists but the linkage is not external, this may | |
67 // come from code that defines its own function named setjmp and doesn't | |
68 // include <setjmp.h>. In such a case we leave the code as it is. | |
69 // | |
70 // The calls are replaced with intrinsics. All other uses | |
71 // of setjmp are disallowed (taking the address of setjmp is disallowed in | |
Mark Seaborn
2013/05/13 23:39:58
Re-wrap (partly fits on previous line)
eliben
2013/05/14 17:38:58
Done.
| |
72 // C and C++). | |
73 Function *SetjmpFunc = TheModule->getFunction(SETJMP_NAME); | |
74 if (SetjmpFunc && SetjmpFunc->hasExternalLinkage()) { | |
75 for (Value::use_iterator UI = SetjmpFunc->use_begin(), | |
76 UE = SetjmpFunc->use_end(); UI != UE;) { | |
77 Value *Use = *UI++; | |
78 if (CallInst *Call = dyn_cast<CallInst>(Use)) { | |
79 rewriteSetjmpCall(Call); | |
80 Changed = true; | |
81 } else { | |
82 report_fatal_error("Taking the address of setjmp is invalid"); | |
83 } | |
84 } | |
85 } | |
86 | |
87 // For longjmp things are a little more complicated, since longjmp's address | |
88 // can be taken. Therefore, longjmp can appear in a variety of Uses. The | |
89 // common case is still a direct call and we want that to be as efficient as | |
90 // possible, so we rewrite it into a direct intrinsic call. If there are other | |
91 // uses, the actual body of longjmp is populated with a wrapper that calls | |
92 // the intrinsic. | |
93 Function *LongjmpFunc = TheModule->getFunction(LONGJMP_NAME); | |
94 bool LongjmpHasNoncallUses = false; | |
95 | |
96 if (LongjmpFunc && LongjmpFunc->hasExternalLinkage()) { | |
97 for (Value::use_iterator UI = LongjmpFunc->use_begin(), | |
98 UE = LongjmpFunc->use_end(); UI != UE;) { | |
99 Value *Use = *UI++; | |
100 if (CallInst *Call = dyn_cast<CallInst>(Use)) { | |
101 rewriteLongjmpCall(Call); | |
102 Changed = true; | |
103 } else { | |
104 LongjmpHasNoncallUses = true; | |
105 } | |
106 } | |
107 } | |
108 | |
109 if (LongjmpHasNoncallUses) { | |
Mark Seaborn
2013/05/13 23:39:58
Could just do:
if (!LongjmpFunc->use_empty())
th
eliben
2013/05/14 17:38:58
Done.
| |
110 populateLongjmpWrapper(LongjmpFunc); | |
111 Changed = true; | |
112 } | |
113 | |
114 return Changed; | |
115 } | |
116 | |
117 void RewritePNaClLibraryCalls::rewriteSetjmpCall(CallInst *Call) { | |
118 FunctionType *FTy = Call->getCalledFunction()->getFunctionType(); | |
119 | |
120 // Sanity check on the setjmp call. | |
121 if (FTy->getNumParams() != 1 || | |
122 !FTy->getReturnType()->isIntegerTy() || | |
123 !FTy->getParamType(0)->isPointerTy()) { | |
124 report_fatal_error(Twine("Wrong signature of function ") + | |
125 Call->getCalledFunction()->getName()); | |
126 } | |
127 const DebugLoc &DLoc = Call->getDebugLoc(); | |
128 | |
129 // Find the intrinsic function. | |
130 Function *NaClSetjmpFunc = Intrinsic::getDeclaration(TheModule, | |
131 Intrinsic::nacl_setjmp); | |
132 // Cast the jmp_buf argument to the type NaClSetjmpCall expects. | |
133 Type *PtrTy = NaClSetjmpFunc->getFunctionType()->getParamType(0); | |
134 BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy, | |
135 "jmp_buf_i8", Call); | |
136 JmpBufCast->setDebugLoc(DLoc); | |
137 | |
138 // Emit the updated call. | |
139 SmallVector<Value *, 1> Args; | |
140 Args.push_back(JmpBufCast); | |
141 CallInst *NaClSetjmpCall = CallInst::Create(NaClSetjmpFunc, Args, "", Call); | |
142 NaClSetjmpCall->setDebugLoc(DLoc); | |
143 NaClSetjmpCall->takeName(Call); | |
144 | |
145 // Replace the original call. | |
146 Call->replaceAllUsesWith(NaClSetjmpCall); | |
147 Call->eraseFromParent(); | |
148 } | |
149 | |
150 void RewritePNaClLibraryCalls::rewriteLongjmpCall(CallInst *Call) { | |
151 FunctionType *FTy = Call->getCalledFunction()->getFunctionType(); | |
152 | |
153 // Sanity check on the longjmp call. | |
154 if (FTy->getNumParams() != 2 || | |
155 !FTy->getReturnType()->isVoidTy() || | |
156 !FTy->getParamType(0)->isPointerTy()) { | |
157 report_fatal_error(Twine("Wrong signature of function ") + | |
158 Call->getCalledFunction()->getName()); | |
159 } | |
160 const DebugLoc &DLoc = Call->getDebugLoc(); | |
161 | |
162 // Find the intrinsic function. | |
163 Function *NaClLongjmpFunc = Intrinsic::getDeclaration( | |
164 TheModule, Intrinsic::nacl_longjmp); | |
165 // Cast the jmp_buf argument to the type NaClLongjmpCall expects. | |
166 Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0); | |
167 BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy, | |
168 "jmp_buf_i8", Call); | |
169 JmpBufCast->setDebugLoc(DLoc); | |
170 | |
171 // Emit the call. | |
172 SmallVector<Value *, 2> Args; | |
173 Args.push_back(JmpBufCast); | |
174 Args.push_back(Call->getArgOperand(1)); | |
175 CallInst *NaClLongjmpCall = CallInst::Create(NaClLongjmpFunc, Args, "", Call); | |
176 NaClLongjmpCall->setDebugLoc(DLoc); | |
177 // No takeName here since longjmp is a void call that does not get assigned to | |
178 // a value. | |
179 | |
180 // Remove the original call. There's no need for RAUW because longjmp | |
181 // returns void. | |
182 Call->eraseFromParent(); | |
183 } | |
184 | |
185 void RewritePNaClLibraryCalls::populateLongjmpWrapper(Function *LongjmpFunc) { | |
186 assert(LongjmpFunc->size() == 0 && | |
187 "Expected to be called when longjmp has an empty body"); | |
188 | |
189 // Populate longjmp with code. | |
190 LLVMContext &Context = TheModule->getContext(); | |
191 BasicBlock *BB = BasicBlock::Create(Context, "entry", LongjmpFunc); | |
192 | |
193 Function::arg_iterator LongjmpArgs = LongjmpFunc->arg_begin(); | |
Mark Seaborn
2013/05/13 23:39:58
Also do a sanity check on this function's args, as
eliben
2013/05/14 17:38:58
Refactored
| |
194 Value *EnvArg = LongjmpArgs++; | |
195 EnvArg->setName("env"); | |
196 Value *ValArg = LongjmpArgs++; | |
197 ValArg->setName("val"); | |
198 | |
199 // Insert an unreachable instruction to terminate this function since longjmp | |
200 // does not return. | |
201 Instruction *End = new UnreachableInst(Context, BB); | |
Mark Seaborn
2013/05/13 23:39:58
Nit: It would be a little more obvious to add the
eliben
2013/05/14 17:38:58
Done.
| |
202 | |
203 // Find the intrinsic function. | |
204 Function *NaClLongjmpFunc = Intrinsic::getDeclaration( | |
205 TheModule, Intrinsic::nacl_longjmp); | |
206 // Cast the jmp_buf argument to the type NaClLongjmpCall expects. | |
207 Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0); | |
208 BitCastInst *JmpBufCast = new BitCastInst(EnvArg, PtrTy, "jmp_buf_i8", End); | |
209 | |
210 // Emit the call. | |
211 SmallVector<Value *, 2> Args; | |
212 Args.push_back(JmpBufCast); | |
213 Args.push_back(ValArg); | |
214 CallInst::Create(NaClLongjmpFunc, Args, "", End); | |
215 | |
216 // Finally, set the linkage to internal | |
217 LongjmpFunc->setLinkage(Function::InternalLinkage); | |
218 } | |
219 | |
220 ModulePass *llvm::createRewritePNaClLibraryCallsPass() { | |
221 return new RewritePNaClLibraryCalls(); | |
222 } | |
223 | |
Mark Seaborn
2013/05/13 23:39:58
Nit: don't put empty lines at the end of the file
eliben
2013/05/14 17:38:58
Done.
| |
OLD | NEW |