From 4abb0075973efd3da41fb4f718ee7c0e7b6e3a7e Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 19 Aug 2022 00:45:07 +0300 Subject: [PATCH 1/2] Add a test --- .../JitBlue/Runtime_74126/Runtime_74126.cs | 82 +++++++++++++++++++ .../Runtime_74126/Runtime_74126.csproj | 9 ++ 2 files changed, 91 insertions(+) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_74126/Runtime_74126.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_74126/Runtime_74126.csproj diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_74126/Runtime_74126.cs b/src/tests/JIT/Regression/JitBlue/Runtime_74126/Runtime_74126.cs new file mode 100644 index 00000000000000..dd21dce550479d --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_74126/Runtime_74126.cs @@ -0,0 +1,82 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Numerics; +using System.Runtime.Intrinsics; +using System.Runtime.CompilerServices; + +public class Runtime_74126 +{ + public static int Main() + { + if (GetVtor(GetVtor2()) != GetVtor2()) + { + return 101; + } + if (GetVtor(GetVtor3()) != GetVtor3()) + { + return 102; + } + if (GetVtor(GetVtor4()) != GetVtor4()) + { + return 103; + } + if (GetVtor(GetVtor64()) != GetVtor64()) + { + return 104; + } + if (GetVtor(GetVtor128()) != GetVtor128()) + { + return 105; + } + if (GetVtor(GetVtor256()) != GetVtor256()) + { + return 106; + } + + return 100; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static Vector2 GetVtor2() + { + return new Vector2(1, 2); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static Vector3 GetVtor3() + { + return new Vector3(1, 2, 3); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static Vector4 GetVtor4() + { + return new Vector4(1, 2, 3, 4); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static Vector64 GetVtor64() + { + return Vector64.Create(1, 2); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static Vector128 GetVtor128() + { + return Vector128.Create(1, 2, 3, 4); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static Vector256 GetVtor256() + { + return Vector256.Create(1, 2, 3, 4, 5, 6, 7, 8); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static T GetVtor(T vtor) + { + return vtor; + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_74126/Runtime_74126.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_74126/Runtime_74126.csproj new file mode 100644 index 00000000000000..f492aeac9d056b --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_74126/Runtime_74126.csproj @@ -0,0 +1,9 @@ + + + Exe + True + + + + + \ No newline at end of file From e64061b31a3c43da5b0a80d6e2a42bad0ad4bcdf Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Fri, 19 Aug 2022 00:25:22 +0300 Subject: [PATCH 2/2] Allow SIMD-returning calls as arguments As of this change we handle all relevant ABI scenarios. 1) Windows x64: - SIMD8: returned and passed as "TYP_LONG", fine. - SIMD12 / SIMD16 / SIMD32: returned and passed via a return buffer, fine. 2) Unix x64: - SIMD8: returned and passed in one FP register, fine. - SIMD12 / SIMD16, Vector4: returned and passed in two FP registers, fine. - SIMD16, Vector128 / SIMD32: returned and passed via a return buffer, fine. 3) x86: - SIMD8: can be returned via two registers or a return buffer (and is always passed on stack), both are fine. - SIMD12/SIMD16/SIMD32: returned via a return buffer, passed on stack, fine. 4) ARM64: - SIMD8, Vector2: returned in two FP registers (and passed as such or "TYP_LONG" under Windows varargs), fine. - SIMD8, Vector64: returned in one FP register, can be passed as such or as "TYP_LONG" under Windows varargs. The latter case is now handled correctly in "Lowering::LowerArg". - SIMD12: returned in three FP registers, passed as such or in two integer registers under Windows varargs, fine. - SIMD16, Vector4: returned in four FP registers, passed as such, or in two integer registers under Windows varargs, fine. - SIMD16, Vector128: returned in one FP register, passed as such, or in two integer registers under Windows varargs, fine (morph will decompose the varargs case into a `FIELD_LIST` via a temp). --- src/coreclr/jit/lower.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 2871a506679acd..1c861c8951809e 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -1425,7 +1425,7 @@ GenTree* Lowering::LowerFloatArg(GenTree** pArg, CallArg* callArg) break; } GenTree* node = use.GetNode(); - if (varTypeIsFloating(node)) + if (varTypeUsesFloatReg(node)) { GenTree* intNode = LowerFloatArgReg(node, currRegNumber); assert(intNode != nullptr); @@ -1447,7 +1447,7 @@ GenTree* Lowering::LowerFloatArg(GenTree** pArg, CallArg* callArg) // List fields were replaced in place. return arg; } - else if (varTypeIsFloating(arg)) + else if (varTypeUsesFloatReg(arg)) { GenTree* intNode = LowerFloatArgReg(arg, callArg->AbiInfo.GetRegNum()); assert(intNode != nullptr); @@ -1470,11 +1470,13 @@ GenTree* Lowering::LowerFloatArg(GenTree** pArg, CallArg* callArg) // GenTree* Lowering::LowerFloatArgReg(GenTree* arg, regNumber regNum) { + assert(varTypeUsesFloatReg(arg)); + var_types floatType = arg->TypeGet(); - assert(varTypeIsFloating(floatType)); - var_types intType = (floatType == TYP_DOUBLE) ? TYP_LONG : TYP_INT; - GenTree* intArg = comp->gtNewBitCastNode(intType, arg); + var_types intType = (floatType == TYP_FLOAT) ? TYP_INT : TYP_LONG; + GenTree* intArg = comp->gtNewBitCastNode(intType, arg); intArg->SetRegNum(regNum); + #ifdef TARGET_ARM if (floatType == TYP_DOUBLE) { @@ -3819,6 +3821,11 @@ void Lowering::LowerCallStruct(GenTreeCall* call) assert(user->TypeIs(origType) || (returnType == user->TypeGet())); break; + case GT_CALL: + // Argument lowering will deal with register file mismatches if needed. + assert(varTypeIsSIMD(origType)); + break; + case GT_STOREIND: #ifdef FEATURE_SIMD if (varTypeIsSIMD(user))