Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit ca3c39c

Browse files
author
Jarret Shook
authored
Do not fast tail call if caller has multislot structs (#25885) (#25910)
* Do not fast tail call if caller has multislot structs * apply patch * Address offline feedback
1 parent 433fb28 commit ca3c39c

File tree

2 files changed

+229
-0
lines changed

2 files changed

+229
-0
lines changed

src/jit/lclvars.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,6 +1004,11 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo)
10041004
#endif // _TARGET_XXX_
10051005

10061006
#if FEATURE_FASTTAILCALL
1007+
if (cSlots > 1)
1008+
{
1009+
varDscInfo->hasMultiSlotStruct = true;
1010+
}
1011+
10071012
varDscInfo->stackArgSize += roundUp(argSize, TARGET_POINTER_SIZE);
10081013
#endif // FEATURE_FASTTAILCALL
10091014
}

tests/src/JIT/opt/FastTailCall/FastTailCallCandidates.cs

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ public static int Tester(int a)
6363
CheckOutput(CallerHFACaseCalleeOnly(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0));
6464
CheckOutput(CallerHFaCaseCalleeStackArgs(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0));
6565
CheckOutput(DoubleCountRetBuffCaller(1));
66+
CheckOutput(Struct32CallerWrapper());
67+
CheckOutput(Struct32CallerWrapperCalleeHasStack(2));
6668

6769
return s_ret_value;
6870

@@ -1154,6 +1156,228 @@ public static int DoubleCountRetBuffCaller(int i)
11541156
}
11551157
}
11561158

1159+
/// <summary>
1160+
/// Decision to fast tail call
1161+
/// </summary>
1162+
///
1163+
/// On x64 linux this will fast tail call.
1164+
///
1165+
/// The caller uses 2 integer registers 32 bytes of stack (3 args)
1166+
/// The callee uses 3 integer registers, 0 bytes of stack (3 args)
1167+
///
1168+
/// Return 100 is a pass.
1169+
/// Return 113 is a failure.
1170+
///
1171+
/// </remarks>
1172+
public static int Struct32Caller(StructSizeThirtyTwo one, long two, long three)
1173+
{
1174+
if (two % 2 == 1)
1175+
{
1176+
return Struct32Callee(two, two, three);
1177+
}
1178+
else
1179+
{
1180+
return Struct32Callee(three, two, three);
1181+
}
1182+
}
1183+
1184+
/// <summary>
1185+
/// Decision to fast tail call
1186+
/// </summary>
1187+
///
1188+
/// On x64 linux this will fast tail call.
1189+
///
1190+
/// The caller uses 2 integer registers 32 bytes of stack (3 args)
1191+
/// The callee uses 3 integer registers, 0 bytes of stack (3 args)
1192+
///
1193+
/// Return 100 is a pass.
1194+
/// Return 113 is a failure.
1195+
///
1196+
/// </remarks>
1197+
public static int Struct32Callee(long one, long two, long three)
1198+
{
1199+
int count = 0;
1200+
for (int i = 0; i < three * 100; ++i)
1201+
{
1202+
if (i % 10 == 0)
1203+
{
1204+
++count;
1205+
}
1206+
}
1207+
1208+
if (count == 30)
1209+
{
1210+
return 84;
1211+
}
1212+
else
1213+
{
1214+
return 85;
1215+
}
1216+
}
1217+
1218+
/// <summary>
1219+
/// Decision to fast tail call
1220+
/// </summary>
1221+
///
1222+
/// On x64 linux this will fast tail call.
1223+
///
1224+
/// The caller uses 2 integer registers 32 bytes of stack (3 args)
1225+
/// The callee uses 3 integer registers, 0 bytes of stack (3 args)
1226+
///
1227+
/// Return 100 is a pass.
1228+
/// Return 113 is a failure.
1229+
///
1230+
/// </remarks>
1231+
public static int Struct32CallerWrapper()
1232+
{
1233+
int ret = Struct32Caller(new StructSizeThirtyTwo(1, 2, 3, 4), 2, 3);
1234+
1235+
if (ret != 84)
1236+
{
1237+
return 113;
1238+
}
1239+
1240+
return 100;
1241+
}
1242+
1243+
/// <summary>
1244+
/// Decision to not fast tail call
1245+
/// </summary>
1246+
///
1247+
/// On x64 linux this will not fast tail call.
1248+
///
1249+
/// The caller uses 6 integer registers 56 bytes of stack (10 args)
1250+
/// The callee uses 6 integer registers, 32 bytes of stack (10 args)
1251+
///
1252+
/// Return 100 is a pass.
1253+
/// Return 114 is a failure.
1254+
///
1255+
/// </remarks>
1256+
public static int Struct32CallerCalleeHasStackSpace(StructSizeThirtyTwo one, // stack slot 1, 2, 3, 4
1257+
long two,
1258+
long three,
1259+
long four,
1260+
long five,
1261+
long six,
1262+
long seven,
1263+
long eight, // stack slot 6
1264+
long nine, // stack slot 7
1265+
long ten) // stack slot 8
1266+
{
1267+
int count = 0;
1268+
for (int i = 0; i < two * 100; ++i)
1269+
{
1270+
if (i % 10 == 0)
1271+
{
1272+
++count;
1273+
}
1274+
}
1275+
1276+
if (count == 20)
1277+
{
1278+
return Struct32CalleeWithStack(one.a,
1279+
one.b,
1280+
one.c,
1281+
one.d,
1282+
two,
1283+
three,
1284+
four, // stack slot 1
1285+
five, // stack slot 2
1286+
six, // stack slot 3
1287+
seven); // stack slot 4
1288+
}
1289+
else
1290+
{
1291+
return Struct32CalleeWithStack(one.a,
1292+
one.b,
1293+
one.c,
1294+
one.d,
1295+
two,
1296+
three,
1297+
four, // stack slot 1
1298+
five, // stack slot 2
1299+
six, // stack slot 3
1300+
seven); // stack slot 4
1301+
}
1302+
}
1303+
1304+
/// <summary>
1305+
/// Decision to not fast tail call
1306+
/// </summary>
1307+
///
1308+
/// On x64 linux this will not fast tail call.
1309+
///
1310+
/// The caller uses 6 integer registers 56 bytes of stack (3 args)
1311+
/// The callee uses 6 integer registers, 32 bytes of stack (3 args)
1312+
///
1313+
/// Return 100 is a pass.
1314+
/// Return 113 is a failure.
1315+
///
1316+
/// </remarks>
1317+
public static int Struct32CalleeWithStack(long one,
1318+
long two,
1319+
long three,
1320+
long four,
1321+
long five,
1322+
long six,
1323+
long seven,
1324+
long eight,
1325+
long nine,
1326+
long ten)
1327+
{
1328+
int count = 0;
1329+
for (int i = 0; i < one * 100; ++i)
1330+
{
1331+
if (i % 10 == 0)
1332+
{
1333+
++count;
1334+
}
1335+
}
1336+
1337+
if (count == 10)
1338+
{
1339+
return 84;
1340+
}
1341+
else
1342+
{
1343+
return 85;
1344+
}
1345+
}
1346+
1347+
/// <summary>
1348+
/// Decision to not fast tail call
1349+
/// </summary>
1350+
///
1351+
/// On x64 linux this will not fast tail call.
1352+
///
1353+
/// The caller uses 6 integer registers 56 bytes of stack (3 args)
1354+
/// The callee uses 6 integer registers, 32 bytes of stack (3 args)
1355+
///
1356+
/// Return 100 is a pass.
1357+
/// Return 113 is a failure.
1358+
///
1359+
/// </remarks>
1360+
public static int Struct32CallerWrapperCalleeHasStack(int two)
1361+
{
1362+
int ret = Struct32CallerCalleeHasStackSpace(new StructSizeThirtyTwo(1, 2, 3, 4),
1363+
5,
1364+
6,
1365+
7,
1366+
8,
1367+
9,
1368+
10,
1369+
11,
1370+
12,
1371+
13);
1372+
1373+
if (ret != 84)
1374+
{
1375+
return 114;
1376+
}
1377+
1378+
return 100;
1379+
}
1380+
11571381
////////////////////////////////////////////////////////////////////////////
11581382
// Main
11591383
////////////////////////////////////////////////////////////////////////////

0 commit comments

Comments
 (0)