diff options
author | Eugene Rozenfeld <erozen@microsoft.com> | 2019-02-08 00:14:35 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-02-08 00:14:35 -0800 |
commit | a8ebed30b50c32a84ca8edbe033870a9e0f1da61 (patch) | |
tree | 43e51ea34350bbc47ce3ba7da2f029b490ac96e9 /src/jit | |
parent | ea452c1ff113413bddd22794dcac0359af0e79fe (diff) | |
download | coreclr-a8ebed30b50c32a84ca8edbe033870a9e0f1da61.tar.gz coreclr-a8ebed30b50c32a84ca8edbe033870a9e0f1da61.tar.bz2 coreclr-a8ebed30b50c32a84ca8edbe033870a9e0f1da61.zip |
Force results of rejected multi-reg-returning tail-call candidates to temp. (#22364)
* Force results of rejected multi-reg-returning tail-call candidates to temp.
Issue #20269 ran into an assert when trying to merge returns, one of which
is a call to a multi-reg-returning method. The repro in the bug is a pmi
of `System.Reflection.Metadata`. I added a simple repro test case.
Results of calls to multi-reg-returning methods are expected to
be saved to temps. Normally it's ensured by `impFixupCallStructReturn`;
however, it doesn't do that for tail-call candidates.
This change forces results of calls to multi-reg-returning methods
to temps if the tail call is rejected late in morph.
Fixes #20269.
Diffstat (limited to 'src/jit')
-rw-r--r-- | src/jit/morph.cpp | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/src/jit/morph.cpp b/src/jit/morph.cpp index 00a0e3aea3..ff9320ab26 100644 --- a/src/jit/morph.cpp +++ b/src/jit/morph.cpp @@ -8248,6 +8248,58 @@ GenTree* Compiler::fgMorphCall(GenTreeCall* call) (call->gtCallType == CT_USER_FUNC) ? call->gtCallMethHnd : nullptr, isTailPrefixed, TAILCALL_FAIL, szFailReason); +#if FEATURE_MULTIREG_RET + if (fgGlobalMorph && call->HasMultiRegRetVal()) + { + // The tail call has been rejected so we must finish the work deferred + // by impFixupCallStructReturn for multi-reg-returning calls and transform + // ret call + // into + // temp = call + // ret temp + + // Create a new temp. + unsigned tmpNum = + lvaGrabTemp(false DEBUGARG("Return value temp for multi-reg return (rejected tail call).")); + lvaTable[tmpNum].lvIsMultiRegRet = true; + + GenTree* assg = nullptr; + if (varTypeIsStruct(callType)) + { + CORINFO_CLASS_HANDLE structHandle = call->gtRetClsHnd; + assert(structHandle != NO_CLASS_HANDLE); + const bool unsafeValueClsCheck = false; + lvaSetStruct(tmpNum, structHandle, unsafeValueClsCheck); + var_types structType = lvaTable[tmpNum].lvType; + GenTree* dst = gtNewLclvNode(tmpNum, structType); + assg = gtNewAssignNode(dst, call); + } + else + { + assg = gtNewTempAssign(tmpNum, call); + } + + assg = fgMorphTree(assg); + + // Create the assignment statement and insert it before the current statement. + GenTree* assgStmt = gtNewStmt(assg, compCurStmt->AsStmt()->gtStmtILoffsx); + fgInsertStmtBefore(compCurBB, compCurStmt, assgStmt); + + // Return the temp. + GenTree* result = gtNewLclvNode(tmpNum, lvaTable[tmpNum].lvType); + result->gtFlags |= GTF_DONT_CSE; + +#ifdef DEBUG + if (verbose) + { + printf("\nInserting assignment of a multi-reg call result to a temp:\n"); + gtDispTree(assgStmt); + } + result->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED; +#endif // DEBUG + return result; + } +#endif goto NO_TAIL_CALL; } |