From 381c782830ef3bb85a01e8e1233dac9d389b4ff6 Mon Sep 17 00:00:00 2001 From: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com> Date: Thu, 15 Dec 2022 04:57:28 +0300 Subject: [PATCH] Stop producing and handling `ADDR` nodes (#78246) * Start importing local address nodes * Stop producing GT_ADDR nodes * Use LCL_FLDs in MD array import * Delete some ADDR uses * Fix formatting * Work around MSVC not being smart Sigh. --- src/coreclr/jit/codegenlinear.cpp | 2 +- src/coreclr/jit/compiler.h | 9 -- src/coreclr/jit/compiler.hpp | 33 ++++- src/coreclr/jit/fgdiagnostic.cpp | 7 - src/coreclr/jit/flowgraph.cpp | 30 +---- src/coreclr/jit/forwardsub.cpp | 6 +- src/coreclr/jit/gentree.cpp | 197 +++++++--------------------- src/coreclr/jit/gentree.h | 4 +- src/coreclr/jit/gschecks.cpp | 9 -- src/coreclr/jit/hwintrinsic.cpp | 7 +- src/coreclr/jit/importer.cpp | 90 +++++-------- src/coreclr/jit/importercalls.cpp | 41 +++--- src/coreclr/jit/lclmorph.cpp | 123 ++++------------- src/coreclr/jit/lclvars.cpp | 18 --- src/coreclr/jit/lsraarm.cpp | 12 -- src/coreclr/jit/lsraarm64.cpp | 12 -- src/coreclr/jit/lsraloongarch64.cpp | 1 - src/coreclr/jit/lsraxarch.cpp | 13 -- src/coreclr/jit/morph.cpp | 125 ++++-------------- src/coreclr/jit/objectalloc.cpp | 66 +++------- src/coreclr/jit/patchpoint.cpp | 3 +- src/coreclr/jit/rationalize.cpp | 54 -------- src/coreclr/jit/rationalize.h | 1 - src/coreclr/jit/simd.cpp | 83 +++++------- src/coreclr/jit/treelifeupdater.cpp | 22 ---- src/coreclr/jit/valuenum.cpp | 20 --- 26 files changed, 245 insertions(+), 743 deletions(-) diff --git a/src/coreclr/jit/codegenlinear.cpp b/src/coreclr/jit/codegenlinear.cpp index 7fdbe014806031..d7f3c66dbe6b2e 100644 --- a/src/coreclr/jit/codegenlinear.cpp +++ b/src/coreclr/jit/codegenlinear.cpp @@ -1781,7 +1781,7 @@ void CodeGen::genConsumePutStructArgStk(GenTreePutArgStk* putArgNode, } // If the op1 is already in the dstReg - nothing to do. - // Otherwise load the op1 (GT_ADDR) into the dstReg to copy the struct on the stack by value. + // Otherwise load the op1 (the address) into the dstReg to copy the struct on the stack by value. CLANG_FORMAT_COMMENT_ANCHOR; #ifdef TARGET_X86 diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 6602b1a64dcf5e..bcc470f9ae74df 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -8517,14 +8517,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX (structHandle != m_simdHandleCache->SIMDVector4Handle)); } - // Returns true if the tree corresponds to a TYP_SIMD lcl var. - // Note that both SIMD vector args and locals are mared as lvSIMDType = true, but - // type of an arg node is TYP_BYREF and a local node is TYP_SIMD or TYP_STRUCT. - bool isSIMDTypeLocal(GenTree* tree) - { - return tree->OperIsLocal() && lvaGetDesc(tree->AsLclVarCommon())->lvSIMDType; - } - // Returns true if the lclVar is an opaque SIMD type. bool isOpaqueSIMDLclVar(const LclVarDsc* varDsc) const { @@ -10821,7 +10813,6 @@ class GenTreeVisitor case GT_BITCAST: case GT_CKFINITE: case GT_LCLHEAP: - case GT_ADDR: case GT_IND: case GT_OBJ: case GT_BLK: diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index 94d2223fe8d94d..946866d63c888f 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -846,14 +846,34 @@ inline GenTree* Compiler::gtNewOperNode(genTreeOps oper, var_types type, GenTree if (oper == GT_ADDR) { - if (op1->OperIsIndir()) + switch (op1->OperGet()) { - assert(op1->IsValue()); - return op1->AsIndir()->Addr(); - } + case GT_LCL_VAR: + return gtNewLclVarAddrNode(op1->AsLclVar()->GetLclNum(), type); + + case GT_LCL_FLD: + return gtNewLclFldAddrNode(op1->AsLclFld()->GetLclNum(), op1->AsLclFld()->GetLclOffs(), type); + + case GT_BLK: + case GT_OBJ: + case GT_IND: + return op1->AsIndir()->Addr(); + + case GT_FIELD: + { + GenTreeField* fieldAddr = + new (this, GT_FIELD_ADDR) GenTreeField(GT_FIELD_ADDR, type, op1->AsField()->GetFldObj(), + op1->AsField()->gtFldHnd, op1->AsField()->gtFldOffset); + fieldAddr->gtFldMayOverlap = op1->AsField()->gtFldMayOverlap; +#ifdef FEATURE_READYTORUN + fieldAddr->gtFieldLookup = op1->AsField()->gtFieldLookup; +#endif + return fieldAddr; + } - assert(op1->OperIsLocalRead() || op1->OperIs(GT_FIELD)); - op1->SetDoNotCSE(); + default: + unreached(); + } } GenTree* node = new (this, oper) GenTreeOp(oper, type, op1, nullptr); @@ -4082,7 +4102,6 @@ void GenTree::VisitOperands(TVisitor visitor) case GT_BITCAST: case GT_CKFINITE: case GT_LCLHEAP: - case GT_ADDR: case GT_IND: case GT_OBJ: case GT_BLK: diff --git a/src/coreclr/jit/fgdiagnostic.cpp b/src/coreclr/jit/fgdiagnostic.cpp index 4b5c7d709b2476..f9b40c7dd6d635 100644 --- a/src/coreclr/jit/fgdiagnostic.cpp +++ b/src/coreclr/jit/fgdiagnostic.cpp @@ -3057,7 +3057,6 @@ void Compiler::fgDebugCheckFlags(GenTree* tree) break; case GT_ASG: - case GT_ADDR: // Note that this is a weak check - the "op1" location node can be a COMMA. assert(!op1->CanCSE()); break; @@ -3151,12 +3150,6 @@ void Compiler::fgDebugCheckFlags(GenTree* tree) return GenTree::VisitResult::Continue; }); - // Addresses of locals never need GTF_GLOB_REF - if (tree->OperIs(GT_ADDR) && tree->IsLocalAddrExpr()) - { - expectedFlags &= ~GTF_GLOB_REF; - } - fgDebugCheckFlagsHelper(tree, actualFlags, expectedFlags); } diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 2ad1f508f78c8b..5c02a6acb3bab2 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -742,7 +742,6 @@ bool Compiler::fgIsCommaThrow(GenTree* tree, bool forFolding /* = false */) // // Return Value: // If "tree" is a indirection (GT_IND, GT_BLK, or GT_OBJ) whose arg is: -// - an ADDR, whose arg in turn is a LCL_VAR, return that LCL_VAR node; // - a LCL_VAR_ADDR, return that LCL_VAR_ADDR; // - else nullptr. // @@ -750,23 +749,11 @@ bool Compiler::fgIsCommaThrow(GenTree* tree, bool forFolding /* = false */) GenTreeLclVar* Compiler::fgIsIndirOfAddrOfLocal(GenTree* tree) { GenTreeLclVar* res = nullptr; - if (tree->OperIsIndir()) + if (tree->OperIsIndir() && tree->AsIndir()->Addr()->OperIs(GT_LCL_VAR_ADDR)) { - GenTree* addr = tree->AsIndir()->Addr(); - - if (addr->OperGet() == GT_ADDR) - { - GenTree* lclvar = addr->AsOp()->gtOp1; - if (lclvar->OperGet() == GT_LCL_VAR) - { - res = lclvar->AsLclVar(); - } - } - else if (addr->OperGet() == GT_LCL_VAR_ADDR) - { - res = addr->AsLclVar(); - } + res = tree->AsIndir()->Addr()->AsLclVar(); } + return res; } @@ -932,14 +919,10 @@ bool Compiler::fgAddrCouldBeNull(GenTree* addr) return !addr->IsIconHandle(); case GT_CNS_STR: - case GT_ADDR: case GT_FIELD_ADDR: case GT_LCL_VAR_ADDR: case GT_LCL_FLD_ADDR: case GT_CLS_VAR_ADDR: - // A GT_ADDR node, by itself, never requires null checking. The expression whose address is being - // taken is either a local or static variable, whose address is necessarily non-null, or else it is - // a field dereference, which will do its own bounds checking if necessary. return false; case GT_IND: @@ -1842,8 +1825,7 @@ GenTree* Compiler::fgCreateMonitorTree(unsigned lvaMonAcquired, unsigned lvaThis { // Insert the expression "enter/exitCrit(this, &acquired)" or "enter/exitCrit(handle, &acquired)" - GenTree* varNode = gtNewLclvNode(lvaMonAcquired, lvaGetDesc(lvaMonAcquired)->TypeGet()); - GenTree* varAddrNode = gtNewOperNode(GT_ADDR, TYP_BYREF, varNode); + GenTree* varAddrNode = gtNewLclVarAddrNode(lvaMonAcquired); GenTree* tree; if (info.compIsStatic) @@ -1978,7 +1960,7 @@ void Compiler::fgAddReversePInvokeEnterExit() // Add enter pinvoke exit callout at the start of prolog - GenTree* pInvokeFrameVar = gtNewOperNode(GT_ADDR, TYP_I_IMPL, gtNewLclvNode(lvaReversePInvokeFrameVar, TYP_BLK)); + GenTree* pInvokeFrameVar = gtNewLclVarAddrNode(lvaReversePInvokeFrameVar); GenTree* tree; @@ -2021,7 +2003,7 @@ void Compiler::fgAddReversePInvokeEnterExit() // Add reverse pinvoke exit callout at the end of epilog - tree = gtNewOperNode(GT_ADDR, TYP_I_IMPL, gtNewLclvNode(lvaReversePInvokeFrameVar, TYP_BLK)); + tree = gtNewLclVarAddrNode(lvaReversePInvokeFrameVar); CorInfoHelpFunc reversePInvokeExitHelper = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_TRACK_TRANSITIONS) ? CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT_TRACK_TRANSITIONS diff --git a/src/coreclr/jit/forwardsub.cpp b/src/coreclr/jit/forwardsub.cpp index d498c2291ca108..c0ce278cc34a79 100644 --- a/src/coreclr/jit/forwardsub.cpp +++ b/src/coreclr/jit/forwardsub.cpp @@ -222,21 +222,19 @@ class ForwardSubVisitor final : public GenTreeVisitor // Screen out contextual "uses" // GenTree* const parent = user; - bool const isAddr = parent->OperIs(GT_ADDR); - - bool isCallTarget = false; // Quirk: // // fgGetStubAddrArg cannot handle complex trees (it calls gtClone) // + bool isCallTarget = false; if (parent->IsCall()) { GenTreeCall* const parentCall = parent->AsCall(); isCallTarget = (parentCall->gtCallType == CT_INDIRECT) && (parentCall->gtCallAddr == node); } - if (!isDef && !isAddr && !isCallTarget) + if (!isDef && !isCallTarget) { m_node = node; m_use = use; diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 4a6ec38d80fb81..41f60a4301bb87 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -2728,14 +2728,11 @@ bool GenTree::Compare(GenTree* op1, GenTree* op2, bool swapOK) // gtHasRef: Find out whether the given tree contains a local. // // Arguments: -// tree - tree to find the local in -// lclNum - the local's number +// tree - tree to find the local in +// lclNum - the local's number // // Return Value: -// Whether "tree" has any LCL_VAR/LCL_FLD nodes that refer to the local. -// -// Notes: -// Does not pay attention to local address nodes. +// Whether "tree" has any local nodes that refer to the local. // /* static */ bool Compiler::gtHasRef(GenTree* tree, unsigned lclNum) { @@ -2746,7 +2743,7 @@ bool GenTree::Compare(GenTree* op1, GenTree* op2, bool swapOK) if (tree->OperIsLeaf()) { - if (tree->OperIs(GT_LCL_VAR, GT_LCL_FLD) && (tree->AsLclVarCommon()->GetLclNum() == lclNum)) + if ((tree->OperIsLocal() || tree->OperIsLocalAddr()) && (tree->AsLclVarCommon()->GetLclNum() == lclNum)) { return true; } @@ -5021,18 +5018,6 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree) level++; break; - case GT_ADDR: - if (op1->OperIsLocalRead()) - { - costEx = 3; - costSz = 3; - goto DONE; - } - - costEx = 0; - costSz = 1; - break; - case GT_ARR_LENGTH: case GT_MDARR_LENGTH: case GT_MDARR_LOWER_BOUND: @@ -5348,16 +5333,7 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree) bool bReverseInAssignment = false; if (oper == GT_ASG && (!optValnumCSE_phase || optCSE_canSwap(op1, op2))) { - GenTree* op1Val = op1; - - // Skip over the GT_IND/GT_ADDR tree (if one exists) - // - if ((op1->gtOper == GT_IND) && (op1->AsOp()->gtOp1->gtOper == GT_ADDR)) - { - op1Val = op1->AsOp()->gtOp1->AsOp()->gtOp1; - } - - switch (op1Val->gtOper) + switch (op1->OperGet()) { case GT_IND: case GT_BLK: @@ -5368,12 +5344,9 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree) // itself. As such, we can discard any side effects "induced" by it in // this logic. // - // Note that for local "addr"s, liveness depends on seeing the defs and - // uses in correct order, and so we MUST reverse the ASG in that case. - // GenTree* op1Addr = op1->AsIndir()->Addr(); - if (op1Addr->IsLocalAddrExpr() || op1Addr->IsInvariant()) + if (op1Addr->IsInvariant()) { bReverseInAssignment = true; tree->gtFlags |= GTF_REVERSE_OPS; @@ -5384,14 +5357,13 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree) break; } - // In case op2 assigns to a local var that is used in op1Val, we have to evaluate op1Val first. + // In case op2 assigns to a local var that is used in op1, we have to evaluate op1 first. if (op2->gtFlags & GTF_ASG) { break; } // If op2 is simple then evaluate op1 first - if (op2->OperKind() & GTK_LEAF) { break; @@ -5402,8 +5374,8 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree) case GT_LCL_VAR: case GT_LCL_FLD: - - // We evaluate op2 before op1 + // Note that for local stores, liveness depends on seeing the defs and + // uses in correct order, and so we MUST reverse the ASG in that case. bReverseInAssignment = true; tree->gtFlags |= GTF_REVERSE_OPS; break; @@ -6069,7 +6041,6 @@ bool GenTree::TryGetUse(GenTree* operand, GenTree*** pUse) case GT_BITCAST: case GT_CKFINITE: case GT_LCLHEAP: - case GT_ADDR: case GT_IND: case GT_OBJ: case GT_BLK: @@ -7564,10 +7535,9 @@ GenTreeField* Compiler::gtNewFieldRef(var_types type, CORINFO_FIELD_HANDLE fldHn GenTreeField* fieldNode = new (this, GT_FIELD) GenTreeField(GT_FIELD, type, obj, fldHnd, offset); // If "obj" is the address of a local, note that a field of that struct local has been accessed. - if ((obj != nullptr) && obj->OperIs(GT_ADDR) && varTypeIsStruct(obj->AsUnOp()->gtOp1) && - obj->AsUnOp()->gtOp1->OperIs(GT_LCL_VAR)) + if ((obj != nullptr) && obj->OperIs(GT_LCL_VAR_ADDR)) { - LclVarDsc* varDsc = lvaGetDesc(obj->AsUnOp()->gtOp1->AsLclVarCommon()); + LclVarDsc* varDsc = lvaGetDesc(obj->AsLclVarCommon()); varDsc->lvFieldAccessed = 1; @@ -7612,10 +7582,9 @@ GenTreeField* Compiler::gtNewFieldAddrNode(var_types type, CORINFO_FIELD_HANDLE GenTreeField* fieldNode = new (this, GT_FIELD_ADDR) GenTreeField(GT_FIELD_ADDR, type, obj, fldHnd, offset); // If "obj" is the address of a local, note that a field of that struct local has been accessed. - if ((obj != nullptr) && obj->OperIs(GT_ADDR) && varTypeIsStruct(obj->AsUnOp()->gtOp1) && - obj->AsUnOp()->gtOp1->OperIs(GT_LCL_VAR)) + if ((obj != nullptr) && obj->OperIs(GT_LCL_VAR_ADDR)) { - LclVarDsc* varDsc = lvaGetDesc(obj->AsUnOp()->gtOp1->AsLclVarCommon()); + LclVarDsc* varDsc = lvaGetDesc(obj->AsLclVarCommon()); varDsc->lvFieldAccessed = 1; @@ -7762,18 +7731,14 @@ void Compiler::gtSetObjGcInfo(GenTreeObj* objNode) // GenTree* Compiler::gtNewStructVal(ClassLayout* layout, GenTree* addr) { - if (addr->OperIs(GT_ADDR)) + if (addr->OperIs(GT_LCL_VAR_ADDR)) { - GenTree* location = addr->gtGetOp1(); - if (location->OperIs(GT_LCL_VAR)) + unsigned lclNum = addr->AsLclVar()->GetLclNum(); + LclVarDsc* varDsc = lvaGetDesc(lclNum); + if (!lvaIsImplicitByRefLocal(lclNum) && varTypeIsStruct(varDsc) && + ClassLayout::AreCompatible(layout, varDsc->GetLayout())) { - unsigned lclNum = location->AsLclVar()->GetLclNum(); - LclVarDsc* varDsc = lvaGetDesc(lclNum); - if (!lvaIsImplicitByRefLocal(lclNum) && varTypeIsStruct(varDsc) && - ClassLayout::AreCompatible(layout, varDsc->GetLayout())) - { - return location; - } + return gtNewLclvNode(lclNum, varDsc->TypeGet()); } } @@ -8073,16 +8038,7 @@ GenTree* Compiler::gtNewBlkOpNode(GenTree* dst, GenTree* srcOrFillVal, bool isVo GenTree* currSrc = srcOrFillVal; GenTree* currDst = dst; - if (currSrc->OperIsBlk() && (currSrc->AsBlk()->Addr()->OperGet() == GT_ADDR)) - { - currSrc = currSrc->AsBlk()->Addr()->gtGetOp1(); - } - if (currDst->OperIsBlk() && (currDst->AsBlk()->Addr()->OperGet() == GT_ADDR)) - { - currDst = currDst->AsBlk()->Addr()->gtGetOp1(); - } - - if (currSrc->OperGet() == GT_LCL_VAR && currDst->OperGet() == GT_LCL_VAR && + if (currSrc->OperIs(GT_LCL_VAR) && currDst->OperIs(GT_LCL_VAR) && currSrc->AsLclVarCommon()->GetLclNum() == currDst->AsLclVarCommon()->GetLclNum()) { result->gtBashToNOP(); // Make this a NOP. @@ -8104,14 +8060,19 @@ GenTree* Compiler::gtNewBlkOpNode(GenTree* dst, GenTree* srcOrFillVal, bool isVo { // TODO-Cleanup: similar logic already exists in "gtNewAssignNode", // however, it is not enabled for x86. Fix that and delete this code. - if (dst->OperIsBlk() && (dst->AsIndir()->Addr()->OperGet() == GT_ADDR)) + GenTreeLclVar* dstLclNode = nullptr; + if (dst->OperIs(GT_LCL_VAR)) { - dst = dst->AsIndir()->Addr()->gtGetOp1(); + dstLclNode = dst->AsLclVar(); + } + else if (dst->OperIsBlk() && dst->AsIndir()->Addr()->OperIs(GT_LCL_VAR_ADDR)) + { + dstLclNode = dst->AsIndir()->Addr()->AsLclVar(); } - if (dst->OperIsLocal() && varTypeIsStruct(dst)) + if ((dstLclNode != nullptr) && varTypeIsStruct(lvaGetDesc(dstLclNode))) { - setLclRelatedToSIMDIntrinsic(dst); + setLclRelatedToSIMDIntrinsic(dstLclNode); } } #endif // FEATURE_SIMD @@ -8312,9 +8273,16 @@ GenTree* Compiler::gtClone(GenTree* tree, bool complexOK) break; } + case GT_LCL_VAR_ADDR: + if (!complexOK) + { + return nullptr; + } + FALLTHROUGH; + case GT_LCL_VAR: - copy = gtNewLclvNode(tree->AsLclVarCommon()->GetLclNum(), - tree->TypeGet() DEBUGARG(tree->AsLclVar()->gtLclILoffs)); + copy = new (this, tree->OperGet()) + GenTreeLclVar(tree->OperGet(), tree->TypeGet(), tree->AsLclVar()->GetLclNum()); goto FINISH_CLONING_LCL_NODE; case GT_LCL_FLD: @@ -8381,15 +8349,6 @@ GenTree* Compiler::gtClone(GenTree* tree, bool complexOK) return nullptr; } } - else if (tree->gtOper == GT_ADDR) - { - GenTree* op1 = gtClone(tree->AsOp()->gtOp1); - if (op1 == nullptr) - { - return nullptr; - } - copy = gtNewOperNode(GT_ADDR, tree->TypeGet(), op1); - } else { return nullptr; @@ -9469,7 +9428,6 @@ GenTreeUseEdgeIterator::GenTreeUseEdgeIterator(GenTree* node) case GT_BITCAST: case GT_CKFINITE: case GT_LCLHEAP: - case GT_ADDR: case GT_IND: case GT_OBJ: case GT_BLK: @@ -14130,18 +14088,16 @@ GenTree* Compiler::gtTryRemoveBoxUpstreamEffects(GenTree* op, BoxRemovalOptions lvaTable[boxTempLcl].lvType = TYP_UNDEF; const bool isUnsafeValueClass = false; lvaSetStruct(boxTempLcl, boxClass, isUnsafeValueClass); - var_types boxTempType = lvaTable[boxTempLcl].lvType; // Remove the newobj and assignment to box temp JITDUMP("Bashing NEWOBJ [%06u] to NOP\n", dspTreeID(asg)); asg->gtBashToNOP(); // Update the copy from the value to be boxed to the box temp - GenTree* newDst = gtNewOperNode(GT_ADDR, TYP_BYREF, gtNewLclvNode(boxTempLcl, boxTempType)); - copyDst->AsOp()->gtOp1 = newDst; + copyDst->AsOp()->gtOp1 = gtNewLclVarAddrNode(boxTempLcl, TYP_BYREF); // Return the address of the now-struct typed box temp - GenTree* retValue = gtNewOperNode(GT_ADDR, TYP_BYREF, gtNewLclvNode(boxTempLcl, boxTempType)); + GenTree* retValue = gtNewLclVarAddrNode(boxTempLcl, TYP_BYREF); return retValue; } @@ -16169,18 +16125,6 @@ void Compiler::gtExtractSideEffList(GenTree* expr, return Compiler::WALK_SKIP_SUBTREES; } - if ((m_flags & GTF_EXCEPT) != 0) - { - // Special case - GT_ADDR of GT_IND nodes of TYP_STRUCT have to be kept together. - if (node->OperIs(GT_ADDR) && node->gtGetOp1()->OperIsIndir() && - (node->gtGetOp1()->TypeGet() == TYP_STRUCT)) - { - JITDUMP("Keep the GT_ADDR and GT_IND together:\n"); - PushSideEffects(node); - return Compiler::WALK_SKIP_SUBTREES; - } - } - // Generally all GT_CALL nodes are considered to have side-effects. // So if we get here it must be a helper call that we decided it does // not have side effects that we needed to keep. @@ -16804,28 +16748,18 @@ bool GenTree::DefinesLocal( // bool GenTree::DefinesLocalAddr(GenTreeLclVarCommon** pLclVarTree, ssize_t* pOffset) { - if (OperIs(GT_ADDR) || OperIsLocalAddr()) + if (OperIsLocalAddr()) { - GenTree* lclNode = this; - if (OperGet() == GT_ADDR) - { - lclNode = AsOp()->gtOp1; - } + *pLclVarTree = AsLclVarCommon(); - if (lclNode->IsLocal() || lclNode->OperIsLocalAddr()) + if (pOffset != nullptr) { - *pLclVarTree = lclNode->AsLclVarCommon(); - - if (pOffset != nullptr) - { - *pOffset += lclNode->AsLclVarCommon()->GetLclOffs(); - } - - return true; + *pOffset += AsLclVarCommon()->GetLclOffs(); } + + return true; } - // Otherwise... return false; } @@ -16834,17 +16768,7 @@ bool GenTree::DefinesLocalAddr(GenTreeLclVarCommon** pLclVarTree, ssize_t* pOffs const GenTreeLclVarCommon* GenTree::IsLocalAddrExpr() const { - if (OperGet() == GT_ADDR) - { - return AsOp()->gtOp1->IsLocal() ? AsOp()->gtOp1->AsLclVarCommon() : nullptr; - } - else if (OperIsLocalAddr()) - { - return this->AsLclVarCommon(); - } - - // Otherwise... - return nullptr; + return OperIsLocalAddr() ? AsLclVarCommon() : nullptr; } //------------------------------------------------------------------------ @@ -16871,19 +16795,10 @@ GenTreeLclVar* GenTree::IsImplicitByrefParameterValue(Compiler* compiler) { GenTree* addr = AsIndir()->Addr(); - if (addr->OperIs(GT_LCL_VAR)) + if (addr->OperIs(GT_LCL_VAR, GT_LCL_VAR_ADDR)) { lcl = addr->AsLclVar(); } - else if (addr->OperIs(GT_ADDR)) - { - GenTree* base = addr->AsOp()->gtOp1; - - if (base->OperIs(GT_LCL_VAR)) - { - lcl = base->AsLclVar(); - } - } } if ((lcl != nullptr) && compiler->lvaIsImplicitByRefLocal(lcl->GetLclNum())) @@ -18700,23 +18615,13 @@ void Compiler::SetOpLclRelatedToSIMDIntrinsic(GenTree* op) return; } - if (op->OperIsLocal()) + if (op->OperIs(GT_LCL_VAR)) { setLclRelatedToSIMDIntrinsic(op); } - else if (op->OperIs(GT_OBJ)) + else if (op->OperIs(GT_OBJ) && op->AsIndir()->Addr()->OperIs(GT_LCL_VAR_ADDR)) { - GenTree* addr = op->AsIndir()->Addr(); - - if (addr->OperIs(GT_ADDR)) - { - GenTree* addrOp1 = addr->AsOp()->gtGetOp1(); - - if (addrOp1->OperIsLocal()) - { - setLclRelatedToSIMDIntrinsic(addrOp1); - } - } + setLclRelatedToSIMDIntrinsic(op->AsIndir()->Addr()); } } diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 5a024a30f4f64b..71cb998eb58783 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -1554,7 +1554,9 @@ struct GenTree // OperIsIndir() returns true also for indirection nodes such as GT_BLK, etc. as well as GT_NULLCHECK. static bool OperIsIndir(genTreeOps gtOper) { - return gtOper == GT_IND || gtOper == GT_STOREIND || gtOper == GT_NULLCHECK || OperIsBlk(gtOper); + static_assert_no_msg(AreContiguous(GT_IND, GT_STOREIND, GT_OBJ, GT_STORE_OBJ, GT_BLK, GT_STORE_BLK, + GT_STORE_DYN_BLK, GT_NULLCHECK)); + return (GT_IND <= gtOper) && (gtOper <= GT_NULLCHECK); } static bool OperIsArrLength(genTreeOps gtOper) diff --git a/src/coreclr/jit/gschecks.cpp b/src/coreclr/jit/gschecks.cpp index 76d53096ceb7b0..05d06ed112036e 100644 --- a/src/coreclr/jit/gschecks.cpp +++ b/src/coreclr/jit/gschecks.cpp @@ -270,15 +270,6 @@ Compiler::fgWalkResult Compiler::gsMarkPtrsAndAssignGroups(GenTree** pTree, fgWa } return WALK_SKIP_SUBTREES; - case GT_ADDR: - newState.isUnderIndir = false; - // We'll assume p in "**p = " can be vulnerable because by changing 'p', someone - // could control where **p stores to. - { - comp->fgWalkTreePre(&tree->AsOp()->gtOp1, comp->gsMarkPtrsAndAssignGroups, (void*)&newState); - } - return WALK_SKIP_SUBTREES; - case GT_ASG: { GenTreeOp* asg = tree->AsOp(); diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp index cb7c69d82793f5..eccb6d1bf792e3 100644 --- a/src/coreclr/jit/hwintrinsic.cpp +++ b/src/coreclr/jit/hwintrinsic.cpp @@ -546,12 +546,13 @@ GenTree* Compiler::getArgForHWIntrinsic(var_types argType, } else { - assert((newobjThis->gtOper == GT_ADDR) && (newobjThis->AsOp()->gtOp1->gtOper == GT_LCL_VAR)); + assert(newobjThis->OperIs(GT_LCL_VAR_ADDR)); arg = newobjThis; // push newobj result on type stack - unsigned tmp = arg->AsOp()->gtOp1->AsLclVarCommon()->GetLclNum(); - impPushOnStack(gtNewLclvNode(tmp, lvaGetRealType(tmp)), verMakeTypeInfo(argClass).NormaliseForStack()); + unsigned lclNum = arg->AsLclVarCommon()->GetLclNum(); + impPushOnStack(gtNewLclvNode(lclNum, lvaGetRealType(lclNum)), + verMakeTypeInfo(argClass).NormaliseForStack()); } } else diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 074510b2d77256..cd021ab658977e 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -1199,30 +1199,20 @@ GenTree* Compiler::impGetStructAddr(GenTree* structVal, { assert(varTypeIsStruct(structVal) || eeIsValueClass(structHnd)); - var_types type = structVal->TypeGet(); - + var_types type = structVal->TypeGet(); genTreeOps oper = structVal->gtOper; - if (oper == GT_OBJ && willDeref) - { - assert(structVal->AsObj()->GetLayout()->GetClassHandle() == structHnd); - return (structVal->AsObj()->Addr()); - } - else if (oper == GT_CALL || oper == GT_RET_EXPR || oper == GT_OBJ || oper == GT_MKREFANY || - structVal->OperIsSimdOrHWintrinsic() || structVal->IsCnsVec()) + if (oper == GT_CALL || oper == GT_RET_EXPR || (oper == GT_OBJ && !willDeref) || oper == GT_MKREFANY || + structVal->OperIsSimdOrHWintrinsic() || structVal->IsCnsVec()) { unsigned tmpNum = lvaGrabTemp(true DEBUGARG("struct address for call/obj")); impAssignTempGen(tmpNum, structVal, structHnd, curLevel); - // The 'return value' is now the temp itself - - type = genActualType(lvaTable[tmpNum].TypeGet()); - GenTree* temp = gtNewLclvNode(tmpNum, type); - temp = gtNewOperNode(GT_ADDR, TYP_BYREF, temp); - return temp; + // The 'return value' is now address of the temp itself. + return gtNewLclVarAddrNode(tmpNum, TYP_BYREF); } - else if (oper == GT_COMMA) + if (oper == GT_COMMA) { assert(structVal->AsOp()->gtOp2->gtType == type); // Second thing is the struct @@ -1255,7 +1245,7 @@ GenTree* Compiler::impGetStructAddr(GenTree* structVal, return (structVal); } - return (gtNewOperNode(GT_ADDR, TYP_BYREF, structVal)); + return gtNewOperNode(GT_ADDR, TYP_BYREF, structVal); } //------------------------------------------------------------------------ @@ -2155,7 +2145,7 @@ void Compiler::impSpillSideEffect(bool spillGlobEffects, unsigned i DEBUGARG(con if ((tree->gtFlags & spillFlags) != 0 || (spillGlobEffects && // Only consider the following when spillGlobEffects == true - !impIsAddressInLocal(tree) && // No need to spill the GT_ADDR node on a local. + !impIsAddressInLocal(tree) && // No need to spill the LCL_ADDR nodes. gtHasLocalsWithAddrOp(tree))) // Spill if we still see GT_LCL_VAR that contains lvHasLdAddrOp or // lvAddrTaken flag. { @@ -3871,22 +3861,15 @@ void Compiler::impImportNewObjArray(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORI // - Pointer to block of int32 dimensions: address of lvaNewObjArrayArgs temp. // - node = gtNewLclvNode(lvaNewObjArrayArgs, TYP_BLK); - node = gtNewOperNode(GT_ADDR, TYP_I_IMPL, node); + node = gtNewLclVarAddrNode(lvaNewObjArrayArgs); // Pop dimension arguments from the stack one at a time and store it // into lvaNewObjArrayArgs temp. for (int i = pCallInfo->sig.numArgs - 1; i >= 0; i--) { - GenTree* arg = impImplicitIorI4Cast(impPopStack().val, TYP_INT); - - GenTree* dest = gtNewLclvNode(lvaNewObjArrayArgs, TYP_BLK); - dest = gtNewOperNode(GT_ADDR, TYP_I_IMPL, dest); - dest = gtNewOperNode(GT_ADD, TYP_I_IMPL, dest, - new (this, GT_CNS_INT) GenTreeIntCon(TYP_I_IMPL, sizeof(INT32) * i)); - dest = gtNewOperNode(GT_IND, TYP_INT, dest); - - node = gtNewOperNode(GT_COMMA, node->TypeGet(), gtNewAssignNode(dest, arg), node); + GenTree* arg = impImplicitIorI4Cast(impPopStack().val, TYP_INT); + GenTree* dest = gtNewLclFldNode(lvaNewObjArrayArgs, TYP_INT, sizeof(INT32) * i); + node = gtNewOperNode(GT_COMMA, node->TypeGet(), gtNewAssignNode(dest, arg), node); } node = @@ -6953,8 +6936,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) lclNum = impInlineFetchLocal(lclNum DEBUGARG("Inline ldloca(s) first use temp")); assert(!lvaGetDesc(lclNum)->lvNormalizeOnLoad()); - op1 = gtNewLclvNode(lclNum, lvaGetActualType(lclNum)); - + op1 = gtNewLclVarAddrNode(lclNum, TYP_BYREF); goto _PUSH_ADRVAR; } @@ -6984,8 +6966,8 @@ void Compiler::impImportBlockCode(BasicBlock* block) return; } - assert(op1->gtOper == GT_LCL_VAR); - + op1->ChangeType(TYP_BYREF); + op1->SetOper(GT_LCL_VAR_ADDR); goto _PUSH_ADRVAR; } @@ -7000,22 +6982,17 @@ void Compiler::impImportBlockCode(BasicBlock* block) goto ADRVAR; ADRVAR: - - op1 = impCreateLocalNode(lclNum DEBUGARG(opcodeOffs + sz + 1)); + // Note that this is supposed to create the transient type "*" + // which may be used as a TYP_I_IMPL. However we catch places + // where it is used as a TYP_I_IMPL and change the node if needed. + // Thus we are pessimistic and may report byrefs in the GC info + // where it was not absolutely needed, but doing otherwise would + // require careful rethinking of the importer routines which use + // the IL validity model (e. g. "impGetByRefResultType"). + op1 = gtNewLclVarAddrNode(lclNum, TYP_BYREF); _PUSH_ADRVAR: - assert(op1->gtOper == GT_LCL_VAR); - - /* Note that this is supposed to create the transient type "*" - which may be used as a TYP_I_IMPL. However we catch places - where it is used as a TYP_I_IMPL and change the node if needed. - Thus we are pessimistic and may report byrefs in the GC info - where it was not absolutely needed, but it is safer this way. - */ - op1 = gtNewOperNode(GT_ADDR, TYP_BYREF, op1); - - // &aliasedVar doesnt need GTF_GLOB_REF, though alisasedVar does - assert((op1->gtFlags & GTF_GLOB_REF) == 0); + assert(op1->OperIs(GT_LCL_VAR_ADDR)); tiRetVal = typeInfo(TI_BYTE).MakeByRef(); impPushOnStack(op1, tiRetVal); @@ -7030,12 +7007,10 @@ void Compiler::impImportBlockCode(BasicBlock* block) assertImp((info.compMethodInfo->args.callConv & CORINFO_CALLCONV_MASK) == CORINFO_CALLCONV_VARARG); - /* The ARGLIST cookie is a hidden 'last' parameter, we have already - adjusted the arg count cos this is like fetching the last param */ - assertImp(0 < numArgs); - lclNum = lvaVarargsHandleArg; - op1 = gtNewLclvNode(lclNum, TYP_I_IMPL DEBUGARG(opcodeOffs + sz + 1)); - op1 = gtNewOperNode(GT_ADDR, TYP_BYREF, op1); + // The ARGLIST cookie is a hidden 'last' parameter, we have already + // adjusted the arg count cos this is like fetching the last param. + assertImp(numArgs > 0); + op1 = gtNewLclVarAddrNode(lvaVarargsHandleArg, TYP_BYREF); impPushOnStack(op1, tiRetVal); break; @@ -8975,8 +8950,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) lclDsc->lvHasLdAddrOp = true; // Obtain the address of the temp - newObjThisPtr = - gtNewOperNode(GT_ADDR, TYP_BYREF, gtNewLclvNode(lclNum, lvaTable[lclNum].TypeGet())); + newObjThisPtr = gtNewLclVarAddrNode(lclNum, TYP_BYREF); } else { @@ -12737,11 +12711,11 @@ bool Compiler::impIsAddressInLocal(const GenTree* tree, GenTree** lclVarTreeOut) op = op->AsField()->GetFldObj(); } - if (op->OperIs(GT_ADDR) && op->AsUnOp()->gtOp1->OperIs(GT_LCL_VAR)) + if (op->OperIs(GT_LCL_VAR_ADDR)) { if (lclVarTreeOut != nullptr) { - *lclVarTreeOut = op->AsUnOp()->gtOp1; + *lclVarTreeOut = const_cast(op); } return true; @@ -13124,7 +13098,7 @@ void Compiler::impInlineRecordArgInfo(InlineInfo* pInlineInfo, { LclVarDsc* varDsc = lvaGetDesc(lclVarTree->AsLclVarCommon()); - if (varTypeIsStruct(lclVarTree)) + if (varTypeIsStruct(varDsc)) { inlCurArgInfo->argIsByRefToStructLocal = true; #ifdef FEATURE_SIMD diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 3504e04d5025a5..3fddff3e163314 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -1036,10 +1036,11 @@ var_types Compiler::impImportCall(OPCODE opcode, if (clsFlags & CORINFO_FLG_VALUECLASS) { - assert(newobjThis->gtOper == GT_ADDR && newobjThis->AsOp()->gtOp1->gtOper == GT_LCL_VAR); + assert(newobjThis->OperIs(GT_LCL_VAR_ADDR)); - unsigned tmp = newobjThis->AsOp()->gtOp1->AsLclVarCommon()->GetLclNum(); - impPushOnStack(gtNewLclvNode(tmp, lvaGetRealType(tmp)), verMakeTypeInfo(clsHnd).NormaliseForStack()); + unsigned lclNum = newobjThis->AsLclVarCommon()->GetLclNum(); + impPushOnStack(gtNewLclvNode(lclNum, lvaGetRealType(lclNum)), + verMakeTypeInfo(clsHnd).NormaliseForStack()); } else { @@ -1992,21 +1993,13 @@ GenTree* Compiler::impInitializeArrayIntrinsic(CORINFO_SIG_INFO* sig) { static bool IsArgsFieldInit(GenTree* tree, unsigned index, unsigned lvaNewObjArrayArgs) { - return (tree->OperGet() == GT_ASG) && IsArgsFieldIndir(tree->gtGetOp1(), index, lvaNewObjArrayArgs) && - IsArgsAddr(tree->gtGetOp1()->gtGetOp1()->gtGetOp1(), lvaNewObjArrayArgs); + return tree->OperIs(GT_ASG) && IsArgsField(tree->gtGetOp1(), index, lvaNewObjArrayArgs); } - static bool IsArgsFieldIndir(GenTree* tree, unsigned index, unsigned lvaNewObjArrayArgs) + static bool IsArgsField(GenTree* tree, unsigned index, unsigned lvaNewObjArrayArgs) { - return (tree->OperGet() == GT_IND) && (tree->gtGetOp1()->OperGet() == GT_ADD) && - (tree->gtGetOp1()->gtGetOp2()->IsIntegralConst(sizeof(INT32) * index)) && - IsArgsAddr(tree->gtGetOp1()->gtGetOp1(), lvaNewObjArrayArgs); - } - - static bool IsArgsAddr(GenTree* tree, unsigned lvaNewObjArrayArgs) - { - return (tree->OperGet() == GT_ADDR) && (tree->gtGetOp1()->OperGet() == GT_LCL_VAR) && - (tree->gtGetOp1()->AsLclVar()->GetLclNum() == lvaNewObjArrayArgs); + return tree->OperIs(GT_LCL_FLD) && (tree->AsLclFld()->GetLclNum() == lvaNewObjArrayArgs) && + (tree->AsLclFld()->GetLclOffs() == sizeof(INT32) * index); } static bool IsComma(GenTree* tree) @@ -2058,7 +2051,8 @@ GenTree* Compiler::impInitializeArrayIntrinsic(CORINFO_SIG_INFO* sig) argIndex++; } - assert((comma != nullptr) && Match::IsArgsAddr(comma, lvaNewObjArrayArgs)); + assert((comma != nullptr) && comma->OperIs(GT_LCL_VAR_ADDR) && + (comma->AsLclVarCommon()->GetLclNum() == lvaNewObjArrayArgs)); if (argIndex != numArgs) { @@ -2630,8 +2624,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, unsigned rawHandleSlot = lvaGrabTemp(true DEBUGARG("rawHandle")); impAssignTempGen(rawHandleSlot, rawHandle, clsHnd, CHECK_SPILL_NONE); - GenTree* lclVar = gtNewLclvNode(rawHandleSlot, TYP_I_IMPL); - GenTree* lclVarAddr = gtNewOperNode(GT_ADDR, TYP_I_IMPL, lclVar); + GenTree* lclVarAddr = gtNewLclVarAddrNode(rawHandleSlot); var_types resultType = JITtype2varType(sig->retType); if (resultType == TYP_STRUCT) { @@ -6164,11 +6157,11 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, if (optimizedTheBox) { - assert(localCopyThis->OperIs(GT_ADDR)); + assert(localCopyThis->OperIs(GT_LCL_VAR_ADDR)); // We may end up inlining this call, so the local copy must be marked as "aliased", // making sure the inlinee importer will know when to spill references to its value. - lvaGetDesc(localCopyThis->AsUnOp()->gtOp1->AsLclVar())->lvHasLdAddrOp = true; + lvaGetDesc(localCopyThis->AsLclVar())->lvHasLdAddrOp = true; #if FEATURE_TAILCALL_OPT if (call->IsImplicitTailCall()) @@ -7885,12 +7878,8 @@ GenTree* Compiler::impKeepAliveIntrinsic(GenTree* objToKeepAlive) boxAsgStmt->SetRootNode(boxTempAsg); } - JITDUMP("\nImporting KEEPALIVE(BOX) as KEEPALIVE(ADDR(LCL_VAR V%02u))", boxTempNum); - - GenTree* boxTemp = gtNewLclvNode(boxTempNum, boxSrc->TypeGet()); - GenTree* boxTempAddr = gtNewOperNode(GT_ADDR, TYP_BYREF, boxTemp); - - return gtNewKeepAliveNode(boxTempAddr); + JITDUMP("\nImporting KEEPALIVE(BOX) as KEEPALIVE(LCL_VAR_ADDR V%02u)", boxTempNum); + objToKeepAlive = gtNewLclVarAddrNode(boxTempNum); } } diff --git a/src/coreclr/jit/lclmorph.cpp b/src/coreclr/jit/lclmorph.cpp index 810f22d7fe7b68..27d0f5ba41613d 100644 --- a/src/coreclr/jit/lclmorph.cpp +++ b/src/coreclr/jit/lclmorph.cpp @@ -14,23 +14,8 @@ class LocalAddressVisitor final : public GenTreeVisitor // actually produce values in IR) in order to support the invariant that every // node produces a value. // - // The existence of GT_ADDR nodes and their use together with GT_FIELD to form - // FIELD/ADDR/FIELD/ADDR/LCL_VAR sequences complicate things a bit. A typical - // GT_FIELD node acts like an indirection and should produce an unknown value, - // local address analysis doesn't know or care what value the field stores. - // But a GT_FIELD can also be used as an operand for a GT_ADDR node and then - // the GT_FIELD node does not perform an indirection, it's just represents a - // location, similar to GT_LCL_VAR and GT_LCL_FLD. - // - // To avoid this issue, the semantics of GT_FIELD (and for simplicity's sake any other - // indirection) nodes slightly deviates from the IR semantics - an indirection does not - // actually produce an unknown value but a location value, if the indirection address - // operand is an address value. - // - // The actual indirection is performed when the indirection's user node is processed: - // - A GT_ADDR user turns the location value produced by the indirection back - // into an address value. - // - Any other user node performs the indirection and produces an unknown value. + // Each value is processed ("escaped") when visiting (in post-order) its parent, + // to achieve uniformity between how address and location values are handled. // class Value { @@ -171,32 +156,6 @@ class LocalAddressVisitor final : public GenTreeVisitor m_address = true; } - //------------------------------------------------------------------------ - // Address: Produce an address value from a location value. - // - // Arguments: - // val - the input value - // - // Notes: - // - LOCATION(lclNum, offset) => ADDRESS(lclNum, offset) - // - ADDRESS(lclNum, offset) => invalid, we should never encounter something like ADDR(ADDR(...)) - // - UNKNOWN => UNKNOWN - // - void Address(Value& val) - { - assert(!IsLocation() && !IsAddress()); - assert(!val.IsAddress()); - - if (val.IsLocation()) - { - m_address = true; - m_lclNum = val.m_lclNum; - m_offset = val.m_offset; - } - - INDEBUG(val.Consume();) - } - //------------------------------------------------------------------------ // AddOffset: Produce an address value from an address value. // @@ -395,7 +354,7 @@ class LocalAddressVisitor final : public GenTreeVisitor MorphLocalField(node, user); } - if (node->OperIsLocal()) + if (node->OperIsLocal() || node->OperIsLocalAddr()) { unsigned const lclNum = node->AsLclVarCommon()->GetLclNum(); LclVarDsc* const varDsc = m_compiler->lvaGetDesc(lclNum); @@ -461,14 +420,6 @@ class LocalAddressVisitor final : public GenTreeVisitor TopValue(0).Address(node->AsLclFld()); break; - case GT_ADDR: - assert(TopValue(1).Node() == node); - assert(TopValue(0).Node() == node->gtGetOp1()); - - TopValue(1).Address(TopValue(0)); - PopValue(); - break; - case GT_ADD: assert(TopValue(2).Node() == node); assert(TopValue(1).Node() == node->gtGetOp1()); @@ -1162,12 +1113,11 @@ class LocalAddressVisitor final : public GenTreeVisitor assert(node->OperIs(GT_IND, GT_FIELD, GT_FIELD_ADDR)); GenTree* objRef = node->AsUnOp()->gtOp1; - GenTree* obj = ((objRef != nullptr) && objRef->OperIs(GT_ADDR)) ? objRef->AsOp()->gtOp1 : nullptr; // TODO-Bug: this code does not pay attention to "GTF_IND_VOLATILE". - if ((obj != nullptr) && obj->OperIs(GT_LCL_VAR) && varTypeIsStruct(obj)) + if ((objRef != nullptr) && objRef->OperIs(GT_LCL_VAR_ADDR)) { - const LclVarDsc* varDsc = m_compiler->lvaGetDesc(obj->AsLclVarCommon()); + const LclVarDsc* varDsc = m_compiler->lvaGetDesc(objRef->AsLclVarCommon()); if (varDsc->lvPromoted) { @@ -1181,37 +1131,30 @@ class LocalAddressVisitor final : public GenTreeVisitor return; } - const LclVarDsc* fieldDsc = m_compiler->lvaGetDesc(fieldLclNum); - var_types fieldType = fieldDsc->TypeGet(); - GenTree* lclVarNode = nullptr; - GenTreeFlags lclVarFlags = node->gtFlags & (GTF_NODE_MASK | GTF_DONT_CSE); + const LclVarDsc* fieldDsc = m_compiler->lvaGetDesc(fieldLclNum); + var_types fieldType = fieldDsc->TypeGet(); assert(fieldType != TYP_STRUCT); // Promoted LCL_VAR can't have a struct type. if (node->OperIs(GT_FIELD_ADDR)) { - node->ChangeOper(GT_ADDR); - node->AsUnOp()->gtOp1 = obj; - - lclVarNode = obj; + node->ChangeOper(GT_LCL_VAR_ADDR); + node->AsLclVar()->SetLclNum(fieldLclNum); } - else if ((node->TypeGet() == fieldType) || ((user != nullptr) && user->OperIs(GT_ADDR))) + else if (node->TypeGet() == fieldType) { - if (user != nullptr) + GenTreeFlags lclVarFlags = node->gtFlags & (GTF_NODE_MASK | GTF_DONT_CSE); + + if ((user != nullptr) && user->OperIs(GT_ASG) && (user->AsOp()->gtOp1 == node)) { - if (user->OperIs(GT_ASG) && (user->AsOp()->gtOp1 == node)) - { - lclVarFlags |= GTF_VAR_DEF; - } - else if (user->OperIs(GT_ADDR)) - { - // TODO-ADDR: delete this quirk. - lclVarFlags &= ~GTF_DONT_CSE; - } + lclVarFlags |= GTF_VAR_DEF; } - lclVarNode = node; + node->ChangeOper(GT_LCL_VAR); + node->AsLclVar()->SetLclNum(fieldLclNum); + node->gtType = fieldType; + node->gtFlags = lclVarFlags; } - else // Here we will turn "FIELD/IND(ADDR(LCL_VAR))" into "OBJ/IND(ADDR(LCL_VAR))". + else // Here we will turn "FIELD/IND(LCL_ADDR_VAR)" into "OBJ/IND(LCL_ADDR_VAR)". { // This type mismatch is somewhat common due to how we retype fields of struct type that // recursively simplify down to a primitive. E. g. for "struct { struct { int a } A, B }", @@ -1247,14 +1190,9 @@ class LocalAddressVisitor final : public GenTreeVisitor node->SetOper(GT_IND); } - lclVarNode = obj; + objRef->AsLclVar()->SetLclNum(fieldLclNum); } - lclVarNode->SetOper(GT_LCL_VAR); - lclVarNode->AsLclVarCommon()->SetLclNum(fieldLclNum); - lclVarNode->gtType = fieldType; - lclVarNode->gtFlags = lclVarFlags; - JITDUMP("Replacing the field in promoted struct with local var V%02u\n", fieldLclNum); m_stmtModified = true; } @@ -1320,7 +1258,7 @@ class LocalAddressVisitor final : public GenTreeVisitor // But the pattern should at least subset the implicit byref cases that are // handled in fgCanFastTailCall and fgMakeOutgoingStructArgCopy. // - // CALL(OBJ(ADDR(LCL_VAR...))) + // CALL(OBJ(LCL_VAR_ADDR...)) bool isArgToCall = false; bool keepSearching = true; for (int i = 0; i < m_ancestors.Height() && keepSearching; i++) @@ -1330,23 +1268,17 @@ class LocalAddressVisitor final : public GenTreeVisitor { case 0: { - keepSearching = node->OperIs(GT_LCL_VAR); + keepSearching = node->OperIs(GT_LCL_VAR_ADDR); } break; case 1: - { - keepSearching = node->OperIs(GT_ADDR); - } - break; - - case 2: { keepSearching = node->OperIs(GT_OBJ); } break; - case 3: + case 2: { keepSearching = false; isArgToCall = node->IsCall(); @@ -1492,9 +1424,9 @@ bool Compiler::fgMorphCombineSIMDFieldAssignments(BasicBlock* block, Statement* unsigned index = 0; CorInfoType simdBaseJitType = CORINFO_TYPE_UNDEF; unsigned simdSize = 0; - GenTree* simdStructNode = getSIMDStructFromField(prevRHS, &simdBaseJitType, &index, &simdSize, true); + GenTree* simdLclAddr = getSIMDStructFromField(prevRHS, &simdBaseJitType, &index, &simdSize, true); - if ((simdStructNode == nullptr) || (index != 0) || (simdBaseJitType != CORINFO_TYPE_FLOAT)) + if ((simdLclAddr == nullptr) || (index != 0) || (simdBaseJitType != CORINFO_TYPE_FLOAT)) { // if the RHS is not from a SIMD vector field X, then there is no need to check further. return false; @@ -1562,10 +1494,7 @@ bool Compiler::fgMorphCombineSIMDFieldAssignments(BasicBlock* block, Statement* JITDUMP("\n" FMT_BB " " FMT_STMT " (before):\n", block->bbNum, stmt->GetID()); DISPSTMT(stmt); - assert(!simdStructNode->CanCSE() && varTypeIsSIMD(simdStructNode)); - simdStructNode->ClearDoNotCSE(); - - tree = gtNewAssignNode(dstNode, simdStructNode); + tree = gtNewAssignNode(dstNode, gtNewLclvNode(simdLclAddr->AsLclVarCommon()->GetLclNum(), simdType)); stmt->SetRootNode(tree); diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index 6897755c8cc0bf..7cfe66c4c64718 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -8230,14 +8230,6 @@ Compiler::fgWalkResult Compiler::lvaStressLclFldCB(GenTree** pTree, fgWalkData* { lcl = tree->AsLclVarCommon(); } - else if (tree->OperIs(GT_ADDR)) - { - GenTree* const addr = tree->AsOp()->gtOp1; - if (addr->OperIs(GT_LCL_VAR, GT_LCL_FLD)) - { - lcl = addr->AsLclVarCommon(); - } - } if (lcl == nullptr) { @@ -8381,16 +8373,6 @@ Compiler::fgWalkResult Compiler::lvaStressLclFldCB(GenTree** pTree, fgWalkData* tree->ChangeOper(GT_LCL_FLD_ADDR); tree->AsLclFld()->SetLclOffs(padding); } - else - { - noway_assert(tree->OperIs(GT_ADDR)); - GenTree* paddingTree = pComp->gtNewIconNode(padding); - GenTree* newAddr = pComp->gtNewOperNode(GT_ADD, tree->gtType, tree, paddingTree); - - *pTree = newAddr; - - lcl->gtType = TYP_BLK; - } } return WALK_SKIP_SUBTREES; diff --git a/src/coreclr/jit/lsraarm.cpp b/src/coreclr/jit/lsraarm.cpp index 06d807772f36cd..47cdbaa7539077 100644 --- a/src/coreclr/jit/lsraarm.cpp +++ b/src/coreclr/jit/lsraarm.cpp @@ -641,18 +641,6 @@ int LinearScan::BuildNode(GenTree* tree) } break; - case GT_ADDR: - { - // For a GT_ADDR, the child node should not be evaluated into a register - GenTree* child = tree->gtGetOp1(); - assert(!isCandidateLocalRef(child)); - assert(child->isContained()); - assert(dstCount == 1); - srcCount = 0; - BuildDef(tree); - } - break; - case GT_STORE_BLK: case GT_STORE_OBJ: case GT_STORE_DYN_BLK: diff --git a/src/coreclr/jit/lsraarm64.cpp b/src/coreclr/jit/lsraarm64.cpp index ab9105c0114948..c816d33834032b 100644 --- a/src/coreclr/jit/lsraarm64.cpp +++ b/src/coreclr/jit/lsraarm64.cpp @@ -545,18 +545,6 @@ int LinearScan::BuildNode(GenTree* tree) } break; - case GT_ADDR: - { - // For a GT_ADDR, the child node should not be evaluated into a register - GenTree* child = tree->gtGetOp1(); - assert(!isCandidateLocalRef(child)); - assert(child->isContained()); - assert(dstCount == 1); - srcCount = 0; - BuildDef(tree); - } - break; - case GT_BLK: // These should all be eliminated prior to Lowering. assert(!"Non-store block node in Lowering"); diff --git a/src/coreclr/jit/lsraloongarch64.cpp b/src/coreclr/jit/lsraloongarch64.cpp index 934d1014d43c42..0d5a20d6f3dfcb 100644 --- a/src/coreclr/jit/lsraloongarch64.cpp +++ b/src/coreclr/jit/lsraloongarch64.cpp @@ -162,7 +162,6 @@ int LinearScan::BuildNode(GenTree* tree) case GT_COMMA: case GT_QMARK: case GT_COLON: - case GT_ADDR: srcCount = 0; assert(dstCount == 0); unreached(); diff --git a/src/coreclr/jit/lsraxarch.cpp b/src/coreclr/jit/lsraxarch.cpp index a51ae28accfcda..682fcec159ff67 100644 --- a/src/coreclr/jit/lsraxarch.cpp +++ b/src/coreclr/jit/lsraxarch.cpp @@ -493,20 +493,7 @@ int LinearScan::BuildNode(GenTree* tree) } break; - case GT_ADDR: - { - // For a GT_ADDR, the child node should not be evaluated into a register - GenTree* child = tree->gtGetOp1(); - assert(!isCandidateLocalRef(child)); - assert(child->isContained()); - assert(dstCount == 1); - srcCount = 0; - } - break; - -#if !defined(FEATURE_PUT_STRUCT_ARG_STK) case GT_OBJ: -#endif case GT_BLK: // These should all be eliminated prior to Lowering. assert(!"Non-store block node in Lowering"); diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 57d1794ae66043..6f518a14b18234 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -6857,9 +6857,9 @@ void Compiler::fgValidateIRForTailCall(GenTreeCall* call) // {args} // GT_COMMA // GT_CALL Dispatcher -// GT_ADDR ReturnAddress +// GT_LCL_VAR_ADDR ReturnAddress // {CallTargetStub} -// GT_ADDR ReturnValue +// GT_LCL_VAR_ADDR ReturnValue // GT_LCL ReturnValue // whenever the call node returns a value. If the call node does not return a // value the last comma will not be there. @@ -7147,9 +7147,8 @@ GenTree* Compiler::fgCreateCallDispatcherAndGetResult(GenTreeCall* orig lvaGetDesc(newRetLcl)->lvIsMultiRegRet = true; } - retValArg = - gtNewOperNode(GT_ADDR, TYP_I_IMPL, gtNewLclvNode(newRetLcl, genActualType(lvaTable[newRetLcl].lvType))); - retVal = gtNewLclvNode(newRetLcl, genActualType(lvaTable[newRetLcl].lvType)); + retValArg = gtNewLclVarAddrNode(newRetLcl); + retVal = gtNewLclvNode(newRetLcl, genActualType(lvaTable[newRetLcl].lvType)); } else { @@ -7168,7 +7167,7 @@ GenTree* Compiler::fgCreateCallDispatcherAndGetResult(GenTreeCall* orig lvaSetVarAddrExposed(lvaRetAddrVar DEBUGARG(AddressExposedReason::DISPATCH_RET_BUF)); } - GenTree* retAddrSlot = gtNewOperNode(GT_ADDR, TYP_I_IMPL, gtNewLclvNode(lvaRetAddrVar, TYP_I_IMPL)); + GenTree* retAddrSlot = gtNewLclVarAddrNode(lvaRetAddrVar); NewCallArg retAddrSlotArg = NewCallArg::Primitive(retAddrSlot); NewCallArg callTargetArg = NewCallArg::Primitive(callTarget); @@ -8629,34 +8628,29 @@ GenTree* Compiler::getSIMDStructFromField(GenTree* tree, unsigned* simdSizeOut, bool ignoreUsedInSIMDIntrinsic /*false*/) { - if (tree->OperIs(GT_FIELD)) + if (tree->OperIs(GT_FIELD) && tree->AsField()->IsInstance()) { GenTree* objRef = tree->AsField()->GetFldObj(); - if ((objRef != nullptr) && objRef->OperIs(GT_ADDR)) + if (objRef->OperIs(GT_LCL_VAR_ADDR)) { - GenTree* obj = objRef->AsOp()->gtOp1; - - if (isSIMDTypeLocal(obj)) + LclVarDsc* varDsc = lvaGetDesc(objRef->AsLclVarCommon()); + if (varTypeIsSIMD(varDsc) && (varDsc->lvIsUsedInSIMDIntrinsic() || ignoreUsedInSIMDIntrinsic)) { - LclVarDsc* varDsc = lvaGetDesc(obj->AsLclVarCommon()); - if (varDsc->lvIsUsedInSIMDIntrinsic() || ignoreUsedInSIMDIntrinsic) - { - CorInfoType simdBaseJitType = varDsc->GetSimdBaseJitType(); - var_types simdBaseType = JITtype2varType(simdBaseJitType); - unsigned fieldOffset = tree->AsField()->gtFldOffset; - unsigned baseTypeSize = genTypeSize(simdBaseType); + CorInfoType simdBaseJitType = varDsc->GetSimdBaseJitType(); + var_types simdBaseType = JITtype2varType(simdBaseJitType); + unsigned fieldOffset = tree->AsField()->gtFldOffset; + unsigned baseTypeSize = genTypeSize(simdBaseType); - // Below condition is convervative. We don't actually need the two types to - // match (only the tree type is relevant), but we don't have a convenient way - // to turn the tree type into "CorInfoType". - if ((tree->TypeGet() == simdBaseType) && ((fieldOffset % baseTypeSize) == 0)) - { - *simdSizeOut = varDsc->lvExactSize; - *simdBaseJitTypeOut = simdBaseJitType; - *indexOut = fieldOffset / baseTypeSize; + // Below condition is convervative. We don't actually need the two types to + // match (only the tree type is relevant), but we don't have a convenient way + // to turn the tree type into "CorInfoType". + if ((tree->TypeGet() == simdBaseType) && ((fieldOffset % baseTypeSize) == 0)) + { + *simdSizeOut = varDsc->lvExactSize; + *simdBaseJitTypeOut = simdBaseJitType; + *indexOut = fieldOffset / baseTypeSize; - return obj; - } + return objRef; } } } @@ -8881,17 +8875,6 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA op1->gtFlags |= GTF_DONT_CSE; break; - case GT_ADDR: - if (op1->OperIs(GT_FIELD) && op1->AsField()->IsInstance()) - { - op1->SetOper(GT_FIELD_ADDR); - return fgMorphField(op1, mac); - } - - // Location nodes cannot be CSEd. - op1->gtFlags |= GTF_DONT_CSE; - break; - case GT_QMARK: case GT_JTRUE: @@ -9503,15 +9486,6 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA // Propagate the new flags tree->gtFlags |= (op1->gtFlags & GTF_ALL_EFFECT); - - // addresses of locals do not need GTF_GLOB_REF, even if the child has - // it (is address exposed). Note that general addressing may still need - // GTF_GLOB_REF, for example if the subtree has a comma that involves a - // global reference. - if (tree->OperIs(GT_ADDR) && ((tree->gtFlags & GTF_GLOB_REF) != 0) && tree->IsLocalAddrExpr()) - { - tree->gtFlags &= ~GTF_GLOB_REF; - } } // if (op1) /*------------------------------------------------------------------------- @@ -10083,14 +10057,6 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA case GT_BLK: case GT_IND: { - // If we have IND(ADDR(X)) and X has GTF_GLOB_REF, we must set GTF_GLOB_REF on - // the OBJ. Note that the GTF_GLOB_REF will have been cleared on ADDR(X) where X - // is a local, even if it has been address-exposed. - if (op1->OperIs(GT_ADDR)) - { - tree->gtFlags |= (op1->AsUnOp()->gtGetOp1()->gtFlags & GTF_GLOB_REF); - } - if (!tree->OperIs(GT_IND)) { break; @@ -10183,53 +10149,6 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA } break; - case GT_ADDR: - // Can not remove a GT_ADDR if it is currently a CSE candidate. - if (gtIsActiveCSE_Candidate(tree)) - { - break; - } - - // Perform the transform ADDR(IND(...)) == (...). - if (op1->OperIsIndir()) - { - GenTree* addr = op1->AsIndir()->Addr(); - - noway_assert(varTypeIsI(genActualType(addr))); - - DEBUG_DESTROY_NODE(op1); - DEBUG_DESTROY_NODE(tree); - - return addr; - } - // Perform the transform ADDR(COMMA(x, ..., z)) == COMMA(x, ..., ADDR(z)). - else if (op1->OperIs(GT_COMMA) && !optValnumCSE_phase) - { - ArrayStack commas(getAllocator(CMK_ArrayStack)); - for (GenTree* comma = op1; comma != nullptr && comma->gtOper == GT_COMMA; comma = comma->gtGetOp2()) - { - commas.Push(comma); - } - - GenTree* commaNode = commas.Top(); - GenTree* addr = gtNewOperNode(GT_ADDR, TYP_BYREF, commaNode->AsOp()->gtOp2); - commaNode->AsOp()->gtOp2 = addr; - - // Retype the comma nodes to match "addr" and update their side effects. - while (!commas.Empty()) - { - GenTree* comma = commas.Pop(); - comma->gtType = addr->TypeGet(); -#ifdef DEBUG - comma->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED; -#endif - gtUpdateNodeSideEffects(comma); - } - - return op1; - } - break; - case GT_COLON: if (fgGlobalMorph) { diff --git a/src/coreclr/jit/objectalloc.cpp b/src/coreclr/jit/objectalloc.cpp index a0e0aebbeea753..28f954f1c7ddf8 100644 --- a/src/coreclr/jit/objectalloc.cpp +++ b/src/coreclr/jit/objectalloc.cpp @@ -169,25 +169,29 @@ void ObjectAllocator::MarkEscapingVarsAndBuildConnGraph() Compiler::fgWalkResult PreOrderVisit(GenTree** use, GenTree* user) { - GenTree* tree = *use; - assert(tree != nullptr); - assert(tree->IsLocal()); + GenTree* tree = *use; + unsigned lclNum = tree->AsLclVarCommon()->GetLclNum(); + bool lclEscapes = true; - var_types type = tree->TypeGet(); - if ((tree->OperGet() == GT_LCL_VAR) && (type == TYP_REF || type == TYP_BYREF || type == TYP_I_IMPL)) + if (tree->OperIs(GT_LCL_VAR) && tree->TypeIs(TYP_REF, TYP_BYREF, TYP_I_IMPL)) { - unsigned int lclNum = tree->AsLclVar()->GetLclNum(); assert(tree == m_ancestors.Top()); - if (m_allocator->CanLclVarEscapeViaParentStack(&m_ancestors, lclNum)) + if (!m_allocator->CanLclVarEscapeViaParentStack(&m_ancestors, lclNum)) { - if (!m_allocator->CanLclVarEscape(lclNum)) - { - JITDUMP("V%02u first escapes via [%06u]\n", lclNum, m_compiler->dspTreeID(tree)); - } - m_allocator->MarkLclVarAsEscaping(lclNum); + lclEscapes = false; + } + } + + if (lclEscapes) + { + if (!m_allocator->CanLclVarEscape(lclNum)) + { + JITDUMP("V%02u first escapes via [%06u]\n", lclNum, m_compiler->dspTreeID(tree)); } + m_allocator->MarkLclVarAsEscaping(lclNum); } + return Compiler::fgWalkResult::WALK_CONTINUE; } }; @@ -662,22 +666,9 @@ bool ObjectAllocator::CanLclVarEscapeViaParentStack(ArrayStack* parent case GT_FIELD: case GT_IND: - { - int grandParentIndex = parentIndex + 1; - if ((parentStack->Height() > grandParentIndex) && - (parentStack->Top(grandParentIndex)->OperGet() == GT_ADDR)) - { - // Check if the address of the field/ind escapes. - parentIndex += 2; - keepChecking = true; - } - else - { - // Address of the field/ind is not taken so the local doesn't escape. - canLclVarEscapeViaParentStack = false; - } + // Address of the field/ind is not taken so the local doesn't escape. + canLclVarEscapeViaParentStack = false; break; - } case GT_CALL: { @@ -782,22 +773,6 @@ void ObjectAllocator::UpdateAncestorTypes(GenTree* tree, ArrayStack* p // It's either null or points to inside a stack-allocated object. parent->gtFlags |= GTF_IND_TGT_NOT_HEAP; } - - int grandParentIndex = parentIndex + 1; - - if (parentStack->Height() > grandParentIndex) - { - GenTree* grandParent = parentStack->Top(grandParentIndex); - if (grandParent->OperGet() == GT_ADDR) - { - if (grandParent->TypeGet() == TYP_REF) - { - grandParent->ChangeType(newType); - } - parentIndex += 2; - keepChecking = true; - } - } break; } @@ -878,9 +853,8 @@ void ObjectAllocator::RewriteUses() if (m_allocator->m_HeapLocalToStackLocalMap.TryGetValue(lclNum, &newLclNum)) { newType = TYP_I_IMPL; - tree = - m_compiler->gtNewOperNode(GT_ADDR, newType, m_compiler->gtNewLclvNode(newLclNum, TYP_STRUCT)); - *use = tree; + tree = m_compiler->gtNewLclVarAddrNode(newLclNum); + *use = tree; } else { diff --git a/src/coreclr/jit/patchpoint.cpp b/src/coreclr/jit/patchpoint.cpp index e75c17a4d37213..48a7f9b6f1b7d7 100644 --- a/src/coreclr/jit/patchpoint.cpp +++ b/src/coreclr/jit/patchpoint.cpp @@ -177,8 +177,7 @@ class PatchpointTransformer // // call PPHelper(&ppCounter, ilOffset) GenTree* ilOffsetNode = compiler->gtNewIconNode(ilOffset, TYP_INT); - GenTree* ppCounterRef = compiler->gtNewLclvNode(ppCounterLclNum, TYP_INT); - GenTree* ppCounterAddr = compiler->gtNewOperNode(GT_ADDR, TYP_I_IMPL, ppCounterRef); + GenTree* ppCounterAddr = compiler->gtNewLclVarAddrNode(ppCounterLclNum); GenTreeCall* helperCall = compiler->gtNewHelperCallNode(CORINFO_HELP_PATCHPOINT, TYP_VOID, ppCounterAddr, ilOffsetNode); diff --git a/src/coreclr/jit/rationalize.cpp b/src/coreclr/jit/rationalize.cpp index 23cbd645a48f1f..e2fae6778b323a 100644 --- a/src/coreclr/jit/rationalize.cpp +++ b/src/coreclr/jit/rationalize.cpp @@ -479,56 +479,6 @@ void Rationalizer::RewriteAssignment(LIR::Use& use) } } -void Rationalizer::RewriteAddress(LIR::Use& use) -{ - assert(use.IsInitialized()); - - GenTreeUnOp* address = use.Def()->AsUnOp(); - assert(address->OperGet() == GT_ADDR); - - GenTree* location = address->gtGetOp1(); - genTreeOps locationOp = location->OperGet(); - - if (location->IsLocal()) - { -// We are changing the child from GT_LCL_VAR TO GT_LCL_VAR_ADDR. -// Therefore gtType of the child needs to be changed to a TYP_BYREF -#ifdef DEBUG - if (locationOp == GT_LCL_VAR) - { - JITDUMP("Rewriting GT_ADDR(GT_LCL_VAR) to GT_LCL_VAR_ADDR:\n"); - } - else - { - assert(locationOp == GT_LCL_FLD); - JITDUMP("Rewriting GT_ADDR(GT_LCL_FLD) to GT_LCL_FLD_ADDR:\n"); - } -#endif // DEBUG - - location->SetOper(addrForm(locationOp)); - location->gtType = TYP_BYREF; - copyFlags(location, address, GTF_ALL_EFFECT); - - use.ReplaceWith(location); - BlockRange().Remove(address); - } - else if (location->OperIsIndir()) - { - use.ReplaceWith(location->gtGetOp1()); - BlockRange().Remove(location); - BlockRange().Remove(address); - - JITDUMP("Rewriting GT_ADDR(GT_IND(X)) to X:\n"); - } - else - { - unreached(); - } - - DISPTREERANGE(BlockRange(), use.Def()); - JITDUMP("\n"); -} - Compiler::fgWalkResult Rationalizer::RewriteNode(GenTree** useEdge, Compiler::GenTreeStack& parentStack) { assert(useEdge != nullptr); @@ -556,10 +506,6 @@ Compiler::fgWalkResult Rationalizer::RewriteNode(GenTree** useEdge, Compiler::Ge RewriteAssignment(use); break; - case GT_ADDR: - RewriteAddress(use); - break; - case GT_IND: case GT_BLK: case GT_OBJ: diff --git a/src/coreclr/jit/rationalize.h b/src/coreclr/jit/rationalize.h index 329fbcbd1ac248..e031b0fac356d2 100644 --- a/src/coreclr/jit/rationalize.h +++ b/src/coreclr/jit/rationalize.h @@ -56,7 +56,6 @@ class Rationalizer final : public Phase // Other transformations void RewriteAssignment(LIR::Use& use); - void RewriteAddress(LIR::Use& use); #ifdef TARGET_ARM64 void RewriteSubLshDiv(GenTree** use); diff --git a/src/coreclr/jit/simd.cpp b/src/coreclr/jit/simd.cpp index 975192787797a6..b66db85f71ba92 100644 --- a/src/coreclr/jit/simd.cpp +++ b/src/coreclr/jit/simd.cpp @@ -1196,13 +1196,17 @@ GenTree* Compiler::impSIMDPopStack(var_types type, bool expectAddr, CORINFO_CLAS tree = gtNewOperNode(GT_IND, type, tree); } - if (tree->OperIsIndir() && tree->AsIndir()->Addr()->OperIs(GT_ADDR)) + if (tree->OperIsIndir() && tree->AsIndir()->Addr()->OperIs(GT_LCL_VAR_ADDR)) { - GenTree* location = tree->AsIndir()->Addr()->gtGetOp1(); - if (location->OperIs(GT_LCL_VAR) && location->TypeIs(type)) + GenTreeLclVar* lclAddr = tree->AsIndir()->Addr()->AsLclVar(); + LclVarDsc* varDsc = lvaGetDesc(lclAddr); + if (varDsc->TypeGet() == type) { assert(type != TYP_STRUCT); - tree = location; + lclAddr->ChangeType(type); + lclAddr->SetOper(GT_LCL_VAR); + + tree = lclAddr; } } @@ -1227,8 +1231,8 @@ GenTree* Compiler::impSIMDPopStack(var_types type, bool expectAddr, CORINFO_CLAS } else if (tree->gtType == TYP_BYREF) { - assert(tree->IsLocal() || (tree->OperGet() == GT_RET_EXPR) || (tree->OperGet() == GT_CALL) || - ((tree->gtOper == GT_ADDR) && varTypeIsSIMD(tree->gtGetOp1()))); + assert(tree->IsLocal() || tree->OperIs(GT_RET_EXPR, GT_CALL) || + (tree->OperIs(GT_LCL_VAR_ADDR) && varTypeIsSIMD(lvaGetDesc(tree->AsLclVar())))); } return tree; @@ -1254,11 +1258,11 @@ GenTree* Compiler::getOp1ForConstructor(OPCODE opcode, GenTree* newobjThis, CORI if (opcode == CEE_NEWOBJ) { op1 = newobjThis; - assert(newobjThis->gtOper == GT_ADDR && newobjThis->AsOp()->gtOp1->gtOper == GT_LCL_VAR); + assert(newobjThis->OperIs(GT_LCL_VAR_ADDR)); // push newobj result on type stack - unsigned tmp = op1->AsOp()->gtOp1->AsLclVarCommon()->GetLclNum(); - impPushOnStack(gtNewLclvNode(tmp, lvaGetRealType(tmp)), verMakeTypeInfo(clsHnd).NormaliseForStack()); + unsigned lclNum = op1->AsLclVarCommon()->GetLclNum(); + impPushOnStack(gtNewLclvNode(lclNum, lvaGetRealType(lclNum)), verMakeTypeInfo(clsHnd).NormaliseForStack()); } else { @@ -1273,10 +1277,10 @@ GenTree* Compiler::getOp1ForConstructor(OPCODE opcode, GenTree* newobjThis, CORI // is used in a SIMD intrinsic. // Arguments: // tree - GenTree* - +// void Compiler::setLclRelatedToSIMDIntrinsic(GenTree* tree) { - assert(tree->OperIsLocal()); + assert(tree->OperIs(GT_LCL_VAR, GT_LCL_VAR_ADDR)); LclVarDsc* lclVarDsc = lvaGetDesc(tree->AsLclVarCommon()); lclVarDsc->lvUsedInSIMDIntrinsic = true; } @@ -1299,24 +1303,18 @@ bool areFieldsParentsLocatedSame(GenTree* op1, GenTree* op2) GenTree* op2ObjRef = op2->AsField()->GetFldObj(); while (op1ObjRef != nullptr && op2ObjRef != nullptr) { - if (op1ObjRef->OperGet() != op2ObjRef->OperGet()) { break; } - else if (op1ObjRef->OperGet() == GT_ADDR) - { - op1ObjRef = op1ObjRef->AsOp()->gtOp1; - op2ObjRef = op2ObjRef->AsOp()->gtOp1; - } - if (op1ObjRef->OperIsLocal() && op2ObjRef->OperIsLocal() && - op1ObjRef->AsLclVarCommon()->GetLclNum() == op2ObjRef->AsLclVarCommon()->GetLclNum()) + if (op1ObjRef->OperIs(GT_LCL_VAR, GT_LCL_VAR_ADDR) && + (op1ObjRef->AsLclVarCommon()->GetLclNum() == op2ObjRef->AsLclVarCommon()->GetLclNum())) { return true; } - else if (op1ObjRef->OperGet() == GT_FIELD && op2ObjRef->OperGet() == GT_FIELD && - op1ObjRef->AsField()->gtFldHnd == op2ObjRef->AsField()->gtFldHnd) + + if (op1ObjRef->OperIs(GT_FIELD) && (op1ObjRef->AsField()->gtFldHnd == op2ObjRef->AsField()->gtFldHnd)) { op1ObjRef = op1ObjRef->AsField()->GetFldObj(); op2ObjRef = op2ObjRef->AsField()->GetFldObj(); @@ -1486,10 +1484,8 @@ GenTree* Compiler::createAddressNodeForSIMDInit(GenTree* tree, unsigned simdSize if (tree->OperIs(GT_FIELD)) { GenTree* objRef = tree->AsField()->GetFldObj(); - if (objRef != nullptr && objRef->gtOper == GT_ADDR) + if ((objRef != nullptr) && objRef->OperIs(GT_LCL_VAR_ADDR)) { - GenTree* obj = objRef->AsOp()->gtOp1; - // If the field is directly from a struct, then in this case, // we should set this struct's lvUsedInSIMDIntrinsic as true, // so that this sturct won't be promoted. @@ -1501,9 +1497,9 @@ GenTree* Compiler::createAddressNodeForSIMDInit(GenTree* tree, unsigned simdSize // TODO-CQ: // In future, we should optimize this case so that if there is a nested field like s1.s2.x and s1.s2.x's // address is used for initializing the vector, then s1 can be promoted but s2 can't. - if (varTypeIsSIMD(obj) && obj->OperIsLocal()) + if (varTypeIsSIMD(lvaGetDesc(objRef->AsLclVar()))) { - setLclRelatedToSIMDIntrinsic(obj); + setLclRelatedToSIMDIntrinsic(objRef); } } @@ -1564,18 +1560,18 @@ void Compiler::impMarkContiguousSIMDFieldAssignments(Statement* stmt) GenTree* expr = stmt->GetRootNode(); if (expr->OperGet() == GT_ASG && expr->TypeGet() == TYP_FLOAT) { - GenTree* curDst = expr->AsOp()->gtOp1; - GenTree* curSrc = expr->AsOp()->gtOp2; - unsigned index = 0; - CorInfoType simdBaseJitType = CORINFO_TYPE_UNDEF; - unsigned simdSize = 0; - GenTree* srcSimdStructNode = getSIMDStructFromField(curSrc, &simdBaseJitType, &index, &simdSize, true); + GenTree* curDst = expr->AsOp()->gtOp1; + GenTree* curSrc = expr->AsOp()->gtOp2; + unsigned index = 0; + CorInfoType simdBaseJitType = CORINFO_TYPE_UNDEF; + unsigned simdSize = 0; + GenTree* srcSimdLclAddr = getSIMDStructFromField(curSrc, &simdBaseJitType, &index, &simdSize, true); - if (srcSimdStructNode == nullptr || simdBaseJitType != CORINFO_TYPE_FLOAT) + if (srcSimdLclAddr == nullptr || simdBaseJitType != CORINFO_TYPE_FLOAT) { fgPreviousCandidateSIMDFieldAsgStmt = nullptr; } - else if (index == 0 && isSIMDTypeLocal(srcSimdStructNode)) + else if (index == 0) { fgPreviousCandidateSIMDFieldAsgStmt = stmt; } @@ -1595,21 +1591,14 @@ void Compiler::impMarkContiguousSIMDFieldAssignments(Statement* stmt) if (index == (simdSize / genTypeSize(simdBaseType) - 1)) { // Successfully found the pattern, mark the lclvar as UsedInSIMDIntrinsic - if (srcSimdStructNode->OperIsLocal()) - { - setLclRelatedToSIMDIntrinsic(srcSimdStructNode); - } + setLclRelatedToSIMDIntrinsic(srcSimdLclAddr); - if (curDst->OperGet() == GT_FIELD) + if (curDst->OperIs(GT_FIELD) && curDst->AsField()->IsInstance()) { GenTree* objRef = curDst->AsField()->GetFldObj(); - if (objRef != nullptr && objRef->gtOper == GT_ADDR) + if (objRef->OperIs(GT_LCL_VAR_ADDR) && varTypeIsStruct(lvaGetDesc(objRef->AsLclVar()))) { - GenTree* obj = objRef->AsOp()->gtOp1; - if (varTypeIsStruct(obj) && obj->OperIsLocal()) - { - setLclRelatedToSIMDIntrinsic(obj); - } + setLclRelatedToSIMDIntrinsic(objRef); } } } @@ -1775,11 +1764,11 @@ GenTree* Compiler::impSIMDIntrinsic(OPCODE opcode, if (initFromFirstArgIndir) { simdTree = op2; - if (op1->AsOp()->gtOp1->OperIsLocal()) + if (op1->OperIs(GT_LCL_VAR_ADDR)) { // label the dst struct's lclvar is used for SIMD intrinsic, // so that this dst struct won't be promoted. - setLclRelatedToSIMDIntrinsic(op1->AsOp()->gtOp1); + setLclRelatedToSIMDIntrinsic(op1); } } else diff --git a/src/coreclr/jit/treelifeupdater.cpp b/src/coreclr/jit/treelifeupdater.cpp index c3e5076d728951..515574a0f64533 100644 --- a/src/coreclr/jit/treelifeupdater.cpp +++ b/src/coreclr/jit/treelifeupdater.cpp @@ -184,28 +184,6 @@ void TreeLifeUpdater::UpdateLifeVar(GenTree* tree) unsigned int lclNum = lclVarTree->AsLclVarCommon()->GetLclNum(); LclVarDsc* varDsc = compiler->lvaGetDesc(lclNum); -#ifdef DEBUG -#if !defined(TARGET_AMD64) - // There are no addr nodes on ARM and we are experimenting with encountering vars in 'random' order. - // Struct fields are not traversed in a consistent order, so ignore them when - // verifying that we see the var nodes in execution order - if (ForCodeGen) - { - if (tree->OperIsIndir()) - { - assert(indirAddrLocal != NULL); - } - else if (tree->gtNext != NULL && tree->gtNext->gtOper == GT_ADDR && - ((tree->gtNext->gtNext == NULL || !tree->gtNext->gtNext->OperIsIndir()))) - { - assert(tree->IsLocal()); // Can only take the address of a local. - // The ADDR might occur in a context where the address it contributes is eventually - // dereferenced, so we can't say that this is not a use or def. - } - } -#endif // !TARGET_AMD64 -#endif // DEBUG - compiler->compCurLifeTree = tree; VarSetOps::Assign(compiler, newLife, compiler->compCurLife); diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 81dc0080124c2d..e82d187d5e889e 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -9165,26 +9165,6 @@ void Compiler::fgValueNumberTree(GenTree* tree) } break; - case GT_ADDR: - { - GenTree* location = tree->AsUnOp()->gtGetOp1(); - - if (location->OperIsLocalRead()) - { - GenTreeLclVarCommon* lclNode = location->AsLclVarCommon(); - ValueNum addrVN = - vnStore->VNForFunc(TYP_BYREF, VNF_PtrToLoc, vnStore->VNForIntCon(lclNode->GetLclNum()), - vnStore->VNForIntPtrCon(lclNode->GetLclOffs())); - tree->gtVNPair.SetBoth(addrVN); // No exceptions for local addresses. - } - else - { - tree->gtVNPair = vnStore->VNPUniqueWithExc(tree->TypeGet(), - vnStore->VNPExceptionSet(location->gtVNPair)); - } - } - break; - case GT_ARR_ADDR: fgValueNumberArrIndexAddr(tree->AsArrAddr()); break;