Deep dive into .NET 11 Performance Improvements #611/09/2026 | 3 minutes to read | Open in Markdown
In this series, I explore some of the most interesting .NET 11 performance improvements described in Stephen Toub's blog post, Performance Improvements in .NET 11.
Each post focuses on one example from the original article while digging a little deeper into an additional aspect that was not covered there. The series covers the following topics:
- Allocation free numbers
- Virtual generic method calls
- Vector zero equality
- Guid creation on Linux
- JIT generating implicit-else assembly instructions
- Current post: Guid equality
- Copy-on-write locking strategy
Guid equality
One .NET 11 improvement optimizes SequenceEqual on spans of bitwise comparable types such as Guid, allowing the runtime to compare their data as bytes. A Guid is 128 bits wide, so a single value can also be compared using a 128 bit vector operation. The original post discusses the span based optimization; here, I wanted to see whether comparing two individual Guid values also uses SIMD.
Let's test it with the following code:
private readonly Guid _guid1 = default; private readonly Guid _guid2 = default; public bool GuidEqual() => _guid1 == _guid2; public bool GuidEqualEmpty() => _guid1 == Guid.Empty;
The GuidEqual method is JIT compiled into the following x64 assembly code:
; Benchmarks.GuidEqual()
vmovups xmm0,[rcx+8]
vpcmpeqb xmm0,xmm0,[rcx+18]
vpmovmskb eax,xmm0
cmp eax,0FFFF
sete al
movzx eax,al
ret
; Total bytes of code 26
The GuidEqualEmpty method is JIT compiled into the following x64 assembly:
; Benchmarks.GuidEqualEmpty()
vmovups xmm0,[rcx+8]
vptest xmm0,xmm0
sete al
movzx eax,al
ret
; Total bytes of code 17
Both methods use 128 bit vector instructions on my AVX2 capable machine. GuidEqual compares the two vectors with vpcmpeqb, then uses vpmovmskb to pack the comparison results into a scalar mask. It compares that mask with 0xFFFF to check whether all bytes matched. GuidEqualEmpty uses vptest to check whether the vector contains only zeroes; sete then writes the zero flag to the boolean return value.
The BCL implementation of Guid equality also uses Vector128 when hardware acceleration is available, as shown in the source code:
private static bool EqualsCore(in Guid left, in Guid right) { if (Vector128.IsHardwareAccelerated) { return Unsafe.BitCast<Guid, Vector128<byte>>(left) == Unsafe.BitCast<Guid, Vector128<byte>>(right); } //...
Conclusion
This post focused on the 6th of seven nuances I learned from the Performance Improvements in .NET 11 article. The post finds that the .NET JIT uses SIMD instructions for both Guid equality and comparison with Guid.Empty on the tested AVX2 machine, with the empty comparison compiling to shorter code.