@@ -47,43 +47,43 @@ PhaseStatus Compiler::optRedundantBranches()
47
47
{
48
48
bool madeChangesThisBlock = m_compiler->optRedundantRelop (block);
49
49
50
- BasicBlock* const bbNext = block->GetFalseTarget ();
51
- BasicBlock* const bbJump = block->GetTrueTarget ();
50
+ BasicBlock* const bbFalse = block->GetFalseTarget ();
51
+ BasicBlock* const bbTrue = block->GetTrueTarget ();
52
52
53
53
madeChangesThisBlock |= m_compiler->optRedundantBranch (block);
54
54
55
- // If we modified some flow out of block but it's still
55
+ // If we modified some flow out of block but it's still referenced and
56
56
// a BBJ_COND, retry; perhaps one of the later optimizations
57
57
// we can do has enabled one of the earlier optimizations.
58
58
//
59
- if (madeChangesThisBlock && block->KindIs (BBJ_COND))
59
+ if (madeChangesThisBlock && block->KindIs (BBJ_COND) && (block-> countOfInEdges () > 0 ) )
60
60
{
61
61
JITDUMP (" Will retry RBO in " FMT_BB " after partial optimization\n " , block->bbNum );
62
62
madeChangesThisBlock |= m_compiler->optRedundantBranch (block);
63
63
}
64
64
65
- // It's possible that the changed flow into bbNext or bbJump may unblock
65
+ // It's possible that the changed flow into bbFalse or bbTrue may unblock
66
66
// further optimizations there.
67
67
//
68
68
// Note this misses cascading retries, consider reworking the overall
69
69
// strategy here to iterate until closure.
70
70
//
71
- if (madeChangesThisBlock && (bbNext ->countOfInEdges () == 0 ))
71
+ if (madeChangesThisBlock && (bbFalse ->countOfInEdges () == 0 ))
72
72
{
73
- for (BasicBlock* succ : bbNext ->Succs ())
73
+ for (BasicBlock* succ : bbFalse ->Succs ())
74
74
{
75
75
JITDUMP (" Will retry RBO in " FMT_BB " ; pred " FMT_BB " now unreachable\n " , succ->bbNum ,
76
- bbNext ->bbNum );
76
+ bbFalse ->bbNum );
77
77
m_compiler->optRedundantBranch (succ);
78
78
}
79
79
}
80
80
81
- if (madeChangesThisBlock && (bbJump ->countOfInEdges () == 0 ))
81
+ if (madeChangesThisBlock && (bbTrue ->countOfInEdges () == 0 ))
82
82
{
83
- for (BasicBlock* succ : bbJump ->Succs ())
83
+ for (BasicBlock* succ : bbTrue ->Succs ())
84
84
{
85
85
JITDUMP (" Will retry RBO in " FMT_BB " ; pred " FMT_BB " now unreachable\n " , succ->bbNum ,
86
- bbNext ->bbNum );
86
+ bbFalse ->bbNum );
87
87
m_compiler->optRedundantBranch (succ);
88
88
}
89
89
}
@@ -828,21 +828,21 @@ bool Compiler::optRedundantBranch(BasicBlock* const block)
828
828
}
829
829
else if (trueReaches && !falseReaches && rii.canInferFromTrue )
830
830
{
831
- // Taken jump in dominator reaches, fall through doesn't; relop must be true/false.
831
+ // True path in dominator reaches, false path doesn't; relop must be true/false.
832
832
//
833
833
const bool relopIsTrue = rii.reverseSense ^ (domIsSameRelop | domIsInferredRelop);
834
- JITDUMP (" Jump successor " FMT_BB " of " FMT_BB " reaches, relop [%06u] must be %s\n " ,
834
+ JITDUMP (" True successor " FMT_BB " of " FMT_BB " reaches, relop [%06u] must be %s\n " ,
835
835
domBlock->GetTrueTarget ()->bbNum , domBlock->bbNum , dspTreeID (tree),
836
836
relopIsTrue ? " true" : " false" );
837
837
relopValue = relopIsTrue ? 1 : 0 ;
838
838
break ;
839
839
}
840
840
else if (falseReaches && !trueReaches && rii.canInferFromFalse )
841
841
{
842
- // Fall through from dominator reaches, taken jump doesn't; relop must be false/true.
842
+ // False path from dominator reaches, true path doesn't; relop must be false/true.
843
843
//
844
844
const bool relopIsFalse = rii.reverseSense ^ (domIsSameRelop | domIsInferredRelop);
845
- JITDUMP (" Fall through successor " FMT_BB " of " FMT_BB " reaches, relop [%06u] must be %s\n " ,
845
+ JITDUMP (" False successor " FMT_BB " of " FMT_BB " reaches, relop [%06u] must be %s\n " ,
846
846
domBlock->GetFalseTarget ()->bbNum , domBlock->bbNum , dspTreeID (tree),
847
847
relopIsFalse ? " false" : " true" );
848
848
relopValue = relopIsFalse ? 0 : 1 ;
@@ -942,7 +942,6 @@ struct JumpThreadInfo
942
942
: m_block(block)
943
943
, m_trueTarget(block->GetTrueTarget ())
944
944
, m_falseTarget(block->GetFalseTarget ())
945
- , m_fallThroughPred(nullptr )
946
945
, m_ambiguousVNBlock(nullptr )
947
946
, m_truePreds(BlockSetOps::MakeEmpty(comp))
948
947
, m_ambiguousPreds(BlockSetOps::MakeEmpty(comp))
@@ -961,8 +960,6 @@ struct JumpThreadInfo
961
960
BasicBlock* const m_trueTarget;
962
961
// Block successor if predicate is false
963
962
BasicBlock* const m_falseTarget;
964
- // Unique pred that falls through to block, if any
965
- BasicBlock* m_fallThroughPred;
966
963
// Block that brings in the ambiguous VN
967
964
BasicBlock* m_ambiguousVNBlock;
968
965
// Pred blocks for which the predicate will be true
@@ -1239,35 +1236,9 @@ bool Compiler::optJumpThreadDom(BasicBlock* const block, BasicBlock* const domBl
1239
1236
// * It's also possible that the pred is a switch; we will treat switch
1240
1237
// preds as ambiguous as well.
1241
1238
//
1242
- // * We note if there is an un-ambiguous pred that falls through to block.
1243
- // This is the "fall through pred", and the (true/false) pred set it belongs to
1244
- // is the "fall through set".
1245
- //
1246
- // Now for some case analysis.
1247
- //
1248
- // (1) If we have both an ambiguous pred and a fall through pred, we treat
1249
- // the fall through pred as an ambiguous pred (we can't reroute its flow to
1250
- // avoid block, and we need to keep block intact), and jump thread the other
1251
- // preds per (2) below.
1252
- //
1253
- // (2) If we have an ambiguous pred and no fall through, we reroute the true and
1254
- // false preds to branch to the true and false successors, respectively.
1255
- //
1256
- // (3) If we don't have an ambiguous pred and don't have a fall through pred,
1257
- // we choose one of the pred sets to be treated as if it was the fall through set.
1258
- // For now the choice is arbitrary, so we chose the true preds, and proceed
1259
- // per (4) below.
1260
- //
1261
- // (4) If we don't have an ambiguous pred, and we have a fall through, we leave
1262
- // all preds in the fall through set alone -- they continue branching to block.
1263
- // We modify block to branch to the appropriate successor for the fall through set.
1264
- // Note block will be empty other than phis and the branch, so this is ok.
1265
- // The preds in the other set target the other successor.
1266
- //
1267
- // The goal of the above is to maximize the number of cases where we jump thread,
1268
- // and to maximize the number of jump threads that reuse the original block. This
1269
- // latter should prove useful in subsequent work, where we aim to enable jump
1270
- // threading in cases where block has side effects.
1239
+ // If there are ambiguous preds they will continue to flow into the
1240
+ // unaltered block, while true and false preds will flow to the appropriate
1241
+ // successors directly.
1271
1242
//
1272
1243
BasicBlock* const domTrueSuccessor = domIsSameRelop ? domBlock->GetTrueTarget () : domBlock->GetFalseTarget ();
1273
1244
BasicBlock* const domFalseSuccessor = domIsSameRelop ? domBlock->GetFalseTarget () : domBlock->GetTrueTarget ();
@@ -1337,15 +1308,6 @@ bool Compiler::optJumpThreadDom(BasicBlock* const block, BasicBlock* const domBl
1337
1308
jti.m_numFalsePreds ++;
1338
1309
JITDUMP (FMT_BB " is a false pred\n " , predBlock->bbNum );
1339
1310
}
1340
-
1341
- // Note if the true or false pred is the fall through pred.
1342
- //
1343
- if (predBlock->NextIs (block))
1344
- {
1345
- JITDUMP (FMT_BB " is the fall-through pred\n " , predBlock->bbNum );
1346
- assert (jti.m_fallThroughPred == nullptr );
1347
- jti.m_fallThroughPred = predBlock;
1348
- }
1349
1311
}
1350
1312
1351
1313
// Do the optimization.
@@ -1597,15 +1559,6 @@ bool Compiler::optJumpThreadPhi(BasicBlock* block, GenTree* tree, ValueNum treeN
1597
1559
1598
1560
continue ;
1599
1561
}
1600
-
1601
- // Note if the true or false pred is the fall through pred.
1602
- //
1603
- if (predBlock->NextIs (block))
1604
- {
1605
- JITDUMP (FMT_BB " is the fall-through pred\n " , predBlock->bbNum );
1606
- assert (jti.m_fallThroughPred == nullptr );
1607
- jti.m_fallThroughPred = predBlock;
1608
- }
1609
1562
}
1610
1563
1611
1564
// Do the optimization.
@@ -1638,102 +1591,10 @@ bool Compiler::optJumpThreadCore(JumpThreadInfo& jti)
1638
1591
return false ;
1639
1592
}
1640
1593
1641
- if ((jti.m_numAmbiguousPreds > 0 ) && (jti.m_fallThroughPred != nullptr ))
1642
- {
1643
- // TODO: Simplify jti.m_fallThroughPred logic, now that implicit fallthrough is disallowed.
1644
- const bool fallThroughIsTruePred = BlockSetOps::IsMember (this , jti.m_truePreds , jti.m_fallThroughPred ->bbNum );
1645
- const bool predJumpsToNext = jti.m_fallThroughPred ->KindIs (BBJ_ALWAYS) && jti.m_fallThroughPred ->JumpsToNext ();
1646
-
1647
- if (predJumpsToNext && ((fallThroughIsTruePred && (jti.m_numFalsePreds == 0 )) ||
1648
- (!fallThroughIsTruePred && (jti.m_numTruePreds == 0 ))))
1649
- {
1650
- JITDUMP (FMT_BB " has ambiguous preds and a (%s) fall through pred and no (%s) preds.\n "
1651
- " Fall through pred " FMT_BB " is BBJ_ALWAYS\n " ,
1652
- jti.m_block ->bbNum , fallThroughIsTruePred ? " true" : " false" ,
1653
- fallThroughIsTruePred ? " false" : " true" , jti.m_fallThroughPred ->bbNum );
1654
-
1655
- assert (jti.m_fallThroughPred ->TargetIs (jti.m_block ));
1656
- }
1657
- else
1658
- {
1659
- // Treat the fall through pred as an ambiguous pred.
1660
- JITDUMP (FMT_BB " has both ambiguous preds and a fall through pred\n " , jti.m_block ->bbNum );
1661
- JITDUMP (" Treating fall through pred " FMT_BB " as an ambiguous pred\n " , jti.m_fallThroughPred ->bbNum );
1662
-
1663
- if (fallThroughIsTruePred)
1664
- {
1665
- BlockSetOps::RemoveElemD (this , jti.m_truePreds , jti.m_fallThroughPred ->bbNum );
1666
- assert (jti.m_numTruePreds > 0 );
1667
- jti.m_numTruePreds --;
1668
- }
1669
- else
1670
- {
1671
- assert (jti.m_numFalsePreds > 0 );
1672
- jti.m_numFalsePreds --;
1673
- }
1674
-
1675
- assert (!(BlockSetOps::IsMember (this , jti.m_ambiguousPreds , jti.m_fallThroughPred ->bbNum )));
1676
- BlockSetOps::AddElemD (this , jti.m_ambiguousPreds , jti.m_fallThroughPred ->bbNum );
1677
- jti.m_numAmbiguousPreds ++;
1678
- }
1679
-
1680
- jti.m_fallThroughPred = nullptr ;
1681
- }
1682
-
1683
- // There still should be at least one pred that can bypass block.
1684
- //
1685
- if ((jti.m_numTruePreds == 0 ) && (jti.m_numFalsePreds == 0 ))
1686
- {
1687
- // This is possible, but also should be rare.
1688
- //
1689
- JITDUMP (FMT_BB " now only has ambiguous preds, not jump threading\n " , jti.m_block ->bbNum );
1690
- return false ;
1691
- }
1692
-
1693
- // Determine if either set of preds will route via block.
1694
- //
1695
- bool truePredsWillReuseBlock = false ;
1696
- bool falsePredsWillReuseBlock = false ;
1697
-
1698
- if (jti.m_fallThroughPred != nullptr )
1699
- {
1700
- assert (jti.m_numAmbiguousPreds == 0 );
1701
- truePredsWillReuseBlock = BlockSetOps::IsMember (this , jti.m_truePreds , jti.m_fallThroughPred ->bbNum );
1702
- falsePredsWillReuseBlock = !truePredsWillReuseBlock;
1703
- }
1704
- else if (jti.m_numAmbiguousPreds == 0 )
1705
- {
1706
- truePredsWillReuseBlock = true ;
1707
- falsePredsWillReuseBlock = !truePredsWillReuseBlock;
1708
- }
1709
-
1710
- assert (!(truePredsWillReuseBlock && falsePredsWillReuseBlock));
1711
-
1712
1594
// We should be good to go
1713
1595
//
1714
1596
JITDUMP (" Optimizing via jump threading\n " );
1715
1597
1716
- // Fix block, if we're reusing it.
1717
- //
1718
- if (truePredsWillReuseBlock)
1719
- {
1720
- Statement* const lastStmt = jti.m_block ->lastStmt ();
1721
- fgRemoveStmt (jti.m_block , lastStmt);
1722
- JITDUMP (" repurposing " FMT_BB " to always jump to " FMT_BB " \n " , jti.m_block ->bbNum , jti.m_trueTarget ->bbNum );
1723
- fgRemoveRefPred (jti.m_falseTarget , jti.m_block );
1724
- jti.m_block ->SetKind (BBJ_ALWAYS);
1725
- }
1726
- else if (falsePredsWillReuseBlock)
1727
- {
1728
- Statement* const lastStmt = jti.m_block ->lastStmt ();
1729
- fgRemoveStmt (jti.m_block , lastStmt);
1730
- JITDUMP (" repurposing " FMT_BB " to always jump to " FMT_BB " \n " , jti.m_block ->bbNum ,
1731
- jti.m_falseTarget ->bbNum );
1732
- fgRemoveRefPred (jti.m_trueTarget , jti.m_block );
1733
- jti.m_block ->SetKindAndTarget (BBJ_ALWAYS, jti.m_falseTarget );
1734
- jti.m_block ->SetFlags (BBF_NONE_QUIRK);
1735
- }
1736
-
1737
1598
// Now reroute the flow from the predecessors.
1738
1599
// If this pred is in the set that will reuse block, do nothing.
1739
1600
// Else revise pred to branch directly to the appropriate successor of block.
@@ -1749,22 +1610,8 @@ bool Compiler::optJumpThreadCore(JumpThreadInfo& jti)
1749
1610
1750
1611
const bool isTruePred = BlockSetOps::IsMember (this , jti.m_truePreds , predBlock->bbNum );
1751
1612
1752
- // Do we need to alter flow from this pred?
1613
+ // Jump to the appropriate successor.
1753
1614
//
1754
- if ((isTruePred && truePredsWillReuseBlock) || (!isTruePred && falsePredsWillReuseBlock))
1755
- {
1756
- // No, we can leave as is.
1757
- //
1758
- JITDUMP (" %s pred " FMT_BB " will continue to target " FMT_BB " \n " , isTruePred ? " true" : " false" ,
1759
- predBlock->bbNum , jti.m_block ->bbNum );
1760
- continue ;
1761
- }
1762
-
1763
- // Yes, we need to jump to the appropriate successor.
1764
- // Note we should not be altering flow for the fall-through pred.
1765
- //
1766
- assert (predBlock != jti.m_fallThroughPred );
1767
-
1768
1615
if (isTruePred)
1769
1616
{
1770
1617
JITDUMP (" Jump flow from pred " FMT_BB " -> " FMT_BB
0 commit comments