llvm::BasicBlock *CleanupScope::runCopying(IRState &irs, llvm::BasicBlock *sourceBlock, llvm::BasicBlock *continueWith, llvm::BasicBlock *unwindTo, llvm::Value *funclet) { if (isCatchSwitchBlock(beginBlock())) return continueWith; if (exitTargets.empty()) { if (!endBlock()->getTerminator()) // Set up the unconditional branch at the end of the cleanup llvm::BranchInst::Create(continueWith, endBlock()); } else { // check whether we have an exit target with the same continuation for (CleanupExitTarget &tgt : exitTargets) if (tgt.branchTarget == continueWith) { tgt.sourceBlocks.push_back(sourceBlock); return tgt.cleanupBlocks.front(); } } // reuse the original IR if not unwinding and not already used bool useOriginal = unwindTo == nullptr && funclet == nullptr; for (CleanupExitTarget &tgt : exitTargets) { if (tgt.cleanupBlocks.front() == beginBlock()) { useOriginal = false; break; } } // append new target exitTargets.emplace_back(continueWith); auto &exitTarget = exitTargets.back(); exitTarget.sourceBlocks.push_back(sourceBlock); if (useOriginal) { // change the continuation target if the initial branch was created // by another instance with unwinding if (continueWith) if (auto term = endBlock()->getTerminator()) if (auto succ = term->getSuccessor(0)) if (succ != continueWith) remapBlocksValue(blocks, succ, continueWith); exitTarget.cleanupBlocks = blocks; } else { // clone the code cloneBlocks(blocks, exitTarget.cleanupBlocks, continueWith, unwindTo, funclet); } return exitTarget.cleanupBlocks.front(); }
void Context::beginFunction(const Text &s) { beginBlock(s); }
llvm::BasicBlock *CleanupScope::run(IRState &irs, llvm::BasicBlock *sourceBlock, llvm::BasicBlock *continueWith) { #if LDC_LLVM_VER >= 308 if (useMSVCEH()) return runCopying(irs, sourceBlock, continueWith); #endif if (exitTargets.empty() || (exitTargets.size() == 1 && exitTargets[0].branchTarget == continueWith)) { // We didn't need a branch selector before and still don't need one. assert(!branchSelector); // Set up the unconditional branch at the end of the cleanup if we have // not done so already. if (exitTargets.empty()) { exitTargets.emplace_back(continueWith); llvm::BranchInst::Create(continueWith, endBlock()); } exitTargets.front().sourceBlocks.push_back(sourceBlock); return beginBlock(); } // We need a branch selector if we are here... if (!branchSelector) { // ... and have not created one yet, so do so now. branchSelector = new llvm::AllocaInst(llvm::Type::getInt32Ty(irs.context()), #if LDC_LLVM_VER >= 500 irs.module.getDataLayout().getAllocaAddrSpace(), #endif llvm::Twine("branchsel.") + beginBlock()->getName(), irs.topallocapoint()); // Now we also need to store 0 to it to keep the paths that go to the // only existing branch target the same. for (auto bb : exitTargets.front().sourceBlocks) { new llvm::StoreInst(DtoConstUint(0), branchSelector, bb->getTerminator()); } // And convert the BranchInst to the existing branch target to a // SelectInst so we can append the other cases to it. endBlock()->getTerminator()->eraseFromParent(); llvm::Value *sel = new llvm::LoadInst(branchSelector, "", endBlock()); llvm::SwitchInst::Create( sel, exitTargets[0].branchTarget, 1, // Expected number of branches, only for pre-allocating. endBlock()); } // If we already know this branch target, figure out the branch selector // value and simply insert the store into the source block (prior to the // last instruction, which is the branch to the first cleanup). for (unsigned i = 0; i < exitTargets.size(); ++i) { CleanupExitTarget &t = exitTargets[i]; if (t.branchTarget == continueWith) { new llvm::StoreInst(DtoConstUint(i), branchSelector, sourceBlock->getTerminator()); // Note: Strictly speaking, keeping this up to date would not be // needed right now, because we never to any optimizations that // require changes to the source blocks after the initial conversion // from one to two branch targets. Keeping this around for now to // ease future development, but may be removed to save some work. t.sourceBlocks.push_back(sourceBlock); return beginBlock(); } } // We don't know this branch target yet, so add it to the SwitchInst... llvm::ConstantInt *const selectorVal = DtoConstUint(exitTargets.size()); llvm::cast<llvm::SwitchInst>(endBlock()->getTerminator()) ->addCase(selectorVal, continueWith); // ... insert the store into the source block... new llvm::StoreInst(selectorVal, branchSelector, sourceBlock->getTerminator()); // ... and keep track of it (again, this is unnecessary right now as // discussed in the above note). exitTargets.emplace_back(continueWith); exitTargets.back().sourceBlocks.push_back(sourceBlock); return beginBlock(); }