@@ -11965,30 +11965,9 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
11965
11965
11966
11966
return tree;
11967
11967
}
11968
- if (varTypeIsStruct( tree) && op1->OperIs(GT_OBJ, GT_BLK))
11968
+ if (!compDoOldStructRetyping() && ! tree->TypeIs(TYP_VOID ) && op1->OperIs(GT_OBJ, GT_BLK, GT_IND ))
11969
11969
{
11970
- assert(!compDoOldStructRetyping());
11971
- GenTree* addr = op1->AsBlk()->Addr();
11972
- // if we return `OBJ` or `BLK` from a local var, lcl var has to have a stack address.
11973
- if (addr->OperIs(GT_ADDR) && addr->gtGetOp1()->OperIs(GT_LCL_VAR))
11974
- {
11975
- GenTreeLclVar* lclVar = addr->gtGetOp1()->AsLclVar();
11976
- assert(!gtIsActiveCSE_Candidate(addr) && !gtIsActiveCSE_Candidate(op1));
11977
- if (gtGetStructHandle(tree) == gtGetStructHandleIfPresent(lclVar))
11978
- {
11979
- // Fold *(&x).
11980
- tree->AsUnOp()->gtOp1 = op1;
11981
- DEBUG_DESTROY_NODE(op1);
11982
- DEBUG_DESTROY_NODE(addr);
11983
- op1 = lclVar;
11984
- }
11985
- else
11986
- {
11987
- // TODO-1stClassStructs: It is not address-taken or block operation,
11988
- // but the current IR doesn't allow to express that cast without stack, see #11413.
11989
- lvaSetVarDoNotEnregister(lclVar->GetLclNum() DEBUGARG(DNER_BlockOp));
11990
- }
11991
- }
11970
+ op1 = fgMorphRetInd(tree->AsUnOp());
11992
11971
}
11993
11972
break;
11994
11973
@@ -14209,6 +14188,71 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
14209
14188
14210
14189
return tree;
14211
14190
}
14191
+
14192
+ //----------------------------------------------------------------------------------------------
14193
+ // fgMorphRetInd: Try to get rid of extra IND(ADDR()) pairs in a return tree.
14194
+ //
14195
+ // Arguments:
14196
+ // node - The return node that uses an indirection.
14197
+ //
14198
+ // Return Value:
14199
+ // the original op1 of the ret if there was no optimization or an optimized new op1.
14200
+ //
14201
+ GenTree* Compiler::fgMorphRetInd(GenTreeUnOp* ret)
14202
+ {
14203
+ assert(!compDoOldStructRetyping());
14204
+ assert(ret->OperIs(GT_RETURN));
14205
+ assert(ret->gtGetOp1()->OperIs(GT_IND, GT_BLK, GT_OBJ));
14206
+ GenTreeIndir* ind = ret->gtGetOp1()->AsIndir();
14207
+ GenTree* addr = ind->Addr();
14208
+
14209
+ if (addr->OperIs(GT_ADDR) && addr->gtGetOp1()->OperIs(GT_LCL_VAR))
14210
+ {
14211
+ // If `return` retypes LCL_VAR as a smaller struct it should not set `doNotEnregister` on that
14212
+ // LclVar.
14213
+ // Example: in `Vector128:AsVector2` we have RETURN SIMD8(OBJ SIMD8(ADDR byref(LCL_VAR SIMD16))).
14214
+ GenTreeLclVar* lclVar = addr->gtGetOp1()->AsLclVar();
14215
+ if (!lvaIsImplicitByRefLocal(lclVar->GetLclNum()))
14216
+ {
14217
+ assert(!gtIsActiveCSE_Candidate(addr) && !gtIsActiveCSE_Candidate(ind));
14218
+ unsigned indSize;
14219
+ if (ind->OperIs(GT_IND))
14220
+ {
14221
+ indSize = genTypeSize(ind);
14222
+ }
14223
+ else
14224
+ {
14225
+ indSize = ind->AsBlk()->GetLayout()->GetSize();
14226
+ }
14227
+
14228
+ LclVarDsc* varDsc = lvaGetDesc(lclVar);
14229
+
14230
+ unsigned lclVarSize;
14231
+ if (!lclVar->TypeIs(TYP_STRUCT))
14232
+
14233
+ {
14234
+ lclVarSize = genTypeSize(lclVar->TypeGet());
14235
+ }
14236
+ else
14237
+ {
14238
+ lclVarSize = varDsc->lvExactSize;
14239
+ }
14240
+ assert((indSize <= lclVarSize) || varDsc->lvDoNotEnregister);
14241
+ if (indSize <= lclVarSize)
14242
+ {
14243
+ // Fold (TYPE1)*(&(TYPE2)x) even if types do not match, lowering will handle it.
14244
+ // Getting rid of this IND(ADDR()) pair allows to keep lclVar as not address taken
14245
+ // and enregister it.
14246
+ DEBUG_DESTROY_NODE(ind);
14247
+ DEBUG_DESTROY_NODE(addr);
14248
+ ret->gtOp1 = lclVar;
14249
+ return ret->gtOp1;
14250
+ }
14251
+ }
14252
+ }
14253
+ return ind;
14254
+ }
14255
+
14212
14256
#ifdef _PREFAST_
14213
14257
#pragma warning(pop)
14214
14258
#endif
0 commit comments