From d42fc3c769ff35b2f8ed42573a00b116ecc55aae Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Tue, 9 Jun 2026 00:18:08 +0200 Subject: [PATCH 1/8] * add tie-break * don't early out * make NoGcPoll preference explicit --- src/coreclr/jit/fgopt.cpp | 66 +++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 38 deletions(-) diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp index 9f6e2f78271e0c..38a230c00b5602 100644 --- a/src/coreclr/jit/fgopt.cpp +++ b/src/coreclr/jit/fgopt.cpp @@ -5274,10 +5274,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()) { @@ -5291,46 +5290,37 @@ 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()); + bool const isNoGcPoll = !predBlock->HasFlag(BasicBlockFlags::BBF_NEEDS_GCPOLL); - // 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; + if (isNoGcPoll) + return 3; + + return 4; + }; - 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; } } @@ -5339,7 +5329,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); } From a9d4d535aa7c80668b929127be23e36fd9af57f9 Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Tue, 9 Jun 2026 05:00:32 +0200 Subject: [PATCH 2/8] * remove explicit isNoGcPoll heuristic --- src/coreclr/jit/fgopt.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp index 38a230c00b5602..263667ddf450cf 100644 --- a/src/coreclr/jit/fgopt.cpp +++ b/src/coreclr/jit/fgopt.cpp @@ -5293,7 +5293,6 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) auto getRank = [=]() -> unsigned { bool const isNoSplit = stmt == predBlock->firstStmt(); bool const isFallThrough = (predBlock->KindIs(BBJ_ALWAYS) && predBlock->JumpsToNext()); - bool const isNoGcPoll = !predBlock->HasFlag(BasicBlockFlags::BBF_NEEDS_GCPOLL); // From most to least preferable. // @@ -5303,10 +5302,8 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) return 1; if (isFallThrough) return 2; - if (isNoGcPoll) - return 3; - return 4; + return 3; }; unsigned const rank = getRank(); From c9a8891a55eb02a8744b78249294c37bba18161b Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Sat, 13 Jun 2026 07:32:19 +0200 Subject: [PATCH 3/8] * process all sets at once * move return/throw block dedulplication to before tail merge * add partition impl, but don't use it yet --- src/coreclr/jit/fgopt.cpp | 233 +++++++++++++++++++------------------- 1 file changed, 115 insertions(+), 118 deletions(-) diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp index 263667ddf450cf..9c5a0a465427b6 100644 --- a/src/coreclr/jit/fgopt.cpp +++ b/src/coreclr/jit/fgopt.cpp @@ -5056,6 +5056,38 @@ unsigned Compiler::fgMeasureIR() #endif // FEATURE_JIT_METHOD_PERF +template +void partition(Iterator first, Iterator last, Pred pred) +{ + while (true) + { + // Skip all left items which are already correct + while (first < last && pred(first)) + { + first++; + } + + if (first == last) + { + return first; + } + + // Predicate was false, the item is left but should be right! + // Find an item on the right which also needs swaping and swap them + do + { + --last; + if (first == last) + { + return first; + } + } while (!pred(last)); + + std::swap(*first, *last); + first++; + } +} + //------------------------------------------------------------------------ // fgHeadTailMerge: merge common sequences of statements in block predecessors/successors // @@ -5123,21 +5155,22 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) Statement* m_stmt; }; - ArrayStack predInfo(getAllocator(CMK_ArrayStack)); - ArrayStack matchedPredInfo(getAllocator(CMK_ArrayStack)); - ArrayStack retryBlocks(getAllocator(CMK_ArrayStack)); + jitstd::vector predInfo(getAllocator(CMK_ArrayStack)); + ArrayStack retryBlocks(getAllocator(CMK_ArrayStack)); // Try tail merging a block. // If return value is true, retry. // May also add to retryBlocks. // - auto tailMergePreds = [&](BasicBlock* commSucc) -> bool { + auto tailMergePreds = [&](BasicBlock* commSucc) -> int { + int optimizedCount = 0; + // Are there enough preds to make it interesting? // - if (predInfo.Height() < 2) + if (predInfo.size() < 2) { // Not enough preds to merge - return false; + return optimizedCount; } // If there are large numbers of viable preds, forgo trying to merge. @@ -5153,67 +5186,61 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) // multiple that avoids code-size regressions (measured via SPMI asmdiffs). // const int effectiveLimit = (commSucc != nullptr) ? mergeLimit : (4 * mergeLimit); - if (predInfo.Height() > effectiveLimit) + if (predInfo.size() > effectiveLimit) { // Too many preds to consider - return false; + return optimizedCount; } // Find a matching set of preds. Potentially O(N^2) tree comparisons. // - int i = 0; - while (i < (predInfo.Height() - 1)) + auto matchesEnd = predInfo.begin(); + while (matchesEnd < (predInfo.end() - 1)) { - matchedPredInfo.Reset(); - matchedPredInfo.Emplace(predInfo.TopRef(i)); - Statement* const baseStmt = predInfo.TopRef(i).m_stmt; - BasicBlock* const baseBlock = predInfo.TopRef(i).m_block; - - for (int j = i + 1; j < predInfo.Height(); j++) - { - BasicBlock* const otherBlock = predInfo.TopRef(j).m_block; + // Previous 'end' becomes new 'begin'. + auto matchesBegin = matchesEnd; + PredInfo candidateA = *matchesBegin; + // Find all matching candidates and partition them to + // be continous in memory at [matchesBegin, matchesEnd - 1] + // + matchesEnd = std::partition(matchesBegin + 1, predInfo.end(), [candidateA](PredInfo candidateB) { // Consider: bypass this for statements that can't cause exceptions. // - if (!BasicBlock::sameEHRegion(baseBlock, otherBlock)) + if (!BasicBlock::sameEHRegion(candidateA.m_block, candidateB.m_block)) { - continue; + return false; } - Statement* const otherStmt = predInfo.TopRef(j).m_stmt; - - // Consider: compute and cache hashes to make this faster - // - if (GenTree::Compare(baseStmt->GetRootNode(), otherStmt->GetRootNode())) - { - matchedPredInfo.Emplace(predInfo.TopRef(j)); - } - } + return GenTree::Compare(candidateA.m_stmt->GetRootNode(), candidateB.m_stmt->GetRootNode()); + }); - if (matchedPredInfo.Height() < 2) + int matchesCount = static_cast(std::distance(matchesBegin, matchesEnd)); + if (matchesCount < 2) { - // This pred didn't match any other. Check other preds for matches. - i++; continue; } + optimizedCount++; + madeChanges = true; + // We can move the identical last statements to commSucc, if it exists, // and all preds have matching last statements, and we're not changing EH behavior. // - bool const hasCommSucc = (commSucc != nullptr); - bool const predsInSameEHRegionAsSucc = hasCommSucc && BasicBlock::sameEHRegion(baseBlock, commSucc); - bool const canMergeAllPreds = hasCommSucc && (matchedPredInfo.Height() == (int)commSucc->countOfInEdges()); + bool const hasCommSucc = (commSucc != nullptr); + bool const predsInSameEHRegionAsSucc = + hasCommSucc && BasicBlock::sameEHRegion(candidateA.m_block, commSucc); + bool const canMergeAllPreds = hasCommSucc && (matchesCount == (int)commSucc->countOfInEdges()); bool const canMergeIntoSucc = predsInSameEHRegionAsSucc && canMergeAllPreds; if (canMergeIntoSucc) { - JITDUMP("All %d preds of " FMT_BB " end with the same tree, moving\n", matchedPredInfo.Height(), - commSucc->bbNum); - JITDUMPEXEC(gtDispStmt(matchedPredInfo.TopRef(0).m_stmt)); + JITDUMP("All %d preds of " FMT_BB " end with the same tree, moving\n", matchesCount, commSucc->bbNum); + JITDUMPEXEC(gtDispStmt(candidateA.m_stmt)); - for (int j = 0; j < matchedPredInfo.Height(); j++) + for (auto it = matchesBegin; it < matchesEnd; it++) { - PredInfo& info = matchedPredInfo.TopRef(j); + PredInfo info = *it; Statement* const stmt = info.m_stmt; BasicBlock* const predBlock = info.m_block; @@ -5235,22 +5262,16 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) commSucc->increaseBBProfileWeight(predBlock->bbWeight); } } - - // Add one of the matching stmts to block, and - // update its flags. - // - if (j == 0) - { - fgInsertStmtAtBeg(commSucc, stmt); - commSucc->CopyFlags(predBlock, BBF_COPY_PROPAGATE); - } - - madeChanges = true; } + // Add one of the matching stmts to commSucc, and update its flags. + fgInsertStmtAtBeg(commSucc, candidateA.m_stmt); + commSucc->CopyFlags(candidateA.m_block, BBF_COPY_PROPAGATE); + // It's worth retrying tail merge on this block. - // - return true; + retryBlocks.Push(commSucc); + + continue; } // All or a subset of preds have matching last stmt, we will cross-jump. @@ -5259,29 +5280,29 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) // if (predsInSameEHRegionAsSucc) { - JITDUMP("A subset of %d preds of " FMT_BB " end with the same tree\n", matchedPredInfo.Height(), - commSucc->bbNum); + JITDUMP("A subset of %d preds of " FMT_BB " end with the same tree\n", matchesCount, commSucc->bbNum); } else if (commSucc != nullptr) { JITDUMP("%s %d preds of " FMT_BB " end with the same tree but are in a different EH region\n", - canMergeAllPreds ? "All" : "A subset of", matchedPredInfo.Height(), commSucc->bbNum); + canMergeAllPreds ? "All" : "A subset of", matchesCount, commSucc->bbNum); } else { - JITDUMP("A set of %d return blocks end with the same tree\n", matchedPredInfo.Height()); + JITDUMP("A set of %d return blocks end with the same tree\n", matchesCount); } - JITDUMPEXEC(gtDispStmt(matchedPredInfo.TopRef(0).m_stmt)); + JITDUMPEXEC(gtDispStmt(candidateA.m_stmt)); BasicBlock* crossJumpVictim = nullptr; Statement* crossJumpStmt = nullptr; unsigned bestRank = UINT32_MAX; - for (PredInfo& info : matchedPredInfo.TopDownOrder()) + for (auto it = matchesBegin; it < matchesEnd; it++) { - Statement* const stmt = info.m_stmt; - BasicBlock* const predBlock = info.m_block; + PredInfo candidate = *it; + Statement* const stmt = candidate.m_stmt; + BasicBlock* const predBlock = candidate.m_block; // Never pick the init block as the victim as that would // cause us to add a predecessor to it, which is invalid. @@ -5340,17 +5361,17 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) // Do the cross jumping // - for (PredInfo& info : matchedPredInfo.TopDownOrder()) + for (auto it = matchesBegin; it < matchesEnd; it++) { - BasicBlock* const predBlock = info.m_block; - Statement* const stmt = info.m_stmt; + PredInfo candidate = *it; + BasicBlock* const predBlock = candidate.m_block; + Statement* const stmt = candidate.m_stmt; if (predBlock == crossJumpVictim) { continue; } - // remove the statement fgUnlinkStmt(predBlock, stmt); // Fix up the flow. @@ -5391,24 +5412,14 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) } } - // We changed things - // - madeChanges = true; - // We should try tail merging the cross jump target. - // - retryBlocks.Push(crossJumpTarget); - - // Continue trying to merge in the current block. - // This is a bit inefficient, we could remember how - // far we got through the pred list perhaps. - // - return true; + if (hasCommSucc) + { + retryBlocks.Push(crossJumpTarget); + } } - // We've looked at everything. - // - return false; + return optimizedCount; }; auto tailMerge = [&](BasicBlock* block) -> bool { @@ -5418,11 +5429,10 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) return false; } - predInfo.Reset(); - // Find the subset of preds that reach along non-critical edges // and populate predInfo. // + predInfo.clear(); for (BasicBlock* const predBlock : block->PredBlocks()) { if (predBlock->GetUniqueSucc() != block) @@ -5472,33 +5482,24 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) // We don't expect to see PHIs but watch for them anyways. // assert(!lastStmt->IsPhiDefnStmt()); - predInfo.Emplace(predBlock, lastStmt); - } - - return tailMergePreds(block); - }; - - auto iterateTailMerge = [&](BasicBlock* block) -> void { - int numOpts = 0; - - while (tailMerge(block)) - { - numOpts++; + predInfo.push_back(PredInfo{predBlock, lastStmt}); } + int numOpts = tailMergePreds(block); if (numOpts > 0) { JITDUMP("Did %d tail merges in " FMT_BB "\n", numOpts, block->bbNum); } - }; - ArrayStack retOrThrowBlocks(getAllocator(CMK_ArrayStack)); + return numOpts; + }; - // Visit each block + // Deduplicate RETURN/THROW blocks. + // This can enable tail-merging so do it first. // + predInfo.clear(); for (BasicBlock* const block : Blocks()) { - iterateTailMerge(block); if (block->isEmpty()) { continue; @@ -5506,7 +5507,7 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) if (block->KindIs(BBJ_THROW)) { - retOrThrowBlocks.Push(block); + predInfo.push_back(PredInfo{block, block->lastStmt()}); } else if (block->KindIs(BBJ_RETURN) && (block != genReturnBB)) { @@ -5523,31 +5524,27 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) } } - retOrThrowBlocks.Push(block); + predInfo.push_back(PredInfo{block, block->lastStmt()}); } } - - JITDUMP("Trying tail merge of return and throw blocks\n"); - do + int numOpts = tailMergePreds(nullptr); + if (numOpts > 0) { - predInfo.Reset(); - for (BasicBlock* const block : retOrThrowBlocks.BottomUpOrder()) - { - // If this block was already processed, skip it - // - if (!block->KindIs(BBJ_RETURN, BBJ_THROW) || block->isEmpty()) - { - continue; - } - predInfo.Push(PredInfo(block, block->lastStmt())); - } - } while (tailMergePreds(nullptr)); + JITDUMP("Deduplicated %d sets of return/throw blocks\n", numOpts); + } - // Work through any retries + // Visit each block // - while (retryBlocks.Height() > 0) + for (BasicBlock* const block : Blocks()) { - iterateTailMerge(retryBlocks.Pop()); + tailMerge(block); + + // Work through any retries + // + while (retryBlocks.Height() > 0) + { + tailMerge(retryBlocks.Pop()); + } } // Visit each block and try to merge first statements of successors. From 8c7e28f812ca3b8e1c70e9347402f51aec05168a Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Sat, 13 Jun 2026 16:29:49 +0200 Subject: [PATCH 4/8] * fix error C4018: '>': signed/unsigned mismatch --- src/coreclr/jit/fgopt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp index 9c5a0a465427b6..dba3a44f9576b5 100644 --- a/src/coreclr/jit/fgopt.cpp +++ b/src/coreclr/jit/fgopt.cpp @@ -5186,7 +5186,7 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) // multiple that avoids code-size regressions (measured via SPMI asmdiffs). // const int effectiveLimit = (commSucc != nullptr) ? mergeLimit : (4 * mergeLimit); - if (predInfo.size() > effectiveLimit) + if (predInfo.size() > static_cast(effectiveLimit)) { // Too many preds to consider return optimizedCount; From 9319e1aabdd3a0f4318c3fb8004b6841c0c46190 Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Sat, 13 Jun 2026 17:33:54 +0200 Subject: [PATCH 5/8] * use custom jitstd::partition * remove 'already processed' check as its no longer needed --- src/coreclr/jit/fgopt.cpp | 44 ++---------------------------- src/coreclr/jit/jitstd/algorithm.h | 35 ++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 41 deletions(-) diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp index dba3a44f9576b5..181906c935ec4b 100644 --- a/src/coreclr/jit/fgopt.cpp +++ b/src/coreclr/jit/fgopt.cpp @@ -7,7 +7,8 @@ #pragma hdrstop #endif -#include "lower.h" // for LowerRange() +#include "lower.h" // for LowerRange() +#include "jitstd/algorithm.h" // for partition() // Flowgraph Optimization @@ -5056,38 +5057,6 @@ unsigned Compiler::fgMeasureIR() #endif // FEATURE_JIT_METHOD_PERF -template -void partition(Iterator first, Iterator last, Pred pred) -{ - while (true) - { - // Skip all left items which are already correct - while (first < last && pred(first)) - { - first++; - } - - if (first == last) - { - return first; - } - - // Predicate was false, the item is left but should be right! - // Find an item on the right which also needs swaping and swap them - do - { - --last; - if (first == last) - { - return first; - } - } while (!pred(last)); - - std::swap(*first, *last); - first++; - } -} - //------------------------------------------------------------------------ // fgHeadTailMerge: merge common sequences of statements in block predecessors/successors // @@ -5204,7 +5173,7 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) // Find all matching candidates and partition them to // be continous in memory at [matchesBegin, matchesEnd - 1] // - matchesEnd = std::partition(matchesBegin + 1, predInfo.end(), [candidateA](PredInfo candidateB) { + matchesEnd = jitstd::partition(matchesBegin + 1, predInfo.end(), [candidateA](PredInfo candidateB) { // Consider: bypass this for statements that can't cause exceptions. // if (!BasicBlock::sameEHRegion(candidateA.m_block, candidateB.m_block)) @@ -5440,13 +5409,6 @@ 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. diff --git a/src/coreclr/jit/jitstd/algorithm.h b/src/coreclr/jit/jitstd/algorithm.h index 3c1fc260068290..0fb913f74c1575 100644 --- a/src/coreclr/jit/jitstd/algorithm.h +++ b/src/coreclr/jit/jitstd/algorithm.h @@ -198,4 +198,39 @@ void sort(RandomAccessIterator first, RandomAccessIterator last, Less less) #endif // DEBUG } } + +// Reorders the elements in the range [first, last) in such a way that all elements for which the predicate returns true +// precede all elements for which predicate returns false. Relative order of the elements is not preserved. +// Returns the first element in the right group. Equivalent to std::partition. +template +Iterator partition(Iterator first, Iterator last, Pred pred) +{ + while (true) + { + // Skip all left items which are already correct + while (first < last && pred(*first)) + { + first++; + } + + if (first == last) + { + return first; + } + + // Predicate was false, the item is left but should be right! + // Find an item on the right which also needs swaping and swap them + do + { + --last; + if (first == last) + { + return first; + } + } while (!pred(*last)); + + std::swap(*first, *last); + first++; + } +} } From ffdf80215904c3c09da1c592058ac3e636d714a5 Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Sat, 13 Jun 2026 17:58:30 +0200 Subject: [PATCH 6/8] * dont use std::distance --- src/coreclr/jit/fgopt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp index 181906c935ec4b..2739171033ab17 100644 --- a/src/coreclr/jit/fgopt.cpp +++ b/src/coreclr/jit/fgopt.cpp @@ -5184,7 +5184,7 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) return GenTree::Compare(candidateA.m_stmt->GetRootNode(), candidateB.m_stmt->GetRootNode()); }); - int matchesCount = static_cast(std::distance(matchesBegin, matchesEnd)); + int matchesCount = static_cast(matchesEnd - matchesBegin); if (matchesCount < 2) { continue; From c7ec29a1b30d65639313c7a86c21aedf023047cf Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Sat, 13 Jun 2026 21:14:58 +0200 Subject: [PATCH 7/8] * try fix x86 tp --- src/coreclr/jit/fgopt.cpp | 16 ++++++++-------- src/coreclr/jit/jitstd/vector.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp index 2739171033ab17..64817aef7ddb56 100644 --- a/src/coreclr/jit/fgopt.cpp +++ b/src/coreclr/jit/fgopt.cpp @@ -5173,7 +5173,7 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) // Find all matching candidates and partition them to // be continous in memory at [matchesBegin, matchesEnd - 1] // - matchesEnd = jitstd::partition(matchesBegin + 1, predInfo.end(), [candidateA](PredInfo candidateB) { + matchesEnd = std::partition(matchesBegin + 1, predInfo.end(), [candidateA](PredInfo candidateB) { // Consider: bypass this for statements that can't cause exceptions. // if (!BasicBlock::sameEHRegion(candidateA.m_block, candidateB.m_block)) @@ -5209,7 +5209,7 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) for (auto it = matchesBegin; it < matchesEnd; it++) { - PredInfo info = *it; + PredInfo& const info = *it; Statement* const stmt = info.m_stmt; BasicBlock* const predBlock = info.m_block; @@ -5269,9 +5269,9 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) for (auto it = matchesBegin; it < matchesEnd; it++) { - PredInfo candidate = *it; - Statement* const stmt = candidate.m_stmt; - BasicBlock* const predBlock = candidate.m_block; + PredInfo& const info = *it; + Statement* const stmt = info.m_stmt; + BasicBlock* const predBlock = info.m_block; // Never pick the init block as the victim as that would // cause us to add a predecessor to it, which is invalid. @@ -5332,9 +5332,9 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) // for (auto it = matchesBegin; it < matchesEnd; it++) { - PredInfo candidate = *it; - BasicBlock* const predBlock = candidate.m_block; - Statement* const stmt = candidate.m_stmt; + PredInfo& const info = *it; + BasicBlock* const predBlock = info.m_block; + Statement* const stmt = info.m_stmt; if (predBlock == crossJumpVictim) { diff --git a/src/coreclr/jit/jitstd/vector.h b/src/coreclr/jit/jitstd/vector.h index 17862714046504..1e059faa5d9ed9 100644 --- a/src/coreclr/jit/jitstd/vector.h +++ b/src/coreclr/jit/jitstd/vector.h @@ -33,7 +33,7 @@ class vector typedef T value_type; // nested classes - class iterator : public jitstd::iterator + class iterator : public jitstd::iterator { iterator(T* ptr); public: From 106401dfde040946721ba1eec5e72ff82c50fcfd Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Sat, 13 Jun 2026 21:34:10 +0200 Subject: [PATCH 8/8] * fix 'const' position --- src/coreclr/jit/fgopt.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp index 64817aef7ddb56..a6c2917aa3a04f 100644 --- a/src/coreclr/jit/fgopt.cpp +++ b/src/coreclr/jit/fgopt.cpp @@ -5209,7 +5209,7 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) for (auto it = matchesBegin; it < matchesEnd; it++) { - PredInfo& const info = *it; + const PredInfo& info = *it; Statement* const stmt = info.m_stmt; BasicBlock* const predBlock = info.m_block; @@ -5269,7 +5269,7 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) for (auto it = matchesBegin; it < matchesEnd; it++) { - PredInfo& const info = *it; + const PredInfo& info = *it; Statement* const stmt = info.m_stmt; BasicBlock* const predBlock = info.m_block; @@ -5332,7 +5332,7 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) // for (auto it = matchesBegin; it < matchesEnd; it++) { - PredInfo& const info = *it; + const PredInfo& info = *it; BasicBlock* const predBlock = info.m_block; Statement* const stmt = info.m_stmt;