Open
Description
Spotted in .NET 6.0.* and .NET 7.0.100-preview.2.22078.1:
Sample code:
public unsafe struct Test
{
private int[] A;
public int Sum_GetArrayDataReferenceCalled()
{
var s = 0;
var l = (nuint)A.Length;
ref var ar = ref MemoryMarshal.GetArrayDataReference(A);
for(nuint i = 0; i < l; i++)
{
s += Unsafe.Add(ref ar, i);
}
return s;
}
// This version is just the same as above but has a manually inlined 'MemoryMarshal.GetArrayDataReference'
// allowing us to narrow down (I believe) the source of the issue
public int Sum_GetArrayDataReferenceInlined()
{
var s = 0;
var l = (nuint)A.Length;
var a = A;
ref var d = ref Unsafe.As<int[], RawArrayData>(ref a); // <---- ???
ref var ar = ref Unsafe.As<byte, int>(ref d.Data);
for(nuint i = 0; i < l; i++)
{
s += Unsafe.Add(ref ar, i);
}
return s;
}
private sealed class RawArrayData
{
public uint Length;
public uint Padding;
public byte Data;
}
}
Result codegen:
; ================================================================================
; Test.Sum_GetArrayDataReferenceCalled()
; 35 (0x23) bytes
; 13 (0xD) instructions
; var s = 0;
xor eax,eax
; var l = (nuint)A.Length;
mov rdx,[rcx]
mov ecx,[rdx+8]
; ref var ar = ref MemoryMarshal.GetArrayDataReference(A);
cmp [rdx],edx
add rdx,10h
; for(nuint i = 0; i < l; i++)
; ^^^^^^^^^^^
xor r8d,r8d
; for(nuint i = 0; i < l; i++)
; ^^^^^
test rcx,rcx
jbe LBL_1
LBL_0:
; s += Unsafe.Add(ref ar, i);
add eax,[rdx+r8*4]
; for(nuint i = 0; i < l; i++)
; ^^^
inc r8
; for(nuint i = 0; i < l; i++)
; ^^^^^
cmp r8,rcx
jb LBL_0
LBL_1:
; return s;
ret
; ================================================================================
; Test.Sum_GetArrayDataReferenceInlined()
; 35 (0x23) bytes
; 13 (0xD) instructions
; var s = 0;
xor eax,eax
; var l = (nuint)A.Length;
mov rdx,[rcx]
mov ecx,[rdx+8]
; ref var d = ref Unsafe.As<int[], RawArrayData>(ref a); // <---- ???
; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
cmp [rdx],edx
add rdx,10h
; for(nuint i = 0; i < l; i++)
; ^^^^^^^^^^^
xor r8d,r8d
; for(nuint i = 0; i < l; i++)
; ^^^^^
test rcx,rcx
jbe LBL_1
LBL_0:
; s += Unsafe.Add(ref ar, i);
add eax,[rdx+r8*4]
; for(nuint i = 0; i < l; i++)
; ^^^
inc r8
; for(nuint i = 0; i < l; i++)
; ^^^^^
cmp r8,rcx
jb LBL_0
LBL_1:
; return s;
ret
category:cq
theme:codegen
skill-level:beginner
cost:small
impact:medium