}
case GT_COMMA:
- {
- Statement* oldLastStmt = impLastStmt;
- structVal->AsOp()->gtOp2 = impGetStructAddr(structVal->AsOp()->gtOp2, structHnd, curLevel, willDeref);
- structVal->gtType = TYP_BYREF;
-
- if (oldLastStmt != impLastStmt)
- {
- // Some temp assignment statement was placed on the statement list
- // for Op2, but that would be out of order with op1, so we need to
- // spill op1 onto the statement list after whatever was last
- // before we recursed on Op2 (i.e. before whatever Op2 appended).
- Statement* beforeStmt;
- if (oldLastStmt == nullptr)
- {
- // The op1 stmt should be the first in the list.
- beforeStmt = impStmtList;
- }
- else
- {
- // Insert after the oldLastStmt before the first inserted for op2.
- beforeStmt = oldLastStmt->GetNextStmt();
- }
-
- impInsertTreeBefore(structVal->AsOp()->gtOp1, impCurStmtDI, beforeStmt);
- structVal->AsOp()->gtOp1 = gtNewNothingNode();
- }
-
- return structVal;
- }
+ impAppendTree(structVal->AsOp()->gtGetOp1(), curLevel, impCurStmtDI);
+ return impGetStructAddr(structVal->AsOp()->gtGetOp2(), structHnd, curLevel, willDeref);
default:
break;
}
//------------------------------------------------------------------------
-// Compiler::impNormStructVal: Normalize a struct value
+// impNormStructVal: Normalize a struct call argument
//
-// Arguments:
-// structVal - the node we are going to normalize
-// structHnd - the class handle for the node
-// curLevel - the current stack level
+// Spills call-like STRUCT arguments to temporaries. "Unwraps" commas.
//
-// Notes:
-// Given struct value 'structVal', make sure it is 'canonical', that is
-// it is either:
-// - a known struct type (non-TYP_STRUCT, e.g. TYP_SIMD8)
-// - a BLK or a MKREFANY node, or
-// - a node (e.g. GT_FIELD) that will be morphed.
-// If the node is a CALL or RET_EXPR, a copy will be made to a new temp.
+// Arguments:
+// structVal - The node to normalize
+// structHnd - The struct type
+// curLevel - The current stack level
+//
+// Return Value:
+// The normalized "structVal".
//
GenTree* Compiler::impNormStructVal(GenTree* structVal, CORINFO_CLASS_HANDLE structHnd, unsigned curLevel)
{
assert(varTypeIsStruct(structVal));
- assert(structHnd != NO_CLASS_HANDLE);
var_types structType = structVal->TypeGet();
- bool makeTemp = false;
- if (structType == TYP_STRUCT)
- {
- structType = impNormStructType(structHnd);
- }
- GenTreeLclVarCommon* structLcl = nullptr;
switch (structVal->OperGet())
{
case GT_CALL:
case GT_RET_EXPR:
- makeTemp = true;
- break;
+ {
+ unsigned lclNum = lvaGrabTemp(true DEBUGARG("spilled call-like call argument"));
+ impAssignTempGen(lclNum, structVal, curLevel);
- case GT_LCL_VAR:
- case GT_LCL_FLD:
- case GT_IND:
- case GT_BLK:
- case GT_FIELD:
- case GT_CNS_VEC:
-#ifdef FEATURE_HW_INTRINSICS
- case GT_HWINTRINSIC:
-#endif
- case GT_MKREFANY:
- // These should already have the appropriate type.
- assert(structVal->TypeGet() == structType);
- break;
+ // The structVal is now the temp itself
+ structVal = gtNewLclvNode(lclNum, structType);
+ }
+ break;
case GT_COMMA:
{
- // The second thing could either be a block node or a GT_FIELD or a GT_COMMA node.
GenTree* blockNode = structVal->AsOp()->gtOp2;
assert(blockNode->gtType == structType);
} while (blockNode->OperGet() == GT_COMMA);
}
-#ifdef FEATURE_SIMD
- if (blockNode->OperIsHWIntrinsic() || blockNode->IsCnsVec())
- {
- parent->AsOp()->gtOp2 = impNormStructVal(blockNode, structHnd, curLevel);
- }
- else
-#endif
+ if (blockNode->OperIsBlk() || blockNode->OperIs(GT_FIELD))
{
- noway_assert(blockNode->OperIsIndir() || blockNode->OperIs(GT_FIELD));
-
// Sink the GT_COMMA below the blockNode addr.
// That is GT_COMMA(op1, op2=blockNode) is transformed into
// blockNode(GT_COMMA(TYP_BYREF, op1, op2's op1)).
commaNode->gtType = blockNodeAddr->gtType;
commaNode->AsOp()->gtOp2 = blockNodeAddr;
blockNode->AsOp()->gtOp1 = commaNode;
+ blockNode->AddAllEffectsFlags(commaNode);
if (parent == structVal)
{
structVal = blockNode;
break;
default:
- noway_assert(!"Unexpected node in impNormStructVal()");
break;
}
- if (makeTemp)
- {
- unsigned tmpNum = lvaGrabTemp(true DEBUGARG("struct address for call/obj"));
-
- impAssignTempGen(tmpNum, structVal, structHnd, curLevel);
-
- // The structVal is now the temp itself
-
- structLcl = gtNewLclvNode(tmpNum, structType)->AsLclVarCommon();
- structVal = structLcl;
- }
-
- if (structLcl != nullptr)
- {
- // A BLK on a ADDR(LCL_VAR) can never raise an exception
- // so we don't set GTF_EXCEPT here.
- if (!lvaIsImplicitByRefLocal(structLcl->GetLclNum()))
- {
- structVal->gtFlags &= ~GTF_GLOB_REF;
- }
- }
- else if (structVal->OperIsBlk())
- {
- // In general a BLK is an indirection and could raise an exception.
- structVal->gtFlags |= GTF_EXCEPT;
- }
return structVal;
}