OLD | NEW |
1 //===- LowerEmAsyncify - transform asynchronous functions for Emscripten/JS --
---------===// | 1 //===- LowerEmAsyncify - transform asynchronous functions for Emscripten/JS --
---------===// |
2 // | 2 // |
3 // The LLVM Compiler Infrastructure | 3 // The LLVM Compiler Infrastructure |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 // | 9 // |
10 // Lu Wang <coolwanglu@gmail.com> | 10 // Lu Wang <coolwanglu@gmail.com> |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
60 Module *TheModule; | 60 Module *TheModule; |
61 | 61 |
62 public: | 62 public: |
63 static char ID; // Pass identification, replacement for typeid | 63 static char ID; // Pass identification, replacement for typeid |
64 explicit LowerEmAsyncify() : ModulePass(ID), TheModule(NULL) { | 64 explicit LowerEmAsyncify() : ModulePass(ID), TheModule(NULL) { |
65 initializeLowerEmAsyncifyPass(*PassRegistry::getPassRegistry()); | 65 initializeLowerEmAsyncifyPass(*PassRegistry::getPassRegistry()); |
66 } | 66 } |
67 virtual ~LowerEmAsyncify() { } | 67 virtual ~LowerEmAsyncify() { } |
68 bool runOnModule(Module &M); | 68 bool runOnModule(Module &M); |
69 | 69 |
70 virtual void getAnalysisUsage(AnalysisUsage &AU) const { | |
71 AU.addRequired<DataLayoutPass>(); | |
72 ModulePass::getAnalysisUsage(AU); | |
73 } | |
74 | |
75 private: | 70 private: |
76 const DataLayout *DL; | 71 const DataLayout *DL; |
77 | 72 |
78 Type *Void, *I1, *I32, *I32Ptr; | 73 Type *Void, *I1, *I32, *I32Ptr; |
79 FunctionType *VFunction, *I1Function, *I32PFunction; | 74 FunctionType *VFunction, *I1Function, *I32PFunction; |
80 FunctionType *VI32PFunction, *I32PI32Function; | 75 FunctionType *VI32PFunction, *I32PI32Function; |
81 FunctionType *CallbackFunctionType; | 76 FunctionType *CallbackFunctionType; |
82 | 77 |
83 Function *AllocAsyncCtxFunction, *ReallocAsyncCtxFunction, *FreeAsyncCtxFunc
tion; | 78 Function *AllocAsyncCtxFunction, *ReallocAsyncCtxFunction, *FreeAsyncCtxFunc
tion; |
84 Function *CheckAsyncFunction; | 79 Function *CheckAsyncFunction; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
117 }; | 112 }; |
118 } | 113 } |
119 | 114 |
120 char LowerEmAsyncify::ID = 0; | 115 char LowerEmAsyncify::ID = 0; |
121 INITIALIZE_PASS(LowerEmAsyncify, "loweremasyncify", | 116 INITIALIZE_PASS(LowerEmAsyncify, "loweremasyncify", |
122 "Lower async functions for js/emscripten", | 117 "Lower async functions for js/emscripten", |
123 false, false) | 118 false, false) |
124 | 119 |
125 bool LowerEmAsyncify::runOnModule(Module &M) { | 120 bool LowerEmAsyncify::runOnModule(Module &M) { |
126 TheModule = &M; | 121 TheModule = &M; |
| 122 DL = &M.getDataLayout(); |
127 | 123 |
128 std::set<std::string> WhiteList(AsyncifyWhiteList.begin(), AsyncifyWhiteList.e
nd()); | 124 std::set<std::string> WhiteList(AsyncifyWhiteList.begin(), AsyncifyWhiteList.e
nd()); |
129 | 125 |
130 /* | 126 /* |
131 * collect all the functions that should be asyncified | 127 * collect all the functions that should be asyncified |
132 * any function that _might_ call an async function is also async | 128 * any function that _might_ call an async function is also async |
133 */ | 129 */ |
134 std::vector<Function*> AsyncFunctionsPending; | 130 std::vector<Function*> AsyncFunctionsPending; |
135 for(unsigned i = 0; i < AsyncifyFunctions.size(); ++i) { | 131 for(unsigned i = 0; i < AsyncifyFunctions.size(); ++i) { |
136 std::string const& AFName = AsyncifyFunctions[i]; | 132 std::string const& AFName = AsyncifyFunctions[i]; |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
190 | 186 |
191 for (FunctionInstructionsMap::iterator I = AsyncFunctionCalls.begin(), E = Asy
ncFunctionCalls.end(); | 187 for (FunctionInstructionsMap::iterator I = AsyncFunctionCalls.begin(), E = Asy
ncFunctionCalls.end(); |
192 I != E; ++I) { | 188 I != E; ++I) { |
193 transformAsyncFunction(*(I->first), I->second); | 189 transformAsyncFunction(*(I->first), I->second); |
194 } | 190 } |
195 | 191 |
196 return true; | 192 return true; |
197 } | 193 } |
198 | 194 |
199 void LowerEmAsyncify::initTypesAndFunctions(void) { | 195 void LowerEmAsyncify::initTypesAndFunctions(void) { |
200 DL = &getAnalysis<DataLayoutPass>().getDataLayout(); | |
201 | |
202 // Data types | 196 // Data types |
203 Void = Type::getVoidTy(TheModule->getContext()); | 197 Void = Type::getVoidTy(TheModule->getContext()); |
204 I1 = Type::getInt1Ty(TheModule->getContext()); | 198 I1 = Type::getInt1Ty(TheModule->getContext()); |
205 I32 = Type::getInt32Ty(TheModule->getContext()); | 199 I32 = Type::getInt32Ty(TheModule->getContext()); |
206 I32Ptr = Type::getInt32PtrTy(TheModule->getContext()); | 200 I32Ptr = Type::getInt32PtrTy(TheModule->getContext()); |
207 | 201 |
208 // Function types | 202 // Function types |
209 SmallVector<Type*, 2> ArgTypes; | 203 SmallVector<Type*, 2> ArgTypes; |
210 VFunction = FunctionType::get(Void, false); | 204 VFunction = FunctionType::get(Void, false); |
211 I1Function = FunctionType::get(I1, false); | 205 I1Function = FunctionType::get(I1, false); |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
430 // - retrieve the async return value and free the async context if the called
function turns out to be sync | 424 // - retrieve the async return value and free the async context if the called
function turns out to be sync |
431 std::vector<AsyncCallEntry> AsyncCallEntries; | 425 std::vector<AsyncCallEntry> AsyncCallEntries; |
432 AsyncCallEntries.reserve(AsyncCalls.size()); | 426 AsyncCallEntries.reserve(AsyncCalls.size()); |
433 for (Instructions::const_iterator I = AsyncCalls.begin(), E = AsyncCalls.end()
; I != E; ++I) { | 427 for (Instructions::const_iterator I = AsyncCalls.begin(), E = AsyncCalls.end()
; I != E; ++I) { |
434 // prepare blocks | 428 // prepare blocks |
435 Instruction *CurAsyncCall = *I; | 429 Instruction *CurAsyncCall = *I; |
436 | 430 |
437 // The block containing the async call | 431 // The block containing the async call |
438 BasicBlock *CurBlock = CurAsyncCall->getParent(); | 432 BasicBlock *CurBlock = CurAsyncCall->getParent(); |
439 // The block should run after the async call | 433 // The block should run after the async call |
440 BasicBlock *AfterCallBlock = SplitBlock(CurBlock, CurAsyncCall->getNextNode(
), this); | 434 BasicBlock *AfterCallBlock = SplitBlock(CurBlock, CurAsyncCall->getNextNode(
)); |
441 // The block where we store the context and return | 435 // The block where we store the context and return |
442 BasicBlock *SaveAsyncCtxBlock = BasicBlock::Create(TheModule->getContext(),
"SaveAsyncCtx", &F, AfterCallBlock); | 436 BasicBlock *SaveAsyncCtxBlock = BasicBlock::Create(TheModule->getContext(),
"SaveAsyncCtx", &F, AfterCallBlock); |
443 // return a dummy value at the end, to make the block valid | 437 // return a dummy value at the end, to make the block valid |
444 new UnreachableInst(TheModule->getContext(), SaveAsyncCtxBlock); | 438 new UnreachableInst(TheModule->getContext(), SaveAsyncCtxBlock); |
445 | 439 |
446 // allocate the context before making the call | 440 // allocate the context before making the call |
447 // we don't know the size yet, will fix it later | 441 // we don't know the size yet, will fix it later |
448 // we cannot insert the instruction later because, | 442 // we cannot insert the instruction later because, |
449 // we need to make sure that all the instructions and blocks are fixed befor
e we can generate DT and find context variables | 443 // we need to make sure that all the instructions and blocks are fixed befor
e we can generate DT and find context variables |
450 // In CallHandler.h `sp` will be put as the second parameter | 444 // In CallHandler.h `sp` will be put as the second parameter |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
499 CurEntry.AllocAsyncCtxInst->setOperand(0, | 493 CurEntry.AllocAsyncCtxInst->setOperand(0, |
500 ConstantInt::get(I32, DL->getTypeStoreSize(CurEntry.ContextStructType)))
; | 494 ConstantInt::get(I32, DL->getTypeStoreSize(CurEntry.ContextStructType)))
; |
501 | 495 |
502 // construct SaveAsyncCtxBlock | 496 // construct SaveAsyncCtxBlock |
503 { | 497 { |
504 // fill in SaveAsyncCtxBlock | 498 // fill in SaveAsyncCtxBlock |
505 // temporarily remove the terminator for convenience | 499 // temporarily remove the terminator for convenience |
506 CurEntry.SaveAsyncCtxBlock->getTerminator()->eraseFromParent(); | 500 CurEntry.SaveAsyncCtxBlock->getTerminator()->eraseFromParent(); |
507 assert(CurEntry.SaveAsyncCtxBlock->empty()); | 501 assert(CurEntry.SaveAsyncCtxBlock->empty()); |
508 | 502 |
509 BitCastInst *AsyncCtxAddr = new BitCastInst(CurEntry.AllocAsyncCtxInst, Cu
rEntry.ContextStructType->getPointerTo(), "AsyncCtxAddr", CurEntry.SaveAsyncCtxB
lock); | 503 Type *AsyncCtxAddrTy = CurEntry.ContextStructType->getPointerTo(); |
| 504 BitCastInst *AsyncCtxAddr = new BitCastInst(CurEntry.AllocAsyncCtxInst, As
yncCtxAddrTy, "AsyncCtxAddr", CurEntry.SaveAsyncCtxBlock); |
510 SmallVector<Value*, 2> Indices; | 505 SmallVector<Value*, 2> Indices; |
511 // store the callback | 506 // store the callback |
512 { | 507 { |
513 Indices.push_back(ConstantInt::get(I32, 0)); | 508 Indices.push_back(ConstantInt::get(I32, 0)); |
514 Indices.push_back(ConstantInt::get(I32, 0)); | 509 Indices.push_back(ConstantInt::get(I32, 0)); |
515 GetElementPtrInst *AsyncVarAddr = GetElementPtrInst::Create(AsyncCtxAddr
, Indices, "", CurEntry.SaveAsyncCtxBlock); | 510 GetElementPtrInst *AsyncVarAddr = GetElementPtrInst::Create(AsyncCtxAddr
Ty, AsyncCtxAddr, Indices, "", CurEntry.SaveAsyncCtxBlock); |
516 new StoreInst(CurEntry.CallbackFunc, AsyncVarAddr, CurEntry.SaveAsyncCtx
Block); | 511 new StoreInst(CurEntry.CallbackFunc, AsyncVarAddr, CurEntry.SaveAsyncCtx
Block); |
517 } | 512 } |
518 // store the context variables | 513 // store the context variables |
519 for (size_t i = 0; i < CurEntry.ContextVariables.size(); ++i) { | 514 for (size_t i = 0; i < CurEntry.ContextVariables.size(); ++i) { |
520 Indices.clear(); | 515 Indices.clear(); |
521 Indices.push_back(ConstantInt::get(I32, 0)); | 516 Indices.push_back(ConstantInt::get(I32, 0)); |
522 Indices.push_back(ConstantInt::get(I32, i + 1)); // the 0th element is t
he callback function | 517 Indices.push_back(ConstantInt::get(I32, i + 1)); // the 0th element is t
he callback function |
523 GetElementPtrInst *AsyncVarAddr = GetElementPtrInst::Create(AsyncCtxAddr
, Indices, "", CurEntry.SaveAsyncCtxBlock); | 518 GetElementPtrInst *AsyncVarAddr = GetElementPtrInst::Create(AsyncCtxAddr
Ty, AsyncCtxAddr, Indices, "", CurEntry.SaveAsyncCtxBlock); |
524 new StoreInst(CurEntry.ContextVariables[i], AsyncVarAddr, CurEntry.SaveA
syncCtxBlock); | 519 new StoreInst(CurEntry.ContextVariables[i], AsyncVarAddr, CurEntry.SaveA
syncCtxBlock); |
525 } | 520 } |
526 // to exit the block, we want to return without unwinding the stack frame | 521 // to exit the block, we want to return without unwinding the stack frame |
527 CallInst::Create(DoNotUnwindFunction, "", CurEntry.SaveAsyncCtxBlock); | 522 CallInst::Create(DoNotUnwindFunction, "", CurEntry.SaveAsyncCtxBlock); |
528 ReturnInst::Create(TheModule->getContext(), | 523 ReturnInst::Create(TheModule->getContext(), |
529 (F.getReturnType()->isVoidTy() ? 0 : Constant::getNullValue(F.getRetur
nType())), | 524 (F.getReturnType()->isVoidTy() ? 0 : Constant::getNullValue(F.getRetur
nType())), |
530 CurEntry.SaveAsyncCtxBlock); | 525 CurEntry.SaveAsyncCtxBlock); |
531 } | 526 } |
532 } | 527 } |
533 | 528 |
534 // Pass 3 | 529 // Pass 3 |
535 // now all the SaveAsyncCtxBlock's have been constructed | 530 // now all the SaveAsyncCtxBlock's have been constructed |
536 // we can clone F and construct callback functions | 531 // we can clone F and construct callback functions |
537 // we could not construct the callbacks in Pass 2 because we need _all_ those
SaveAsyncCtxBlock's appear in _each_ callback | 532 // we could not construct the callbacks in Pass 2 because we need _all_ those
SaveAsyncCtxBlock's appear in _each_ callback |
538 for (std::vector<AsyncCallEntry>::iterator EI = AsyncCallEntries.begin(), EE =
AsyncCallEntries.end(); EI != EE; ++EI) { | 533 for (std::vector<AsyncCallEntry>::iterator EI = AsyncCallEntries.begin(), EE =
AsyncCallEntries.end(); EI != EE; ++EI) { |
539 AsyncCallEntry & CurEntry = *EI; | 534 AsyncCallEntry & CurEntry = *EI; |
540 | 535 |
541 Function *CurCallbackFunc = CurEntry.CallbackFunc; | 536 Function *CurCallbackFunc = CurEntry.CallbackFunc; |
542 ValueToValueMapTy VMap; | 537 ValueToValueMapTy VMap; |
543 | 538 |
544 // Add the entry block | 539 // Add the entry block |
545 // load variables from the context | 540 // load variables from the context |
546 // also update VMap for CloneFunction | 541 // also update VMap for CloneFunction |
547 BasicBlock *EntryBlock = BasicBlock::Create(TheModule->getContext(), "AsyncC
allbackEntry", CurCallbackFunc); | 542 BasicBlock *EntryBlock = BasicBlock::Create(TheModule->getContext(), "AsyncC
allbackEntry", CurCallbackFunc); |
548 std::vector<LoadInst *> LoadedAsyncVars; | 543 std::vector<LoadInst *> LoadedAsyncVars; |
549 { | 544 { |
550 BitCastInst *AsyncCtxAddr = new BitCastInst(CurCallbackFunc->arg_begin(),
CurEntry.ContextStructType->getPointerTo(), "AsyncCtx", EntryBlock); | 545 Type *AsyncCtxAddrTy = CurEntry.ContextStructType->getPointerTo(); |
| 546 BitCastInst *AsyncCtxAddr = new BitCastInst(CurCallbackFunc->arg_begin(),
AsyncCtxAddrTy, "AsyncCtx", EntryBlock); |
551 SmallVector<Value*, 2> Indices; | 547 SmallVector<Value*, 2> Indices; |
552 for (size_t i = 0; i < CurEntry.ContextVariables.size(); ++i) { | 548 for (size_t i = 0; i < CurEntry.ContextVariables.size(); ++i) { |
553 Indices.clear(); | 549 Indices.clear(); |
554 Indices.push_back(ConstantInt::get(I32, 0)); | 550 Indices.push_back(ConstantInt::get(I32, 0)); |
555 Indices.push_back(ConstantInt::get(I32, i + 1)); // the 0th element of A
syncCtx is the callback function | 551 Indices.push_back(ConstantInt::get(I32, i + 1)); // the 0th element of A
syncCtx is the callback function |
556 GetElementPtrInst *AsyncVarAddr = GetElementPtrInst::Create(AsyncCtxAddr
, Indices, "", EntryBlock); | 552 GetElementPtrInst *AsyncVarAddr = GetElementPtrInst::Create(AsyncCtxAddr
Ty, AsyncCtxAddr, Indices, "", EntryBlock); |
557 LoadedAsyncVars.push_back(new LoadInst(AsyncVarAddr, "", EntryBlock)); | 553 LoadedAsyncVars.push_back(new LoadInst(AsyncVarAddr, "", EntryBlock)); |
558 // we want the argument to be replaced by the loaded value | 554 // we want the argument to be replaced by the loaded value |
559 if (isa<Argument>(CurEntry.ContextVariables[i])) | 555 if (isa<Argument>(CurEntry.ContextVariables[i])) |
560 VMap[CurEntry.ContextVariables[i]] = LoadedAsyncVars.back(); | 556 VMap[CurEntry.ContextVariables[i]] = LoadedAsyncVars.back(); |
561 } | 557 } |
562 } | 558 } |
563 | 559 |
564 // we don't need any argument, just leave dummy entries there to cheat Clone
FunctionInto | 560 // we don't need any argument, just leave dummy entries there to cheat Clone
FunctionInto |
565 for (Function::const_arg_iterator AI = F.arg_begin(), AE = F.arg_end(); AI !
= AE; ++AI) { | 561 for (Function::const_arg_iterator AI = F.arg_begin(), AE = F.arg_end(); AI !
= AE; ++AI) { |
566 if (VMap.count(AI) == 0) | 562 if (VMap.count(AI) == 0) |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
720 // mostly from CallHandler.h | 716 // mostly from CallHandler.h |
721 ImmutableCallSite CS(I); | 717 ImmutableCallSite CS(I); |
722 if (!CS) return false; // not call nor invoke | 718 if (!CS) return false; // not call nor invoke |
723 const Value *CV = CS.getCalledValue()->stripPointerCasts(); | 719 const Value *CV = CS.getCalledValue()->stripPointerCasts(); |
724 return !isa<const Function>(CV); | 720 return !isa<const Function>(CV); |
725 } | 721 } |
726 | 722 |
727 ModulePass *llvm::createLowerEmAsyncifyPass() { | 723 ModulePass *llvm::createLowerEmAsyncifyPass() { |
728 return new LowerEmAsyncify(); | 724 return new LowerEmAsyncify(); |
729 } | 725 } |
730 | |
OLD | NEW |