Skip to content

Type check in shared generic doesn't eliminate casts to/from confirmed exact type #49614

Open
@benaadams

Description

@benaadams

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<T>
{
    private IEqualityComparer<T>? _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<string>? GetStringComparer(IEqualityComparer<string>? comparer)
    {
        return comparer;
    }
}

Data

Ideally the non Unsafe version:

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

Would produce the same asm as the Unsafe version:

if (typeof(T) == typeof(string))
{
    _comparer = Unsafe.As<IEqualityComparer<T>?>(
        NonRandomizedStringEqualityComparer.GetStringComparer(
            Unsafe.As<IEqualityComparer<string>?>(_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:
-      mov      rcx, qword ptr [rsi]
-      call     [CORINFO_HELP_READYTORUN_GENERIC_HANDLE]
-      mov      rdi, rax
       mov      rcx, gword ptr [rsi+24]
-      call     [CORINFO_HELP_READYTORUN_CHKCAST]
-      mov      rcx, rax
       call     [NonRandomizedStringEqualityComparer:GetStringComparer(IEqualityComparer`1):IEqualityComparer`1]
-      mov      rdx, rax
-      mov      rcx, rdi
-      call     [CORINFO_HELP_CHKCASTANY]
       lea      rcx, bword ptr [rsi+24]
       mov      rdx, rax
       call     [CORINFO_HELP_ASSIGN_REF]
-					;; bbWeight=0.50 PerfScore 10.38
+					;; bbWeight=0.50 PerfScore 4.38
G_M17833_IG09:
       nop      
						;; bbWeight=1    PerfScore 0.25

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMItenet-performancePerformance related issue

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions