@@ -12520,8 +12520,7 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
1252012520 ival1 = 0;
1252112521
1252212522 // Don't remove a volatile GT_IND, even if the address points to a local variable.
12523- // For TYP_STRUCT INDs, we do not know their size, and so will not morph as well.
12524- if (!tree->AsIndir()->IsVolatile() && !tree->TypeIs(TYP_STRUCT))
12523+ if ((tree->gtFlags & GTF_IND_VOLATILE) == 0)
1252512524 {
1252612525 /* Try to Fold *(&X) into X */
1252712526 if (op1->gtOper == GT_ADDR)
@@ -12534,9 +12533,13 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
1253412533
1253512534 temp = op1->AsOp()->gtOp1; // X
1253612535
12537- if (typ == temp->TypeGet())
12536+ // In the test below, if they're both TYP_STRUCT, this of course does *not* mean that
12537+ // they are the *same* struct type. In fact, they almost certainly aren't. If the
12538+ // address has an associated field sequence, that identifies this case; go through
12539+ // the "lcl_fld" path rather than this one.
12540+ FieldSeqNode* addrFieldSeq = nullptr; // This is an unused out parameter below.
12541+ if (typ == temp->TypeGet() && !GetZeroOffsetFieldMap()->Lookup(op1, &addrFieldSeq))
1253812542 {
12539- assert(typ != TYP_STRUCT);
1254012543 foldAndReturnTemp = true;
1254112544 }
1254212545 else if (temp->OperIsLocal())
@@ -12712,17 +12715,22 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
1271212715 // out-of-bounds w.r.t. the local).
1271312716 if ((temp != nullptr) && !foldAndReturnTemp)
1271412717 {
12715- assert(temp->OperIsLocalRead ());
12718+ assert(temp->OperIsLocal ());
1271612719
12717- unsigned lclNum = temp->AsLclVarCommon()->GetLclNum();
12720+ const unsigned lclNum = temp->AsLclVarCommon()->GetLclNum();
12721+ LclVarDsc* const varDsc = lvaGetDesc(lclNum);
12722+
12723+ const var_types tempTyp = temp->TypeGet();
12724+ const bool useExactSize = varTypeIsStruct(tempTyp) || (tempTyp == TYP_BLK) || (tempTyp == TYP_LCLBLK);
12725+ const unsigned varSize = useExactSize ? varDsc->lvExactSize : genTypeSize(temp);
1271812726
1271912727 // Make sure we do not enregister this lclVar.
1272012728 lvaSetVarDoNotEnregister(lclNum DEBUGARG(DoNotEnregisterReason::LocalField));
1272112729
1272212730 // If the size of the load is greater than the size of the lclVar, we cannot fold this access into
1272312731 // a lclFld: the access represented by an lclFld node must begin at or after the start of the
1272412732 // lclVar and must not extend beyond the end of the lclVar.
12725- if ((ival1 >= 0) && ((ival1 + genTypeSize(typ)) <= lvaLclExactSize(lclNum) ))
12733+ if ((ival1 >= 0) && ((ival1 + genTypeSize(typ)) <= varSize ))
1272612734 {
1272712735 GenTreeLclFld* lclFld;
1272812736
@@ -13816,47 +13824,6 @@ GenTree* Compiler::fgOptimizeAddition(GenTreeOp* add)
1381613824 return op1;
1381713825 }
1381813826
13819- // Reduce local addresses: ADD(ADDR(LCL_VAR), OFFSET) => ADDR(LCL_FLD OFFSET).
13820- // TODO-ADDR: do ADD(LCL_FLD/VAR_ADDR, OFFSET) => LCL_FLD_ADDR instead.
13821- //
13822- if (opts.OptimizationEnabled() && fgGlobalMorph && op1->OperIs(GT_ADDR) && op2->IsCnsIntOrI() &&
13823- op1->AsUnOp()->gtGetOp1()->OperIs(GT_LCL_VAR, GT_LCL_FLD))
13824- {
13825- GenTreeUnOp* addrNode = op1->AsUnOp();
13826- GenTreeLclVarCommon* lclNode = addrNode->gtGetOp1()->AsLclVarCommon();
13827- GenTreeIntCon* offsetNode = op2->AsIntCon();
13828- if (FitsIn<uint16_t>(offsetNode->IconValue()))
13829- {
13830- unsigned offset = lclNode->GetLclOffs() + static_cast<uint16_t>(offsetNode->IconValue());
13831-
13832- // Note: the emitter does not expect out-of-bounds access for LCL_FLD_ADDR.
13833- if (FitsIn<uint16_t>(offset) && (offset < lvaLclExactSize(lclNode->GetLclNum())))
13834- {
13835- // Compose the field sequence: [LCL, ADDR, OFFSET].
13836- FieldSeqNode* fieldSeq = lclNode->GetFieldSeq();
13837- FieldSeqNode* zeroOffsetFieldSeq = nullptr;
13838- if (GetZeroOffsetFieldMap()->Lookup(addrNode, &zeroOffsetFieldSeq))
13839- {
13840- fieldSeq = GetFieldSeqStore()->Append(fieldSeq, zeroOffsetFieldSeq);
13841- GetZeroOffsetFieldMap()->Remove(addrNode);
13842- }
13843- fieldSeq = GetFieldSeqStore()->Append(fieldSeq, offsetNode->gtFieldSeq);
13844-
13845- // Types of location nodes under ADDRs do not matter. We arbitrarily choose TYP_UBYTE.
13846- lclNode->ChangeType(TYP_UBYTE);
13847- lclNode->SetOper(GT_LCL_FLD);
13848- lclNode->AsLclFld()->SetLclOffs(offset);
13849- lclNode->AsLclFld()->SetFieldSeq(fieldSeq);
13850- lvaSetVarDoNotEnregister(lclNode->GetLclNum() DEBUGARG(DoNotEnregisterReason::LocalField));
13851-
13852- DEBUG_DESTROY_NODE(offsetNode);
13853- DEBUG_DESTROY_NODE(add);
13854-
13855- return addrNode;
13856- }
13857- }
13858- }
13859-
1386013827 // Note that these transformations are legal for floating-point ADDs as well.
1386113828 if (opts.OptimizationEnabled())
1386213829 {
0 commit comments