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

[mono] Optimize boxing in Pattern Matching idioms #32194

Merged
merged 3 commits into from
Mar 11, 2020

Conversation

EgorBo
Copy link
Member

@EgorBo EgorBo commented Feb 12, 2020

This PR optimizes boxing for pattern matching idioms. Basically, it copies existing optimizations from CoreCLR to mono, see impBoxPatternMatch (one of them was recently added by me for coreclr, see #1817)

1) box + isinst + brtrue/brfalse --> ldc.i4.0/1 + brtrue/brfalse

public static int Case1<T>(T t)
{
    if (t is int)
        return 42;
    return 0;
}
/*
    IL_0000: ldarg.0
    IL_0001: box !!T
    IL_0006: isinst [System.Private.CoreLib]System.Int32
    IL_000b: brfalse.s IL_0010
    IL_000d: ldc.i4.s 42
    IL_000f: ret
    IL_0010: ldc.i4.0
    IL_0011: ret
*/

2) box + isinst + ldnull + ceq/cgt.un --> ldc.i4.0/1

public static bool Case2<T>(T t)
{
    return t is int;
}
/*
    IL_0000: ldarg.0
    IL_0001: box !!T
    IL_0006: isinst [System.Private.CoreLib]System.Int32
    IL_000b: ldnull
    IL_000c: cgt.un
    IL_000e: ret
*/

3) box + isinst + unbox.any --> nop

public static int Case3_1<T>(T o)
{
    if (o is int x)
        return x;
    return 0;
}

// or

public static int Case3_2<T>(T o) => o is int n ? n : 42;

// or

public static int Case3_3<T>(T o)
{
    return o switch
    {
        int n => n,
        string str => str.Length,
        _ => 0
    };
}

Tests can be found here: https://github.com/dotnet/runtime/tree/master/src/coreclr/tests/src/JIT/Generics/Conversions/Boxing

Sharplab.io link to observe IL code for the samples above.

Codegen diff example:

static bool Test(int n) => Validate(n);

static bool Validate<T>(T t) => t is int;

Before (for Test):

0000000000000000	pushq	%r14
0000000000000002	pushq	%rbx
0000000000000003	pushq	%rax
0000000000000004	movl	%edi, %ebx
0000000000000006	movabsq	$0x7fdf9c5090c0, %rax
0000000000000010	movabsq	$0x7fdfad0268e8, %r14
000000000000001a	leaq	0x1be800(%r14), %rdi
0000000000000021	movl	$0x14, %esi
0000000000000026	callq	*(%rax)
0000000000000028	movl	%ebx, 0x10(%rax)
000000000000002b	movq	(%rax), %rax
000000000000002e	cmpq	%r14, (%rax)
0000000000000031	sete	%al
0000000000000034	addq	$0x8, %rsp
0000000000000038	popq	%rbx
0000000000000039	popq	%r14
000000000000003b	retq

After:

0000000000000000	movb	$0x1, %al
0000000000000002	retq

Co-Authored-By: Aleksey Kliger (λgeek) <akliger@gmail.com>
@EgorBo EgorBo merged commit 20ad8cf into dotnet:master Mar 11, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 10, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants