Hi! On Tue, Oct 29, 2013 at 04:29:56PM +0100, Jakub Jelinek wrote: > > Surely you can't rely on CCP and VRP compute exactly the same > > nonzero_bits. As you don't record/compute zero_bits you can't > > tell whether a not set bit in nonzer_bits is "don't know" or > > if it is "zero". And you cannot do an assert during iteration
Unset bits in get_nonzero_bits are always known to be zero, set bits are don't know or known to be nonzero. > > (during iteration optimistically 'wrong' values can disappear). > > > > During CCP iteration the rule is that bits may only be added to mask > > (and obviously the constant itself on a CONSTANT lattice value may > > not change). Here is an untested safer variant of the original patch that attempts to honor the constraints you've mentioned by looking at get_value and either making nonzero_bits more conservative or not applying it at all if the above rules would be violated. Still, not doing anything for the !is_constant case, because I don't know what would be the right thing. Say, if for iteration we assume some constant value that has some bits unset in mask (known) and set in value (known non-zero), yet they are clear in get_nonzero_bits, shall we punt, or ignore what the iteration would try to do and adjust from get_nonzero_bits instead, something else? > > > Factor this out to commonize with code in evaluate_stmt > > Ok. But in this more conservative patch I don't see enough code to commonize any more. The only change in the patch below since the previous patch is in the evaluate_stmt function: 2013-10-29 Jakub Jelinek <ja...@redhat.com> * gimple-pretty-print.c (dump_ssaname_info): Print newline also in case of VR_VARYING. Print get_nonzero_bits if not all ones. * tree-ssanames.h (struct range_info_def): Add nonzero_bits field. (set_nonzero_bits, get_nonzero_bits): New prototypes. * tree-ssa-ccp.c (get_default_value): Use get_range_info to see if a default def isn't partially constant. (ccp_finalize): If after IPA, set_range_info if integral SSA_NAME is known to be partially zero. (evaluate_stmt): If we'd return otherwise VARYING, use get_range_info to see if a default def isn't partially constant. * tree-ssanames.c (set_range_info): Initialize nonzero_bits upon creation of a range, if VR_RANGE, try to improve nonzero_bits from the range. (set_nonzero_bits, get_nonzero_bits): New functions. * g++.dg/warn/pr33738.C (main): Initialize a2 again to make sure we warn about it already during VRP1 pass. --- gcc/gimple-pretty-print.c.jj 2013-10-23 14:43:12.000000000 +0200 +++ gcc/gimple-pretty-print.c 2013-10-24 17:26:59.650945232 +0200 @@ -1731,7 +1731,7 @@ dump_ssaname_info (pretty_printer *buffe if (!POINTER_TYPE_P (TREE_TYPE (node)) && SSA_NAME_RANGE_INFO (node)) { - double_int min, max; + double_int min, max, nonzero_bits; value_range_type range_type = get_range_info (node, &min, &max); if (range_type == VR_VARYING) @@ -1744,8 +1744,20 @@ dump_ssaname_info (pretty_printer *buffe pp_printf (buffer, ", "); pp_double_int (buffer, max, TYPE_UNSIGNED (TREE_TYPE (node))); pp_printf (buffer, "]"); - newline_and_indent (buffer, spc); } + nonzero_bits = get_nonzero_bits (node); + if (nonzero_bits != double_int_minus_one + && (nonzero_bits + != double_int::mask (TYPE_PRECISION (TREE_TYPE (node))))) + { + pp_string (buffer, " NONZERO "); + sprintf (pp_buffer (buffer)->digit_buffer, + HOST_WIDE_INT_PRINT_DOUBLE_HEX, + (unsigned HOST_WIDE_INT) nonzero_bits.high, + nonzero_bits.low); + pp_string (buffer, pp_buffer (buffer)->digit_buffer); + } + newline_and_indent (buffer, spc); } } --- gcc/tree-ssanames.h.jj 2013-09-27 15:42:44.000000000 +0200 +++ gcc/tree-ssanames.h 2013-10-24 15:52:53.765955605 +0200 @@ -52,6 +52,8 @@ struct GTY (()) range_info_def { double_int min; /* Maximum for value range. */ double_int max; + /* Non-zero bits - bits not set are guaranteed to be always zero. */ + double_int nonzero_bits; }; @@ -68,10 +70,11 @@ struct GTY (()) range_info_def { enum value_range_type { VR_UNDEFINED, VR_RANGE, VR_ANTI_RANGE, VR_VARYING }; /* Sets the value range to SSA. */ -extern void set_range_info (tree ssa, double_int min, double_int max); +extern void set_range_info (tree, double_int, double_int); /* Gets the value range from SSA. */ -extern enum value_range_type get_range_info (tree name, double_int *min, - double_int *max); +extern enum value_range_type get_range_info (tree, double_int *, double_int *); +extern void set_nonzero_bits (tree, double_int); +extern double_int get_nonzero_bits (tree); extern void init_ssanames (struct function *, int); extern void fini_ssanames (void); extern void ssanames_print_statistics (void); --- gcc/tree-ssa-ccp.c.jj 2013-10-29 09:25:38.365478051 +0100 +++ gcc/tree-ssa-ccp.c 2013-10-29 18:02:58.660085620 +0100 @@ -260,6 +260,19 @@ get_default_value (tree var) { val.lattice_val = VARYING; val.mask = double_int_minus_one; + if (flag_tree_bit_ccp) + { + double_int nonzero_bits = get_nonzero_bits (var); + double_int mask + = double_int::mask (TYPE_PRECISION (TREE_TYPE (var))); + if (nonzero_bits != double_int_minus_one && nonzero_bits != mask) + { + val.lattice_val = CONSTANT; + val.value = build_zero_cst (TREE_TYPE (var)); + /* CCP wants the bits above precision set. */ + val.mask = nonzero_bits | ~mask; + } + } } } else if (is_gimple_assign (stmt)) @@ -828,7 +841,8 @@ ccp_finalize (void) do_dbg_cnt (); /* Derive alignment and misalignment information from partially - constant pointers in the lattice. */ + constant pointers in the lattice or nonzero bits from partially + constant integers. */ for (i = 1; i < num_ssa_names; ++i) { tree name = ssa_name (i); @@ -836,7 +850,11 @@ ccp_finalize (void) unsigned int tem, align; if (!name - || !POINTER_TYPE_P (TREE_TYPE (name))) + || (!POINTER_TYPE_P (TREE_TYPE (name)) + && (!INTEGRAL_TYPE_P (TREE_TYPE (name)) + /* Don't record nonzero bits before IPA to avoid + using too much memory. */ + || first_pass_instance))) continue; val = get_value (name); @@ -844,13 +862,24 @@ ccp_finalize (void) || TREE_CODE (val->value) != INTEGER_CST) continue; - /* Trailing constant bits specify the alignment, trailing value - bits the misalignment. */ - tem = val->mask.low; - align = (tem & -tem); - if (align > 1) - set_ptr_info_alignment (get_ptr_info (name), align, - TREE_INT_CST_LOW (val->value) & (align - 1)); + if (POINTER_TYPE_P (TREE_TYPE (name))) + { + /* Trailing mask bits specify the alignment, trailing value + bits the misalignment. */ + tem = val->mask.low; + align = (tem & -tem); + if (align > 1) + set_ptr_info_alignment (get_ptr_info (name), align, + (TREE_INT_CST_LOW (val->value) + & (align - 1))); + } + else + { + double_int nonzero_bits = val->mask; + nonzero_bits = nonzero_bits | tree_to_double_int (val->value); + nonzero_bits &= get_nonzero_bits (name); + set_nonzero_bits (name, nonzero_bits); + } } /* Perform substitutions based on the known constant values. */ @@ -1671,6 +1700,48 @@ evaluate_stmt (gimple stmt) is_constant = (val.lattice_val == CONSTANT); } + if (flag_tree_bit_ccp + && !is_constant + && likelyvalue != UNDEFINED + && gimple_get_lhs (stmt) + && TREE_CODE (gimple_get_lhs (stmt)) == SSA_NAME) + { + tree lhs = gimple_get_lhs (stmt); + double_int nonzero_bits = get_nonzero_bits (lhs); + double_int mask = double_int::mask (TYPE_PRECISION (TREE_TYPE (lhs))); + if (nonzero_bits != double_int_minus_one && nonzero_bits != mask) + { + prop_value_t *oldval = get_value (lhs); + if (oldval->lattice_val == VARYING) + nonzero_bits = double_int_minus_one; + else if (oldval->lattice_val == CONSTANT) + { + if (TREE_CODE (oldval->value) != INTEGER_CST) + nonzero_bits = double_int_minus_one; + else + { + /* Make sure we never remove bits from mask nor + change value. */ + nonzero_bits + |= oldval->mask | tree_to_double_int (oldval->value); + if ((nonzero_bits & mask) == mask) + nonzero_bits = double_int_minus_one; + } + } + if (nonzero_bits != double_int_minus_one) + { + val.lattice_val = CONSTANT; + if (oldval->lattice_val == CONSTANT) + val.value = oldval->value; + else + val.value = build_zero_cst (TREE_TYPE (lhs)); + /* CCP wants the bits above precision set. */ + val.mask = nonzero_bits | ~mask; + is_constant = true; + } + } + } + if (!is_constant) { /* The statement produced a nonconstant value. If the statement --- gcc/tree-ssanames.c.jj 2013-10-23 14:43:16.000000000 +0200 +++ gcc/tree-ssanames.c 2013-10-24 17:32:22.127281080 +0200 @@ -189,11 +189,30 @@ set_range_info (tree name, double_int mi { ri = ggc_alloc_cleared_range_info_def (); SSA_NAME_RANGE_INFO (name) = ri; + ri->nonzero_bits = double_int::mask (TYPE_PRECISION (TREE_TYPE (name))); } /* Set the values. */ ri->min = min; ri->max = max; + + /* If it is a range, try to improve nonzero_bits from the min/max. */ + if (min.cmp (max, TYPE_UNSIGNED (TREE_TYPE (name))) != 1) + { + int prec = TYPE_PRECISION (TREE_TYPE (name)); + double_int xorv; + + min = min.zext (prec); + max = max.zext (prec); + xorv = min ^ max; + if (xorv.high) + xorv = double_int::mask (2 * HOST_BITS_PER_WIDE_INT + - clz_hwi (xorv.high)); + else if (xorv.low) + xorv = double_int::mask (HOST_BITS_PER_WIDE_INT + - clz_hwi (xorv.low)); + ri->nonzero_bits = ri->nonzero_bits & (min | xorv); + } } @@ -233,6 +252,47 @@ get_range_info (tree name, double_int *m return range_type; } +/* Change non-zero bits bitmask of NAME. */ + +void +set_nonzero_bits (tree name, double_int mask) +{ + gcc_assert (!POINTER_TYPE_P (TREE_TYPE (name))); + if (SSA_NAME_RANGE_INFO (name) == NULL) + set_range_info (name, + tree_to_double_int (TYPE_MIN_VALUE (TREE_TYPE (name))), + tree_to_double_int (TYPE_MAX_VALUE (TREE_TYPE (name)))); + range_info_def *ri = SSA_NAME_RANGE_INFO (name); + ri->nonzero_bits + = mask & double_int::mask (TYPE_PRECISION (TREE_TYPE (name))); +} + +/* Return a double_int with potentially non-zero bits in SSA_NAME + NAME, or double_int_minus_one if unknown. */ + +double_int +get_nonzero_bits (tree name) +{ + if (POINTER_TYPE_P (TREE_TYPE (name))) + { + struct ptr_info_def *pi = SSA_NAME_PTR_INFO (name); + if (pi && pi->align) + { + double_int al = double_int::from_uhwi (pi->align - 1); + return ((double_int::mask (TYPE_PRECISION (TREE_TYPE (name))) & ~al) + | double_int::from_uhwi (pi->misalign)); + } + return double_int_minus_one; + } + + range_info_def *ri = SSA_NAME_RANGE_INFO (name); + if (!ri || (GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (name))) + > 2 * HOST_BITS_PER_WIDE_INT)) + return double_int_minus_one; + + return ri->nonzero_bits; +} + /* We no longer need the SSA_NAME expression VAR, release it so that it may be reused. --- gcc/testsuite/g++.dg/warn/pr33738.C.jj 2010-05-04 12:02:18.000000000 +0200 +++ gcc/testsuite/g++.dg/warn/pr33738.C 2013-10-25 08:52:24.052881493 +0200 @@ -18,6 +18,7 @@ int main() { if (a2 == -1) { // { dg-warning "always false due" } link_error (); } + a2 = static_cast<Alpha>(GetM1()); if (-1 == a2) { // { dg-warning "always false due" } link_error (); } Jakub