Hi!

This patch handles unsigned narrowing casts the same as
BIT_AND_EXPR with the unsigned narrow type's max value.

Bootstrapped/regtested on x86_64-linux and i686-linux,
ok for trunk?

2012-10-04  Jakub Jelinek  <ja...@redhat.com>

        PR tree-optimization/54810
        * tree-vrp.c (register_edge_assert_for_2): Handle
        NAME = (unsigned) NAME2; if (NAME cmp CST) for
        narrowing casts to unsigned integral type like
        NAME = NAME2 & CST2; if (NAME cmp CST) where CST2
        is the max value of the unsigned integral type.

--- gcc/tree-vrp.c.jj   2012-09-25 14:45:48.000000000 +0200
+++ gcc/tree-vrp.c      2012-10-04 11:43:32.334988401 +0200
@@ -4712,6 +4712,11 @@ register_edge_assert_for_2 (tree name, e
       tree val2 = NULL_TREE;
       double_int mask = double_int_zero;
       unsigned int prec = TYPE_PRECISION (TREE_TYPE (val));
+      unsigned int nprec = prec;
+      enum tree_code rhs_code = ERROR_MARK;
+
+      if (is_gimple_assign (def_stmt))
+       rhs_code = gimple_assign_rhs_code (def_stmt);
 
       /* Add asserts for NAME cmp CST and NAME being defined
         as NAME = (int) NAME2.  */
@@ -4721,7 +4726,7 @@ register_edge_assert_for_2 (tree name, e
          && gimple_assign_cast_p (def_stmt))
        {
          name2 = gimple_assign_rhs1 (def_stmt);
-         if (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt))
+         if (CONVERT_EXPR_CODE_P (rhs_code)
              && INTEGRAL_TYPE_P (TREE_TYPE (name2))
              && TYPE_UNSIGNED (TREE_TYPE (name2))
              && prec == TYPE_PRECISION (TREE_TYPE (name2))
@@ -4767,8 +4772,7 @@ register_edge_assert_for_2 (tree name, e
         NAME = NAME2 >> CST2.
 
         Extract CST2 from the right shift.  */
-      if (is_gimple_assign (def_stmt)
-         && gimple_assign_rhs_code (def_stmt) == RSHIFT_EXPR)
+      if (rhs_code == RSHIFT_EXPR)
        {
          name2 = gimple_assign_rhs1 (def_stmt);
          cst2 = gimple_assign_rhs2 (def_stmt);
@@ -4840,21 +4844,37 @@ register_edge_assert_for_2 (tree name, e
       /* Add asserts for NAME cmp CST and NAME being defined as
         NAME = NAME2 & CST2.
 
-        Extract CST2 from the and.  */
+        Extract CST2 from the and.
+
+        Also handle
+        NAME = (unsigned) NAME2;
+        casts where NAME's type is unsigned and has smaller precision
+        than NAME2's type as if it was NAME = NAME2 & MASK.  */
       names[0] = NULL_TREE;
       names[1] = NULL_TREE;
       cst2 = NULL_TREE;
-      if (is_gimple_assign (def_stmt)
-         && gimple_assign_rhs_code (def_stmt) == BIT_AND_EXPR)
+      if (rhs_code == BIT_AND_EXPR
+         || (CONVERT_EXPR_CODE_P (rhs_code)
+             && TREE_CODE (TREE_TYPE (val)) == INTEGER_TYPE
+             && TYPE_UNSIGNED (TREE_TYPE (val))
+             && TYPE_PRECISION (TREE_TYPE (gimple_assign_rhs1 (def_stmt)))
+                > prec
+             && !retval))
        {
          name2 = gimple_assign_rhs1 (def_stmt);
-         cst2 = gimple_assign_rhs2 (def_stmt);
+         if (rhs_code == BIT_AND_EXPR)
+           cst2 = gimple_assign_rhs2 (def_stmt);
+         else
+           {
+             cst2 = TYPE_MAX_VALUE (TREE_TYPE (val));
+             nprec = TYPE_PRECISION (TREE_TYPE (name2));
+           }
          if (TREE_CODE (name2) == SSA_NAME
              && INTEGRAL_TYPE_P (TREE_TYPE (name2))
              && TREE_CODE (cst2) == INTEGER_CST
              && !integer_zerop (cst2)
-             && prec <= HOST_BITS_PER_DOUBLE_INT
-             && (prec > 1
+             && nprec <= HOST_BITS_PER_DOUBLE_INT
+             && (nprec > 1
                  || TYPE_UNSIGNED (TREE_TYPE (val))))
            {
              gimple def_stmt2 = SSA_NAME_DEF_STMT (name2);
@@ -4881,12 +4901,12 @@ register_edge_assert_for_2 (tree name, e
          bool valid_p = false, valn = false, cst2n = false;
          enum tree_code ccode = comp_code;
 
-         valv = tree_to_double_int (val).zext (prec);
-         cst2v = tree_to_double_int (cst2).zext (prec);
+         valv = tree_to_double_int (val).zext (nprec);
+         cst2v = tree_to_double_int (cst2).zext (nprec);
          if (!TYPE_UNSIGNED (TREE_TYPE (val)))
            {
-             valn = valv.sext (prec).is_negative ();
-             cst2n = cst2v.sext (prec).is_negative ();
+             valn = valv.sext (nprec).is_negative ();
+             cst2n = cst2v.sext (nprec).is_negative ();
            }
          /* If CST2 doesn't have most significant bit set,
             but VAL is negative, we have comparison like
@@ -4894,7 +4914,7 @@ register_edge_assert_for_2 (tree name, e
          if (!cst2n && valn)
            ccode = ERROR_MARK;
          if (cst2n)
-           sgnbit = double_int_one.llshift (prec - 1, prec).zext (prec);
+           sgnbit = double_int_one.llshift (nprec - 1, nprec).zext (nprec);
          else
            sgnbit = double_int_zero;
          minv = valv & cst2v;
@@ -4906,12 +4926,12 @@ register_edge_assert_for_2 (tree name, e
                 have folded the comparison into false) and
                 maximum unsigned value is VAL | ~CST2.  */
              maxv = valv | ~cst2v;
-             maxv = maxv.zext (prec);
+             maxv = maxv.zext (nprec);
              valid_p = true;
              break;
            case NE_EXPR:
              tem = valv | ~cst2v;
-             tem = tem.zext (prec);
+             tem = tem.zext (nprec);
              /* If VAL is 0, handle (X & CST2) != 0 as (X & CST2) > 0U.  */
              if (valv.is_zero ())
                {
@@ -4921,7 +4941,7 @@ register_edge_assert_for_2 (tree name, e
                }
              /* If (VAL | ~CST2) is all ones, handle it as
                 (X & CST2) < VAL.  */
-             if (tem == double_int::mask (prec))
+             if (tem == double_int::mask (nprec))
                {
                  cst2n = false;
                  valn = false;
@@ -4929,8 +4949,9 @@ register_edge_assert_for_2 (tree name, e
                  goto lt_expr;
                }
              if (!cst2n
-                 && cst2v.sext (prec).is_negative ())
-               sgnbit = double_int_one.llshift (prec - 1, prec).zext (prec);
+                 && cst2v.sext (nprec).is_negative ())
+               sgnbit
+                 = double_int_one.llshift (nprec - 1, nprec).zext (nprec);
              if (!sgnbit.is_zero ())
                {
                  if (valv == sgnbit)
@@ -4939,7 +4960,7 @@ register_edge_assert_for_2 (tree name, e
                      valn = true;
                      goto gt_expr;
                    }
-                 if (tem == double_int::mask (prec - 1))
+                 if (tem == double_int::mask (nprec - 1))
                    {
                      cst2n = true;
                      goto lt_expr;
@@ -4958,22 +4979,22 @@ register_edge_assert_for_2 (tree name, e
                {
                  /* If (VAL & CST2) != VAL, X & CST2 can't be equal to
                     VAL.  */
-                 minv = masked_increment (valv, cst2v, sgnbit, prec);
+                 minv = masked_increment (valv, cst2v, sgnbit, nprec);
                  if (minv == valv)
                    break;
                }
-             maxv = double_int::mask (prec - (cst2n ? 1 : 0));
+             maxv = double_int::mask (nprec - (cst2n ? 1 : 0));
              valid_p = true;
              break;
            case GT_EXPR:
            gt_expr:
              /* Find out smallest MINV where MINV > VAL
                 && (MINV & CST2) == MINV, if any.  If VAL is signed and
-                CST2 has MSB set, compute it biased by 1 << (prec - 1).  */
-             minv = masked_increment (valv, cst2v, sgnbit, prec);
+                CST2 has MSB set, compute it biased by 1 << (nprec - 1).  */
+             minv = masked_increment (valv, cst2v, sgnbit, nprec);
              if (minv == valv)
                break;
-             maxv = double_int::mask (prec - (cst2n ? 1 : 0));
+             maxv = double_int::mask (nprec - (cst2n ? 1 : 0));
              valid_p = true;
              break;
            case LE_EXPR:
@@ -4989,13 +5010,13 @@ register_edge_assert_for_2 (tree name, e
                maxv = valv;
              else
                {
-                 maxv = masked_increment (valv, cst2v, sgnbit, prec);
+                 maxv = masked_increment (valv, cst2v, sgnbit, nprec);
                  if (maxv == valv)
                    break;
                  maxv -= double_int_one;
                }
              maxv |= ~cst2v;
-             maxv = maxv.zext (prec);
+             maxv = maxv.zext (nprec);
              minv = sgnbit;
              valid_p = true;
              break;
@@ -5017,13 +5038,13 @@ register_edge_assert_for_2 (tree name, e
                }
              else
                {
-                 maxv = masked_increment (valv, cst2v, sgnbit, prec);
+                 maxv = masked_increment (valv, cst2v, sgnbit, nprec);
                  if (maxv == valv)
                    break;
                }
              maxv -= double_int_one;
              maxv |= ~cst2v;
-             maxv = maxv.zext (prec);
+             maxv = maxv.zext (nprec);
              minv = sgnbit;
              valid_p = true;
              break;
@@ -5031,7 +5052,7 @@ register_edge_assert_for_2 (tree name, e
              break;
            }
          if (valid_p
-             && (maxv - minv).zext (prec) != double_int::mask (prec))
+             && (maxv - minv).zext (nprec) != double_int::mask (nprec))
            {
              tree tmp, new_val, type;
              int i;
@@ -5044,7 +5065,7 @@ register_edge_assert_for_2 (tree name, e
                    type = TREE_TYPE (names[i]);
                    if (!TYPE_UNSIGNED (type))
                      {
-                       type = build_nonstandard_integer_type (prec, 1);
+                       type = build_nonstandard_integer_type (nprec, 1);
                        tmp = build1 (NOP_EXPR, type, names[i]);
                      }
                    if (!minv.is_zero ())
--- gcc/testsuite/gcc.dg/tree-ssa/vrp85.c.jj    2012-10-04 11:32:18.787781121 
+0200
+++ gcc/testsuite/gcc.dg/tree-ssa/vrp85.c       2012-10-04 11:49:18.128031124 
+0200
@@ -0,0 +1,40 @@
+/* PR tree-optimization/54810 */
+/* { dg-do link } */
+/* { dg-options "-O2 -fdump-tree-vrp1" } */
+
+extern void link_error (void);
+
+#define T(n, ntype, wtype) \
+void                           \
+f##n (wtype s)                 \
+{                              \
+  if ((ntype) s == 0)          \
+    return;                    \
+  if (s == 0)                  \
+    link_error ();             \
+}
+
+T(1, unsigned char, unsigned char)
+T(2, unsigned char, unsigned short)
+T(3, unsigned char, unsigned int)
+T(4, unsigned char, unsigned long int)
+T(5, unsigned char, unsigned long long int)
+T(6, unsigned short int, unsigned short int)
+T(7, unsigned short int, unsigned int)
+T(8, unsigned short int, unsigned long int)
+T(9, unsigned short int, unsigned long long int)
+T(10, unsigned int, unsigned int)
+T(11, unsigned int, unsigned long int)
+T(12, unsigned int, unsigned long long int)
+T(13, unsigned long int, unsigned long int)
+T(14, unsigned long int, unsigned long long int)
+T(15, unsigned long long int, unsigned long long int)
+
+int
+main ()
+{
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-not "link_error" "vrp1"} } */
+/* { dg-final { cleanup-tree-dump "vrp1" } } */

        Jakub

Reply via email to