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), | |
Mark Seaborn
2013/05/13 20:09:00
Indent by 2 more spaces so that this is more inden
eliben
2013/05/13 22:07:18
Done.
| |
33 LongjmpFunc(0), LongjmpWrapperFunc(0) { | |
Mark Seaborn
2013/05/13 20:09:00
0 -> NULL?
eliben
2013/05/13 22:07:18
Done.
| |
34 // This is a module pass because it may have to introduce | |
35 // intrinsic declarations into the module, and rewrite global | |
36 // initializers. | |
37 initializeRewritePNaClLibraryCallsPass(*PassRegistry::getPassRegistry()); | |
38 } | |
39 | |
40 virtual bool runOnModule(Module &M); | |
41 private: | |
42 /// Rewrites the given \p Call to setjmp. | |
43 void rewriteSetjmpCall(CallInst *Call); | |
44 | |
45 /// Rewrites the given \p Call to longjmp. | |
46 void rewriteLongjmpCall(CallInst *Call); | |
47 | |
48 /// Rewrites the given \p Store instruction that stores a pointer to | |
Mark Seaborn
2013/05/13 20:09:00
Why are you checking specifically for Store instru
| |
49 /// longjmp. | |
50 void rewriteLongjmpStore(StoreInst *Store); | |
51 | |
52 void rewriteAddrOfLongjmpInGlobal(GlobalVariable *Global); | |
Mark Seaborn
2013/05/13 20:09:00
This also doesn't make sense. You should handle a
| |
53 | |
54 /// Creates the longjmp wrapper on-demand. | |
55 Function *getOrCreateLongjmpWrapper(); | |
56 | |
57 /// The module this pass runs on. | |
58 Module *TheModule; | |
59 | |
60 /// Global longjmp function the original code calls. NULL if it's not in | |
61 /// the module. | |
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 | |
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 Function *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); | |
96 Changed = true; | |
97 } else if (isa<StoreInst>(Use) || isa<GlobalVariable>(Use)) { | |
98 report_fatal_error("Taking the address of setjmp is invalid"); | |
99 } else { | |
100 report_fatal_error("Invalid use of setjmp"); | |
101 } | |
102 } | |
103 } | |
104 | |
105 LongjmpFunc = TheModule->getFunction(LONGJMP_NAME); | |
106 if (LongjmpFunc && LongjmpFunc->hasExternalLinkage()) { | |
107 for (Value::use_iterator UI = LongjmpFunc->use_begin(), | |
108 UE = LongjmpFunc->use_end(); UI != UE;) { | |
109 Value *Use = *UI++; | |
110 if (CallInst *Call = dyn_cast<CallInst>(Use)) { | |
111 rewriteLongjmpCall(Call); | |
112 Changed = true; | |
113 } else if (StoreInst *Store = dyn_cast<StoreInst>(Use)) { | |
114 rewriteLongjmpStore(Store); | |
115 Changed = true; | |
116 } else if (GlobalVariable *Global = dyn_cast<GlobalVariable>(Use)) { | |
117 rewriteAddrOfLongjmpInGlobal(Global); | |
118 Changed = true; | |
119 } else { | |
120 report_fatal_error("Invalid use of longjmp"); | |
121 } | |
122 } | |
123 } | |
124 | |
125 return Changed; | |
126 } | |
127 | |
128 void RewritePNaClLibraryCalls::rewriteSetjmpCall(CallInst *Call) { | |
129 FunctionType *FTy = Call->getCalledFunction()->getFunctionType(); | |
130 | |
131 // Sanity check on the setjmp call. | |
132 if (FTy->getNumParams() != 1 || | |
133 !FTy->getReturnType()->isIntegerTy() || | |
134 !FTy->getParamType(0)->isPointerTy()) { | |
135 report_fatal_error(Twine("Wrong signature of function ") + | |
136 Call->getCalledFunction()->getName()); | |
137 } | |
138 const DebugLoc &DLoc = Call->getDebugLoc(); | |
139 | |
140 // Find the intrinsic function. | |
141 Function *NaClSetjmpFunc = Intrinsic::getDeclaration(TheModule, | |
142 Intrinsic::nacl_setjmp); | |
143 // Cast the jmp_buf argument to the type NaClSetjmpCall expects. | |
144 Type *PtrTy = NaClSetjmpFunc->getFunctionType()->getParamType(0); | |
145 BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy, | |
146 "jmp_buf_i8", Call); | |
147 JmpBufCast->setDebugLoc(DLoc); | |
148 | |
149 // Emit the updated call. | |
150 SmallVector<Value *, 2> Args; | |
Mark Seaborn
2013/05/13 20:20:42
Nit: 1 will do here instead of 2
eliben
2013/05/13 22:07:18
Done.
| |
151 Args.push_back(JmpBufCast); | |
152 CallInst *NaClSetjmpCall = CallInst::Create(NaClSetjmpFunc, Args, "", Call); | |
153 NaClSetjmpCall->setDebugLoc(DLoc); | |
154 NaClSetjmpCall->takeName(Call); | |
155 | |
156 // Replace the original call. | |
157 Call->replaceAllUsesWith(NaClSetjmpCall); | |
158 Call->eraseFromParent(); | |
159 } | |
160 | |
161 void RewritePNaClLibraryCalls::rewriteLongjmpCall(CallInst *Call) { | |
162 FunctionType *FTy = Call->getCalledFunction()->getFunctionType(); | |
163 | |
164 // Sanity check on the longjmp call. | |
165 if (FTy->getNumParams() != 2 || | |
166 !FTy->getReturnType()->isVoidTy() || | |
167 !FTy->getParamType(0)->isPointerTy()) { | |
168 report_fatal_error(Twine("Wrong signature of function ") + | |
169 Call->getCalledFunction()->getName()); | |
170 } | |
171 const DebugLoc &DLoc = Call->getDebugLoc(); | |
172 | |
173 // Find the intrinsic function. | |
174 Function *NaClLongjmpFunc = Intrinsic::getDeclaration( | |
175 TheModule, Intrinsic::nacl_longjmp); | |
176 // Cast the jmp_buf argument to the type NaClLongjmpCall expects. | |
177 Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0); | |
178 BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy, | |
179 "jmp_buf_i8", Call); | |
180 JmpBufCast->setDebugLoc(DLoc); | |
181 | |
182 // Emit the call. | |
183 SmallVector<Value *, 2> Args; | |
184 Args.push_back(JmpBufCast); | |
185 Args.push_back(Call->getArgOperand(1)); | |
186 CallInst *NaClLongjmpCall = CallInst::Create(NaClLongjmpFunc, Args, "", Call); | |
187 NaClLongjmpCall->setDebugLoc(DLoc); | |
188 // No takeName here since longjmp is a void call that does not get assigned to | |
189 // a value. | |
190 | |
191 // Remove the original call. There's no need for RAUW because longjmp | |
192 // returns void. | |
193 Call->eraseFromParent(); | |
194 } | |
195 | |
196 void RewritePNaClLibraryCalls::rewriteLongjmpStore(StoreInst *Store) { | |
197 // Sanity check: this method was called for a store that uses a function | |
198 // pointer to setjmp. | |
199 Function *CalledFunc = dyn_cast_or_null<Function>(Store->getValueOperand()); | |
200 if (CalledFunc != LongjmpFunc) { | |
201 report_fatal_error(Twine("Badly formed store of ") + | |
202 LongjmpFunc->getName()); | |
203 } | |
204 | |
205 Function *LongjmpWrapperFunc = getOrCreateLongjmpWrapper(); | |
206 | |
207 // Replace Store by a new store that stores a pointer to the wrapper. | |
Mark Seaborn
2013/05/13 20:20:42
You should bitcast your wrapper function rather th
| |
208 StoreInst *WrapperStore = new StoreInst(LongjmpWrapperFunc, | |
209 Store->getPointerOperand(), | |
210 Store); | |
211 WrapperStore->setDebugLoc(Store->getDebugLoc()); | |
212 WrapperStore->takeName(Store); | |
213 Store->replaceAllUsesWith(WrapperStore); | |
214 Store->eraseFromParent(); | |
215 } | |
216 | |
217 void RewritePNaClLibraryCalls::rewriteAddrOfLongjmpInGlobal( | |
218 GlobalVariable *Global) { | |
219 if (!Global->hasUniqueInitializer()) { | |
220 report_fatal_error(Twine("Badly formed assignment to global ") + | |
221 Global->getName()); | |
222 } | |
223 | |
224 Function *LongjmpWrapperFunc = getOrCreateLongjmpWrapper(); | |
225 | |
226 GlobalVariable *NewGlobal = new GlobalVariable( | |
227 /* M */ *TheModule, | |
228 /* Ty */ LongjmpWrapperFunc->getType(), | |
229 /* isConstant */ Global->isConstant(), | |
230 /* Linkage */ GlobalValue::PrivateLinkage, | |
231 /* Initializer */ LongjmpWrapperFunc, | |
232 /* Name */ "", | |
233 /* InsertBefore */ Global, | |
234 /* ThreadLocalMode */ Global->getThreadLocalMode()); | |
235 NewGlobal->setAlignment(Global->getAlignment()); | |
236 // Using takeName instead of assigning Name in the constructor of | |
237 // GlobalVariable because otherwise a numeric suffix is added to the name, | |
238 // while we want it to stay exactly the same. | |
239 NewGlobal->takeName(Global); | |
240 Global->eraseFromParent(); | |
241 } | |
242 | |
243 Function *RewritePNaClLibraryCalls::getOrCreateLongjmpWrapper() { | |
244 if (LongjmpWrapperFunc) | |
245 return LongjmpWrapperFunc; | |
246 | |
247 // A wrapper function is created that has the same type as longjmp; it | |
Mark Seaborn
2013/05/13 20:20:42
You actually don't need to create a new function.
eliben
2013/05/13 22:07:18
Done.
| |
248 // redirects the call to the intrinsic after casting pointer argument. | |
249 FunctionType *WrapFuncTy = LongjmpFunc->getFunctionType(); | |
250 SmallString<32> Name(WRAP_FUNC_PREFIX); Name.append(LONGJMP_NAME); | |
Mark Seaborn
2013/05/13 20:20:42
Split onto separate lines.
eliben
2013/05/13 22:07:18
Function removed.
| |
251 Function *LongjmpWrapperFunc = dyn_cast<Function>( | |
252 TheModule->getOrInsertFunction(Name, WrapFuncTy)); | |
253 LongjmpWrapperFunc->setLinkage(Function::PrivateLinkage); | |
254 | |
255 // This function has just been created. Fill its contents. | |
256 LLVMContext &Context = TheModule->getContext(); | |
257 BasicBlock *BB = BasicBlock::Create(Context, "entry", LongjmpWrapperFunc); | |
258 | |
259 Function::arg_iterator LongjmpArgs = LongjmpWrapperFunc->arg_begin(); | |
260 Value *EnvArg = LongjmpArgs++; | |
261 EnvArg->setName("env"); | |
262 Value *ValArg = LongjmpArgs++; | |
263 ValArg->setName("val"); | |
264 | |
265 // Insert a return instruction | |
Mark Seaborn
2013/05/13 20:20:42
Nit: could insert 'unreachable' instead
eliben
2013/05/13 22:07:18
Done.
| |
266 Instruction *Ret = ReturnInst::Create(Context, 0, BB); | |
267 | |
268 // Find the intrinsic function. | |
269 Function *NaClLongjmpFunc = Intrinsic::getDeclaration( | |
270 TheModule, Intrinsic::nacl_longjmp); | |
271 // Cast the jmp_buf argument to the type NaClLongjmpCall expects. | |
272 Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0); | |
273 BitCastInst *JmpBufCast = new BitCastInst(EnvArg, PtrTy, "jmp_buf_i8", Ret); | |
274 | |
275 // Emit the call. | |
276 SmallVector<Value *, 2> Args; | |
277 Args.push_back(JmpBufCast); | |
278 Args.push_back(ValArg); | |
279 CallInst::Create(NaClLongjmpFunc, Args, "", Ret); | |
280 | |
281 return LongjmpWrapperFunc; | |
282 } | |
283 | |
284 ModulePass *llvm::createRewritePNaClLibraryCallsPass() { | |
285 return new RewritePNaClLibraryCalls(); | |
286 } | |
287 | |
OLD | NEW |