Files
swift-mirror/lib/SILOptimizer/Utils/CheckedCastBrJumpThreading.cpp

755 lines
26 KiB
C++

#define DEBUG_TYPE "sil-simplify-cfg"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/InstructionUtils.h"
#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h"
#include "swift/SILOptimizer/Utils/CFG.h"
#include "swift/SILOptimizer/Utils/Local.h"
#include "swift/SILOptimizer/Utils/SILInliner.h"
using namespace swift;
namespace {
/// This is a class implementing a dominator-based jump-threading
/// for checked_cast_br [exact].
class CheckedCastBrJumpThreading {
// The checked_cast_br instruction, which
// we try to jump-thread
CheckedCastBranchInst *CCBI;
// Basic block of the current checked_cast_br instruction.
SILBasicBlock *BB;
// Condition used by the current checked_cast_br instruction.
SILValue Condition;
// Success branch of the current checked_cast_br instruction.
SILBasicBlock *SuccessBB;
// Failure branch of the current checked_cast_br instruction.
SILBasicBlock *FailureBB;
// Current dominating checked_cast_br instruction.
CheckedCastBranchInst *DomCCBI;
// Basic block of the dominating checked_cast_br instruction.
SILBasicBlock *DomBB;
// Condition used by the dominating checked_cast_br instruction.
SILValue DomCondition;
// Success branch of the dominating checked_cast_br instruction.
SILBasicBlock *DomSuccessBB;
// Failure branch of the dominating checked_cast_br instruction.
SILBasicBlock *DomFailureBB;
// Current dominator tree node where we look for a dominating
// checked_cast_br instruction.
llvm::DomTreeNodeBase<SILBasicBlock> *Node;
SILBasicBlock *ArgBB;
// Dominator information to be used.
DominanceInfo *DT;
// Basic block created as a landing BB for all failure predecessors.
SILBasicBlock *TargetFailureBB;
// Basic block created as a landing BB for all success predecessors.
SILBasicBlock *TargetSuccessBB;
// Cloner used to clone the BB to FailureSuccessBB.
Optional<BasicBlockCloner> FailureBBCloner;
// Cloner used to clone the BB to TargetSuccessBB.
Optional<BasicBlockCloner> SuccessBBCloner;
// Predecessors reached only via a path along the
// success branch of the dominating checked_cast_br.
SmallVector<SILBasicBlock *, 8> SuccessPreds;
// Predecessors reached only via a path along the
// failure branch of the dominating checked_cast_br.
SmallVector<SILBasicBlock *, 8> FailurePreds;
// All other predecessors, where the outcome of the
// checked_cast_br along the path is not known.
SmallVector<SILBasicBlock *, 8> UnknownPreds;
// Basic blocks to be added to for reprocessing
// after jump-threading is done.
SmallVectorImpl<SILBasicBlock *> &BlocksForWorklist;
bool areEquivalentConditionsAlongPaths();
bool areEquivalentConditionsAlongSomePaths();
bool handleArgBBIsEntryBlock(SILBasicBlock *ArgBB);
bool checkCloningConstraints();
void modifyCFGForUnknownPreds();
void modifyCFGForFailurePreds();
void modifyCFGForSuccessPreds();
void updateDominatorTree();
void updateSSA();
void addBlockToSimplifyCFGWorklist(SILBasicBlock *BB);
void addBlocksToWorklist();
void classifyPredecessor(
SILBasicBlock *Pred,
SmallVectorImpl<SILBasicBlock *> &SuccessPreds,
SmallVectorImpl<SILBasicBlock *> &FailurePreds,
SmallVectorImpl<SILBasicBlock *> &UnknownPreds,
bool SuccessDominates,
bool FailureDominates);
SILValue isArgValueEquivalentToCondition(SILValue Value,
SILBasicBlock *DomBB,
SILValue DomValue,
DominanceInfo *DT);
public:
CheckedCastBrJumpThreading(DominanceInfo *DT,
SmallVectorImpl<SILBasicBlock *> &BBs)
: DT(DT), BlocksForWorklist(BBs) { }
bool trySimplify(TermInst *Term);
ArrayRef<SILBasicBlock*> getBlocksForWorklist() {
return BlocksForWorklist;
}
};
} // end anonymous namespace
/// Find a nearest common dominator for a given set of basic blocks.
static DominanceInfoNode *findCommonDominator(ArrayRef<SILBasicBlock *> BBs,
DominanceInfo *DT) {
DominanceInfoNode *CommonDom = nullptr;
for (auto *BB : BBs) {
if (!CommonDom) {
CommonDom = DT->getNode(BB);
} else {
CommonDom = DT->getNode(
DT->findNearestCommonDominator(CommonDom->getBlock(), BB));
}
}
return CommonDom;
}
/// Find a nearest common dominator for all predecessors of
/// a given basic block.
static DominanceInfoNode *findCommonDominator(SILBasicBlock *BB,
DominanceInfo *DT) {
SmallVector<SILBasicBlock *, 8> Preds;
for (auto *Pred: BB->getPreds())
Preds.push_back(Pred);
return findCommonDominator(Preds, DT);
}
/// Estimate the cost of inlining a given basic block.
static unsigned basicBlockInlineCost(SILBasicBlock *BB, unsigned Cutoff) {
unsigned Cost = 0;
for (auto &I : *BB) {
auto ICost = instructionInlineCost(I);
Cost += unsigned(ICost);
if (Cost > Cutoff)
return Cost;
}
return Cost;
}
/// We cannot duplicate blocks with AllocStack instructions (they need to be
/// FIFO). Other instructions can be duplicated.
static bool canDuplicateBlock(SILBasicBlock *BB) {
for (auto &I : *BB) {
if (!I.isTriviallyDuplicatable())
return false;
}
return true;
}
void CheckedCastBrJumpThreading::addBlockToSimplifyCFGWorklist(SILBasicBlock *BB) {
BlocksForWorklist.push_back(BB);
}
/// Add affected blocks for re-processing by simplifyCFG
void CheckedCastBrJumpThreading::addBlocksToWorklist() {
if (TargetFailureBB) {
if (!TargetFailureBB->pred_empty())
addBlockToSimplifyCFGWorklist(TargetFailureBB);
}
if (TargetSuccessBB) {
if (!TargetSuccessBB->pred_empty())
addBlockToSimplifyCFGWorklist(TargetSuccessBB);
}
if (!BB->pred_empty())
addBlockToSimplifyCFGWorklist(BB);
}
/// Classify a predecessor of a BB containing checked_cast_br as being
/// reachable via success or failure branches of a dominating checked_cast_br
/// or as unknown if it can be reached via success or failure branches
/// at the same time.
void CheckedCastBrJumpThreading::classifyPredecessor(
SILBasicBlock *Pred,
SmallVectorImpl<SILBasicBlock *> &SuccessPreds,
SmallVectorImpl<SILBasicBlock *> &FailurePreds,
SmallVectorImpl<SILBasicBlock *> &UnknownPreds,
bool SuccessDominates,
bool FailureDominates) {
if (SuccessDominates && FailureDominates) {
UnknownPreds.push_back(Pred);
return;
}
if (SuccessDominates) {
SuccessPreds.push_back(Pred);
return;
}
if (FailureDominates) {
FailurePreds.push_back(Pred);
return;
}
UnknownPreds.push_back(Pred);
}
/// Check if the root value for Value that comes
/// along the path from DomBB is equivalent to the
/// DomCondition.
SILValue CheckedCastBrJumpThreading::isArgValueEquivalentToCondition(
SILValue Value, SILBasicBlock *DomBB, SILValue DomValue,
DominanceInfo *DT) {
SmallPtrSet<ValueBase *, 16> SeenValues;
DomValue = stripClassCasts(DomValue);
while (true) {
Value = stripClassCasts(Value);
if (Value == DomValue)
return Value;
// We know how to propagate through BBArgs only.
auto *V = dyn_cast<SILArgument>(Value);
if (!V)
return SILValue();
// Have we visited this BB already?
if (!SeenValues.insert(Value).second)
return SILValue();
if (SeenValues.size() > 10)
return SILValue();
SmallVector<SILValue, 4> IncomingValues;
if (!V->getIncomingValues(IncomingValues) || IncomingValues.empty())
return SILValue();
ValueBase *Def = nullptr;
for (auto IncomingValue : IncomingValues) {
// Each incoming value should be either from a block
// dominated by DomBB or it should be the value used in
// condition in DomBB
Value = stripClassCasts(IncomingValue);
if (Value == DomValue)
continue;
// Values should be the same
if (!Def)
Def = Value;
if (Def != Value)
return SILValue();
if (!DT->dominates(DomBB, Value->getParentBB()))
return SILValue();
// OK, this value is a potential candidate
}
Value = IncomingValues[0];
}
}
/// Update the SSA form after all changes.
void CheckedCastBrJumpThreading::updateSSA() {
assert(!(SuccessBBCloner.hasValue() && FailureBBCloner.hasValue()) &&
"Both cloners cannot be used at the same time yet");
// Now update the SSA form.
if (!FailurePreds.empty() && FailureBBCloner.hasValue() &&
!SuccessBBCloner.hasValue())
updateSSAAfterCloning(*FailureBBCloner.getPointer(), TargetFailureBB, BB);
if (SuccessBBCloner.hasValue() && !FailureBBCloner.hasValue()) {
updateSSAAfterCloning(*SuccessBBCloner.getPointer(), TargetSuccessBB, BB);
}
}
/// Update the SSA form after all changes.
void CheckedCastBrJumpThreading::updateDominatorTree() {
// Update the dominator tree.
// If BB was IDom of something, then PredCBBI becomes the IDOM
// of this after jump-threading.
auto *BBDomNode = DT->getNode(BB);
auto &Children = BBDomNode->getChildren();
if (Children.size() > 1) {
SmallVector<DominanceInfoNode *, 16> ChildrenCopy;
std::copy(Children.begin(), Children.end(),
std::back_inserter(ChildrenCopy));
for (auto *Child : ChildrenCopy) {
DT->changeImmediateDominator(Child, Node);
}
}
DominanceInfoNode *CommonDom;
// Find a common dominator for all unknown preds.
if (!UnknownPreds.empty()) {
// Find a new IDom for FailureBB
CommonDom = findCommonDominator(FailureBB, DT);
if (CommonDom)
DT->changeImmediateDominator(FailureBB, CommonDom->getBlock());
CommonDom = findCommonDominator(UnknownPreds, DT);
// This common dominator dominates the BB now.
if (CommonDom) {
DT->changeImmediateDominator(BB, CommonDom->getBlock());
}
}
// Find a common dominator for all failure preds.
CommonDom = findCommonDominator(FailurePreds, DT);
// This common dominator dominates the TargetFailureBB now.
if (CommonDom) {
DT->addNewBlock(TargetFailureBB, CommonDom->getBlock());
// Find a new IDom for FailureBB
CommonDom = findCommonDominator(FailureBB, DT);
if (CommonDom)
DT->changeImmediateDominator(FailureBB, CommonDom->getBlock());
}
// Find a common dominator for all success preds.
CommonDom = findCommonDominator(SuccessPreds, DT);
// This common dominator of all success preds dominates the BB now.
if (CommonDom) {
if (TargetSuccessBB) {
DT->addNewBlock(TargetSuccessBB, CommonDom->getBlock());
} else {
DT->changeImmediateDominator(BB, CommonDom->getBlock());
}
CommonDom = findCommonDominator(SuccessBB, DT);
if (CommonDom)
DT->changeImmediateDominator(SuccessBB, CommonDom->getBlock());
}
// End of dominator tree update.
}
void CheckedCastBrJumpThreading::modifyCFGForUnknownPreds() {
if (UnknownPreds.empty())
return;
// Check the FailureBB if it is a BB that contains a class_method
// referring to the same value as a condition. This pattern is typical
// for method chaining code like obj.method1().method2().etc()
SILInstruction *Inst = &*FailureBB->begin();
if (ClassMethodInst *CMI = dyn_cast<ClassMethodInst>(Inst)) {
if (CMI->getOperand() == Condition) {
// Replace checked_cast_br by branch to FailureBB.
SILBuilder(BB).createBranch(CCBI->getLoc(), FailureBB);
CCBI->eraseFromParent();
}
}
}
/// Create a copy of the BB as a landing BB
/// for all FailurePreds.
void CheckedCastBrJumpThreading::modifyCFGForFailurePreds() {
if (FailurePreds.empty())
return;
FailureBBCloner.emplace(BasicBlockCloner(BB));
FailureBBCloner->clone();
TargetFailureBB = FailureBBCloner->getDestBB();
auto *TI = TargetFailureBB->getTerminator();
SILBuilderWithScope Builder(TI);
// This BB copy branches to a FailureBB.
Builder.createBranch(TI->getLoc(), FailureBB);
TI->eraseFromParent();
// Redirect all FailurePreds to the copy of BB.
for (auto *Pred : FailurePreds) {
TermInst *TI = Pred->getTerminator();
// Replace branch to BB by branch to TargetFailureBB.
replaceBranchTarget(TI, BB, TargetFailureBB, /*PreserveArgs=*/true);
Pred = nullptr;
}
}
/// Create a copy of the BB or reuse BB as
/// a landing basic block for all FailurePreds.
void CheckedCastBrJumpThreading::modifyCFGForSuccessPreds() {
if (!UnknownPreds.empty()) {
if (!SuccessPreds.empty()) {
// Create a copy of the BB as a landing BB.
// for all SuccessPreds.
SuccessBBCloner.emplace(BasicBlockCloner(BB));
SuccessBBCloner->clone();
TargetSuccessBB = SuccessBBCloner->getDestBB();
auto *TI = TargetSuccessBB->getTerminator();
SILBuilderWithScope Builder(TI);
SmallVector<SILValue, 8> SuccessBBArgs;
// Take argument value from the dominating BB.
SuccessBBArgs.push_back(DomSuccessBB->getBBArg(0));
// This BB copy branches to SuccessBB.
Builder.createBranch(TI->getLoc(), SuccessBB, SuccessBBArgs);
TI->eraseFromParent();
// Redirect all SuccessPreds to the copy of BB.
for (auto *Pred : SuccessPreds) {
TermInst *TI = Pred->getTerminator();
// Replace branch to BB by branch to TargetSuccessBB.
replaceBranchTarget(TI, BB, TargetSuccessBB, /*PreserveArgs=*/true);
SuccessBBArgs.push_back(DomSuccessBB->getBBArg(0));
Pred = nullptr;
}
}
} else {
// There are no predecessors where it is not clear
// if they are dominated by a success or failure branch
// of DomBB. Therefore, there is no need to clone
// the BB for SuccessPreds. Current BB can be re-used
// instead as their target.
// Add an unconditional jump at the end of the block.
SmallVector<SILValue, 1> SuccessBBArgs;
// Take argument value from the dominating BB
SuccessBBArgs.push_back(DomSuccessBB->getBBArg(0));
SILBuilder(BB).createBranch(CCBI->getLoc(), SuccessBB, SuccessBBArgs);
CCBI->eraseFromParent();
}
}
/// Handle a special case, where ArgBB is the entry block.
bool CheckedCastBrJumpThreading::handleArgBBIsEntryBlock(SILBasicBlock *ArgBB) {
if (ArgBB->getPreds().begin() == ArgBB->getPreds().end()) {
// It must be the entry block
// See if it is reached over Success or Failure path.
bool SuccessDominates = DomSuccessBB == BB;
bool FailureDominates = DomFailureBB == BB;
classifyPredecessor(ArgBB, SuccessPreds, FailurePreds, UnknownPreds,
SuccessDominates, FailureDominates);
return true;
}
return false;
}
// Returns false if cloning required by jump threading cannot
// be performed, because some of the constraints are violated.
bool CheckedCastBrJumpThreading::checkCloningConstraints() {
// Check some cloning related constraints.
// If this argument from a different BB, then jump-threading
// may require too much code duplication.
if (ArgBB && ArgBB != BB)
return false;
// Bail out if current BB cannot be duplicated.
if (!canDuplicateBlock(BB))
return false;
// Check if code-bloat would be too big when this BB
// is jump-threaded.
// TODO: Make InlineCostCutoff parameter configurable?
// Dec 1, 2014:
// We looked at the inline costs of BBs from our benchmark suite
// and found that currently the highest inline cost for the
// whole benchmark suite is 12. In 95% of all cases it is <=3.
const unsigned InlineCostCutoff = 20;
if (basicBlockInlineCost(BB, InlineCostCutoff) >= InlineCostCutoff)
return false;
return true;
}
/// If conditions are not equivalent along all paths, try harder
/// to check if they are actually equivalent along a subset of paths.
/// To do it, try to back-propagate the Condition
/// backwards and see if it is actually equivalent to DomCondition.
/// along some of the paths.
bool CheckedCastBrJumpThreading::areEquivalentConditionsAlongSomePaths() {
auto *Arg = dyn_cast<SILArgument>(Condition);
if (!Arg)
return false;
ArgBB = Arg->getParent();
if (!DT->dominates(DomBB, ArgBB))
return false;
// Incoming values for the BBArg.
SmallVector<SILValue, 4> IncomingValues;
if (ArgBB != ArgBB->getParent()->begin() &&
(!Arg->getIncomingValues(IncomingValues) || IncomingValues.empty()))
return false;
// Check for each predecessor, if the incoming value coming from it
// is equivalent to the DomCondition. If this is the case, it is
// possible to try jump-threading along this path.
if (!handleArgBBIsEntryBlock(ArgBB)) {
// ArgBB is not the entry block and has predecessors.
unsigned idx = 0;
for (auto *PredBB : ArgBB->getPreds()) {
auto IncomingValue = IncomingValues[idx];
SILValue ReachingValue = isArgValueEquivalentToCondition(
IncomingValue, DomBB, DomCondition, DT);
if (ReachingValue == SILValue()) {
UnknownPreds.push_back(PredBB);
idx++;
continue;
}
// Condition is the same if BB is reached over a pass through Pred.
DEBUG(llvm::dbgs() << "Condition is the same if reached over ");
DEBUG(PredBB->print(llvm::dbgs()));
// See if it is reached over Success or Failure path.
bool SuccessDominates = DT->dominates(DomSuccessBB, PredBB) ||
DT->dominates(DomSuccessBB, BB) ||
DomSuccessBB == BB;
bool FailureDominates = DT->dominates(DomFailureBB, PredBB) ||
DT->dominates(DomFailureBB, BB) ||
DomFailureBB == BB;
classifyPredecessor(
PredBB, SuccessPreds, FailurePreds, UnknownPreds,
SuccessDominates, FailureDominates);
idx++;
}
} else {
// ArgBB is the entry block. Check that conditions are the equivalent in this
// case as well.
if (!isArgValueEquivalentToCondition(Condition, DomBB, DomCondition, DT))
return false;
}
// At this point we know for each predecessor of ArgBB if its reached
// over the success, failure or unknown path from DomBB.
// Now we can generate a new BB for preds reaching BB over the success
// path and a new BB for preds reaching BB over the failure path.
// Then we redirect those preds to those new basic blocks.
return true;
}
/// Check if conditions of CCBI and DomCCBI are equivalent along
/// all or at least some paths.
bool CheckedCastBrJumpThreading::areEquivalentConditionsAlongPaths() {
// Are conditions equivalent along all paths?
if (DomCondition == Condition) {
// Conditions are exactly the same, without any restrictions.
// They are equivalent along all paths.
// Figure out for each predecessor which branch of
// the dominating checked_cast_br is used to reach it.
for (auto *PredBB : BB->getPreds()) {
// All predecessors should either unconditionally branch
// to the current BB or be another checked_cast_br instruction.
if (!dyn_cast<CheckedCastBranchInst>(PredBB->getTerminator()) &&
!dyn_cast<BranchInst>(PredBB->getTerminator()))
return false;
bool SuccessDominates =
DT->dominates(DomSuccessBB, PredBB) || DomSuccessBB == BB;
bool FailureDominates =
DT->dominates(DomFailureBB, PredBB) || DomFailureBB == BB;
classifyPredecessor(PredBB, SuccessPreds, FailurePreds, UnknownPreds,
SuccessDominates, FailureDominates);
}
return true;
}
// Check if conditions are equivalent along a subset of reaching paths.
return areEquivalentConditionsAlongSomePaths();
}
/// Try performing a dominator-based jump-threading for
/// checked_cast_br instructions.
bool CheckedCastBrJumpThreading::trySimplify(TermInst *Term) {
CCBI = cast<CheckedCastBranchInst>(Term);
if (!CCBI)
return false;
// Init information about the checked_cast_br we try to
// jump-thread.
BB = Term->getParent();
Condition = stripClassCasts(Term->getOperand(0));
SuccessBB = CCBI->getSuccessBB();
FailureBB = CCBI->getFailureBB();
// Find a dominating checked_cast_br, which performs the same check.
for (Node = DT->getNode(BB)->getIDom(); Node; Node = Node->getIDom()) {
// Get current dominating block.
DomBB = Node->getBlock();
auto *DomTerm = DomBB->getTerminator();
if (!DomTerm->getNumOperands())
continue;
// Check that it is a dominating checked_cast_br.
DomCCBI = dyn_cast<CheckedCastBranchInst>(DomTerm);
if (!DomCCBI)
continue;
// We need to verify that the result type is the same in the
// dominating checked_cast_br, but only for non-exact casts.
// For exact casts, we are interested only in the
// fact that the source operand is the same for
// both instructions.
if (!CCBI->isExact() && !DomCCBI->isExact()) {
if (DomCCBI->getCastType() != CCBI->getCastType())
continue;
}
// Conservatively check that both checked_cast_br instructions
// are either exact or non-exact. This is very conservative,
// but safe.
//
// TODO:
// If the dominating checked_cast_br is non-exact, then
// it is in general not safe to assume that current exact cast
// would have the same outcome. But if the dominating non-exact
// checked_cast_br fails, then the current exact cast would
// always fail as well.
//
// If the dominating checked_cast_br is exact then then
// it is in general not safe to assume that the current non-exact
// cast would have the same outcome. But if the dominating exact
// checked_cast_br succeeds, then the current non-exact cast
// would always succeed as well.
//
// TODO: In some specific cases, it is possible to prove that
// success or failure of the dominating cast is equivalent to
// the success or failure of the current cast, even if one
// of them is exact and the other not. This is the case
// e.g. if the class has no subclasses.
if (DomCCBI->isExact() != CCBI->isExact())
continue;
// Initialize state variables for the current round of checks
// based on the found dominating checked_cast_br.
DomSuccessBB = DomCCBI->getSuccessBB();
DomFailureBB = DomCCBI->getFailureBB();
DomCondition = stripClassCasts(DomTerm->getOperand(0));
// Init state variables for paths analysis
SuccessPreds.clear();
FailurePreds.clear();
UnknownPreds.clear();
ArgBB = nullptr;
// Init state variables for jump-threading transformation.
TargetFailureBB = nullptr;
TargetSuccessBB = nullptr;
// Are conditions of CCBI and DomCCBI equivalent along (some) paths?
// If this is the case, classify all incoming paths into SuccessPreds,
// FailurePreds or UnknownPreds depending on how they reach CCBI.
if (!areEquivalentConditionsAlongPaths())
continue;
// Check if any jump-threading is required and possible.
if (SuccessPreds.empty() && FailurePreds.empty())
return false;
// If this check is reachable via success, failure and unknown
// at the same time, then we don't know the outcome of the
// dominating check. No jump-threading is possible in this case.
if (!SuccessPreds.empty() && !FailurePreds.empty() &&
!UnknownPreds.empty()) {
return false;
}
unsigned TotalPreds =
SuccessPreds.size() + FailurePreds.size() + UnknownPreds.size();
// We only need to clone the BB if not all of its
// predecessors are in the same group.
if (TotalPreds != SuccessPreds.size() &&
TotalPreds != UnknownPreds.size()) {
// Check some cloning related constraints.
if (!checkCloningConstraints())
return false;
}
bool InvertSuccess = false;
if (DomCCBI->isExact() && CCBI->isExact() &&
DomCCBI->getCastType() != CCBI->getCastType()) {
if (TotalPreds == SuccessPreds.size()) {
// The dominating exact cast was successful, but it casted to a
// different type. Therefore, the current cast fails for sure.
// Since we are going to change the BB,
// add its successors and predecessors
// for re-processing.
InvertSuccess = true;
} else {
// Otherwise, we don't know if the current cast will succeed or
// fail.
return false;
}
}
// If we have predecessors, where it is not known if they are reached over
// success or failure path, we cannot eliminate a checked_cast_br.
// We have to generate new dedicated BBs as landing BBs for all
// FailurePreds and all SuccessPreds.
// Since we are going to change the BB,
// add its successors and predecessors
// for re-processing.
for (auto *B : BB->getPreds()) {
addBlockToSimplifyCFGWorklist(B);
}
for (auto *B : BB->getSuccessorBlocks()) {
addBlockToSimplifyCFGWorklist(B);
}
// Create a copy of the BB as a landing BB
// for all FailurePreds.
modifyCFGForFailurePreds();
if (InvertSuccess) {
SILBuilder(BB).createBranch(CCBI->getLoc(), FailureBB);
CCBI->eraseFromParent();
SuccessPreds.clear();
} else {
// Create a copy of the BB or reuse BB as
// a landing basic block for all SuccessPreds.
modifyCFGForSuccessPreds();
}
// Handle unknown preds.
modifyCFGForUnknownPreds();
// Update the dominator tree after all changes.
updateDominatorTree();
// Update the SSA form after all changes.
updateSSA();
// Since a few BBs were changed now, add them for re-processing.
addBlocksToWorklist();
return true;
}
// Jump-threading was not possible.
return false;
}
namespace swift {
bool tryCheckedCastBrJumpThreading(TermInst *Term, DominanceInfo *DT,
SmallVectorImpl<SILBasicBlock *> &BBs) {
CheckedCastBrJumpThreading CCBJumpThreading(DT, BBs);
return CCBJumpThreading.trySimplify(Term);
}
} // end namespace swift