Skip to content

Instantly share code, notes, and snippets.

@aalmada
Last active July 30, 2023 22:09
Show Gist options
  • Save aalmada/ca24a7d5d58b6b1108e0fc316df1873c to your computer and use it in GitHub Desktop.
Save aalmada/ca24a7d5d58b6b1108e0fc316df1873c to your computer and use it in GitHub Desktop.
The ASM code generated by .NET 8 when foreach is applied to different types of collections
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
static class MyExtensions
{
static int Sum(this int[] source)
{
var sum = 0;
foreach (var item in source)
sum += item;
return sum;
}
static int Sum(this ReadOnlySpan<int> source)
{
var sum = 0;
foreach (var item in source)
sum += item;
return sum;
}
static int Sum(this ImmutableArray<int> source)
{
var sum = 0;
foreach (var item in source)
sum += item;
return sum;
}
static int Sum(this List<int> source)
{
var sum = 0;
foreach (var item in source)
sum += item;
return sum;
}
static int Sum(this IEnumerable<int> source)
{
var sum = 0;
foreach (var item in source)
sum += item;
return sum;
}
}

.NET 6.0.20 (6.0.2023.32017), X64 RyuJIT AVX2

; ForEachBenchmarks.Array()
;         var sum = 0;
;         ^^^^^^^^^^^^
       xor       eax,eax
;         foreach (var item in array!)
;                              ^^^^^^
       mov       rdx,[rcx+8]
       xor       ecx,ecx
       mov       r8d,[rdx+8]
       test      r8d,r8d
       jle       short M00_L01
       nop       dword ptr [rax]
       nop       dword ptr [rax+rax]
M00_L00:
       movsxd    r9,ecx
       mov       r9d,[rdx+r9*4+10]
;             sum += item;
;             ^^^^^^^^^^^^
       add       eax,r9d
       inc       ecx
       cmp       r8d,ecx
       jg        short M00_L00
M00_L01:
       ret
; Total bytes of code 51

.NET 6.0.20 (6.0.2023.32017), X64 RyuJIT AVX2

; ForEachBenchmarks.Array_AsSpan()
;         var sum = 0;
;         ^^^^^^^^^^^^
       xor       eax,eax
;         foreach (var item in array!.AsSpan())
;                              ^^^^^^^^^^^^^^^
       mov       rdx,[rcx+8]
       test      rdx,rdx
       jne       short M00_L00
       xor       ecx,ecx
       xor       r8d,r8d
       jmp       short M00_L01
M00_L00:
       lea       rcx,[rdx+10]
       mov       r8d,[rdx+8]
M00_L01:
       xor       edx,edx
       test      r8d,r8d
       jle       short M00_L03
M00_L02:
       movsxd    r9,edx
       mov       r9d,[rcx+r9*4]
;             sum += item;
;             ^^^^^^^^^^^^
       add       eax,r9d
       inc       edx
       cmp       edx,r8d
       jl        short M00_L02
M00_L03:
       ret
; Total bytes of code 51

.NET 6.0.20 (6.0.2023.32017), X64 RyuJIT AVX2

; ForEachBenchmarks.List()
       sub       rsp,28
;         var sum = 0;
;         ^^^^^^^^^^^^
       xor       eax,eax
;         foreach (var item in list!)
;                              ^^^^^
       mov       rdx,[rcx+10]
       mov       ecx,[rdx+14]
       mov       r8d,ecx
       xor       r9d,r9d
       jmp       short M00_L01
;             sum += item;
;             ^^^^^^^^^^^^
M00_L00:
       add       eax,r10d
M00_L01:
       cmp       r8d,ecx
       jne       short M00_L04
       cmp       r9d,[rdx+10]
       jae       short M00_L02
       mov       r10,[rdx+8]
       cmp       r9d,[r10+8]
       jae       short M00_L05
       movsxd    r11,r9d
       mov       r10d,[r10+r11*4+10]
       inc       r9d
       mov       r11d,1
       jmp       short M00_L03
M00_L02:
       mov       r9d,[rdx+10]
       inc       r9d
       xor       r10d,r10d
       xor       r11d,r11d
M00_L03:
       test      r11d,r11d
       jne       short M00_L00
       add       rsp,28
       ret
M00_L04:
       call      System.ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion()
       int       3
M00_L05:
       call      CORINFO_HELP_RNGCHKFAIL
       int       3
; Total bytes of code 99

Method was not JITted yet. System.ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion()

.NET 6.0.20 (6.0.2023.32017), X64 RyuJIT AVX2

; ForEachBenchmarks.List_AsSpan()
       sub       rsp,28
;         var sum = 0;
;         ^^^^^^^^^^^^
       xor       eax,eax
;         foreach (var item in CollectionsMarshal.AsSpan(list!))
;                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
       mov       rdx,[rcx+10]
       test      rdx,rdx
       je        short M00_L02
       mov       rcx,[rdx+8]
       mov       edx,[rdx+10]
       test      rcx,rcx
       jne       short M00_L00
       test      edx,edx
       jne       short M00_L06
       xor       r8d,r8d
       xor       edx,edx
       jmp       short M00_L01
M00_L00:
       mov       r8d,[rcx+8]
       mov       r9d,edx
       cmp       r8,r9
       jb        short M00_L06
       add       rcx,10
       mov       r8,rcx
M00_L01:
       jmp       short M00_L03
M00_L02:
       xor       r8d,r8d
       xor       edx,edx
M00_L03:
       xor       ecx,ecx
       test      edx,edx
       jle       short M00_L05
M00_L04:
       movsxd    r9,ecx
       mov       r9d,[r8+r9*4]
;             sum += item;
;             ^^^^^^^^^^^^
       add       eax,r9d
       inc       ecx
       cmp       ecx,edx
       jl        short M00_L04
M00_L05:
       add       rsp,28
       ret
M00_L06:
       call      System.ThrowHelper.ThrowArgumentOutOfRangeException()
       int       3
; Total bytes of code 97

Method was not JITted yet. System.ThrowHelper.ThrowArgumentOutOfRangeException()

.NET 6.0.20 (6.0.2023.32017), X64 RyuJIT AVX2

; ForEachBenchmarks.ImmutableArray()
       sub       rsp,28
;         var sum = 0;
;         ^^^^^^^^^^^^
       xor       eax,eax
;         foreach (var item in immutableArray!)
;                              ^^^^^^^^^^^^^^^
       add       rcx,20
       cmp       byte ptr [rcx],0
       je        short M00_L02
       mov       rdx,[rcx+8]
       mov       ecx,[rdx+8]
       xor       r8d,r8d
       test      ecx,ecx
       jle       short M00_L01
       nop       dword ptr [rax]
M00_L00:
       movsxd    r9,r8d
       mov       r9d,[rdx+r9*4+10]
;             sum += item;
;             ^^^^^^^^^^^^
       add       eax,r9d
       inc       r8d
       cmp       ecx,r8d
       jg        short M00_L00
M00_L01:
       add       rsp,28
       ret
M00_L02:
       call      System.ThrowHelper.ThrowInvalidOperationException_InvalidOperation_NoValue()
       int       3
; Total bytes of code 62

Method was not JITted yet. System.ThrowHelper.ThrowInvalidOperationException_InvalidOperation_NoValue()

.NET 8.0.0 (8.0.23.32907), X64 RyuJIT AVX2

; ForEachBenchmarks.Array()
;         var sum = 0;
;         ^^^^^^^^^^^^
;         foreach (var item in array!)
;                              ^^^^^^
;             sum += item;
;             ^^^^^^^^^^^^
;         return sum;
;         ^^^^^^^^^^^
       xor       eax,eax
       mov       rdx,[rcx+8]
       xor       ecx,ecx
       mov       r8d,[rdx+8]
       test      r8d,r8d
       jle       short M00_L01
M00_L00:
       mov       r9d,ecx
       add       eax,[rdx+r9*4+10]
       inc       ecx
       cmp       r8d,ecx
       jg        short M00_L00
M00_L01:
       ret
; Total bytes of code 33

.NET 8.0.0 (8.0.23.32907), X64 RyuJIT AVX2

; ForEachBenchmarks.Array_AsSpan()
;         var sum = 0;
;         ^^^^^^^^^^^^
;         foreach (var item in array!.AsSpan())
;                              ^^^^^^^^^^^^^^^
;             sum += item;
;             ^^^^^^^^^^^^
;         return sum;
;         ^^^^^^^^^^^
       xor       eax,eax
       mov       rdx,[rcx+8]
       test      rdx,rdx
       je        short M00_L03
       lea       rcx,[rdx+10]
       mov       edx,[rdx+8]
M00_L00:
       xor       r8d,r8d
       test      edx,edx
       jle       short M00_L02
       nop       dword ptr [rax]
M00_L01:
       mov       r9d,r8d
       add       eax,[rcx+r9*4]
       inc       r8d
       cmp       r8d,edx
       jl        short M00_L01
M00_L02:
       ret
M00_L03:
       xor       ecx,ecx
       xor       edx,edx
       jmp       short M00_L00
; Total bytes of code 54

.NET 8.0.0 (8.0.23.32907), X64 RyuJIT AVX2

; ForEachBenchmarks.List()
;         var sum = 0;
;         ^^^^^^^^^^^^
;         foreach (var item in list!)
;                              ^^^^^
;             sum += item;
;             ^^^^^^^^^^^^
;         return sum;
;         ^^^^^^^^^^^
       sub       rsp,28
       xor       eax,eax
       mov       rdx,[rcx+10]
       mov       ecx,[rdx+14]
       xor       ecx,ecx
       jmp       short M00_L01
M00_L00:
       add       eax,r8d
M00_L01:
       mov       r8d,[rdx+10]
       cmp       ecx,r8d
       jae       short M00_L02
       mov       r8,[rdx+8]
       cmp       ecx,[r8+8]
       jae       short M00_L03
       mov       r9d,ecx
       mov       r8d,[r8+r9*4+10]
       inc       ecx
       jmp       short M00_L00
M00_L02:
       add       rsp,28
       ret
M00_L03:
       call      CORINFO_HELP_RNGCHKFAIL
       int       3
; Total bytes of code 62

.NET 8.0.0 (8.0.23.32907), X64 RyuJIT AVX2

; ForEachBenchmarks.List_AsSpan()
;         var sum = 0;
;         ^^^^^^^^^^^^
;         foreach (var item in CollectionsMarshal.AsSpan(list!))
;                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;             sum += item;
;             ^^^^^^^^^^^^
;         return sum;
;         ^^^^^^^^^^^
       sub       rsp,28
       xor       eax,eax
       mov       rdx,[rcx+10]
       test      rdx,rdx
       je        short M00_L05
       mov       rcx,[rdx+8]
       mov       edx,[rdx+10]
       test      rcx,rcx
       je        short M00_L03
       cmp       [rcx+8],edx
       jb        short M00_L04
       add       rcx,10
M00_L00:
       xor       r8d,r8d
       test      edx,edx
       jle       short M00_L02
M00_L01:
       mov       r9d,r8d
       add       eax,[rcx+r9*4]
       inc       r8d
       cmp       r8d,edx
       jl        short M00_L01
M00_L02:
       add       rsp,28
       ret
M00_L03:
       test      edx,edx
       jne       short M00_L04
       xor       ecx,ecx
       xor       edx,edx
       jmp       short M00_L00
M00_L04:
       call      qword ptr [7FFF24E04390]
       int       3
M00_L05:
       xor       ecx,ecx
       xor       edx,edx
       jmp       short M00_L00
; Total bytes of code 86

.NET 8.0.0 (8.0.23.32907), X64 RyuJIT AVX2

; ForEachBenchmarks.ImmutableArray()
;         var sum = 0;
;         ^^^^^^^^^^^^
;         foreach (var item in immutableArray!)
;                              ^^^^^^^^^^^^^^^
;             sum += item;
;             ^^^^^^^^^^^^
;         return sum;
;         ^^^^^^^^^^^
       sub       rsp,28
       xor       eax,eax
       add       rcx,20
       cmp       byte ptr [rcx],0
       je        short M00_L02
       mov       rdx,[rcx+8]
       mov       ecx,[rdx+8]
       xor       r8d,r8d
       test      ecx,ecx
       jle       short M00_L01
       nop       dword ptr [rax]
M00_L00:
       mov       r9d,r8d
       add       eax,[rdx+r9*4+10]
       inc       r8d
       cmp       ecx,r8d
       jg        short M00_L00
M00_L01:
       add       rsp,28
       ret
M00_L02:
       call      qword ptr [7FFF24E149D8]
       int       3
; Total bytes of code 60
; Core CLR 7.0.523.17405 on x64
MyExtensions.Sum(Int32[])
L0000: xor eax, eax
L0002: xor edx, edx
L0004: mov r8d, [rcx+8]
L0008: test r8d, r8d
L000b: jle short L001c
L000d: mov r9d, edx
L0010: add eax, [rcx+r9*4+0x10]
L0015: inc edx
L0017: cmp r8d, edx
L001a: jg short L000d
L001c: ret
MyExtensions.Sum(System.ReadOnlySpan`1<Int32>)
L0000: xor eax, eax
L0002: mov rdx, [rcx]
L0005: mov ecx, [rcx+8]
L0008: xor r8d, r8d
L000b: test ecx, ecx
L000d: jle short L001e
L000f: mov r9d, r8d
L0012: add eax, [rdx+r9*4]
L0016: inc r8d
L0019: cmp r8d, ecx
L001c: jl short L000f
L001e: ret
MyExtensions.Sum(System.Collections.Immutable.ImmutableArray`1<Int32>)
L0000: xor eax, eax
L0002: mov edx, [rcx+8]
L0005: xor r8d, r8d
L0008: test edx, edx
L000a: jle short L001c
L000c: mov r9d, r8d
L000f: add eax, [rcx+r9*4+0x10]
L0014: inc r8d
L0017: cmp edx, r8d
L001a: jg short L000c
L001c: ret
MyExtensions.Sum(System.Collections.Generic.List`1<Int32>)
L0000: sub rsp, 0x28
L0004: xor eax, eax
L0006: mov edx, [rcx+0x14]
L0009: xor edx, edx
L000b: jmp short L0010
L000d: add eax, r8d
L0010: cmp edx, [rcx+0x10]
L0013: jae short L0039
L0015: mov r8, [rcx+8]
L0019: cmp edx, [r8+8]
L001d: jae short L0046
L001f: mov r9d, edx
L0022: mov r8d, [r8+r9*4+0x10]
L0027: inc edx
L0029: mov r9d, 1
L002f: test r9d, r9d
L0032: jne short L000d
L0034: add rsp, 0x28
L0038: ret
L0039: mov edx, [rcx+0x10]
L003c: inc edx
L003e: xor r8d, r8d
L0041: xor r9d, r9d
L0044: jmp short L002f
L0046: call 0x00007fff90a59ae0
L004b: int3
MyExtensions.Sum(System.Collections.Generic.IEnumerable`1<Int32>)
L0000: push rbp
L0001: push rsi
L0002: sub rsp, 0x38
L0006: lea rbp, [rsp+0x40]
L000b: mov [rbp-0x20], rsp
L000f: xor esi, esi
L0011: mov r11, 0x7fff3dc87000
L001b: call qword ptr [r11]
L001e: mov rcx, rax
L0021: mov [rbp-0x10], rcx
L0025: mov r11, 0x7fff3dc87008
L002f: call qword ptr [r11]
L0032: test eax, eax
L0034: je short L005e
L0036: mov rcx, [rbp-0x10]
L003a: mov r11, 0x7fff3dc87010
L0044: call qword ptr [r11]
L0047: add esi, eax
L0049: mov rcx, [rbp-0x10]
L004d: mov r11, 0x7fff3dc87008
L0057: call qword ptr [r11]
L005a: test eax, eax
L005c: jne short L0036
L005e: mov rcx, [rbp-0x10]
L0062: mov r11, 0x7fff3dc87018
L006c: call qword ptr [r11]
L006f: mov eax, esi
L0071: add rsp, 0x38
L0075: pop rsi
L0076: pop rbp
L0077: ret
L0078: push rbp
L0079: push rsi
L007a: sub rsp, 0x28
L007e: mov rbp, [rcx+0x20]
L0082: mov [rsp+0x20], rbp
L0087: lea rbp, [rbp+0x40]
L008b: cmp qword ptr [rbp-0x10], 0
L0090: je short L00a3
L0092: mov rcx, [rbp-0x10]
L0096: mov r11, 0x7fff3dc87018
L00a0: call qword ptr [r11]
L00a3: nop
L00a4: add rsp, 0x28
L00a8: pop rsi
L00a9: pop rbp
L00aa: ret
Microsoft.CodeAnalysis.EmbeddedAttribute..ctor()
L0000: ret
System.Runtime.CompilerServices.NullableAttribute..ctor(Byte)
L0000: push rdi
L0001: push rsi
L0002: sub rsp, 0x28
L0006: mov rsi, rcx
L0009: mov edi, edx
L000b: mov rcx, 0x7fff30f28ec0
L0015: mov edx, 1
L001a: call 0x00007fff90930380
L001f: mov [rax+0x10], dil
L0023: lea rcx, [rsi+8]
L0027: mov rdx, rax
L002a: call 0x00007fff30c40010
L002f: nop
L0030: add rsp, 0x28
L0034: pop rsi
L0035: pop rdi
L0036: ret
System.Runtime.CompilerServices.NullableAttribute..ctor(Byte[])
L0000: lea rcx, [rcx+8]
L0004: call 0x00007fff30c40010
L0009: nop
L000a: ret
System.Runtime.CompilerServices.NullableContextAttribute..ctor(Byte)
L0000: mov [rcx+8], dl
L0003: ret
System.Runtime.CompilerServices.RefSafetyRulesAttribute..ctor(Int32)
L0000: mov [rcx+8], edx
L0003: ret
{
"version": 1,
"target": "JIT ASM",
"mode": "Release",
"branch": "core-x64"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment