@@ -1725,20 +1725,12 @@ void Lowering::LowerArg(GenTreeCall* call, CallArg* callArg)
17251725 {
17261726 if (abiInfo.HasAnyRegisterSegment ())
17271727 {
1728- #if FEATURE_MULTIREG_ARGS
1729- if ((abiInfo.NumSegments > 1 ) && arg->OperIs (GT_FIELD_LIST))
1728+ if (arg->OperIs (GT_FIELD_LIST))
17301729 {
1731- unsigned int regIndex = 0 ;
1732- for (GenTreeFieldList::Use& use : arg->AsFieldList ()->Uses ())
1733- {
1734- const ABIPassingSegment& segment = abiInfo.Segment (regIndex);
1735- InsertPutArgReg (&use.NodeRef (), segment);
1736-
1737- regIndex++;
1738- }
1730+ LowerArgFieldList (callArg, arg->AsFieldList ());
1731+ arg = *ppArg;
17391732 }
17401733 else
1741- #endif // FEATURE_MULTIREG_ARGS
17421734 {
17431735 assert (abiInfo.HasExactlyOneRegisterSegment ());
17441736 InsertPutArgReg (ppArg, abiInfo.Segment (0 ));
@@ -4809,6 +4801,18 @@ void Lowering::LowerRet(GenTreeOp* ret)
48094801 ContainCheckRet (ret);
48104802}
48114803
4804+ struct LowerFieldListRegisterInfo
4805+ {
4806+ unsigned Offset;
4807+ var_types RegType;
4808+
4809+ LowerFieldListRegisterInfo (unsigned offset, var_types regType)
4810+ : Offset(offset)
4811+ , RegType(regType)
4812+ {
4813+ }
4814+ };
4815+
48124816// ----------------------------------------------------------------------------------------------
48134817// LowerRetFieldList:
48144818// Lower a returned FIELD_LIST node.
@@ -4822,21 +4826,18 @@ void Lowering::LowerRetFieldList(GenTreeOp* ret, GenTreeFieldList* fieldList)
48224826 const ReturnTypeDesc& retDesc = comp->compRetTypeDesc ;
48234827 unsigned numRegs = retDesc.GetReturnRegCount ();
48244828
4825- bool isCompatible = IsFieldListCompatibleWithReturn (fieldList);
4829+ auto getRegInfo = [=, &retDesc](unsigned regIndex) {
4830+ unsigned offset = retDesc.GetReturnFieldOffset (regIndex);
4831+ var_types regType = genActualType (retDesc.GetReturnRegType (regIndex));
4832+ return LowerFieldListRegisterInfo (offset, regType);
4833+ };
4834+
4835+ bool isCompatible = IsFieldListCompatibleWithRegisters (fieldList, numRegs, getRegInfo);
48264836 if (!isCompatible)
48274837 {
4828- JITDUMP ( " Spilling field list [%06u] to stack \n " , Compiler::dspTreeID (fieldList));
4829- unsigned lclNum = comp->lvaGrabTemp ( true DEBUGARG ( " Spilled local for return value " ) );
4838+ unsigned lclNum =
4839+ StoreFieldListToNewLocal ( comp->typGetObjLayout (comp-> info . compMethodInfo -> args . retTypeClass ), fieldList );
48304840 LclVarDsc* varDsc = comp->lvaGetDesc (lclNum);
4831- comp->lvaSetStruct (lclNum, comp->info .compMethodInfo ->args .retTypeClass , false );
4832- comp->lvaSetVarDoNotEnregister (lclNum DEBUGARG (DoNotEnregisterReason::BlockOpRet));
4833-
4834- for (GenTreeFieldList::Use& use : fieldList->Uses ())
4835- {
4836- GenTree* store = comp->gtNewStoreLclFldNode (lclNum, use.GetType (), use.GetOffset (), use.GetNode ());
4837- BlockRange ().InsertAfter (use.GetNode (), store);
4838- LowerNode (store);
4839- }
48404841
48414842 GenTree* retValue = comp->gtNewLclvNode (lclNum, varDsc->TypeGet ());
48424843 ret->SetReturnValue (retValue);
@@ -4859,7 +4860,89 @@ void Lowering::LowerRetFieldList(GenTreeOp* ret, GenTreeFieldList* fieldList)
48594860 return ;
48604861 }
48614862
4862- LowerFieldListToFieldListOfRegisters (fieldList);
4863+ LowerFieldListToFieldListOfRegisters (fieldList, numRegs, getRegInfo);
4864+ }
4865+
4866+ // ----------------------------------------------------------------------------------------------
4867+ // StoreFieldListToNewLocal:
4868+ // Create a new local with the specified layout and store the specified
4869+ // fields of the specified FIELD_LIST into it.
4870+ //
4871+ // Arguments:
4872+ // layout - Layout of the new local
4873+ // fieldList - Fields to store to it
4874+ //
4875+ // Returns:
4876+ // Var number of new local.
4877+ //
4878+ unsigned Lowering::StoreFieldListToNewLocal (ClassLayout* layout, GenTreeFieldList* fieldList)
4879+ {
4880+ JITDUMP (" Spilling field list [%06u] to stack\n " , Compiler::dspTreeID (fieldList));
4881+ unsigned lclNum = comp->lvaGrabTemp (true DEBUGARG (" Spilled local for field list" ));
4882+ LclVarDsc* varDsc = comp->lvaGetDesc (lclNum);
4883+ comp->lvaSetStruct (lclNum, layout, false );
4884+ comp->lvaSetVarDoNotEnregister (lclNum DEBUGARG (DoNotEnregisterReason::LocalField));
4885+
4886+ for (GenTreeFieldList::Use& use : fieldList->Uses ())
4887+ {
4888+ GenTree* store = comp->gtNewStoreLclFldNode (lclNum, use.GetType (), use.GetOffset (), use.GetNode ());
4889+ BlockRange ().InsertAfter (use.GetNode (), store);
4890+ LowerNode (store);
4891+ }
4892+
4893+ return lclNum;
4894+ }
4895+
4896+ // ----------------------------------------------------------------------------------------------
4897+ // LowerArgFieldList:
4898+ // Lower an argument FIELD_LIST node.
4899+ //
4900+ // Arguments:
4901+ // arg - The argument
4902+ // fieldList - The FIELD_LIST node
4903+ //
4904+ void Lowering::LowerArgFieldList (CallArg* arg, GenTreeFieldList* fieldList)
4905+ {
4906+ assert (!arg->AbiInfo .HasAnyStackSegment ());
4907+
4908+ auto getRegInfo = [=](unsigned regIndex) {
4909+ const ABIPassingSegment& seg = arg->AbiInfo .Segment (regIndex);
4910+ return LowerFieldListRegisterInfo (seg.Offset , seg.GetRegisterType ());
4911+ };
4912+
4913+ bool isCompatible = IsFieldListCompatibleWithRegisters (fieldList, arg->AbiInfo .NumSegments , getRegInfo);
4914+ if (!isCompatible)
4915+ {
4916+ ClassLayout* layout = comp->typGetObjLayout (arg->GetSignatureClassHandle ());
4917+ unsigned lclNum = StoreFieldListToNewLocal (layout, fieldList);
4918+ fieldList->Uses ().Clear ();
4919+ for (const ABIPassingSegment& seg : arg->AbiInfo .Segments ())
4920+ {
4921+ GenTreeLclFld* fld = comp->gtNewLclFldNode (lclNum, seg.GetRegisterType (layout), seg.Offset );
4922+ fieldList->AddFieldLIR (comp, fld, seg.Offset , fld->TypeGet ());
4923+ BlockRange ().InsertBefore (fieldList, fld);
4924+ }
4925+ }
4926+ else
4927+ {
4928+ LowerFieldListToFieldListOfRegisters (fieldList, arg->AbiInfo .NumSegments , getRegInfo);
4929+ }
4930+
4931+ GenTreeFieldList::Use* field = fieldList->Uses ().GetHead ();
4932+ for (const ABIPassingSegment& seg : arg->AbiInfo .Segments ())
4933+ {
4934+ assert ((field != nullptr ) && " Ran out of fields while inserting PUTARG_REG" );
4935+ InsertPutArgReg (&field->NodeRef (), seg);
4936+ field = field->GetNext ();
4937+ }
4938+
4939+ assert ((field == nullptr ) && " Missed fields while inserting PUTARG_REG" );
4940+
4941+ arg->NodeRef () = fieldList->SoleFieldOrThis ();
4942+ if (arg->GetNode () != fieldList)
4943+ {
4944+ BlockRange ().Remove (fieldList);
4945+ }
48634946}
48644947
48654948// ----------------------------------------------------------------------------------------------
@@ -4874,21 +4957,23 @@ void Lowering::LowerRetFieldList(GenTreeOp* ret, GenTreeFieldList* fieldList)
48744957// True if the fields of the FIELD_LIST are all direct insertions into the
48754958// return registers.
48764959//
4877- bool Lowering::IsFieldListCompatibleWithReturn (GenTreeFieldList* fieldList)
4960+ template <typename GetRegisterInfoFunc>
4961+ bool Lowering::IsFieldListCompatibleWithRegisters (GenTreeFieldList* fieldList,
4962+ unsigned numRegs,
4963+ GetRegisterInfoFunc getRegInfo)
48784964{
4879- JITDUMP (" Checking if field list [%06u] is compatible with return ABI: " , Compiler::dspTreeID (fieldList));
4880- const ReturnTypeDesc& retDesc = comp->compRetTypeDesc ;
4881- unsigned numRetRegs = retDesc.GetReturnRegCount ();
4965+ JITDUMP (" Checking if field list [%06u] is compatible with registers: " , Compiler::dspTreeID (fieldList));
48824966
48834967 GenTreeFieldList::Use* use = fieldList->Uses ().GetHead ();
4884- for (unsigned i = 0 ; i < numRetRegs ; i++)
4968+ for (unsigned i = 0 ; i < numRegs ; i++)
48854969 {
4886- unsigned regStart = retDesc.GetReturnFieldOffset (i);
4887- var_types regType = retDesc.GetReturnRegType (i);
4888- unsigned regEnd = regStart + genTypeSize (regType);
4970+ LowerFieldListRegisterInfo regInfo = getRegInfo (i);
4971+ unsigned regStart = regInfo.Offset ;
4972+ var_types regType = regInfo.RegType ;
4973+ unsigned regEnd = regStart + genTypeSize (regType);
48894974
48904975 // TODO-CQ: Could just create a 0 for this.
4891- if (use == nullptr )
4976+ if (( use == nullptr ) || (use-> GetOffset () >= regEnd) )
48924977 {
48934978 JITDUMP (" it is not; register %u has no corresponding field\n " , i);
48944979 return false ;
@@ -4949,19 +5034,20 @@ bool Lowering::IsFieldListCompatibleWithReturn(GenTreeFieldList* fieldList)
49495034// Arguments:
49505035// fieldList - The field list
49515036//
4952- void Lowering::LowerFieldListToFieldListOfRegisters (GenTreeFieldList* fieldList)
5037+ template <typename GetRegisterInfoFunc>
5038+ void Lowering::LowerFieldListToFieldListOfRegisters (GenTreeFieldList* fieldList,
5039+ unsigned numRegs,
5040+ GetRegisterInfoFunc getRegInfo)
49535041{
4954- const ReturnTypeDesc& retDesc = comp->compRetTypeDesc ;
4955- unsigned numRegs = retDesc.GetReturnRegCount ();
4956-
49575042 GenTreeFieldList::Use* use = fieldList->Uses ().GetHead ();
49585043 assert (fieldList->Uses ().IsSorted ());
49595044
49605045 for (unsigned i = 0 ; i < numRegs; i++)
49615046 {
4962- unsigned regStart = retDesc.GetReturnFieldOffset (i);
4963- var_types regType = genActualType (retDesc.GetReturnRegType (i));
4964- unsigned regEnd = regStart + genTypeSize (regType);
5047+ LowerFieldListRegisterInfo regInfo = getRegInfo (i);
5048+ unsigned regStart = regInfo.Offset ;
5049+ var_types regType = regInfo.RegType ;
5050+ unsigned regEnd = regStart + genTypeSize (regType);
49655051
49665052 GenTreeFieldList::Use* regEntry = use;
49675053
@@ -5001,7 +5087,7 @@ void Lowering::LowerFieldListToFieldListOfRegisters(GenTreeFieldList* fieldList)
50015087 }
50025088
50035089 // If this is a float -> int insertion, then we need the bitcast now.
5004- if (varTypeUsesFloatReg (value) && varTypeUsesIntReg (regType ))
5090+ if (varTypeUsesFloatReg (value) && varTypeUsesIntReg (regInfo. RegType ))
50055091 {
50065092 assert ((genTypeSize (value) == 4 ) || (genTypeSize (value) == 8 ));
50075093 var_types castType = genTypeSize (value) == 4 ? TYP_INT : TYP_LONG;
0 commit comments