Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Array variance checks are not optimized away for types known to be not arrays #97000

Open
neon-sunset opened this issue Jan 15, 2024 · 3 comments
Assignees
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI tenet-performance Performance related issue
Milestone

Comments

@neon-sunset
Copy link
Contributor

Description

It appears that array variance checks against e.g. List<T> are not optimized away for patterns like (obj)list is int[].

Configuration

.NET 8.0.100

Regression?

No

Analysis

Given below pattern

static bool Foo(List<int> l)
{
    return (object)l is int[];
}

The produced asm is

G_M39343_IG01:  ;; offset=0x0000
       push     rax
G_M39343_IG02:  ;; offset=0x0001
       mov      rsi, rdi
       mov      rdi, 0x7FDDF17D91D0      ; int[]
       call     [CORINFO_HELP_ISINSTANCEOFARRAY]
       test     rax, rax
       setne    al
       movzx    rax, al
G_M39343_IG03:  ;; offset=0x001D
       add      rsp, 8
       ret      

instead of

       xor rax, rax
       ret

Should this pattern get optimized, this will allow to update e.g. Enumerable.SequenceEquals in such a way that type tests are optimized away and it directly forwards to CollectionsMarshal.AsSpan(list).SequenceEquals(...).

@neon-sunset neon-sunset added the tenet-performance Performance related issue label Jan 15, 2024
@dotnet-issue-labeler dotnet-issue-labeler bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jan 15, 2024
@ghost ghost added the untriaged New issue has not been triaged by the area owner label Jan 15, 2024
@ghost
Copy link

ghost commented Jan 15, 2024

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

Issue Details

Description

It appears that array variance checks against e.g. List<T> are not optimized away for patterns like (obj)list is int[].

Configuration

.NET 8.0.100

Regression?

No

Analysis

Given below pattern

static bool Foo(List<int> l)
{
    return (object)l is int[];
}

The produced asm is

G_M39343_IG01:  ;; offset=0x0000
       push     rax
G_M39343_IG02:  ;; offset=0x0001
       mov      rsi, rdi
       mov      rdi, 0x7FDDF17D91D0      ; int[]
       call     [CORINFO_HELP_ISINSTANCEOFARRAY]
       test     rax, rax
       setne    al
       movzx    rax, al
G_M39343_IG03:  ;; offset=0x001D
       add      rsp, 8
       ret      

instead of

       xor rax, rax
       ret

Should this pattern get optimized, this will allow to update e.g. Enumerable.SequenceEquals in such a way that type tests are optimized away and it directly forwards to CollectionsMarshal.AsSpan(list).SequenceEquals(...).

Author: neon-sunset
Assignees: -
Labels:

tenet-performance, area-CodeGen-coreclr

Milestone: -

@EgorBo
Copy link
Member

EgorBo commented Jan 15, 2024

I was using this as a repro:

internal class Program
{
    private static void Main(string[] args)
    {
        Test(new List<int>());
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    static bool Test(List<int> x) => Foo(x);

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    static bool Foo<TSource>(IEnumerable<TSource> x) => x is TSource[];
}

jakobbotsch added a commit to jakobbotsch/runtime that referenced this issue Jan 15, 2024
Folding `x isinst B` where `x` is statically of type `A` is currently
done via a call to `compareTypesForCast`. If it returns
`TypeCompareState::Must` then we know that `A` can be cast to `B`, which
also means any class derived from `A` can be cast to `B`, so we can
always fold that. However, if it returns `TypeCompareState::MustNot` we
only learn something if we know `x` is exactly `A`; otherwise, if `x` is
more derived than `A`, it could still potentially be cast to `B`.

In cases where the type hierarchies are distinct, however, we can still
know that some type checks will fail. To detect the case add a query in
the opposite direction; that is, if `B` cannot be cast to `A`, then the
type hierarchies are distinct, so in that case we can fold it,
regardless of having exact knowledge. This also requires some explicit
checks for interface types, but perhaps we can move those to the EE
side.

Fix dotnet#97000
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Jan 15, 2024
@EgorBo EgorBo added this to the 9.0.0 milestone Jan 15, 2024
@EgorBo EgorBo removed the untriaged New issue has not been triaged by the area owner label Jan 15, 2024
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Jan 16, 2024
@jakobbotsch
Copy link
Member

The diffs were very minor. Doesn't seem worth the TP cost.

@jakobbotsch jakobbotsch modified the milestones: 9.0.0, Future Jan 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI tenet-performance Performance related issue
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants