@@ -3112,8 +3112,6 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
31123112 }
31133113 }
31143114
3115- CORINFO_CLASS_HANDLE copyBlkClass = NO_CLASS_HANDLE;
3116-
31173115 // TODO-ARGS: Review this, is it really necessary to treat them specially here?
31183116 if (call->gtArgs.IsNonStandard(this, call, &arg) && arg.AbiInfo.IsPassedInRegisters())
31193117 {
@@ -3138,41 +3136,40 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
31383136 // Struct arguments may be morphed into a node that is not a struct type.
31393137 // In such case the CallArgABIInformation keeps track of whether the original node (before morphing)
31403138 // was a struct and the struct classification.
3141- bool isStructArg = arg.AbiInfo.IsStruct;
3139+ bool isStructArg = arg.AbiInfo.IsStruct;
3140+ GenTree* argObj = argx->gtEffectiveVal(true /*commaOnly*/);
3141+ bool makeOutArgCopy = false;
31423142
3143- GenTree* argObj = argx->gtEffectiveVal(true /*commaOnly*/);
31443143 if (isStructArg && varTypeIsStruct(argObj) && !argObj->OperIs(GT_ASG, GT_MKREFANY, GT_FIELD_LIST))
31453144 {
3146- CORINFO_CLASS_HANDLE objClass = gtGetStructHandle(argObj);
3147- unsigned originalSize;
3145+ unsigned originalSize;
31483146 if (argObj->TypeGet() == TYP_STRUCT)
31493147 {
31503148 if (argObj->OperIs(GT_OBJ))
31513149 {
3152- // Get the size off the OBJ node.
3153- originalSize = argObj->AsObj()->GetLayout()->GetSize();
3154- assert(originalSize == info.compCompHnd->getClassSize(objClass));
3150+ originalSize = argObj->AsObj()->Size();
31553151 }
31563152 else
31573153 {
3158- // We have a BADCODE assert for this in AddFinalArgsAndDetermineABIInfo.
3159- assert(argObj->OperIs(GT_LCL_VAR));
3160- originalSize = lvaGetDesc(argObj->AsLclVarCommon())->lvExactSize;
3154+ // Must be LCL_VAR: we have a BADCODE assert for this in AddFinalArgsAndDetermineABIInfo.
3155+ originalSize = lvaGetDesc(argObj->AsLclVar())->lvExactSize;
31613156 }
31623157 }
31633158 else
31643159 {
31653160 originalSize = genTypeSize(argx);
3166- assert(originalSize == info.compCompHnd->getClassSize(objClass));
31673161 }
3162+
3163+ assert(originalSize == info.compCompHnd->getClassSize(arg.GetSignatureClassHandle()));
3164+
31683165 unsigned roundupSize = (unsigned)roundUp(originalSize, TARGET_POINTER_SIZE);
31693166 var_types structBaseType = arg.AbiInfo.ArgType;
31703167
31713168 // First, handle the case where the argument is passed by reference.
31723169 if (arg.AbiInfo.PassedByRef)
31733170 {
31743171 assert(arg.AbiInfo.ByteSize == TARGET_POINTER_SIZE);
3175- copyBlkClass = objClass ;
3172+ makeOutArgCopy = true ;
31763173#ifdef UNIX_AMD64_ABI
31773174 assert(!"Structs are not passed by reference on x64/ux");
31783175#endif // UNIX_AMD64_ABI
@@ -3219,7 +3216,7 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
32193216 // On Windows structs are always copied and passed by reference (handled above) unless they are
32203217 // passed by value in a single register.
32213218 assert(arg.AbiInfo.GetStackSlotsNumber() == 1);
3222- copyBlkClass = objClass ;
3219+ makeOutArgCopy = true ;
32233220#else // UNIX_AMD64_ABI
32243221 // On Unix, structs are always passed by value.
32253222 // We only need a copy if we have one of the following:
@@ -3233,7 +3230,7 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
32333230 {
32343231 if (passingSize != structSize)
32353232 {
3236- copyBlkClass = objClass ;
3233+ makeOutArgCopy = true ;
32373234 }
32383235 }
32393236 else if (lclVar == nullptr)
@@ -3242,15 +3239,15 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
32423239 assert(argObj->TypeGet() != TYP_STRUCT);
32433240 if (arg.AbiInfo.NumRegs > 1)
32443241 {
3245- copyBlkClass = objClass ;
3242+ makeOutArgCopy = true ;
32463243 }
32473244 }
32483245 }
32493246#endif // UNIX_AMD64_ABI
32503247#elif defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64)
32513248 if ((passingSize != structSize) && (lclVar == nullptr))
32523249 {
3253- copyBlkClass = objClass ;
3250+ makeOutArgCopy = true ;
32543251 }
32553252#endif
32563253
@@ -3260,12 +3257,12 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
32603257 (lvaGetPromotionType(lclVar->AsLclVarCommon()->GetLclNum()) == PROMOTION_TYPE_INDEPENDENT)) ||
32613258 ((argObj->OperIs(GT_OBJ)) && (passingSize != structSize)))
32623259 {
3263- copyBlkClass = objClass ;
3260+ makeOutArgCopy = true ;
32643261 }
32653262
32663263 if (structSize < TARGET_POINTER_SIZE)
32673264 {
3268- copyBlkClass = objClass ;
3265+ makeOutArgCopy = true ;
32693266 }
32703267#endif // TARGET_ARM
32713268 }
@@ -3328,7 +3325,7 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
33283325 argObj->gtType = structBaseType;
33293326 }
33303327 assert(varTypeIsEnregisterable(argObj->TypeGet()));
3331- assert(copyBlkClass == NO_CLASS_HANDLE );
3328+ assert(!makeOutArgCopy );
33323329 }
33333330 else
33343331 {
@@ -3342,7 +3339,7 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
33423339 {
33433340 // The struct fits into a single register, but it has been promoted into its
33443341 // constituent fields, and so we have to re-assemble it
3345- copyBlkClass = objClass ;
3342+ makeOutArgCopy = true ;
33463343 }
33473344 }
33483345 else if (genTypeSize(varDsc->TypeGet()) != genTypeSize(structBaseType))
@@ -3359,7 +3356,7 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
33593356 argObj->gtType = structBaseType;
33603357 }
33613358 assert(varTypeIsEnregisterable(argObj->TypeGet()) ||
3362- ((copyBlkClass != NO_CLASS_HANDLE) && varTypeIsEnregisterable(structBaseType)));
3359+ (makeOutArgCopy && varTypeIsEnregisterable(structBaseType)));
33633360 }
33643361
33653362#if !defined(UNIX_AMD64_ABI) && !defined(TARGET_ARMARCH) && !defined(TARGET_LOONGARCH64)
@@ -3377,15 +3374,15 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
33773374 // the obj reading memory past the end of the valuetype
33783375 if (roundupSize > originalSize)
33793376 {
3380- copyBlkClass = objClass ;
3377+ makeOutArgCopy = true ;
33813378
33823379 // There are a few special cases where we can omit using a CopyBlk
33833380 // where we normally would need to use one.
33843381
33853382 if (argObj->OperIs(GT_OBJ) &&
33863383 argObj->AsObj()->gtGetOp1()->IsLocalAddrExpr() != nullptr) // Is the source a LclVar?
33873384 {
3388- copyBlkClass = NO_CLASS_HANDLE ;
3385+ makeOutArgCopy = false ;
33893386 }
33903387 }
33913388 }
@@ -3394,9 +3391,9 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
33943391 }
33953392 }
33963393
3397- if (copyBlkClass != NO_CLASS_HANDLE )
3394+ if (makeOutArgCopy )
33983395 {
3399- fgMakeOutgoingStructArgCopy(call, &arg, copyBlkClass );
3396+ fgMakeOutgoingStructArgCopy(call, &arg);
34003397 }
34013398
34023399 if (argx->gtOper == GT_MKREFANY)
@@ -4063,14 +4060,13 @@ GenTreeFieldList* Compiler::fgMorphLclArgToFieldlist(GenTreeLclVarCommon* lcl)
40634060// Arguments:
40644061// call - call being processed
40654062// arg - arg for the call
4066- // copyBlkClass - class handle for the struct
40674063//
40684064// The arg is updated if necessary with the copy.
40694065//
4070- void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call, CallArg* arg, CORINFO_CLASS_HANDLE copyBlkClass )
4066+ void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call, CallArg* arg)
40714067{
40724068 GenTree* argx = arg->GetEarlyNode();
4073- noway_assert(argx->gtOper != GT_MKREFANY);
4069+ noway_assert(! argx->OperIs( GT_MKREFANY) );
40744070
40754071 // If we're optimizing, see if we can avoid making a copy.
40764072 //
@@ -4121,8 +4117,9 @@ void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call, CallArg* arg, CORI
41214117 fgOutgoingArgTemps = hashBv::Create(this);
41224118 }
41234119
4124- unsigned tmp = 0;
4125- bool found = false;
4120+ CORINFO_CLASS_HANDLE copyBlkClass = arg->GetSignatureClassHandle();
4121+ unsigned tmp = 0;
4122+ bool found = false;
41264123
41274124 // Attempt to find a local we have already used for an outgoing struct and reuse it.
41284125 // We do not reuse within a statement.
0 commit comments