Skip to content

Commit 7dba9af

Browse files
authored
JIT: update tail call IR validity checks (#94130)
Remove `fgCheckStmtAfterTailCall` as it did less thorough and less correct checking. Contributes to #93246.
1 parent 69f2b40 commit 7dba9af

2 files changed

Lines changed: 0 additions & 109 deletions

File tree

src/coreclr/jit/compiler.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5979,7 +5979,6 @@ class Compiler
59795979
bool fgCallArgWillPointIntoLocalFrame(GenTreeCall* call, CallArg& arg);
59805980

59815981
#endif
5982-
bool fgCheckStmtAfterTailCall();
59835982
GenTree* fgMorphTailCallViaHelpers(GenTreeCall* call, CORINFO_TAILCALL_HELPERS& help);
59845983
bool fgCanTailCallViaJitHelper(GenTreeCall* call);
59855984
void fgMorphTailCallViaJitHelper(GenTreeCall* call);

src/coreclr/jit/morph.cpp

Lines changed: 0 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -5894,12 +5894,6 @@ GenTree* Compiler::fgMorphPotentialTailCall(GenTreeCall* call)
58945894
}
58955895
}
58965896

5897-
if (!fgCheckStmtAfterTailCall())
5898-
{
5899-
failTailCall("Unexpected statements after the tail call");
5900-
return nullptr;
5901-
}
5902-
59035897
const char* failReason = nullptr;
59045898
bool canFastTailCall = fgCanFastTailCall(call, &failReason);
59055899

@@ -15367,108 +15361,6 @@ void Compiler::fgMarkDemotedImplicitByRefArgs()
1536715361
#endif // FEATURE_IMPLICIT_BYREFS
1536815362
}
1536915363

15370-
//------------------------------------------------------------------------
15371-
// fgCheckStmtAfterTailCall: check that statements after the tail call stmt
15372-
// candidate are in one of expected forms, that are desctibed below.
15373-
//
15374-
// Return Value:
15375-
// 'true' if stmts are in the expected form, else 'false'.
15376-
//
15377-
bool Compiler::fgCheckStmtAfterTailCall()
15378-
{
15379-
15380-
// For void calls, we would have created a GT_CALL in the stmt list.
15381-
// For non-void calls, we would have created a GT_RETURN(GT_CAST(GT_CALL)).
15382-
// For calls returning structs, we would have a void call, followed by a void return.
15383-
// For debuggable code, it would be an assignment of the call to a temp
15384-
// We want to get rid of any of this extra trees, and just leave
15385-
// the call.
15386-
Statement* callStmt = fgMorphStmt;
15387-
15388-
Statement* nextMorphStmt = callStmt->GetNextStmt();
15389-
15390-
// Check that the rest stmts in the block are in one of the following pattern:
15391-
// 1) ret(void)
15392-
// 2) ret(cast*(callResultLclVar))
15393-
// 3) lclVar = callResultLclVar, the actual ret(lclVar) in another block
15394-
// 4) nop
15395-
if (nextMorphStmt != nullptr)
15396-
{
15397-
GenTree* callExpr = callStmt->GetRootNode();
15398-
if (!callExpr->OperIs(GT_STORE_LCL_VAR))
15399-
{
15400-
// The next stmt can be GT_RETURN(TYP_VOID) or GT_RETURN(lclVar),
15401-
// where lclVar was return buffer in the call for structs or simd.
15402-
Statement* retStmt = nextMorphStmt;
15403-
GenTree* retExpr = retStmt->GetRootNode();
15404-
noway_assert(retExpr->gtOper == GT_RETURN);
15405-
15406-
nextMorphStmt = retStmt->GetNextStmt();
15407-
}
15408-
else
15409-
{
15410-
noway_assert(callExpr->OperIs(GT_STORE_LCL_VAR));
15411-
unsigned callResultLclNumber = callExpr->AsLclVar()->GetLclNum();
15412-
15413-
#if FEATURE_TAILCALL_OPT_SHARED_RETURN
15414-
15415-
// We can have a chain of assignments from the call result to
15416-
// various inline return spill temps. These are ok as long
15417-
// as the last one ultimately provides the return value or is ignored.
15418-
//
15419-
// And if we're returning a small type we may see a cast
15420-
// on the source side.
15421-
while ((nextMorphStmt != nullptr) && (nextMorphStmt->GetRootNode()->OperIs(GT_STORE_LCL_VAR, GT_NOP)))
15422-
{
15423-
if (nextMorphStmt->GetRootNode()->OperIs(GT_NOP))
15424-
{
15425-
nextMorphStmt = nextMorphStmt->GetNextStmt();
15426-
continue;
15427-
}
15428-
Statement* moveStmt = nextMorphStmt;
15429-
GenTree* moveExpr = nextMorphStmt->GetRootNode();
15430-
15431-
// Tunnel through any casts on the source side.
15432-
GenTree* moveSource = moveExpr->AsLclVar()->Data();
15433-
while (moveSource->OperIs(GT_CAST))
15434-
{
15435-
noway_assert(!moveSource->gtOverflow());
15436-
moveSource = moveSource->gtGetOp1();
15437-
}
15438-
noway_assert(moveSource->OperIsLocal());
15439-
15440-
// Verify we're just passing the value from one local to another
15441-
// along the chain.
15442-
const unsigned srcLclNum = moveSource->AsLclVarCommon()->GetLclNum();
15443-
noway_assert(srcLclNum == callResultLclNumber);
15444-
const unsigned dstLclNum = moveExpr->AsLclVar()->GetLclNum();
15445-
callResultLclNumber = dstLclNum;
15446-
15447-
nextMorphStmt = moveStmt->GetNextStmt();
15448-
}
15449-
if (nextMorphStmt != nullptr)
15450-
#endif
15451-
{
15452-
Statement* retStmt = nextMorphStmt;
15453-
GenTree* retExpr = nextMorphStmt->GetRootNode();
15454-
noway_assert(retExpr->gtOper == GT_RETURN);
15455-
15456-
GenTree* treeWithLcl = retExpr->gtGetOp1();
15457-
while (treeWithLcl->gtOper == GT_CAST)
15458-
{
15459-
noway_assert(!treeWithLcl->gtOverflow());
15460-
treeWithLcl = treeWithLcl->gtGetOp1();
15461-
}
15462-
15463-
noway_assert(callResultLclNumber == treeWithLcl->AsLclVarCommon()->GetLclNum());
15464-
15465-
nextMorphStmt = retStmt->GetNextStmt();
15466-
}
15467-
}
15468-
}
15469-
return nextMorphStmt == nullptr;
15470-
}
15471-
1547215364
//------------------------------------------------------------------------
1547315365
// fgCanTailCallViaJitHelper: check whether we can use the faster tailcall
1547415366
// JIT helper on x86.

0 commit comments

Comments
 (0)