Patchwork Teach VRP to handle if ((unsigned_narrowing_cast) x != 0) similarly to if ((x & 0xffff) != 0) (PR tree-optimization/54810)

login
register
mail settings
Submitter Jakub Jelinek
Date Oct. 4, 2012, 4:31 p.m.
Message ID <20121004163101.GB1787@tucnak.redhat.com>
Download mbox | patch
Permalink /patch/189203/
State New
Headers show

Comments

Jakub Jelinek - Oct. 4, 2012, 4:31 p.m.
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  <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.


	Jakub
Richard Guenther - Oct. 4, 2012, 5:29 p.m.
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

Patch

--- 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" } } */