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

JIT: optimize "o is byte[]" casts #75991

Closed
wants to merge 4 commits into from

Conversation

EgorBo
Copy link
Member

@EgorBo EgorBo commented Sep 21, 2022

Follow up to #75816 that optimized such checks for exact classes.

Array of integers, bytes, etc are special and can be casted to their signed/unsigned equivalents, so let's expand isinst for them to handle at least one of the cases as a fast path. Presumably, it's a rare case when e.g. obj is int[] and obj is uint[]. In theory we can check for both without the fallback but that will require a new JIT-EE API with extra complexity while I think the declaration type is the most likely target.

bool IsByteArray(IEnumerable o) => o is byte[];

Current codegen:

; Method Tests:IsByteArray(System.Collections.IEnumerable):bool:this
G_M51298_IG01:             
       4883EC28             sub      rsp, 40
G_M51298_IG02:              
       48B920FD447CFE7F0000 mov      rcx, 0x7FFE7C44FD20      ; ubyte[]
       FF155472FBFF         call     [CORINFO_HELP_ISINSTANCEOFARRAY]
       4885C0               test     rax, rax
       0F95C0               setne    al
       0FB6C0               movzx    rax, al
G_M51298_IG03:            
       4883C428             add      rsp, 40
       C3                   ret      
; Total bytes of code: 34

New codegen:

; Method Tests:IsByteArray(System.Collections.IEnumerable):bool:this
G_M51298_IG01:              
       4883EC28             sub      rsp, 40
G_M51298_IG02:             
       488BC2               mov      rax, rdx
       4885C0               test     rax, rax
       741F                 je       SHORT G_M51298_IG05
G_M51298_IG03:         
       48B920FDB976FE7F0000 mov      rcx, 0x7FFE76B9FD20      ; ubyte[]
       483908               cmp      qword ptr [rax], rcx
       7410                 je       SHORT G_M51298_IG05
G_M51298_IG04:             
       48B920FDB976FE7F0000 mov      rcx, 0x7FFE76B9FD20      ; ubyte[]
       FF153D72FBFF         call     [CORINFO_HELP_ISINSTANCEOFARRAY]
G_M51298_IG05:             
       4885C0               test     rax, rax
       0F95C0               setne    al
       0FB6C0               movzx    rax, al
G_M51298_IG06:             
       4883C428             add      rsp, 40
       C3                   ret      
; Total bytes of code: 57

@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 Sep 21, 2022
@ghost ghost assigned EgorBo Sep 21, 2022
@ghost
Copy link

ghost commented Sep 21, 2022

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

Issue Details

Follow up to #75816 that optimized such checks for exact classes.

Array of integers, bytes, etc are special and can be casted to their signed/unsigned equivalents, so let's expand isinst for them to handle at least one of the cases as a fast path. Presumably, it's a rare case when e.g. obj is int[] and obj is uint[]. In theory we can check for both without the fallback but that will require a new JIT-EE API with extra complexity while I think the declaration type is the most likely type as is.

bool IsByteArray(IEnumerable o) => o is byte[];

Current codegen:

; Method Tests:IsByteArray(System.Collections.IEnumerable):bool:this
G_M51298_IG01:             
       4883EC28             sub      rsp, 40
G_M51298_IG02:              
       48B920FD447CFE7F0000 mov      rcx, 0x7FFE7C44FD20      ; ubyte[]
       FF155472FBFF         call     [CORINFO_HELP_ISINSTANCEOFARRAY]
       4885C0               test     rax, rax
       0F95C0               setne    al
       0FB6C0               movzx    rax, al
G_M51298_IG03:            
       4883C428             add      rsp, 40
       C3                   ret      
; Total bytes of code: 34

New codegen:

; Method Tests:IsByteArray(System.Collections.IEnumerable):bool:this
G_M51298_IG01:              
       4883EC28             sub      rsp, 40
G_M51298_IG02:             
       488BC2               mov      rax, rdx
       4885C0               test     rax, rax
       741F                 je       SHORT G_M51298_IG05G_M51298_IG03:         
       48B920FDB976FE7F0000 mov      rcx, 0x7FFE76B9FD20      ; ubyte[]
       483908               cmp      qword ptr [rax], rcx
       7410                 je       SHORT G_M51298_IG05
G_M51298_IG04:             
       48B920FDB976FE7F0000 mov      rcx, 0x7FFE76B9FD20      ; ubyte[]
       FF153D72FBFF         call     [CORINFO_HELP_ISINSTANCEOFARRAY]
G_M51298_IG05:             
       4885C0               test     rax, rax
       0F95C0               setne    al
       0FB6C0               movzx    rax, al
G_M51298_IG06:             
       4883C428             add      rsp, 40
       C3                   ret      
; Total bytes of code: 57
Author: EgorBo
Assignees: -
Labels:

area-CodeGen-coreclr

Milestone: -

@jkotas
Copy link
Member

jkotas commented Sep 21, 2022

You can make similar argument for all o is InexactType cases. Why do we want to do this for arrays and not the other cases - do you have any data to support this?

The problem with the o is InexactType is that it tends to be used as part of the pattern matching and execute the fallback pretty frequently.

@EgorBo
Copy link
Member Author

EgorBo commented Sep 21, 2022

You can make similar argument for all o is InexactType cases. Why do we want to do this for arrays and not the other cases - do you have any data to support this?

The problem with the o is InexactType is that it tends to be used as part of the pattern matching and execute the fallback pretty frequently.

@jkotas Thanks, also realized that when I was looking at this.
So I'm converting this to a double MT check without the fallback, do I understand it correctly that I need to special case these:

 byte[], sbyte[]
 short[], ushort[]
 int[], uint[]
 long[], ulong[]
 IntPtr[], UIntPtr[] /nint/nuint

other primitives like bool, float, double, pointer are fine with a single pMT check?

@jkotas
Copy link
Member

jkotas commented Sep 21, 2022

Nope. This prints true:

object a = new MyEnum[1];

Console.WriteLine(a is int[]); 

enum MyEnum
{
}

@EgorBo
Copy link
Member Author

EgorBo commented Sep 21, 2022

Ah, totally forgot about the Enums it makes it way more difficult then 🙁

@EgorBo EgorBo closed this Sep 21, 2022
@EgorBo
Copy link
Member Author

EgorBo commented Sep 21, 2022

Technically still can be allowed for some primitives where we can't use Enums: char, bool, float, double, pointer, although, it's probably possible via IL/dynamically emitted code

@ghost ghost locked as resolved and limited conversation to collaborators Oct 22, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants