-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Pinning a ReadOnlySpan<> where the length is constant generates code that checks the length.
This managed code
static void Main()
{
var data = new byte[128];
fixed (byte* ptr = (ReadOnlySpan<byte>)data)
{
DoSomething(ptr);
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
static void DoSomething(byte* bob) { }generates this assembly on x64 for pinning (from godbolt, using the latest runtime):
mov edi, 128
xor rcx, rcx
test edi, edi
cmovne rcx, rax
mov bword ptr [rsp], rcx
The JIT is able to figure out that the length is constant (mov edi, 128) which makes the rest of the code unnecessary. test edi, edi will always clear ZF because edi is constant not zero which will cause cmovne rcx, rax to always execute which will overwrite rcx that just got zerod. This whole sequence could be converted to a mov bword ptr [rsp], rax when the length can be proven to be constant.
The codegen on .NET 7 uses a jump instead of cmovne but the testing of constant is still present, .NET 6 does things differently (and worse) so this issue probably only applies to .NET 7 and newer.