Start using local address nodes in the JIT frontend (#305)
authormikedn <onemihaid@hotmail.com>
Tue, 3 Dec 2019 03:03:16 +0000 (05:03 +0200)
committerCarol Eidt <carol.eidt@microsoft.com>
Tue, 3 Dec 2019 03:03:16 +0000 (19:03 -0800)
* Add GenTreeLclFld getters/setters

Also change the offset type to uint16_t since the emitter does not support
offsets larger than 65535. The freed space will later be used to store a
class layout number to support struct typed GenTreeLclFld nodes.

* Track field sequences in LocalAddressVisitor

* Generate LCL_(VAR|FLD)_ADDR nodes in LocalAddressVisitor

This starts the process of moving away from ADDR nodes by generating
some LCL_(VAR|FLD)_ADDR nodes in LocalAddressVisitor. For now, these
nodes are generated in only 2 specific cases:
 - when a local address is a call argument
 - when a local address is the RHS of an assignment
There's not a lot going on with call arguments that are addresses and
the lack of some kind of forward substituion in the JIT means that the
RHS of an assignment will not move under a different node. The result
is that very few other changes are needed to support local address
nodes at this time. In particular, this avoids the need to change the
myriad of "is local address" checks and the GTF_GLOB_REF propagation
to indirections involving address exposed variables.

* Add TODO-ADDR comments

20 files changed:
src/coreclr/src/jit/codegenarm.cpp
src/coreclr/src/jit/codegenarm64.cpp
src/coreclr/src/jit/codegenarmarch.cpp
src/coreclr/src/jit/codegenlinear.cpp
src/coreclr/src/jit/codegenxarch.cpp
src/coreclr/src/jit/compiler.cpp
src/coreclr/src/jit/compiler.h
src/coreclr/src/jit/compiler.hpp
src/coreclr/src/jit/decomposelongs.cpp
src/coreclr/src/jit/emitxarch.cpp
src/coreclr/src/jit/gentree.cpp
src/coreclr/src/jit/gentree.h
src/coreclr/src/jit/hwintrinsiccodegenxarch.cpp
src/coreclr/src/jit/instr.cpp
src/coreclr/src/jit/lclvars.cpp
src/coreclr/src/jit/lower.cpp
src/coreclr/src/jit/morph.cpp
src/coreclr/src/jit/rationalize.cpp
src/coreclr/src/jit/simdcodegenxarch.cpp
src/coreclr/src/jit/valuenum.cpp

index 677b712..c1d4dbd 100644 (file)
@@ -984,7 +984,7 @@ void CodeGen::genCodeForStoreLclFld(GenTreeLclFld* tree)
     noway_assert(targetType != TYP_STRUCT);
 
     // record the offset
-    unsigned offset = tree->gtLclOffs;
+    unsigned offset = tree->GetLclOffs();
 
     // We must have a stack store with GT_STORE_LCL_FLD
     noway_assert(targetReg == REG_NA);
index ec74ba2..7acd311 100644 (file)
@@ -1875,7 +1875,7 @@ void CodeGen::genCodeForStoreLclFld(GenTreeLclFld* tree)
 #endif // FEATURE_SIMD
 
     // record the offset
-    unsigned offset = tree->gtLclOffs;
+    unsigned offset = tree->GetLclOffs();
 
     // We must have a stack store with GT_STORE_LCL_FLD
     noway_assert(targetReg == REG_NA);
@@ -4974,7 +4974,7 @@ void CodeGen::genStoreLclTypeSIMD12(GenTree* treeNode)
 
     if (treeNode->OperGet() == GT_STORE_LCL_FLD)
     {
-        offs = treeNode->AsLclFld()->gtLclOffs;
+        offs = treeNode->AsLclFld()->GetLclOffs();
     }
 
     GenTree* op1 = treeNode->AsOp()->gtOp1;
index aeb5c9d..bf822a3 100644 (file)
@@ -1758,7 +1758,7 @@ void CodeGen::genCodeForLclFld(GenTreeLclFld* tree)
     assert(targetReg != REG_NA);
 
     emitAttr size   = emitTypeSize(targetType);
-    unsigned offs   = tree->gtLclOffs;
+    unsigned offs   = tree->GetLclOffs();
     unsigned varNum = tree->GetLclNum();
     assert(varNum < compiler->lvaCount);
 
@@ -1966,8 +1966,7 @@ void CodeGen::genCodeForInitBlkUnroll(GenTreeBlk* node)
 
         if (dstAddr->OperIs(GT_LCL_FLD_ADDR))
         {
-            assert(dstAddr->AsLclFld()->gtLclOffs <= INT32_MAX);
-            dstOffset = dstAddr->AsLclFld()->gtLclOffs;
+            dstOffset = dstAddr->AsLclFld()->GetLclOffs();
         }
     }
 
@@ -2103,8 +2102,7 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* node)
 
         if (dstAddr->OperIs(GT_LCL_FLD_ADDR))
         {
-            assert(dstAddr->AsLclFld()->gtLclOffs <= INT32_MAX);
-            dstOffset = dstAddr->AsLclFld()->gtLclOffs;
+            dstOffset = dstAddr->AsLclFld()->GetLclOffs();
         }
     }
 
@@ -2121,8 +2119,7 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* node)
 
         if (src->OperIs(GT_LCL_FLD))
         {
-            assert(src->AsLclFld()->gtLclOffs <= INT32_MAX);
-            srcOffset = static_cast<int>(src->AsLclFld()->gtLclOffs);
+            srcOffset = src->AsLclFld()->GetLclOffs();
         }
     }
     else
@@ -2146,8 +2143,7 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* node)
 
             if (srcAddr->OperIs(GT_LCL_FLD_ADDR))
             {
-                assert(srcAddr->AsLclFld()->gtLclOffs <= INT32_MAX);
-                srcOffset = static_cast<int>(srcAddr->AsLclFld()->gtLclOffs);
+                srcOffset = srcAddr->AsLclFld()->GetLclOffs();
             }
         }
     }
index 811cf8f..88e3c69 100644 (file)
@@ -1584,7 +1584,7 @@ void CodeGen::genConsumePutStructArgStk(GenTreePutArgStk* putArgNode,
             unsigned int offset = 0;
             if (srcAddr->OperGet() == GT_LCL_FLD_ADDR)
             {
-                offset = srcAddr->AsLclFld()->gtLclOffs;
+                offset = srcAddr->AsLclFld()->GetLclOffs();
             }
             GetEmitter()->emitIns_R_S(INS_lea, EA_PTRSIZE, srcReg, lclNode->GetLclNum(), offset);
         }
index 2303cbe..4a302c6 100644 (file)
@@ -2966,8 +2966,7 @@ void CodeGen::genCodeForInitBlkUnroll(GenTreeBlk* node)
 
         if (dstAddr->OperIs(GT_LCL_FLD_ADDR))
         {
-            assert(dstAddr->AsLclFld()->gtLclOffs <= INT32_MAX);
-            dstOffset = static_cast<int>(dstAddr->AsLclFld()->gtLclOffs);
+            dstOffset = dstAddr->AsLclFld()->GetLclOffs();
         }
     }
 
@@ -3090,7 +3089,7 @@ void CodeGen::genCodeForLoadOffset(instruction ins, emitAttr size, regNumber dst
     {
         if (baseNode->gtOper == GT_LCL_FLD_ADDR)
         {
-            offset += baseNode->AsLclFld()->gtLclOffs;
+            offset += baseNode->AsLclFld()->GetLclOffs();
         }
         emit->emitIns_R_S(ins, size, dst, baseNode->AsLclVarCommon()->GetLclNum(), offset);
     }
@@ -3146,8 +3145,7 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* node)
 
         if (dstAddr->OperIs(GT_LCL_FLD_ADDR))
         {
-            assert(dstAddr->AsLclFld()->gtLclOffs <= INT32_MAX);
-            dstOffset = static_cast<int>(dstAddr->AsLclFld()->gtLclOffs);
+            dstOffset = dstAddr->AsLclFld()->GetLclOffs();
         }
     }
 
@@ -3166,8 +3164,7 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* node)
 
         if (src->OperIs(GT_LCL_FLD))
         {
-            assert(src->AsLclFld()->gtLclOffs <= INT32_MAX);
-            srcOffset = static_cast<int>(src->AsLclFld()->gtLclOffs);
+            srcOffset = src->AsLclFld()->GetLclOffs();
         }
     }
     else
@@ -3203,8 +3200,7 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* node)
 
             if (srcAddr->OperIs(GT_LCL_FLD_ADDR))
             {
-                assert(srcAddr->AsLclFld()->gtLclOffs <= INT32_MAX);
-                srcOffset = static_cast<int>(srcAddr->AsLclFld()->gtLclOffs);
+                srcOffset = srcAddr->AsLclFld()->GetLclOffs();
             }
         }
     }
@@ -4557,7 +4553,7 @@ void CodeGen::genCodeForLclFld(GenTreeLclFld* tree)
     noway_assert(targetType != TYP_STRUCT);
 
     emitAttr size   = emitTypeSize(targetType);
-    unsigned offs   = tree->gtLclOffs;
+    unsigned offs   = tree->GetLclOffs();
     unsigned varNum = tree->GetLclNum();
     assert(varNum < compiler->lvaCount);
 
@@ -7348,13 +7344,9 @@ void CodeGen::genSSE41RoundOp(GenTreeOp* treeNode)
                 }
 
                 case GT_LCL_FLD:
-                {
-                    GenTreeLclFld* lclField = srcNode->AsLclFld();
-
-                    varNum = lclField->GetLclNum();
-                    offset = lclField->gtLclOffs;
+                    varNum = srcNode->AsLclFld()->GetLclNum();
+                    offset = srcNode->AsLclFld()->GetLclOffs();
                     break;
-                }
 
                 case GT_LCL_VAR:
                 {
@@ -8227,7 +8219,7 @@ void CodeGen::genPutStructArgStk(GenTreePutArgStk* putArgStk)
             srcLclNum = srcAddr->AsLclVarCommon()->GetLclNum();
             if (srcAddr->OperGet() == GT_LCL_FLD_ADDR)
             {
-                srcLclOffset = srcAddr->AsLclFld()->gtLclOffs;
+                srcLclOffset = srcAddr->AsLclFld()->GetLclOffs();
             }
         }
 
index 2440ada..a7cd81b 100644 (file)
@@ -9819,11 +9819,11 @@ int cLeafIR(Compiler* comp, GenTree* tree)
             comp->gtGetLclVarNameInfo(lclNum, &ilKind, &ilName, &ilNum);
             if (ilName != nullptr)
             {
-                chars += printf("%s+%u", ilName, tree->AsLclFld()->gtLclOffs);
+                chars += printf("%s+%u", ilName, tree->AsLclFld()->GetLclOffs());
             }
             else
             {
-                chars += printf("%s%d+%u", ilKind, ilNum, tree->AsLclFld()->gtLclOffs);
+                chars += printf("%s%d+%u", ilKind, ilNum, tree->AsLclFld()->GetLclOffs());
                 LclVarDsc* varDsc = comp->lvaTable + lclNum;
                 if (comp->dumpIRLocals)
                 {
index 825697d..60dcacd 100644 (file)
@@ -2467,6 +2467,7 @@ public:
                                 GenTree*   op2  = nullptr);
 
     GenTreeIntCon* gtNewIconNode(ssize_t value, var_types type = TYP_INT);
+    GenTreeIntCon* gtNewIconNode(unsigned fieldOffset, FieldSeqNode* fieldSeq);
 
     GenTree* gtNewPhysRegNode(regNumber reg, var_types type);
 
@@ -2544,6 +2545,12 @@ public:
     GenTree* gtNewLclvNode(unsigned lnum, var_types type DEBUGARG(IL_OFFSETX ILoffs = BAD_IL_OFFSET));
     GenTree* gtNewLclLNode(unsigned lnum, var_types type DEBUGARG(IL_OFFSETX ILoffs = BAD_IL_OFFSET));
 
+    GenTreeLclVar* gtNewLclVarAddrNode(unsigned lclNum, var_types type = TYP_I_IMPL);
+    GenTreeLclFld* gtNewLclFldAddrNode(unsigned      lclNum,
+                                       unsigned      lclOffs,
+                                       FieldSeqNode* fieldSeq,
+                                       var_types     type = TYP_I_IMPL);
+
 #ifdef FEATURE_SIMD
     GenTreeSIMD* gtNewSIMDNode(
         var_types type, GenTree* op1, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size);
index 4b53725..eb73160 100644 (file)
@@ -1456,13 +1456,13 @@ inline void GenTree::ChangeOper(genTreeOps oper, ValueNumberUpdate vnUpdate)
             Compiler*     compiler     = JitTls::GetCompiler();
             bool          isZeroOffset = compiler->GetZeroOffsetFieldMap()->Lookup(this, &zeroFieldSeq);
 
-            AsLclFld()->gtLclOffs  = 0;
-            AsLclFld()->gtFieldSeq = FieldSeqStore::NotAField();
+            AsLclFld()->SetLclOffs(0);
+            AsLclFld()->SetFieldSeq(FieldSeqStore::NotAField());
 
             if (zeroFieldSeq != nullptr)
             {
                 // Set the zeroFieldSeq in the GT_LCL_FLD node
-                AsLclFld()->gtFieldSeq = zeroFieldSeq;
+                AsLclFld()->SetFieldSeq(zeroFieldSeq);
                 // and remove the annotation from the ZeroOffsetFieldMap
                 compiler->GetZeroOffsetFieldMap()->Remove(this);
             }
index 9d42c0f..8178bd2 100644 (file)
@@ -361,12 +361,12 @@ GenTree* DecomposeLongs::DecomposeLclVar(LIR::Use& use)
     else
     {
         loResult->SetOper(GT_LCL_FLD);
-        loResult->AsLclFld()->gtLclOffs  = 0;
-        loResult->AsLclFld()->gtFieldSeq = FieldSeqStore::NotAField();
+        loResult->AsLclFld()->SetLclOffs(0);
+        loResult->AsLclFld()->SetFieldSeq(FieldSeqStore::NotAField());
 
         hiResult->SetOper(GT_LCL_FLD);
-        hiResult->AsLclFld()->gtLclOffs  = 4;
-        hiResult->AsLclFld()->gtFieldSeq = FieldSeqStore::NotAField();
+        hiResult->AsLclFld()->SetLclOffs(4);
+        hiResult->AsLclFld()->SetFieldSeq(FieldSeqStore::NotAField());
     }
 
     return FinalizeDecomposition(use, loResult, hiResult, hiResult);
@@ -390,7 +390,7 @@ GenTree* DecomposeLongs::DecomposeLclFld(LIR::Use& use)
     GenTreeLclFld* loResult = tree->AsLclFld();
     loResult->gtType        = TYP_INT;
 
-    GenTree* hiResult = m_compiler->gtNewLclFldNode(loResult->GetLclNum(), TYP_INT, loResult->gtLclOffs + 4);
+    GenTree* hiResult = m_compiler->gtNewLclFldNode(loResult->GetLclNum(), TYP_INT, loResult->GetLclOffs() + 4);
     Range().InsertAfter(loResult, hiResult);
 
     return FinalizeDecomposition(use, loResult, hiResult, hiResult);
@@ -510,7 +510,7 @@ GenTree* DecomposeLongs::DecomposeStoreLclFld(LIR::Use& use)
     loStore->gtFlags |= GTF_VAR_USEASG;
 
     // Create the store for the upper half of the GT_LONG and insert it after the low store.
-    GenTreeLclFld* hiStore = m_compiler->gtNewLclFldNode(loStore->GetLclNum(), TYP_INT, loStore->gtLclOffs + 4);
+    GenTreeLclFld* hiStore = m_compiler->gtNewLclFldNode(loStore->GetLclNum(), TYP_INT, loStore->GetLclOffs() + 4);
     hiStore->SetOper(GT_STORE_LCL_FLD);
     hiStore->gtOp1 = value->gtOp2;
     hiStore->gtFlags |= (GTF_VAR_DEF | GTF_VAR_USEASG);
index 9c3a302..33d8592 100644 (file)
@@ -3360,12 +3360,9 @@ regNumber emitter::emitInsBinary(instruction ins, emitAttr attr, GenTree* dst, G
             {
                 case GT_LCL_FLD:
                 case GT_STORE_LCL_FLD:
-                {
-                    GenTreeLclFld* lclField = memOp->AsLclFld();
-                    varNum                  = lclField->GetLclNum();
-                    offset                  = lclField->gtLclOffs;
+                    varNum = memOp->AsLclFld()->GetLclNum();
+                    offset = memOp->AsLclFld()->GetLclOffs();
                     break;
-                }
 
                 case GT_LCL_VAR:
                 {
index f767ef7..02fd018 100644 (file)
@@ -1322,8 +1322,8 @@ AGAIN:
                 return true;
 
             case GT_LCL_FLD:
-                if (op1->AsLclFld()->GetLclNum() != op2->AsLclFld()->GetLclNum() ||
-                    op1->AsLclFld()->gtLclOffs != op2->AsLclFld()->gtLclOffs)
+                if ((op1->AsLclFld()->GetLclNum() != op2->AsLclFld()->GetLclNum()) ||
+                    (op1->AsLclFld()->GetLclOffs() != op2->AsLclFld()->GetLclOffs()))
                 {
                     break;
                 }
@@ -1971,7 +1971,7 @@ AGAIN:
                 break;
             case GT_LCL_FLD:
                 hash = genTreeHashAdd(hash, tree->AsLclFld()->GetLclNum());
-                add  = tree->AsLclFld()->gtLclOffs;
+                add  = tree->AsLclFld()->GetLclOffs();
                 break;
 
             case GT_CNS_INT:
@@ -3422,6 +3422,13 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
                 }
                 break;
 
+            case GT_LCL_FLD_ADDR:
+            case GT_LCL_VAR_ADDR:
+                level  = 1;
+                costEx = 3;
+                costSz = 3;
+                break;
+
             case GT_PHI_ARG:
             case GT_ARGPLACE:
                 level  = 0;
@@ -5678,6 +5685,13 @@ GenTreeIntCon* Compiler::gtNewIconNode(ssize_t value, var_types type)
     return new (this, GT_CNS_INT) GenTreeIntCon(type, value);
 }
 
+GenTreeIntCon* Compiler::gtNewIconNode(unsigned fieldOffset, FieldSeqNode* fieldSeq)
+{
+    GenTreeIntCon* node = new (this, GT_CNS_INT) GenTreeIntCon(TYP_I_IMPL, static_cast<ssize_t>(fieldOffset));
+    node->gtFieldSeq    = fieldSeq == nullptr ? FieldSeqStore::NotAField() : fieldSeq;
+    return node;
+}
+
 // return a new node representing the value in a physical register
 GenTree* Compiler::gtNewPhysRegNode(regNumber reg, var_types type)
 {
@@ -6144,6 +6158,18 @@ GenTree* Compiler::gtNewLclLNode(unsigned lnum, var_types type DEBUGARG(IL_OFFSE
     return node;
 }
 
+GenTreeLclVar* Compiler::gtNewLclVarAddrNode(unsigned lclNum, var_types type)
+{
+    return new (this, GT_LCL_VAR_ADDR) GenTreeLclVar(type, lclNum);
+}
+
+GenTreeLclFld* Compiler::gtNewLclFldAddrNode(unsigned lclNum, unsigned lclOffs, FieldSeqNode* fieldSeq, var_types type)
+{
+    GenTreeLclFld* node = new (this, GT_LCL_FLD_ADDR) GenTreeLclFld(type, lclNum, lclOffs);
+    node->SetFieldSeq(fieldSeq == nullptr ? FieldSeqStore::NotAField() : fieldSeq);
+    return node;
+}
+
 GenTreeLclFld* Compiler::gtNewLclFldNode(unsigned lnum, var_types type, unsigned offset)
 {
     GenTreeLclFld* node = new (this, GT_LCL_FLD) GenTreeLclFld(type, lnum, offset);
@@ -6153,7 +6179,7 @@ GenTreeLclFld* Compiler::gtNewLclFldNode(unsigned lnum, var_types type, unsigned
 
     // assert(lnum < lvaCount);
 
-    node->gtFieldSeq = FieldSeqStore::NotAField();
+    node->SetFieldSeq(FieldSeqStore::NotAField());
     return node;
 }
 
@@ -6925,9 +6951,10 @@ GenTree* Compiler::gtClone(GenTree* tree, bool complexOK)
             // Remember that the LclVar node has been cloned. The flag will be set
             // on 'copy' as well.
             tree->gtFlags |= GTF_VAR_CLONED;
-            copy = new (this, tree->gtOper) GenTreeLclFld(tree->gtOper, tree->TypeGet(), tree->AsLclFld()->GetLclNum(),
-                                                          tree->AsLclFld()->gtLclOffs);
-            copy->AsLclFld()->gtFieldSeq = tree->AsLclFld()->gtFieldSeq;
+            copy = new (this, tree->OperGet())
+                GenTreeLclFld(tree->OperGet(), tree->TypeGet(), tree->AsLclFld()->GetLclNum(),
+                              tree->AsLclFld()->GetLclOffs());
+            copy->AsLclFld()->SetFieldSeq(tree->AsLclFld()->GetFieldSeq());
             break;
 
         case GT_CLS_VAR:
@@ -7120,9 +7147,9 @@ GenTree* Compiler::gtCloneExpr(
                     // be set on 'copy' as well.
                     tree->gtFlags |= GTF_VAR_CLONED;
                     copy = new (this, GT_LCL_FLD)
-                        GenTreeLclFld(tree->TypeGet(), tree->AsLclFld()->GetLclNum(), tree->AsLclFld()->gtLclOffs);
-                    copy->AsLclFld()->gtFieldSeq = tree->AsLclFld()->gtFieldSeq;
-                    copy->gtFlags                = tree->gtFlags;
+                        GenTreeLclFld(tree->TypeGet(), tree->AsLclFld()->GetLclNum(), tree->AsLclFld()->GetLclOffs());
+                    copy->AsLclFld()->SetFieldSeq(tree->AsLclFld()->GetFieldSeq());
+                    copy->gtFlags = tree->gtFlags;
                 }
                 goto DONE;
 
@@ -7167,6 +7194,16 @@ GenTree* Compiler::gtCloneExpr(
                 copy = new (this, oper) GenTreeVal(oper, tree->gtType, tree->AsVal()->gtVal1);
                 goto DONE;
 
+            case GT_LCL_VAR_ADDR:
+                copy = new (this, oper) GenTreeLclVar(oper, tree->TypeGet(), tree->AsLclVar()->GetLclNum());
+                goto DONE;
+
+            case GT_LCL_FLD_ADDR:
+                copy = new (this, oper)
+                    GenTreeLclFld(oper, tree->TypeGet(), tree->AsLclFld()->GetLclNum(), tree->AsLclFld()->GetLclOffs());
+                copy->AsLclFld()->SetFieldSeq(tree->AsLclFld()->GetFieldSeq());
+                goto DONE;
+
             default:
                 NO_WAY("Cloning of node not supported");
                 goto DONE;
@@ -10583,8 +10620,8 @@ void Compiler::gtDispLeaf(GenTree* tree, IndentStack* indentStack)
 
             if (isLclFld)
             {
-                printf("[+%u]", tree->AsLclFld()->gtLclOffs);
-                gtDispFieldSeq(tree->AsLclFld()->gtFieldSeq);
+                printf("[+%u]", tree->AsLclFld()->GetLclOffs());
+                gtDispFieldSeq(tree->AsLclFld()->GetFieldSeq());
             }
 
             if (varDsc->lvRegister)
@@ -15820,7 +15857,7 @@ bool GenTree::DefinesLocalAddr(Compiler* comp, unsigned width, GenTreeLclVarComm
                 unsigned lclOffset = 0;
                 if (addrArg->OperIsLocalField())
                 {
-                    lclOffset = addrArg->AsLclFld()->gtLclOffs;
+                    lclOffset = addrArg->AsLclFld()->GetLclOffs();
                 }
 
                 if (lclOffset != 0)
@@ -15922,7 +15959,7 @@ bool GenTree::IsLocalExpr(Compiler* comp, GenTreeLclVarCommon** pLclVarTree, Fie
         if (OperGet() == GT_LCL_FLD)
         {
             // Otherwise, prepend this field to whatever we've already accumulated outside in.
-            *pFldSeq = comp->GetFieldSeqStore()->Append(AsLclFld()->gtFieldSeq, *pFldSeq);
+            *pFldSeq = comp->GetFieldSeqStore()->Append(AsLclFld()->GetFieldSeq(), *pFldSeq);
         }
         return true;
     }
@@ -15972,7 +16009,7 @@ bool GenTree::IsLocalAddrExpr(Compiler* comp, GenTreeLclVarCommon** pLclVarTree,
             if (addrArg->OperGet() == GT_LCL_FLD)
             {
                 // Otherwise, prepend this field to whatever we've already accumulated outside in.
-                *pFldSeq = comp->GetFieldSeqStore()->Append(addrArg->AsLclFld()->gtFieldSeq, *pFldSeq);
+                *pFldSeq = comp->GetFieldSeqStore()->Append(addrArg->AsLclFld()->GetFieldSeq(), *pFldSeq);
             }
             return true;
         }
@@ -15986,7 +16023,7 @@ bool GenTree::IsLocalAddrExpr(Compiler* comp, GenTreeLclVarCommon** pLclVarTree,
         *pLclVarTree = this->AsLclVarCommon();
         if (this->OperGet() == GT_LCL_FLD_ADDR)
         {
-            *pFldSeq = comp->GetFieldSeqStore()->Append(this->AsLclFld()->gtFieldSeq, *pFldSeq);
+            *pFldSeq = comp->GetFieldSeqStore()->Append(this->AsLclFld()->GetFieldSeq(), *pFldSeq);
         }
         return true;
     }
index eadf82b..c88ba80 100644 (file)
@@ -1016,6 +1016,17 @@ public:
     void dumpLIRFlags();
 #endif
 
+    bool TypeIs(var_types type) const
+    {
+        return gtType == type;
+    }
+
+    template <typename... T>
+    bool TypeIs(var_types type, T... rest) const
+    {
+        return TypeIs(type) || TypeIs(rest...);
+    }
+
     bool OperIs(genTreeOps oper) const
     {
         return OperGet() == oper;
@@ -3109,22 +3120,44 @@ struct GenTreeLclVar : public GenTreeLclVarCommon
 
 struct GenTreeLclFld : public GenTreeLclVarCommon
 {
-    unsigned gtLclOffs; // offset into the variable to access
-
-    FieldSeqNode* gtFieldSeq; // This LclFld node represents some sequences of accesses.
+private:
+    uint16_t      m_lclOffs;  // offset into the variable to access
+    FieldSeqNode* m_fieldSeq; // This LclFld node represents some sequences of accesses.
 
-    // old/FE style constructor where load/store/addr share same opcode
+public:
     GenTreeLclFld(var_types type, unsigned lclNum, unsigned lclOffs)
-        : GenTreeLclVarCommon(GT_LCL_FLD, type, lclNum), gtLclOffs(lclOffs), gtFieldSeq(nullptr)
+        : GenTreeLclVarCommon(GT_LCL_FLD, type, lclNum), m_lclOffs(static_cast<uint16_t>(lclOffs)), m_fieldSeq(nullptr)
     {
-        assert(sizeof(*this) <= s_gtNodeSizes[GT_LCL_FLD]);
+        assert(lclOffs <= UINT16_MAX);
     }
 
     GenTreeLclFld(genTreeOps oper, var_types type, unsigned lclNum, unsigned lclOffs)
-        : GenTreeLclVarCommon(oper, type, lclNum), gtLclOffs(lclOffs), gtFieldSeq(nullptr)
+        : GenTreeLclVarCommon(oper, type, lclNum), m_lclOffs(static_cast<uint16_t>(lclOffs)), m_fieldSeq(nullptr)
     {
-        assert(sizeof(*this) <= s_gtNodeSizes[GT_LCL_FLD]);
+        assert(lclOffs <= UINT16_MAX);
     }
+
+    uint16_t GetLclOffs() const
+    {
+        return m_lclOffs;
+    }
+
+    void SetLclOffs(unsigned lclOffs)
+    {
+        assert(lclOffs <= UINT16_MAX);
+        m_lclOffs = static_cast<uint16_t>(lclOffs);
+    }
+
+    FieldSeqNode* GetFieldSeq() const
+    {
+        return m_fieldSeq;
+    }
+
+    void SetFieldSeq(FieldSeqNode* fieldSeq)
+    {
+        m_fieldSeq = fieldSeq;
+    }
+
 #if DEBUGGABLE_GENTREE
     GenTreeLclFld() : GenTreeLclVarCommon()
     {
index 66a00fe..2093561 100644 (file)
@@ -498,13 +498,9 @@ void CodeGen::genHWIntrinsic_R_RM(
             switch (rmOp->OperGet())
             {
                 case GT_LCL_FLD:
-                {
-                    GenTreeLclFld* lclField = rmOp->AsLclFld();
-
-                    varNum = lclField->GetLclNum();
-                    offset = lclField->gtLclOffs;
+                    varNum = rmOp->AsLclFld()->GetLclNum();
+                    offset = rmOp->AsLclFld()->GetLclOffs();
                     break;
-                }
 
                 case GT_LCL_VAR:
                 {
@@ -684,13 +680,9 @@ void CodeGen::genHWIntrinsic_R_R_RM(
             switch (op2->OperGet())
             {
                 case GT_LCL_FLD:
-                {
-                    GenTreeLclFld* lclField = op2->AsLclFld();
-
-                    varNum = lclField->GetLclNum();
-                    offset = lclField->AsLclFld()->gtLclOffs;
+                    varNum = op2->AsLclFld()->GetLclNum();
+                    offset = op2->AsLclFld()->GetLclOffs();
                     break;
-                }
 
                 case GT_LCL_VAR:
                 {
@@ -852,13 +844,9 @@ void CodeGen::genHWIntrinsic_R_R_RM_I(GenTreeHWIntrinsic* node, instruction ins,
             switch (op2->OperGet())
             {
                 case GT_LCL_FLD:
-                {
-                    GenTreeLclFld* lclField = op2->AsLclFld();
-
-                    varNum = lclField->GetLclNum();
-                    offset = lclField->AsLclFld()->gtLclOffs;
+                    varNum = op2->AsLclFld()->GetLclNum();
+                    offset = op2->AsLclFld()->GetLclOffs();
                     break;
-                }
 
                 case GT_LCL_VAR:
                 {
@@ -1019,13 +1007,9 @@ void CodeGen::genHWIntrinsic_R_R_RM_R(GenTreeHWIntrinsic* node, instruction ins)
             switch (op2->OperGet())
             {
                 case GT_LCL_FLD:
-                {
-                    GenTreeLclFld* lclField = op2->AsLclFld();
-
-                    varNum = lclField->GetLclNum();
-                    offset = lclField->AsLclFld()->gtLclOffs;
+                    varNum = op2->AsLclFld()->GetLclNum();
+                    offset = op2->AsLclFld()->GetLclOffs();
                     break;
-                }
 
                 case GT_LCL_VAR:
                 {
@@ -1147,13 +1131,9 @@ void CodeGen::genHWIntrinsic_R_R_R_RM(
             switch (op3->OperGet())
             {
                 case GT_LCL_FLD:
-                {
-                    GenTreeLclFld* lclField = op3->AsLclFld();
-
-                    varNum = lclField->GetLclNum();
-                    offset = lclField->AsLclFld()->gtLclOffs;
+                    varNum = op3->AsLclFld()->GetLclNum();
+                    offset = op3->AsLclFld()->GetLclOffs();
                     break;
-                }
 
                 case GT_LCL_VAR:
                 {
index 8055dc6..eb5ecf8 100644 (file)
@@ -583,8 +583,7 @@ AGAIN:
             goto LCL;
 
         case GT_LCL_FLD:
-
-            offs += tree->AsLclFld()->gtLclOffs;
+            offs += tree->AsLclFld()->GetLclOffs();
             goto LCL;
 
         LCL:
@@ -691,7 +690,7 @@ AGAIN:
 
         case GT_LCL_FLD:
         case GT_STORE_LCL_FLD:
-            offs += tree->AsLclFld()->gtLclOffs;
+            offs += tree->AsLclFld()->GetLclOffs();
             goto LCL;
 
         LCL:
@@ -840,7 +839,7 @@ AGAIN:
 
         case GT_LCL_FLD_ADDR:
         case GT_LCL_FLD:
-            offs += tree->AsLclFld()->gtLclOffs;
+            offs += tree->AsLclFld()->GetLclOffs();
             goto LCL;
 
         LCL:
@@ -1131,13 +1130,9 @@ void CodeGen::inst_RV_TT_IV(instruction ins, emitAttr attr, regNumber reg1, GenT
             switch (rmOp->OperGet())
             {
                 case GT_LCL_FLD:
-                {
-                    GenTreeLclFld* lclField = rmOp->AsLclFld();
-
-                    varNum = lclField->GetLclNum();
-                    offset = lclField->AsLclFld()->gtLclOffs;
+                    varNum = rmOp->AsLclFld()->GetLclNum();
+                    offset = rmOp->AsLclFld()->GetLclOffs();
                     break;
-                }
 
                 case GT_LCL_VAR:
                 {
index 7de0f86..e76d8ec 100644 (file)
@@ -3615,6 +3615,14 @@ void Compiler::lvaMarkLclRefs(GenTree* tree, BasicBlock* block, Statement* stmt,
         }
     }
 
+    if (tree->OperIsLocalAddr())
+    {
+        LclVarDsc* varDsc = lvaGetDesc(tree->AsLclVarCommon());
+        assert(varDsc->lvAddrExposed);
+        varDsc->incRefCnts(weight, this);
+        return;
+    }
+
     if ((tree->gtOper != GT_LCL_VAR) && (tree->gtOper != GT_LCL_FLD))
     {
         return;
@@ -7348,7 +7356,7 @@ Compiler::fgWalkResult Compiler::lvaStressLclFldCB(GenTree** pTree, fgWalkData*
             /* Change lclVar(lclNum) to lclFld(lclNum,padding) */
 
             tree->ChangeOper(GT_LCL_FLD);
-            tree->AsLclFld()->gtLclOffs = padding;
+            tree->AsLclFld()->SetLclOffs(padding);
         }
         else
         {
index 6ab876c..f8068a4 100644 (file)
@@ -4084,8 +4084,7 @@ GenTree* Lowering::LowerVirtualVtableCall(GenTreeCall* call)
     GenTree* local;
     if (thisPtr->isLclField())
     {
-        local = new (comp, GT_LCL_FLD)
-            GenTreeLclFld(GT_LCL_FLD, thisPtr->TypeGet(), lclNum, thisPtr->AsLclFld()->gtLclOffs);
+        local = new (comp, GT_LCL_FLD) GenTreeLclFld(thisPtr->TypeGet(), lclNum, thisPtr->AsLclFld()->GetLclOffs());
     }
     else
     {
index 12791f7..75ceb05 100644 (file)
@@ -1312,6 +1312,8 @@ void fgArgInfo::ArgsComplete()
                 fgArgTabEntry* prevArgTabEntry = argTable[prevInx];
                 assert(prevArgTabEntry->argNum < curArgTabEntry->argNum);
 
+                // TODO-CQ: We should also allow LCL_VAR_ADDR and LCL_FLD_ADDR here, they're
+                // side effect free leaf nodes that like constant can be evaluated at any point.
                 if (prevArgTabEntry->GetNode()->gtOper != GT_CNS_INT)
                 {
                     prevArgTabEntry->needTmp = true;
@@ -3944,9 +3946,9 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
             // (tmp.ptr=argx),(tmp.type=handle)
             GenTreeLclFld* destPtrSlot  = gtNewLclFldNode(tmp, TYP_I_IMPL, OFFSETOF__CORINFO_TypedReference__dataPtr);
             GenTreeLclFld* destTypeSlot = gtNewLclFldNode(tmp, TYP_I_IMPL, OFFSETOF__CORINFO_TypedReference__type);
-            destPtrSlot->gtFieldSeq     = GetFieldSeqStore()->CreateSingleton(GetRefanyDataField());
+            destPtrSlot->SetFieldSeq(GetFieldSeqStore()->CreateSingleton(GetRefanyDataField()));
             destPtrSlot->gtFlags |= GTF_VAR_DEF;
-            destTypeSlot->gtFieldSeq = GetFieldSeqStore()->CreateSingleton(GetRefanyTypeField());
+            destTypeSlot->SetFieldSeq(GetFieldSeqStore()->CreateSingleton(GetRefanyTypeField()));
             destTypeSlot->gtFlags |= GTF_VAR_DEF;
 
             GenTree* asgPtrSlot  = gtNewAssignNode(destPtrSlot, argx->AsOp()->gtOp1);
@@ -4661,7 +4663,7 @@ GenTree* Compiler::fgMorphMultiregStructArg(GenTree* arg, fgArgTabEntry* fgEntry
             assert(varNum < lvaCount);
             LclVarDsc* varDsc = &lvaTable[varNum];
 
-            unsigned baseOffset = (argValue->OperGet() == GT_LCL_FLD) ? argValue->AsLclFld()->gtLclOffs : 0;
+            unsigned baseOffset = argValue->OperIs(GT_LCL_FLD) ? argValue->AsLclFld()->GetLclOffs() : 0;
             unsigned lastOffset = baseOffset + structSize;
 
             // The allocated size of our LocalVar must be at least as big as lastOffset
@@ -8554,8 +8556,8 @@ GenTree* Compiler::fgMorphLeaf(GenTree* tree)
     {
         if (info.compIsVarArgs)
         {
-            GenTree* newTree =
-                fgMorphStackArgForVarArgs(tree->AsLclFld()->GetLclNum(), tree->gtType, tree->AsLclFld()->gtLclOffs);
+            GenTree* newTree = fgMorphStackArgForVarArgs(tree->AsLclFld()->GetLclNum(), tree->TypeGet(),
+                                                         tree->AsLclFld()->GetLclOffs());
             if (newTree != nullptr)
             {
                 if (newTree->OperIsBlk() && ((tree->gtFlags & GTF_VAR_DEF) == 0))
@@ -9785,7 +9787,7 @@ GenTree* Compiler::fgMorphCopyBlock(GenTree* tree)
                 assert(dest->gtOper == GT_LCL_FLD);
                 blockWidth = genTypeSize(dest->TypeGet());
                 destAddr   = gtNewOperNode(GT_ADDR, TYP_BYREF, dest);
-                destFldSeq = dest->AsLclFld()->gtFieldSeq;
+                destFldSeq = dest->AsLclFld()->GetFieldSeq();
             }
         }
         else
@@ -9867,7 +9869,7 @@ GenTree* Compiler::fgMorphCopyBlock(GenTree* tree)
             srcLclNum     = srcLclVarTree->GetLclNum();
             if (rhs->OperGet() == GT_LCL_FLD)
             {
-                srcFldSeq = rhs->AsLclFld()->gtFieldSeq;
+                srcFldSeq = rhs->AsLclFld()->GetFieldSeq();
             }
         }
         else if (rhs->OperIsIndir())
@@ -10403,10 +10405,10 @@ GenTree* Compiler::fgMorphCopyBlock(GenTree* tree)
                             {
                                 srcLclVarTree->gtFlags |= GTF_VAR_CAST;
                                 srcLclVarTree->ChangeOper(GT_LCL_FLD);
-                                srcLclVarTree->gtType                 = destType;
-                                srcLclVarTree->AsLclFld()->gtFieldSeq = curFieldSeq;
-                                src                                   = srcLclVarTree;
-                                done                                  = true;
+                                srcLclVarTree->gtType = destType;
+                                srcLclVarTree->AsLclFld()->SetFieldSeq(curFieldSeq);
+                                src  = srcLclVarTree;
+                                done = true;
                             }
                         }
                     }
@@ -12882,8 +12884,8 @@ DONE_MORPHING_CHILDREN:
                             if ((fieldSeq != nullptr) && (temp->OperGet() == GT_LCL_FLD))
                             {
                                 // Append the field sequence, change the type.
-                                temp->AsLclFld()->gtFieldSeq =
-                                    GetFieldSeqStore()->Append(temp->AsLclFld()->gtFieldSeq, fieldSeq);
+                                temp->AsLclFld()->SetFieldSeq(
+                                    GetFieldSeqStore()->Append(temp->AsLclFld()->GetFieldSeq(), fieldSeq));
                                 temp->gtType = typ;
 
                                 foldAndReturnTemp = true;
@@ -13005,29 +13007,29 @@ DONE_MORPHING_CHILDREN:
                     if (temp->OperGet() == GT_LCL_FLD)
                     {
                         lclFld = temp->AsLclFld();
-                        lclFld->gtLclOffs += (unsigned short)ival1;
-                        lclFld->gtFieldSeq = GetFieldSeqStore()->Append(lclFld->gtFieldSeq, fieldSeq);
+                        lclFld->SetLclOffs(lclFld->GetLclOffs() + static_cast<unsigned>(ival1));
+                        lclFld->SetFieldSeq(GetFieldSeqStore()->Append(lclFld->GetFieldSeq(), fieldSeq));
                     }
                     else // we have a GT_LCL_VAR
                     {
                         assert(temp->OperGet() == GT_LCL_VAR);
                         temp->ChangeOper(GT_LCL_FLD); // Note that this typically makes the gtFieldSeq "NotAField",
                         // unless there is a zero filed offset associated with 'temp'.
-                        lclFld            = temp->AsLclFld();
-                        lclFld->gtLclOffs = (unsigned short)ival1;
+                        lclFld = temp->AsLclFld();
+                        lclFld->SetLclOffs(static_cast<unsigned>(ival1));
 
-                        if (lclFld->gtFieldSeq == FieldSeqStore::NotAField())
+                        if (lclFld->GetFieldSeq() == FieldSeqStore::NotAField())
                         {
                             if (fieldSeq != nullptr)
                             {
                                 // If it does represent a field, note that.
-                                lclFld->gtFieldSeq = fieldSeq;
+                                lclFld->SetFieldSeq(fieldSeq);
                             }
                         }
                         else
                         {
                             // Append 'fieldSeq' to the existing one
-                            lclFld->gtFieldSeq = GetFieldSeqStore()->Append(lclFld->gtFieldSeq, fieldSeq);
+                            lclFld->SetFieldSeq(GetFieldSeqStore()->Append(lclFld->GetFieldSeq(), fieldSeq));
                         }
                     }
                     temp->gtType      = tree->gtType;
@@ -17010,7 +17012,7 @@ void Compiler::fgMorphLocalField(GenTree* tree, GenTree* parent)
     if (varTypeIsStruct(varDsc) && (varDsc->lvPromoted))
     {
         // Promoted struct
-        unsigned   fldOffset     = tree->AsLclFld()->gtLclOffs;
+        unsigned   fldOffset     = tree->AsLclFld()->GetLclOffs();
         unsigned   fieldLclIndex = 0;
         LclVarDsc* fldVarDsc     = nullptr;
 
@@ -17569,16 +17571,18 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
     //
     class Value
     {
-        GenTree* m_node;
-        unsigned m_lclNum;
-        unsigned m_offset;
-        bool     m_address;
+        GenTree*      m_node;
+        FieldSeqNode* m_fieldSeq;
+        unsigned      m_lclNum;
+        unsigned      m_offset;
+        bool          m_address;
         INDEBUG(bool m_consumed;)
 
     public:
         // Produce an unknown value associated with the specified node.
         Value(GenTree* node)
             : m_node(node)
+            , m_fieldSeq(nullptr)
             , m_lclNum(BAD_VAR_NUM)
             , m_offset(0)
             , m_address(false)
@@ -17624,22 +17628,90 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
             return m_offset;
         }
 
+        // Get the location's field sequence.
+        FieldSeqNode* FieldSeq() const
+        {
+            return m_fieldSeq;
+        }
+
+        //------------------------------------------------------------------------
+        // Location: Produce a location value.
+        //
+        // Arguments:
+        //    lclVar - a GT_LCL_VAR node that defines the location
+        //
+        // Notes:
+        //   - (lclnum) => LOCATION(lclNum, 0)
+        //
+        void Location(GenTreeLclVar* lclVar)
+        {
+            assert(lclVar->OperIs(GT_LCL_VAR));
+            assert(!IsLocation() && !IsAddress());
+
+            m_lclNum = lclVar->GetLclNum();
+
+            assert(m_offset == 0);
+            assert(m_fieldSeq == nullptr);
+        }
+
+        //------------------------------------------------------------------------
+        // Location: Produce an address value from a GT_LCL_VAR_ADDR node.
+        //
+        // Arguments:
+        //    lclVar - a GT_LCL_VAR_ADDR node that defines the address
+        //
+        // Notes:
+        //   - (lclnum) => ADDRESS(lclNum, 0)
+        //
+        void Address(GenTreeLclVar* lclVar)
+        {
+            assert(lclVar->OperIs(GT_LCL_VAR_ADDR));
+            assert(!IsLocation() && !IsAddress());
+
+            m_lclNum  = lclVar->GetLclNum();
+            m_address = true;
+
+            assert(m_offset == 0);
+            assert(m_fieldSeq == nullptr);
+        }
+
         //------------------------------------------------------------------------
         // Location: Produce a location value.
         //
         // Arguments:
-        //    lclNum - the local variable number
-        //    offset - the byte offset of the location (used for GT_LCL_FLD nodes)
+        //    lclFld - a GT_LCL_FLD node that defines the location
         //
         // Notes:
-        //   - (lclnum, offset) => LOCATION(lclNum, offset)
+        //   - (lclnum, lclOffs) => LOCATION(lclNum, offset)
         //
-        void Location(unsigned lclNum, unsigned offset = 0)
+        void Location(GenTreeLclFld* lclFld)
         {
+            assert(lclFld->OperIs(GT_LCL_FLD));
             assert(!IsLocation() && !IsAddress());
 
-            m_lclNum = lclNum;
-            m_offset = offset;
+            m_lclNum   = lclFld->GetLclNum();
+            m_offset   = lclFld->GetLclOffs();
+            m_fieldSeq = lclFld->GetFieldSeq();
+        }
+
+        //------------------------------------------------------------------------
+        // Address: Produce an address value from a LCL_FLD_ADDR node.
+        //
+        // Arguments:
+        //    lclFld - a GT_LCL_FLD_ADDR node that defines the address
+        //
+        // Notes:
+        //   - (lclnum, lclOffs) => ADDRESS(lclNum, offset)
+        //
+        void Address(GenTreeLclFld* lclFld)
+        {
+            assert(lclFld->OperIs(GT_LCL_FLD_ADDR));
+            assert(!IsLocation() && !IsAddress());
+
+            m_lclNum   = lclFld->GetLclNum();
+            m_offset   = lclFld->GetLclOffs();
+            m_fieldSeq = lclFld->GetFieldSeq();
+            m_address  = true;
         }
 
         //------------------------------------------------------------------------
@@ -17660,9 +17732,10 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
 
             if (val.IsLocation())
             {
-                m_address = true;
-                m_lclNum  = val.m_lclNum;
-                m_offset  = val.m_offset;
+                m_address  = true;
+                m_lclNum   = val.m_lclNum;
+                m_offset   = val.m_offset;
+                m_fieldSeq = val.m_fieldSeq;
             }
 
             INDEBUG(val.Consume();)
@@ -17672,8 +17745,9 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
         // Field: Produce a location value from an address value.
         //
         // Arguments:
-        //    val    - the input value
-        //    offset - the offset to add to the existing location offset
+        //    val - the input value
+        //    field - the FIELD node that uses the input address value
+        //    fieldSeqStore - the compiler's field sequence store
         //
         // Return Value:
         //    `true` if the value was consumed. `false` if the input value
@@ -17687,7 +17761,7 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
         //     if the offset overflows then location is not representable, must escape
         //   - UNKNOWN => UNKNOWN
         //
-        bool Field(Value& val, unsigned offset)
+        bool Field(Value& val, GenTreeField* field, FieldSeqStore* fieldSeqStore)
         {
             assert(!IsLocation() && !IsAddress());
 
@@ -17698,7 +17772,8 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
 
             if (val.IsAddress())
             {
-                ClrSafeInt<unsigned> newOffset = ClrSafeInt<unsigned>(val.m_offset) + ClrSafeInt<unsigned>(offset);
+                ClrSafeInt<unsigned> newOffset =
+                    ClrSafeInt<unsigned>(val.m_offset) + ClrSafeInt<unsigned>(field->gtFldOffset);
 
                 if (newOffset.IsOverflow())
                 {
@@ -17707,6 +17782,15 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
 
                 m_lclNum = val.m_lclNum;
                 m_offset = newOffset.Value();
+
+                if (field->gtFldMayOverlap)
+                {
+                    m_fieldSeq = FieldSeqStore::NotAField();
+                }
+                else
+                {
+                    m_fieldSeq = fieldSeqStore->Append(val.m_fieldSeq, fieldSeqStore->CreateSingleton(field->gtFldHnd));
+                }
             }
 
             INDEBUG(val.Consume();)
@@ -17740,8 +17824,9 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
 
             if (val.IsAddress())
             {
-                m_lclNum = val.m_lclNum;
-                m_offset = val.m_offset;
+                m_lclNum   = val.m_lclNum;
+                m_offset   = val.m_offset;
+                m_fieldSeq = val.m_fieldSeq;
             }
 
             INDEBUG(val.Consume();)
@@ -17880,13 +17965,25 @@ public:
             case GT_LCL_VAR:
                 assert(TopValue(0).Node() == node);
 
-                TopValue(0).Location(node->AsLclVar()->GetLclNum());
+                TopValue(0).Location(node->AsLclVar());
+                break;
+
+            case GT_LCL_VAR_ADDR:
+                assert(TopValue(0).Node() == node);
+
+                TopValue(0).Address(node->AsLclVar());
                 break;
 
             case GT_LCL_FLD:
                 assert(TopValue(0).Node() == node);
 
-                TopValue(0).Location(node->AsLclFld()->GetLclNum(), node->AsLclFld()->gtLclOffs);
+                TopValue(0).Location(node->AsLclFld());
+                break;
+
+            case GT_LCL_FLD_ADDR:
+                assert(TopValue(0).Node() == node);
+
+                TopValue(0).Address(node->AsLclFld());
                 break;
 
             case GT_ADDR:
@@ -17903,7 +18000,7 @@ public:
                     assert(TopValue(1).Node() == node);
                     assert(TopValue(0).Node() == node->AsField()->gtFldObj);
 
-                    if (!TopValue(1).Field(TopValue(0), node->AsField()->gtFldOffset))
+                    if (!TopValue(1).Field(TopValue(0), node->AsField(), m_compiler->GetFieldSeqStore()))
                     {
                         // Either the address comes from a location value (e.g. FIELD(IND(...)))
                         // or the field offset has overflowed.
@@ -18056,6 +18153,15 @@ private:
         }
 #endif // _TARGET_64BIT_
 
+        // TODO-ADDR: For now use LCL_VAR_ADDR and LCL_FLD_ADDR only as call arguments and assignment sources.
+        // Other usages require more changes. For example, a tree like OBJ(ADD(ADDR(LCL_VAR), 4))
+        // could be changed to OBJ(LCL_FLD_ADDR) but then DefinesLocalAddr does not recognize
+        // LCL_FLD_ADDR (even though it does recognize LCL_VAR_ADDR).
+        if (user->OperIs(GT_CALL, GT_ASG))
+        {
+            MorphLocalAddress(val);
+        }
+
         INDEBUG(val.Consume();)
     }
 
@@ -18214,6 +18320,57 @@ private:
     }
 
     //------------------------------------------------------------------------
+    // MorphLocalAddress: Change a tree that represents a local variable address
+    //    to a single LCL_VAR_ADDR or LCL_FLD_ADDR node.
+    //
+    // Arguments:
+    //    val - a value that represents the local address
+    //
+    void MorphLocalAddress(const Value& val)
+    {
+        assert(val.IsAddress());
+        assert(val.Node()->TypeIs(TYP_BYREF, TYP_I_IMPL));
+        assert(m_compiler->lvaVarAddrExposed(val.LclNum()));
+
+        LclVarDsc* varDsc = m_compiler->lvaGetDesc(val.LclNum());
+
+        if (varDsc->lvPromoted || varDsc->lvIsStructField || m_compiler->lvaIsImplicitByRefLocal(val.LclNum()))
+        {
+            // TODO-ADDR: For now we ignore promoted and "implict by ref" variables,
+            // they require additional changes in subsequent phases.
+            return;
+        }
+
+        GenTree* addr = val.Node();
+
+        if (val.Offset() > UINT16_MAX)
+        {
+            // The offset is too large to store in a LCL_FLD_ADDR node,
+            // use ADD(LCL_VAR_ADDR, offset) instead.
+            addr->ChangeOper(GT_ADD);
+            addr->AsOp()->gtOp1 = m_compiler->gtNewLclVarAddrNode(val.LclNum());
+            addr->AsOp()->gtOp2 = m_compiler->gtNewIconNode(val.Offset(), val.FieldSeq());
+        }
+        else if ((val.Offset() != 0) || (val.FieldSeq() != nullptr))
+        {
+            addr->ChangeOper(GT_LCL_FLD_ADDR);
+            addr->AsLclFld()->SetLclNum(val.LclNum());
+            addr->AsLclFld()->SetLclOffs(val.Offset());
+            addr->AsLclFld()->SetFieldSeq(val.FieldSeq());
+        }
+        else
+        {
+            addr->ChangeOper(GT_LCL_VAR_ADDR);
+            addr->AsLclVar()->SetLclNum(val.LclNum());
+        }
+
+        // Local address nodes never have side effects (nor any other flags, at least at this point).
+        addr->gtFlags = 0;
+
+        INDEBUG(m_stmtModified = true;)
+    }
+
+    //------------------------------------------------------------------------
     // MorphStructField: Replaces a GT_FIELD based promoted/normed struct field access
     //    (e.g. FIELD(ADDR(LCL_VAR))) with a GT_LCL_VAR that references the struct field.
     //
@@ -18331,9 +18488,9 @@ void Compiler::fgAddFieldSeqForZeroOffset(GenTree* addr, FieldSeqNode* fieldSeqZ
         case GT_LCL_FLD:
         {
             GenTreeLclFld* lclFld = addr->AsLclFld();
-            fieldSeqUpdate        = GetFieldSeqStore()->Append(lclFld->gtFieldSeq, fieldSeqZero);
-            lclFld->gtFieldSeq    = fieldSeqUpdate;
-            fieldSeqRecorded      = true;
+            fieldSeqUpdate        = GetFieldSeqStore()->Append(lclFld->GetFieldSeq(), fieldSeqZero);
+            lclFld->SetFieldSeq(fieldSeqUpdate);
+            fieldSeqRecorded = true;
             break;
         }
 
@@ -18343,9 +18500,9 @@ void Compiler::fgAddFieldSeqForZeroOffset(GenTree* addr, FieldSeqNode* fieldSeqZ
                 fieldSeqNode = addr->AsOp()->gtOp1;
 
                 GenTreeLclFld* lclFld = addr->AsOp()->gtOp1->AsLclFld();
-                fieldSeqUpdate        = GetFieldSeqStore()->Append(lclFld->gtFieldSeq, fieldSeqZero);
-                lclFld->gtFieldSeq    = fieldSeqUpdate;
-                fieldSeqRecorded      = true;
+                fieldSeqUpdate        = GetFieldSeqStore()->Append(lclFld->GetFieldSeq(), fieldSeqZero);
+                lclFld->SetFieldSeq(fieldSeqUpdate);
+                fieldSeqRecorded = true;
             }
             break;
 
index 089d7fb..2c3efd4 100644 (file)
@@ -83,8 +83,8 @@ void Rationalizer::RewriteSIMDIndir(LIR::Use& use)
         else
         {
             addr->SetOper(GT_LCL_FLD);
-            addr->AsLclFld()->gtLclOffs  = 0;
-            addr->AsLclFld()->gtFieldSeq = FieldSeqStore::NotAField();
+            addr->AsLclFld()->SetLclOffs(0);
+            addr->AsLclFld()->SetFieldSeq(FieldSeqStore::NotAField());
 
             if (((addr->gtFlags & GTF_VAR_DEF) != 0) && (genTypeSize(simdType) < genTypeSize(lclType)))
             {
@@ -291,8 +291,8 @@ static void RewriteAssignmentIntoStoreLclCore(GenTreeOp* assignment,
 
     if (locationOp == GT_LCL_FLD)
     {
-        store->AsLclFld()->gtLclOffs  = var->AsLclFld()->gtLclOffs;
-        store->AsLclFld()->gtFieldSeq = var->AsLclFld()->gtFieldSeq;
+        store->AsLclFld()->SetLclOffs(var->AsLclFld()->GetLclOffs());
+        store->AsLclFld()->SetFieldSeq(var->AsLclFld()->GetFieldSeq());
     }
 
     copyFlags(store, var, GTF_LIVENESS_MASK);
index 57e0ee9..83d1093 100644 (file)
@@ -849,7 +849,7 @@ void CodeGen::genSIMDIntrinsicInit(GenTreeSIMD* simdNode)
             }
             else if (op1->OperIsLocalAddr())
             {
-                unsigned offset = (op1->OperGet() == GT_LCL_FLD_ADDR) ? op1->AsLclFld()->gtLclOffs : 0;
+                unsigned offset = op1->OperIs(GT_LCL_FLD_ADDR) ? op1->AsLclFld()->GetLclOffs() : 0;
                 GetEmitter()->emitIns_R_S(ins, emitTypeSize(targetType), targetReg, op1->AsLclVarCommon()->GetLclNum(),
                                           offset);
             }
@@ -2458,7 +2458,7 @@ void CodeGen::genSIMDIntrinsicGetItem(GenTreeSIMD* simdNode)
             offset += compiler->lvaFrameAddress(varNum, &isEBPbased);
             if (op1->OperGet() == GT_LCL_FLD)
             {
-                offset += op1->AsLclFld()->gtLclOffs;
+                offset += op1->AsLclFld()->GetLclOffs();
             }
             baseReg = (isEBPbased) ? REG_EBP : REG_ESP;
         }
@@ -2916,7 +2916,7 @@ void CodeGen::genStoreLclTypeSIMD12(GenTree* treeNode)
 
     if (treeNode->OperGet() == GT_STORE_LCL_FLD)
     {
-        offs = treeNode->AsLclFld()->gtLclOffs;
+        offs = treeNode->AsLclFld()->GetLclOffs();
     }
 
     GenTree* op1 = treeNode->AsOp()->gtOp1;
@@ -2958,7 +2958,7 @@ void CodeGen::genLoadLclTypeSIMD12(GenTree* treeNode)
 
     if (treeNode->OperGet() == GT_LCL_FLD)
     {
-        offs = treeNode->AsLclFld()->gtLclOffs;
+        offs = treeNode->AsLclFld()->GetLclOffs();
     }
 
     // Need an additional Xmm register that is different from targetReg to read upper 4 bytes.
index 89e40d7..ea54e23 100644 (file)
@@ -6723,6 +6723,12 @@ void Compiler::fgValueNumberTree(GenTree* tree)
     {
         switch (oper)
         {
+            case GT_LCL_VAR_ADDR:
+            case GT_LCL_FLD_ADDR:
+                assert(lvaVarAddrExposed(tree->AsLclVarCommon()->GetLclNum()));
+                tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
+                break;
+
             case GT_LCL_VAR:
             {
                 GenTreeLclVarCommon* lcl    = tree->AsLclVarCommon();
@@ -6877,7 +6883,7 @@ void Compiler::fgValueNumberTree(GenTree* tree)
             case GT_LCL_FLD:
             {
                 GenTreeLclFld* lclFld = tree->AsLclFld();
-                assert(!lvaInSsa(lclFld->GetLclNum()) || lclFld->gtFieldSeq != nullptr);
+                assert(!lvaInSsa(lclFld->GetLclNum()) || (lclFld->GetFieldSeq() != nullptr));
                 // If this is a (full) def, then the variable will be labeled with the new SSA number,
                 // which will not have a value.  We skip; it will be handled by one of the assignment-like
                 // forms (assignment, or initBlk or copyBlk).
@@ -6888,7 +6894,7 @@ void Compiler::fgValueNumberTree(GenTree* tree)
                     LclVarDsc* varDsc = &lvaTable[lclNum];
 
                     var_types indType = tree->TypeGet();
-                    if (lclFld->gtFieldSeq == FieldSeqStore::NotAField() || !lvaInSsa(lclFld->GetLclNum()))
+                    if ((lclFld->GetFieldSeq() == FieldSeqStore::NotAField()) || !lvaInSsa(lclFld->GetLclNum()))
                     {
                         // This doesn't represent a proper field access or it's a struct
                         // with overlapping fields that is hard to reason about; return a new unique VN.
@@ -6897,7 +6903,7 @@ void Compiler::fgValueNumberTree(GenTree* tree)
                     else
                     {
                         ValueNumPair lclVNPair = varDsc->GetPerSsaData(ssaNum)->m_vnPair;
-                        tree->gtVNPair         = vnStore->VNPairApplySelectors(lclVNPair, lclFld->gtFieldSeq, indType);
+                        tree->gtVNPair = vnStore->VNPairApplySelectors(lclVNPair, lclFld->GetFieldSeq(), indType);
                     }
                 }
             }
@@ -7169,8 +7175,8 @@ void Compiler::fgValueNumberTree(GenTree* tree)
                         else
                         {
                             // We should never have a null field sequence here.
-                            assert(lclFld->gtFieldSeq != nullptr);
-                            if (lclFld->gtFieldSeq == FieldSeqStore::NotAField())
+                            assert(lclFld->GetFieldSeq() != nullptr);
+                            if (lclFld->GetFieldSeq() == FieldSeqStore::NotAField())
                             {
                                 // We don't know what field this represents.  Assign a new VN to the whole variable
                                 // (since we may be writing to an unknown portion of it.)
@@ -7184,7 +7190,7 @@ void Compiler::fgValueNumberTree(GenTree* tree)
                                 // (we looked in a side table above for its "def" identity).  Look up that value.
                                 ValueNumPair oldLhsVNPair =
                                     lvaTable[lclFld->GetLclNum()].GetPerSsaData(lclFld->GetSsaNum())->m_vnPair;
-                                newLhsVNPair = vnStore->VNPairApplySelectorsAssign(oldLhsVNPair, lclFld->gtFieldSeq,
+                                newLhsVNPair = vnStore->VNPairApplySelectorsAssign(oldLhsVNPair, lclFld->GetFieldSeq(),
                                                                                    rhsVNPair, // Pre-value.
                                                                                    lclFld->TypeGet(), compCurBB);
                             }
@@ -7607,7 +7613,7 @@ void Compiler::fgValueNumberTree(GenTree* tree)
                 }
                 else if (arg->OperGet() == GT_LCL_FLD)
                 {
-                    fieldSeq = arg->AsLclFld()->gtFieldSeq;
+                    fieldSeq = arg->AsLclFld()->GetFieldSeq();
                     if (fieldSeq == nullptr)
                     {
                         // Local field with unknown field seq -- not a precise pointer.