@@ -11194,7 +11194,6 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
1119411194 */
1119511195
1119611196 GenTree* temp;
11197- size_t ival1;
1119811197 GenTree* lclVarTree;
1119911198 GenTree* effectiveOp1;
1120011199 FieldSeqNode* fieldSeq = nullptr;
@@ -11571,15 +11570,14 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
1157111570
1157211571 bool foldAndReturnTemp = false;
1157311572 temp = nullptr;
11574- ival1 = 0;
1157511573
1157611574 // Don't remove a volatile GT_IND, even if the address points to a local variable.
11577- if ((tree->gtFlags & GTF_IND_VOLATILE) == 0)
11575+ //
11576+ if (!tree->AsIndir()->IsVolatile())
1157811577 {
1157911578 /* Try to Fold *(&X) into X */
1158011579 if (op1->gtOper == GT_ADDR)
1158111580 {
11582- // Can not remove a GT_ADDR if it is currently a CSE candidate.
1158311581 if (gtIsActiveCSE_Candidate(op1))
1158411582 {
1158511583 break;
@@ -11679,98 +11677,34 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
1167911677 }
1168011678 }
1168111679#endif // TARGET_ARM
11682-
11683- /* Try to change *(&lcl + cns) into lcl[cns] to prevent materialization of &lcl */
11684-
11685- if (op1->AsOp()->gtOp1->OperGet() == GT_ADDR && op1->AsOp()->gtOp2->OperGet() == GT_CNS_INT &&
11686- opts.OptimizationEnabled())
11687- {
11688- // No overflow arithmetic with pointers
11689- noway_assert(!op1->gtOverflow());
11690-
11691- temp = op1->AsOp()->gtOp1->AsOp()->gtOp1;
11692- if (!temp->OperIsLocal())
11693- {
11694- temp = nullptr;
11695- break;
11696- }
11697-
11698- // Can not remove the GT_ADDR if it is currently a CSE candidate.
11699- if (gtIsActiveCSE_Candidate(op1->AsOp()->gtOp1))
11700- {
11701- break;
11702- }
11703-
11704- ival1 = op1->AsOp()->gtOp2->AsIntCon()->gtIconVal;
11705- fieldSeq = op1->AsOp()->gtOp2->AsIntCon()->gtFieldSeq;
11706-
11707- if (ival1 == 0 && typ == temp->TypeGet() && temp->TypeGet() != TYP_STRUCT)
11708- {
11709- noway_assert(!varTypeIsGC(temp->TypeGet()));
11710- foldAndReturnTemp = true;
11711- }
11712- else
11713- {
11714- // The emitter can't handle large offsets
11715- if (ival1 != (unsigned short)ival1)
11716- {
11717- break;
11718- }
11719-
11720- // The emitter can get confused by invalid offsets
11721- if (ival1 >= Compiler::lvaLclSize(temp->AsLclVarCommon()->GetLclNum()))
11722- {
11723- break;
11724- }
11725- }
11726- // Now we can fold this into a GT_LCL_FLD below
11727- // where we check (temp != nullptr)
11728- }
1172911680 }
1173011681 }
1173111682
11732- // At this point we may have a lclVar or lclFld that might be foldable with a bit of extra massaging:
11733- // - We may have a load of a local where the load has a different type than the local
11734- // - We may have a load of a local plus an offset
11735- //
11736- // In these cases, we will change the lclVar or lclFld into a lclFld of the appropriate type and
11737- // offset if doing so is legal. The only cases in which this transformation is illegal are if the load
11738- // begins before the local or if the load extends beyond the end of the local (i.e. if the load is
11739- // out-of-bounds w.r.t. the local).
11683+ // At this point we may have a lclVar or lclFld of some mismatched type. In this case, we will change
11684+ // the lclVar or lclFld into a lclFld of the appropriate type if doing so is legal. The only cases in
11685+ // which this transformation is illegal is when we have a STRUCT indirection, as we do not have the
11686+ // necessary layout information, or if the load would extend beyond the local.
1174011687 if ((temp != nullptr) && !foldAndReturnTemp)
1174111688 {
11742- assert(temp->OperIsLocal( ));
11689+ assert(temp->OperIs(GT_LCL_VAR, GT_LCL_FLD ));
1174311690
11744- unsigned lclNum = temp->AsLclVarCommon()->GetLclNum();
11691+ unsigned lclNum = temp->AsLclVarCommon()->GetLclNum();
11692+ unsigned lclOffs = temp->AsLclVarCommon()->GetLclOffs();
1174511693
1174611694 // Make sure we do not enregister this lclVar.
1174711695 lvaSetVarDoNotEnregister(lclNum DEBUGARG(DoNotEnregisterReason::LocalField));
1174811696
11749- // If the size of the load is greater than the size of the lclVar, we cannot fold this access into
11750- // a lclFld: the access represented by an lclFld node must begin at or after the start of the
11751- // lclVar and must not extend beyond the end of the lclVar.
11752- if ((ival1 >= 0) && ((ival1 + genTypeSize(typ)) <= lvaLclExactSize(lclNum)))
11697+ if ((typ != TYP_STRUCT) && ((lclOffs + genTypeSize(typ)) <= lvaLclExactSize(lclNum)))
1175311698 {
11754- GenTreeLclFld* lclFld;
11755-
11756- // We will turn a GT_LCL_VAR into a GT_LCL_FLD with an gtLclOffs of 'ival'
11757- // or if we already have a GT_LCL_FLD we will adjust the gtLclOffs by adding 'ival'
11758- // Then we change the type of the GT_LCL_FLD to match the orginal GT_IND type.
11699+ // We will change the type of the node to match the orginal GT_IND type.
1175911700 //
11760- if (temp->OperGet() == GT_LCL_FLD)
11761- {
11762- lclFld = temp->AsLclFld();
11763- lclFld->SetLclOffs(lclFld->GetLclOffs() + static_cast<unsigned>(ival1));
11764- }
11765- else // We have a GT_LCL_VAR.
11701+ temp->gtType = typ;
11702+
11703+ if (temp->OperIs(GT_LCL_VAR))
1176611704 {
11767- assert(temp->OperGet() == GT_LCL_VAR);
11768- temp->ChangeOper(GT_LCL_FLD); // Note that this makes the gtFieldSeq "NotAField".
11769- lclFld = temp->AsLclFld();
11770- lclFld->SetLclOffs(static_cast<unsigned>(ival1));
11705+ temp->ChangeOper(GT_LCL_FLD);
1177111706 }
1177211707
11773- temp->gtType = tree->gtType;
1177411708 foldAndReturnTemp = true;
1177511709 }
1177611710 }
@@ -11779,20 +11713,15 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
1177911713 {
1178011714 assert(temp != nullptr);
1178111715 assert(temp->TypeGet() == typ);
11782- assert(( op1->OperGet() == GT_ADD) || (op1->OperGet() == GT_ADDR));
11716+ assert(op1->OperIs( GT_ADDR));
1178311717
1178411718 // Copy the value of GTF_DONT_CSE from the original tree to `temp`: it can be set for
1178511719 // 'temp' because a GT_ADDR always marks it for its operand.
1178611720 temp->gtFlags &= ~GTF_DONT_CSE;
1178711721 temp->gtFlags |= (tree->gtFlags & GTF_DONT_CSE);
1178811722 temp->SetVNsFromNode(tree);
1178911723
11790- if (op1->OperGet() == GT_ADD)
11791- {
11792- DEBUG_DESTROY_NODE(op1->AsOp()->gtOp1); // GT_ADDR
11793- DEBUG_DESTROY_NODE(op1->AsOp()->gtOp2); // GT_CNS_INT
11794- }
11795- DEBUG_DESTROY_NODE(op1); // GT_ADD or GT_ADDR
11724+ DEBUG_DESTROY_NODE(op1); // GT_ADDR
1179611725 DEBUG_DESTROY_NODE(tree); // GT_IND
1179711726
1179811727 // If the result of the fold is a local var, we may need to perform further adjustments e.g. for
@@ -12794,9 +12723,39 @@ GenTree* Compiler::fgOptimizeAddition(GenTreeOp* add)
1279412723 return op1;
1279512724 }
1279612725
12797- // Note that these transformations are legal for floating-point ADDs as well.
1279812726 if (opts.OptimizationEnabled())
1279912727 {
12728+ // Reduce local addresses: "ADD(ADDR(LCL_VAR), OFFSET)" => "ADDR(LCL_FLD OFFSET)".
12729+ // TODO-ADDR: do "ADD(LCL_FLD/VAR_ADDR, OFFSET)" => "LCL_FLD_ADDR" instead.
12730+ //
12731+ if (op1->OperIs(GT_ADDR) && op2->IsCnsIntOrI() && op1->gtGetOp1()->OperIsLocalRead())
12732+ {
12733+ GenTreeUnOp* addrNode = op1->AsUnOp();
12734+ GenTreeLclVarCommon* lclNode = addrNode->gtGetOp1()->AsLclVarCommon();
12735+ GenTreeIntCon* offsetNode = op2->AsIntCon();
12736+ if (FitsIn<uint16_t>(offsetNode->IconValue()))
12737+ {
12738+ unsigned offset = lclNode->GetLclOffs() + static_cast<uint16_t>(offsetNode->IconValue());
12739+
12740+ // Note: the emitter does not expect out-of-bounds access for LCL_FLD_ADDR.
12741+ if (FitsIn<uint16_t>(offset) && (offset < lvaLclExactSize(lclNode->GetLclNum())))
12742+ {
12743+ // Types of location nodes under ADDRs do not matter. We arbitrarily choose TYP_UBYTE.
12744+ lclNode->ChangeType(TYP_UBYTE);
12745+ lclNode->SetOper(GT_LCL_FLD);
12746+ lclNode->AsLclFld()->SetLclOffs(offset);
12747+ lvaSetVarDoNotEnregister(lclNode->GetLclNum() DEBUGARG(DoNotEnregisterReason::LocalField));
12748+
12749+ addrNode->SetVNsFromNode(add);
12750+
12751+ DEBUG_DESTROY_NODE(offsetNode);
12752+ DEBUG_DESTROY_NODE(add);
12753+
12754+ return addrNode;
12755+ }
12756+ }
12757+ }
12758+
1280012759 // - a + b = > b - a
1280112760 // ADD((NEG(a), b) => SUB(b, a)
1280212761
0 commit comments