{
GenTreeLclVarCommon* lclVar = op1->AsLclVarCommon();
LclVarDsc* varDsc = &(compiler->lvaTable[lclVar->gtLclNum]);
- assert(varDsc->lvIsMultiRegArgOrRet);
+ assert(varDsc->lvIsMultiRegRet);
ReturnTypeDesc retTypeDesc;
retTypeDesc.InitializeReturnType(compiler, varDsc->lvVerTypeInfo.GetClassHandle());
assert(varTypeIsStruct(treeNode));
// Assumption: current x64 Unix implementation requires that a multi-reg struct
- // var in 'var = call' is flagged as lvIsMultiRegArgOrRet to prevent it from
+ // var in 'var = call' is flagged as lvIsMultiRegRet to prevent it from
// being struct promoted.
unsigned lclNum = treeNode->AsLclVarCommon()->gtLclNum;
LclVarDsc* varDsc = &(compiler->lvaTable[lclNum]);
- noway_assert(varDsc->lvIsMultiRegArgOrRet);
+ noway_assert(varDsc->lvIsMultiRegRet);
GenTree* op1 = treeNode->gtGetOp1();
GenTree* actualOp1 = op1->gtSkipReloadOrCopy();
assert(varTypeIsLong(treeNode));
// Assumption: current x86 implementation requires that a multi-reg long
- // var in 'var = call' is flagged as lvIsMultiRegArgOrRet to prevent it from
+ // var in 'var = call' is flagged as lvIsMultiRegRet to prevent it from
// being promoted.
unsigned lclNum = treeNode->AsLclVarCommon()->gtLclNum;
LclVarDsc* varDsc = &(compiler->lvaTable[lclNum]);
- noway_assert(varDsc->lvIsMultiRegArgOrRet);
+ noway_assert(varDsc->lvIsMultiRegRet);
GenTree* op1 = treeNode->gtGetOp1();
GenTree* actualOp1 = op1->gtSkipReloadOrCopy();
unsigned char lvOverlappingFields :1; // True when we have a struct with possibly overlapping fields
unsigned char lvContainsHoles :1; // True when we have a promoted struct that contains holes
unsigned char lvCustomLayout :1; // True when this struct has "CustomLayout"
- unsigned char lvIsMultiRegArgOrRet:1; // Is this a struct that would be passed or returned in multiple registers?
+
+ unsigned char lvIsMultiRegArg :1; // true if this is a multireg LclVar struct used in an argument context
+ unsigned char lvIsMultiRegRet :1; // true if this is a multireg LclVar struct assigned from a multireg call
#ifdef FEATURE_HFA
unsigned char _lvIsHfa :1; // Is this a struct variable who's class handle is an HFA type
#endif // _TARGET_ARM64_
}
+ // lvIsMultiRegArgOrRet()
+ // returns true if this is a multireg LclVar struct used in an argument context
+ // or if this is a multireg LclVar struct assigned from a multireg call
+ bool lvIsMultiRegArgOrRet()
+ {
+ return lvIsMultiRegArg || lvIsMultiRegRet;
+ }
+
private:
regNumberSmall _lvRegNum; // Used to store the register this variable is in (or, the low register of a register pair).
{
lvaTable[genReturnLocal].lvType = TYP_STRUCT;
lvaSetStruct(genReturnLocal, info.compMethodInfo->args.retTypeClass, true);
- lvaTable[genReturnLocal].lvIsMultiRegArgOrRet = true;
+ lvaTable[genReturnLocal].lvIsMultiRegRet = true;
}
else
{
newInlinee = gtNewAssignNode(dst, src);
// When returning a multi-register value in a local var, make sure the variable is
- // marked as lvIsMultiRegArgOrRet, so it does not get promoted.
+ // marked as lvIsMultiRegRet, so it does not get promoted.
if (src->AsCall()->HasMultiRegRetVal())
{
- lvaTable[tmpNum].lvIsMultiRegArgOrRet = true;
+ lvaTable[tmpNum].lvIsMultiRegRet = true;
}
// If inlinee was comma, but a deeper call, new inlinee is (, , , v05 = call())
dst = gtNewOperNode(GT_ADDR, TYP_BYREF, dst);
opAssign = gtNewCpObjNode(dst, src, clsHnd, false);
- lvaTable[shadowVar].lvIsMultiRegArgOrRet = lvaTable[lclNum].lvIsMultiRegArgOrRet;
+ lvaTable[shadowVar].lvIsMultiRegArg = lvaTable[lclNum].lvIsMultiRegArg;
+ lvaTable[shadowVar].lvIsMultiRegRet = lvaTable[lclNum].lvIsMultiRegRet;
}
else
{
assert(!src->gtCall.IsVarargs() && "varargs not allowed for System V OSs.");
// Make the struct non promotable. The eightbytes could contain multiple fields.
- lvaTable[lcl->gtLclVarCommon.gtLclNum].lvIsMultiRegArgOrRet = true;
+ lvaTable[lcl->gtLclVarCommon.gtLclNum].lvIsMultiRegRet = true;
#endif
}
else
{
// Make sure that this struct stays in memory and doesn't get promoted.
unsigned lclNum = op->gtLclVarCommon.gtLclNum;
- lvaTable[lclNum].lvIsMultiRegArgOrRet = true;
+ lvaTable[lclNum].lvIsMultiRegRet = true;
return op;
}
// This LCL_VAR is an HFA return value, it stays as a TYP_STRUCT
unsigned lclNum = op->gtLclVarCommon.gtLclNum;
// Make sure this struct type stays as struct so that we can return it as an HFA
- lvaTable[lclNum].lvIsMultiRegArgOrRet = true;
+ lvaTable[lclNum].lvIsMultiRegRet = true;
return op;
}
// rdi/rsi (depending whether there is a "this").
unsigned tmp = lvaGrabTemp(true DEBUGARG("UNBOXing a register returnable nullable"));
- lvaTable[tmp].lvIsMultiRegArgOrRet = true;
+ lvaTable[tmp].lvIsMultiRegArg = true;
lvaSetStruct(tmp, resolvedToken.hClass, true /* unsafe value cls check */);
op2 = gtNewLclvNode(tmp, TYP_STRUCT);
(hfaType == TYP_FLOAT && hfaSlots == sizeof(float) / REGSIZE_BYTES))
{
// Make sure this struct type stays as struct so we can receive the call in a struct.
- lvaTable[tmpNum].lvIsMultiRegArgOrRet = true;
+ lvaTable[tmpNum].lvIsMultiRegRet = true;
}
}
}
assert(IsMultiRegReturnedType(hClass));
// Mark the var so that fields are not promoted and stay together.
- lvaTable[tmpNum].lvIsMultiRegArgOrRet = true;
+ lvaTable[tmpNum].lvIsMultiRegRet = true;
#endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
return ret;
varDsc->lvSetIsHfa();
varDsc->lvSetIsHfaRegArg();
varDsc->SetHfaType(hfaType);
- varDsc->lvIsMultiRegArgOrRet = (varDsc->lvHfaSlots() > 1);
+ varDsc->lvIsMultiRegArg = (varDsc->lvHfaSlots() > 1);
}
varDsc->lvIsRegArg = 1;
lclNum++)
{
LclVarDsc * varDsc = &lvaTable[lclNum];
- if(!varTypeIsLong(varDsc) || varDsc->lvDoNotEnregister || varDsc->lvIsMultiRegArgOrRet || (varDsc->lvRefCnt == 0))
+ if(!varTypeIsLong(varDsc) || varDsc->lvDoNotEnregister || varDsc->lvIsMultiRegArgOrRet() || (varDsc->lvRefCnt == 0))
{
continue;
}
if (parent->gtOper == GT_STORE_LCL_VAR)
{
// If parent is already a STORE_LCL_VAR, we can skip it if
- // it is already marked as lvIsMultiRegArgOrRet
+ // it is already marked as lvIsMultiRegRet
unsigned varNum = parent->AsLclVarCommon()->gtLclNum;
- if (comp->lvaTable[varNum].lvIsMultiRegArgOrRet)
+ if (comp->lvaTable[varNum].lvIsMultiRegRet)
{
break;
}
else if (!comp->lvaTable[varNum].lvPromoted)
{
- // If var wasn't promoted, we can just set lvIsMultiRegArgOrRet
- comp->lvaTable[varNum].lvIsMultiRegArgOrRet = true;
+ // If var wasn't promoted, we can just set lvIsMultiRegRet
+ comp->lvaTable[varNum].lvIsMultiRegRet = true;
break;
}
}
assert(stLclVar->OperIsLocalStore());
unsigned varNum = stLclVar->AsLclVarCommon()->gtLclNum;
- comp->lvaTable[varNum].lvIsMultiRegArgOrRet = true;
+ comp->lvaTable[varNum].lvIsMultiRegRet = true;
comp->fgFixupIfCallArg(data->parentStack, tree, *treePtr);
// Decompose new node
{
GenTreeLclVarCommon* lclVarCommon = op1->AsLclVarCommon();
LclVarDsc* varDsc = &(compiler->lvaTable[lclVarCommon->gtLclNum]);
- assert(varDsc->lvIsMultiRegArgOrRet);
+ assert(varDsc->lvIsMultiRegRet);
// Mark var as contained if not enregistrable.
if (!varTypeIsEnregisterableStruct(op1))
//
assert((varDsc->lvSize() == 2*TARGET_POINTER_SIZE) || varDsc->lvIsHfa());
- varDsc->lvIsMultiRegArgOrRet = true;
+ varDsc->lvIsMultiRegArg = true;
#ifdef DEBUG
if (verbose)
tooManyLocals = true;
}
#if !FEATURE_MULTIREG_STRUCT_PROMOTE
- else if (varDsc->lvIsMultiRegArgOrRet)
+ else if (varDsc->lvIsMultiRegArg)
{
- JITDUMP("Skipping V%02u: marked lvIsMultiRegArgOrRet.\n", lclNum);
+ JITDUMP("Skipping V%02u: marked lvIsMultiRegArg.\n", lclNum);
}
#endif // !FEATURE_MULTIREG_STRUCT_PROMOTE
+ else if (varDsc->lvIsMultiRegRet)
+ {
+ JITDUMP("Skipping V%02u: marked lvIsMultiRegRet.\n", lclNum);
+ }
else if (varTypeIsStruct(varDsc))
{
lvaCanPromoteStructVar(lclNum, &structPromotionInfo);