@@ -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