diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp index 5be7aea1445a53..30c161b278f9fa 100644 --- a/src/coreclr/jit/fgopt.cpp +++ b/src/coreclr/jit/fgopt.cpp @@ -5212,6 +5212,23 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) fgUnlinkStmt(predBlock, stmt); + bool canRemove = + predBlock->isEmpty() && !predBlock->HasFlag(BBF_DONT_REMOVE) && predBlock != fgFirstBB; + if (canRemove) + { + for (BasicBlock* const pred : predBlock->PredBlocksEditing()) + { + fgReplaceJumpTarget(pred, predBlock, commSucc); + } + + fgRemoveBlock(predBlock, true); + + if (commSucc->hasProfileWeight()) + { + commSucc->increaseBBProfileWeight(predBlock->bbWeight); + } + } + // Add one of the matching stmts to block, and // update its flags. // @@ -5250,10 +5267,9 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) JITDUMPEXEC(gtDispStmt(matchedPredInfo.TopRef(0).m_stmt)); - BasicBlock* crossJumpVictim = nullptr; - Statement* crossJumpStmt = nullptr; - bool haveNoSplitVictim = false; - bool haveFallThroughVictim = false; + BasicBlock* crossJumpVictim = nullptr; + Statement* crossJumpStmt = nullptr; + unsigned bestRank = UINT32_MAX; for (PredInfo& info : matchedPredInfo.TopDownOrder()) { @@ -5267,46 +5283,34 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) continue; } - bool const isNoSplit = stmt == predBlock->firstStmt(); - bool const isFallThrough = (predBlock->KindIs(BBJ_ALWAYS) && predBlock->JumpsToNext()); + auto getRank = [=]() -> unsigned { + bool const isNoSplit = stmt == predBlock->firstStmt(); + bool const isFallThrough = (predBlock->KindIs(BBJ_ALWAYS) && predBlock->JumpsToNext()); - // Is this block possibly better than what we have? - // - bool useBlock = false; - - if (crossJumpVictim == nullptr) - { - // Pick an initial candidate. - useBlock = true; - } - else if (isNoSplit && isFallThrough) - { - // This is the ideal choice. + // From most to least preferable. // - useBlock = true; - } - else if (!haveNoSplitVictim && isNoSplit) - { - useBlock = true; - } - else if (!haveNoSplitVictim && !haveFallThroughVictim && isFallThrough) - { - useBlock = true; - } + if (isNoSplit && isFallThrough) + return 0; + if (isNoSplit) + return 1; + if (isFallThrough) + return 2; + + return 3; + }; - if (useBlock) + unsigned const rank = getRank(); + bool pick = rank < bestRank; + if (rank == bestRank) { - crossJumpVictim = predBlock; - crossJumpStmt = stmt; - haveNoSplitVictim = isNoSplit; - haveFallThroughVictim = isFallThrough; + pick = predBlock->bbNum < crossJumpVictim->bbNum; } - // If we have the perfect victim, stop looking. - // - if (haveNoSplitVictim && haveFallThroughVictim) + if (pick) { - break; + crossJumpVictim = predBlock; + crossJumpStmt = stmt; + bestRank = rank; } } @@ -5315,7 +5319,7 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) // If this block requires splitting, then split it. // Note we know that stmt has a prev stmt. // - if (haveNoSplitVictim) + if (crossJumpStmt == crossJumpTarget->firstStmt()) { JITDUMP("Will cross-jump to " FMT_BB "\n", crossJumpTarget->bbNum); } @@ -5344,15 +5348,32 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) // Fix up the flow. // - if (commSucc != nullptr) + bool canRemove = predBlock->isEmpty() && !predBlock->HasFlag(BBF_DONT_REMOVE) && predBlock != fgFirstBB; + if (canRemove) { - assert(predBlock->KindIs(BBJ_ALWAYS)); - fgRedirectEdge(predBlock->TargetEdgeRef(), crossJumpTarget); + for (BasicBlock* const pred : predBlock->PredBlocksEditing()) + { + fgReplaceJumpTarget(pred, predBlock, crossJumpTarget); + } + fgRemoveBlock(predBlock, true); + + if (commSucc != nullptr && commSucc->hasProfileWeight()) + { + commSucc->increaseBBProfileWeight(predBlock->bbWeight); + } } else { - FlowEdge* const newEdge = fgAddRefPred(crossJumpTarget, predBlock); - predBlock->SetKindAndTargetEdge(BBJ_ALWAYS, newEdge); + if (commSucc != nullptr) + { + assert(predBlock->KindIs(BBJ_ALWAYS)); + fgRedirectEdge(predBlock->TargetEdgeRef(), crossJumpTarget); + } + else + { + FlowEdge* const newEdge = fgAddRefPred(crossJumpTarget, predBlock); + predBlock->SetKindAndTargetEdge(BBJ_ALWAYS, newEdge); + } } // For tail merge we have a common successor of predBlock and @@ -5402,6 +5423,13 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) continue; } + // If this block was already processed, skip it + // + if (predBlock->isEmpty()) + { + continue; + } + Statement* lastStmt = predBlock->lastStmt(); // Block might be empty. @@ -5498,9 +5526,9 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) predInfo.Reset(); for (BasicBlock* const block : retOrThrowBlocks.BottomUpOrder()) { - // If this block was already merged, skip it + // If this block was already processed, skip it // - if (!block->KindIs(BBJ_RETURN, BBJ_THROW)) + if (!block->KindIs(BBJ_RETURN, BBJ_THROW) || block->isEmpty()) { continue; }