Skip to content

Redundant null checks in null-coalescing scenarios #111980

@rameel

Description

@rameel

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:

mov eax, 1
ret

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

Metadata

Metadata

Assignees

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions