OLD | NEW |
| (Empty) |
1 //===- LowerEmSetjmp - Lower setjmp/longjmp for Emscripten/JS -----------===// | |
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 // Lowers setjmp to a reasonably-performant approach for emscripten. The idea | |
11 // is that each block with a setjmp is broken up into the part right after | |
12 // the setjmp, and a new basic block is added which is either reached from | |
13 // the setjmp, or later from a longjmp. To handle the longjmp, all calls that | |
14 // might longjmp are checked immediately afterwards. | |
15 // | |
16 //===----------------------------------------------------------------------===// | |
17 | |
18 #include "llvm/Transforms/Scalar.h" | |
19 #include "llvm/ADT/SmallVector.h" | |
20 #include "llvm/ADT/Statistic.h" | |
21 #include "llvm/IR/Constants.h" | |
22 #include "llvm/IR/DerivedTypes.h" | |
23 #include "llvm/IR/Instructions.h" | |
24 #include "llvm/IR/Intrinsics.h" | |
25 #include "llvm/IR/LLVMContext.h" | |
26 #include "llvm/IR/Module.h" | |
27 #include "llvm/Pass.h" | |
28 #include "llvm/Support/CommandLine.h" | |
29 #include "llvm/Target/TargetLowering.h" | |
30 #include "llvm/Transforms/Utils/BasicBlockUtils.h" | |
31 #include "llvm/Transforms/Utils/Local.h" | |
32 #include "llvm/Transforms/NaCl.h" | |
33 #include "llvm/IR/Dominators.h" | |
34 #include "llvm/Transforms/Utils/PromoteMemToReg.h" | |
35 #include <vector> | |
36 #include <set> | |
37 #include <list> | |
38 | |
39 #include "llvm/Support/raw_ostream.h" | |
40 | |
41 #ifdef NDEBUG | |
42 #undef assert | |
43 #define assert(x) { if (!(x)) report_fatal_error(#x); } | |
44 #endif | |
45 | |
46 using namespace llvm; | |
47 | |
48 // Utilities for mem/reg: based on Reg2Mem and MemToReg | |
49 | |
50 bool valueEscapes(const Instruction *Inst) { | |
51 const BasicBlock *BB = Inst->getParent(); | |
52 for (Value::const_user_iterator UI = Inst->user_begin(),E = Inst->user_end(); | |
53 UI != E; ++UI) { | |
54 const User *U = *UI; | |
55 const Instruction *I = cast<Instruction>(U); | |
56 if (I->getParent() != BB || isa<PHINode>(I)) | |
57 return true; | |
58 } | |
59 return false; | |
60 } | |
61 | |
62 void doRegToMem(Function &F) { // see Reg2Mem.cpp | |
63 // Insert all new allocas into entry block. | |
64 BasicBlock *BBEntry = &F.getEntryBlock(); | |
65 assert(pred_begin(BBEntry) == pred_end(BBEntry) && | |
66 "Entry block to function must not have predecessors!"); | |
67 | |
68 // Find first non-alloca instruction and create insertion point. This is | |
69 // safe if block is well-formed: it always have terminator, otherwise | |
70 // we'll get and assertion. | |
71 BasicBlock::iterator I = BBEntry->begin(); | |
72 while (isa<AllocaInst>(I)) ++I; | |
73 | |
74 CastInst *AllocaInsertionPoint = | |
75 new BitCastInst(Constant::getNullValue(Type::getInt32Ty(F.getContext())), | |
76 Type::getInt32Ty(F.getContext()), | |
77 "reg2mem alloca point", I); | |
78 | |
79 // Find the escaped instructions. But don't create stack slots for | |
80 // allocas in entry block. | |
81 std::list<Instruction*> WorkList; | |
82 for (Function::iterator ibb = F.begin(), ibe = F.end(); | |
83 ibb != ibe; ++ibb) | |
84 for (BasicBlock::iterator iib = ibb->begin(), iie = ibb->end(); | |
85 iib != iie; ++iib) { | |
86 if (!(isa<AllocaInst>(iib) && iib->getParent() == BBEntry) && | |
87 valueEscapes(iib)) { | |
88 WorkList.push_front(&*iib); | |
89 } | |
90 } | |
91 | |
92 // Demote escaped instructions | |
93 for (std::list<Instruction*>::iterator ilb = WorkList.begin(), | |
94 ile = WorkList.end(); ilb != ile; ++ilb) | |
95 DemoteRegToStack(**ilb, false, AllocaInsertionPoint); | |
96 | |
97 WorkList.clear(); | |
98 | |
99 // Find all phi's | |
100 for (Function::iterator ibb = F.begin(), ibe = F.end(); | |
101 ibb != ibe; ++ibb) | |
102 for (BasicBlock::iterator iib = ibb->begin(), iie = ibb->end(); | |
103 iib != iie; ++iib) | |
104 if (isa<PHINode>(iib)) | |
105 WorkList.push_front(&*iib); | |
106 | |
107 // Demote phi nodes | |
108 for (std::list<Instruction*>::iterator ilb = WorkList.begin(), | |
109 ile = WorkList.end(); ilb != ile; ++ilb) | |
110 DemotePHIToStack(cast<PHINode>(*ilb), AllocaInsertionPoint); | |
111 } | |
112 | |
113 void doMemToReg(Function &F) { | |
114 std::vector<AllocaInst*> Allocas; | |
115 | |
116 BasicBlock &BB = F.getEntryBlock(); // Get the entry node for the function | |
117 | |
118 DominatorTreeWrapperPass DTW; | |
119 DTW.runOnFunction(F); | |
120 DominatorTree& DT = DTW.getDomTree(); | |
121 | |
122 while (1) { | |
123 Allocas.clear(); | |
124 | |
125 // Find allocas that are safe to promote, by looking at all instructions in | |
126 // the entry node | |
127 for (BasicBlock::iterator I = BB.begin(), E = --BB.end(); I != E; ++I) | |
128 if (AllocaInst *AI = dyn_cast<AllocaInst>(I)) // Is it an alloca? | |
129 if (isAllocaPromotable(AI)) | |
130 Allocas.push_back(AI); | |
131 | |
132 if (Allocas.empty()) break; | |
133 | |
134 PromoteMemToReg(Allocas, DT); | |
135 } | |
136 } | |
137 | |
138 // LowerEmSetjmp | |
139 | |
140 namespace { | |
141 class LowerEmSetjmp : public ModulePass { | |
142 Module *TheModule; | |
143 | |
144 public: | |
145 static char ID; // Pass identification, replacement for typeid | |
146 explicit LowerEmSetjmp() : ModulePass(ID), TheModule(NULL) { | |
147 initializeLowerEmSetjmpPass(*PassRegistry::getPassRegistry()); | |
148 } | |
149 bool runOnModule(Module &M); | |
150 }; | |
151 } | |
152 | |
153 char LowerEmSetjmp::ID = 0; | |
154 INITIALIZE_PASS(LowerEmSetjmp, "loweremsetjmp", | |
155 "Lower setjmp and longjmp for js/emscripten", | |
156 false, false) | |
157 | |
158 bool LowerEmSetjmp::runOnModule(Module &M) { | |
159 TheModule = &M; | |
160 | |
161 Function *Setjmp = TheModule->getFunction("setjmp"); | |
162 Function *Longjmp = TheModule->getFunction("longjmp"); | |
163 if (!Setjmp && !Longjmp) return false; | |
164 | |
165 Type *i32 = Type::getInt32Ty(M.getContext()); | |
166 Type *Void = Type::getVoidTy(M.getContext()); | |
167 | |
168 // Add functions | |
169 | |
170 Function *EmSetjmp = NULL; | |
171 | |
172 if (Setjmp) { | |
173 SmallVector<Type*, 2> EmSetjmpTypes; | |
174 EmSetjmpTypes.push_back(Setjmp->getFunctionType()->getParamType(0)); | |
175 EmSetjmpTypes.push_back(i32); // extra param that says which setjmp in the f
unction it is | |
176 FunctionType *EmSetjmpFunc = FunctionType::get(i32, EmSetjmpTypes, false); | |
177 EmSetjmp = Function::Create(EmSetjmpFunc, GlobalValue::ExternalLinkage, "ems
cripten_setjmp", TheModule); | |
178 } | |
179 | |
180 Function *EmLongjmp = Longjmp ? Function::Create(Longjmp->getFunctionType(), G
lobalValue::ExternalLinkage, "emscripten_longjmp", TheModule) : NULL; | |
181 | |
182 SmallVector<Type*, 1> IntArgTypes; | |
183 IntArgTypes.push_back(i32); | |
184 FunctionType *IntIntFunc = FunctionType::get(i32, IntArgTypes, false); | |
185 | |
186 Function *CheckLongjmp = Function::Create(IntIntFunc, GlobalValue::ExternalLin
kage, "emscripten_check_longjmp", TheModule); // gets control flow | |
187 | |
188 Function *GetLongjmpResult = Function::Create(IntIntFunc, GlobalValue::Externa
lLinkage, "emscripten_get_longjmp_result", TheModule); // gets int value longjmp
'd | |
189 | |
190 FunctionType *VoidFunc = FunctionType::get(Void, false); | |
191 Function *PrepSetjmp = Function::Create(VoidFunc, GlobalValue::ExternalLinkage
, "emscripten_prep_setjmp", TheModule); | |
192 | |
193 Function *CleanupSetjmp = Function::Create(VoidFunc, GlobalValue::ExternalLink
age, "emscripten_cleanup_setjmp", TheModule); | |
194 | |
195 Function *PreInvoke = TheModule->getFunction("emscripten_preinvoke"); | |
196 if (!PreInvoke) PreInvoke = Function::Create(VoidFunc, GlobalValue::ExternalLi
nkage, "emscripten_preinvoke", TheModule); | |
197 | |
198 FunctionType *IntFunc = FunctionType::get(i32, false); | |
199 Function *PostInvoke = TheModule->getFunction("emscripten_postinvoke"); | |
200 if (!PostInvoke) PostInvoke = Function::Create(IntFunc, GlobalValue::ExternalL
inkage, "emscripten_postinvoke", TheModule); | |
201 | |
202 // Process all callers of setjmp and longjmp. Start with setjmp. | |
203 | |
204 typedef std::vector<PHINode*> Phis; | |
205 typedef std::map<Function*, Phis> FunctionPhisMap; | |
206 FunctionPhisMap SetjmpOutputPhis; | |
207 std::vector<Instruction*> ToErase; | |
208 | |
209 if (Setjmp) { | |
210 for (Instruction::user_iterator UI = Setjmp->user_begin(), UE = Setjmp->user
_end(); UI != UE; ++UI) { | |
211 User *U = *UI; | |
212 if (CallInst *CI = dyn_cast<CallInst>(U)) { | |
213 BasicBlock *SJBB = CI->getParent(); | |
214 // The tail is everything right after the call, and will be reached once
when setjmp is | |
215 // called, and later when longjmp returns to the setjmp | |
216 BasicBlock *Tail = SplitBlock(SJBB, CI->getNextNode()); | |
217 // Add a phi to the tail, which will be the output of setjmp, which indi
cates if this is the | |
218 // first call or a longjmp back. The phi directly uses the right value b
ased on where we | |
219 // arrive from | |
220 PHINode *SetjmpOutput = PHINode::Create(i32, 2, "", Tail->getFirstNonPHI
()); | |
221 SetjmpOutput->addIncoming(ConstantInt::get(i32, 0), SJBB); // setjmp ini
tial call returns 0 | |
222 CI->replaceAllUsesWith(SetjmpOutput); // The proper output is now this,
not the setjmp call itself | |
223 // longjmp returns to the setjmp will add themselves to this phi | |
224 Phis& P = SetjmpOutputPhis[SJBB->getParent()]; | |
225 P.push_back(SetjmpOutput); | |
226 // fix call target | |
227 SmallVector<Value *, 2> Args; | |
228 Args.push_back(CI->getArgOperand(0)); | |
229 Args.push_back(ConstantInt::get(i32, P.size())); // our index in the fun
ction is our place in the array + 1 | |
230 CallInst::Create(EmSetjmp, Args, "", CI); | |
231 ToErase.push_back(CI); | |
232 } else { | |
233 errs() << **UI << "\n"; | |
234 report_fatal_error("bad use of setjmp, should only call it"); | |
235 } | |
236 } | |
237 } | |
238 | |
239 // Update longjmp FIXME: we could avoid throwing in longjmp as an optimization
when longjmping back into the current function perhaps? | |
240 | |
241 if (Longjmp) Longjmp->replaceAllUsesWith(EmLongjmp); | |
242 | |
243 // Update all setjmping functions | |
244 | |
245 for (FunctionPhisMap::iterator I = SetjmpOutputPhis.begin(); I != SetjmpOutput
Phis.end(); I++) { | |
246 Function *F = I->first; | |
247 Phis& P = I->second; | |
248 | |
249 CallInst::Create(PrepSetjmp, "", F->begin()->begin()); | |
250 | |
251 // Update each call that can longjmp so it can return to a setjmp where rele
vant | |
252 | |
253 for (Function::iterator BBI = F->begin(), E = F->end(); BBI != E; ) { | |
254 BasicBlock *BB = BBI++; | |
255 for (BasicBlock::iterator Iter = BB->begin(), E = BB->end(); Iter != E; )
{ | |
256 Instruction *I = Iter++; | |
257 CallInst *CI; | |
258 if ((CI = dyn_cast<CallInst>(I))) { | |
259 Value *V = CI->getCalledValue(); | |
260 if (V == PrepSetjmp || V == EmSetjmp || V == CheckLongjmp || V == GetL
ongjmpResult || V == PreInvoke || V == PostInvoke) continue; | |
261 if (Function *CF = dyn_cast<Function>(V)) if (CF->isIntrinsic()) conti
nue; | |
262 // TODO: proper analysis of what can actually longjmp. Currently we as
sume anything but setjmp can. | |
263 // This may longjmp, so we need to check if it did. Split at that poin
t, and | |
264 // envelop the call in pre/post invoke, if we need to | |
265 CallInst *After; | |
266 Instruction *Check = NULL; | |
267 if (Iter != E && (After = dyn_cast<CallInst>(Iter)) && After->getCalle
dValue() == PostInvoke) { | |
268 // use the pre|postinvoke that exceptions lowering already made | |
269 Check = Iter++; | |
270 } | |
271 BasicBlock *Tail = SplitBlock(BB, Iter); // Iter already points to the
next instruction, as we need | |
272 TerminatorInst *TI = BB->getTerminator(); | |
273 if (!Check) { | |
274 // no existing pre|postinvoke, create our own | |
275 CallInst::Create(PreInvoke, "", CI); | |
276 Check = CallInst::Create(PostInvoke, "", TI); // CI is at the end of
the block | |
277 | |
278 // If we are calling a function that is noreturn, we must remove tha
t attribute. The code we | |
279 // insert here does expect it to return, after we catch the exceptio
n. | |
280 if (CI->doesNotReturn()) { | |
281 if (Function *F = dyn_cast<Function>(CI->getCalledValue())) { | |
282 F->removeFnAttr(Attribute::NoReturn); | |
283 } | |
284 CI->setAttributes(CI->getAttributes().removeAttribute(TheModule->g
etContext(), AttributeSet::FunctionIndex, Attribute::NoReturn)); | |
285 assert(!CI->doesNotReturn()); | |
286 } | |
287 } | |
288 | |
289 // We need to replace the terminator in Tail - SplitBlock makes BB go
straight to Tail, we need to check if a longjmp occurred, and | |
290 // go to the right setjmp-tail if so | |
291 SmallVector<Value *, 1> Args; | |
292 Args.push_back(Check); | |
293 Instruction *LongjmpCheck = CallInst::Create(CheckLongjmp, Args, "", B
B); | |
294 Instruction *LongjmpResult = CallInst::Create(GetLongjmpResult, Args,
"", BB); | |
295 SwitchInst *SI = SwitchInst::Create(LongjmpCheck, Tail, 2, BB); | |
296 // -1 means no longjmp happened, continue normally (will hit the defau
lt switch case). 0 means a longjmp that is not ours to handle, needs a rethrow.
Otherwise | |
297 // the index mean is the same as the index in P+1 (to avoid 0). | |
298 for (unsigned i = 0; i < P.size(); i++) { | |
299 SI->addCase(cast<ConstantInt>(ConstantInt::get(i32, i+1)), P[i]->get
Parent()); | |
300 P[i]->addIncoming(LongjmpResult, BB); | |
301 } | |
302 ToErase.push_back(TI); // new terminator is now the switch | |
303 | |
304 // we are splitting the block here, and must continue to find other ca
lls in the block - which is now split. so continue | |
305 // to traverse in the Tail | |
306 BB = Tail; | |
307 Iter = BB->begin(); | |
308 E = BB->end(); | |
309 } else if (InvokeInst *CI = dyn_cast<InvokeInst>(I)) { // XXX check if t
arget is setjmp | |
310 (void)CI; | |
311 report_fatal_error("TODO: invoke inside setjmping functions"); | |
312 } | |
313 } | |
314 } | |
315 | |
316 // add a cleanup before each return | |
317 for (Function::iterator BBI = F->begin(), E = F->end(); BBI != E; ) { | |
318 BasicBlock *BB = BBI++; | |
319 TerminatorInst *TI = BB->getTerminator(); | |
320 if (isa<ReturnInst>(TI)) { | |
321 CallInst::Create(CleanupSetjmp, "", TI); | |
322 } | |
323 } | |
324 } | |
325 | |
326 for (unsigned i = 0; i < ToErase.size(); i++) { | |
327 ToErase[i]->eraseFromParent(); | |
328 } | |
329 | |
330 // Finally, our modifications to the cfg can break dominance of SSA variables.
For example, | |
331 // if (x()) { .. setjmp() .. } | |
332 // if (y()) { .. longjmp() .. } | |
333 // We must split the longjmp block, and it can jump into the setjmp one. But t
hat means that when | |
334 // we split the setjmp block, it's first part no longer dominates its second p
art - there is | |
335 // a theoretically possible control flow path where x() is false, then y() is
true and we | |
336 // reach the second part of the setjmp block, without ever reaching the first
part. So, | |
337 // we recalculate regs vs. mem | |
338 for (FunctionPhisMap::iterator I = SetjmpOutputPhis.begin(); I != SetjmpOutput
Phis.end(); I++) { | |
339 Function *F = I->first; | |
340 doRegToMem(*F); | |
341 doMemToReg(*F); | |
342 } | |
343 | |
344 return true; | |
345 } | |
346 | |
347 ModulePass *llvm::createLowerEmSetjmpPass() { | |
348 return new LowerEmSetjmp(); | |
349 } | |
OLD | NEW |