This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] Teach VRP to handle if ((unsigned_narrowing_cast) x != 0) similarly to if ((x & 0xffff) != 0) (PR tree-optimization/54810)
- From: Richard Guenther <richard dot guenther at gmail dot com>
- To: Jakub Jelinek <jakub at redhat dot com>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Thu, 4 Oct 2012 19:29:13 +0200
- Subject: Re: [PATCH] Teach VRP to handle if ((unsigned_narrowing_cast) x != 0) similarly to if ((x & 0xffff) != 0) (PR tree-optimization/54810)
- References: <20121004163101.GB1787@tucnak.redhat.com>
On Thu, Oct 4, 2012 at 6:31 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> 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?
Ok.
Thanks,
Richard.
> 2012-10-04 Jakub Jelinek <jakub@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