From be46c18bb176b255cd8d1e5496ebda8f8ba73ca7 Mon Sep 17 00:00:00 2001 From: Carol Eidt Date: Mon, 6 Jun 2016 14:24:05 -0700 Subject: [PATCH] Factor out method to check for a lclVar update tree This is functionality currently incorporated in optIsLoopIncrTree(), but which is also useful for the RyuJIT tutorial. --- src/jit/gentree.cpp | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/jit/gentree.h | 4 ++++ src/jit/optimizer.cpp | 52 +++++++++--------------------------------------- 3 files changed, 68 insertions(+), 43 deletions(-) diff --git a/src/jit/gentree.cpp b/src/jit/gentree.cpp index 42ccf2b..0dd5b99 100644 --- a/src/jit/gentree.cpp +++ b/src/jit/gentree.cpp @@ -12938,6 +12938,61 @@ bool GenTree::IsLocalAddrExpr(Compiler* comp, GenTreeLclVarCommon** pLclVarTree, return false; } +//------------------------------------------------------------------------ +// IsLclVarUpdateTree: Determine whether this is an assignment tree of the +// form Vn = Vn 'oper' 'otherTree' where Vn is a lclVar +// +// Arguments: +// pOtherTree - An "out" argument in which 'otherTree' will be returned. +// pOper - An "out" argument in which 'oper' will be returned. +// +// Return Value: +// If the tree is of the above form, the lclNum of the variable being +// updated is returned, and 'pOtherTree' and 'pOper' are set. +// Otherwise, returns BAD_VAR_NUM. +// +// Notes: +// 'otherTree' can have any shape. +// We avoid worrying about whether the op is commutative by only considering the +// first operand of the rhs. It is expected that most trees of this form will +// already have the lclVar on the lhs. +// TODO-CQ: Evaluate whether there are missed opportunities due to this, or +// whether gtSetEvalOrder will already have put the lclVar on the lhs in +// the cases of interest. + +unsigned +GenTree::IsLclVarUpdateTree(GenTree** pOtherTree, genTreeOps *pOper) +{ + unsigned lclNum = BAD_VAR_NUM; + if (OperIsAssignment()) + { + GenTree* lhs = gtOp.gtOp1; + if (lhs->OperGet() == GT_LCL_VAR) + { + unsigned lhsLclNum = lhs->AsLclVarCommon()->gtLclNum; + if (gtOper == GT_ASG) + { + GenTree* rhs = gtOp.gtOp2; + if (rhs->OperIsBinary() && + (rhs->gtOp.gtOp1->gtOper == GT_LCL_VAR) && + (rhs->gtOp.gtOp1->AsLclVarCommon()->gtLclNum == lhsLclNum)) + { + lclNum = lhsLclNum; + *pOtherTree = rhs->gtOp.gtOp2; + *pOper = rhs->gtOper; + } + } + else + { + lclNum = lhsLclNum; + *pOper = GenTree::OpAsgToOper(gtOper); + *pOtherTree = gtOp.gtOp2; + } + } + } + return lclNum; +} + // return true if this tree node is a subcomponent of parent for codegen purposes // (essentially, will be rolled into the same instruction) // Note that this method relies upon the value of gtRegNum field to determine diff --git a/src/jit/gentree.h b/src/jit/gentree.h index e2b14bf..0e9adab 100644 --- a/src/jit/gentree.h +++ b/src/jit/gentree.h @@ -1477,6 +1477,10 @@ public: // yields an address into a local GenTreeLclVarCommon* IsLocalAddrExpr(); + // Determine whether this is an assignment tree of the form X = X (op) Y, + // where Y is an arbitrary tree, and X is a lclVar. + unsigned IsLclVarUpdateTree(GenTree** otherTree, genTreeOps *updateOper); + // If returns "true", "this" may represent the address of a static or instance field // (or a field of such a field, in the case of an object field of type struct). // If returns "true", then either "*pObj" is set to the object reference, diff --git a/src/jit/optimizer.cpp b/src/jit/optimizer.cpp index d1bce8a..a3f37ae 100644 --- a/src/jit/optimizer.cpp +++ b/src/jit/optimizer.cpp @@ -856,27 +856,13 @@ bool Compiler::optCheckIterInLoopTest(unsigned loopInd, GenTreePtr test, BasicBl // unsigned Compiler::optIsLoopIncrTree(GenTreePtr incr) { - switch (incr->gtOper) - { - case GT_ASG_ADD: - case GT_ASG_SUB: - case GT_ASG_MUL: - case GT_ASG_RSH: - case GT_ASG_LSH: - case GT_ASG: - break; - default: - return BAD_VAR_NUM; - } - - unsigned iterVar; - GenTreePtr incrVal; - if (incr->gtOper == GT_ASG) + GenTree* incrVal; + genTreeOps updateOper; + unsigned iterVar = incr->IsLclVarUpdateTree(&incrVal, &updateOper); + if (iterVar != BAD_VAR_NUM) { - // We have v = v + 1 type asg node. - GenTreePtr lhs = incr->gtOp.gtOp1; - GenTreePtr rhs = incr->gtOp.gtOp2; - switch (rhs->gtOper) + // We have v = v op y type asg node. + switch (updateOper) { case GT_ADD: case GT_SUB: @@ -887,33 +873,13 @@ unsigned Compiler::optIsLoopIncrTree(GenTreePtr incr) default: return BAD_VAR_NUM; } - GenTreePtr rhsOp1 = rhs->gtOp.gtOp1; - incrVal = rhs->gtOp.gtOp2; - // Make sure lhs and rhs have the right variable numbers. - if (lhs->gtOper != GT_LCL_VAR || rhsOp1->gtOper != GT_LCL_VAR || rhsOp1->gtLclVarCommon.gtLclNum != lhs->gtLclVarCommon.gtLclNum) + // Increment should be by a const int. + // TODO-CQ: CLONE: allow variable increments. + if ((incrVal->gtOper != GT_CNS_INT) || (incrVal->TypeGet() != TYP_INT)) { return BAD_VAR_NUM; } - iterVar = rhsOp1->gtLclVarCommon.gtLclNum; - } - else - { - // We have op= - GenTreePtr lhs = incr->gtOp.gtOp1; - incrVal = incr->gtOp.gtOp2; - if (lhs->gtOper != GT_LCL_VAR) - { - return BAD_VAR_NUM; - } - iterVar = lhs->gtLclVarCommon.gtLclNum; - } - - // Increment should be by a const int. - // TODO-CQ: CLONE: allow variable increments. - if (incrVal->gtOper != GT_CNS_INT || incrVal->TypeGet() != TYP_INT) - { - return BAD_VAR_NUM; } return iterVar; -- 2.7.4