Skip to content

JIT: Strange redunant 'cmp' in Unsafe.As<TFrom, TTo>() codegen #64532

Open
@hypeartist

Description

@hypeartist

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

https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA0AXEBDAzgWwB8ABAJgEYBYAKGIAYACY8gOgBkBLAOwEcBuGvSbkUA2o2YsASgFcuGDvhgsAwhHwAHDgBsYUAMp6AbhzAxcYoZNnzFygJLy9EDYagmzFwRNYA5GUpQpl7iwtJyCkosjhhBXLjBLAAaABxIlj7htlExcQlgIYIAzAxyuNgAZjAMuLEyYBgMACrmGDQA3gCQNJ0aQUbYGNXcGADaALoMAIJi3dSdxCUjDPoBAPoA4jAYU1BQ2ACeACKD2FIwVbBcZirY2roAJgAUAJQMPe09nQNQNQwAvAw6LNvthftoAQwnlwZCMXlN2DAuABzDAACxBsAqDB+DDBkKxDAAsjB8NADkSwbg0XcWFsdntDicMGcLnokWYnlMXiCKtBobD5AwOJDgcKGAAeBjaPjCgDUcreX0+806nVwDDlgIAqvFKsopg9noSwWhhTyvgBfL7EADsNVm1vmPQA9C7mmiOBqjHoEhAuMKNQArGS1Bjo6rlJR4jXYYAQH0MYAyRo02MMfDYGF3bQHYVcbTcGAPBgAchJZKgFKpNO0dO2u32x1O50uHJgpfe8zdePuEAA7txkaUNRgIAwuGCoAOGA8BwGnvYkzBCzAfW8IzUIDIoGYGBBsZuvbgZDAeot841VvhNg3Gc2Wa32dcYI5C1xi68u50VWrcRrAWBL5cQhQEBThBE2CRVEMWA/FsEhGYvkJXES0BQldXKKoWCmXAJRGCYzSkbB+0bJlTgAPieE0eQYHtJTgRi4AYAB+NjkIuHF4N+dDOMw/UcLw4ADiGM0RiowkHhYZlsAtVUvj5KBwKFEVANlEUpRleVFW/H8vnVTUdT1bDDWNTjTXNEEnTVO0HR6ayej6DgBiGGoYDuYsmFIBhiNI+8ZI+G0SkFRooJRdEQQvEKGAABWwI0h0ikphNcmTHRoS0gA

category:cq
theme:codegen
skill-level:beginner
cost:small
impact:medium

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMIhelp wanted[up-for-grabs] Good issue for external contributors

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions