summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Forstall <brucefo@microsoft.com>2019-03-13 15:38:41 -0700
committerGitHub <noreply@github.com>2019-03-13 15:38:41 -0700
commitc71c92a0c0ff7ac442c3ca9d1ae7cc177072b23f (patch)
tree3eb787f80968f583f2a856c237cb40200b1c54d1
parente73c7bca3ebc46055cbdfb87adb39334474abb96 (diff)
parentc08f182bc90b0d32279201b7de89658765e3f6e8 (diff)
downloadcoreclr-c71c92a0c0ff7ac442c3ca9d1ae7cc177072b23f.tar.gz
coreclr-c71c92a0c0ff7ac442c3ca9d1ae7cc177072b23f.tar.bz2
coreclr-c71c92a0c0ff7ac442c3ca9d1ae7cc177072b23f.zip
Merge pull request #23220 from BruceForstall/FixArm64HfaJmpCallNyi
Arm64: Implement JMP call for HFA register arguments
-rw-r--r--src/jit/codegenarmarch.cpp84
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_23147/GitHub_23147.cs.txt342
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_23147/GitHub_23147.il696
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_23147/GitHub_23147.ilproj25
4 files changed, 1116 insertions, 31 deletions
diff --git a/src/jit/codegenarmarch.cpp b/src/jit/codegenarmarch.cpp
index 5e50e927e4..50180133d4 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 0000000000..6799607896
--- /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 0000000000..1298444f17
--- /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 0000000000..fe2d403ced
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_23147/GitHub_23147.ilproj
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <AssemblyName>$(MSBuildProjectName)</AssemblyName>
+ <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ <CLRTestPriority>1</CLRTestPriority>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "></PropertyGroup>
+ <PropertyGroup>
+ <DebugType>None</DebugType>
+ <Optimize>True</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="GitHub_23147.il" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' ">
+ </PropertyGroup>
+</Project>