-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Improve codegen for switch when cases are sealed classes #44960
Comments
I would think that the following would be a better pattern to emit: public static void M1(object obj)
{
if (obj is A a)
{
Do(a.Number);
}
else if (obj is B b)
{
Do(b.Number);
}
else if (obj is C c)
{
Do(c.Text);
}
}
|
As far as I can tell, the JIT uses the same type check in both cases, e.g.: mov rax, 0x7ff8599bd130
cmp [rcx], rax
je short L0019 The only real difference between the two cases is that the current version has unnecessary repeated
That's pretty much what the compiler already emits and it's equivalent to the sequence of "
As I understand it, this proposal wouldn't either: the compiler would emit (unverifiable) IL that performs the equivalent of That being said, the only reason the proposed codegen is faster is that it avoids repeated null checks. And I think that's something that would be better handled by the JIT. And if the JIT did handle this better, it would improve the performance of both |
You're right, this looks like sharplab just showing a different decompilation to the actual IL (which is |
@svick Thank you for chiming in and for sharing more info! And yes, this proposal was just to emit IL that would do the equivalent of that If you say this is then only something regarding the JIT compiler, should I rephrase this issue better to clarify that and possibly this should get moved back into |
I think so, yes. If the fourth case you described in that issue ("object is T value, when T is a sealed class") was fixed, then I think there would be no real performance difference between the current IL and your proposed optimization. |
Description
The C# compiler currently produces not really ideal codegen when using a
switch
statement where each case declares a variable of a given type and then uses it into that case, when the declared type is a sealed class. It looks like the compiler does a series of safe casts, and multiple checks fornull
. This is not needed when each type being checked is sealed. Consider this example:The C# compiler currently produces the following:
Which could actually be rewritten in a faster way like so:
This does a single
null
check, has much faster type checks as the JIT recognizes theGetType() == typeof(T)
pattern and only emits the single address check, plus theUnsafe.As
call can then skip the checks once we know we have the correct type. Of course this is only a general idea, and this should just be properly written in IL directly, without thoseUnsafe.As
calls. There does seem to be room left for improvements in this particular case though 😊Full sharplab.io sample here.
Configuration
.NET Core 3.1, Release, on sharplab.io.
Other information
As mentioned above, this can currently be optimized manually by using the
Unsafe.As
method. This is not ideal though as the code is more verbose, more error prone, and I believe using generic methods can have some issues in AOT scenarios like R2R? I think I remember @GrabYourPitchforks mentioning this in the past when talking about the JIT intrinsics forGetRawArrayData
in dotnet/runtime#35528.The text was updated successfully, but these errors were encountered: