-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Labels
area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMICLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMIin-prThere is an active PR which will close this issue when it is mergedThere is an active PR which will close this issue when it is merged
Milestone
Description
Repro:
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System.Runtime.CompilerServices;
[MemoryDiagnoser]
[DisassemblyDiagnoser]
public class Program
{
static void Main(string[] args) => BenchmarkSwitcher.FromAssemblies(new[] { typeof(Program).Assembly }).Run(args);
private S _s = default(S);
private C _c = new C();
private S? _ns = (S?)default(S);
[Benchmark] public int Struct() => CallM(_s);
[Benchmark] public int Class() => CallM(_c);
[Benchmark] public int Nullable() => CallM(_ns);
[Benchmark] public int NullableSpecialized() => CallMSpecial(_ns);
static int CallM<T>(T t)
{
if (t is IMyInterface)
{
return ((IMyInterface)t).M();
}
return 0;
}
static int CallMSpecial<T>(T? t) where T : struct
{
if (t.HasValue)
{
return CallM(t.GetValueOrDefault());
}
return 0;
}
}
interface IMyInterface
{
int M();
}
struct S : IMyInterface
{
public int M() => 42;
}
class C : IMyInterface
{
public int M() => 42;
}| Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated | Code Size |
|---|---|---|---|---|---|---|---|---|
| Struct | 0.4807 ns | 0.0044 ns | 0.0037 ns | - | - | - | - | 16 B |
| Class | 3.0842 ns | 0.0045 ns | 0.0038 ns | - | - | - | - | 86 B |
| Nullable | 88.6692 ns | 0.5664 ns | 0.4729 ns | 0.0076 | - | - | 48 B | 132 B |
| NullableSpecialized | 1.5149 ns | 0.0087 ns | 0.0077 ns | - | - | - | - | 64 B |
Is there anything we can do to make the nullable case faster and less inclined to box without needing a special code path to handle it (e.g. my CallMSpecial, which in my current actual code is another overload so that a nullable binds to it more tightly).
Here's what the codegen for the nullable case looks like:
; Program.CallM[[System.Nullable`1[[S, Benchmarks]], System.Private.CoreLib]](System.Nullable`1<S>)
sub rsp,28
mov [rsp+30],rcx
lea rdx,[rsp+30]
mov rcx,offset MT_System.Nullable`1[[S, Benchmarks]]
call CORINFO_HELP_BOX_NULLABLE
mov rdx,rax
mov rcx,offset MT_IMyInterface
call CORINFO_HELP_ISINSTANCEOFINTERFACE
test rax,rax
je short M01_L00
lea rdx,[rsp+30]
mov rcx,offset MT_System.Nullable`1[[S, Benchmarks]]
call CORINFO_HELP_BOX_NULLABLE
mov rdx,rax
mov rcx,offset MT_IMyInterface
call CORINFO_HELP_CHKCASTINTERFACE
mov rcx,rax
mov r11,7FFCDCEE05D0
call qword ptr [7FFCDD2705D0]
nop
add rsp,28
ret
M01_L00:
xor eax,eax
add rsp,28
ret
; Total bytes of code 122category:cq
theme:basic-cq
skill-level:intermediate
cost:medium
impact:small
pentp, PaulusParssinen, NN---, austindrenski, avsorokin and 2 more
Metadata
Metadata
Assignees
Labels
area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMICLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMIin-prThere is an active PR which will close this issue when it is mergedThere is an active PR which will close this issue when it is merged
Type
Projects
Status
Optimizations