@@ -47,43 +47,43 @@ PhaseStatus Compiler::optRedundantBranches()
4747 {
4848 bool madeChangesThisBlock = m_compiler->optRedundantRelop (block);
4949
50- BasicBlock* const bbNext = block->GetFalseTarget ();
51- BasicBlock* const bbJump = block->GetTrueTarget ();
50+ BasicBlock* const bbFalse = block->GetFalseTarget ();
51+ BasicBlock* const bbTrue = block->GetTrueTarget ();
5252
5353 madeChangesThisBlock |= m_compiler->optRedundantBranch (block);
5454
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
5656 // a BBJ_COND, retry; perhaps one of the later optimizations
5757 // we can do has enabled one of the earlier optimizations.
5858 //
59- if (madeChangesThisBlock && block->KindIs (BBJ_COND))
59+ if (madeChangesThisBlock && block->KindIs (BBJ_COND) && (block-> countOfInEdges () > 0 ) )
6060 {
6161 JITDUMP (" Will retry RBO in " FMT_BB " after partial optimization\n " , block->bbNum );
6262 madeChangesThisBlock |= m_compiler->optRedundantBranch (block);
6363 }
6464
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
6666 // further optimizations there.
6767 //
6868 // Note this misses cascading retries, consider reworking the overall
6969 // strategy here to iterate until closure.
7070 //
71- if (madeChangesThisBlock && (bbNext ->countOfInEdges () == 0 ))
71+ if (madeChangesThisBlock && (bbFalse ->countOfInEdges () == 0 ))
7272 {
73- for (BasicBlock* succ : bbNext ->Succs ())
73+ for (BasicBlock* succ : bbFalse ->Succs ())
7474 {
7575 JITDUMP (" Will retry RBO in " FMT_BB " ; pred " FMT_BB " now unreachable\n " , succ->bbNum ,
76- bbNext ->bbNum );
76+ bbFalse ->bbNum );
7777 m_compiler->optRedundantBranch (succ);
7878 }
7979 }
8080
81- if (madeChangesThisBlock && (bbJump ->countOfInEdges () == 0 ))
81+ if (madeChangesThisBlock && (bbTrue ->countOfInEdges () == 0 ))
8282 {
83- for (BasicBlock* succ : bbJump ->Succs ())
83+ for (BasicBlock* succ : bbTrue ->Succs ())
8484 {
8585 JITDUMP (" Will retry RBO in " FMT_BB " ; pred " FMT_BB " now unreachable\n " , succ->bbNum ,
86- bbNext ->bbNum );
86+ bbFalse ->bbNum );
8787 m_compiler->optRedundantBranch (succ);
8888 }
8989 }
@@ -828,21 +828,21 @@ bool Compiler::optRedundantBranch(BasicBlock* const block)
828828 }
829829 else if (trueReaches && !falseReaches && rii.canInferFromTrue )
830830 {
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.
832832 //
833833 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 " ,
835835 domBlock->GetTrueTarget ()->bbNum , domBlock->bbNum , dspTreeID (tree),
836836 relopIsTrue ? " true" : " false" );
837837 relopValue = relopIsTrue ? 1 : 0 ;
838838 break ;
839839 }
840840 else if (falseReaches && !trueReaches && rii.canInferFromFalse )
841841 {
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.
843843 //
844844 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 " ,
846846 domBlock->GetFalseTarget ()->bbNum , domBlock->bbNum , dspTreeID (tree),
847847 relopIsFalse ? " false" : " true" );
848848 relopValue = relopIsFalse ? 0 : 1 ;
@@ -942,7 +942,6 @@ struct JumpThreadInfo
942942 : m_block(block)
943943 , m_trueTarget(block->GetTrueTarget ())
944944 , m_falseTarget(block->GetFalseTarget ())
945- , m_fallThroughPred(nullptr )
946945 , m_ambiguousVNBlock(nullptr )
947946 , m_truePreds(BlockSetOps::MakeEmpty(comp))
948947 , m_ambiguousPreds(BlockSetOps::MakeEmpty(comp))
@@ -961,8 +960,6 @@ struct JumpThreadInfo
961960 BasicBlock* const m_trueTarget;
962961 // Block successor if predicate is false
963962 BasicBlock* const m_falseTarget;
964- // Unique pred that falls through to block, if any
965- BasicBlock* m_fallThroughPred;
966963 // Block that brings in the ambiguous VN
967964 BasicBlock* m_ambiguousVNBlock;
968965 // Pred blocks for which the predicate will be true
@@ -1239,35 +1236,9 @@ bool Compiler::optJumpThreadDom(BasicBlock* const block, BasicBlock* const domBl
12391236 // * It's also possible that the pred is a switch; we will treat switch
12401237 // preds as ambiguous as well.
12411238 //
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.
12711242 //
12721243 BasicBlock* const domTrueSuccessor = domIsSameRelop ? domBlock->GetTrueTarget () : domBlock->GetFalseTarget ();
12731244 BasicBlock* const domFalseSuccessor = domIsSameRelop ? domBlock->GetFalseTarget () : domBlock->GetTrueTarget ();
@@ -1337,15 +1308,6 @@ bool Compiler::optJumpThreadDom(BasicBlock* const block, BasicBlock* const domBl
13371308 jti.m_numFalsePreds ++;
13381309 JITDUMP (FMT_BB " is a false pred\n " , predBlock->bbNum );
13391310 }
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- }
13491311 }
13501312
13511313 // Do the optimization.
@@ -1597,15 +1559,6 @@ bool Compiler::optJumpThreadPhi(BasicBlock* block, GenTree* tree, ValueNum treeN
15971559
15981560 continue ;
15991561 }
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- }
16091562 }
16101563
16111564 // Do the optimization.
@@ -1638,102 +1591,10 @@ bool Compiler::optJumpThreadCore(JumpThreadInfo& jti)
16381591 return false ;
16391592 }
16401593
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-
17121594 // We should be good to go
17131595 //
17141596 JITDUMP (" Optimizing via jump threading\n " );
17151597
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-
17371598 // Now reroute the flow from the predecessors.
17381599 // If this pred is in the set that will reuse block, do nothing.
17391600 // Else revise pred to branch directly to the appropriate successor of block.
@@ -1749,22 +1610,8 @@ bool Compiler::optJumpThreadCore(JumpThreadInfo& jti)
17491610
17501611 const bool isTruePred = BlockSetOps::IsMember (this , jti.m_truePreds , predBlock->bbNum );
17511612
1752- // Do we need to alter flow from this pred?
1613+ // Jump to the appropriate successor.
17531614 //
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-
17681615 if (isTruePred)
17691616 {
17701617 JITDUMP (" Jump flow from pred " FMT_BB " -> " FMT_BB
0 commit comments