summaryrefslogtreecommitdiff
path: root/src/jit/morph.cpp
diff options
context:
space:
mode:
authorEugene Rozenfeld <erozen@microsoft.com>2019-02-08 00:14:35 -0800
committerGitHub <noreply@github.com>2019-02-08 00:14:35 -0800
commita8ebed30b50c32a84ca8edbe033870a9e0f1da61 (patch)
tree43e51ea34350bbc47ce3ba7da2f029b490ac96e9 /src/jit/morph.cpp
parentea452c1ff113413bddd22794dcac0359af0e79fe (diff)
downloadcoreclr-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/morph.cpp')
-rw-r--r--src/jit/morph.cpp52
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;
}