Skip to content

Pointless codegen for '>=' and '<' comparisons of values with UInt32 / UInt64 underlying types to 0 #11349

@voinokin

Description

@voinokin

As of .NET Core 2.1, JIT produces some code when UInt32 / UInt64 value is compared >= 0 or < 0 even when optimization is turned on.

>= 0 comparisons can be optimized away as they're always evaluated to true since UInt32 / UInt64 values are never negative. (That is, of course, respecting any side effects when obtaining the value to compare with.)
The same applies to < 0 comparisons - they're always evaluated to false in the same manner.

Besides, the codegen (see repro code below) is pointless since TEST instruction always sets CF=0, and both JB and JAE instructions analyse just that CF flag.
This can be confirmed at https://www.felixcloutier.com/x86/Jcc.html , https://www.felixcloutier.com/x86/TEST.html , or any proper x86/x64 ISA manual.

Notes above also apply to enum values having UInt32 / UInt64 as their underlying type.
There is similar behavior when value being compared is of UInt8 or UInt16 types, but I'm not sure whether this should be reported as related to CLR or to C# compiler optimization, since there is intermediate conversion thru Int32 for these types in CLR.


Repro:

        enum SEnum : uint { SEnum1 = 1 }

        [MethodImpl(MethodImplOptions.NoInlining)]
        static void Test(uint u32, ulong u64, SEnum x)
        {
            if (u32 >= 0) Console.WriteLine("{0}", u32);
            if (u64 >= 0) Console.WriteLine("{0}", u64);
            if (x >= 0) Console.WriteLine("{0}", x);
            if (u32 < 0) Console.WriteLine("{0}", u32);
            if (u64 < 0) Console.WriteLine("{0}", u64);
            if (x < 0) Console.WriteLine("{0}", x);
        }

ILDASM:

.method private hidebysig static void  Test(uint32 u32,
                                            uint64 u64,
                                            valuetype _100GbSort.Program2/SEnum x) cil managed noinlining
{
  // Code size       123 (0x7b)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  blt.un.s   IL_0014
  IL_0004:  ldstr      "{0}"
  IL_0009:  ldarg.0
  IL_000a:  box        [System.Runtime]System.UInt32
  IL_000f:  call       void [System.Console]System.Console::WriteLine(string,
                                                                      object)
  IL_0014:  ldarg.1
  IL_0015:  ldc.i4.0
  IL_0016:  conv.i8
  IL_0017:  blt.un.s   IL_0029
  IL_0019:  ldstr      "{0}"
  IL_001e:  ldarg.1
  IL_001f:  box        [System.Runtime]System.UInt64
  IL_0024:  call       void [System.Console]System.Console::WriteLine(string,
                                                                      object)
  IL_0029:  ldarg.2
  IL_002a:  ldc.i4.0
  IL_002b:  blt.un.s   IL_003d
  IL_002d:  ldstr      "{0}"
  IL_0032:  ldarg.2
  IL_0033:  box        _100GbSort.Program2/SEnum
  IL_0038:  call       void [System.Console]System.Console::WriteLine(string,
                                                                      object)
  IL_003d:  ldarg.0
  IL_003e:  ldc.i4.0
  IL_003f:  bge.un.s   IL_0051
  IL_0041:  ldstr      "{0}"
  IL_0046:  ldarg.0
  IL_0047:  box        [System.Runtime]System.UInt32
  IL_004c:  call       void [System.Console]System.Console::WriteLine(string,
                                                                      object)
  IL_0051:  ldarg.1
  IL_0052:  ldc.i4.0
  IL_0053:  conv.i8
  IL_0054:  bge.un.s   IL_0066
  IL_0056:  ldstr      "{0}"
  IL_005b:  ldarg.1
  IL_005c:  box        [System.Runtime]System.UInt64
  IL_0061:  call       void [System.Console]System.Console::WriteLine(string,
                                                                      object)
  IL_0066:  ldarg.2
  IL_0067:  ldc.i4.0
  IL_0068:  bge.un.s   IL_007a
  IL_006a:  ldstr      "{0}"
  IL_006f:  ldarg.2
  IL_0070:  box        _100GbSort.Program2/SEnum
  IL_0075:  call       void [System.Console]System.Console::WriteLine(string,
                                                                      object)
  IL_007a:  ret
} // end of method Program2::Test

Disasm:

            if (u32 >= 0) Console.WriteLine("{0}", u32);
000007FE74007590  push        rdi  
000007FE74007591  push        rsi  
000007FE74007592  push        rbx  
000007FE74007593  sub         rsp,20h  
000007FE74007597  mov         esi,ecx  
000007FE74007599  mov         rdi,rdx  
000007FE7400759C  mov         ebx,r8d  
000007FE7400759F  test        esi,esi  <=====================
000007FE740075A1  jb          000007FE740075C5  <=====================
000007FE740075A3  mov         rcx,7FECA2519E0h  
000007FE740075AD  call        000007FED3B022B0  
000007FE740075B2  mov         rdx,rax  
000007FE740075B5  mov         dword ptr [rdx+8],esi  
000007FE740075B8  mov         rcx,qword ptr [123B3158h]  
000007FE740075C0  call        000007FE74003750  
            if (u64 >= 0) Console.WriteLine("{0}", u64);
000007FE740075C5  test        rdi,rdi  <=====================
000007FE740075C8  jb          000007FE740075ED  <=====================
000007FE740075CA  mov         rcx,7FECA251B10h  
000007FE740075D4  call        000007FED3B022B0  
000007FE740075D9  mov         rdx,rax  
000007FE740075DC  mov         qword ptr [rdx+8],rdi  
000007FE740075E0  mov         rcx,qword ptr [123B3158h]  
000007FE740075E8  call        000007FE74003750  
            if (x >= 0) Console.WriteLine("{0}", x);
000007FE740075ED  test        ebx,ebx  <=====================
000007FE740075EF  jb          000007FE74007613  <=====================
000007FE740075F1  mov         rcx,7FE73EEB350h  
000007FE740075FB  call        000007FED3B022B0  
000007FE74007600  mov         rdx,rax  
000007FE74007603  mov         dword ptr [rdx+8],ebx  
000007FE74007606  mov         rcx,qword ptr [123B3158h]  
000007FE7400760E  call        000007FE74003750  
            if (u32 < 0) Console.WriteLine("{0}", u32);
000007FE74007613  test        esi,esi  <=====================
000007FE74007615  jae         000007FE74007639  <=====================
000007FE74007617  mov         rcx,7FECA2519E0h  
000007FE74007621  call        000007FED3B022B0  
000007FE74007626  mov         rdx,rax  
000007FE74007629  mov         dword ptr [rdx+8],esi  
000007FE7400762C  mov         rcx,qword ptr [123B3158h]  
000007FE74007634  call        000007FE74003750  
            if (u64 < 0) Console.WriteLine("{0}", u64);
000007FE74007639  test        rdi,rdi  <=====================
000007FE7400763C  jae         000007FE74007661  <=====================
000007FE7400763E  mov         rcx,7FECA251B10h  
000007FE74007648  call        000007FED3B022B0  
000007FE7400764D  mov         rdx,rax  
000007FE74007650  mov         qword ptr [rdx+8],rdi  
000007FE74007654  mov         rcx,qword ptr [123B3158h]  
000007FE7400765C  call        000007FE74003750  
            if (x < 0) Console.WriteLine("{0}", x);
000007FE74007661  test        ebx,ebx  <=====================
000007FE74007663  jae         000007FE74007687  <=====================
000007FE74007665  mov         rcx,7FE73EEB350h  
000007FE7400766F  call        000007FED3B022B0  
            if (x < 0) Console.WriteLine("{0}", x);
000007FE74007674  mov         rdx,rax  
000007FE74007677  mov         dword ptr [rdx+8],ebx  
000007FE7400767A  mov         rcx,qword ptr [123B3158h]  
000007FE74007682  call        000007FE74003750  
000007FE74007687  nop  
000007FE74007688  add         rsp,20h  
000007FE7400768C  pop         rbx  
000007FE7400768D  pop         rsi  
000007FE7400768E  pop         rdi  
000007FE7400768F  ret  

category:cq
theme:range-check
skill-level:intermediate
cost:medium

Metadata

Metadata

Assignees

No one assigned

    Labels

    JitUntriagedCLR JIT issues needing additional triagearea-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMIoptimization

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions