JIT: (bug) Strength reduction produces wrong values: `AddRecMayOverflow` treats a non-constant add-recurrence start as zero
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
Description
### Minimal repro
```csharp
using System;
using System.Runtime.CompilerServices;
public static class Program
{
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
public static void Test(int seed, long[] dst)
{
int c = seed;
for (int i = 0; i < 10; i++)
{
dst[i] = (uint)c * 8L;
c++;
}
}
public static int Main()
{
long[] actual = new long[10];
Test(-3, actual);
long[] expected = new long[10];
for (int i = 0, c = -3; i < 10; i++, c++)
expected[i] = (uint)c * 8L;
Console.WriteLine("expected: " + string.Join(",", expected));
Console.WriteLine("actual: " + string.Join(",", actual));
for (int i = 0; i < 10; i++)
if (actual[i] != expected[i]) { Console.WriteLine("FAILED"); return 101; }
Console.WriteLine("PASSED");
return 100;
}
}
```
### Expected
`34359738344,34359738352,34359738360,0,8,16,24,32,40,48` (the `int` counter wraps through zero, so `(uint)c` restarts at 0). Reproduced with `DOTNET_JitEnableStrengthReduction=0`.
### Actual
`34359738344,34359738352,34359738360,34359738368,34359738376,34359738384,34359738392,34359738400,34359738408,34359738416` — the sequence keeps climbing past 2^32*8, exit code 101.
### Notes
`scev.cpp:1738-1742` in `AddRecMayOverflow` returns "cannot overflow" whenever `Start->GetConstantValue()` fails, i.e. treats any symbolic start as 0, contradicting the comment at `scev.cpp:1731` ("only ... `addRec = `"). `Simplify` (`scev.cpp:1132-1136`) then distributes the `zext` into `` producing ``, and strength reduction materializes it as a new 64-bit primary IV. Correct shape would be the step guard's form: `if (!GetConstantValue(...) || (startCns != 0)) return true;`.
Contributor guide
Assessment
This issue has not been assessed yet.