From b2770414fdc80a718bf4daf14b001326bdf7c1ad Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Wed, 10 Nov 2021 23:10:22 +0300 Subject: [PATCH 1/5] Delete "gtGetChildPointer" TryGetUse does the same thing and is used more often. Also some editorial renames to standardize on the "user/use" terminology. --- src/coreclr/jit/earlyprop.cpp | 2 +- src/coreclr/jit/gentree.cpp | 290 +++++++--------------------------- src/coreclr/jit/gentree.h | 17 +- 3 files changed, 65 insertions(+), 244 deletions(-) diff --git a/src/coreclr/jit/earlyprop.cpp b/src/coreclr/jit/earlyprop.cpp index 74f3c36c1bb18..e4b29df2166dd 100644 --- a/src/coreclr/jit/earlyprop.cpp +++ b/src/coreclr/jit/earlyprop.cpp @@ -700,7 +700,7 @@ bool Compiler::optIsNullCheckFoldingLegal(GenTree* tree, assert(fgStmtListThreaded); while (canRemoveNullCheck && (currentTree != tree) && (currentTree != nullptr)) { - if ((*nullCheckParent == nullptr) && (nullCheckTree->gtGetChildPointer(currentTree) != nullptr)) + if ((*nullCheckParent == nullptr) && currentTree->TryGetUse(nullCheckTree)) { *nullCheckParent = currentTree; } diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 01b1296f13f59..2cfedd817cec8 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -4986,199 +4986,20 @@ unsigned GenTree::GetScaledIndex() } //------------------------------------------------------------------------ -// gtGetChildPointer: If 'parent' is the parent of this node, return the pointer -// to the child node so that it can be modified; otherwise, return nullptr. +// TryGetUse: Get the def -> def edge for a child of this tree. // // Arguments: -// parent - The possible parent of this node +// def - the node to find the use for +// pUse - [out] parameter for the use // // Return Value: -// If "child" is a child of "parent", returns a pointer to the child node in the parent -// (i.e. a pointer to a GenTree pointer). -// Otherwise, returns nullptr. +// Whether "def" is a child of this node. If it is, "*pUse" is set, +// allowing for the replacement of "def" with some other node. // -// Assumptions: -// 'parent' must be non-null -// -// Notes: -// When FEATURE_MULTIREG_ARGS is defined we can get here with GT_OBJ tree. -// This happens when we have a struct that is passed in multiple registers. -// -// Also note that when UNIX_AMD64_ABI is defined the GT_LDOBJ -// later gets converted to a GT_FIELD_LIST with two GT_LCL_FLDs in Lower/LowerXArch. -// -GenTree** GenTree::gtGetChildPointer(GenTree* parent) const -{ - // TODO-List-Cleanup: remove, use TryGetUse instead. - switch (parent->OperGet()) - { - default: - if (!parent->OperIsSimple()) - { - return nullptr; - } - if (this == parent->AsOp()->gtOp1) - { - return &(parent->AsOp()->gtOp1); - } - if (this == parent->AsOp()->gtOp2) - { - return &(parent->AsOp()->gtOp2); - } - break; - - case GT_PHI: - for (GenTreePhi::Use& use : parent->AsPhi()->Uses()) - { - if (use.GetNode() == this) - { - return &use.NodeRef(); - } - } - break; - - case GT_FIELD_LIST: - for (GenTreeFieldList::Use& use : parent->AsFieldList()->Uses()) - { - if (this == use.GetNode()) - { - return &use.NodeRef(); - } - } - break; - - case GT_CMPXCHG: - if (this == parent->AsCmpXchg()->gtOpLocation) - { - return &(parent->AsCmpXchg()->gtOpLocation); - } - if (this == parent->AsCmpXchg()->gtOpValue) - { - return &(parent->AsCmpXchg()->gtOpValue); - } - if (this == parent->AsCmpXchg()->gtOpComparand) - { - return &(parent->AsCmpXchg()->gtOpComparand); - } - break; - - case GT_ARR_ELEM: - if (this == parent->AsArrElem()->gtArrObj) - { - return &(parent->AsArrElem()->gtArrObj); - } - for (int i = 0; i < GT_ARR_MAX_RANK; i++) - { - if (this == parent->AsArrElem()->gtArrInds[i]) - { - return &(parent->AsArrElem()->gtArrInds[i]); - } - } - break; - - case GT_ARR_OFFSET: - if (this == parent->AsArrOffs()->gtOffset) - { - return &(parent->AsArrOffs()->gtOffset); - } - if (this == parent->AsArrOffs()->gtIndex) - { - return &(parent->AsArrOffs()->gtIndex); - } - if (this == parent->AsArrOffs()->gtArrObj) - { - return &(parent->AsArrOffs()->gtArrObj); - } - break; - - case GT_STORE_DYN_BLK: - case GT_DYN_BLK: - if (this == parent->AsDynBlk()->gtOp1) - { - return &(parent->AsDynBlk()->gtOp1); - } - if (this == parent->AsDynBlk()->gtOp2) - { - return &(parent->AsDynBlk()->gtOp2); - } - if (this == parent->AsDynBlk()->gtDynamicSize) - { - return &(parent->AsDynBlk()->gtDynamicSize); - } - break; - - case GT_RET_EXPR: - if (this == parent->AsRetExpr()->gtInlineCandidate) - { - return &(parent->AsRetExpr()->gtInlineCandidate); - } - break; - - case GT_CALL: - { - GenTreeCall* call = parent->AsCall(); - - if ((call->gtCallThisArg != nullptr) && (this == call->gtCallThisArg->GetNode())) - { - return &call->gtCallThisArg->NodeRef(); - } - for (GenTreeCall::Use& use : call->Args()) - { - if (this == use.GetNode()) - { - return &use.NodeRef(); - } - } - for (GenTreeCall::Use& use : call->LateArgs()) - { - if (this == use.GetNode()) - { - return &use.NodeRef(); - } - } - if (this == call->gtControlExpr) - { - return &(call->gtControlExpr); - } - if (call->gtCallType == CT_INDIRECT) - { - if (this == call->gtCallCookie) - { - return &(call->gtCallCookie); - } - if (this == call->gtCallAddr) - { - return &(call->gtCallAddr); - } - } - } - break; - -#if defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS) -#if defined(FEATURE_SIMD) - case GT_SIMD: -#endif -#if defined(FEATURE_HW_INTRINSICS) - case GT_HWINTRINSIC: -#endif - for (GenTree** use : parent->AsMultiOp()->UseEdges()) - { - if (this == *use) - { - return use; - } - } - break; -#endif // defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS) - } - - return nullptr; -} - -bool GenTree::TryGetUse(GenTree* def, GenTree*** use) +bool GenTree::TryGetUse(GenTree* def, GenTree*** pUse) { assert(def != nullptr); - assert(use != nullptr); + assert(pUse != nullptr); switch (OperGet()) { @@ -5254,7 +5075,7 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** use) case GT_INC_SATURATE: if (def == this->AsUnOp()->gtOp1) { - *use = &this->AsUnOp()->gtOp1; + *pUse = &this->AsUnOp()->gtOp1; return true; } return false; @@ -5264,11 +5085,11 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** use) case GT_PUTARG_SPLIT: if (this->AsUnOp()->gtOp1->gtOper == GT_FIELD_LIST) { - return this->AsUnOp()->gtOp1->TryGetUse(def, use); + return this->AsUnOp()->gtOp1->TryGetUse(def, pUse); } if (def == this->AsUnOp()->gtOp1) { - *use = &this->AsUnOp()->gtOp1; + *pUse = &this->AsUnOp()->gtOp1; return true; } return false; @@ -5285,7 +5106,7 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** use) { if (*opUse == def) { - *use = opUse; + *pUse = opUse; return true; } } @@ -5298,7 +5119,7 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** use) { if (phiUse.GetNode() == def) { - *use = &phiUse.NodeRef(); + *pUse = &phiUse.NodeRef(); return true; } } @@ -5309,7 +5130,7 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** use) { if (fieldUse.GetNode() == def) { - *use = &fieldUse.NodeRef(); + *pUse = &fieldUse.NodeRef(); return true; } } @@ -5320,17 +5141,17 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** use) GenTreeCmpXchg* const cmpXchg = this->AsCmpXchg(); if (def == cmpXchg->gtOpLocation) { - *use = &cmpXchg->gtOpLocation; + *pUse = &cmpXchg->gtOpLocation; return true; } if (def == cmpXchg->gtOpValue) { - *use = &cmpXchg->gtOpValue; + *pUse = &cmpXchg->gtOpValue; return true; } if (def == cmpXchg->gtOpComparand) { - *use = &cmpXchg->gtOpComparand; + *pUse = &cmpXchg->gtOpComparand; return true; } return false; @@ -5341,14 +5162,14 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** use) GenTreeArrElem* const arrElem = this->AsArrElem(); if (def == arrElem->gtArrObj) { - *use = &arrElem->gtArrObj; + *pUse = &arrElem->gtArrObj; return true; } for (unsigned i = 0; i < arrElem->gtArrRank; i++) { if (def == arrElem->gtArrInds[i]) { - *use = &arrElem->gtArrInds[i]; + *pUse = &arrElem->gtArrInds[i]; return true; } } @@ -5360,17 +5181,17 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** use) GenTreeArrOffs* const arrOffs = this->AsArrOffs(); if (def == arrOffs->gtOffset) { - *use = &arrOffs->gtOffset; + *pUse = &arrOffs->gtOffset; return true; } if (def == arrOffs->gtIndex) { - *use = &arrOffs->gtIndex; + *pUse = &arrOffs->gtIndex; return true; } if (def == arrOffs->gtArrObj) { - *use = &arrOffs->gtArrObj; + *pUse = &arrOffs->gtArrObj; return true; } return false; @@ -5381,12 +5202,12 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** use) GenTreeDynBlk* const dynBlock = this->AsDynBlk(); if (def == dynBlock->gtOp1) { - *use = &dynBlock->gtOp1; + *pUse = &dynBlock->gtOp1; return true; } if (def == dynBlock->gtDynamicSize) { - *use = &dynBlock->gtDynamicSize; + *pUse = &dynBlock->gtDynamicSize; return true; } return false; @@ -5397,17 +5218,17 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** use) GenTreeDynBlk* const dynBlock = this->AsDynBlk(); if (def == dynBlock->gtOp1) { - *use = &dynBlock->gtOp1; + *pUse = &dynBlock->gtOp1; return true; } if (def == dynBlock->gtOp2) { - *use = &dynBlock->gtOp2; + *pUse = &dynBlock->gtOp2; return true; } if (def == dynBlock->gtDynamicSize) { - *use = &dynBlock->gtDynamicSize; + *pUse = &dynBlock->gtDynamicSize; return true; } return false; @@ -5418,24 +5239,24 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** use) GenTreeCall* const call = this->AsCall(); if ((call->gtCallThisArg != nullptr) && (def == call->gtCallThisArg->GetNode())) { - *use = &call->gtCallThisArg->NodeRef(); + *pUse = &call->gtCallThisArg->NodeRef(); return true; } if (def == call->gtControlExpr) { - *use = &call->gtControlExpr; + *pUse = &call->gtControlExpr; return true; } if (call->gtCallType == CT_INDIRECT) { if (def == call->gtCallCookie) { - *use = &call->gtCallCookie; + *pUse = &call->gtCallCookie; return true; } if (def == call->gtCallAddr) { - *use = &call->gtCallAddr; + *pUse = &call->gtCallAddr; return true; } } @@ -5443,7 +5264,7 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** use) { if (argUse.GetNode() == def) { - *use = &argUse.NodeRef(); + *pUse = &argUse.NodeRef(); return true; } } @@ -5451,7 +5272,7 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** use) { if (argUse.GetNode() == def) { - *use = &argUse.NodeRef(); + *pUse = &argUse.NodeRef(); return true; } } @@ -5461,25 +5282,25 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** use) // Binary nodes default: assert(this->OperIsBinary()); - return TryGetUseBinOp(def, use); + return TryGetUseBinOp(def, pUse); } } -bool GenTree::TryGetUseBinOp(GenTree* def, GenTree*** use) +bool GenTree::TryGetUseBinOp(GenTree* def, GenTree*** pUse) { assert(def != nullptr); - assert(use != nullptr); + assert(pUse != nullptr); assert(this->OperIsBinary()); GenTreeOp* const binOp = this->AsOp(); if (def == binOp->gtOp1) { - *use = &binOp->gtOp1; + *pUse = &binOp->gtOp1; return true; } if (def == binOp->gtOp2) { - *use = &binOp->gtOp2; + *pUse = &binOp->gtOp2; return true; } return false; @@ -5516,37 +5337,38 @@ void GenTree::ReplaceOperand(GenTree** useEdge, GenTree* replacement) // pointer to the child so that it can be modified. // // Arguments: -// parentChildPointer - A pointer to a GenTree** (yes, that's three -// levels, i.e. GenTree ***), which if non-null, -// will be set to point to the field in the parent -// that points to this node. +// pUse - A pointer to a GenTree** (yes, that's three +// levels, i.e. GenTree ***), which if non-null, +// will be set to point to the field in the parent +// that points to this node. // -// Return value - The parent of this node. -// -// Notes: +// Return value +// The parent of this node. // +// Notes: // This requires that the execution order must be defined (i.e. gtSetEvalOrder() has been called). -// To enable the child to be replaced, it accepts an argument, parentChildPointer that, if non-null, +// To enable the child to be replaced, it accepts an argument, "pUse", that, if non-null, // will be set to point to the child pointer in the parent that points to this node. - -GenTree* GenTree::gtGetParent(GenTree*** parentChildPtrPtr) const +// +GenTree* GenTree::gtGetParent(GenTree*** pUse) { // Find the parent node; it must be after this node in the execution order. - GenTree** parentChildPtr = nullptr; - GenTree* parent; - for (parent = gtNext; parent != nullptr; parent = parent->gtNext) + GenTree* user; + GenTree** use = nullptr; + for (user = gtNext; user != nullptr; user = user->gtNext) { - parentChildPtr = gtGetChildPointer(parent); - if (parentChildPtr != nullptr) + if (user->TryGetUse(this, &use)) { break; } } - if (parentChildPtrPtr != nullptr) + + if (pUse != nullptr) { - *parentChildPtrPtr = parentChildPtr; + *pUse = use; } - return parent; + + return user; } //------------------------------------------------------------------------- diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 8ca83d21bc1b4..e408a285a9ec7 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -1770,20 +1770,19 @@ struct GenTree // The returned pointer might be nullptr if the node is not binary, or if non-null op2 is not required. inline GenTree* gtGetOp2IfPresent() const; - // Given a tree node, if this is a child of that node, return the pointer to the child node so that it - // can be modified; otherwise, return null. - GenTree** gtGetChildPointer(GenTree* parent) const; + bool TryGetUse(GenTree* def, GenTree*** pUse); - // Given a tree node, if this node uses that node, return the use as an out parameter and return true. - // Otherwise, return false. - bool TryGetUse(GenTree* def, GenTree*** use); + bool TryGetUse(GenTree* def) + { + GenTree** unusedUse = nullptr; + return TryGetUse(def, &unusedUse); + } private: - bool TryGetUseBinOp(GenTree* def, GenTree*** use); + bool TryGetUseBinOp(GenTree* def, GenTree*** pUse); public: - // Get the parent of this node, and optionally capture the pointer to the child so that it can be modified. - GenTree* gtGetParent(GenTree*** parentChildPtrPtr) const; + GenTree* gtGetParent(GenTree*** use); void ReplaceOperand(GenTree** useEdge, GenTree* replacement); From a41635e6fe4c1b5d43154bf6d21aef8f0f9693f3 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Sun, 14 Nov 2021 00:27:16 +0300 Subject: [PATCH 2/5] Delete NumChildren and GetChild In most situations these methods are the wrong thing to call - they are not very efficient by design. Not surprisingly, thus, they were mostly only used in debug code. The few product dependencies were removed and replaced with equivalent alternatives, deduplicating the code. In the process, BasicBlock::firstNode() was removed as it was not used anywhere. --- src/coreclr/jit/block.cpp | 8 - src/coreclr/jit/block.h | 1 - src/coreclr/jit/compiler.cpp | 17 +- src/coreclr/jit/compiler.h | 2 +- src/coreclr/jit/compiler.hpp | 1 + src/coreclr/jit/flowgraph.cpp | 43 ++-- src/coreclr/jit/gentree.cpp | 395 ++-------------------------------- src/coreclr/jit/gentree.h | 15 +- src/coreclr/jit/morph.cpp | 6 +- 9 files changed, 49 insertions(+), 439 deletions(-) diff --git a/src/coreclr/jit/block.cpp b/src/coreclr/jit/block.cpp index 62add7f24dd3f..3dab0a5e0d5b2 100644 --- a/src/coreclr/jit/block.cpp +++ b/src/coreclr/jit/block.cpp @@ -841,14 +841,6 @@ Statement* BasicBlock::lastStmt() const return result; } -//------------------------------------------------------------------------ -// BasicBlock::firstNode: Returns the first node in the block. -// -GenTree* BasicBlock::firstNode() const -{ - return IsLIR() ? GetFirstLIRNode() : Compiler::fgGetFirstNode(firstStmt()->GetRootNode()); -} - //------------------------------------------------------------------------ // BasicBlock::lastNode: Returns the last node in the block. // diff --git a/src/coreclr/jit/block.h b/src/coreclr/jit/block.h index 3b8ecf7f0dacf..2a90e55ab8ddc 100644 --- a/src/coreclr/jit/block.h +++ b/src/coreclr/jit/block.h @@ -1248,7 +1248,6 @@ struct BasicBlock : private LIR::Range return StatementList(FirstNonPhiDef()); } - GenTree* firstNode() const; GenTree* lastNode() const; bool endsWithJmpMethod(Compiler* comp) const; diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index a2b0265a579dd..eb68aaf4d9de4 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -8942,8 +8942,6 @@ BasicBlock* dbBlock; GenTree* dFindTree(GenTree* tree, unsigned id) { - GenTree* child; - if (tree == nullptr) { return nullptr; @@ -8955,18 +8953,13 @@ GenTree* dFindTree(GenTree* tree, unsigned id) return tree; } - unsigned childCount = tree->NumChildren(); - for (unsigned childIndex = 0; childIndex < childCount; childIndex++) - { - child = tree->GetChild(childIndex); + GenTree* child = nullptr; + tree->VisitOperands([&child, id](GenTree* operand) -> GenTree::VisitResult { child = dFindTree(child, id); - if (child != nullptr) - { - return child; - } - } + return (child != nullptr) ? GenTree::VisitResult::Abort : GenTree::VisitResult::Continue; + }); - return nullptr; + return child; } GenTree* dFindTree(unsigned id) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 97b8024b860e6..6de30072ecdf5 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3626,7 +3626,7 @@ class Compiler void gtDispBlockStmts(BasicBlock* block); void gtGetArgMsg(GenTreeCall* call, GenTree* arg, unsigned argNum, char* bufp, unsigned bufLength); void gtGetLateArgMsg(GenTreeCall* call, GenTree* arg, int argNum, char* bufp, unsigned bufLength); - void gtDispArgList(GenTreeCall* call, IndentStack* indentStack); + void gtDispArgList(GenTreeCall* call, GenTree* lastCallOperand, IndentStack* indentStack); void gtDispFieldSeq(FieldSeqNode* pfsn); void gtDispRange(LIR::ReadOnlyRange const& range); diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index 616080be59c12..80c117112c182 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -4254,6 +4254,7 @@ void GenTree::VisitOperands(TVisitor visitor) case GT_BOX: case GT_ALLOCOBJ: case GT_INIT_VAL: + case GT_RUNTIMELOOKUP: case GT_JTRUE: case GT_SWITCH: case GT_NULLCHECK: diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index d99bc4d0be846..1ca11864c1e94 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -4426,32 +4426,29 @@ void Compiler::fgSetBlockOrder(BasicBlock* block) // Return Value: // The first node in execution order, that belongs to tree. // -// Assumptions: -// 'tree' must either be a leaf, or all of its constituent nodes must be contiguous -// in execution order. -// TODO-Cleanup: Add a debug-only method that verifies this. - -/* static */ -GenTree* Compiler::fgGetFirstNode(GenTree* tree) +// Notes: +// This function is only correct for HIR trees. +// +/* static */ GenTree* Compiler::fgGetFirstNode(GenTree* tree) { - GenTree* child = tree; - while (child->NumChildren() > 0) + GenTree* firstNode = tree; + while (true) { - if ((child->OperIsBinary() || child->OperIsMultiOp()) && child->IsReverseOp()) - { - child = child->GetChild(1); - } - else + auto operandsBegin = firstNode->OperandsBegin(); + auto operandsEnd = firstNode->OperandsEnd(); + + if (operandsBegin == operandsEnd) { - child = child->GetChild(0); + break; } + + firstNode = *operandsBegin; } - return child; + + return firstNode; } -/*****************************************************************************/ -/*static*/ -Compiler::fgWalkResult Compiler::fgChkThrowCB(GenTree** pTree, fgWalkData* data) +/*static*/ Compiler::fgWalkResult Compiler::fgChkThrowCB(GenTree** pTree, fgWalkData* data) { GenTree* tree = *pTree; @@ -4493,9 +4490,7 @@ Compiler::fgWalkResult Compiler::fgChkThrowCB(GenTree** pTree, fgWalkData* data) return Compiler::WALK_CONTINUE; } -/*****************************************************************************/ -/*static*/ -Compiler::fgWalkResult Compiler::fgChkLocAllocCB(GenTree** pTree, fgWalkData* data) +/*static*/ Compiler::fgWalkResult Compiler::fgChkLocAllocCB(GenTree** pTree, fgWalkData* data) { GenTree* tree = *pTree; @@ -4507,9 +4502,7 @@ Compiler::fgWalkResult Compiler::fgChkLocAllocCB(GenTree** pTree, fgWalkData* da return Compiler::WALK_CONTINUE; } -/*****************************************************************************/ -/*static*/ -Compiler::fgWalkResult Compiler::fgChkQmarkCB(GenTree** pTree, fgWalkData* data) +/*static*/ Compiler::fgWalkResult Compiler::fgChkQmarkCB(GenTree** pTree, fgWalkData* data) { GenTree* tree = *pTree; diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 2cfedd817cec8..10b0ff66783fc 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -8274,15 +8274,10 @@ void Compiler::gtUpdateNodeOperSideEffectsPost(GenTree* tree) void Compiler::gtUpdateNodeSideEffects(GenTree* tree) { gtUpdateNodeOperSideEffects(tree); - unsigned nChildren = tree->NumChildren(); - for (unsigned childNum = 0; childNum < nChildren; childNum++) - { - GenTree* child = tree->GetChild(childNum); - if (child != nullptr) - { - tree->gtFlags |= (child->gtFlags & GTF_ALL_EFFECT); - } - } + tree->VisitOperands([tree](GenTree* operand) -> GenTree::VisitResult { + tree->gtFlags |= (operand->gtFlags & GTF_ALL_EFFECT); + return GenTree::VisitResult::Continue; + }); } //------------------------------------------------------------------------ @@ -8448,360 +8443,6 @@ bool GenTree::gtRequestSetFlags() return result; } -// TODO-List-Cleanup: remove. -unsigned GenTree::NumChildren() -{ - if (OperIsConst() || OperIsLeaf()) - { - return 0; - } - else if (OperIsUnary()) - { - if (AsUnOp()->gtOp1 == nullptr) - { - return 0; - } - else - { - return 1; - } - } - else if (OperIsBinary()) - { - // All binary operators except LEA have at least one arg; the second arg may sometimes be null, however. - if (OperGet() == GT_LEA) - { - unsigned childCount = 0; - if (AsOp()->gtOp1 != nullptr) - { - childCount++; - } - if (AsOp()->gtOp2 != nullptr) - { - childCount++; - } - return childCount; - } -#ifdef FEATURE_HW_INTRINSICS - // GT_HWINTRINSIC require special handling - if (OperGet() == GT_HWINTRINSIC) - { - if (AsOp()->gtOp1 == nullptr) - { - return 0; - } - } -#endif - assert(AsOp()->gtOp1 != nullptr); - if (AsOp()->gtOp2 == nullptr) - { - return 1; - } - else - { - return 2; - } - } - else - { - // Special - switch (OperGet()) - { - case GT_PHI: - { - unsigned count = 0; - for (GenTreePhi::Use& use : AsPhi()->Uses()) - { - count++; - } - return count; - } - - case GT_FIELD_LIST: - { - unsigned count = 0; - for (GenTreeFieldList::Use& use : AsFieldList()->Uses()) - { - count++; - } - return count; - } - - case GT_CMPXCHG: - return 3; - - case GT_ARR_ELEM: - return 1 + AsArrElem()->gtArrRank; - - case GT_DYN_BLK: - return 2; - - case GT_ARR_OFFSET: - case GT_STORE_DYN_BLK: - return 3; - - case GT_CALL: - { - GenTreeCall* call = AsCall(); - unsigned res = 0; - if (call->gtCallThisArg != nullptr) - { - res++; - } - for (GenTreeCall::Use& use : call->Args()) - { - res++; - } - for (GenTreeCall::Use& use : call->LateArgs()) - { - res++; - } - if (call->gtControlExpr != nullptr) - { - res++; - } - - if (call->gtCallType == CT_INDIRECT) - { - if (call->gtCallCookie != nullptr) - { - res++; - } - if (call->gtCallAddr != nullptr) - { - res++; - } - } - return res; - } - -#if defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS) -#if defined(FEATURE_SIMD) - case GT_SIMD: -#endif -#if defined(FEATURE_HW_INTRINSICS) - case GT_HWINTRINSIC: -#endif - return static_cast(AsMultiOp()->GetOperandCount()); -#endif // defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS) - - case GT_NONE: - return 0; - default: - unreached(); - } - } -} - -// TODO-List-Cleanup: remove. -GenTree* GenTree::GetChild(unsigned childNum) -{ - assert(childNum < NumChildren()); // Precondition. - assert(!(OperIsConst() || OperIsLeaf())); - if (OperIsUnary()) - { - return AsUnOp()->gtOp1; - } - // Special case for assignment of dynamic block. - // This code is here to duplicate the former case where the size may be evaluated prior to the - // source and destination addresses. In order to do this, we treat the size as a child of the - // assignment. - // TODO-1stClassStructs: Revisit the need to duplicate former behavior, so that we can remove - // these special cases. - if ((OperGet() == GT_ASG) && (AsOp()->gtOp1->OperGet() == GT_DYN_BLK) && (childNum == 2)) - { - return AsOp()->gtOp1->AsDynBlk()->gtDynamicSize; - } - else if (OperIsBinary()) - { - if (OperIsAddrMode()) - { - // If this is the first (0th) child, only return op1 if it is non-null - // Otherwise, we return gtOp2. - if (childNum == 0 && AsOp()->gtOp1 != nullptr) - { - return AsOp()->gtOp1; - } - return AsOp()->gtOp2; - } - // TODO-Cleanup: Consider handling ReverseOps here, and then we wouldn't have to handle it in - // fgGetFirstNode(). However, it seems that it causes loop hoisting behavior to change. - if (childNum == 0) - { - return AsOp()->gtOp1; - } - else - { - return AsOp()->gtOp2; - } - } - else - { - // Special - switch (OperGet()) - { - case GT_PHI: - for (GenTreePhi::Use& use : AsPhi()->Uses()) - { - if (childNum == 0) - { - return use.GetNode(); - } - childNum--; - } - unreached(); - - case GT_FIELD_LIST: - for (GenTreeFieldList::Use& use : AsFieldList()->Uses()) - { - if (childNum == 0) - { - return use.GetNode(); - } - childNum--; - } - unreached(); - - case GT_CMPXCHG: - switch (childNum) - { - case 0: - return AsCmpXchg()->gtOpLocation; - case 1: - return AsCmpXchg()->gtOpValue; - case 2: - return AsCmpXchg()->gtOpComparand; - default: - unreached(); - } - - case GT_STORE_DYN_BLK: - switch (childNum) - { - case 0: - return AsDynBlk()->Addr(); - case 1: - return AsDynBlk()->Data(); - case 2: - return AsDynBlk()->gtDynamicSize; - default: - unreached(); - } - case GT_DYN_BLK: - switch (childNum) - { - case 0: - return AsDynBlk()->gtEvalSizeFirst ? AsDynBlk()->gtDynamicSize : AsDynBlk()->Addr(); - case 1: - return AsDynBlk()->gtEvalSizeFirst ? AsDynBlk()->Addr() : AsDynBlk()->gtDynamicSize; - default: - unreached(); - } - - case GT_ARR_ELEM: - if (childNum == 0) - { - return AsArrElem()->gtArrObj; - } - else - { - return AsArrElem()->gtArrInds[childNum - 1]; - } - - case GT_ARR_OFFSET: - switch (childNum) - { - case 0: - return AsArrOffs()->gtOffset; - case 1: - return AsArrOffs()->gtIndex; - case 2: - return AsArrOffs()->gtArrObj; - default: - unreached(); - } - - case GT_CALL: - { - GenTreeCall* call = AsCall(); - - if (call->gtCallThisArg != nullptr) - { - if (childNum == 0) - { - return call->gtCallThisArg->GetNode(); - } - - childNum--; - } - - for (GenTreeCall::Use& use : call->Args()) - { - if (childNum == 0) - { - return use.GetNode(); - } - - childNum--; - } - - for (GenTreeCall::Use& use : call->LateArgs()) - { - if (childNum == 0) - { - return use.GetNode(); - } - - childNum--; - } - - if (call->gtControlExpr != nullptr) - { - if (childNum == 0) - { - return call->gtControlExpr; - } - - childNum--; - } - - if ((call->gtCallType == CT_INDIRECT) && (call->gtCallCookie != nullptr)) - { - if (childNum == 0) - { - return call->gtCallCookie; - } - - childNum--; - } - - if (call->gtCallAddr != nullptr) - { - if (childNum == 0) - { - return call->gtCallAddr; - } - } - - unreached(); - } - -#if defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS) -#if defined(FEATURE_SIMD) - case GT_SIMD: -#endif -#if defined(FEATURE_HW_INTRINSICS) - case GT_HWINTRINSIC: -#endif - return AsMultiOp()->Op(childNum + 1); -#endif // defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS) - - default: - unreached(); - } - } -} - GenTreeUseEdgeIterator::GenTreeUseEdgeIterator() : m_advance(nullptr), m_node(nullptr), m_edge(nullptr), m_statePtr(nullptr), m_state(-1) { @@ -11562,14 +11203,12 @@ void Compiler::gtDispTree(GenTree* tree, case GT_CALL: { - GenTreeCall* call = tree->AsCall(); - assert(call->gtFlags & GTF_CALL); - unsigned numChildren = call->NumChildren(); - GenTree* lastChild = nullptr; - if (numChildren != 0) - { - lastChild = call->GetChild(numChildren - 1); - } + GenTreeCall* call = tree->AsCall(); + GenTree* lastChild = nullptr; + call->VisitOperands([&lastChild](GenTree* operand) -> GenTree::VisitResult { + lastChild = operand; + return GenTree::VisitResult::Continue; + }); if (call->gtCallType != CT_INDIRECT) { @@ -11617,7 +11256,7 @@ void Compiler::gtDispTree(GenTree* tree, if (call->gtCallArgs) { - gtDispArgList(call, indentStack); + gtDispArgList(call, lastChild, indentStack); } if (call->gtCallType == CT_INDIRECT) @@ -11913,17 +11552,15 @@ void Compiler::gtGetLateArgMsg(GenTreeCall* call, GenTree* argx, int lateArgInde // gtDispArgList: Dump the tree for a call arg list // // Arguments: -// call - The call to dump arguments for -// indentStack - the specification for the current level of indentation & arcs +// call - the call to dump arguments for +// lastCallOperand - the call's last operand (to determine the arc types) +// indentStack - the specification for the current level of indentation & arcs // // Return Value: // None. // -void Compiler::gtDispArgList(GenTreeCall* call, IndentStack* indentStack) +void Compiler::gtDispArgList(GenTreeCall* call, GenTree* lastCallOperand, IndentStack* indentStack) { - unsigned numChildren = call->NumChildren(); - GenTree* lastArgNode = call->GetChild(numChildren - 1); - unsigned argnum = 0; if (call->gtCallThisArg != nullptr) @@ -11938,7 +11575,7 @@ void Compiler::gtDispArgList(GenTreeCall* call, IndentStack* indentStack) { char buf[256]; gtGetArgMsg(call, argNode, argnum, buf, sizeof(buf)); - gtDispChild(argNode, indentStack, (argNode == lastArgNode) ? IIArcBottom : IIArc, buf, false); + gtDispChild(argNode, indentStack, (argNode == lastCallOperand) ? IIArcBottom : IIArc, buf, false); } argnum++; } diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index e408a285a9ec7..50cd3e3c635b3 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -2236,12 +2236,6 @@ struct GenTree { } - // Returns the number of children of the current node. - unsigned NumChildren(); - - // Requires "childNum < NumChildren()". Returns the "n"th child of "this." - GenTree* GetChild(unsigned childNum); - // Returns an iterator that will produce the use edge to each operand of this node. Differs // from the sequence of nodes produced by a loop over `GetChild` in its handling of call, phi, // and block op nodes. @@ -2250,13 +2244,11 @@ struct GenTree IteratorPair UseEdges(); - // Returns an iterator that will produce each operand of this node. Differs from the sequence - // of nodes produced by a loop over `GetChild` in its handling of call, phi, and block op - // nodes. + // Returns an iterator that will produce each operand of this node, in execution order. GenTreeOperandIterator OperandsBegin(); GenTreeOperandIterator OperandsEnd(); - // Returns a range that will produce the operands of this node in use order. + // Returns a range that will produce the operands of this node in execution order. IteratorPair Operands(); enum class VisitResult @@ -2871,8 +2863,7 @@ class GenTreeUseEdgeIterator final // GenTreeOperandIterator: an iterator that will produce each operand of a // GenTree node in the order in which they are // used. This uses `GenTreeUseEdgeIterator` under -// the covers and comes with the same caveats -// w.r.t. `GetChild`. +// the covers. // // Note: valid values of this type may be obtained by calling // `GenTree::OperandsBegin` and `GenTree::OperandsEnd`. diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 53a4c29bc6667..dfdb53d213177 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -2704,7 +2704,11 @@ void Compiler::fgInitArgInfo(GenTreeCall* call) GenTreeCall::Use* nodeArgs = call->gtCallArgs; // It could include many arguments not included in `sig->numArgs`, for example, `this`, runtime lookup, cookie // etc. - unsigned nodeArgsCount = call->NumChildren(); + unsigned nodeArgsCount = 0; + call->VisitOperands([&nodeArgsCount](GenTree* operand) -> GenTree::VisitResult { + nodeArgsCount++; + return GenTree::VisitResult::Continue; + }); if (call->gtCallThisArg != nullptr) { From 2aba97e79e9ceb462ecb5ae1437902ff3d835156 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Wed, 24 Nov 2021 12:11:05 +0300 Subject: [PATCH 3/5] Rename 'def' -> 'operand' --- src/coreclr/jit/gentree.cpp | 68 ++++++++++++++++++------------------- src/coreclr/jit/gentree.h | 8 ++--- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 10b0ff66783fc..4fbf1390cbca3 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -4986,19 +4986,19 @@ unsigned GenTree::GetScaledIndex() } //------------------------------------------------------------------------ -// TryGetUse: Get the def -> def edge for a child of this tree. +// TryGetUse: Get the use edge for an operand of this tree. // // Arguments: -// def - the node to find the use for -// pUse - [out] parameter for the use +// operand - the node to find the use for +// pUse - [out] parameter for the use // // Return Value: -// Whether "def" is a child of this node. If it is, "*pUse" is set, -// allowing for the replacement of "def" with some other node. +// Whether "operand" is a child of this node. If it is, "*pUse" is set, +// allowing for the replacement of "operand" with some other node. // -bool GenTree::TryGetUse(GenTree* def, GenTree*** pUse) +bool GenTree::TryGetUse(GenTree* operand, GenTree*** pUse) { - assert(def != nullptr); + assert(operand != nullptr); assert(pUse != nullptr); switch (OperGet()) @@ -5073,7 +5073,7 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** pUse) case GT_BSWAP16: case GT_KEEPALIVE: case GT_INC_SATURATE: - if (def == this->AsUnOp()->gtOp1) + if (operand == this->AsUnOp()->gtOp1) { *pUse = &this->AsUnOp()->gtOp1; return true; @@ -5117,7 +5117,7 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** pUse) case GT_PHI: for (GenTreePhi::Use& phiUse : AsPhi()->Uses()) { - if (phiUse.GetNode() == def) + if (phiUse.GetNode() == operand) { *pUse = &phiUse.NodeRef(); return true; @@ -5128,7 +5128,7 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** pUse) case GT_FIELD_LIST: for (GenTreeFieldList::Use& fieldUse : AsFieldList()->Uses()) { - if (fieldUse.GetNode() == def) + if (fieldUse.GetNode() == operand) { *pUse = &fieldUse.NodeRef(); return true; @@ -5139,17 +5139,17 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** pUse) case GT_CMPXCHG: { GenTreeCmpXchg* const cmpXchg = this->AsCmpXchg(); - if (def == cmpXchg->gtOpLocation) + if (operand == cmpXchg->gtOpLocation) { *pUse = &cmpXchg->gtOpLocation; return true; } - if (def == cmpXchg->gtOpValue) + if (operand == cmpXchg->gtOpValue) { *pUse = &cmpXchg->gtOpValue; return true; } - if (def == cmpXchg->gtOpComparand) + if (operand == cmpXchg->gtOpComparand) { *pUse = &cmpXchg->gtOpComparand; return true; @@ -5160,14 +5160,14 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** pUse) case GT_ARR_ELEM: { GenTreeArrElem* const arrElem = this->AsArrElem(); - if (def == arrElem->gtArrObj) + if (operand == arrElem->gtArrObj) { *pUse = &arrElem->gtArrObj; return true; } for (unsigned i = 0; i < arrElem->gtArrRank; i++) { - if (def == arrElem->gtArrInds[i]) + if (operand == arrElem->gtArrInds[i]) { *pUse = &arrElem->gtArrInds[i]; return true; @@ -5179,17 +5179,17 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** pUse) case GT_ARR_OFFSET: { GenTreeArrOffs* const arrOffs = this->AsArrOffs(); - if (def == arrOffs->gtOffset) + if (operand == arrOffs->gtOffset) { *pUse = &arrOffs->gtOffset; return true; } - if (def == arrOffs->gtIndex) + if (operand == arrOffs->gtIndex) { *pUse = &arrOffs->gtIndex; return true; } - if (def == arrOffs->gtArrObj) + if (operand == arrOffs->gtArrObj) { *pUse = &arrOffs->gtArrObj; return true; @@ -5200,12 +5200,12 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** pUse) case GT_DYN_BLK: { GenTreeDynBlk* const dynBlock = this->AsDynBlk(); - if (def == dynBlock->gtOp1) + if (operand == dynBlock->gtOp1) { *pUse = &dynBlock->gtOp1; return true; } - if (def == dynBlock->gtDynamicSize) + if (operand == dynBlock->gtDynamicSize) { *pUse = &dynBlock->gtDynamicSize; return true; @@ -5216,17 +5216,17 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** pUse) case GT_STORE_DYN_BLK: { GenTreeDynBlk* const dynBlock = this->AsDynBlk(); - if (def == dynBlock->gtOp1) + if (operand == dynBlock->gtOp1) { *pUse = &dynBlock->gtOp1; return true; } - if (def == dynBlock->gtOp2) + if (operand == dynBlock->gtOp2) { *pUse = &dynBlock->gtOp2; return true; } - if (def == dynBlock->gtDynamicSize) + if (operand == dynBlock->gtDynamicSize) { *pUse = &dynBlock->gtDynamicSize; return true; @@ -5237,24 +5237,24 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** pUse) case GT_CALL: { GenTreeCall* const call = this->AsCall(); - if ((call->gtCallThisArg != nullptr) && (def == call->gtCallThisArg->GetNode())) + if ((call->gtCallThisArg != nullptr) && (operand == call->gtCallThisArg->GetNode())) { *pUse = &call->gtCallThisArg->NodeRef(); return true; } - if (def == call->gtControlExpr) + if (operand == call->gtControlExpr) { *pUse = &call->gtControlExpr; return true; } if (call->gtCallType == CT_INDIRECT) { - if (def == call->gtCallCookie) + if (operand == call->gtCallCookie) { *pUse = &call->gtCallCookie; return true; } - if (def == call->gtCallAddr) + if (operand == call->gtCallAddr) { *pUse = &call->gtCallAddr; return true; @@ -5262,7 +5262,7 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** pUse) } for (GenTreeCall::Use& argUse : call->Args()) { - if (argUse.GetNode() == def) + if (argUse.GetNode() == operand) { *pUse = &argUse.NodeRef(); return true; @@ -5270,7 +5270,7 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** pUse) } for (GenTreeCall::Use& argUse : call->LateArgs()) { - if (argUse.GetNode() == def) + if (argUse.GetNode() == operand) { *pUse = &argUse.NodeRef(); return true; @@ -5282,23 +5282,23 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** pUse) // Binary nodes default: assert(this->OperIsBinary()); - return TryGetUseBinOp(def, pUse); + return TryGetUseBinOp(operand, pUse); } } -bool GenTree::TryGetUseBinOp(GenTree* def, GenTree*** pUse) +bool GenTree::TryGetUseBinOp(GenTree* operand, GenTree*** pUse) { - assert(def != nullptr); + assert(operand != nullptr); assert(pUse != nullptr); assert(this->OperIsBinary()); GenTreeOp* const binOp = this->AsOp(); - if (def == binOp->gtOp1) + if (operand == binOp->gtOp1) { *pUse = &binOp->gtOp1; return true; } - if (def == binOp->gtOp2) + if (operand == binOp->gtOp2) { *pUse = &binOp->gtOp2; return true; diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 50cd3e3c635b3..0ddec9783a31c 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -1770,19 +1770,19 @@ struct GenTree // The returned pointer might be nullptr if the node is not binary, or if non-null op2 is not required. inline GenTree* gtGetOp2IfPresent() const; - bool TryGetUse(GenTree* def, GenTree*** pUse); + bool TryGetUse(GenTree* operand, GenTree*** pUse); - bool TryGetUse(GenTree* def) + bool TryGetUse(GenTree* operand) { GenTree** unusedUse = nullptr; return TryGetUse(def, &unusedUse); } private: - bool TryGetUseBinOp(GenTree* def, GenTree*** pUse); + bool TryGetUseBinOp(GenTree* operand, GenTree*** pUse); public: - GenTree* gtGetParent(GenTree*** use); + GenTree* gtGetParent(GenTree*** pUse); void ReplaceOperand(GenTree** useEdge, GenTree* replacement); From e73e2a3d5f23b76eb168d11ccba39587befab101 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Wed, 24 Nov 2021 12:30:42 +0300 Subject: [PATCH 4/5] A few forgotten pieces --- src/coreclr/jit/gentree.cpp | 4 ++-- src/coreclr/jit/gentree.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 4fbf1390cbca3..0240d7b5b6567 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -5087,7 +5087,7 @@ bool GenTree::TryGetUse(GenTree* operand, GenTree*** pUse) { return this->AsUnOp()->gtOp1->TryGetUse(def, pUse); } - if (def == this->AsUnOp()->gtOp1) + if (operand == this->AsUnOp()->gtOp1) { *pUse = &this->AsUnOp()->gtOp1; return true; @@ -5104,7 +5104,7 @@ bool GenTree::TryGetUse(GenTree* operand, GenTree*** pUse) #endif for (GenTree** opUse : this->AsMultiOp()->UseEdges()) { - if (*opUse == def) + if (*opUse == operand) { *pUse = opUse; return true; diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 0ddec9783a31c..e241dbbb678f2 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -1775,7 +1775,7 @@ struct GenTree bool TryGetUse(GenTree* operand) { GenTree** unusedUse = nullptr; - return TryGetUse(def, &unusedUse); + return TryGetUse(operand, &unusedUse); } private: From fbce9ae320fb7a1795ec4ba86cc2cbeeb58840e1 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Wed, 24 Nov 2021 12:50:25 +0300 Subject: [PATCH 5/5] One more --- src/coreclr/jit/gentree.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 0240d7b5b6567..0c57d65696267 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -5085,7 +5085,7 @@ bool GenTree::TryGetUse(GenTree* operand, GenTree*** pUse) case GT_PUTARG_SPLIT: if (this->AsUnOp()->gtOp1->gtOper == GT_FIELD_LIST) { - return this->AsUnOp()->gtOp1->TryGetUse(def, pUse); + return this->AsUnOp()->gtOp1->TryGetUse(operand, pUse); } if (operand == this->AsUnOp()->gtOp1) {