@@ -6729,69 +6729,7 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early)
67296729 // If return value is true, retry.
67306730 // May also add to retryBlocks.
67316731 //
6732- auto tailMerge = [&](BasicBlock* block) -> bool {
6733-
6734- if (block->countOfInEdges () < 2 )
6735- {
6736- // Nothing to merge here
6737- return false ;
6738- }
6739-
6740- predInfo.Reset ();
6741-
6742- // Find the subset of preds that reach along non-critical edges
6743- // and populate predInfo.
6744- //
6745- for (BasicBlock* const predBlock : block->PredBlocks ())
6746- {
6747- if (predBlock->GetUniqueSucc () != block)
6748- {
6749- continue ;
6750- }
6751-
6752- if (!BasicBlock::sameEHRegion (block, predBlock))
6753- {
6754- continue ;
6755- }
6756-
6757- Statement* lastStmt = predBlock->lastStmt ();
6758-
6759- // Block might be empty.
6760- //
6761- if (lastStmt == nullptr )
6762- {
6763- continue ;
6764- }
6765-
6766- // Walk back past any GT_NOPs.
6767- //
6768- Statement* const firstStmt = predBlock->firstStmt ();
6769- while (lastStmt->GetRootNode ()->OperIs (GT_NOP))
6770- {
6771- if (lastStmt == firstStmt)
6772- {
6773- // predBlock is evidently all GT_NOP.
6774- //
6775- lastStmt = nullptr ;
6776- break ;
6777- }
6778-
6779- lastStmt = lastStmt->GetPrevStmt ();
6780- }
6781-
6782- // Block might be effectively empty.
6783- //
6784- if (lastStmt == nullptr )
6785- {
6786- continue ;
6787- }
6788-
6789- // We don't expect to see PHIs but watch for them anyways.
6790- //
6791- assert (!lastStmt->IsPhiDefnStmt ());
6792- predInfo.Emplace (predBlock, lastStmt);
6793- }
6794-
6732+ auto tailMergePreds = [&](BasicBlock* commSucc) -> bool {
67956733 // Are there enough preds to make it interesting?
67966734 //
67976735 if (predInfo.Height () < 2 )
@@ -6842,9 +6780,9 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early)
68426780 // We have some number of preds that have identical last statements.
68436781 // If all preds of block have a matching last stmt, move that statement to the start of block.
68446782 //
6845- if (matchedPredInfo.Height () == (int )block ->countOfInEdges ())
6783+ if ((commSucc != nullptr ) && ( matchedPredInfo.Height () == (int )commSucc ->countOfInEdges () ))
68466784 {
6847- JITDUMP (" All preds of " FMT_BB " end with the same tree, moving\n " , block ->bbNum );
6785+ JITDUMP (" All preds of " FMT_BB " end with the same tree, moving\n " , commSucc ->bbNum );
68486786 JITDUMPEXEC (gtDispStmt (matchedPredInfo.TopRef (0 ).m_stmt ));
68496787
68506788 for (int j = 0 ; j < matchedPredInfo.Height (); j++)
@@ -6860,8 +6798,8 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early)
68606798 //
68616799 if (j == 0 )
68626800 {
6863- fgInsertStmtAtBeg (block , stmt);
6864- block ->bbFlags |= predBlock->bbFlags & BBF_COPY_PROPAGATE;
6801+ fgInsertStmtAtBeg (commSucc , stmt);
6802+ commSucc ->bbFlags |= predBlock->bbFlags & BBF_COPY_PROPAGATE;
68656803 }
68666804
68676805 madeChanges = true ;
@@ -6876,7 +6814,16 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early)
68766814 // Pick one block as the victim -- preferably a block with just one
68776815 // statement or one that falls through to block (or both).
68786816 //
6879- JITDUMP (" A set of %d preds of " FMT_BB " end with the same tree\n " , matchedPredInfo.Height (), block->bbNum );
6817+ if (commSucc != nullptr )
6818+ {
6819+ JITDUMP (" A set of %d preds of " FMT_BB " end with the same tree\n " , matchedPredInfo.Height (),
6820+ commSucc->bbNum );
6821+ }
6822+ else
6823+ {
6824+ JITDUMP (" A set of %d return blocks end with the same tree\n " , matchedPredInfo.Height ());
6825+ }
6826+
68806827 JITDUMPEXEC (gtDispStmt (matchedPredInfo.TopRef (0 ).m_stmt ));
68816828
68826829 BasicBlock* crossJumpVictim = nullptr ;
@@ -6977,7 +6924,10 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early)
69776924 //
69786925 predBlock->SetJumpKindAndTarget (BBJ_ALWAYS, crossJumpTarget DEBUG_ARG (this ));
69796926
6980- fgRemoveRefPred (block, predBlock);
6927+ if (commSucc != nullptr )
6928+ {
6929+ fgRemoveRefPred (commSucc, predBlock);
6930+ }
69816931 fgAddRefPred (crossJumpTarget, predBlock);
69826932 }
69836933
@@ -7001,6 +6951,71 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early)
70016951 return false ;
70026952 };
70036953
6954+ auto tailMerge = [&](BasicBlock* block) -> bool {
6955+ if (block->countOfInEdges () < 2 )
6956+ {
6957+ // Nothing to merge here
6958+ return false ;
6959+ }
6960+
6961+ predInfo.Reset ();
6962+
6963+ // Find the subset of preds that reach along non-critical edges
6964+ // and populate predInfo.
6965+ //
6966+ for (BasicBlock* const predBlock : block->PredBlocks ())
6967+ {
6968+ if (predBlock->GetUniqueSucc () != block)
6969+ {
6970+ continue ;
6971+ }
6972+
6973+ if (!BasicBlock::sameEHRegion (block, predBlock))
6974+ {
6975+ continue ;
6976+ }
6977+
6978+ Statement* lastStmt = predBlock->lastStmt ();
6979+
6980+ // Block might be empty.
6981+ //
6982+ if (lastStmt == nullptr )
6983+ {
6984+ continue ;
6985+ }
6986+
6987+ // Walk back past any GT_NOPs.
6988+ //
6989+ Statement* const firstStmt = predBlock->firstStmt ();
6990+ while (lastStmt->GetRootNode ()->OperIs (GT_NOP))
6991+ {
6992+ if (lastStmt == firstStmt)
6993+ {
6994+ // predBlock is evidently all GT_NOP.
6995+ //
6996+ lastStmt = nullptr ;
6997+ break ;
6998+ }
6999+
7000+ lastStmt = lastStmt->GetPrevStmt ();
7001+ }
7002+
7003+ // Block might be effectively empty.
7004+ //
7005+ if (lastStmt == nullptr )
7006+ {
7007+ continue ;
7008+ }
7009+
7010+ // We don't expect to see PHIs but watch for them anyways.
7011+ //
7012+ assert (!lastStmt->IsPhiDefnStmt ());
7013+ predInfo.Emplace (predBlock, lastStmt);
7014+ }
7015+
7016+ return tailMergePreds (block);
7017+ };
7018+
70047019 auto iterateTailMerge = [&](BasicBlock* block) -> void {
70057020
70067021 int numOpts = 0 ;
@@ -7016,13 +7031,30 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early)
70167031 }
70177032 };
70187033
7034+ ArrayStack<BasicBlock*> retBlocks (getAllocator (CMK_ArrayStack));
7035+
70197036 // Visit each block
70207037 //
70217038 for (BasicBlock* const block : Blocks ())
70227039 {
70237040 iterateTailMerge (block);
7041+
7042+ // TODO: consider removing hasSingleStmt(), it should find more opportunities
7043+ // (with size and TP regressions)
7044+ if (block->KindIs (BBJ_RETURN) && block->hasSingleStmt () && (block != genReturnBB))
7045+ {
7046+ retBlocks.Push (block);
7047+ }
70247048 }
70257049
7050+ predInfo.Reset ();
7051+ for (int i = 0 ; i < retBlocks.Height (); i++)
7052+ {
7053+ predInfo.Push (PredInfo (retBlocks.Bottom (i), retBlocks.Bottom (i)->lastStmt ()));
7054+ }
7055+
7056+ tailMergePreds (nullptr );
7057+
70267058 // Work through any retries
70277059 //
70287060 while (retryBlocks.Height () > 0 )
0 commit comments