//===--- BasicBlockUtils.cpp - Utilities for SILBasicBlock ----------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include "swift/SIL/BasicBlockUtils.h" #include "swift/SIL/Dominance.h" #include "swift/SIL/LoopInfo.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBasicBlock.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILFunction.h" using namespace swift; static bool hasBranchArguments(TermInst *T, unsigned edgeIdx) { if (auto *BI = dyn_cast(T)) { assert(edgeIdx == 0); return BI->getNumArgs() != 0; } if (auto CBI = dyn_cast(T)) { assert(edgeIdx <= 1); return edgeIdx == CondBranchInst::TrueIdx ? !CBI->getTrueArgs().empty() : !CBI->getFalseArgs().empty(); } // No other terminator have branch arguments. return false; } void swift::changeBranchTarget(TermInst *T, unsigned edgeIdx, SILBasicBlock *newDest, bool preserveArgs) { // In many cases, we can just rewrite the successor in place. if (preserveArgs || !hasBranchArguments(T, edgeIdx)) { T->getSuccessors()[edgeIdx] = newDest; return; } // Otherwise, we have to build a new branch instruction. SILBuilderWithScope B(T); switch (T->getTermKind()) { // Only Branch and CondBranch may have arguments. case TermKind::BranchInst: { auto *BI = cast(T); SmallVector args; if (preserveArgs) { for (auto arg : BI->getArgs()) args.push_back(arg); } B.createBranch(T->getLoc(), newDest, args); BI->dropAllReferences(); BI->eraseFromParent(); return; } case TermKind::CondBranchInst: { auto CBI = cast(T); SILBasicBlock *trueDest = CBI->getTrueBB(); SILBasicBlock *falseDest = CBI->getFalseBB(); SmallVector trueArgs; SmallVector falseArgs; if (edgeIdx == CondBranchInst::FalseIdx) { falseDest = newDest; for (auto arg : CBI->getTrueArgs()) trueArgs.push_back(arg); } else { trueDest = newDest; for (auto arg : CBI->getFalseArgs()) falseArgs.push_back(arg); } B.createCondBranch(CBI->getLoc(), CBI->getCondition(), trueDest, trueArgs, falseDest, falseArgs, CBI->getTrueBBCount(), CBI->getFalseBBCount()); CBI->dropAllReferences(); CBI->eraseFromParent(); return; } default: llvm_unreachable("only branch and cond_branch have branch arguments"); } } template static SILBasicBlock *getNthEdgeBlock(SwitchInstTy *S, unsigned edgeIdx) { if (S->getNumCases() == edgeIdx) return S->getDefaultBB(); return S->getCase(edgeIdx).second; } void swift::getEdgeArgs(TermInst *T, unsigned edgeIdx, SILBasicBlock *newEdgeBB, llvm::SmallVectorImpl &args) { switch (T->getKind()) { case SILInstructionKind::BranchInst: { auto *B = cast(T); for (auto V : B->getArgs()) args.push_back(V); return; } case SILInstructionKind::CondBranchInst: { auto CBI = cast(T); assert(edgeIdx < 2); auto OpdArgs = edgeIdx ? CBI->getFalseArgs() : CBI->getTrueArgs(); for (auto V : OpdArgs) args.push_back(V); return; } case SILInstructionKind::SwitchValueInst: { auto SEI = cast(T); auto *succBB = getNthEdgeBlock(SEI, edgeIdx); assert(succBB->getNumArguments() == 0 && "Can't take an argument"); (void)succBB; return; } // A switch_enum can implicitly pass the enum payload. We need to look at the // destination block to figure this out. case SILInstructionKind::SwitchEnumInst: case SILInstructionKind::SwitchEnumAddrInst: { auto SEI = cast(T); auto *succBB = getNthEdgeBlock(SEI, edgeIdx); assert(succBB->getNumArguments() < 2 && "Can take at most one argument"); if (!succBB->getNumArguments()) return; args.push_back(newEdgeBB->createPhiArgument( succBB->getArgument(0)->getType(), ValueOwnershipKind::Owned)); return; } // A dynamic_method_br passes the function to the first basic block. case SILInstructionKind::DynamicMethodBranchInst: { auto DMBI = cast(T); auto *succBB = (edgeIdx == 0) ? DMBI->getHasMethodBB() : DMBI->getNoMethodBB(); if (!succBB->getNumArguments()) return; args.push_back(newEdgeBB->createPhiArgument( succBB->getArgument(0)->getType(), ValueOwnershipKind::Owned)); return; } /// A checked_cast_br passes the result of the cast to the first basic block. case SILInstructionKind::CheckedCastBranchInst: { auto CBI = cast(T); auto succBB = edgeIdx == 0 ? CBI->getSuccessBB() : CBI->getFailureBB(); if (!succBB->getNumArguments()) return; args.push_back(newEdgeBB->createPhiArgument( succBB->getArgument(0)->getType(), ValueOwnershipKind::Owned)); return; } case SILInstructionKind::CheckedCastAddrBranchInst: { auto CBI = cast(T); auto succBB = edgeIdx == 0 ? CBI->getSuccessBB() : CBI->getFailureBB(); if (!succBB->getNumArguments()) return; args.push_back(newEdgeBB->createPhiArgument( succBB->getArgument(0)->getType(), ValueOwnershipKind::Owned)); return; } case SILInstructionKind::CheckedCastValueBranchInst: { auto CBI = cast(T); auto succBB = edgeIdx == 0 ? CBI->getSuccessBB() : CBI->getFailureBB(); if (!succBB->getNumArguments()) return; args.push_back(newEdgeBB->createPhiArgument( succBB->getArgument(0)->getType(), ValueOwnershipKind::Owned)); return; } case SILInstructionKind::TryApplyInst: { auto *TAI = cast(T); auto *succBB = edgeIdx == 0 ? TAI->getNormalBB() : TAI->getErrorBB(); if (!succBB->getNumArguments()) return; args.push_back(newEdgeBB->createPhiArgument( succBB->getArgument(0)->getType(), ValueOwnershipKind::Owned)); return; } case SILInstructionKind::YieldInst: // The edges from 'yield' never have branch arguments. return; case SILInstructionKind::ReturnInst: case SILInstructionKind::ThrowInst: case SILInstructionKind::UnwindInst: case SILInstructionKind::UnreachableInst: llvm_unreachable("terminator never has successors"); #define TERMINATOR(ID, ...) #define INST(ID, BASE) case SILInstructionKind::ID: #include "swift/SIL/SILNodes.def" llvm_unreachable("not a terminator"); } llvm_unreachable("bad instruction kind"); } SILBasicBlock *swift::splitEdge(TermInst *T, unsigned edgeIdx, DominanceInfo *DT, SILLoopInfo *LI) { auto *srcBB = T->getParent(); auto *F = srcBB->getParent(); SILBasicBlock *destBB = T->getSuccessors()[edgeIdx]; // Create a new basic block in the edge, and insert it after the srcBB. auto *edgeBB = F->createBasicBlockAfter(srcBB); SmallVector args; getEdgeArgs(T, edgeIdx, edgeBB, args); SILBuilderWithScope(edgeBB, T).createBranch(T->getLoc(), destBB, args); // Strip the arguments and rewire the branch in the source block. changeBranchTarget(T, edgeIdx, edgeBB, /*PreserveArgs=*/false); if (!DT && !LI) return edgeBB; // Update the dominator tree. if (DT) { auto *srcBBNode = DT->getNode(srcBB); // Unreachable code could result in a null return here. if (srcBBNode) { // The new block is dominated by the srcBB. auto *edgeBBNode = DT->addNewBlock(edgeBB, srcBB); // Are all predecessors of destBB dominated by destBB? auto *destBBNode = DT->getNode(destBB); bool oldSrcBBDominatesAllPreds = std::all_of( destBB->pred_begin(), destBB->pred_end(), [=](SILBasicBlock *B) { if (B == edgeBB) return true; auto *PredNode = DT->getNode(B); if (!PredNode) return true; if (DT->dominates(destBBNode, PredNode)) return true; return false; }); // If so, the new bb dominates destBB now. if (oldSrcBBDominatesAllPreds) DT->changeImmediateDominator(destBBNode, edgeBBNode); } } if (!LI) return edgeBB; // Update loop info. Both blocks must be in a loop otherwise the split block // is outside the loop. SILLoop *srcBBLoop = LI->getLoopFor(srcBB); if (!srcBBLoop) return edgeBB; SILLoop *DstBBLoop = LI->getLoopFor(destBB); if (!DstBBLoop) return edgeBB; // Same loop. if (DstBBLoop == srcBBLoop) { DstBBLoop->addBasicBlockToLoop(edgeBB, LI->getBase()); return edgeBB; } // Edge from inner to outer loop. if (DstBBLoop->contains(srcBBLoop)) { DstBBLoop->addBasicBlockToLoop(edgeBB, LI->getBase()); return edgeBB; } // Edge from outer to inner loop. if (srcBBLoop->contains(DstBBLoop)) { srcBBLoop->addBasicBlockToLoop(edgeBB, LI->getBase()); return edgeBB; } // Neither loop contains the other. The destination must be the header of its // loop. Otherwise, we would be creating irreducible control flow. assert(DstBBLoop->getHeader() == destBB && "Creating irreducible control flow?"); // Add to outer loop if there is one. if (auto *parent = DstBBLoop->getParentLoop()) parent->addBasicBlockToLoop(edgeBB, LI->getBase()); return edgeBB; } /// Merge the basic block with its successor if possible. void swift::mergeBasicBlockWithSingleSuccessor(SILBasicBlock *BB, SILBasicBlock *succBB) { auto *BI = cast(BB->getTerminator()); assert(succBB->getSinglePredecessorBlock()); // If there are any BB arguments in the destination, replace them with the // branch operands, since they must dominate the dest block. for (unsigned i = 0, e = BI->getArgs().size(); i != e; ++i) succBB->getArgument(i)->replaceAllUsesWith(BI->getArg(i)); BI->eraseFromParent(); // Move the instruction from the successor block to the current block. BB->spliceAtEnd(succBB); succBB->eraseFromParent(); } //===----------------------------------------------------------------------===// // DeadEndBlocks //===----------------------------------------------------------------------===// void DeadEndBlocks::compute() { assert(ReachableBlocks.empty() && "Computed twice"); // First step: find blocks which end up in a no-return block (terminated by // an unreachable instruction). // Search for function-exiting blocks, i.e. return and throw. for (const SILBasicBlock &BB : *F) { const TermInst *TI = BB.getTerminator(); if (TI->isFunctionExiting()) ReachableBlocks.insert(&BB); } // Propagate the reachability up the control flow graph. unsigned Idx = 0; while (Idx < ReachableBlocks.size()) { const SILBasicBlock *BB = ReachableBlocks[Idx++]; for (SILBasicBlock *Pred : BB->getPredecessorBlocks()) ReachableBlocks.insert(Pred); } }