mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
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:
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user