Handle cmp(and(x, y), 0)
authorMike Danes <onemihaid@hotmail.com>
Mon, 19 Dec 2016 21:15:01 +0000 (23:15 +0200)
committerMike Danes <onemihaid@hotmail.com>
Tue, 17 Jan 2017 18:26:27 +0000 (20:26 +0200)
There's no need to require y to be a constant. This restriction was an artifact of the old implementation using containment in lower/codegen to recognize this pattern.

This results in a couple of hundred AND instructions being converted to TEST. This is preferable as TEST can be macro-fused with the conditional branch that may follow it.

Occasionally this also saves a MOV because TEST doesn't update its first operand like AND does.

FX diff shows a 118 bytes improvement without any regressions.

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

src/coreclr/src/jit/lower.cpp
src/coreclr/src/jit/lowerxarch.cpp

index 2aae6ba..53a25b9 100644 (file)
@@ -2082,11 +2082,7 @@ void Lowering::LowerCompare(GenTree* cmp)
                 }
             }
 
-            // TODO-CQ: The second GT_AND operand does not need to be a constant, this is a temporary
-            // restriction to prevent TreeNodeInfoInitCmp creating a contained second memory operand.
-            // Unlike CMP TEST does not have a TEST reg, mem form.
-
-            if (op2Value == 0 && andOp2->IsIntegralConst())
+            if (op2Value == 0)
             {
                 BlockRange().Remove(op1);
                 BlockRange().Remove(op2);
@@ -2095,12 +2091,13 @@ void Lowering::LowerCompare(GenTree* cmp)
                 cmp->gtOp.gtOp1 = andOp1;
                 cmp->gtOp.gtOp2 = andOp2;
 
-                if (andOp1->isMemoryOp() && varTypeIsSmall(andOp1))
+                if (andOp1->isMemoryOp() && andOp2->IsIntegralConst())
                 {
                     // TOOD-CQ: There's more than can be done here. This is just enough to prevent
                     // code size regressions.
 
-                    if (genTypeValueFitsIn(andOp2->AsIntCon()->IconValue(), andOp1->TypeGet()))
+                    if (varTypeIsSmall(andOp1) &&
+                        genTypeValueFitsIn(andOp2->AsIntCon()->IconValue(), andOp1->TypeGet()))
                     {
                         andOp2->gtType = andOp1->TypeGet();
                     }
index 2a2209d..aa615c7 100644 (file)
@@ -3495,6 +3495,9 @@ void Lowering::TreeNodeInfoInitCmp(GenTreePtr tree)
     }
     else if (op1Type == op2Type)
     {
+        // Note that TEST does not have a r,rm encoding like CMP has but we can still
+        // contain the second operand because the emitter maps both r,rm and rm,r to
+        // the same instruction code. This avoids the need to special case TEST here.
         if (op2->isMemoryOp())
         {
             MakeSrcContained(tree, op2);