@@ -821,18 +821,10 @@ void CallArg::Dump(Compiler* comp)
821821 {
822822 printf(", isSplit");
823823 }
824- if (m_needTmp)
825- {
826- printf(", tmpNum=V%02u", m_tmpNum);
827- }
828824 if (m_needPlace)
829825 {
830826 printf(", needPlace");
831827 }
832- if (m_isTmp)
833- {
834- printf(", isTmp");
835- }
836828 if (m_processed)
837829 {
838830 printf(", processed");
@@ -849,15 +841,6 @@ void CallArg::Dump(Compiler* comp)
849841}
850842#endif
851843
852- //------------------------------------------------------------------------
853- // SetTemp: Set that the specified argument was evaluated into a temp.
854- //
855- void CallArgs::SetTemp(CallArg* arg, unsigned tmpNum)
856- {
857- arg->m_tmpNum = tmpNum;
858- arg->m_isTmp = true;
859- }
860-
861844//------------------------------------------------------------------------
862845// ArgsComplete: Make final decisions on which arguments to evaluate into temporaries.
863846//
@@ -874,13 +857,7 @@ void CallArgs::ArgsComplete(Compiler* comp, GenTreeCall* call)
874857 for (CallArg& arg : Args())
875858 {
876859 GenTree* argx = arg.GetEarlyNode();
877-
878- if (argx == nullptr)
879- {
880- // Should only happen if remorphing in which case we do not need to
881- // make a decision about temps.
882- continue;
883- }
860+ assert(argx != nullptr);
884861
885862 bool canEvalToTemp = true;
886863 if (arg.AbiInfo.GetRegNum() == REG_STK)
@@ -909,19 +886,16 @@ void CallArgs::ArgsComplete(Compiler* comp, GenTreeCall* call)
909886 //
910887 if ((argx->gtFlags & GTF_ASG) != 0)
911888 {
912- // If this is not the only argument, or it's a copyblk, or it
913- // already evaluates the expression to a tmp then we need a temp in
914- // the late arg list.
915- // In the latter case this might not even be a value;
916- // fgMakeOutgoingStructArgCopy will leave the copying nodes here
917- // for FEATURE_FIXED_OUT_ARGS.
918- if (canEvalToTemp && ((argCount > 1) || argx->OperIsCopyBlkOp() || (FEATURE_FIXED_OUT_ARGS && arg.m_isTmp)))
889+ // fgMakeOutgoingStructArgCopy can have introduced a temp already,
890+ // in which case it will have created a setup node in the early
891+ // node.
892+ if (!argx->IsValue())
919893 {
920- SetNeedsTemp(& arg);
894+ assert( arg.m_needTmp );
921895 }
922- else
896+ else if (canEvalToTemp && (argCount > 1))
923897 {
924- assert(argx->IsValue() );
898+ SetNeedsTemp(&arg );
925899 }
926900
927901 // For all previous arguments that may interfere with the store we
@@ -1318,8 +1292,6 @@ void CallArgs::SortArgs(Compiler* comp, GenTreeCall* call, CallArg** sortedArgs)
13181292 regCount++;
13191293 }
13201294
1321- assert(arg->GetLateNode() == nullptr);
1322-
13231295 // Skip any already processed args
13241296 //
13251297 if (!arg->m_processed)
@@ -1556,9 +1528,8 @@ void CallArgs::SortArgs(Compiler* comp, GenTreeCall* call, CallArg** sortedArgs)
15561528// Return Value:
15571529// the newly created temp var tree.
15581530//
1559- GenTree* CallArgs::MakeTmpArgNode(Compiler* comp, CallArg* arg)
1531+ GenTree* CallArgs::MakeTmpArgNode(Compiler* comp, CallArg* arg, unsigned lclNum )
15601532{
1561- unsigned lclNum = arg->m_tmpNum;
15621533 LclVarDsc* varDsc = comp->lvaGetDesc(lclNum);
15631534 var_types argType = varDsc->TypeGet();
15641535 assert(genActualType(argType) == genActualType(arg->GetSignatureType()));
@@ -1633,7 +1604,16 @@ void CallArgs::EvalArgsToTemps(Compiler* comp, GenTreeCall* call)
16331604 for (size_t i = 0; i < numArgs; i++)
16341605 {
16351606 CallArg& arg = *(sortedArgs[i]);
1636- assert(arg.GetLateNode() == nullptr);
1607+
1608+ if (arg.GetLateNode() != nullptr)
1609+ {
1610+ // We may already have created the temp as part of
1611+ // fgMakeOutgoingStructArgCopy. In that case there is no work to be
1612+ // done.
1613+ *lateTail = &arg;
1614+ lateTail = &arg.LateNextRef();
1615+ continue;
1616+ }
16371617
16381618 GenTree* argx = arg.GetEarlyNode();
16391619 assert(argx != nullptr);
@@ -1655,82 +1635,60 @@ void CallArgs::EvalArgsToTemps(Compiler* comp, GenTreeCall* call)
16551635
16561636 if (arg.m_needTmp)
16571637 {
1658- if (arg.m_isTmp)
1659- {
1660- // Create a copy of the temp to go into the late argument list
1661- defArg = MakeTmpArgNode(comp, &arg);
1662- }
1663- else
1664- {
1665- // Create a temp store for the argument
1666- // Put the temp in the late arg list
1638+ // Create a temp store for the argument
1639+ // Put the temp in the late arg list
16671640
16681641#ifdef DEBUG
1669- if (comp->verbose)
1670- {
1671- printf("Argument with 'side effect'...\n");
1672- comp->gtDispTree(argx);
1673- }
1642+ if (comp->verbose)
1643+ {
1644+ printf("Argument with 'side effect'...\n");
1645+ comp->gtDispTree(argx);
1646+ }
16741647#endif
16751648
16761649#if defined(TARGET_AMD64) && !defined(UNIX_AMD64_ABI)
1677- noway_assert(argx->gtType != TYP_STRUCT);
1650+ noway_assert(argx->gtType != TYP_STRUCT);
16781651#endif
16791652
1680- unsigned tmpVarNum = comp->lvaGrabTemp(true DEBUGARG("argument with side effect"));
1653+ unsigned tmpVarNum = comp->lvaGrabTemp(true DEBUGARG("argument with side effect"));
16811654
1682- if (setupArg != nullptr)
1683- {
1684- // Now keep the mkrefany for the late argument list
1685- defArg = argx;
1655+ setupArg = comp->gtNewTempStore(tmpVarNum, argx);
16861656
1687- // Clear the side-effect flags because now both op1 and op2 have no side-effects
1688- defArg->gtFlags &= ~GTF_ALL_EFFECT;
1689- }
1690- else
1691- {
1692- setupArg = comp->gtNewTempStore(tmpVarNum, argx);
1657+ LclVarDsc* varDsc = comp->lvaGetDesc(tmpVarNum);
1658+ var_types lclVarType = genActualType(argx->gtType);
1659+ var_types scalarType = TYP_UNKNOWN;
16931660
1694- LclVarDsc* varDsc = comp->lvaGetDesc(tmpVarNum);
1695- var_types lclVarType = genActualType(argx->gtType);
1696- var_types scalarType = TYP_UNKNOWN;
1697-
1698- if (setupArg->OperIsCopyBlkOp())
1699- {
1700- setupArg = comp->fgMorphCopyBlock(setupArg);
1661+ if (setupArg->OperIsCopyBlkOp())
1662+ {
1663+ setupArg = comp->fgMorphCopyBlock(setupArg);
17011664#if defined(TARGET_ARMARCH) || defined(UNIX_AMD64_ABI) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
1702- if ((lclVarType == TYP_STRUCT) && (arg.AbiInfo.ArgType != TYP_STRUCT))
1703- {
1704- scalarType = arg.AbiInfo.ArgType;
1705- }
1665+ if ((lclVarType == TYP_STRUCT) && (arg.AbiInfo.ArgType != TYP_STRUCT))
1666+ {
1667+ scalarType = arg.AbiInfo.ArgType;
1668+ }
17061669#endif // TARGET_ARMARCH || defined (UNIX_AMD64_ABI) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
1707- }
1708-
1709- // scalarType can be set to a wider type for ARM or unix amd64 architectures: (3 => 4) or (5,6,7 =>
1710- // 8)
1711- if ((scalarType != TYP_UNKNOWN) && (scalarType != lclVarType))
1712- {
1713- // Create a GT_LCL_FLD using the wider type to go to the late argument list
1714- defArg = comp->gtNewLclFldNode(tmpVarNum, scalarType, 0);
1715- }
1716- else
1717- {
1718- // Create a copy of the temp to go to the late argument list
1719- defArg = comp->gtNewLclvNode(tmpVarNum, lclVarType);
1720- }
1670+ }
17211671
1722- arg.m_isTmp = true;
1723- arg.m_tmpNum = tmpVarNum;
1724- }
1672+ // scalarType can be set to a wider type for ARM or unix amd64 architectures: (3 => 4) or (5,6,7 =>
1673+ // 8)
1674+ if ((scalarType != TYP_UNKNOWN) && (scalarType != lclVarType))
1675+ {
1676+ // Create a GT_LCL_FLD using the wider type to go to the late argument list
1677+ defArg = comp->gtNewLclFldNode(tmpVarNum, scalarType, 0);
1678+ }
1679+ else
1680+ {
1681+ // Create a copy of the temp to go to the late argument list
1682+ defArg = comp->gtNewLclvNode(tmpVarNum, lclVarType);
1683+ }
17251684
17261685#ifdef DEBUG
1727- if (comp->verbose)
1728- {
1729- printf("\n Evaluate to a temp:\n");
1730- comp->gtDispTree(setupArg);
1731- }
1732- #endif
1686+ if (comp->verbose)
1687+ {
1688+ printf("\n Evaluate to a temp:\n");
1689+ comp->gtDispTree(setupArg);
17331690 }
1691+ #endif
17341692 }
17351693 else // curArgTabEntry->needTmp == false
17361694 {
@@ -3289,29 +3247,31 @@ void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call, CallArg* arg)
32893247 assert(!fgGlobalMorph);
32903248 }
32913249
3250+ call->gtArgs.SetNeedsTemp(arg);
3251+
32923252 // Copy the valuetype to the temp
32933253 GenTree* copyBlk = gtNewStoreLclVarNode(tmp, argx);
32943254 copyBlk = fgMorphCopyBlock(copyBlk);
32953255
3296- call->gtArgs.SetTemp(arg, tmp);
32973256#if FEATURE_FIXED_OUT_ARGS
32983257
3299- // Do the copy early, and evaluate the temp later (see EvalArgsToTemps)
3300- // When on Unix create LCL_FLD for structs passed in more than one registers. See fgMakeTmpArgNode
3301- GenTree* argNode = copyBlk;
3258+ // For fixed out args we create the setup node here; EvalArgsToTemps knows
3259+ // to handle the case of "already have a setup node" properly.
3260+ arg->SetEarlyNode(copyBlk);
3261+ arg->SetLateNode(call->gtArgs.MakeTmpArgNode(this, arg, tmp));
33023262
33033263#else // !FEATURE_FIXED_OUT_ARGS
33043264
33053265 // Structs are always on the stack, and thus never need temps
33063266 // so we have to put the copy and temp all into one expression.
3307- GenTree* argNode = call->gtArgs.MakeTmpArgNode(this, arg);
3267+ GenTree* argNode = call->gtArgs.MakeTmpArgNode(this, arg, tmp );
33083268
33093269 // Change the expression to "(tmp=val),tmp"
33103270 argNode = gtNewOperNode(GT_COMMA, argNode->TypeGet(), copyBlk, argNode);
33113271
3312- #endif // !FEATURE_FIXED_OUT_ARGS
3313-
33143272 arg->SetEarlyNode(argNode);
3273+
3274+ #endif // !FEATURE_FIXED_OUT_ARGS
33153275}
33163276
33173277/*****************************************************************************
@@ -6772,12 +6732,12 @@ Statement* Compiler::fgAssignRecursiveCallArgToCallerParam(GenTree* arg,
67726732 // TODO-CQ: enable calls with struct arguments passed in registers.
67736733 noway_assert(!varTypeIsStruct(arg->TypeGet()));
67746734
6775- if (callArg->IsTemp() || arg->IsCnsIntOrI() || arg->IsCnsFltOrDbl())
6735+ if (arg->IsCnsIntOrI() || arg->IsCnsFltOrDbl())
67766736 {
67776737 // The argument is already assigned to a temp or is a const.
67786738 argInTemp = arg;
67796739 }
6780- else if (arg->OperGet() == GT_LCL_VAR)
6740+ else if (arg->OperIs( GT_LCL_VAR) )
67816741 {
67826742 unsigned lclNum = arg->AsLclVar()->GetLclNum();
67836743 LclVarDsc* varDsc = lvaGetDesc(lclNum);
0 commit comments