Type check in shared generic doesn't eliminate casts to/from confirmed exact type (original) (raw)

From #49608 (review)

A type check e.g. if (typeof(T) == typeof(string)) in a shared generic doesn't eliminate casts to and from a confirmed exact type

using System; using System.Collections.Generic; using System.Runtime.CompilerServices;

public class HashSet { private IEqualityComparer? _comparer;

public HashSet(IEqualityComparer<T>? comparer)
{
    if (comparer is not null && comparer != EqualityComparer<T>.Default) 
    {
        _comparer = comparer;
    }

    if (typeof(T) == typeof(string))
    {
        // Double casts to concrete and back to generic not eliminated

        _comparer = (IEqualityComparer<T>?)
            NonRandomizedStringEqualityComparer.GetStringComparer(
                (IEqualityComparer<string>?)_comparer);
    }
}

}

public static class NonRandomizedStringEqualityComparer { [MethodImpl(MethodImplOptions.NoInlining)] public static IEqualityComparer? GetStringComparer(IEqualityComparer? comparer) { return comparer; } }

Data

Ideally the non Unsafe version:

if (typeof(T) == typeof(string)) { _comparer = (IEqualityComparer?)NonRandomizedStringEqualityComparer .GetStringComparer((IEqualityComparer?)_comparer); }

Would produce the same asm as the Unsafe version:

if (typeof(T) == typeof(string)) { _comparer = Unsafe.As<IEqualityComparer?>( NonRandomizedStringEqualityComparer.GetStringComparer( Unsafe.As<IEqualityComparer?>(_comparer))); }

However the regular casting includes a double cast even though its passed the typeof(TKey) == typeof(string) guard which implies the casts will always succeed.

G_M17833_IG07: mov rcx, qword ptr [rsi] call [CORINFO_HELP_READYTORUN_GENERIC_HANDLE] cmp rax, qword ptr [(reloc)] jne SHORT G_M17833_IG09 ;; bbWeight=1 PerfScore 8.00 G_M17833_IG08:

G_M17833_IG09: nop
;; bbWeight=1 PerfScore 0.25

category:cq
theme:generics
skill-level:expert
cost:medium
impact:small