Skip to content

Commit

Permalink
Fix loop canonicalization for call-finally case (#76734)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
BruceForstall committed Oct 11, 2022
1 parent 744fc9b commit 3435b39
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 2 deletions.
32 changes: 30 additions & 2 deletions src/coreclr/jit/optimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
//
Expand Down
40 changes: 40 additions & 0 deletions src/tests/JIT/Regression/JitBlue/Runtime_76346/Runtime_76346.cs
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<Optimize>True</Optimize>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs" />
</ItemGroup>
</Project>

0 comments on commit 3435b39

Please sign in to comment.