re PR tree-optimization/28632 (VRP should understand bitwise OR and AND)
PR tree-optimization/28632 * tree-vrp.c (zero_nonzero_bits_from_vr): New function. (extract_range_from_binary_expr): Further optimize BIT_AND_EXPR and BIT_IOR_EXPR. * gcc.dg/tree-ssa/vrp51.c: New test. * gcc.dg/tree-ssa/vrp52.c: New test. Co-Authored-By: Bernhard Reutner-Fischer <aldot@gcc.gnu.org> Co-Authored-By: Denys Vlasenko <dvlasenk@redhat.com> From-SVN: r162009
This commit is contained in:
parent
02dea3ffc6
commit
85e693aa55
@ -1,3 +1,12 @@
|
||||
2010-07-09 Jakub Jelinek <jakub@redhat.com>
|
||||
Denys Vlasenko <dvlasenk@redhat.com>
|
||||
Bernhard Reutner-Fischer <aldot@gcc.gnu.org>
|
||||
|
||||
PR tree-optimization/28632
|
||||
* tree-vrp.c (zero_nonzero_bits_from_vr): New function.
|
||||
(extract_range_from_binary_expr): Further optimize
|
||||
BIT_AND_EXPR and BIT_IOR_EXPR.
|
||||
|
||||
2010-07-09 Sebastian Pop <sebastian.pop@amd.com>
|
||||
|
||||
* tree-if-conv.c (fold_or_predicates): New.
|
||||
|
@ -1,3 +1,11 @@
|
||||
2010-07-09 Jakub Jelinek <jakub@redhat.com>
|
||||
Denys Vlasenko <dvlasenk@redhat.com>
|
||||
Bernhard Reutner-Fischer <aldot@gcc.gnu.org>
|
||||
|
||||
PR tree-optimization/28632
|
||||
* gcc.dg/tree-ssa/vrp51.c: New test.
|
||||
* gcc.dg/tree-ssa/vrp52.c: New test.
|
||||
|
||||
2010-07-09 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* g++.dg/abi/covariant6.C: New.
|
||||
|
58
gcc/testsuite/gcc.dg/tree-ssa/vrp51.c
Normal file
58
gcc/testsuite/gcc.dg/tree-ssa/vrp51.c
Normal file
@ -0,0 +1,58 @@
|
||||
/* PR tree-optimization/28632 */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -ftree-vrp" } */
|
||||
|
||||
void
|
||||
v4 (unsigned a, unsigned b)
|
||||
{
|
||||
if (a < 0x1000) return;
|
||||
if (a > 0x1000) return;
|
||||
if (b < 0x0110) return;
|
||||
/* constant true. */
|
||||
if (!__builtin_constant_p ((a|b) >= 0x01000))
|
||||
__asm__("bug.always.true");
|
||||
/* VRP must not think that this is constant. */
|
||||
if (__builtin_constant_p ((a|b) >= 0x10000))
|
||||
__asm__("bug.not.always.true");
|
||||
}
|
||||
|
||||
void
|
||||
u4 (unsigned n)
|
||||
{
|
||||
if (n > 0x10111) return;
|
||||
if (n < 0x10101) return;
|
||||
/* always true. */
|
||||
if (!__builtin_constant_p (n & 0x00100))
|
||||
__asm__("bug.always.true");
|
||||
/* VRP must not think that this is constant true. */
|
||||
if (__builtin_constant_p (n & 0x00001))
|
||||
__asm__("bug.not.always.true");
|
||||
/* Out of range, always evaluates to constant false. */
|
||||
if (!__builtin_constant_p (n & 0x01000))
|
||||
__asm__("bug.always.false");
|
||||
}
|
||||
|
||||
void
|
||||
u5 (unsigned n)
|
||||
{
|
||||
struct s {unsigned exp:8;} x;
|
||||
x.exp = n;
|
||||
if (__builtin_constant_p(((n + 1) & 255) > 1))
|
||||
__asm__("bug.not.always.true");
|
||||
}
|
||||
|
||||
void
|
||||
v5 (int a, int b)
|
||||
{
|
||||
if (a < 0x1000) return;
|
||||
if (a > 0x1000) return;
|
||||
if (b < 0x0110) return;
|
||||
/* constant true. */
|
||||
if (!__builtin_constant_p ((a|b) >= 0x01000))
|
||||
__asm__("bug.always.true");
|
||||
/* VRP must not think that this is always true. */
|
||||
if (__builtin_constant_p ((a|b) >= 0x10000))
|
||||
__asm__("bug.not.always.true");
|
||||
}
|
||||
|
||||
/* { dg-final { scan-assembler-not "bug\." } } */
|
16
gcc/testsuite/gcc.dg/tree-ssa/vrp52.c
Normal file
16
gcc/testsuite/gcc.dg/tree-ssa/vrp52.c
Normal file
@ -0,0 +1,16 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-vrp1" } */
|
||||
|
||||
int
|
||||
foo (unsigned int i, unsigned int j)
|
||||
{
|
||||
i &= 15;
|
||||
j &= 15;
|
||||
i += 1024;
|
||||
j += 2048;
|
||||
i |= j;
|
||||
return i >= 1024 + 2048;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump "Folding predicate i_\[^\n\r\]* to 1" "vrp1" } } */
|
||||
/* { dg-final { cleanup-tree-dump "vrp1" } } */
|
199
gcc/tree-vrp.c
199
gcc/tree-vrp.c
@ -2064,6 +2064,60 @@ vrp_int_const_binop (enum tree_code code, tree val1, tree val2)
|
||||
}
|
||||
|
||||
|
||||
/* For range VR compute two double_int bitmasks. In *MAY_BE_NONZERO
|
||||
bitmask if some bit is unset, it means for all numbers in the range
|
||||
the bit is 0, otherwise it might be 0 or 1. In *MUST_BE_NONZERO
|
||||
bitmask if some bit is set, it means for all numbers in the range
|
||||
the bit is 1, otherwise it might be 0 or 1. */
|
||||
|
||||
static bool
|
||||
zero_nonzero_bits_from_vr (value_range_t *vr, double_int *may_be_nonzero,
|
||||
double_int *must_be_nonzero)
|
||||
{
|
||||
if (range_int_cst_p (vr))
|
||||
{
|
||||
if (range_int_cst_singleton_p (vr))
|
||||
{
|
||||
*may_be_nonzero = tree_to_double_int (vr->min);
|
||||
*must_be_nonzero = *may_be_nonzero;
|
||||
return true;
|
||||
}
|
||||
if (tree_int_cst_sgn (vr->min) >= 0)
|
||||
{
|
||||
double_int dmin = tree_to_double_int (vr->min);
|
||||
double_int dmax = tree_to_double_int (vr->max);
|
||||
double_int xor_mask = double_int_xor (dmin, dmax);
|
||||
*may_be_nonzero = double_int_ior (dmin, dmax);
|
||||
*must_be_nonzero = double_int_and (dmin, dmax);
|
||||
if (xor_mask.high != 0)
|
||||
{
|
||||
unsigned HOST_WIDE_INT mask
|
||||
= ((unsigned HOST_WIDE_INT) 1
|
||||
<< floor_log2 (xor_mask.high)) - 1;
|
||||
may_be_nonzero->low = ALL_ONES;
|
||||
may_be_nonzero->high |= mask;
|
||||
must_be_nonzero->low = 0;
|
||||
must_be_nonzero->high &= ~mask;
|
||||
}
|
||||
else if (xor_mask.low != 0)
|
||||
{
|
||||
unsigned HOST_WIDE_INT mask
|
||||
= ((unsigned HOST_WIDE_INT) 1
|
||||
<< floor_log2 (xor_mask.low)) - 1;
|
||||
may_be_nonzero->low |= mask;
|
||||
must_be_nonzero->low &= ~mask;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
may_be_nonzero->low = ALL_ONES;
|
||||
may_be_nonzero->high = ALL_ONES;
|
||||
must_be_nonzero->low = 0;
|
||||
must_be_nonzero->high = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Extract range information from a binary expression EXPR based on
|
||||
the ranges of each of its operands and the expression code. */
|
||||
|
||||
@ -2569,120 +2623,79 @@ extract_range_from_binary_expr (value_range_t *vr,
|
||||
min = vrp_int_const_binop (code, vr0.min, vr1.max);
|
||||
max = vrp_int_const_binop (code, vr0.max, vr1.min);
|
||||
}
|
||||
else if (code == BIT_AND_EXPR)
|
||||
else if (code == BIT_AND_EXPR || code == BIT_IOR_EXPR)
|
||||
{
|
||||
bool vr0_int_cst_singleton_p, vr1_int_cst_singleton_p;
|
||||
bool int_cst_range0, int_cst_range1;
|
||||
double_int may_be_nonzero0, may_be_nonzero1;
|
||||
double_int must_be_nonzero0, must_be_nonzero1;
|
||||
|
||||
vr0_int_cst_singleton_p = range_int_cst_singleton_p (&vr0);
|
||||
vr1_int_cst_singleton_p = range_int_cst_singleton_p (&vr1);
|
||||
int_cst_range0 = zero_nonzero_bits_from_vr (&vr0, &may_be_nonzero0,
|
||||
&must_be_nonzero0);
|
||||
int_cst_range1 = zero_nonzero_bits_from_vr (&vr1, &may_be_nonzero1,
|
||||
&must_be_nonzero1);
|
||||
|
||||
type = VR_RANGE;
|
||||
if (vr0_int_cst_singleton_p && vr1_int_cst_singleton_p)
|
||||
min = max = int_const_binop (code, vr0.max, vr1.max, 0);
|
||||
else if (range_int_cst_p (&vr0)
|
||||
&& range_int_cst_p (&vr1)
|
||||
&& tree_int_cst_sgn (vr0.min) >= 0
|
||||
&& tree_int_cst_sgn (vr1.min) >= 0)
|
||||
{
|
||||
double_int vr0_mask = tree_to_double_int (vr0.min);
|
||||
double_int vr1_mask = tree_to_double_int (vr1.min);
|
||||
double_int maxd, diff;
|
||||
tree mask;
|
||||
|
||||
min = build_int_cst (expr_type, 0);
|
||||
/* Compute non-zero bits mask from both ranges. */
|
||||
if (!vr0_int_cst_singleton_p)
|
||||
{
|
||||
maxd = tree_to_double_int (vr0.max);
|
||||
diff = double_int_sub (maxd, vr0_mask);
|
||||
if (diff.high)
|
||||
{
|
||||
diff.low = ~(unsigned HOST_WIDE_INT)0;
|
||||
diff.high = ((HOST_WIDE_INT) 2
|
||||
<< floor_log2 (diff.high)) - 1;
|
||||
}
|
||||
else
|
||||
diff.low = ((HOST_WIDE_INT) 2 << floor_log2 (diff.low)) - 1;
|
||||
vr0_mask = double_int_ior (vr0_mask,
|
||||
double_int_ior (maxd, diff));
|
||||
}
|
||||
if (!vr1_int_cst_singleton_p)
|
||||
{
|
||||
maxd = tree_to_double_int (vr1.max);
|
||||
diff = double_int_sub (maxd, vr1_mask);
|
||||
if (diff.high)
|
||||
{
|
||||
diff.low = ~(unsigned HOST_WIDE_INT)0;
|
||||
diff.high = ((HOST_WIDE_INT) 2
|
||||
<< floor_log2 (diff.high)) - 1;
|
||||
}
|
||||
else
|
||||
diff.low = ((HOST_WIDE_INT) 2 << floor_log2 (diff.low)) - 1;
|
||||
vr1_mask = double_int_ior (vr1_mask,
|
||||
double_int_ior (maxd, diff));
|
||||
}
|
||||
mask = double_int_to_tree (expr_type,
|
||||
double_int_and (vr0_mask, vr1_mask));
|
||||
max = vr0.max;
|
||||
if (tree_int_cst_lt (vr1.max, max))
|
||||
max = vr1.max;
|
||||
if (!TREE_OVERFLOW (mask)
|
||||
&& tree_int_cst_lt (mask, max)
|
||||
&& tree_int_cst_sgn (mask) >= 0)
|
||||
max = mask;
|
||||
}
|
||||
else if (vr0_int_cst_singleton_p
|
||||
&& tree_int_cst_sgn (vr0.max) >= 0)
|
||||
{
|
||||
min = build_int_cst (expr_type, 0);
|
||||
max = vr0.max;
|
||||
}
|
||||
else if (vr1_int_cst_singleton_p
|
||||
&& tree_int_cst_sgn (vr1.max) >= 0)
|
||||
{
|
||||
type = VR_RANGE;
|
||||
min = build_int_cst (expr_type, 0);
|
||||
max = vr1.max;
|
||||
}
|
||||
else
|
||||
else if (!int_cst_range0 && !int_cst_range1)
|
||||
{
|
||||
set_value_range_to_varying (vr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (code == BIT_IOR_EXPR)
|
||||
else if (code == BIT_AND_EXPR)
|
||||
{
|
||||
if (range_int_cst_p (&vr0)
|
||||
&& range_int_cst_p (&vr1)
|
||||
&& tree_int_cst_sgn (vr0.min) >= 0
|
||||
&& tree_int_cst_sgn (vr1.min) >= 0)
|
||||
min = double_int_to_tree (expr_type,
|
||||
double_int_and (must_be_nonzero0,
|
||||
must_be_nonzero1));
|
||||
max = double_int_to_tree (expr_type,
|
||||
double_int_and (may_be_nonzero0,
|
||||
may_be_nonzero1));
|
||||
if (TREE_OVERFLOW (min) || tree_int_cst_sgn (min) < 0)
|
||||
min = NULL_TREE;
|
||||
if (TREE_OVERFLOW (max) || tree_int_cst_sgn (max) < 0)
|
||||
max = NULL_TREE;
|
||||
if (int_cst_range0 && tree_int_cst_sgn (vr0.min) >= 0)
|
||||
{
|
||||
double_int vr0_max = tree_to_double_int (vr0.max);
|
||||
double_int vr1_max = tree_to_double_int (vr1.max);
|
||||
double_int ior_max;
|
||||
|
||||
/* Set all bits to the right of the most significant one to 1.
|
||||
For example, [0, 4] | [4, 4] = [4, 7]. */
|
||||
ior_max.low = vr0_max.low | vr1_max.low;
|
||||
ior_max.high = vr0_max.high | vr1_max.high;
|
||||
if (ior_max.high != 0)
|
||||
if (min == NULL_TREE)
|
||||
min = build_int_cst (expr_type, 0);
|
||||
if (max == NULL_TREE || tree_int_cst_lt (vr0.max, max))
|
||||
max = vr0.max;
|
||||
}
|
||||
if (int_cst_range1 && tree_int_cst_sgn (vr1.min) >= 0)
|
||||
{
|
||||
ior_max.low = ~(unsigned HOST_WIDE_INT)0u;
|
||||
ior_max.high |= ((HOST_WIDE_INT) 1
|
||||
<< floor_log2 (ior_max.high)) - 1;
|
||||
if (min == NULL_TREE)
|
||||
min = build_int_cst (expr_type, 0);
|
||||
if (max == NULL_TREE || tree_int_cst_lt (vr1.max, max))
|
||||
max = vr1.max;
|
||||
}
|
||||
else if (ior_max.low != 0)
|
||||
ior_max.low |= ((unsigned HOST_WIDE_INT) 1u
|
||||
<< floor_log2 (ior_max.low)) - 1;
|
||||
|
||||
/* Both of these endpoints are conservative. */
|
||||
min = vrp_int_const_binop (MAX_EXPR, vr0.min, vr1.min);
|
||||
max = double_int_to_tree (expr_type, ior_max);
|
||||
}
|
||||
else
|
||||
else if (!int_cst_range0
|
||||
|| !int_cst_range1
|
||||
|| tree_int_cst_sgn (vr0.min) < 0
|
||||
|| tree_int_cst_sgn (vr1.min) < 0)
|
||||
{
|
||||
set_value_range_to_varying (vr);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
min = double_int_to_tree (expr_type,
|
||||
double_int_ior (must_be_nonzero0,
|
||||
must_be_nonzero1));
|
||||
max = double_int_to_tree (expr_type,
|
||||
double_int_ior (may_be_nonzero0,
|
||||
may_be_nonzero1));
|
||||
if (TREE_OVERFLOW (min) || tree_int_cst_sgn (min) < 0)
|
||||
min = vr0.min;
|
||||
else
|
||||
min = vrp_int_const_binop (MAX_EXPR, min, vr0.min);
|
||||
if (TREE_OVERFLOW (max) || tree_int_cst_sgn (max) < 0)
|
||||
max = NULL_TREE;
|
||||
min = vrp_int_const_binop (MAX_EXPR, min, vr1.min);
|
||||
}
|
||||
}
|
||||
else
|
||||
gcc_unreachable ();
|
||||
|
Loading…
Reference in New Issue
Block a user