runtime: [RyuJIT] Expression a % 0 sometimes generates incorrect code.

The following example:

[MethodImpl(MethodImplOptions.NoInlining)]
static int Test(sbyte x)
{
    return x % 0;
}

generates

G_M55886_IG02:
       480FBEC1             movsx    rax, cl
G_M55886_IG03:
       C3                   ret

Of course, this doesn’t generate a DivideByZeroException exception as it should.

This is partially caused by a recent change I did that transforms x % c into x - (x / c) * c if c is not a power of 2. 0 is not a power of 2 but the transform should not be done when c is 0. ARM64 appears to do the same transform unconditionally so probably it is also affected by this. I think we should simply transform x % 0 into x / 0.

However, the actual bug is somewhere else. The following IL code triggers it as well:

.method private hidebysig static int32 
        Test(int8 arg) cil managed noinlining
{
        .maxstack  8
        ldarg.0
        ldarg.0
        ldc.i4.0
        div
        ldc.i4.0
        mul
        sub
        ret
}

The C# compiler doesn’t usually produce this kind of code, it drops x * 0. It’s that multiplication that’s probably mishandled by the JIT, it tries to drop it and sometimes it drops the division as well. When it works correctly the generated code looks like this:

G_M55886_IG02:
       480FBEC9             movsx    rcx, cl
       4533C0               xor      r8d, r8d
       8BC1                 mov      eax, ecx
       99                   cdq
       41F7F8               idiv     edx:eax, r8d
       8BC1                 mov      eax, ecx

I’ll look into this. category:correctness theme:cse skill-level:intermediate cost:medium

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 29 (29 by maintainers)

Commits related to this issue

Most upvoted comments

Fixed with dotnet/coreclr#20129