diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp49.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp49.c new file mode 100644 index 0000000..55503d7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp49.c @@ -0,0 +1,51 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -ftree-vrp" } */ +/* PR28632 was concerned about VRP understanding bitwise OR and AND expressions. + */ + +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\." } } */ diff --git a/gcc/testsuite/gcc.dg/vect/slp-perm-4.c b/gcc/testsuite/gcc.dg/vect/slp-perm-4.c index 867dfd4..f452a92 100644 --- a/gcc/testsuite/gcc.dg/vect/slp-perm-4.c +++ b/gcc/testsuite/gcc.dg/vect/slp-perm-4.c @@ -65,6 +65,7 @@ int main (int argc, const char* argv[]) for (i = 0; i < N; i++) { + __asm__("":"+r"(i)); /* don't vectorize this.. */ input[i] = i%256; if (input[i] > 200) abort(); diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index a0f4c3d..1375c95 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -391,10 +391,10 @@ set_value_range (value_range_t *vr, enum value_range_type t, tree min, } if (t == VR_UNDEFINED || t == VR_VARYING) - gcc_assert (min == NULL_TREE && max == NULL_TREE); - - if (t == VR_UNDEFINED || t == VR_VARYING) - gcc_assert (equiv == NULL || bitmap_empty_p (equiv)); + { + gcc_assert (min == NULL_TREE && max == NULL_TREE); + gcc_assert (equiv == NULL || bitmap_empty_p (equiv)); + } #endif vr->type = t; @@ -2339,7 +2339,6 @@ extract_range_from_binary_expr (value_range_t *vr, || range_includes_zero_p (&vr1))) { tree zero = build_int_cst (TREE_TYPE (vr0.min), 0); - int cmp; sop = false; min = NULL_TREE; @@ -2493,30 +2492,235 @@ extract_range_from_binary_expr (value_range_t *vr, } else if (code == BIT_AND_EXPR) { +#define DEBUG_STUFF(vr0, vr1, type, str) \ + { \ + fprintf (dump_file, "Incoming " str " (%s", \ + vr0.type == VR_UNDEFINED ? "UNDEFINED " : \ + vr0.type == VR_RANGE ? "" : \ + vr0.type == VR_ANTI_RANGE ? "~" : \ + vr0.type == VR_VARYING ? "VARYING " : "XXX"); \ + fprintf (dump_file, "["); \ + print_generic_expr (dump_file, vr0.min, 0); \ + fprintf (dump_file, ", "); \ + print_generic_expr (dump_file, vr0.max, 0); \ + fprintf (dump_file, "] , %s[", \ + vr1.type == VR_UNDEFINED ? "UNDEFINED " : \ + vr1.type == VR_RANGE ? "" : \ + vr1.type == VR_ANTI_RANGE ? "~" : \ + vr1.type == VR_VARYING ? "VARYING " : "XXX"); \ + print_generic_expr (dump_file, vr1.min, 0); \ + fprintf (dump_file, ", "); \ + print_generic_expr (dump_file, vr1.max, 0); \ + fprintf (dump_file, "]"); \ + fprintf (dump_file, ") using %s", \ + type == VR_UNDEFINED ? "UNDEFINED " : \ + type == VR_RANGE ? "" : \ + type == VR_ANTI_RANGE ? "~" : \ + type == VR_VARYING ? "VARYING " : "XXX"); \ + fprintf (dump_file, "["); \ + print_generic_expr (dump_file, min, 0); \ + fprintf (dump_file, ", "); \ + print_generic_expr (dump_file, max, 0); \ + fprintf (dump_file, "]\n"); \ + } + + double_int vr0_min, vr0_max, vr1_min, vr1_max; + double_int bits0, bits1, tmp0, tmp1; + double_int and_min, and_max; + + if ((vr0.type != VR_RANGE + && vr0.type != VR_ANTI_RANGE + && vr1.type != VR_RANGE + && vr1.type != VR_ANTI_RANGE) + /* -ENOIDEA */ + || (vr0.type == VR_VARYING && range_is_nonnull (&vr1)) + || (vr1.type == VR_VARYING && range_is_nonnull (&vr0))) + { + set_value_range_to_varying (vr); + return; + } + + /* For usual RANGE, RANGE we can just take the normal ranges. + * + * If either one of the ranges is an ANTI_RANGE though, then we + * currently have to use 0 or -1 as the minimum or maximum, respectively. + * + * If the non-anti range is, however, VARYING or it's minimum or maximum + * otherwise NULL_TREE, then give up (by setting the current range + * to VARYING too). + */ if (vr0.type == VR_RANGE - && vr0.min == vr0.max - && TREE_CODE (vr0.max) == INTEGER_CST - && !TREE_OVERFLOW (vr0.max) - && tree_int_cst_sgn (vr0.max) >= 0) + && vr0.min != NULL_TREE + && TREE_CODE (vr0.min) == INTEGER_CST) + vr0_min = tree_to_double_int (vr0.min); + else if (vr1.min != NULL_TREE && TREE_CODE (vr1.min) == INTEGER_CST) { - min = build_int_cst (expr_type, 0); - max = vr0.max; + vr0_min.low = 0; + vr0_min.high = 0; } - else if (vr1.type == VR_RANGE - && vr1.min == vr1.max - && TREE_CODE (vr1.max) == INTEGER_CST - && !TREE_OVERFLOW (vr1.max) - && tree_int_cst_sgn (vr1.max) >= 0) + else { - type = VR_RANGE; - min = build_int_cst (expr_type, 0); - max = vr1.max; + set_value_range_to_varying (vr); + return; + } + if (vr1.type == VR_RANGE + && vr1.min != NULL_TREE + && TREE_CODE (vr1.min) == INTEGER_CST) + vr1_min = tree_to_double_int (vr1.min); + else if (vr0.min != NULL_TREE && TREE_CODE (vr0.min) == INTEGER_CST) + { + vr1_min.low = 0; + vr1_min.high = 0; + } + else + { + set_value_range_to_varying (vr); + return; + } + if (vr0.type == VR_RANGE + && vr0.max != NULL_TREE + && TREE_CODE (vr0.max) == INTEGER_CST) + vr0_max = tree_to_double_int (vr0.max); + else if (vr1.max != NULL_TREE && TREE_CODE (vr1.max) == INTEGER_CST) + { + vr0_max.low = ALL_ONES; + vr0_max.high = ALL_ONES; } else { set_value_range_to_varying (vr); return; } + if (vr1.type == VR_RANGE + && vr1.max != NULL_TREE + && TREE_CODE (vr1.max) == INTEGER_CST) + vr1_max = tree_to_double_int (vr1.max); + else if (vr0.max != NULL_TREE && TREE_CODE (vr0.max) == INTEGER_CST) + { + vr1_max.low = ALL_ONES; + vr1_max.high = ALL_ONES; + } + else + { + set_value_range_to_varying (vr); + return; + } + + type = VR_RANGE; + + /* Undo the damage of set_value_range_to_nonnull(). */ + if (range_is_nonnull (&vr0) + && vr1.type == VR_RANGE + && !integer_zerop (vr1.min)) + { + type = VR_RANGE; + max = vr1.max; + if (compare_values (vr1.min, vr1.max) == 0) + min = build_int_cst (expr_type, 0); + else + min = vr1.min; + + if (dump_file && (dump_flags & TDF_DETAILS) != 0) + DEBUG_STUFF(vr0, vr1, type, "nonnull0") + } + else if (range_is_nonnull (&vr1) + && vr0.type == VR_RANGE + && !integer_zerop (vr0.min)) + { + type = VR_RANGE; + max = vr0.max; + if (compare_values (vr0.min, vr0.max) == 0) + min = build_int_cst (expr_type, 0); + else + min = vr0.min; + + if (dump_file && (dump_flags & TDF_DETAILS) != 0) + DEBUG_STUFF(vr0, vr1, type, "nonnull1") + } + else + /* Two ranges, finally! */ + { + bits0.low = vr0_min.low ^ vr0_max.low; + bits0.high = vr0_min.high ^ vr0_max.high; + bits1.low = vr1_min.low ^ vr1_max.low; + bits1.high = vr1_min.high ^ vr1_max.high; + + /* Handle bits that are always high i.e. set. */ + tmp0.high = vr0_min.high & vr0_max.high; + if (bits0.high != 0) + { + tmp0.low = (unsigned HOST_WIDE_INT) 0u; + tmp0.high &= ~(((unsigned HOST_WIDE_INT) 1u + << floor_log2 (bits0.high)) - 1); + } + else if (bits0.low != 0) + { + tmp0.low = (vr0_min.low & vr0_max.low) + & ~(((unsigned HOST_WIDE_INT) 1u + << floor_log2 (bits0.low)) - 1); + } + else + tmp0.low = vr0_min.low & vr0_max.low; + tmp1.high = vr1_min.high & vr1_max.high; + if (bits1.high != 0) + { + tmp1.low = (unsigned HOST_WIDE_INT) 0u; + tmp1.high &= ~(((unsigned HOST_WIDE_INT) 1u + << floor_log2 (bits1.high)) - 1); + } + else if (bits1.low != 0) + { + tmp1.low = (vr1_min.low & vr1_max.low) + & ~(((unsigned HOST_WIDE_INT) 1u + << floor_log2 (bits1.low)) - 1); + } + else + tmp1.low = vr1_min.low & vr1_max.low; + /* Finally BIT_AND_EXPR them together. */ + and_min.low = tmp0.low & tmp1.low; + and_min.high = tmp0.high & tmp1.high; + + /* Handle bits that are always low i.e. unset. */ + tmp0.high = vr0_min.high | vr0_max.high; + if (bits0.high != 0) + { + tmp0.low = ~(unsigned HOST_WIDE_INT) 0u; + tmp0.high |= ((unsigned HOST_WIDE_INT) 1u + << floor_log2 (bits0.high)) - 1; + } + else if (bits0.low & ((~(unsigned HOST_WIDE_INT) 0u) - 1)) + { + tmp0.low = (vr0_min.low | vr0_max.low) + | (((unsigned HOST_WIDE_INT) 1u + << floor_log2 (bits0.low)) - 1); + } + else + tmp0.low = vr0_min.low | vr0_max.low; + tmp1.high = vr1_min.high | vr1_max.high; + if (bits1.high != 0) + { + tmp1.low = ~(unsigned HOST_WIDE_INT) 0u; + tmp1.high |= ((unsigned HOST_WIDE_INT) 1u + << floor_log2 (bits1.high)) - 1; + } + else if (bits1.low & ((~(unsigned HOST_WIDE_INT) 0u) - 1)) + { + tmp1.low = (vr1_min.low | vr1_max.low) + | (((unsigned HOST_WIDE_INT) 1u + << floor_log2 (bits1.low)) - 1); + } + else + tmp1.low = vr1_min.low | vr1_max.low; + /* Finally BIT_AND_EXPR them together. */ + and_max.low = tmp0.low & tmp1.low; + and_max.high = tmp0.high & tmp1.high; + + min = double_int_to_tree (expr_type, and_min); + max = double_int_to_tree (expr_type, and_max); + + if (dump_file && (dump_flags & TDF_DETAILS) != 0) + DEBUG_STUFF(vr0, vr1, type, "") + } } else if (code == BIT_IOR_EXPR) {