-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Test failure: JIT/IL_Conformance/Convert/TestConvertFromIntegral/TestConvertFromIntegral.dll #112329
Comments
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
I suspect this is a register allocation issue. Test output:
Repros with the following:
cc @dotnet/jit-contrib |
@kunalspathak, PTAL. |
This might be fixed by #112217. I would wait for that to go in before starting to work on a different fix. |
Failed in: runtime-coreclr r2r-extra 20250209.1 Failed tests:
Error message:
Stack trace:
|
Failed in: runtime-coreclr r2r-extra 20250215.1 Failed tests:
Error message:
Stack trace:
|
Failed in: runtime-coreclr r2r-extra 20250216.1 Failed tests:
Error message:
Stack trace:
|
Looks like that didn't fix it. Since this only reproduces with using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Reflection;
using System.Reflection.Emit;
class Program
{
static int failedCount;
const bool ExpectException = true;
const bool DontExpectException = false;
const bool UnspecifiedBehaviour = true;
[MethodImpl(MethodImplOptions.NoInlining)]
static void GenerateTest<F, T>(F from, OpCode fromOpcode, OpCode convOpcode, bool exceptionExpected, T expectedTo, bool undefined = false) where F : struct where T : struct, IEquatable<T>
{
bool checkResult = !exceptionExpected && !undefined;
Debug.Assert(!exceptionExpected || !checkResult);
Debug.Assert(checkResult || expectedTo.Equals(default(T)));
Type[] args = Array.Empty<Type>(); // No args.
Type returnType = typeof(T);
string name = "DynamicConvertFrom" + typeof(F).FullName + "To" + typeof(T).FullName + from.ToString() + expectedTo.ToString() + "Op" + convOpcode.Name;
DynamicMethod dm = new DynamicMethod(name, returnType, args);
ILGenerator generator = dm.GetILGenerator();
if (typeof(F) == typeof(int)) generator.Emit(fromOpcode, (int)(object)from);
else if (typeof(F) == typeof(long)) generator.Emit(fromOpcode, (long)(object)from);
else if (typeof(F) == typeof(nint)) generator.Emit(fromOpcode, (nint)(object)from);
else if (typeof(F) == typeof(float)) generator.Emit(fromOpcode, (float)(object)from);
else if (typeof(F) == typeof(double)) generator.Emit(fromOpcode, (double)(object)from);
else
{
throw new NotSupportedException();
}
generator.Emit(convOpcode);
generator.Emit(OpCodes.Ret);
try
{
T res = (T)dm.Invoke(null, BindingFlags.Default, null, Array.Empty<object>(), null);
Console.WriteLine("Expected: " + expectedTo + " Actual: " + res);
if (exceptionExpected)
{
failedCount++;
Console.WriteLine("No exception in " + name);
}
if (checkResult && !expectedTo.Equals(res))
{
failedCount++;
Console.WriteLine("Wrong result in " + name);
}
}
catch
{
if (!exceptionExpected)
{
failedCount++;
Console.WriteLine("Not expected exception in " + name);
}
}
}
public static void Main()
{
OpCode sourceOp = OpCodes.Ldc_R4;
OpCode convOvf = OpCodes.Conv_Ovf_U1;
GenerateTest<float, byte>(1F, sourceOp, convOvf, DontExpectException, 1);
GenerateTest<float, byte>(1.9F, sourceOp, convOvf, DontExpectException, 1);
GenerateTest<float, byte>(sbyte.MaxValue, sourceOp, convOvf, DontExpectException, (byte)sbyte.MaxValue);
GenerateTest<float, byte>(byte.MaxValue, sourceOp, convOvf, DontExpectException, byte.MaxValue);
GenerateTest<float, byte>(byte.MinValue, sourceOp, convOvf, DontExpectException, byte.MinValue);
GenerateTest<float, byte>(long.MaxValue, sourceOp, convOvf, ExpectException, 0);
GenerateTest<float, byte>(long.MinValue, sourceOp, convOvf, ExpectException, 0);
GenerateTest<float, byte>(Single.NaN, sourceOp, convOvf, ExpectException, 0);
OpCode convOvfUn = OpCodes.Conv_Ovf_U1_Un;
GenerateTest<float, byte>(1F, sourceOp, convOvfUn, DontExpectException, 1); // BAD
GenerateTest<float, byte>(2.2F, sourceOp, convOvfUn, DontExpectException, 2);
GenerateTest<float, byte>(sbyte.MaxValue, sourceOp, convOvfUn, DontExpectException, (byte)sbyte.MaxValue);
GenerateTest<float, byte>(byte.MaxValue, sourceOp, convOvfUn, DontExpectException, byte.MaxValue);
GenerateTest<float, byte>(byte.MinValue, sourceOp, convOvfUn, DontExpectException, byte.MinValue);
}
} |
Hello. What's the best way to repro duce this locally? I did the following and don't see the failure It would be helpful to know the exact repro steps ` |
you can just create a hello world app with code provided by @amanasifkhalid and run with those environment variables set. |
@DeepakRajendrakumaran your method of building and running the IL conformance tests should work, too. Could you please try rebuilding them without passing the |
Tried that. Didn't help |
Still passing. Do you happen to know which exact x86 machine you're using? |
I'm able to repro this on an AMD EPYC 7763. |
Thanks for the information. I'm not exactly sure what I'm missing. Can you check this- https://godbolt.org/z/n4danr8a3 . I would have expected the fail to show up here as well. |
FYI, the overrides tab doesn't work on compiler explorer for C#. You have to pass environment variables in the compiler flags, like this: https://godbolt.org/z/KKE5fKvnY But it doesn't repro there anyway because it's Linux, and this looks to be an issue with callee-saved regs on Windows. Here's the relevant asm from Main on a failing run: mov rbx, 0xD1FFAB1E ; data for System.Reflection.Emit.OpCodes:Conv_Ovf_U1_Un
mov esi, dword ptr [rbx]
mov ebx, dword ptr [rbx+0x04]
mov dword ptr [rsp+0x30], esi
mov dword ptr [rsp+0x34], ebx
mov dword ptr [rsp+0x20], 1
xor ebx, ebx
mov dword ptr [rsp+0x28], ebx
mov rbx, qword ptr [rsp+0x38]
mov rdx, rbx
mov rbx, qword ptr [rsp+0x30]
mov r8, rbx
vmovaps xmm0, xmm6 ; <---------- problem here, xmm6 has bad value
xor ebx, ebx
mov r9d, ebx
call [Programz:GenerateTest[float,ubyte](float,System.Reflection.Emit.OpCode,System.Reflection.Emit.OpCode,ubyte,ubyte,ubyte)] xmm6 was loaded with the vmovss xmm6, dword ptr [reloc @RWD00] but apparently got clobbered by one of the calls in between, leaving it with a zero value, and causing the dynamic compiled conversion method to compile to const ; Assembly listing for method (dynamicClass):DynamicConvertFromSystem.SingleToSystem.Byte01Opconv.ovf.u1.un():ubyte (FullOpts)
; Emitting BLENDED_CODE for X64 with AVX512 - Windows
; FullOpts code
; optimized code
; rsp based frame
; partially interruptible
; No PGO data
; Final local variable assignments
;
;# V00 OutArgs [V00 ] ( 1, 1 ) struct ( 0) [rsp+0x00] do-not-enreg[XS] addr-exposed "OutgoingArgSpace" <Empty>
;
; Lcl frame size = 0
G_M41797_IG01: ;; offset=0x0000
push rbx
;; size=1 bbWeight=1 PerfScore 1.00
G_M41797_IG02: ;; offset=0x0001
xor ebx, ebx
mov eax, ebx
;; size=4 bbWeight=1 PerfScore 0.50
G_M41797_IG03: ;; offset=0x0005
pop rbx
ret
;; size=2 bbWeight=1 PerfScore 1.50
; Total bytes of code 7, prolog size 1, PerfScore 3.00, instruction count 5, allocated bytes for code 7 (MethodHash=4ba45cba) for method (dynamicClass):DynamicConvertFromSystem.SingleToSystem.Byte01Opconv.ovf.u1.un():ubyte (FullOpts)
; ============================================================ Resulting in this output:
|
@saucecontrol Thank you for the above. This really helps. I went through my PR and went over any parts likely to touch ABI logic. The parts I touched were all dealing only with |
There was nothing special to the repro, I'm afraid. Just: Core_Root build:
Repro build:
Run:
Running a build from c153833, I've gotten the above failure every time (a few times I've had a second failure as well). Tested the following, all with the same results:
|
FWIW, I ran with |
Second failure reproduces reliably for me with
|
I'm able to repro now. I should be able to figure it out from here :) Thank you. Appreciate the help |
A simplified repro.
|
@kunalspathak identified the issue and has a PR - #112799 This is due to a bug in the unwind code not working correctly due to change is regnum as a result of newly added registers. In the example above, Internally,
Here, we can see that we are handling |
fixed by #112799 |
Failed in: runtime-coreclr r2r-extra 20250208.1
Failed tests:
Error message:
Stack trace:
The text was updated successfully, but these errors were encountered: