The change fixes a bug in importing POP instruction where a copy between a tempvar and the return value of a tail call is misgenerated for Unix with enregisterable struct return values.
The change also fixes a bug of using GenTree::CopyFrom in fMorphInline where the dst node is a child of the src node.
else
{
// Just assign the inlinee to a variable to keep it simple.
- tree->CopyFrom(comp->fgAssignStructInlineeToVar(tree, retClsHnd), comp);
+ tree = comp->fgAssignStructInlineeToVar(tree, retClsHnd);
}
}
#endif // defined(_TARGET_ARM_) || defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
if ((op1->gtFlags & GTF_SIDE_EFFECT) || opts.compDbgCode)
{
+#if FEATURE_MULTIREG_STRUCT_RET
+ bool isStructTailCall = varTypeIsStruct(op1) && (op1->gtOper == GT_CALL)
+ && op1->gtCall.CanTailCall();
+#endif
// Since we are throwing away the value, just normalize
// it to its address. This is more efficient.
op1 = gtUnusedValNode(op1);
}
- /* Append the value to the tree list */
+ // Append the value to the tree list
+#if FEATURE_MULTIREG_STRUCT_RET
+ // On Unix, a call with a structral return value will have either an assignment
+ // copying the return registers to stack or an address taken expression of the
+ // hidden parameter inserted, depends on the size of the return value. We don't
+ // want to insert any more instructions after the call, since it will screw up
+ // the tail call morphing logic.
+ if (!isStructTailCall)
+#endif
goto SPILL_APPEND;
}
}
else if ((stmtExpr->gtOper == GT_ASG) && (fgMorphStmt->gtNext != nullptr))
{
- GenTreePtr nextStmtExpr = fgMorphStmt->gtNext->gtStmt.gtStmtExpr;
- noway_assert(nextStmtExpr->gtOper == GT_RETURN);
- // In this case we have an assignment of the result of the call, and then a return of the result of the assignment.
- // This can occur if impSpillStackEnsure() has introduced an assignment to a temp.
- noway_assert(stmtExpr->gtGetOp1()->OperIsLocal() &&
- nextStmtExpr->OperGet() == GT_RETURN &&
- nextStmtExpr->gtGetOp1() != nullptr &&
- nextStmtExpr->gtGetOp1()->OperIsLocal() &&
- stmtExpr->gtGetOp1()->AsLclVarCommon()->gtLclNum == nextStmtExpr->gtGetOp1()->AsLclVarCommon()->gtLclNum);
+ noway_assert(fgMorphStmt->gtNext->gtStmt.gtStmtExpr->gtOper == GT_RETURN);
deleteReturn = true;
}
+
if (deleteReturn)
{
fgRemoveStmt(compCurBB, fgMorphStmt->gtNext);