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