-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Replace several Nullable<T>.Value with .GetValueOrDefault() #22297
Conversation
The former does extra work that the latter doesn't do, and they're equivalent when we know it contains a value, such as immediately after a HasValue check.
Different check, but looks similar to https://github.com/dotnet/coreclr/issues/22246 (though probably different areas handling the conditions in the Jit) |
Haven't drilled in to confirm, but I suspect what you're seeing is that Similar issues seen over in #22079 with Might be amusing to look at x86 codegen here and see if it is better. Or try |
Interesting to see what code Roslyn and .NET Framework JIT generate for different approaches. |
It looks like it's indeed related to struct handling. Though it can also be blamed on assertion propagation. Due to the struct issues we end up with a
and assertion propagation doesn't seem too happy to deal with a Ultimately I'd say "blame struct handling". Because it's not only that it causes other optimizations issues, it also forces the argument to memory. This: mov qword ptr [rsp+08H], rcx
G_M60387_IG02:
cmp byte ptr [rsp+08H], 0
je SHORT G_M60387_IG04 should be G_M60387_IG02:
test cl, cl
je SHORT G_M60387_IG04 So we need to either make struct promotion somehow handle this or make it so that |
Yeah, that seems to be the case -- here
|
Even with G_M51227_IG02:
0FB601 movzx rax, byte ptr [rcx]
488B5108 mov rdx, qword ptr [rcx+8]
84C0 test al, al
7412 je SHORT G_M51227_IG05
84C0 test al, al
7415 je SHORT G_M51227_IG07 Looks like
|
There were only a few cases here, so I changed them. But there are a bunch in corefx, and I'm not currently planning on going through and doing all those... besides, having them there should give @AndyAyers and @mikedn something to verify a fix against :) |
Ever since dotnet/roslyn#22800 shipped in 16.0, I've been preferring |
…oreclr#22297) The former does extra work that the latter doesn't do, and they're equivalent when we know it contains a value, such as immediately after a HasValue check. Commit migrated from dotnet/coreclr@1b2810b
The former does extra work that the latter doesn't do, and they're equivalent when we know it contains a value, such as immediately after a HasValue check.
@AndyAyersMS, I was a little surprised in some of these cases that the JIT isn't able to compile down to the same code for Value as it does for GetValueOrDefault. As an example, for this:
I get this for Positive1 that uses Value:
and this for Positive2 that uses GetValueOrDefault:
The former ends up doing the HasValue check twice, even though they happen one right after the other as part of Value getting inlined, and then I'd have expected it to be able to eliminate the dead branch that includes the ThrowHelper call.
Is it expected that it can't get this?