Skip to content

Commit

Permalink
JIT: Fix downwards loop transformation with multiply executed exiting…
Browse files Browse the repository at this point in the history
… blocks (#103723)

The transformation to turn loops into downwards counted loops was
missing a check for whether the block containing the exit test was
potentially executed multiple times.
  • Loading branch information
jakobbotsch committed Jun 20, 2024
1 parent 8ab80b9 commit 9e57de2
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -2230,6 +2230,8 @@ class FlowGraphNaturalLoop
bool CanDuplicate(INDEBUG(const char** reason));
void Duplicate(BasicBlock** insertAfter, BlockToBlockMap* map, weight_t weightScale);

bool MayExecuteBlockMultipleTimesPerIteration(BasicBlock* block);

#ifdef DEBUG
static void Dump(FlowGraphNaturalLoop* loop);
#endif // DEBUG
Expand Down
33 changes: 33 additions & 0 deletions src/coreclr/jit/flowgraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5768,6 +5768,39 @@ void FlowGraphNaturalLoop::Duplicate(BasicBlock** insertAfter, BlockToBlockMap*
});
}

//------------------------------------------------------------------------
// MayExecuteBlockMultipleTimesPerIteration:
// Check if the loop may execute a particular loop block multiple times for
// each iteration.
//
// Parameters:
// block - The basic block
//
// Returns:
// True if so. May return true even if the true answer is false.
//
bool FlowGraphNaturalLoop::MayExecuteBlockMultipleTimesPerIteration(BasicBlock* block)
{
assert(ContainsBlock(block));

if (ContainsImproperHeader())
{
// To be more precise we could check if 'block' can reach itself
// without going through the header, but this case is rare.
return true;
}

for (FlowGraphNaturalLoop* child = GetChild(); child != nullptr; child = child->GetSibling())
{
if (child->ContainsBlock(block))
{
return true;
}
}

return false;
}

//------------------------------------------------------------------------
// IterConst: Get the constant with which the iterator is modified
//
Expand Down
6 changes: 6 additions & 0 deletions src/coreclr/jit/inductionvariableopts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,12 @@ bool Compiler::optMakeLoopDownwardsCounted(ScalarEvolutionContext& scevContext,
// At this point we know that the single exit dominates all backedges.
JITDUMP(" All backedges are dominated by exiting block " FMT_BB "\n", exiting->bbNum);

if (loop->MayExecuteBlockMultipleTimesPerIteration(exiting))
{
JITDUMP(" Exiting block may be executed multiple times per iteration; cannot place decrement in it\n");
return false;
}

Scev* backedgeCount = scevContext.ComputeExitNotTakenCount(exiting);
if (backedgeCount == nullptr)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// 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;
using Xunit;

public class DownwardsLoopMultiplyExecutedExiting
{
[Fact]
public static int ExitFromNestedLoop()
{
int n = Get10();
int i = 0;
int result = 0;
if (n < 0)
return -1;

do
{
int j = 0;
do
{
if (i >= n)
return result;

j++;
result++;
} while (j < 10);

i++;
} while (true);
}

[Fact]
public static int ExitFromNestedIrreducibleLoop()
{
int n = Get10();
int i = 0;
int result = -1;
if (n < 0)
return -1;

do
{
int j = 0;
if (AlwaysFalse())
goto InsideLoop;

LoopHeader:
j++;
result++;

InsideLoop:;
if (i >= n)
return result;

if (j < 10)
goto LoopHeader;

i++;
} while (true);
}

[MethodImpl(MethodImplOptions.NoInlining)]
private static bool AlwaysFalse() => false;

[MethodImpl(MethodImplOptions.NoInlining)]
private static int Get10() => 10;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<DebugType>PdbOnly</DebugType>
<Optimize>True</Optimize>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs" />
</ItemGroup>
</Project>

0 comments on commit 9e57de2

Please sign in to comment.