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/GlobalVariable.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/Support/raw_ostream.h" | |
23 #include "llvm/Transforms/NaCl.h" | |
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(0), | |
33 SetjmpFunc(0), LongjmpFunc(0), LongjmpWrapperFunc(0) { | |
34 // This is a module pass because it may have to introduce | |
35 // intrindic declarations into the module. | |
jvoung (off chromium)
2013/05/13 18:12:30
intrindic -> intrinsic
Another reason (if you wan
eliben
2013/05/13 18:33:36
Done.
| |
36 initializeExpandTlsPass(*PassRegistry::getPassRegistry()); | |
jvoung (off chromium)
2013/05/13 18:12:30
initializeExpandTlsPass?
eliben
2013/05/13 18:33:36
Oops :-/
Thanks, fixed.
| |
37 } | |
38 | |
39 virtual bool runOnModule(Module &M); | |
40 private: | |
41 /// Rewrites the given \p Call to setjmp. | |
42 void rewriteSetjmpCall(CallInst *Call); | |
43 | |
44 /// Rewrites the given \p Call to longjmp. | |
45 void rewriteLongjmpCall(CallInst *Call); | |
46 | |
47 /// Rewrites the given \p Store instruction that stores a pointer to | |
48 /// longjmp. | |
49 void rewriteLongjmpStore(StoreInst *Store); | |
50 | |
51 void rewriteAddrOfLongjmpInGlobal(GlobalVariable *Global); | |
52 | |
53 /// Creates the longjmp wrapper on-demand. | |
54 Function *getOrCreateLongjmpWrapper(); | |
55 | |
56 /// The module this pass runs on. | |
57 Module *TheModule; | |
58 | |
59 /// Global setjmp/longjmp functions the original code calls. NULL if they | |
60 /// are not in the module. | |
61 Function *SetjmpFunc; | |
jvoung (off chromium)
2013/05/13 18:12:30
Does SetjmpFunc really need to be a field? It loo
eliben
2013/05/13 18:33:36
Yeah, SetjmpFunc is definitely a leftover from ref
| |
62 Function *LongjmpFunc; | |
63 | |
64 /// The wrapper for longjmp is created on-demand and cached here. | |
65 Function *LongjmpWrapperFunc; | |
66 }; | |
67 } | |
68 | |
69 static const char *LONGJMP_NAME = "longjmp"; | |
70 static const char *SETJMP_NAME = "setjmp"; | |
71 static const char *WRAP_FUNC_PREFIX = "__nacl_wrap_"; | |
72 | |
73 char RewritePNaClLibraryCalls::ID = 0; | |
74 INITIALIZE_PASS(RewritePNaClLibraryCalls, "rewrite-pnacl-library-calls", | |
75 "Rewrite PNaCl library calls to stable intrinsics", | |
76 false, false) | |
77 | |
78 bool RewritePNaClLibraryCalls::runOnModule(Module &M) { | |
79 TheModule = &M; | |
80 bool Changed = false; | |
81 | |
82 // Iterate over all uses of the setjmp and longjmp functions, if they exist | |
83 // in the module with external linkage. | |
84 // For setjmp, calls are replaced by calls to intrinsics. | |
85 // For longjmp calls are also replaced; however, longjmp can have its | |
jvoung (off chromium)
2013/05/13 18:12:30
no need for two spaces between ";" and "however"?
eliben
2013/05/13 18:33:36
Done.
| |
86 // address taken, so in these places an address of a wrapper function is | |
87 // stored instead (or used as an initializer in a global variable). | |
88 // The wrapper function calls the intrinsic with an appropriate cast. | |
89 SetjmpFunc = TheModule->getFunction(SETJMP_NAME); | |
90 if (SetjmpFunc && SetjmpFunc->hasExternalLinkage()) { | |
91 for (Value::use_iterator UI = SetjmpFunc->use_begin(), | |
92 UE = SetjmpFunc->use_end(); UI != UE;) { | |
93 Value *Use = *UI++; | |
94 if (CallInst *Call = dyn_cast<CallInst>(Use)) { | |
95 rewriteSetjmpCall(Call); | |
jvoung (off chromium)
2013/05/13 18:12:30
Now that you aren't checking "Call->getCalledFunct
eliben
2013/05/13 18:33:36
Not sure what you mean. Only going over the uses o
jvoung (off chromium)
2013/05/13 19:52:07
I was wondering if you had IL like this:
%call =
| |
96 Changed = true; | |
97 } else if (isa<StoreInst>(Use)) { | |
98 report_fatal_error("Invalid store of setjmp's address"); | |
99 } | |
jvoung (off chromium)
2013/05/13 18:12:30
Do we expect to see other uses of setjmp (else bra
eliben
2013/05/13 18:33:36
Done.
| |
100 } | |
101 } | |
102 | |
103 LongjmpFunc = TheModule->getFunction(LONGJMP_NAME); | |
104 if (LongjmpFunc && LongjmpFunc->hasExternalLinkage()) { | |
105 for (Value::use_iterator UI = LongjmpFunc->use_begin(), | |
106 UE = LongjmpFunc->use_end(); UI != UE;) { | |
107 Value *Use = *UI++; | |
108 if (CallInst *Call = dyn_cast<CallInst>(Use)) { | |
109 rewriteLongjmpCall(Call); | |
110 Changed = true; | |
111 } else if (StoreInst *Store = dyn_cast<StoreInst>(Use)) { | |
112 rewriteLongjmpStore(Store); | |
113 Changed = true; | |
114 } else if (GlobalVariable *Global = dyn_cast<GlobalVariable>(Use)) { | |
115 rewriteAddrOfLongjmpInGlobal(Global); | |
116 Changed = true; | |
117 } | |
118 } | |
119 } | |
120 | |
121 return Changed; | |
122 } | |
123 | |
124 void RewritePNaClLibraryCalls::rewriteSetjmpCall(CallInst *Call) { | |
125 FunctionType *FTy = Call->getCalledFunction()->getFunctionType(); | |
126 | |
127 // Sanity check on the setjmp call. | |
128 if (FTy->getNumParams() != 1 || | |
129 !FTy->getReturnType()->isIntegerTy() || | |
130 !FTy->getParamType(0)->isPointerTy()) { | |
131 report_fatal_error(Twine("Wrong signature of function ") + | |
132 Call->getCalledFunction()->getName()); | |
133 } | |
134 const DebugLoc &DLoc = Call->getDebugLoc(); | |
135 | |
136 // Find the intrinsic function. | |
137 Function *NaClSetjmpFunc = Intrinsic::getDeclaration(TheModule, | |
138 Intrinsic::nacl_setjmp); | |
139 // Cast the jmp_buf argument to the type NaClSetjmpCall expects. | |
140 Type *PtrTy = NaClSetjmpFunc->getFunctionType()->getParamType(0); | |
141 BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy, | |
142 "jmp_buf_i8", Call); | |
143 JmpBufCast->setDebugLoc(DLoc); | |
144 | |
145 // Emit the updated call. | |
146 SmallVector<Value *, 2> Args; | |
147 Args.push_back(JmpBufCast); | |
148 CallInst *NaClSetjmpCall = CallInst::Create(NaClSetjmpFunc, Args, "", Call); | |
149 NaClSetjmpCall->setDebugLoc(DLoc); | |
150 NaClSetjmpCall->takeName(Call); | |
151 | |
152 // Replace the original call. | |
153 Call->replaceAllUsesWith(NaClSetjmpCall); | |
154 Call->eraseFromParent(); | |
155 } | |
156 | |
157 void RewritePNaClLibraryCalls::rewriteLongjmpCall(CallInst *Call) { | |
158 FunctionType *FTy = Call->getCalledFunction()->getFunctionType(); | |
159 | |
160 // Sanity check on the longjmp call. | |
161 if (FTy->getNumParams() != 2 || | |
162 !FTy->getReturnType()->isVoidTy() || | |
163 !FTy->getParamType(0)->isPointerTy()) { | |
164 report_fatal_error(Twine("Wrong signature of function ") + | |
165 Call->getCalledFunction()->getName()); | |
166 } | |
167 const DebugLoc &DLoc = Call->getDebugLoc(); | |
168 | |
169 // Find the intrinsic function. | |
170 Function *NaClLongjmpFunc = Intrinsic::getDeclaration( | |
171 TheModule, Intrinsic::nacl_longjmp); | |
172 // Cast the jmp_buf argument to the type NaClLongjmpCall expects. | |
173 Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0); | |
174 BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy, | |
175 "jmp_buf_i8", Call); | |
176 JmpBufCast->setDebugLoc(DLoc); | |
177 | |
178 // Emit the call. | |
179 SmallVector<Value *, 2> Args; | |
180 Args.push_back(JmpBufCast); | |
181 Args.push_back(Call->getArgOperand(1)); | |
182 CallInst *NaClLongjmpCall = CallInst::Create(NaClLongjmpFunc, Args, "", Call); | |
183 NaClLongjmpCall->setDebugLoc(DLoc); | |
184 // No takeName here since longjmp is a void call that does not get assigned to | |
185 // a value. | |
186 | |
187 // Remove the original call. There's no need for RAUW because longjmp | |
188 // returns void. | |
189 Call->eraseFromParent(); | |
190 } | |
191 | |
192 void RewritePNaClLibraryCalls::rewriteLongjmpStore(StoreInst *Store) { | |
193 // Sanity check: this method was called for a store that uses a function | |
194 // pointer to setjmp. | |
195 Function *CalledFunc = dyn_cast_or_null<Function>(Store->getValueOperand()); | |
196 if (CalledFunc != LongjmpFunc) { | |
197 report_fatal_error(Twine("Badly formed store of ") + | |
198 LongjmpFunc->getName()); | |
199 } | |
200 | |
201 Function *LongjmpWrapperFunc = getOrCreateLongjmpWrapper(); | |
202 | |
203 // Replace Store by a new store that stores a pointer to the wrapper. | |
204 StoreInst *WrapperStore = new StoreInst(LongjmpWrapperFunc, | |
205 Store->getPointerOperand(), | |
206 Store); | |
207 WrapperStore->setDebugLoc(Store->getDebugLoc()); | |
208 WrapperStore->takeName(Store); | |
209 Store->replaceAllUsesWith(WrapperStore); | |
210 Store->eraseFromParent(); | |
211 } | |
212 | |
213 void RewritePNaClLibraryCalls::rewriteAddrOfLongjmpInGlobal( | |
214 GlobalVariable *Global) { | |
215 if (!Global->hasUniqueInitializer()) { | |
216 report_fatal_error(Twine("Badly formed assignment to global ") + | |
217 Global->getName()); | |
218 } | |
219 | |
220 Function *LongjmpWrapperFunc = getOrCreateLongjmpWrapper(); | |
221 | |
222 GlobalVariable *NewGlobal = new GlobalVariable( | |
223 /* M */ *TheModule, | |
224 /* Ty */ LongjmpWrapperFunc->getType(), | |
225 /* isConstant */ Global->isConstant(), | |
226 /* Linkage */ GlobalValue::PrivateLinkage, | |
227 /* Initializer */ LongjmpWrapperFunc, | |
228 /* Name */ "", | |
229 /* InsertBefore */ Global, | |
230 /* ThreadLocalMode */ Global->getThreadLocalMode()); | |
231 NewGlobal->setAlignment(Global->getAlignment()); | |
232 // Using takeName instead of assigning Name in the constructor of | |
233 // GlobalVariable because otherwise a numeric suffix is added to the name, | |
234 // while we want it to stay exactly the same. | |
235 NewGlobal->takeName(Global); | |
236 Global->eraseFromParent(); | |
237 } | |
238 | |
239 Function *RewritePNaClLibraryCalls::getOrCreateLongjmpWrapper() { | |
240 if (LongjmpWrapperFunc) | |
241 return LongjmpWrapperFunc; | |
242 | |
243 // A wrapper function is created that has the same type as longjmp; it | |
244 // redirects the call to the intrinsic after casting pointer argument. | |
245 FunctionType *WrapFuncTy = LongjmpFunc->getFunctionType(); | |
246 SmallString<32> Name(WRAP_FUNC_PREFIX); Name.append(LONGJMP_NAME); | |
247 Function *LongjmpWrapperFunc = dyn_cast<Function>( | |
248 TheModule->getOrInsertFunction(Name, WrapFuncTy)); | |
249 LongjmpWrapperFunc->setLinkage(Function::PrivateLinkage); | |
250 | |
251 // This function has just been created. Fill its contents. | |
252 LLVMContext &Context = TheModule->getContext(); | |
253 BasicBlock *BB = BasicBlock::Create(Context, "entry", LongjmpWrapperFunc); | |
254 | |
255 Function::arg_iterator LongjmpArgs = LongjmpWrapperFunc->arg_begin(); | |
256 Value *EnvArg = LongjmpArgs++; | |
257 EnvArg->setName("env"); | |
258 Value *ValArg = LongjmpArgs++; | |
259 ValArg->setName("val"); | |
260 | |
261 // Insert a return instruction | |
262 Instruction *Ret = ReturnInst::Create(Context, 0, BB); | |
263 | |
264 // Find the intrinsic function. | |
265 Function *NaClLongjmpFunc = Intrinsic::getDeclaration( | |
266 TheModule, Intrinsic::nacl_longjmp); | |
267 // Cast the jmp_buf argument to the type NaClLongjmpCall expects. | |
268 Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0); | |
269 BitCastInst *JmpBufCast = new BitCastInst(EnvArg, PtrTy, "jmp_buf_i8", Ret); | |
270 | |
271 // Emit the call. | |
272 SmallVector<Value *, 2> Args; | |
273 Args.push_back(JmpBufCast); | |
274 Args.push_back(ValArg); | |
275 CallInst::Create(NaClLongjmpFunc, Args, "", Ret); | |
276 | |
277 return LongjmpWrapperFunc; | |
278 } | |
279 | |
280 ModulePass *llvm::createRewritePNaClLibraryCallsPass() { | |
281 return new RewritePNaClLibraryCalls(); | |
282 } | |
283 | |
OLD | NEW |