@@ -675,6 +675,52 @@ bool Compiler::optRedundantBranch(BasicBlock* const block)
675675 return true ;
676676}
677677
678+ // ------------------------------------------------------------------------
679+ // JumpThreadInfo
680+ //
681+ // Describes the relationship between a block-ending predicate value and the
682+ // block's predecessors.
683+ //
684+ struct JumpThreadInfo
685+ {
686+ JumpThreadInfo (Compiler* comp, BasicBlock* block)
687+ : m_block(block)
688+ , m_trueTarget(block->bbJumpDest)
689+ , m_falseTarget(block->bbNext)
690+ , m_fallThroughPred(nullptr )
691+ , m_truePreds(BlockSetOps::MakeEmpty(comp))
692+ , m_ambiguousPreds(BlockSetOps::MakeEmpty(comp))
693+ , m_numPreds(0 )
694+ , m_numAmbiguousPreds(0 )
695+ , m_numTruePreds(0 )
696+ , m_numFalsePreds(0 )
697+ {
698+ }
699+
700+ // Block we're trying to optimize
701+ BasicBlock* const m_block;
702+ // Block successor if predicate is true
703+ BasicBlock* const m_trueTarget;
704+ // Block successor if predicate is false
705+ BasicBlock* const m_falseTarget;
706+ // Unique pred that falls through to block, if any
707+ BasicBlock* m_fallThroughPred = nullptr ;
708+ // Pred blocks for which the predicate will be true
709+ BlockSet m_truePreds;
710+ // Pred blocks that can't be threaded or for which the predicate
711+ // value can't be determined
712+ BlockSet m_ambiguousPreds;
713+ // Total number of predecessors
714+ int m_numPreds;
715+ // Number of predecessors that can't be threaded or for which the predicate
716+ // value can't be determined
717+ int m_numAmbiguousPreds;
718+ // Number of predecessors for which predicate is true
719+ int m_numTruePreds;
720+ // Number of predecessors for which predicate is false
721+ int m_numFalsePreds;
722+ };
723+
678724// ------------------------------------------------------------------------
679725// optJumpThread: try and bypass the current block by rerouting
680726// flow from predecessors directly to successors.
@@ -900,40 +946,32 @@ bool Compiler::optJumpThread(BasicBlock* const block, BasicBlock* const domBlock
900946 // latter should prove useful in subsequent work, where we aim to enable jump
901947 // threading in cases where block has side effects.
902948 //
903- int numPreds = 0 ;
904- int numAmbiguousPreds = 0 ;
905- int numTruePreds = 0 ;
906- int numFalsePreds = 0 ;
907- BasicBlock* fallThroughPred = nullptr ;
908- BasicBlock* const trueSuccessor = domIsSameRelop ? domBlock->bbJumpDest : domBlock->bbNext ;
909- BasicBlock* const falseSuccessor = domIsSameRelop ? domBlock->bbNext : domBlock->bbJumpDest ;
910- BasicBlock* const trueTarget = block->bbJumpDest ;
911- BasicBlock* const falseTarget = block->bbNext ;
912- BlockSet truePreds = BlockSetOps::MakeEmpty (this );
913- BlockSet ambiguousPreds = BlockSetOps::MakeEmpty (this );
949+ BasicBlock* const domTrueSuccessor = domIsSameRelop ? domBlock->bbJumpDest : domBlock->bbNext ;
950+ BasicBlock* const domFalseSuccessor = domIsSameRelop ? domBlock->bbNext : domBlock->bbJumpDest ;
951+ JumpThreadInfo jti (this , block);
914952
915953 for (BasicBlock* const predBlock : block->PredBlocks ())
916954 {
917- numPreds ++;
955+ jti. m_numPreds ++;
918956
919957 // Treat switch preds as ambiguous for now.
920958 //
921959 if (predBlock->bbJumpKind == BBJ_SWITCH)
922960 {
923961 JITDUMP (FMT_BB " is a switch pred\n " , predBlock->bbNum );
924- BlockSetOps::AddElemD (this , ambiguousPreds , predBlock->bbNum );
925- numAmbiguousPreds ++;
962+ BlockSetOps::AddElemD (this , jti. m_ambiguousPreds , predBlock->bbNum );
963+ jti. m_numAmbiguousPreds ++;
926964 continue ;
927965 }
928966
929- const bool isTruePred =
930- ((predBlock == domBlock) && (trueSuccessor == block)) || optReachable (trueSuccessor , predBlock, domBlock);
931- const bool isFalsePred =
932- ((predBlock == domBlock) && (falseSuccessor == block)) || optReachable (falseSuccessor , predBlock, domBlock);
967+ const bool isTruePred = ((predBlock == domBlock) && (domTrueSuccessor == block)) ||
968+ optReachable (domTrueSuccessor , predBlock, domBlock);
969+ const bool isFalsePred = ((predBlock == domBlock) && (domFalseSuccessor == block)) ||
970+ optReachable (domFalseSuccessor , predBlock, domBlock);
933971
934972 if (isTruePred == isFalsePred)
935973 {
936- // Either both reach, or neither reaches.
974+ // Either both dom successors reach, or neither reaches.
937975 //
938976 // We should rarely see (false,false) given that optReachable is returning
939977 // up to date results, but as we optimize we create unreachable blocks,
@@ -942,38 +980,38 @@ bool Compiler::optJumpThread(BasicBlock* const block, BasicBlock* const domBlock
942980 // lead to more complications, and it isn't that common. So we tolerate it.
943981 //
944982 JITDUMP (FMT_BB " is an ambiguous pred\n " , predBlock->bbNum );
945- BlockSetOps::AddElemD (this , ambiguousPreds , predBlock->bbNum );
946- numAmbiguousPreds ++;
983+ BlockSetOps::AddElemD (this , jti. m_ambiguousPreds , predBlock->bbNum );
984+ jti. m_numAmbiguousPreds ++;
947985 continue ;
948986 }
949987
950988 if (isTruePred)
951989 {
952- if (!BasicBlock::sameEHRegion (predBlock, trueTarget ))
990+ if (!BasicBlock::sameEHRegion (predBlock, jti. m_trueTarget ))
953991 {
954992 JITDUMP (FMT_BB " is an eh constrained pred\n " , predBlock->bbNum );
955- numAmbiguousPreds ++;
956- BlockSetOps::AddElemD (this , ambiguousPreds , predBlock->bbNum );
993+ jti. m_numAmbiguousPreds ++;
994+ BlockSetOps::AddElemD (this , jti. m_ambiguousPreds , predBlock->bbNum );
957995 continue ;
958996 }
959997
960- numTruePreds ++;
961- BlockSetOps::AddElemD (this , truePreds , predBlock->bbNum );
998+ jti. m_numTruePreds ++;
999+ BlockSetOps::AddElemD (this , jti. m_truePreds , predBlock->bbNum );
9621000 JITDUMP (FMT_BB " is a true pred\n " , predBlock->bbNum );
9631001 }
9641002 else
9651003 {
9661004 assert (isFalsePred);
9671005
968- if (!BasicBlock::sameEHRegion (predBlock, falseTarget ))
1006+ if (!BasicBlock::sameEHRegion (predBlock, jti. m_falseTarget ))
9691007 {
9701008 JITDUMP (FMT_BB " is an eh constrained pred\n " , predBlock->bbNum );
971- BlockSetOps::AddElemD (this , ambiguousPreds , predBlock->bbNum );
972- numAmbiguousPreds ++;
1009+ BlockSetOps::AddElemD (this , jti. m_ambiguousPreds , predBlock->bbNum );
1010+ jti. m_numAmbiguousPreds ++;
9731011 continue ;
9741012 }
9751013
976- numFalsePreds ++;
1014+ jti. m_numFalsePreds ++;
9771015 JITDUMP (FMT_BB " is a false pred\n " , predBlock->bbNum );
9781016 }
9791017
@@ -982,59 +1020,87 @@ bool Compiler::optJumpThread(BasicBlock* const block, BasicBlock* const domBlock
9821020 if (predBlock->bbNext == block)
9831021 {
9841022 JITDUMP (FMT_BB " is the fall-through pred\n " , predBlock->bbNum );
985- assert (fallThroughPred == nullptr );
986- fallThroughPred = predBlock;
1023+ assert (jti. m_fallThroughPred == nullptr );
1024+ jti. m_fallThroughPred = predBlock;
9871025 }
9881026 }
9891027
1028+ // Do the optimization.
1029+ //
1030+ return optJumpThreadCore (jti);
1031+ }
1032+
1033+ // ------------------------------------------------------------------------
1034+ // optJumpThreadCore: restructure block flow based on jump thread information
1035+ //
1036+ // Arguments:
1037+ // jit - information on how to jump thread this block
1038+ //
1039+ // Returns:
1040+ // True if the branch was optimized.
1041+ //
1042+ bool Compiler::optJumpThreadCore (JumpThreadInfo& jti)
1043+ {
9901044 // All preds should have been classified.
9911045 //
992- assert (numPreds == numTruePreds + numFalsePreds + numAmbiguousPreds );
1046+ assert (jti. m_numPreds == jti. m_numTruePreds + jti. m_numFalsePreds + jti. m_numAmbiguousPreds );
9931047
994- if ((numTruePreds == 0 ) && (numFalsePreds == 0 ))
1048+ // There should be at least one pred that can bypass block.
1049+ //
1050+ if ((jti.m_numTruePreds == 0 ) && (jti.m_numFalsePreds == 0 ))
9951051 {
9961052 // This is possible, but should be rare.
9971053 //
998- JITDUMP (FMT_BB " only has ambiguous preds, not optimizing \n " , block ->bbNum );
1054+ JITDUMP (FMT_BB " only has ambiguous preds, not jump threading \n " , jti. m_block ->bbNum );
9991055 return false ;
10001056 }
10011057
1002- if ((numAmbiguousPreds > 0 ) && (fallThroughPred != nullptr ))
1058+ if ((jti. m_numAmbiguousPreds > 0 ) && (jti. m_fallThroughPred != nullptr ))
10031059 {
10041060 // Treat the fall through pred as an ambiguous pred.
1005- JITDUMP (FMT_BB " has both ambiguous preds and a fall through pred\n " , block ->bbNum );
1006- JITDUMP (" Treating fall through pred " FMT_BB " as an ambiguous pred\n " , fallThroughPred ->bbNum );
1061+ JITDUMP (FMT_BB " has both ambiguous preds and a fall through pred\n " , jti. m_block ->bbNum );
1062+ JITDUMP (" Treating fall through pred " FMT_BB " as an ambiguous pred\n " , jti. m_fallThroughPred ->bbNum );
10071063
1008- if (BlockSetOps::IsMember (this , truePreds, fallThroughPred ->bbNum ))
1064+ if (BlockSetOps::IsMember (this , jti. m_truePreds , jti. m_fallThroughPred ->bbNum ))
10091065 {
1010- BlockSetOps::RemoveElemD (this , truePreds, fallThroughPred ->bbNum );
1011- assert (numTruePreds > 0 );
1012- numTruePreds --;
1066+ BlockSetOps::RemoveElemD (this , jti. m_truePreds , jti. m_fallThroughPred ->bbNum );
1067+ assert (jti. m_numTruePreds > 0 );
1068+ jti. m_numTruePreds --;
10131069 }
10141070 else
10151071 {
1016- assert (numFalsePreds > 0 );
1017- numFalsePreds --;
1072+ assert (jti. m_numFalsePreds > 0 );
1073+ jti. m_numFalsePreds --;
10181074 }
10191075
1020- assert (!(BlockSetOps::IsMember (this , ambiguousPreds, fallThroughPred->bbNum )));
1021- BlockSetOps::AddElemD (this , ambiguousPreds, fallThroughPred->bbNum );
1022- numAmbiguousPreds++;
1023- fallThroughPred = nullptr ;
1076+ assert (!(BlockSetOps::IsMember (this , jti.m_ambiguousPreds , jti.m_fallThroughPred ->bbNum )));
1077+ BlockSetOps::AddElemD (this , jti.m_ambiguousPreds , jti.m_fallThroughPred ->bbNum );
1078+ jti.m_numAmbiguousPreds ++;
1079+ jti.m_fallThroughPred = nullptr ;
1080+ }
1081+
1082+ // There still should be at least one pred that can bypass block.
1083+ //
1084+ if ((jti.m_numTruePreds == 0 ) && (jti.m_numFalsePreds == 0 ))
1085+ {
1086+ // This is possible, but also should be rare.
1087+ //
1088+ JITDUMP (FMT_BB " now only has ambiguous preds, not jump threading\n " , jti.m_block ->bbNum );
1089+ return false ;
10241090 }
10251091
10261092 // Determine if either set of preds will route via block.
10271093 //
10281094 bool truePredsWillReuseBlock = false ;
10291095 bool falsePredsWillReuseBlock = false ;
10301096
1031- if (fallThroughPred != nullptr )
1097+ if (jti. m_fallThroughPred != nullptr )
10321098 {
1033- assert (numAmbiguousPreds == 0 );
1034- truePredsWillReuseBlock = BlockSetOps::IsMember (this , truePreds, fallThroughPred ->bbNum );
1099+ assert (jti. m_numAmbiguousPreds == 0 );
1100+ truePredsWillReuseBlock = BlockSetOps::IsMember (this , jti. m_truePreds , jti. m_fallThroughPred ->bbNum );
10351101 falsePredsWillReuseBlock = !truePredsWillReuseBlock;
10361102 }
1037- else if (numAmbiguousPreds == 0 )
1103+ else if (jti. m_numAmbiguousPreds == 0 )
10381104 {
10391105 truePredsWillReuseBlock = true ;
10401106 falsePredsWillReuseBlock = !truePredsWillReuseBlock;
@@ -1050,35 +1116,36 @@ bool Compiler::optJumpThread(BasicBlock* const block, BasicBlock* const domBlock
10501116 //
10511117 if (truePredsWillReuseBlock)
10521118 {
1053- Statement* lastStmt = block ->lastStmt ();
1054- fgRemoveStmt (block , lastStmt);
1055- JITDUMP (" repurposing " FMT_BB " to always jump to " FMT_BB " \n " , block ->bbNum , trueTarget ->bbNum );
1056- fgRemoveRefPred (block-> bbNext , block );
1057- block ->bbJumpKind = BBJ_ALWAYS;
1119+ Statement* const lastStmt = jti. m_block ->lastStmt ();
1120+ fgRemoveStmt (jti. m_block , lastStmt);
1121+ JITDUMP (" repurposing " FMT_BB " to always jump to " FMT_BB " \n " , jti. m_block ->bbNum , jti. m_trueTarget ->bbNum );
1122+ fgRemoveRefPred (jti. m_falseTarget , jti. m_block );
1123+ jti. m_block ->bbJumpKind = BBJ_ALWAYS;
10581124 }
10591125 else if (falsePredsWillReuseBlock)
10601126 {
1061- Statement* lastStmt = block->lastStmt ();
1062- fgRemoveStmt (block, lastStmt);
1063- JITDUMP (" repurposing " FMT_BB " to always fall through to " FMT_BB " \n " , block->bbNum , falseTarget->bbNum );
1064- fgRemoveRefPred (block->bbJumpDest , block);
1065- block->bbJumpKind = BBJ_NONE;
1127+ Statement* const lastStmt = jti.m_block ->lastStmt ();
1128+ fgRemoveStmt (jti.m_block , lastStmt);
1129+ JITDUMP (" repurposing " FMT_BB " to always fall through to " FMT_BB " \n " , jti.m_block ->bbNum ,
1130+ jti.m_falseTarget ->bbNum );
1131+ fgRemoveRefPred (jti.m_trueTarget , jti.m_block );
1132+ jti.m_block ->bbJumpKind = BBJ_NONE;
10661133 }
10671134
10681135 // Now reroute the flow from the predecessors.
10691136 // If this pred is in the set that will reuse block, do nothing.
10701137 // Else revise pred to branch directly to the appropriate successor of block.
10711138 //
1072- for (BasicBlock* const predBlock : block ->PredBlocks ())
1139+ for (BasicBlock* const predBlock : jti. m_block ->PredBlocks ())
10731140 {
10741141 // If this was an ambiguous pred, skip.
10751142 //
1076- if (BlockSetOps::IsMember (this , ambiguousPreds , predBlock->bbNum ))
1143+ if (BlockSetOps::IsMember (this , jti. m_ambiguousPreds , predBlock->bbNum ))
10771144 {
10781145 continue ;
10791146 }
10801147
1081- const bool isTruePred = BlockSetOps::IsMember (this , truePreds , predBlock->bbNum );
1148+ const bool isTruePred = BlockSetOps::IsMember (this , jti. m_truePreds , predBlock->bbNum );
10821149
10831150 // Do we need to alter flow from this pred?
10841151 //
@@ -1087,36 +1154,35 @@ bool Compiler::optJumpThread(BasicBlock* const block, BasicBlock* const domBlock
10871154 // No, we can leave as is.
10881155 //
10891156 JITDUMP (" %s pred " FMT_BB " will continue to target " FMT_BB " \n " , isTruePred ? " true" : " false" ,
1090- predBlock->bbNum , block ->bbNum );
1157+ predBlock->bbNum , jti. m_block ->bbNum );
10911158 continue ;
10921159 }
10931160
10941161 // Yes, we need to jump to the appropriate successor.
10951162 // Note we should not be altering flow for the fall-through pred.
10961163 //
1097- assert (predBlock != fallThroughPred );
1098- assert (predBlock->bbNext != block );
1164+ assert (predBlock != jti. m_fallThroughPred );
1165+ assert (predBlock->bbNext != jti. m_block );
10991166
11001167 if (isTruePred)
11011168 {
1102- assert (!optReachable (falseSuccessor, predBlock, domBlock));
11031169 JITDUMP (" Jump flow from pred " FMT_BB " -> " FMT_BB
11041170 " implies predicate true; we can safely redirect flow to be " FMT_BB " -> " FMT_BB " \n " ,
1105- predBlock->bbNum , block ->bbNum , predBlock->bbNum , trueTarget ->bbNum );
1171+ predBlock->bbNum , jti. m_block ->bbNum , predBlock->bbNum , jti. m_trueTarget ->bbNum );
11061172
1107- fgRemoveRefPred (block , predBlock);
1108- fgReplaceJumpTarget (predBlock, trueTarget, block );
1109- fgAddRefPred (trueTarget , predBlock);
1173+ fgRemoveRefPred (jti. m_block , predBlock);
1174+ fgReplaceJumpTarget (predBlock, jti. m_trueTarget , jti. m_block );
1175+ fgAddRefPred (jti. m_trueTarget , predBlock);
11101176 }
11111177 else
11121178 {
11131179 JITDUMP (" Jump flow from pred " FMT_BB " -> " FMT_BB
11141180 " implies predicate false; we can safely redirect flow to be " FMT_BB " -> " FMT_BB " \n " ,
1115- predBlock->bbNum , block ->bbNum , predBlock->bbNum , falseTarget ->bbNum );
1181+ predBlock->bbNum , jti. m_block ->bbNum , predBlock->bbNum , jti. m_falseTarget ->bbNum );
11161182
1117- fgRemoveRefPred (block , predBlock);
1118- fgReplaceJumpTarget (predBlock, falseTarget, block );
1119- fgAddRefPred (falseTarget , predBlock);
1183+ fgRemoveRefPred (jti. m_block , predBlock);
1184+ fgReplaceJumpTarget (predBlock, jti. m_falseTarget , jti. m_block );
1185+ fgAddRefPred (jti. m_falseTarget , predBlock);
11201186 }
11211187 }
11221188
0 commit comments