JIT compiler generates redundant null checks in null-coalescing scenarios or after non-null assignment.
Example 1
public static ReadOnlySpan<char> Test1(string s)
{
s = s ?? "";
return s;
}
public static ReadOnlySpan<char> Test2(string s)
{
var v = s ?? "";
return v; // return s ?? ""
}
In Test1, the JIT does not eliminate the dead branch for the null value, even though s cannot be null after the null-coalescing operation. However, in Test2, the generated code is optimized.
Sample:Test1(System.String):System.ReadOnlySpan`1[ushort] (FullOpts):
push rbp
mov rbp, rsp
mov rax, 0x730E50600008 ; ''
test rdi, rdi
cmove rdi, rax
test rdi, rdi
je SHORT G_M33461_IG04
lea rax, bword ptr [rdi+0x0C]
mov edx, dword ptr [rdi+0x08]
jmp SHORT G_M33461_IG05
G_M33461_IG04: ;; offset=0x0023
xor rax, rax
xor edx, edx
G_M33461_IG05: ;; offset=0x0027
pop rbp
ret
Sample:Test2(System.String):System.ReadOnlySpan`1[ushort] (FullOpts):
mov rax, 0x730E50600008 ; ''
test rdi, rdi
cmove rdi, rax
lea rax, bword ptr [rdi+0x0C]
mov edx, dword ptr [rdi+0x08]
ret
Example 2
public static bool Test3(string s)
{
var v = s != null ? s : "";
return v != null;
}
public static bool Test4(string s)
{
return (s ?? "") != null;
}
For Test3 and Test4, I expected the JIT to generate a simple return true, since the result of (s ?? "") can never be null. For example:
However, the JIT generates explicit null checks instead:
Sample:Test3(System.String):ubyte (FullOpts):
mov rax, 0x730E50600008 ; ''
test rdi, rdi
cmove rdi, rax
test rdi, rdi
setne al
movzx rax, al
ret
Sample:Test4(System.String):ubyte (FullOpts):
mov rax, 0x730E50600008 ; ''
test rdi, rdi
cmove rdi, rax
test rdi, rdi
setne al
movzx rax, al
ret
Source code: godbolt
JIT compiler generates redundant null checks in null-coalescing scenarios or after non-null assignment.
Example 1
In
Test1, the JIT does not eliminate the dead branch for the null value, even thoughscannot be null after the null-coalescing operation. However, inTest2, the generated code is optimized.Example 2
For
Test3andTest4, I expected the JIT to generate a simplereturn true, since the result of(s ?? "")can never be null. For example:However, the JIT generates explicit null checks instead:
Source code: godbolt