Factor out method to check for a lclVar update tree
authorCarol Eidt <carol.eidt@microsoft.com>
Mon, 6 Jun 2016 21:24:05 +0000 (14:24 -0700)
committerCarol Eidt <carol.eidt@microsoft.com>
Tue, 7 Jun 2016 01:35:27 +0000 (18:35 -0700)
This is functionality currently incorporated in optIsLoopIncrTree(),
but which is also useful for the RyuJIT tutorial.

Commit migrated from https://github.com/dotnet/coreclr/commit/be46c18bb176b255cd8d1e5496ebda8f8ba73ca7

src/coreclr/src/jit/gentree.cpp
src/coreclr/src/jit/gentree.h
src/coreclr/src/jit/optimizer.cpp

index 42ccf2b..0dd5b99 100644 (file)
@@ -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 
index e2b14bf..0e9adab 100644 (file)
@@ -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, 
index d1bce8a..a3f37ae 100644 (file)
@@ -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;