Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[mono] Optimize boxing in Pattern Matching idioms
This PR optimizes boxing for pattern matching idioms. Basically, it copies existing optimizations from CoreCLR to mono, see [impBoxPatternMatch](https://github.com/dotnet/runtime/blob/084dd1a5aae0fbe6ed4f9164ac4ee1c5f0b2398f/src/coreclr/src/jit/importer.cpp#L5856-L6032) (one of them was recently added by me for coreclr, see dotnet/runtime#1817) #### 1) `box + isinst + brtrue/brfalse` --> `ldc.i4.0/1 + brtrue/brfalse` ```csharp 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` ```csharp 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` ```csharp 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](https://sharplab.io/#v2:EYLgtghgzgLgpgJwDQxASwDYB8CwAoAAQAYACAZQAsIEAHAGQmADoAlAVwDsY0w4BufPgIBmEgQCMANjEAmEgGF8Ab3wk1Y0ROlouC6HHEAeACoA+ABTGSMAJSr1KvOuck0AMxLmYrqK652nFyCCAHYSABYZAUDgsKJo5wBfezUUjTEpEmAAe2yMPSg4GRMLK1s0xyC1UOsfPxgE9WSYkjSRDO1deX1hAH0jM0sSbIDnSqr3T2y6nW8AD1Gq5xq5xtiSeLTmts1M2YK4PuLBqxGSAF5TYZndDhIAfhI7kAiowRb2rXqDvuESoZGFTSyzC0ygAHc0DAAMYUYFVcZLIL7O6XJ5IeFIjKkWAIC5XXFMOhwDgAcxgFAxLSxal6+I2mJciTWJGaznwiSAA===) to observe IL code for the samples above. #### Codegen diff example: ```csharp static bool Test(int n) => Validate(n); static bool Validate<T>(T t) => t is int; ``` Before (for `Test`): ```asm 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: ```asm 0000000000000000 movb $0x1, %al 0000000000000002 retq ```
- Loading branch information