Skip to content

Commit 2f90038

Browse files
authored
JIT: create recursive tail call scratch block early in morph (#93764)
Create the scratch BB (if likely to be needed) before we get into morphing all the blocks, so that morph is not creating new blocks while morphing. Also enhance detection of potential recursive tall calls to include cases created by GDV.
1 parent de011df commit 2f90038

File tree

6 files changed

+54
-17
lines changed

6 files changed

+54
-17
lines changed

src/coreclr/jit/compiler.cpp

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1901,17 +1901,16 @@ void Compiler::compInit(ArenaAllocator* pAlloc,
19011901
codeGen = nullptr;
19021902
}
19031903

1904-
compJmpOpUsed = false;
1905-
compLongUsed = false;
1906-
compTailCallUsed = false;
1907-
compTailPrefixSeen = false;
1908-
compMayConvertTailCallToLoop = false;
1909-
compLocallocSeen = false;
1910-
compLocallocUsed = false;
1911-
compLocallocOptimized = false;
1912-
compQmarkRationalized = false;
1913-
compQmarkUsed = false;
1914-
compFloatingPointUsed = false;
1904+
compJmpOpUsed = false;
1905+
compLongUsed = false;
1906+
compTailCallUsed = false;
1907+
compTailPrefixSeen = false;
1908+
compLocallocSeen = false;
1909+
compLocallocUsed = false;
1910+
compLocallocOptimized = false;
1911+
compQmarkRationalized = false;
1912+
compQmarkUsed = false;
1913+
compFloatingPointUsed = false;
19151914

19161915
compSuppressedZeroInit = false;
19171916

src/coreclr/jit/compiler.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7118,6 +7118,7 @@ class Compiler
71187118
#define OMF_HAS_STATIC_INIT 0x00008000 // Method has static initializations we might want to partially inline
71197119
#define OMF_HAS_TLS_FIELD 0x00010000 // Method contains TLS field access
71207120
#define OMF_HAS_SPECIAL_INTRINSICS 0x00020000 // Method contains special intrinsics expanded in late phases
7121+
#define OMF_HAS_RECURSIVE_TAILCALL 0x00040000 // Method contains recursive tail call
71217122

71227123
// clang-format on
71237124

@@ -7188,6 +7189,16 @@ class Compiler
71887189
optMethodFlags |= OMF_HAS_SPECIAL_INTRINSICS;
71897190
}
71907191

7192+
bool doesMethodHaveRecursiveTailcall()
7193+
{
7194+
return (optMethodFlags & OMF_HAS_RECURSIVE_TAILCALL) != 0;
7195+
}
7196+
7197+
void setMethodHasRecursiveTailcall()
7198+
{
7199+
optMethodFlags |= OMF_HAS_RECURSIVE_TAILCALL;
7200+
}
7201+
71917202
void pickGDV(GenTreeCall* call,
71927203
IL_OFFSET ilOffset,
71937204
bool isInterface,
@@ -9361,7 +9372,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
93619372
bool compFloatingPointUsed; // Does the method use TYP_FLOAT or TYP_DOUBLE
93629373
bool compTailCallUsed; // Does the method do a tailcall
93639374
bool compTailPrefixSeen; // Does the method IL have tail. prefix
9364-
bool compMayConvertTailCallToLoop; // Does the method have a recursive tail call that we may convert to a loop?
93659375
bool compLocallocSeen; // Does the method IL have localloc opcode
93669376
bool compLocallocUsed; // Does the method use localloc.
93679377
bool compLocallocOptimized; // Does the method have an optimized localloc

src/coreclr/jit/importercalls.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1255,7 +1255,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
12551255
dspTreeID(call), loopHead->bbNum, compCurBB->bbNum);
12561256
fgMarkBackwardJump(loopHead, compCurBB);
12571257

1258-
compMayConvertTailCallToLoop = true;
1258+
setMethodHasRecursiveTailcall();
12591259
compCurBB->bbFlags |= BBF_RECURSIVE_TAILCALL;
12601260
}
12611261

src/coreclr/jit/indirectcalltransformer.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -916,6 +916,21 @@ class IndirectCallTransformer
916916
//
917917
assert(!call->IsVirtual() && !call->IsDelegateInvoke());
918918

919+
// If this call is in tail position, see if we've created a recursive tail call
920+
// candidate...
921+
//
922+
if (call->CanTailCall() && compiler->gtIsRecursiveCall(methodHnd))
923+
{
924+
compiler->setMethodHasRecursiveTailcall();
925+
block->bbFlags |= BBF_RECURSIVE_TAILCALL;
926+
JITDUMP("[%06u] is a recursive call in tail position\n", compiler->dspTreeID(call));
927+
}
928+
else
929+
{
930+
JITDUMP("[%06u] is%s in tail position and is%s recursive\n", compiler->dspTreeID(call),
931+
call->CanTailCall() ? "" : " not", compiler->gtIsRecursiveCall(methodHnd) ? "" : " not");
932+
}
933+
919934
// If the devirtualizer was unable to transform the call to invoke the unboxed entry, the inline info
920935
// we set up may be invalid. We won't be able to inline anyways. So demote the call as an inline candidate.
921936
//

src/coreclr/jit/lclvars.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8065,7 +8065,7 @@ Compiler::fgWalkResult Compiler::lvaStressLclFldCB(GenTree** pTree, fgWalkData*
80658065
// TYP_BLK locals.
80668066
// TODO-Cleanup: Can probably be removed now since TYP_BLK does not
80678067
// exist anymore.
8068-
if (pComp->compMayConvertTailCallToLoop)
8068+
if (pComp->doesMethodHaveRecursiveTailcall())
80698069
{
80708070
varDsc->lvNoLclFldStress = true;
80718071
return WALK_CONTINUE;

src/coreclr/jit/morph.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7450,11 +7450,16 @@ void Compiler::fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCa
74507450
}
74517451
else
74527452
{
7453-
// Ensure we have a scratch block and then target the next
7454-
// block. Loop detection needs to see a pred out of the loop,
7453+
// We should have ensured the first BB was scratch
7454+
// in morph init...
7455+
//
7456+
assert(doesMethodHaveRecursiveTailcall());
7457+
assert(fgFirstBBisScratch());
7458+
7459+
// Loop detection needs to see a pred out of the loop,
74557460
// so mark the scratch block BBF_DONT_REMOVE to prevent empty
74567461
// block removal on it.
7457-
fgEnsureFirstBBisScratch();
7462+
//
74587463
fgFirstBB->bbFlags |= BBF_DONT_REMOVE;
74597464
block->SetJumpKindAndTarget(BBJ_ALWAYS, fgFirstBB->Next() DEBUG_ARG(this));
74607465
}
@@ -13854,6 +13859,14 @@ void Compiler::fgMorphBlocks()
1385413859
lvSetMinOptsDoNotEnreg();
1385513860
}
1385613861

13862+
// Ensure the first BB is scratch if we might need it as a pred for
13863+
// the recursive tail call to loop optimization.
13864+
//
13865+
if (doesMethodHaveRecursiveTailcall())
13866+
{
13867+
fgEnsureFirstBBisScratch();
13868+
}
13869+
1385713870
/*-------------------------------------------------------------------------
1385813871
* Process all basic blocks in the function
1385913872
*/

0 commit comments

Comments
 (0)