Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 27 additions & 34 deletions src/coreclr/jit/optimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,7 @@ bool Compiler::optComputeLoopRep(int constInit,

int64_t constInitX;
int64_t constLimitX;
int64_t iterIncX;

unsigned loopCount;
int iterSign;
Expand Down Expand Up @@ -847,17 +848,24 @@ bool Compiler::optComputeLoopRep(int constInit,
NO_WAY("Bad type");
}

// If iterInc is zero we have an infinite loop.
if (iterInc == 0)
// Normalize subtraction into an additive step before reasoning about loop direction.
iterIncX = iterInc;
if (iterOper == GT_SUB)
{
iterIncX = -iterIncX;
Comment thread
AndyAyersMS marked this conversation as resolved.
}

// If iterIncX is zero we have an infinite loop.
if (iterIncX == 0)
{
return false;
}

iterSign = (iterInc > 0) ? +1 : -1;
iterSign = (iterIncX > 0) ? +1 : -1;
loopCount = 0;

// bail if count is based on wrap-around math
if (iterInc > 0)
if (iterIncX > 0)
{
if (constLimitX < constInitX)
{
Expand Down Expand Up @@ -886,12 +894,12 @@ bool Compiler::optComputeLoopRep(int constInit,
// If "mod iterInc" is not zero then the limit test will miss and a wrap will occur
// which is probably not what the end user wanted, but it is legal.

if (iterInc > 0)
if (iterIncX > 0)
{
// Stepping by one, i.e. Mod with 1 is always zero.
if (iterInc != 1)
if (iterIncX != 1)
{
if (((constLimitX - constInitX) % iterInc) != 0)
if (((constLimitX - constInitX) % iterIncX) != 0)
{
return false;
}
Expand All @@ -900,9 +908,9 @@ bool Compiler::optComputeLoopRep(int constInit,
else
{
// Stepping by -1, i.e. Mod with 1 is always zero.
if (iterInc != -1)
if (iterIncX != -1)
{
if (((constInitX - constLimitX) % (-iterInc)) != 0)
if (((constInitX - constLimitX) % (-iterIncX)) != 0)
{
return false;
}
Expand All @@ -912,16 +920,13 @@ bool Compiler::optComputeLoopRep(int constInit,
switch (iterOper)
{
case GT_SUB:
iterInc = -iterInc;
FALLTHROUGH;

case GT_ADD:
if (constInitX != constLimitX)
{
loopCount += (unsigned)((constLimitX - constInitX - iterSign) / iterInc) + 1;
loopCount += (unsigned)((constLimitX - constInitX - iterSign) / iterIncX) + 1;
}

iterAtExitX = (int)(constInitX + iterInc * (int)loopCount);
iterAtExitX = (int)(constInitX + iterIncX * (int)loopCount);

if (unsTest)
{
Expand Down Expand Up @@ -959,16 +964,13 @@ bool Compiler::optComputeLoopRep(int constInit,
switch (iterOper)
{
case GT_SUB:
iterInc = -iterInc;
FALLTHROUGH;

case GT_ADD:
if (constInitX < constLimitX)
{
loopCount += (unsigned)((constLimitX - constInitX - iterSign) / iterInc) + 1;
loopCount += (unsigned)((constLimitX - constInitX - iterSign) / iterIncX) + 1;
}

iterAtExitX = (int)(constInitX + iterInc * (int)loopCount);
iterAtExitX = (int)(constInitX + iterIncX * (int)loopCount);

if (unsTest)
{
Expand Down Expand Up @@ -1006,16 +1008,13 @@ bool Compiler::optComputeLoopRep(int constInit,
switch (iterOper)
{
case GT_SUB:
iterInc = -iterInc;
FALLTHROUGH;

case GT_ADD:
if (constInitX <= constLimitX)
{
loopCount += (unsigned)((constLimitX - constInitX) / iterInc) + 1;
loopCount += (unsigned)((constLimitX - constInitX) / iterIncX) + 1;
}

iterAtExitX = (int)(constInitX + iterInc * (int)loopCount);
iterAtExitX = (int)(constInitX + iterIncX * (int)loopCount);

if (unsTest)
{
Expand Down Expand Up @@ -1053,16 +1052,13 @@ bool Compiler::optComputeLoopRep(int constInit,
switch (iterOper)
{
case GT_SUB:
iterInc = -iterInc;
FALLTHROUGH;

case GT_ADD:
if (constInitX > constLimitX)
{
loopCount += (unsigned)((constLimitX - constInitX - iterSign) / iterInc) + 1;
loopCount += (unsigned)((constLimitX - constInitX - iterSign) / iterIncX) + 1;
}

iterAtExitX = (int)(constInitX + iterInc * (int)loopCount);
iterAtExitX = (int)(constInitX + iterIncX * (int)loopCount);

if (unsTest)
{
Expand Down Expand Up @@ -1100,16 +1096,13 @@ bool Compiler::optComputeLoopRep(int constInit,
switch (iterOper)
{
case GT_SUB:
iterInc = -iterInc;
FALLTHROUGH;

case GT_ADD:
if (constInitX >= constLimitX)
{
loopCount += (unsigned)((constLimitX - constInitX) / iterInc) + 1;
loopCount += (unsigned)((constLimitX - constInitX) / iterIncX) + 1;
}

iterAtExitX = (int)(constInitX + iterInc * (int)loopCount);
iterAtExitX = (int)(constInitX + iterIncX * (int)loopCount);

if (unsTest)
{
Expand Down
119 changes: 119 additions & 0 deletions src/tests/JIT/Regression/JitBlue/Runtime_133583/Runtime_133583.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// 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 Runtime_133583
{
[Fact]
public static void TestEntryPoint()
{
Assert.Equal(2, NotEqual());
Assert.Equal(2, LessThan());
Assert.Equal(3, LessThanOrEqual());
Assert.Equal(2, GreaterThan());
Assert.Equal(3, GreaterThanOrEqual());
Assert.Equal(1, SubtractIntMinValue());
Assert.Throws<OverflowException>(() => { _ = NotEqualOverflow(); });
}

[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
private static int NotEqual()
{
int count = 0;
int i = 0;
while (i != 2)
{
count++;
i = checked(i - (-1));
}

return count;
}

[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
private static int LessThan()
{
int count = 0;
int i = -2;
while (i < 0)
{
count++;
i = checked(i - (-1));
}

return count;
}

[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
private static int LessThanOrEqual()
{
int count = 0;
int i = -2;
while (i <= 0)
{
count++;
i = checked(i - (-1));
}

return count;
}

[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
private static int GreaterThan()
{
int count = 0;
int i = 2;
while (i > 0)
{
count++;
i = checked(i - 1);
}

return count;
}

[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
private static int GreaterThanOrEqual()
{
int count = 0;
int i = 2;
while (i >= 0)
{
count++;
i = checked(i - 1);
}

return count;
}

[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
private static int SubtractIntMinValue()
{
int count = 0;
int i = int.MinValue;
while (i != 0)
{
count++;
i = checked(i - int.MinValue);
}

return count;
}

[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
private static int NotEqualOverflow()
{
int count = 0;
int i = int.MaxValue - 1;
while (i != int.MaxValue - 2)
{
count++;
i = checked(i - (-1));
}

return count;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Optimize>True</Optimize>
<CLRTestPriority>1</CLRTestPriority>
<RequiresProcessIsolation>true</RequiresProcessIsolation>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs" />

<CLRTestEnvironmentVariable Include="DOTNET_TieredCompilation" Value="0" />
</ItemGroup>
</Project>
Loading