re PR tree-optimization/54810 (VRP doesn't handle comparison of narrowing cast like comparison of BIT_AND_EXPR)

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.dg/tree-ssa/vrp85.c: New test.

From-SVN: r192115
This commit is contained in:
Jakub Jelinek 2012-10-05 11:37:25 +02:00 committed by Jakub Jelinek
parent 5e3e4fe874
commit 440d347233
4 changed files with 106 additions and 31 deletions

View File

@ -1,3 +1,12 @@
2012-10-05 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.
2012-10-04 Jeff Law <law@redhat.com>
* PR target/50356

View File

@ -1,3 +1,8 @@
2012-10-05 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/54810
* gcc.dg/tree-ssa/vrp85.c: New test.
2012-10-04 David Edelsohn <dje.gcc@gmail.com>
* gcc.dg/ucnid-7.c: Skip on AIX.

View File

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

View File

@ -4712,6 +4712,11 @@ register_edge_assert_for_2 (tree name, edge e, gimple_stmt_iterator bsi,
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, edge e, gimple_stmt_iterator bsi,
&& 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, edge e, gimple_stmt_iterator bsi,
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, edge e, gimple_stmt_iterator bsi,
/* 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, edge e, gimple_stmt_iterator bsi,
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, edge e, gimple_stmt_iterator bsi,
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, edge e, gimple_stmt_iterator bsi,
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, edge e, gimple_stmt_iterator bsi,
}
/* 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, edge e, gimple_stmt_iterator bsi,
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, edge e, gimple_stmt_iterator bsi,
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, edge e, gimple_stmt_iterator bsi,
{
/* 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, edge e, gimple_stmt_iterator bsi,
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, edge e, gimple_stmt_iterator bsi,
}
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, edge e, gimple_stmt_iterator bsi,
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, edge e, gimple_stmt_iterator bsi,
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 ())