| 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 |