Move narrowing from TreeNodeInfoInitCmp to LowerCompare
authorMike Danes <onemihaid@hotmail.com>
Sat, 17 Dec 2016 16:28:42 +0000 (18:28 +0200)
committerMike Danes <onemihaid@hotmail.com>
Tue, 17 Jan 2017 18:25:19 +0000 (20:25 +0200)
FX diff shows a 1274 bytes improvement without any regressions. The original code didn't narrow the compare when op2 was 0. Because of this we had

movzx eax, byte ptr [ebx]
test eax, eax

instead of the shorter

cmp byte ptr[ebx], 0

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

index d1ecf7c..41b94c6 100644 (file)
@@ -1989,6 +1989,45 @@ GenTree* Lowering::LowerTailCallViaHelper(GenTreeCall* call, GenTree* callTarget
 //
 void Lowering::LowerCompare(GenTree* cmp)
 {
+#ifdef _TARGET_XARCH_
+    if (cmp->gtGetOp2()->IsIntegralConst())
+    {
+        GenTree*       op1      = cmp->gtGetOp1();
+        var_types      op1Type  = op1->TypeGet();
+        GenTreeIntCon* op2      = cmp->gtGetOp2()->AsIntCon();
+        ssize_t        op2Value = op2->IconValue();
+
+        if (op1->isMemoryOp() && varTypeIsSmallInt(op1Type))
+        {
+            //
+            // If op1's type is small then try to narrow op2 so it has the same type as op1.
+            // Small types are usually used by memory loads and if both compare operands have
+            // the same type then the memory load can be contained. In certain situations
+            // (e.g "cmp ubyte, 200") we also get a smaller instruction encoding.
+            //
+
+            if ((op1Type == TYP_UBYTE) && FitsIn<UINT8>(op2Value))
+            {
+                cmp->gtFlags |= GTF_UNSIGNED;
+                op2->gtType = op1Type;
+            }
+            else if ((op1Type == TYP_BYTE) && FitsIn<INT8>(op2Value))
+            {
+                op2->gtType = op1Type;
+            }
+            else if ((op1Type == TYP_CHAR) && FitsIn<UINT16>(op2Value))
+            {
+                cmp->gtFlags |= GTF_UNSIGNED;
+                op2->gtType = op1Type;
+            }
+            else if ((op1Type == TYP_SHORT) && FitsIn<INT16>(op2Value))
+            {
+                op2->gtType = op1Type;
+            }
+        }
+    }
+#endif // _TARGET_XARCH_
+
 #ifndef _TARGET_64BIT_
     if (cmp->gtGetOp1()->TypeGet() != TYP_LONG)
     {
index 61ab63c..b54e784 100644 (file)
@@ -3448,63 +3448,6 @@ void Lowering::TreeNodeInfoInitCmp(GenTreePtr tree)
         // we can treat the isMemoryOp as contained.
         bool op1CanBeContained = (genTypeSize(op1Type) == genTypeSize(op2Type));
 
-        // Do we have a short compare against a constant in op2
-        //
-        if (varTypeIsSmall(op1Type))
-        {
-            GenTreeIntCon* con  = op2->AsIntCon();
-            ssize_t        ival = con->gtIconVal;
-
-            bool isEqualityCompare = (tree->gtOper == GT_EQ || tree->gtOper == GT_NE);
-            bool useTest           = isEqualityCompare && (ival == 0);
-
-            if (!useTest)
-            {
-                ssize_t lo         = 0; // minimum imm value allowed for cmp reg,imm
-                ssize_t hi         = 0; // maximum imm value allowed for cmp reg,imm
-                bool    isUnsigned = false;
-
-                switch (op1Type)
-                {
-                    case TYP_BOOL:
-                        op1Type = TYP_UBYTE;
-                        __fallthrough;
-                    case TYP_UBYTE:
-                        lo         = 0;
-                        hi         = 0x7f;
-                        isUnsigned = true;
-                        break;
-                    case TYP_BYTE:
-                        lo = -0x80;
-                        hi = 0x7f;
-                        break;
-                    case TYP_CHAR:
-                        lo         = 0;
-                        hi         = 0x7fff;
-                        isUnsigned = true;
-                        break;
-                    case TYP_SHORT:
-                        lo = -0x8000;
-                        hi = 0x7fff;
-                        break;
-                    default:
-                        unreached();
-                }
-
-                if ((ival >= lo) && (ival <= hi))
-                {
-                    // We can perform a small compare with the immediate 'ival'
-                    tree->gtFlags |= GTF_RELOP_SMALL;
-                    if (isUnsigned && !isEqualityCompare)
-                    {
-                        tree->gtFlags |= GTF_UNSIGNED;
-                    }
-                    // We can treat the isMemoryOp as "contained"
-                    op1CanBeContained = true;
-                }
-            }
-        }
-
         if (op1CanBeContained)
         {
             if (op1->isMemoryOp())