From 0fc6ef0d1164697a6f3c8200a83f028721650973 Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Thu, 3 Sep 2026 03:05:29 +0200 Subject: [PATCH 1/4] * always pick the self-loop as the crossJumpVictim as that makes most sense and avoids trying to delete commSucc (which happens to be a silent assumption the caller makes) * move 'if (predBlock->isEmpty())' check down to when the stmt was inserted (fixes an issue where predBlock==commSuc) --- src/coreclr/jit/fgopt.cpp | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp index 8ecd739aa0da2e..01f51490784ba0 100644 --- a/src/coreclr/jit/fgopt.cpp +++ b/src/coreclr/jit/fgopt.cpp @@ -5298,11 +5298,6 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) fgUnlinkStmt(predBlock, stmt); - if (predBlock->isEmpty()) - { - tryRemoveAndFixFlow(predBlock, commSucc); - } - // Add one of the matching stmts to block, and // update its flags. // @@ -5312,6 +5307,11 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) commSucc->CopyFlags(predBlock, BBF_COPY_PROPAGATE); } + if (predBlock->isEmpty()) + { + tryRemoveAndFixFlow(predBlock, commSucc); + } + madeChanges = true; } @@ -5363,20 +5363,24 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) // From most to least preferable. // - if (isNoSplit && isFallThrough) + if (predBlock == commSucc) { return 0; } - if (isNoSplit) + if (isNoSplit && isFallThrough) { return 1; } - if (isFallThrough) + if (isNoSplit) { return 2; } + if (isFallThrough) + { + return 3; + } - return 3; + return 4; }; unsigned const rank = getRank(); @@ -5485,6 +5489,11 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) // for (BasicBlock* const predBlock : block->PredBlocks()) { + // if (predBlock == block) + // { + // continue; + // } + if (predBlock->GetUniqueSucc() != block) { continue; From ae9012a092c64e0fbf0964ccdf5af6b4350d571d Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Thu, 3 Sep 2026 03:07:40 +0200 Subject: [PATCH 2/4] * accidentally commited experiment, remove --- src/coreclr/jit/fgopt.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp index 01f51490784ba0..aff6e25c12dc58 100644 --- a/src/coreclr/jit/fgopt.cpp +++ b/src/coreclr/jit/fgopt.cpp @@ -5489,11 +5489,6 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early) // for (BasicBlock* const predBlock : block->PredBlocks()) { - // if (predBlock == block) - // { - // continue; - // } - if (predBlock->GetUniqueSucc() != block) { continue; From 79afea55622019938500bf616787a006bd085f4c Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Thu, 3 Sep 2026 23:17:08 +0200 Subject: [PATCH 3/4] * add regression test --- .../JitBlue/Runtime_133131/Runtime_133131.cs | 61 +++++++++++++++++++ .../JIT/Regression/Regression_ro_2.csproj | 1 + 2 files changed, 62 insertions(+) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_133131/Runtime_133131.cs diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_133131/Runtime_133131.cs b/src/tests/JIT/Regression/JitBlue/Runtime_133131/Runtime_133131.cs new file mode 100644 index 00000000000000..fcc89d1034e9df --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_133131/Runtime_133131.cs @@ -0,0 +1,61 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Runtime_133131; + +using System.Runtime.CompilerServices; +using Xunit; + +public class Runtime_133131 +{ + private static int s_v; + + [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] + private static void TailMergePickSelfLoopAsVictim(int x) + { + if (x == 1) + { + goto P; + } + if (x == 2) + { + s_v = 77; + goto L; + } + return; + P: + s_v = 1; + goto L; + L: + s_v = 1; + goto L; + } + + [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] + private static void TailMergeDontRemoveSelfLoop(int x) + { + if (x >= 0) + { + goto P; + } + return; + L: + s_v = 1; + goto L; + P: + s_v = 1; + goto L; + } + + [Fact] + public static void TestEntryPoint() + { + s_v = 0; + TailMergePickSelfLoopAsVictim(-1); + Assert.Equal(s_v, 0); + + s_v = 0; + TailMergeDontRemoveSelfLoop(-1); + Assert.Equal(s_v, 0); + } +} diff --git a/src/tests/JIT/Regression/Regression_ro_2.csproj b/src/tests/JIT/Regression/Regression_ro_2.csproj index a6bdb64234975f..784e36dc513771 100644 --- a/src/tests/JIT/Regression/Regression_ro_2.csproj +++ b/src/tests/JIT/Regression/Regression_ro_2.csproj @@ -124,6 +124,7 @@ + From 4b0005202bcfc756805ace79e074100d1246a785 Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Fri, 4 Sep 2026 00:18:58 +0200 Subject: [PATCH 4/4] * make literal lhs in Assert.Equal --- .../JIT/Regression/JitBlue/Runtime_133131/Runtime_133131.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_133131/Runtime_133131.cs b/src/tests/JIT/Regression/JitBlue/Runtime_133131/Runtime_133131.cs index fcc89d1034e9df..3d0ec47a03027b 100644 --- a/src/tests/JIT/Regression/JitBlue/Runtime_133131/Runtime_133131.cs +++ b/src/tests/JIT/Regression/JitBlue/Runtime_133131/Runtime_133131.cs @@ -52,10 +52,10 @@ public static void TestEntryPoint() { s_v = 0; TailMergePickSelfLoopAsVictim(-1); - Assert.Equal(s_v, 0); + Assert.Equal(0, s_v); s_v = 0; TailMergeDontRemoveSelfLoop(-1); - Assert.Equal(s_v, 0); + Assert.Equal(0, s_v); } }