From 3435b39194137676d9b2da12c8ebd21d69cd06b9 Mon Sep 17 00:00:00 2001 From: Bruce Forstall Date: Mon, 10 Oct 2022 23:23:40 -0700 Subject: [PATCH] Fix loop canonicalization for call-finally case (#76734) * Fix loop canonicalization for call-finally case If a call-finally is followed by a loop body that requires canonicalization, we hit an assert that the `head` block preceding the loop must be a fall-through block. This was true in all cases except if the preceding block was the BBJ_ALWAYS of a BBJ_CALLFINALLY/BBJ_ALWAYS pair. To fix this, add a new canonicalization. If this case occurs, simply insert a new fall-through block above the loop top and redirect the BBJ_ALWAYS to that new block. Fixes #76346 * Add unit test --- src/coreclr/jit/optimizer.cpp | 32 ++++++++++++++- .../JitBlue/Runtime_76346/Runtime_76346.cs | 40 +++++++++++++++++++ .../Runtime_76346/Runtime_76346.csproj | 9 +++++ 3 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_76346/Runtime_76346.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_76346/Runtime_76346.csproj diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index d2f53ebc8269c..99d6271246508 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -2951,10 +2951,38 @@ bool Compiler::optCanonicalizeLoopNest(unsigned char loopInd) bool Compiler::optCanonicalizeLoop(unsigned char loopInd) { bool modified = false; - BasicBlock* const b = optLoopTable[loopInd].lpBottom; + BasicBlock* h = optLoopTable[loopInd].lpHead; BasicBlock* const t = optLoopTable[loopInd].lpTop; - BasicBlock* const h = optLoopTable[loopInd].lpHead; BasicBlock* const e = optLoopTable[loopInd].lpEntry; + BasicBlock* const b = optLoopTable[loopInd].lpBottom; + + // Normally, `head` either falls through to the `top` or branches to a non-`top` middle + // entry block. If the `head` branches to `top` because it is the BBJ_ALWAYS of a + // BBJ_CALLFINALLY/BBJ_ALWAYS pair, we canonicalize by introducing a new fall-through + // head block. See FindEntry() for the logic that allows this. + if ((h->bbJumpKind == BBJ_ALWAYS) && (h->bbJumpDest == t) && (h->bbFlags & BBF_KEEP_BBJ_ALWAYS)) + { + // Insert new head + + BasicBlock* const newH = fgNewBBafter(BBJ_NONE, h, /*extendRegion*/ true); + newH->inheritWeight(h); + newH->bbNatLoopNum = h->bbNatLoopNum; + h->bbJumpDest = newH; + + fgRemoveRefPred(t, h); + fgAddRefPred(newH, h); + fgAddRefPred(t, newH); + + optUpdateLoopHead(loopInd, h, newH); + + JITDUMP("in optCanonicalizeLoop: " FMT_LP " head " FMT_BB + " is BBJ_ALWAYS of BBJ_CALLFINALLY/BBJ_ALWAYS pair that targets top " FMT_BB + ". Replacing with new BBJ_NONE head " FMT_BB ".", + loopInd, h->bbNum, t->bbNum, newH->bbNum); + + h = newH; + modified = true; + } // Look for case (1) // diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_76346/Runtime_76346.cs b/src/tests/JIT/Regression/JitBlue/Runtime_76346/Runtime_76346.cs new file mode 100644 index 0000000000000..07e3df9e1af3b --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_76346/Runtime_76346.cs @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; + +public class Program +{ + public static int Main() + { + int i = 0; + + try + { + Console.WriteLine("Running... {0}", i); + } + finally + { + // Don't want this to be cloned, so add more EH + Console.WriteLine("In finally1"); + try + { + Console.WriteLine("try2... {0}", i); + } + finally + { + Console.WriteLine("finally2... {0}", i); + } + } + do + { + do + { + ++i; + } while (i % 19 != 0); + } while (i < 40); + + return (i == 57) ? 100 : 101; + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_76346/Runtime_76346.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_76346/Runtime_76346.csproj new file mode 100644 index 0000000000000..f492aeac9d056 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_76346/Runtime_76346.csproj @@ -0,0 +1,9 @@ + + + Exe + True + + + + + \ No newline at end of file