From d0a9dc74befea8438d89e1b35f65f4f00b94b274 Mon Sep 17 00:00:00 2001 From: mikedn Date: Tue, 3 Dec 2019 05:03:16 +0200 Subject: [PATCH] Start using local address nodes in the JIT frontend (#305) * 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 --- src/coreclr/src/jit/codegenarm.cpp | 2 +- src/coreclr/src/jit/codegenarm64.cpp | 4 +- src/coreclr/src/jit/codegenarmarch.cpp | 14 +- src/coreclr/src/jit/codegenlinear.cpp | 2 +- src/coreclr/src/jit/codegenxarch.cpp | 26 +-- src/coreclr/src/jit/compiler.cpp | 4 +- src/coreclr/src/jit/compiler.h | 7 + src/coreclr/src/jit/compiler.hpp | 6 +- src/coreclr/src/jit/decomposelongs.cpp | 12 +- src/coreclr/src/jit/emitxarch.cpp | 7 +- src/coreclr/src/jit/gentree.cpp | 69 +++++-- src/coreclr/src/jit/gentree.h | 49 ++++- src/coreclr/src/jit/hwintrinsiccodegenxarch.cpp | 40 +--- src/coreclr/src/jit/instr.cpp | 15 +- src/coreclr/src/jit/lclvars.cpp | 10 +- src/coreclr/src/jit/lower.cpp | 3 +- src/coreclr/src/jit/morph.cpp | 255 +++++++++++++++++++----- src/coreclr/src/jit/rationalize.cpp | 8 +- src/coreclr/src/jit/simdcodegenxarch.cpp | 8 +- src/coreclr/src/jit/valuenum.cpp | 20 +- 20 files changed, 384 insertions(+), 177 deletions(-) diff --git a/src/coreclr/src/jit/codegenarm.cpp b/src/coreclr/src/jit/codegenarm.cpp index 677b712..c1d4dbd 100644 --- a/src/coreclr/src/jit/codegenarm.cpp +++ b/src/coreclr/src/jit/codegenarm.cpp @@ -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); diff --git a/src/coreclr/src/jit/codegenarm64.cpp b/src/coreclr/src/jit/codegenarm64.cpp index ec74ba2..7acd311 100644 --- a/src/coreclr/src/jit/codegenarm64.cpp +++ b/src/coreclr/src/jit/codegenarm64.cpp @@ -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; diff --git a/src/coreclr/src/jit/codegenarmarch.cpp b/src/coreclr/src/jit/codegenarmarch.cpp index aeb5c9d..bf822a3 100644 --- a/src/coreclr/src/jit/codegenarmarch.cpp +++ b/src/coreclr/src/jit/codegenarmarch.cpp @@ -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(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(srcAddr->AsLclFld()->gtLclOffs); + srcOffset = srcAddr->AsLclFld()->GetLclOffs(); } } } diff --git a/src/coreclr/src/jit/codegenlinear.cpp b/src/coreclr/src/jit/codegenlinear.cpp index 811cf8f..88e3c69 100644 --- a/src/coreclr/src/jit/codegenlinear.cpp +++ b/src/coreclr/src/jit/codegenlinear.cpp @@ -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); } diff --git a/src/coreclr/src/jit/codegenxarch.cpp b/src/coreclr/src/jit/codegenxarch.cpp index 2303cbe..4a302c6 100644 --- a/src/coreclr/src/jit/codegenxarch.cpp +++ b/src/coreclr/src/jit/codegenxarch.cpp @@ -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(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(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(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(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(); } } diff --git a/src/coreclr/src/jit/compiler.cpp b/src/coreclr/src/jit/compiler.cpp index 2440ada..a7cd81b 100644 --- a/src/coreclr/src/jit/compiler.cpp +++ b/src/coreclr/src/jit/compiler.cpp @@ -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) { diff --git a/src/coreclr/src/jit/compiler.h b/src/coreclr/src/jit/compiler.h index 825697d..60dcacd 100644 --- a/src/coreclr/src/jit/compiler.h +++ b/src/coreclr/src/jit/compiler.h @@ -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); diff --git a/src/coreclr/src/jit/compiler.hpp b/src/coreclr/src/jit/compiler.hpp index 4b53725..eb73160 100644 --- a/src/coreclr/src/jit/compiler.hpp +++ b/src/coreclr/src/jit/compiler.hpp @@ -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); } diff --git a/src/coreclr/src/jit/decomposelongs.cpp b/src/coreclr/src/jit/decomposelongs.cpp index 9d42c0f..8178bd2 100644 --- a/src/coreclr/src/jit/decomposelongs.cpp +++ b/src/coreclr/src/jit/decomposelongs.cpp @@ -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); diff --git a/src/coreclr/src/jit/emitxarch.cpp b/src/coreclr/src/jit/emitxarch.cpp index 9c3a302..33d8592 100644 --- a/src/coreclr/src/jit/emitxarch.cpp +++ b/src/coreclr/src/jit/emitxarch.cpp @@ -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: { diff --git a/src/coreclr/src/jit/gentree.cpp b/src/coreclr/src/jit/gentree.cpp index f767ef7..02fd018e 100644 --- a/src/coreclr/src/jit/gentree.cpp +++ b/src/coreclr/src/jit/gentree.cpp @@ -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(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; } diff --git a/src/coreclr/src/jit/gentree.h b/src/coreclr/src/jit/gentree.h index eadf82b..c88ba80 100644 --- a/src/coreclr/src/jit/gentree.h +++ b/src/coreclr/src/jit/gentree.h @@ -1016,6 +1016,17 @@ public: void dumpLIRFlags(); #endif + bool TypeIs(var_types type) const + { + return gtType == type; + } + + template + 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(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(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(lclOffs); + } + + FieldSeqNode* GetFieldSeq() const + { + return m_fieldSeq; + } + + void SetFieldSeq(FieldSeqNode* fieldSeq) + { + m_fieldSeq = fieldSeq; + } + #if DEBUGGABLE_GENTREE GenTreeLclFld() : GenTreeLclVarCommon() { diff --git a/src/coreclr/src/jit/hwintrinsiccodegenxarch.cpp b/src/coreclr/src/jit/hwintrinsiccodegenxarch.cpp index 66a00fe..2093561 100644 --- a/src/coreclr/src/jit/hwintrinsiccodegenxarch.cpp +++ b/src/coreclr/src/jit/hwintrinsiccodegenxarch.cpp @@ -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: { diff --git a/src/coreclr/src/jit/instr.cpp b/src/coreclr/src/jit/instr.cpp index 8055dc6..eb5ecf8 100644 --- a/src/coreclr/src/jit/instr.cpp +++ b/src/coreclr/src/jit/instr.cpp @@ -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: { diff --git a/src/coreclr/src/jit/lclvars.cpp b/src/coreclr/src/jit/lclvars.cpp index 7de0f86..e76d8ec 100644 --- a/src/coreclr/src/jit/lclvars.cpp +++ b/src/coreclr/src/jit/lclvars.cpp @@ -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 { diff --git a/src/coreclr/src/jit/lower.cpp b/src/coreclr/src/jit/lower.cpp index 6ab876c..f8068a4 100644 --- a/src/coreclr/src/jit/lower.cpp +++ b/src/coreclr/src/jit/lower.cpp @@ -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 { diff --git a/src/coreclr/src/jit/morph.cpp b/src/coreclr/src/jit/morph.cpp index 12791f7..75ceb05 100644 --- a/src/coreclr/src/jit/morph.cpp +++ b/src/coreclr/src/jit/morph.cpp @@ -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(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(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 // 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 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 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 // 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 // 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 if (val.IsAddress()) { - ClrSafeInt newOffset = ClrSafeInt(val.m_offset) + ClrSafeInt(offset); + ClrSafeInt newOffset = + ClrSafeInt(val.m_offset) + ClrSafeInt(field->gtFldOffset); if (newOffset.IsOverflow()) { @@ -17707,6 +17782,15 @@ class LocalAddressVisitor final : public GenTreeVisitor 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 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; diff --git a/src/coreclr/src/jit/rationalize.cpp b/src/coreclr/src/jit/rationalize.cpp index 089d7fb..2c3efd4 100644 --- a/src/coreclr/src/jit/rationalize.cpp +++ b/src/coreclr/src/jit/rationalize.cpp @@ -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); diff --git a/src/coreclr/src/jit/simdcodegenxarch.cpp b/src/coreclr/src/jit/simdcodegenxarch.cpp index 57e0ee9..83d1093 100644 --- a/src/coreclr/src/jit/simdcodegenxarch.cpp +++ b/src/coreclr/src/jit/simdcodegenxarch.cpp @@ -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. diff --git a/src/coreclr/src/jit/valuenum.cpp b/src/coreclr/src/jit/valuenum.cpp index 89e40d7..ea54e23 100644 --- a/src/coreclr/src/jit/valuenum.cpp +++ b/src/coreclr/src/jit/valuenum.cpp @@ -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. -- 2.7.4