Description
Given the following code:
public static int M1(int y)
{
if (y < 0) { return y; }
return y % 8;
}
public static uint M2(uint y)
{
if ((int)y < 0) { return y; }
return y % 8;
}
We currently generate the same assembly:
mov eax, ecx
and eax, 7
test ecx, ecx
cmovl eax, ecx
This is due to the if (y < 0) { return y; }
check in M1
allowing the JIT to determine that y
is never negative
when it comes to the y % 8
expression.
However, in the case of the the following:
public static int M3(Span<int> x, int y)
{
return x[y] + (y % 8);
}
We instead generate the following for the y % 8
:
mov eax, ecx
sar eax, 31
and eax, 7
add eax, ecx
and eax, -8
sub ecx, eax
mov eax, ecx
This is unexpected since x[y]
for both Span<T>
and T[]
is known to require a positive index and to throw if the index is not positive or greater than Length
(i.e the bounds check fails). As such, it should be possible for the JIT to assert that y
is never negative after it is successfully used as an index into a span or array.
While the code example given above is minimal and not necessarily representative of real world code, there are many places where such an index is used for latter indexing or computation and thus tracking the fact can lead to other downstream codegen improvements (whether that be simplified bounds checks elsewhere or optimizations such as is done for %
).