Skip to content

Commit 367b006

Browse files
authored
Support fast tailcalls in R2R (#56669)
* Support fast tailcalls in R2R Partially addresses #5857 * Support ARM64 * Run jit-format * Fix non-R2R ARM build * Fix recursive-call-to-loop optimization with non-standard args * Implement new delay load helper for fast tailcalls * Minor changes and fix build break * Switch to a define for tailcall register * Fix x86 * Implement DefType.IsUnsafeValueType * Emit rex.jmp for tailcall jumps on x64 * Refactor non standard args + refix recursive tailcall opt * Set nonStandardArgKind for stack args also * Regenerate JIT interface * Improve recursion-to-loop decision about which args need to be reassigned * Use INS_tail_i_jmp for func token indir * More efficient arm64 VSD fast tailcalls, fix some bad merging Also fix logic since we removed tailcall register. For ARM64 that means we now use the single temp reg that is available for R2R/VSD calls, and in LSRA we ensure this goes into a volatile register. * Take R2R indirection into account for tail call profitability On x64 an R2R indirected direct call normally disassembles the call site to determine the indirection cell, so it is more expensive to do tail calls in this scenario as the indirection cell needs to be passed in a register. Take this into account: if there is no tail. prefix, do normal calls, and otherwise use tail calls. * Disallow tailcalls via JIT helper in R2R builds * Revert "Take R2R indirection into account for tail call profitability" This reverts commit 863ad4d. Let's not divert on the behavior here. It is not clear that having a smaller call site is better than tail calling albeit with a larger call site. * Add SPMI support, clean up mcPackets enum * Take necessary conditions into account in canTailCall Do not do implicit tailcalls when * The caller is the entry point * The caller is marked NoInline * The callee requires security object
1 parent a258c4f commit 367b006

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+668
-314
lines changed

src/coreclr/ToolBox/superpmi/superpmi-shared/lwmlist.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ LWM(GetSharedCCtorHelper, DWORDLONG, DWORD)
128128
LWM(GetStringConfigValue, DWORD, DWORD)
129129
LWM(GetSystemVAmd64PassStructInRegisterDescriptor, DWORDLONG, Agnostic_GetSystemVAmd64PassStructInRegisterDescriptor)
130130
LWM(GetTailCallHelpers, Agnostic_GetTailCallHelpers, Agnostic_CORINFO_TAILCALL_HELPERS)
131+
LWM(UpdateEntryPointForTailCall, Agnostic_CORINFO_CONST_LOOKUP, Agnostic_CORINFO_CONST_LOOKUP)
131132
LWM(GetThreadTLSIndex, DWORD, DLD)
132133
LWM(GetTokenTypeAsHandle, GetTokenTypeAsHandleValue, DWORDLONG)
133134
LWM(GetTypeForBox, DWORDLONG, DWORDLONG)

src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6608,6 +6608,41 @@ bool MethodContext::repGetTailCallHelpers(
66086608
return true;
66096609
}
66106610

6611+
void MethodContext::recUpdateEntryPointForTailCall(
6612+
const CORINFO_CONST_LOOKUP& origEntryPoint,
6613+
const CORINFO_CONST_LOOKUP& newEntryPoint)
6614+
{
6615+
if (UpdateEntryPointForTailCall == nullptr)
6616+
UpdateEntryPointForTailCall = new LightWeightMap<Agnostic_CORINFO_CONST_LOOKUP, Agnostic_CORINFO_CONST_LOOKUP>();
6617+
6618+
Agnostic_CORINFO_CONST_LOOKUP key = SpmiRecordsHelper::StoreAgnostic_CORINFO_CONST_LOOKUP(&origEntryPoint);
6619+
Agnostic_CORINFO_CONST_LOOKUP value = SpmiRecordsHelper::StoreAgnostic_CORINFO_CONST_LOOKUP(&newEntryPoint);
6620+
UpdateEntryPointForTailCall->Add(key, value);
6621+
DEBUG_REC(dmpUpdateEntryPointForTailCall(key, value));
6622+
}
6623+
6624+
void MethodContext::dmpUpdateEntryPointForTailCall(
6625+
const Agnostic_CORINFO_CONST_LOOKUP& origEntryPoint,
6626+
const Agnostic_CORINFO_CONST_LOOKUP& newEntryPoint)
6627+
{
6628+
printf("UpdateEntryPointForTailcall orig=%s new=%s",
6629+
SpmiDumpHelper::DumpAgnostic_CORINFO_CONST_LOOKUP(origEntryPoint).c_str(),
6630+
SpmiDumpHelper::DumpAgnostic_CORINFO_CONST_LOOKUP(newEntryPoint).c_str());
6631+
}
6632+
6633+
void MethodContext::repUpdateEntryPointForTailCall(CORINFO_CONST_LOOKUP* entryPoint)
6634+
{
6635+
AssertMapExistsNoMessage(UpdateEntryPointForTailCall);
6636+
6637+
Agnostic_CORINFO_CONST_LOOKUP key = SpmiRecordsHelper::StoreAgnostic_CORINFO_CONST_LOOKUP(entryPoint);
6638+
AssertKeyExistsNoMessage(UpdateEntryPointForTailCall, key);
6639+
6640+
Agnostic_CORINFO_CONST_LOOKUP value = UpdateEntryPointForTailCall->Get(key);
6641+
DEBUG_REP(dmpUpdateEntryPointForTailCall(key, value));
6642+
6643+
*entryPoint = SpmiRecordsHelper::RestoreCORINFO_CONST_LOOKUP(value);
6644+
}
6645+
66116646
void MethodContext::recGetMethodDefFromMethod(CORINFO_METHOD_HANDLE hMethod, mdMethodDef result)
66126647
{
66136648
if (GetMethodDefFromMethod == nullptr)

src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.h

Lines changed: 193 additions & 193 deletions
Large diffs are not rendered by default.

src/coreclr/ToolBox/superpmi/superpmi-shared/spmirecordhelper.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,9 @@ class SpmiRecordsHelper
9797
static CORINFO_LOOKUP_KIND RestoreCORINFO_LOOKUP_KIND(Agnostic_CORINFO_LOOKUP_KIND& lookupKind);
9898

9999
static Agnostic_CORINFO_CONST_LOOKUP StoreAgnostic_CORINFO_CONST_LOOKUP(
100-
CORINFO_CONST_LOOKUP* pLookup);
100+
const CORINFO_CONST_LOOKUP* pLookup);
101101

102-
static CORINFO_CONST_LOOKUP RestoreCORINFO_CONST_LOOKUP(Agnostic_CORINFO_CONST_LOOKUP& lookup);
102+
static CORINFO_CONST_LOOKUP RestoreCORINFO_CONST_LOOKUP(const Agnostic_CORINFO_CONST_LOOKUP& lookup);
103103

104104
static Agnostic_CORINFO_RUNTIME_LOOKUP StoreAgnostic_CORINFO_RUNTIME_LOOKUP(
105105
CORINFO_RUNTIME_LOOKUP* pLookup);
@@ -459,7 +459,7 @@ inline CORINFO_LOOKUP_KIND SpmiRecordsHelper::RestoreCORINFO_LOOKUP_KIND(
459459
}
460460

461461
inline Agnostic_CORINFO_CONST_LOOKUP SpmiRecordsHelper::StoreAgnostic_CORINFO_CONST_LOOKUP(
462-
CORINFO_CONST_LOOKUP* pLookup)
462+
const CORINFO_CONST_LOOKUP* pLookup)
463463
{
464464
Agnostic_CORINFO_CONST_LOOKUP constLookup;
465465
ZeroMemory(&constLookup, sizeof(constLookup));
@@ -469,7 +469,7 @@ inline Agnostic_CORINFO_CONST_LOOKUP SpmiRecordsHelper::StoreAgnostic_CORINFO_CO
469469
}
470470

471471
inline CORINFO_CONST_LOOKUP SpmiRecordsHelper::RestoreCORINFO_CONST_LOOKUP(
472-
Agnostic_CORINFO_CONST_LOOKUP& lookup)
472+
const Agnostic_CORINFO_CONST_LOOKUP& lookup)
473473
{
474474
CORINFO_CONST_LOOKUP constLookup;
475475
constLookup.accessType = (InfoAccessType)lookup.accessType;

src/coreclr/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1776,6 +1776,14 @@ bool interceptor_ICJI::getTailCallHelpers(
17761776
return result;
17771777
}
17781778

1779+
void interceptor_ICJI::updateEntryPointForTailCall(CORINFO_CONST_LOOKUP* entryPoint)
1780+
{
1781+
mc->cr->AddCall("updateEntryPointForTailCall");
1782+
CORINFO_CONST_LOOKUP origEntryPoint = *entryPoint;
1783+
original_ICorJitInfo->updateEntryPointForTailCall(entryPoint);
1784+
mc->recUpdateEntryPointForTailCall(origEntryPoint, *entryPoint);
1785+
}
1786+
17791787
// Stuff directly on ICorJitInfo
17801788

17811789
// Returns extended flags for a particular compilation instance.

src/coreclr/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,6 +1250,13 @@ bool interceptor_ICJI::notifyInstructionSetUsage(
12501250
return original_ICorJitInfo->notifyInstructionSetUsage(instructionSet, supportEnabled);
12511251
}
12521252

1253+
void interceptor_ICJI::updateEntryPointForTailCall(
1254+
CORINFO_CONST_LOOKUP* entryPoint)
1255+
{
1256+
mcs->AddCall("updateEntryPointForTailCall");
1257+
original_ICorJitInfo->updateEntryPointForTailCall(entryPoint);
1258+
}
1259+
12531260
void interceptor_ICJI::allocMem(
12541261
AllocMemArgs* pArgs)
12551262
{

src/coreclr/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,6 +1094,12 @@ bool interceptor_ICJI::notifyInstructionSetUsage(
10941094
return original_ICorJitInfo->notifyInstructionSetUsage(instructionSet, supportEnabled);
10951095
}
10961096

1097+
void interceptor_ICJI::updateEntryPointForTailCall(
1098+
CORINFO_CONST_LOOKUP* entryPoint)
1099+
{
1100+
original_ICorJitInfo->updateEntryPointForTailCall(entryPoint);
1101+
}
1102+
10971103
void interceptor_ICJI::allocMem(
10981104
AllocMemArgs* pArgs)
10991105
{

src/coreclr/ToolBox/superpmi/superpmi/icorjitinfo.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1556,6 +1556,12 @@ bool MyICJI::notifyInstructionSetUsage(CORINFO_InstructionSet instructionSet, bo
15561556
return supported;
15571557
}
15581558

1559+
void MyICJI::updateEntryPointForTailCall(CORINFO_CONST_LOOKUP* entryPoint)
1560+
{
1561+
jitInstance->mc->cr->AddCall("updateEntryPointForTailCall");
1562+
jitInstance->mc->repUpdateEntryPointForTailCall(entryPoint);
1563+
}
1564+
15591565
// Stuff directly on ICorJitInfo
15601566

15611567
// Returns extended flags for a particular compilation instance.

src/coreclr/inc/corinfo.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3164,6 +3164,13 @@ class ICorDynamicInfo : public ICorStaticInfo
31643164
CORINFO_InstructionSet instructionSet,
31653165
bool supportEnabled
31663166
) = 0;
3167+
3168+
// Notify EE that JIT needs an entry-point that is tail-callable.
3169+
// This is used for AOT on x64 to support delay loaded fast tailcalls.
3170+
// Normally the indirection cell is retrieved from the return address,
3171+
// but for tailcalls, the contract is that JIT leaves the indirection cell in
3172+
// a register during tailcall.
3173+
virtual void updateEntryPointForTailCall(CORINFO_CONST_LOOKUP* entryPoint) = 0;
31673174
};
31683175

31693176
/**********************************************************************************/

src/coreclr/inc/icorjitinfoimpl_generated.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,9 @@ bool notifyInstructionSetUsage(
635635
CORINFO_InstructionSet instructionSet,
636636
bool supportEnabled) override;
637637

638+
void updateEntryPointForTailCall(
639+
CORINFO_CONST_LOOKUP* entryPoint) override;
640+
638641
void allocMem(
639642
AllocMemArgs* pArgs) override;
640643

0 commit comments

Comments
 (0)