Skip to content

Possible JIT (?) or code gen regression between .NET 10 preview 3 and 4 (10.0.100-preview.3.25201.16 vs. 10.0.100-preview.4.25258.110) #116674

@varelen

Description

@varelen

Description

Hey, I am currently experimenting with a custom programming language with the Compiler and VM implementation written in .NET, and I am not quite sure what is wrong.

I have noticed after wanting to check if there is a performance difference between .NET 9 and the latest .NET 10 preview 5, that the VM had a weird runtime error when doing a binary MULTIPLY operation.

The weird thing is that the error place changes if I change the overloaded operator * from [MethodImpl(MethodImplOptions.AggressiveInlining)] to [MethodImpl(MethodImplOptions.NoInlining)]. Then the exception occurs for example for an ADD operation etc.

I also couldn't hit the break point and the test log said both IsNumber props returned true:

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static Value operator *(Value left, Value right)
    {
        if (left.IsNumber && right.IsNumber)
        {
            return new Value(left.AsNumber() * right.AsNumber());
        }

        Console.WriteLine($"Left: {left.IsNumber}, Right: {right.IsNumber}");

        throw new RuntimeException($"Unsupported operator type * for left '{left}' and right '{right}'");
    }

The problem only occurs in a release build, in a debug build it works.

I have got the following JIT disassembly (part of it) from 10.0.100-preview.3.25201.16 and 10.0.100-preview.4.25258.110 (there was no difference between 10.0.100-preview.4.25258.110 to 10.0.100-preview.5.25277.114).

The JIT disasm is from the main Execute method that contains the VM main loop switch in a release build.

Some noise like:

10.0.100-preview.3.25201.16:

G_M000_IG34:
       mov      rcx, gword ptr [r14+0x10]
       mov      rdx, 0xD1FFAB1E
       and      rdx, rsi
       mov      r8, 0xD1FFAB1E
       cmp      rdx, r8
       je       SHORT G_M000_IG36
       call     CORINFO_HELP_STRCNS

10.0.100-preview.4.25258.110:

G_M000_IG34:
       mov      rcx, gword ptr [r14+0x10]
       mov      rdx, rsi
       not      rdx
       mov      r8, 0xD1FFAB1E
       and      rdx, r8
       je       SHORT G_M000_IG36
       call     [CORINFO_HELP_STRCNS]

But the largest diff was this (middle part):

10.0.100-preview.3.25201.16:

G_M000_IG67:
       call     [VmTest.VmObjectList:get_Items():System.Collections.Generic.List`1[VmTest.Value]:this]
       mov      r14, rax
       lea      rcx, [rbp-0x88]
       call     [VmTest.Value:AsNumber():double:this]
       vmovddup xmm1, xmm0
       vmovddup xmm2, xmm0
       vmovddup xmm0, xmm0
       vcmppd   xmm1, xmm2, xmm1, 0
       vandpd   xmm0, xmm1, xmm0
       vcmppd   xmm1, xmm0, xmmword ptr [reloc @RWD00], 13
       vcvttsd2si ecx, xmm0
       vmovd    xmm0, ecx
       vpbroadcastd xmm0, xmm0
       vpblendvb xmm0, xmm0, xmmword ptr [reloc @RWD16], xmm1
       vmovd    edx, xmm0
       mov      rcx, r14
       cmp      dword ptr [rcx], ecx
       call     [System.Collections.Generic.List`1[VmTest.Value]:get_Item(int):VmTest.Value:this]
       mov      rdx, rax
       mov      rcx, rbx
       call     [VmTest.VirtualMachine:Push(VmTest.Value):this]
       jmp      G_M000_IG148

10.0.100-preview.4.25258.110:

G_M000_IG67:
       call     [VmTest.VmObjectList:get_Items():System.Collections.Generic.List`1[VmTest.Value]:this]
       mov      r14, rax
       lea      rcx, [rbp-0x88]
       call     [VmTest.Value:AsNumber():double:this]
       vcmpsd   xmm1, xmm0, xmm0, 7
       vandpd   xmm1, xmm1, xmm0
       mov      ecx, 0xD1FFAB1E
       vcvttsd2si edx, xmm1
       vucomisd xmm0, qword ptr [reloc @RWD00]
       cmovb    ecx, edx
       mov      edx, ecx
       mov      rcx, r14
       cmp      dword ptr [rcx], ecx
       call     [System.Collections.Generic.List`1[VmTest.Value]:get_Item(int):VmTest.Value:this]
       mov      rdx, rax
       mov      rcx, rbx
       call     [VmTest.VirtualMachine:Push(VmTest.Value):this]
       jmp      G_M000_IG148

These are a few times in the diff. The problem seems to occur with and without native AOT.

Reproduction Steps

If desired I can send the project to an MS employee or maybe try to create a minimal project and create a public repository. I want to have it as an open-source project, but currently it's more of a testing ground.

Expected behavior

The executed program should execute like before with 10.0.100-preview.3.25201.16 and .NET 9.

Source code of the custom language:

number counter = 0

for i in 0..1_500
	counter += 1

WriteLine("Counter: {counter}")

Output working program (with .NET 9 and .NET 10 preview 3):

FunctionRegistry:Load took 5 ms
ClassRegistry:Load took 1 ms
Counter: 1500

Actual behavior

Source code of the custom language:

number counter = 0

for i in 0..1_500
	counter += 1

WriteLine("Counter: {counter}")

Output of not working program (with .NET 10 preview 4):

FunctionRegistry:Load took 5 ms
ClassRegistry:Load took 1 ms
Unhandled exception. VmTest.Exceptions.RuntimeException: RuntimeError: Unsupported operator type + for left '1427' and right '1'
   at VmTest.VirtualMachine.Execute() in C:\Users\{USER}\source\repos\VmTest\VmTest\VirtualMachine.cs:line 314
   at Program.<Main>$(String[] args) in C:\Users\{USER}\source\repos\VmTest\VmTest\Program.cs:line 40

As you can see, the left and right operand are both ints (numbers in my language).

Interesting enough is that it does not occur with a lower iteration count like for example 1000.

Regression?

Maybe, it woks with -c Release with 10.0.100-preview.3.25201.16 and fails with 10.0.100-preview.4.25258.110

Known Workarounds

Use .NET 10 preview 3 or run in debug mode.

Configuration

OS: Windows 11 23H2
Architecture: x64

Working:
.NET 9 and 10.0.100-preview.3.25201.16

Not working in release mode (works in debug mode):

= 10.0.100-preview.4.25258.110

Other information

If you have any questions or things I can provide or test please let me know.

Metadata

Metadata

Assignees

Labels

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

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions