Expose SIL/BasicBlockUtils for critical edge splitting.

The primary interfaces for CFG manipulation belong in SIL. This is
just what's necessary to fix SILCloner.
This commit is contained in:
Andrew Trick
2018-09-26 18:39:40 -07:00
parent f625f466c4
commit 12bb49f57a
7 changed files with 315 additions and 302 deletions

View File

@@ -13,12 +13,40 @@
#ifndef SWIFT_SIL_DEADENDBLOCKS_H
#define SWIFT_SIL_DEADENDBLOCKS_H
#include "swift/SIL/SILValue.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallVector.h"
namespace swift {
class SILFunction;
class SILBasicBlock;
class TermInst;
class DominanceInfo;
class SILLoopInfo;
/// \brief Replace a branch target.
///
/// \param T The terminating instruction to modify.
/// \param edgeIdx The successor edges index that will be replaced.
/// \param newDest The new target block.
/// \param preserveArgs If set, preserve arguments on the replaced edge.
void changeBranchTarget(TermInst *T, unsigned edgeIdx, SILBasicBlock *newDest,
bool preserveArgs);
/// Returns the arguments values on the specified CFG edge. If necessary, may
/// add create new SILPHIArguments, using `NewEdgeBB` as the placeholder.
void getEdgeArgs(TermInst *T, unsigned edgeIdx, SILBasicBlock *newEdgeBB,
llvm::SmallVectorImpl<SILValue> &args);
/// \brief Splits the edge from terminator.
///
/// Also updates dominance and loop information if not null.
///
/// Returns the newly created basic block.
SILBasicBlock *splitEdge(TermInst *T, unsigned edgeIdx,
DominanceInfo *DT = nullptr,
SILLoopInfo *LI = nullptr);
/// \brief Merge a basic block ending in a branch with its successor
/// if possible.

View File

@@ -45,23 +45,14 @@ TermInst *addNewEdgeValueToBranch(TermInst *Branch, SILBasicBlock *Dest,
TermInst *changeEdgeValue(TermInst *Branch, SILBasicBlock *Dest, size_t Idx,
SILValue Val);
/// \brief Replace a branch target.
///
/// \param T The terminating instruction to modify.
/// \param EdgeIdx The successor edges index that will be replaced.
/// \param NewDest The new target block.
/// \param PreserveArgs If set, preserve arguments on the replaced edge.
void changeBranchTarget(TermInst *T, unsigned EdgeIdx, SILBasicBlock *NewDest,
bool PreserveArgs);
/// \brief Replace a branch target.
///
/// \param T The terminating instruction to modify.
/// \param OldDest The successor block that will be replaced.
/// \param NewDest The new target block.
/// \param PreserveArgs If set, preserve arguments on the replaced edge.
void replaceBranchTarget(TermInst *T, SILBasicBlock *OldDest, SILBasicBlock *NewDest,
bool PreserveArgs);
void replaceBranchTarget(TermInst *T, SILBasicBlock *OldDest,
SILBasicBlock *NewDest, bool PreserveArgs);
/// \brief Check if the edge from the terminator is critical.
bool isCriticalEdge(TermInst *T, unsigned EdgeIdx);
@@ -85,14 +76,6 @@ SILBasicBlock *splitIfCriticalEdge(SILBasicBlock *From, SILBasicBlock *To,
DominanceInfo *DT = nullptr,
SILLoopInfo *LI = nullptr);
/// \brief Splits the edge from terminator.
///
/// Updates dominance information and loop information if not null.
/// Returns the newly created basic block.
SILBasicBlock *splitEdge(TermInst *T, unsigned EdgeIdx,
DominanceInfo *DT = nullptr,
SILLoopInfo *LI = nullptr);
/// \brief Splits the edges between two basic blocks.
///
/// Updates dominance information and loop information if not null.

View File

@@ -11,12 +11,292 @@
//===----------------------------------------------------------------------===//
#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<BranchInst>(T)) {
assert(edgeIdx == 0);
return BI->getNumArgs() != 0;
}
if (auto CBI = dyn_cast<CondBranchInst>(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<BranchInst>(T);
SmallVector<SILValue, 8> args;
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<CondBranchInst>(T);
SILBasicBlock *trueDest = CBI->getTrueBB();
SILBasicBlock *falseDest = CBI->getFalseBB();
SmallVector<SILValue, 8> trueArgs;
SmallVector<SILValue, 8> 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 <class SwitchInstTy>
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<SILValue> &args) {
switch (T->getKind()) {
case SILInstructionKind::BranchInst: {
auto *B = cast<BranchInst>(T);
for (auto V : B->getArgs())
args.push_back(V);
return;
}
case SILInstructionKind::CondBranchInst: {
auto CBI = cast<CondBranchInst>(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<SwitchValueInst>(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<SwitchEnumInstBase>(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<DynamicMethodBranchInst>(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<CheckedCastBranchInst>(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<CheckedCastAddrBranchInst>(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<CheckedCastValueBranchInst>(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<TryApplyInst>(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<SILValue, 16> args;
getEdgeArgs(T, edgeIdx, edgeBB, args);
SILBuilder(edgeBB).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) {

View File

@@ -17,6 +17,7 @@
#define DEBUG_TYPE "sil-speculative-devirtualizer"
#include "swift/SIL/BasicBlockUtils.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILFunction.h"
@@ -29,7 +30,6 @@
#include "swift/SILOptimizer/PassManager/Passes.h"
#include "swift/SILOptimizer/PassManager/PassManager.h"
#include "swift/SILOptimizer/PassManager/Transforms.h"
#include "swift/SILOptimizer/Utils/CFG.h"
#include "swift/SILOptimizer/Utils/Devirtualize.h"
#include "swift/SILOptimizer/Utils/SILInliner.h"
#include "swift/AST/ASTContext.h"

View File

@@ -13,6 +13,7 @@
#include "swift/SIL/BasicBlockUtils.h"
#include "swift/SIL/Dominance.h"
#include "swift/SIL/LoopInfo.h"
#include "swift/SIL/BasicBlockUtils.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SILOptimizer/Utils/CFG.h"
@@ -171,76 +172,6 @@ SILBasicBlock *replaceSwitchDest(SwitchEnumTy *S,
return DefaultBB;
}
static bool hasBranchArguments(TermInst *T, unsigned EdgeIdx) {
if (auto Br = dyn_cast<BranchInst>(T)) {
assert(EdgeIdx == 0);
return Br->getNumArgs() != 0;
} else if (auto CondBr = dyn_cast<CondBranchInst>(T)) {
assert(EdgeIdx <= 1);
return EdgeIdx == CondBranchInst::TrueIdx
? !CondBr->getTrueArgs().empty()
: !CondBr->getFalseArgs().empty();
} else {
// 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 Br = cast<BranchInst>(T);
SmallVector<SILValue, 8> Args;
for (auto Arg : Br->getArgs())
Args.push_back(Arg);
B.createBranch(T->getLoc(), NewDest, Args);
Br->dropAllReferences();
Br->eraseFromParent();
return;
}
case TermKind::CondBranchInst: {
auto CondBr = cast<CondBranchInst>(T);
SILBasicBlock *TrueDest = CondBr->getTrueBB();
SILBasicBlock *FalseDest = CondBr->getFalseBB();
SmallVector<SILValue, 8> TrueArgs;
SmallVector<SILValue, 8> FalseArgs;
if (EdgeIdx == CondBranchInst::FalseIdx) {
FalseDest = NewDest;
for (auto Arg : CondBr->getTrueArgs())
TrueArgs.push_back(Arg);
} else {
TrueDest = NewDest;
for (auto Arg : CondBr->getFalseArgs())
FalseArgs.push_back(Arg);
}
B.createCondBranch(CondBr->getLoc(), CondBr->getCondition(), TrueDest,
TrueArgs, FalseDest, FalseArgs, CondBr->getTrueBBCount(),
CondBr->getFalseBBCount());
CondBr->dropAllReferences();
CondBr->eraseFromParent();
return;
}
default:
llvm_unreachable("only branch and cond_branch have branch arguments");
}
}
template <class SwitchEnumTy, class SwitchEnumCaseTy>
SILBasicBlock *replaceSwitchDest(SwitchEnumTy *S,
SmallVectorImpl<SwitchEnumCaseTy> &Cases,
@@ -421,124 +352,6 @@ bool swift::isCriticalEdge(TermInst *T, unsigned EdgeIdx) {
return true;
}
template<class SwitchInstTy>
SILBasicBlock *getNthEdgeBlock(SwitchInstTy *S, unsigned EdgeIdx) {
if (S->getNumCases() == EdgeIdx)
return S->getDefaultBB();
return S->getCase(EdgeIdx).second;
}
static void getEdgeArgs(TermInst *T, unsigned EdgeIdx, SILBasicBlock *NewEdgeBB,
SmallVectorImpl<SILValue> &Args) {
switch (T->getKind()) {
case SILInstructionKind::BranchInst: {
auto Br = cast<BranchInst>(T);
for (auto V : Br->getArgs())
Args.push_back(V);
return;
}
case SILInstructionKind::CondBranchInst: {
auto CondBr = cast<CondBranchInst>(T);
assert(EdgeIdx < 2);
auto OpdArgs = EdgeIdx ? CondBr->getFalseArgs() : CondBr->getTrueArgs();
for (auto V: OpdArgs)
Args.push_back(V);
return;
}
case SILInstructionKind::SwitchValueInst: {
auto SEI = cast<SwitchValueInst>(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<SwitchEnumInstBase>(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<DynamicMethodBranchInst>(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<CheckedCastBranchInst>(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<CheckedCastAddrBranchInst>(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<CheckedCastValueBranchInst>(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<TryApplyInst>(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");
}
/// Splits the basic block at the iterator with an unconditional branch and
/// updates the dominator tree and loop info.
SILBasicBlock *swift::splitBasicBlockAndBranch(SILBuilder &B,
@@ -574,98 +387,6 @@ SILBasicBlock *swift::splitBasicBlockAndBranch(SILBuilder &B,
return NewBB;
}
SILBasicBlock *swift::splitEdge(TermInst *T, unsigned EdgeIdx,
DominanceInfo *DT, SILLoopInfo *LI) {
auto *SrcBB = T->getParent();
auto *Fn = SrcBB->getParent();
SILBasicBlock *DestBB = T->getSuccessors()[EdgeIdx];
// Create a new basic block in the edge, and insert it after the SrcBB.
auto *EdgeBB = Fn->createBasicBlockAfter(SrcBB);
SmallVector<SILValue, 16> Args;
getEdgeArgs(T, EdgeIdx, EdgeBB, Args);
SILBuilder(EdgeBB).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;
}
/// Split every edge between two basic blocks.
void swift::splitEdgesFromTo(SILBasicBlock *From, SILBasicBlock *To,
DominanceInfo *DT, SILLoopInfo *LI) {

View File

@@ -12,6 +12,7 @@
#define DEBUG_TYPE "sil-loop-utils"
#include "swift/SILOptimizer/Utils/LoopUtils.h"
#include "swift/SIL/BasicBlockUtils.h"
#include "swift/SIL/Dominance.h"
#include "swift/SIL/LoopInfo.h"
#include "swift/SIL/SILArgument.h"

View File

@@ -11,9 +11,9 @@
//===----------------------------------------------------------------------===//
#include "swift/SILOptimizer/Utils/StackNesting.h"
#include "swift/SILOptimizer/Utils/CFG.h"
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/BasicBlockUtils.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILFunction.h"
#include "llvm/Support/Debug.h"
using namespace swift;