From c08f182bc90b0d32279201b7de89658765e3f6e8 Mon Sep 17 00:00:00 2001 From: Bruce Forstall Date: Fri, 8 Mar 2019 17:58:54 -0800 Subject: [PATCH] Arm64: Implement JMP call for HFA register arguments Add the code to load up HFA register arguments into their correct registers before a JMP call. Removes remaining NYI. Fixes #23147 Add a test case with several variants of HFA and JMP call. --- src/jit/codegenarmarch.cpp | 84 ++- .../JitBlue/GitHub_23147/GitHub_23147.cs.txt | 342 ++++++++++ .../JitBlue/GitHub_23147/GitHub_23147.il | 696 +++++++++++++++++++++ .../JitBlue/GitHub_23147/GitHub_23147.ilproj | 25 + 4 files changed, 1116 insertions(+), 31 deletions(-) create mode 100644 tests/src/JIT/Regression/JitBlue/GitHub_23147/GitHub_23147.cs.txt create mode 100644 tests/src/JIT/Regression/JitBlue/GitHub_23147/GitHub_23147.il create mode 100644 tests/src/JIT/Regression/JitBlue/GitHub_23147/GitHub_23147.ilproj diff --git a/src/jit/codegenarmarch.cpp b/src/jit/codegenarmarch.cpp index 5e50e92..5018013 100644 --- a/src/jit/codegenarmarch.cpp +++ b/src/jit/codegenarmarch.cpp @@ -2675,47 +2675,68 @@ void CodeGen::genJmpMethod(GenTree* jmp) if (varDsc->lvRegNum != argReg) { var_types loadType = TYP_UNDEF; - if (varTypeIsStruct(varDsc)) - { - // Must be <= 16 bytes or else it wouldn't be passed in registers - noway_assert(EA_SIZE_IN_BYTES(varDsc->lvSize()) <= MAX_PASS_MULTIREG_BYTES); - loadType = compiler->getJitGCType(varDsc->lvGcLayout[0]); - } - else + + if (varDsc->lvIsHfaRegArg()) { - loadType = compiler->mangleVarArgsType(genActualType(varDsc->TypeGet())); - } - emitAttr loadSize = emitActualTypeSize(loadType); - getEmitter()->emitIns_R_S(ins_Load(loadType), loadSize, argReg, varNum, 0); + // Note that for HFA, the argument is currently marked address exposed so lvRegNum will always be + // REG_STK. We home the incoming HFA argument registers in the prolog. Then we'll load them back + // here, whether they are already in the correct registers or not. This is such a corner case that + // it is not worth optimizing it. - // Update argReg life and GC Info to indicate varDsc stack slot is dead and argReg is going live. - // Note that we cannot modify varDsc->lvRegNum here because another basic block may not be expecting it. - // Therefore manually update life of argReg. Note that GT_JMP marks the end of the basic block - // and after which reg life and gc info will be recomputed for the new block in genCodeForBBList(). - regSet.AddMaskVars(genRegMask(argReg)); - gcInfo.gcMarkRegPtrVal(argReg, loadType); + assert(!compiler->info.compIsVarArgs); - if (compiler->lvaIsMultiregStruct(varDsc, compiler->info.compIsVarArgs)) + loadType = varDsc->GetHfaType(); + regNumber fieldReg = argReg; + emitAttr loadSize = emitActualTypeSize(loadType); + unsigned cSlots = varDsc->lvHfaSlots(); + + for (unsigned ofs = 0, cSlot = 0; cSlot < cSlots; cSlot++, ofs += (unsigned)loadSize) + { + getEmitter()->emitIns_R_S(ins_Load(loadType), loadSize, fieldReg, varNum, ofs); + assert(genIsValidFloatReg(fieldReg)); // No GC register tracking for floating point registers. + fieldReg = regNextOfType(fieldReg, loadType); + } + } + else { - if (varDsc->lvIsHfa()) + if (varTypeIsStruct(varDsc)) + { + // Must be <= 16 bytes or else it wouldn't be passed in registers, except for HFA, + // which can be bigger (and is handled above). + noway_assert(EA_SIZE_IN_BYTES(varDsc->lvSize()) <= 16); + loadType = compiler->getJitGCType(varDsc->lvGcLayout[0]); + } + else { - NYI_ARM64("CodeGen::genJmpMethod with multireg HFA arg"); + loadType = compiler->mangleVarArgsType(genActualType(varDsc->TypeGet())); } + emitAttr loadSize = emitActualTypeSize(loadType); + getEmitter()->emitIns_R_S(ins_Load(loadType), loadSize, argReg, varNum, 0); + + // Update argReg life and GC Info to indicate varDsc stack slot is dead and argReg is going live. + // Note that we cannot modify varDsc->lvRegNum here because another basic block may not be expecting it. + // Therefore manually update life of argReg. Note that GT_JMP marks the end of the basic block + // and after which reg life and gc info will be recomputed for the new block in genCodeForBBList(). + regSet.AddMaskVars(genRegMask(argReg)); + gcInfo.gcMarkRegPtrVal(argReg, loadType); - // Restore the second register. - argRegNext = genRegArgNext(argReg); + if (compiler->lvaIsMultiregStruct(varDsc, compiler->info.compIsVarArgs)) + { + // Restore the second register. + argRegNext = genRegArgNext(argReg); - loadType = compiler->getJitGCType(varDsc->lvGcLayout[1]); - loadSize = emitActualTypeSize(loadType); - getEmitter()->emitIns_R_S(ins_Load(loadType), loadSize, argRegNext, varNum, TARGET_POINTER_SIZE); + loadType = compiler->getJitGCType(varDsc->lvGcLayout[1]); + loadSize = emitActualTypeSize(loadType); + getEmitter()->emitIns_R_S(ins_Load(loadType), loadSize, argRegNext, varNum, TARGET_POINTER_SIZE); - regSet.AddMaskVars(genRegMask(argRegNext)); - gcInfo.gcMarkRegPtrVal(argRegNext, loadType); - } + regSet.AddMaskVars(genRegMask(argRegNext)); + gcInfo.gcMarkRegPtrVal(argRegNext, loadType); + } - if (compiler->lvaIsGCTracked(varDsc)) - { - VarSetOps::RemoveElemD(compiler, gcInfo.gcVarPtrSetCur, varDsc->lvVarIndex); + if (compiler->lvaIsGCTracked(varDsc)) + { + VarSetOps::RemoveElemD(compiler, gcInfo.gcVarPtrSetCur, varDsc->lvVarIndex); + } } } @@ -2723,6 +2744,7 @@ void CodeGen::genJmpMethod(GenTree* jmp) { // In case of a jmp call to a vararg method ensure only integer registers are passed. assert((genRegMask(argReg) & (RBM_ARG_REGS | RBM_ARG_RET_BUFF)) != RBM_NONE); + assert(!varDsc->lvIsHfaRegArg()); fixedIntArgMask |= genRegMask(argReg); diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_23147/GitHub_23147.cs.txt b/tests/src/JIT/Regression/JitBlue/GitHub_23147/GitHub_23147.cs.txt new file mode 100644 index 0000000..6799607 --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_23147/GitHub_23147.cs.txt @@ -0,0 +1,342 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; + +// Test case to generate a function with a JMP call and register HFA arguments. +// Also, make sure the HFA register arguments need to be re-loaded from +// the stack into registers. Make another call before the final JMP call +// to clear the argument registers. This was designed to test an NYI in +// the ARM64 JIT compiler. +// +// Note that this is the C# code; to generate the actual test case, you +// need to "ildasm" the generated EXE from this C# code, then manually convert the +// final call in each of the "jmp_test_*" functions to a JMP. +// The test case code will be an IL file. + +namespace Test +{ + struct HFA_f2 + { + public float f1; + public float f2; + } + struct HFA_f3 + { + public float f1; + public float f2; + public float f3; + } + struct HFA_f4 + { + public float f1; + public float f2; + public float f3; + public float f4; + } + struct HFA_d2 + { + public double d1; + public double d2; + } + struct HFA_d3 + { + public double d1; + public double d2; + public double d3; + } + struct HFA_d4 + { + public double d1; + public double d2; + public double d3; + public double d4; + } + + class X + { + public static float fx1; + public static float fx2; + public static float fx3; + public static float fx4; + public static double dx1; + public static double dx2; + public static double dx3; + public static double dx4; + + // arm64 has 8 int and 8 float argument registers. Create a function + // call that requires using all of them. + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static void clear_argument_regs( + int i1, + int i2, + int i3, + int i4, + int i5, + int i6, + int i7, + int i8, + int i9, // make sure something is on the stack + double f1, + double f2, + double f3, + double f4, + double f5, + double f6, + double f7, + double f8, + double f9) // make sure something is on the stack + { + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static int test_f2(HFA_f2 a) + { + if ((a.f1 == fx1) && (a.f2 == fx2)) + { + // pass + return 100; + } + else + { + // fail + return 1; + } + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static int test_f3(HFA_f3 a) + { + if ((a.f1 == fx1) && (a.f2 == fx2) && (a.f3 == fx3)) + { + // pass + return 100; + } + else + { + // fail + return 1; + } + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static int test_f4(HFA_f4 a) + { + if ((a.f1 == fx1) && (a.f2 == fx2) && (a.f3 == fx3) && (a.f4 == fx4)) + { + // pass + return 100; + } + else + { + // fail + return 1; + } + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static int test_d2(HFA_d2 a) + { + if ((a.d1 == dx1) && (a.d2 == dx2)) + { + // pass + return 100; + } + else + { + // fail + return 1; + } + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static int test_d3(HFA_d3 a) + { + if ((a.d1 == dx1) && (a.d2 == dx2) && (a.d3 == dx3)) + { + // pass + return 100; + } + else + { + // fail + return 1; + } + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static int test_d4(HFA_d4 a) + { + if ((a.d1 == dx1) && (a.d2 == dx2) && (a.d3 == dx3) && (a.d4 == dx4)) + { + // pass + return 100; + } + else + { + // fail + return 1; + } + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static int jmp_test_f2(HFA_f2 a) + { + clear_argument_regs(1,2,3,4,5,6,7,8,9,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0); + return test_f2(a); // CONVERT THIS TO JMP CALL! + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static int jmp_test_f3(HFA_f3 a) + { + clear_argument_regs(1,2,3,4,5,6,7,8,9,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0); + return test_f3(a); // CONVERT THIS TO JMP CALL! + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static int jmp_test_f4(HFA_f4 a) + { + clear_argument_regs(1,2,3,4,5,6,7,8,9,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0); + return test_f4(a); // CONVERT THIS TO JMP CALL! + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static int jmp_test_d2(HFA_d2 a) + { + clear_argument_regs(1,2,3,4,5,6,7,8,9,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0); + return test_d2(a); // CONVERT THIS TO JMP CALL! + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static int jmp_test_d3(HFA_d3 a) + { + clear_argument_regs(1,2,3,4,5,6,7,8,9,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0); + return test_d3(a); // CONVERT THIS TO JMP CALL! + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static int jmp_test_d4(HFA_d4 a) + { + clear_argument_regs(1,2,3,4,5,6,7,8,9,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0); + return test_d4(a); // CONVERT THIS TO JMP CALL! + } + + public static int Main() + { + fx1 = 1.1F; + fx2 = 2.2F; + fx3 = 3.3F; + fx4 = 4.4F; + + dx1 = 1.0; + dx2 = 2.0; + dx3 = 3.0; + dx4 = 4.0; + + HFA_f2 hf2 = new HFA_f2(); + hf2.f1 = fx1; + hf2.f2 = fx2; + + HFA_f3 hf3 = new HFA_f3(); + hf3.f1 = fx1; + hf3.f2 = fx2; + hf3.f3 = fx3; + + HFA_f4 hf4 = new HFA_f4(); + hf4.f1 = fx1; + hf4.f2 = fx2; + hf4.f3 = fx3; + hf4.f4 = fx4; + + HFA_d2 hd2 = new HFA_d2(); + hd2.d1 = dx1; + hd2.d2 = dx2; + + HFA_d3 hd3 = new HFA_d3(); + hd3.d1 = dx1; + hd3.d2 = dx2; + hd3.d3 = dx3; + + HFA_d4 hd4 = new HFA_d4(); + hd4.d1 = dx1; + hd4.d2 = dx2; + hd4.d3 = dx3; + hd4.d4 = dx4; + + int final_result = 100; // assume pass + int result; + + result = jmp_test_f2(hf2); + if (result == 100) + { + Console.WriteLine("jmp_test_f2 PASS"); + } + else + { + Console.WriteLine("jmp_test_f2 FAIL"); + final_result = 1; + } + + result = jmp_test_f3(hf3); + if (result == 100) + { + Console.WriteLine("jmp_test_f3 PASS"); + } + else + { + Console.WriteLine("jmp_test_f3 FAIL"); + final_result = 1; + } + + result = jmp_test_f4(hf4); + if (result == 100) + { + Console.WriteLine("jmp_test_f4 PASS"); + } + else + { + Console.WriteLine("jmp_test_f4 FAIL"); + final_result = 1; + } + + result = jmp_test_d2(hd2); + if (result == 100) + { + Console.WriteLine("jmp_test_d2 PASS"); + } + else + { + Console.WriteLine("jmp_test_d2 FAIL"); + final_result = 1; + } + + result = jmp_test_d3(hd3); + if (result == 100) + { + Console.WriteLine("jmp_test_d3 PASS"); + } + else + { + Console.WriteLine("jmp_test_d3 FAIL"); + final_result = 1; + } + + result = jmp_test_d4(hd4); + if (result == 100) + { + Console.WriteLine("jmp_test_d4 PASS"); + } + else + { + Console.WriteLine("jmp_test_d4 FAIL"); + final_result = 1; + } + + return final_result; + } + + } + +} diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_23147/GitHub_23147.il b/tests/src/JIT/Regression/JitBlue/GitHub_23147/GitHub_23147.il new file mode 100644 index 0000000..1298444 --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_23147/GitHub_23147.il @@ -0,0 +1,696 @@ +.assembly extern System.Runtime { } +.assembly extern System.Console +{ +} + +.assembly GitHub_23147 +{ +} +.module GitHub_23147.exe + +.class private sequential ansi sealed beforefieldinit Test.HFA_f2 + extends [System.Runtime]System.ValueType +{ + .field public float32 f1 + .field public float32 f2 +} // end of class Test.HFA_f2 + +.class private sequential ansi sealed beforefieldinit Test.HFA_f3 + extends [System.Runtime]System.ValueType +{ + .field public float32 f1 + .field public float32 f2 + .field public float32 f3 +} // end of class Test.HFA_f3 + +.class private sequential ansi sealed beforefieldinit Test.HFA_f4 + extends [System.Runtime]System.ValueType +{ + .field public float32 f1 + .field public float32 f2 + .field public float32 f3 + .field public float32 f4 +} // end of class Test.HFA_f4 + +.class private sequential ansi sealed beforefieldinit Test.HFA_d2 + extends [System.Runtime]System.ValueType +{ + .field public float64 d1 + .field public float64 d2 +} // end of class Test.HFA_d2 + +.class private sequential ansi sealed beforefieldinit Test.HFA_d3 + extends [System.Runtime]System.ValueType +{ + .field public float64 d1 + .field public float64 d2 + .field public float64 d3 +} // end of class Test.HFA_d3 + +.class private sequential ansi sealed beforefieldinit Test.HFA_d4 + extends [System.Runtime]System.ValueType +{ + .field public float64 d1 + .field public float64 d2 + .field public float64 d3 + .field public float64 d4 +} // end of class Test.HFA_d4 + +.class private auto ansi beforefieldinit Test.X + extends [System.Runtime]System.Object +{ + .field public static float32 fx1 + .field public static float32 fx2 + .field public static float32 fx3 + .field public static float32 fx4 + .field public static float64 dx1 + .field public static float64 dx2 + .field public static float64 dx3 + .field public static float64 dx4 + .method public hidebysig static void clear_argument_regs(int32 i1, + int32 i2, + int32 i3, + int32 i4, + int32 i5, + int32 i6, + int32 i7, + int32 i8, + int32 i9, + float64 f1, + float64 f2, + float64 f3, + float64 f4, + float64 f5, + float64 f6, + float64 f7, + float64 f8, + float64 f9) cil managed noinlining + { + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method X::clear_argument_regs + + .method public hidebysig static int32 test_f2(valuetype Test.HFA_f2 a) cil managed noinlining + { + // Code size 31 (0x1f) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld float32 Test.HFA_f2::f1 + IL_0006: ldsfld float32 Test.X::fx1 + IL_000b: bne.un.s IL_001d + + IL_000d: ldarg.0 + IL_000e: ldfld float32 Test.HFA_f2::f2 + IL_0013: ldsfld float32 Test.X::fx2 + IL_0018: bne.un.s IL_001d + + IL_001a: ldc.i4.s 100 + IL_001c: ret + + IL_001d: ldc.i4.1 + IL_001e: ret + } // end of method X::test_f2 + + .method public hidebysig static int32 test_f3(valuetype Test.HFA_f3 a) cil managed noinlining + { + // Code size 44 (0x2c) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld float32 Test.HFA_f3::f1 + IL_0006: ldsfld float32 Test.X::fx1 + IL_000b: bne.un.s IL_002a + + IL_000d: ldarg.0 + IL_000e: ldfld float32 Test.HFA_f3::f2 + IL_0013: ldsfld float32 Test.X::fx2 + IL_0018: bne.un.s IL_002a + + IL_001a: ldarg.0 + IL_001b: ldfld float32 Test.HFA_f3::f3 + IL_0020: ldsfld float32 Test.X::fx3 + IL_0025: bne.un.s IL_002a + + IL_0027: ldc.i4.s 100 + IL_0029: ret + + IL_002a: ldc.i4.1 + IL_002b: ret + } // end of method X::test_f3 + + .method public hidebysig static int32 test_f4(valuetype Test.HFA_f4 a) cil managed noinlining + { + // Code size 57 (0x39) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld float32 Test.HFA_f4::f1 + IL_0006: ldsfld float32 Test.X::fx1 + IL_000b: bne.un.s IL_0037 + + IL_000d: ldarg.0 + IL_000e: ldfld float32 Test.HFA_f4::f2 + IL_0013: ldsfld float32 Test.X::fx2 + IL_0018: bne.un.s IL_0037 + + IL_001a: ldarg.0 + IL_001b: ldfld float32 Test.HFA_f4::f3 + IL_0020: ldsfld float32 Test.X::fx3 + IL_0025: bne.un.s IL_0037 + + IL_0027: ldarg.0 + IL_0028: ldfld float32 Test.HFA_f4::f4 + IL_002d: ldsfld float32 Test.X::fx4 + IL_0032: bne.un.s IL_0037 + + IL_0034: ldc.i4.s 100 + IL_0036: ret + + IL_0037: ldc.i4.1 + IL_0038: ret + } // end of method X::test_f4 + + .method public hidebysig static int32 test_d2(valuetype Test.HFA_d2 a) cil managed noinlining + { + // Code size 31 (0x1f) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld float64 Test.HFA_d2::d1 + IL_0006: ldsfld float64 Test.X::dx1 + IL_000b: bne.un.s IL_001d + + IL_000d: ldarg.0 + IL_000e: ldfld float64 Test.HFA_d2::d2 + IL_0013: ldsfld float64 Test.X::dx2 + IL_0018: bne.un.s IL_001d + + IL_001a: ldc.i4.s 100 + IL_001c: ret + + IL_001d: ldc.i4.1 + IL_001e: ret + } // end of method X::test_d2 + + .method public hidebysig static int32 test_d3(valuetype Test.HFA_d3 a) cil managed noinlining + { + // Code size 44 (0x2c) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld float64 Test.HFA_d3::d1 + IL_0006: ldsfld float64 Test.X::dx1 + IL_000b: bne.un.s IL_002a + + IL_000d: ldarg.0 + IL_000e: ldfld float64 Test.HFA_d3::d2 + IL_0013: ldsfld float64 Test.X::dx2 + IL_0018: bne.un.s IL_002a + + IL_001a: ldarg.0 + IL_001b: ldfld float64 Test.HFA_d3::d3 + IL_0020: ldsfld float64 Test.X::dx3 + IL_0025: bne.un.s IL_002a + + IL_0027: ldc.i4.s 100 + IL_0029: ret + + IL_002a: ldc.i4.1 + IL_002b: ret + } // end of method X::test_d3 + + .method public hidebysig static int32 test_d4(valuetype Test.HFA_d4 a) cil managed noinlining + { + // Code size 57 (0x39) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld float64 Test.HFA_d4::d1 + IL_0006: ldsfld float64 Test.X::dx1 + IL_000b: bne.un.s IL_0037 + + IL_000d: ldarg.0 + IL_000e: ldfld float64 Test.HFA_d4::d2 + IL_0013: ldsfld float64 Test.X::dx2 + IL_0018: bne.un.s IL_0037 + + IL_001a: ldarg.0 + IL_001b: ldfld float64 Test.HFA_d4::d3 + IL_0020: ldsfld float64 Test.X::dx3 + IL_0025: bne.un.s IL_0037 + + IL_0027: ldarg.0 + IL_0028: ldfld float64 Test.HFA_d4::d4 + IL_002d: ldsfld float64 Test.X::dx4 + IL_0032: bne.un.s IL_0037 + + IL_0034: ldc.i4.s 100 + IL_0036: ret + + IL_0037: ldc.i4.1 + IL_0038: ret + } // end of method X::test_d4 + + .method public hidebysig static int32 jmp_test_f2(valuetype Test.HFA_f2 a) cil managed noinlining + { + // Code size 103 (0x67) + .maxstack 18 + IL_0000: ldc.i4.1 + IL_0001: ldc.i4.2 + IL_0002: ldc.i4.3 + IL_0003: ldc.i4.4 + IL_0004: ldc.i4.5 + IL_0005: ldc.i4.6 + IL_0006: ldc.i4.7 + IL_0007: ldc.i4.8 + IL_0008: ldc.i4.s 9 + IL_000a: ldc.r8 1. + IL_0013: ldc.r8 2. + IL_001c: ldc.r8 3. + IL_0025: ldc.r8 4. + IL_002e: ldc.r8 5. + IL_0037: ldc.r8 6. + IL_0040: ldc.r8 7. + IL_0049: ldc.r8 8. + IL_0052: ldc.r8 9. + IL_005b: call void Test.X::clear_argument_regs(int32, + int32, + int32, + int32, + int32, + int32, + int32, + int32, + int32, + float64, + float64, + float64, + float64, + float64, + float64, + float64, + float64, + float64) + jmp int32 Test.X::test_f2(valuetype Test.HFA_f2) + } // end of method X::jmp_test_f2 + + .method public hidebysig static int32 jmp_test_f3(valuetype Test.HFA_f3 a) cil managed noinlining + { + // Code size 103 (0x67) + .maxstack 18 + IL_0000: ldc.i4.1 + IL_0001: ldc.i4.2 + IL_0002: ldc.i4.3 + IL_0003: ldc.i4.4 + IL_0004: ldc.i4.5 + IL_0005: ldc.i4.6 + IL_0006: ldc.i4.7 + IL_0007: ldc.i4.8 + IL_0008: ldc.i4.s 9 + IL_000a: ldc.r8 1. + IL_0013: ldc.r8 2. + IL_001c: ldc.r8 3. + IL_0025: ldc.r8 4. + IL_002e: ldc.r8 5. + IL_0037: ldc.r8 6. + IL_0040: ldc.r8 7. + IL_0049: ldc.r8 8. + IL_0052: ldc.r8 9. + IL_005b: call void Test.X::clear_argument_regs(int32, + int32, + int32, + int32, + int32, + int32, + int32, + int32, + int32, + float64, + float64, + float64, + float64, + float64, + float64, + float64, + float64, + float64) + jmp int32 Test.X::test_f3(valuetype Test.HFA_f3) + } // end of method X::jmp_test_f3 + + .method public hidebysig static int32 jmp_test_f4(valuetype Test.HFA_f4 a) cil managed noinlining + { + // Code size 103 (0x67) + .maxstack 18 + IL_0000: ldc.i4.1 + IL_0001: ldc.i4.2 + IL_0002: ldc.i4.3 + IL_0003: ldc.i4.4 + IL_0004: ldc.i4.5 + IL_0005: ldc.i4.6 + IL_0006: ldc.i4.7 + IL_0007: ldc.i4.8 + IL_0008: ldc.i4.s 9 + IL_000a: ldc.r8 1. + IL_0013: ldc.r8 2. + IL_001c: ldc.r8 3. + IL_0025: ldc.r8 4. + IL_002e: ldc.r8 5. + IL_0037: ldc.r8 6. + IL_0040: ldc.r8 7. + IL_0049: ldc.r8 8. + IL_0052: ldc.r8 9. + IL_005b: call void Test.X::clear_argument_regs(int32, + int32, + int32, + int32, + int32, + int32, + int32, + int32, + int32, + float64, + float64, + float64, + float64, + float64, + float64, + float64, + float64, + float64) + jmp int32 Test.X::test_f4(valuetype Test.HFA_f4) + } // end of method X::jmp_test_f4 + + .method public hidebysig static int32 jmp_test_d2(valuetype Test.HFA_d2 a) cil managed noinlining + { + // Code size 103 (0x67) + .maxstack 18 + IL_0000: ldc.i4.1 + IL_0001: ldc.i4.2 + IL_0002: ldc.i4.3 + IL_0003: ldc.i4.4 + IL_0004: ldc.i4.5 + IL_0005: ldc.i4.6 + IL_0006: ldc.i4.7 + IL_0007: ldc.i4.8 + IL_0008: ldc.i4.s 9 + IL_000a: ldc.r8 1. + IL_0013: ldc.r8 2. + IL_001c: ldc.r8 3. + IL_0025: ldc.r8 4. + IL_002e: ldc.r8 5. + IL_0037: ldc.r8 6. + IL_0040: ldc.r8 7. + IL_0049: ldc.r8 8. + IL_0052: ldc.r8 9. + IL_005b: call void Test.X::clear_argument_regs(int32, + int32, + int32, + int32, + int32, + int32, + int32, + int32, + int32, + float64, + float64, + float64, + float64, + float64, + float64, + float64, + float64, + float64) + jmp int32 Test.X::test_d2(valuetype Test.HFA_d2) + } // end of method X::jmp_test_d2 + + .method public hidebysig static int32 jmp_test_d3(valuetype Test.HFA_d3 a) cil managed noinlining + { + // Code size 103 (0x67) + .maxstack 18 + IL_0000: ldc.i4.1 + IL_0001: ldc.i4.2 + IL_0002: ldc.i4.3 + IL_0003: ldc.i4.4 + IL_0004: ldc.i4.5 + IL_0005: ldc.i4.6 + IL_0006: ldc.i4.7 + IL_0007: ldc.i4.8 + IL_0008: ldc.i4.s 9 + IL_000a: ldc.r8 1. + IL_0013: ldc.r8 2. + IL_001c: ldc.r8 3. + IL_0025: ldc.r8 4. + IL_002e: ldc.r8 5. + IL_0037: ldc.r8 6. + IL_0040: ldc.r8 7. + IL_0049: ldc.r8 8. + IL_0052: ldc.r8 9. + IL_005b: call void Test.X::clear_argument_regs(int32, + int32, + int32, + int32, + int32, + int32, + int32, + int32, + int32, + float64, + float64, + float64, + float64, + float64, + float64, + float64, + float64, + float64) + jmp int32 Test.X::test_d3(valuetype Test.HFA_d3) + } // end of method X::jmp_test_d3 + + .method public hidebysig static int32 jmp_test_d4(valuetype Test.HFA_d4 a) cil managed noinlining + { + // Code size 103 (0x67) + .maxstack 18 + IL_0000: ldc.i4.1 + IL_0001: ldc.i4.2 + IL_0002: ldc.i4.3 + IL_0003: ldc.i4.4 + IL_0004: ldc.i4.5 + IL_0005: ldc.i4.6 + IL_0006: ldc.i4.7 + IL_0007: ldc.i4.8 + IL_0008: ldc.i4.s 9 + IL_000a: ldc.r8 1. + IL_0013: ldc.r8 2. + IL_001c: ldc.r8 3. + IL_0025: ldc.r8 4. + IL_002e: ldc.r8 5. + IL_0037: ldc.r8 6. + IL_0040: ldc.r8 7. + IL_0049: ldc.r8 8. + IL_0052: ldc.r8 9. + IL_005b: call void Test.X::clear_argument_regs(int32, + int32, + int32, + int32, + int32, + int32, + int32, + int32, + int32, + float64, + float64, + float64, + float64, + float64, + float64, + float64, + float64, + float64) + jmp int32 Test.X::test_d4(valuetype Test.HFA_d4) + } // end of method X::jmp_test_d4 + + .method public hidebysig static int32 Main() cil managed + { + .entrypoint + // Code size 579 (0x243) + .maxstack 2 + .locals init (valuetype Test.HFA_f2 V_0, + valuetype Test.HFA_f3 V_1, + valuetype Test.HFA_f4 V_2, + valuetype Test.HFA_d2 V_3, + valuetype Test.HFA_d3 V_4, + valuetype Test.HFA_d4 V_5, + int32 V_6) + IL_0000: ldc.r4 1.1 + IL_0005: stsfld float32 Test.X::fx1 + IL_000a: ldc.r4 2.2 + IL_000f: stsfld float32 Test.X::fx2 + IL_0014: ldc.r4 3.3 + IL_0019: stsfld float32 Test.X::fx3 + IL_001e: ldc.r4 4.4000001 + IL_0023: stsfld float32 Test.X::fx4 + IL_0028: ldc.r8 1. + IL_0031: stsfld float64 Test.X::dx1 + IL_0036: ldc.r8 2. + IL_003f: stsfld float64 Test.X::dx2 + IL_0044: ldc.r8 3. + IL_004d: stsfld float64 Test.X::dx3 + IL_0052: ldc.r8 4. + IL_005b: stsfld float64 Test.X::dx4 + IL_0060: ldloca.s V_0 + IL_0062: initobj Test.HFA_f2 + IL_0068: ldloca.s V_0 + IL_006a: ldsfld float32 Test.X::fx1 + IL_006f: stfld float32 Test.HFA_f2::f1 + IL_0074: ldloca.s V_0 + IL_0076: ldsfld float32 Test.X::fx2 + IL_007b: stfld float32 Test.HFA_f2::f2 + IL_0080: ldloca.s V_1 + IL_0082: initobj Test.HFA_f3 + IL_0088: ldloca.s V_1 + IL_008a: ldsfld float32 Test.X::fx1 + IL_008f: stfld float32 Test.HFA_f3::f1 + IL_0094: ldloca.s V_1 + IL_0096: ldsfld float32 Test.X::fx2 + IL_009b: stfld float32 Test.HFA_f3::f2 + IL_00a0: ldloca.s V_1 + IL_00a2: ldsfld float32 Test.X::fx3 + IL_00a7: stfld float32 Test.HFA_f3::f3 + IL_00ac: ldloca.s V_2 + IL_00ae: initobj Test.HFA_f4 + IL_00b4: ldloca.s V_2 + IL_00b6: ldsfld float32 Test.X::fx1 + IL_00bb: stfld float32 Test.HFA_f4::f1 + IL_00c0: ldloca.s V_2 + IL_00c2: ldsfld float32 Test.X::fx2 + IL_00c7: stfld float32 Test.HFA_f4::f2 + IL_00cc: ldloca.s V_2 + IL_00ce: ldsfld float32 Test.X::fx3 + IL_00d3: stfld float32 Test.HFA_f4::f3 + IL_00d8: ldloca.s V_2 + IL_00da: ldsfld float32 Test.X::fx4 + IL_00df: stfld float32 Test.HFA_f4::f4 + IL_00e4: ldloca.s V_3 + IL_00e6: initobj Test.HFA_d2 + IL_00ec: ldloca.s V_3 + IL_00ee: ldsfld float64 Test.X::dx1 + IL_00f3: stfld float64 Test.HFA_d2::d1 + IL_00f8: ldloca.s V_3 + IL_00fa: ldsfld float64 Test.X::dx2 + IL_00ff: stfld float64 Test.HFA_d2::d2 + IL_0104: ldloca.s V_4 + IL_0106: initobj Test.HFA_d3 + IL_010c: ldloca.s V_4 + IL_010e: ldsfld float64 Test.X::dx1 + IL_0113: stfld float64 Test.HFA_d3::d1 + IL_0118: ldloca.s V_4 + IL_011a: ldsfld float64 Test.X::dx2 + IL_011f: stfld float64 Test.HFA_d3::d2 + IL_0124: ldloca.s V_4 + IL_0126: ldsfld float64 Test.X::dx3 + IL_012b: stfld float64 Test.HFA_d3::d3 + IL_0130: ldloca.s V_5 + IL_0132: initobj Test.HFA_d4 + IL_0138: ldloca.s V_5 + IL_013a: ldsfld float64 Test.X::dx1 + IL_013f: stfld float64 Test.HFA_d4::d1 + IL_0144: ldloca.s V_5 + IL_0146: ldsfld float64 Test.X::dx2 + IL_014b: stfld float64 Test.HFA_d4::d2 + IL_0150: ldloca.s V_5 + IL_0152: ldsfld float64 Test.X::dx3 + IL_0157: stfld float64 Test.HFA_d4::d3 + IL_015c: ldloca.s V_5 + IL_015e: ldsfld float64 Test.X::dx4 + IL_0163: stfld float64 Test.HFA_d4::d4 + IL_0168: ldc.i4.s 100 + IL_016a: stloc.s V_6 + IL_016c: ldloc.0 + IL_016d: call int32 Test.X::jmp_test_f2(valuetype Test.HFA_f2) + IL_0172: ldc.i4.s 100 + IL_0174: bne.un.s IL_0182 + + IL_0176: ldstr "jmp_test_f2 PASS" + IL_017b: call void [System.Console]System.Console::WriteLine(string) + IL_0180: br.s IL_018f + + IL_0182: ldstr "jmp_test_f2 FAIL" + IL_0187: call void [System.Console]System.Console::WriteLine(string) + IL_018c: ldc.i4.1 + IL_018d: stloc.s V_6 + IL_018f: ldloc.1 + IL_0190: call int32 Test.X::jmp_test_f3(valuetype Test.HFA_f3) + IL_0195: ldc.i4.s 100 + IL_0197: bne.un.s IL_01a5 + + IL_0199: ldstr "jmp_test_f3 PASS" + IL_019e: call void [System.Console]System.Console::WriteLine(string) + IL_01a3: br.s IL_01b2 + + IL_01a5: ldstr "jmp_test_f3 FAIL" + IL_01aa: call void [System.Console]System.Console::WriteLine(string) + IL_01af: ldc.i4.1 + IL_01b0: stloc.s V_6 + IL_01b2: ldloc.2 + IL_01b3: call int32 Test.X::jmp_test_f4(valuetype Test.HFA_f4) + IL_01b8: ldc.i4.s 100 + IL_01ba: bne.un.s IL_01c8 + + IL_01bc: ldstr "jmp_test_f4 PASS" + IL_01c1: call void [System.Console]System.Console::WriteLine(string) + IL_01c6: br.s IL_01d5 + + IL_01c8: ldstr "jmp_test_f4 FAIL" + IL_01cd: call void [System.Console]System.Console::WriteLine(string) + IL_01d2: ldc.i4.1 + IL_01d3: stloc.s V_6 + IL_01d5: ldloc.3 + IL_01d6: call int32 Test.X::jmp_test_d2(valuetype Test.HFA_d2) + IL_01db: ldc.i4.s 100 + IL_01dd: bne.un.s IL_01eb + + IL_01df: ldstr "jmp_test_d2 PASS" + IL_01e4: call void [System.Console]System.Console::WriteLine(string) + IL_01e9: br.s IL_01f8 + + IL_01eb: ldstr "jmp_test_d2 FAIL" + IL_01f0: call void [System.Console]System.Console::WriteLine(string) + IL_01f5: ldc.i4.1 + IL_01f6: stloc.s V_6 + IL_01f8: ldloc.s V_4 + IL_01fa: call int32 Test.X::jmp_test_d3(valuetype Test.HFA_d3) + IL_01ff: ldc.i4.s 100 + IL_0201: bne.un.s IL_020f + + IL_0203: ldstr "jmp_test_d3 PASS" + IL_0208: call void [System.Console]System.Console::WriteLine(string) + IL_020d: br.s IL_021c + + IL_020f: ldstr "jmp_test_d3 FAIL" + IL_0214: call void [System.Console]System.Console::WriteLine(string) + IL_0219: ldc.i4.1 + IL_021a: stloc.s V_6 + IL_021c: ldloc.s V_5 + IL_021e: call int32 Test.X::jmp_test_d4(valuetype Test.HFA_d4) + IL_0223: ldc.i4.s 100 + IL_0225: bne.un.s IL_0233 + + IL_0227: ldstr "jmp_test_d4 PASS" + IL_022c: call void [System.Console]System.Console::WriteLine(string) + IL_0231: br.s IL_0240 + + IL_0233: ldstr "jmp_test_d4 FAIL" + IL_0238: call void [System.Console]System.Console::WriteLine(string) + IL_023d: ldc.i4.1 + IL_023e: stloc.s V_6 + IL_0240: ldloc.s V_6 + IL_0242: ret + } // end of method X::Main + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [System.Runtime]System.Object::.ctor() + IL_0006: ret + } // end of method X::.ctor + +} // end of class Test.X diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_23147/GitHub_23147.ilproj b/tests/src/JIT/Regression/JitBlue/GitHub_23147/GitHub_23147.ilproj new file mode 100644 index 0000000..fe2d403 --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_23147/GitHub_23147.ilproj @@ -0,0 +1,25 @@ + + + + + Debug + AnyCPU + $(MSBuildProjectName) + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + ..\..\ + 1 + + + + + None + True + + + + + + + + -- 2.7.4