_Extracted from New methods for EqualityComparer
Tuples could directly benefit from that. As well as any code which gets IEqualityComparer<T> externally - it could devirtualize calls to Equals and GetHashCode if the instance passed in is EqualityComparer<T>.Default.
Quoting @jkotas :
The .NET Native compiler for UWP does similar transformation of EqualityComparer
.Default.Equals to reduce binary size for full AOT. You can see the class library side of the implementation here: https://github.com/dotnet/corert/blob/master/src/System.Private.Reflection.Execution/src/Internal/IntrinsicSupport/EqualityComparerHelpers.cs. The compiler side of the implementation is closed source unfortunately, but there is no rocket science in it.
This optimization would make RyuJIT better AOT codegenerator for CoreRT project, closer to the .NET Native compiler for UWP compiler.The beauty of doing this as JIT optimization is that it will kick in for all existing code, without any changes.
Would be great to have this, although it may require duplicating some more logic with EqualityComparer.CreateComparer. +1
Does it have a chance to appear in 2.0?
I am not aware of anybody working on this right now, so it is pretty unlikely.
Am going to start in on this.
I have this partially working now, see master...AndyAyersMS:EqualityComparerDefault
For
```C#
public static bool Compare(ref ValueTuple
{
return a.Equals(b);
}
we now get the following code
```asm
; Total bytes of code 23, prolog size 0
G_M57469_IG02:
mov eax, dword ptr [rdx]
mov edx, dword ptr [rdx+4]
cmp dword ptr [rcx], eax
jne SHORT G_M57469_IG03
cmp dword ptr [rcx+4], edx
sete al
movzx rax, al
jmp SHORT G_M57469_IG04
G_M57469_IG03:
xor eax, eax
G_M57469_IG04:
ret
instead of
; Total bytes of code 108, prolog size 7
G_M57469_IG01:
push rdi
push rsi
push rbx
sub rsp, 48
mov rsi, rcx
G_M57469_IG02:
mov edi, dword ptr [rdx]
mov ebx, dword ptr [rdx+4]
mov rcx, 0x7FFF427D3028
mov edx, 79
call CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS
mov rcx, 0x1EE27732820
mov rcx, gword ptr [rcx]
mov edx, dword ptr [rsi]
mov r8d, edi
mov rax, qword ptr [rcx]
mov rax, qword ptr [rax+72]
call qword ptr [rax+32] ;; virtual
test eax, eax
je SHORT G_M57469_IG03
mov rcx, 0x1EE27732820
mov rcx, gword ptr [rcx]
mov edx, dword ptr [rsi+4]
mov r8d, ebx
mov rax, qword ptr [rcx]
mov rax, qword ptr [rax+72]
call qword ptr [rax+32] ;; virtual
jmp SHORT G_M57469_IG04
G_M57469_IG03:
xor eax, eax
G_M57469_IG04:
add rsp, 48
pop rbx
pop rsi
pop rdi
ret
This uses an explicit expansion of Equals by the jit when T is a simple integer type. It would be cleaner if the jit could determine what class Default exactly refers to, then regular devirt/inline could kick in and we'd handle all the methods on the comparer and use their actual implementations.
I'm not sure how to best go about doing that. It seems like the knowledge of this mapping might need to be hard coded on the VM side?
Also we might want to tone down struct promotion a bit, so we don't eagerly load all the fields like we do here. Or else move the loads closer to their uses....
I'm not sure how to best go about doing that. It seems like the knowledge of this mapping might need to be hard coded on the VM side?
Yes. .NET Native has some code for it - it is probably not 100% reusable for RyuJIT, but bits and pieces may be. As you have said, the basic idea is that the virtual comparer gets replaced by a concrete one - like https://github.com/dotnet/corert/blob/280f6a0e29954d31c94263d6137d215ca71282fd/src/System.Private.CoreLib/src/Internal/IntrinsicSupport/EqualityComparerHelpers.cs#L155.
Most helpful comment
Am going to start in on this.