Skip to content

Commit 2c5d001

Browse files
[release/7.0] Allow SIMD-returning calls as arguments (#74520)
* Add a test * 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). Co-authored-by: SingleAccretion <[email protected]>
1 parent 5c9432e commit 2c5d001

File tree

3 files changed

+103
-5
lines changed

3 files changed

+103
-5
lines changed

src/coreclr/jit/lower.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1425,7 +1425,7 @@ GenTree* Lowering::LowerFloatArg(GenTree** pArg, CallArg* callArg)
14251425
break;
14261426
}
14271427
GenTree* node = use.GetNode();
1428-
if (varTypeIsFloating(node))
1428+
if (varTypeUsesFloatReg(node))
14291429
{
14301430
GenTree* intNode = LowerFloatArgReg(node, currRegNumber);
14311431
assert(intNode != nullptr);
@@ -1447,7 +1447,7 @@ GenTree* Lowering::LowerFloatArg(GenTree** pArg, CallArg* callArg)
14471447
// List fields were replaced in place.
14481448
return arg;
14491449
}
1450-
else if (varTypeIsFloating(arg))
1450+
else if (varTypeUsesFloatReg(arg))
14511451
{
14521452
GenTree* intNode = LowerFloatArgReg(arg, callArg->AbiInfo.GetRegNum());
14531453
assert(intNode != nullptr);
@@ -1470,11 +1470,13 @@ GenTree* Lowering::LowerFloatArg(GenTree** pArg, CallArg* callArg)
14701470
//
14711471
GenTree* Lowering::LowerFloatArgReg(GenTree* arg, regNumber regNum)
14721472
{
1473+
assert(varTypeUsesFloatReg(arg));
1474+
14731475
var_types floatType = arg->TypeGet();
1474-
assert(varTypeIsFloating(floatType));
1475-
var_types intType = (floatType == TYP_DOUBLE) ? TYP_LONG : TYP_INT;
1476-
GenTree* intArg = comp->gtNewBitCastNode(intType, arg);
1476+
var_types intType = (floatType == TYP_FLOAT) ? TYP_INT : TYP_LONG;
1477+
GenTree* intArg = comp->gtNewBitCastNode(intType, arg);
14771478
intArg->SetRegNum(regNum);
1479+
14781480
#ifdef TARGET_ARM
14791481
if (floatType == TYP_DOUBLE)
14801482
{
@@ -3819,6 +3821,11 @@ void Lowering::LowerCallStruct(GenTreeCall* call)
38193821
assert(user->TypeIs(origType) || (returnType == user->TypeGet()));
38203822
break;
38213823

3824+
case GT_CALL:
3825+
// Argument lowering will deal with register file mismatches if needed.
3826+
assert(varTypeIsSIMD(origType));
3827+
break;
3828+
38223829
case GT_STOREIND:
38233830
#ifdef FEATURE_SIMD
38243831
if (varTypeIsSIMD(user))
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Numerics;
6+
using System.Runtime.Intrinsics;
7+
using System.Runtime.CompilerServices;
8+
9+
public class Runtime_74126
10+
{
11+
public static int Main()
12+
{
13+
if (GetVtor(GetVtor2()) != GetVtor2())
14+
{
15+
return 101;
16+
}
17+
if (GetVtor(GetVtor3()) != GetVtor3())
18+
{
19+
return 102;
20+
}
21+
if (GetVtor(GetVtor4()) != GetVtor4())
22+
{
23+
return 103;
24+
}
25+
if (GetVtor(GetVtor64()) != GetVtor64())
26+
{
27+
return 104;
28+
}
29+
if (GetVtor(GetVtor128()) != GetVtor128())
30+
{
31+
return 105;
32+
}
33+
if (GetVtor(GetVtor256()) != GetVtor256())
34+
{
35+
return 106;
36+
}
37+
38+
return 100;
39+
}
40+
41+
[MethodImpl(MethodImplOptions.NoInlining)]
42+
private static Vector2 GetVtor2()
43+
{
44+
return new Vector2(1, 2);
45+
}
46+
47+
[MethodImpl(MethodImplOptions.NoInlining)]
48+
private static Vector3 GetVtor3()
49+
{
50+
return new Vector3(1, 2, 3);
51+
}
52+
53+
[MethodImpl(MethodImplOptions.NoInlining)]
54+
private static Vector4 GetVtor4()
55+
{
56+
return new Vector4(1, 2, 3, 4);
57+
}
58+
59+
[MethodImpl(MethodImplOptions.NoInlining)]
60+
private static Vector64<int> GetVtor64()
61+
{
62+
return Vector64.Create(1, 2);
63+
}
64+
65+
[MethodImpl(MethodImplOptions.NoInlining)]
66+
private static Vector128<int> GetVtor128()
67+
{
68+
return Vector128.Create(1, 2, 3, 4);
69+
}
70+
71+
[MethodImpl(MethodImplOptions.NoInlining)]
72+
private static Vector256<int> GetVtor256()
73+
{
74+
return Vector256.Create(1, 2, 3, 4, 5, 6, 7, 8);
75+
}
76+
77+
[MethodImpl(MethodImplOptions.NoInlining)]
78+
private static T GetVtor<T>(T vtor)
79+
{
80+
return vtor;
81+
}
82+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
<Optimize>True</Optimize>
5+
</PropertyGroup>
6+
<ItemGroup>
7+
<Compile Include="$(MSBuildProjectName).cs" />
8+
</ItemGroup>
9+
</Project>

0 commit comments

Comments
 (0)