[gcc r15-992] Remove value_range typedef.
https://gcc.gnu.org/g:6fb43d1b90e2683f6f41f04a65341fc2dab4b495 commit r15-992-g6fb43d1b90e2683f6f41f04a65341fc2dab4b495 Author: Aldy Hernandez Date: Fri May 31 15:49:26 2024 +0200 Remove value_range typedef. Now that pointers and integers have been disambiguated from irange, and all the pointer range temporaries use prange, we can reclaim value_range as a general purpose range container. This patch removes the typedef, in favor of int_range_max, thus providing slightly better ranges in places. I have also used int_range<1> or <2> when it's known ahead of time how big the range will be, thus saving a few words. In a follow-up patch I will rename the Value_Range temporary to value_range. No change in performance. gcc/ChangeLog: * builtins.cc (expand_builtin_strnlen): Replace value_range use with int_range_max or irange when appropriate. (determine_block_size): Same. * fold-const.cc (minmax_from_comparison): Same. * gimple-array-bounds.cc (check_out_of_bounds_and_warn): Same. (array_bounds_checker::check_array_ref): Same. * gimple-fold.cc (size_must_be_zero_p): Same. * gimple-predicate-analysis.cc (find_var_cmp_const): Same. * gimple-ssa-sprintf.cc (get_int_range): Same. (format_integer): Same. (try_substitute_return_value): Same. (handle_printf_call): Same. * gimple-ssa-warn-restrict.cc (builtin_memref::extend_offset_range): Same. * graphite-sese-to-poly.cc (add_param_constraints): Same. * internal-fn.cc (get_min_precision): Same. * match.pd: Same. * pointer-query.cc (get_size_range): Same. * range-op.cc (get_shift_range): Same. (operator_trunc_mod::op1_range): Same. (operator_trunc_mod::op2_range): Same. * range.cc (range_negatives): Same. * range.h (range_positives): Same. (range_negatives): Same. * tree-affine.cc (expr_to_aff_combination): Same. * tree-data-ref.cc (compute_distributive_range): Same. (nop_conversion_for_offset_p): Same. (split_constant_offset): Same. (split_constant_offset_1): Same. (dr_step_indicator): Same. * tree-dfa.cc (get_ref_base_and_extent): Same. * tree-scalar-evolution.cc (iv_can_overflow_p): Same. * tree-ssa-math-opts.cc (optimize_spaceship): Same. * tree-ssa-pre.cc (insert_into_preds_of_block): Same. * tree-ssa-reassoc.cc (optimize_range_tests_to_bit_test): Same. * tree-ssa-strlen.cc (compare_nonzero_chars): Same. (dump_strlen_info): Same. (get_range_strlen_dynamic): Same. (set_strlen_range): Same. (maybe_diag_stxncpy_trunc): Same. (strlen_pass::get_len_or_size): Same. (strlen_pass::handle_builtin_string_cmp): Same. (strlen_pass::count_nonzero_bytes_addr): Same. (strlen_pass::handle_integral_assign): Same. * tree-switch-conversion.cc (bit_test_cluster::emit): Same. * tree-vect-loop-manip.cc (vect_gen_vector_loop_niters): Same. (vect_do_peeling): Same. * tree-vect-patterns.cc (vect_get_range_info): Same. (vect_recog_divmod_pattern): Same. * tree.cc (get_range_pos_neg): Same. * value-range.cc (debug): Remove value_range variants. * value-range.h (value_range): Remove typedef. * vr-values.cc (simplify_using_ranges::op_with_boolean_value_range_p): Replace value_range use with int_range_max or irange when appropriate. (check_for_binary_op_overflow): Same. (simplify_using_ranges::legacy_fold_cond_overflow): Same. (find_case_label_ranges): Same. (simplify_using_ranges::simplify_abs_using_ranges): Same. (test_for_singularity): Same. (simplify_using_ranges::simplify_compare_using_ranges_1): Same. (simplify_using_ranges::simplify_casted_compare): Same. (simplify_using_ranges::simplify_switch_using_ranges): Same. (simplify_conversion_using_ranges): Same. (simplify_using_ranges::two_valued_val_range_p): Same. Diff: --- gcc/builtins.cc | 4 ++-- gcc/fold-const.cc| 4 ++-- gcc/gimple-array-bounds.cc | 4 ++-- gcc/gimple-fold.cc | 4 ++-- gcc/gimple-predicate-analysis.cc | 2 +- gcc/gimple-ssa-sprintf.cc| 8 gcc/gimple-ssa-warn-restrict.cc | 2 +- gcc/graphite-sese-to-poly.cc | 2 +- gcc/internal-fn.cc | 2 +- gcc/match.pd | 22 +++--- gcc/pointer-query.cc | 2 +- gcc/range-op.cc |
[gcc r15-785] [prange] Use type agnostic range in phiopt [PR115191]
https://gcc.gnu.org/g:35a293a6454ac0cd88735036f536d8f4ec65951a commit r15-785-g35a293a6454ac0cd88735036f536d8f4ec65951a Author: Aldy Hernandez Date: Wed May 22 22:32:57 2024 +0200 [prange] Use type agnostic range in phiopt [PR115191] Fix a use of int_range_max in phiopt that should be a type agnostic range, because it could be either a pointer or an int. PR tree-optimization/115191 gcc/ChangeLog: * tree-ssa-phiopt.cc (value_replacement): Use Value_Range instead of int_range_max. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/pr115191.c: New test. Diff: --- gcc/testsuite/gcc.dg/tree-ssa/pr115191.c | 10 ++ gcc/tree-ssa-phiopt.cc | 5 ++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr115191.c b/gcc/testsuite/gcc.dg/tree-ssa/pr115191.c new file mode 100644 index 000..43f780aa3b8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr115191.c @@ -0,0 +1,10 @@ +// { dg-do compile } +// { dg-options "-O1 -w" } + +typedef void *SCM; +void set_socket_io_ports(); +void STk_socket_accept(SCM line_buffered) { + if (!line_buffered) +line_buffered = (SCM)3; + set_socket_io_ports(line_buffered != 1); +} diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc index 918cf50b589..65f63eb0652 100644 --- a/gcc/tree-ssa-phiopt.cc +++ b/gcc/tree-ssa-phiopt.cc @@ -1326,12 +1326,11 @@ value_replacement (basic_block cond_bb, basic_block middle_bb, { /* After the optimization PHI result can have value which it couldn't have previously. */ - int_range_max r; + Value_Range r (TREE_TYPE (phires)); if (get_global_range_query ()->range_of_expr (r, phires, phi)) { - wide_int warg = wi::to_wide (carg); - int_range<2> tmp (TREE_TYPE (carg), warg, warg); + Value_Range tmp (carg, carg); r.union_ (tmp); reset_flow_sensitive_info (phires); set_range_info (phires, r);
[gcc r15-632] [prange] Drop range to VARYING if the bitmask intersection made it so [PR115131]
https://gcc.gnu.org/g:1accf4454a2ab57c4d681d1f6db332c46c61c058 commit r15-632-g1accf4454a2ab57c4d681d1f6db332c46c61c058 Author: Aldy Hernandez Date: Fri May 17 13:44:08 2024 +0200 [prange] Drop range to VARYING if the bitmask intersection made it so [PR115131] If the intersection of the bitmasks made the range span the entire domain, normalize the range to VARYING. gcc/ChangeLog: PR middle-end/115131 * value-range.cc (prange::intersect): Set VARYING if intersection of bitmasks made the range span the entire domain. (range_tests_misc): New test. Diff: --- gcc/value-range.cc | 21 + 1 file changed, 21 insertions(+) diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 334ffb70fbc2..b38d6159a856 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -589,6 +589,11 @@ prange::intersect (const vrange ) irange_bitmask new_bitmask = get_bitmask_from_range (m_type, m_min, m_max); m_bitmask.intersect (new_bitmask); m_bitmask.intersect (r.m_bitmask); + if (varying_compatible_p ()) +{ + set_varying (type ()); + return true; +} if (flag_checking) verify_range (); @@ -2889,6 +2894,22 @@ range_tests_misc () p0.invert (); ASSERT_TRUE (p0 == p1); + // The intersection of: + //[0, +INF] MASK 0xff..00 VALUE 0xf8 + //[0, +INF] MASK 0xff..00 VALUE 0x00 + // is [0, +INF] MASK 0xff..ff VALUE 0x00, which is VARYING. + // Test that we normalized to VARYING. + unsigned prec = TYPE_PRECISION (voidp); + p0.set_varying (voidp); + wide_int mask = wi::mask (8, true, prec); + wide_int value = wi::uhwi (0xf8, prec); + irange_bitmask bm (wi::uhwi (0xf8, prec), mask); + p0.update_bitmask (bm); + p1.set_varying (voidp); + bm = irange_bitmask (wi::zero (prec), mask); + p1.update_bitmask (bm); + p0.intersect (p1); + // [10,20] U [15, 30] => [10, 30]. r0 = range_int (10, 20); r1 = range_int (15, 30);
[gcc r15-627] [prange] Avoid looking at type() for undefined ranges
https://gcc.gnu.org/g:bc6e336cb7c85094ddc77757be97c3d8588f35ca commit r15-627-gbc6e336cb7c85094ddc77757be97c3d8588f35ca Author: Aldy Hernandez Date: Fri May 17 10:30:03 2024 +0200 [prange] Avoid looking at type() for undefined ranges Undefined ranges have no type. This patch fixes the thinko. gcc/ChangeLog: PR middle-end/115128 * ipa-cp.cc (ipa_value_range_from_jfunc): Check for undefined_p before looking at type. (propagate_vr_across_jump_function): Same. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/pr115128.c: New test. Diff: --- gcc/ipa-cp.cc| 4 gcc/testsuite/gcc.dg/tree-ssa/pr115128.c | 31 +++ 2 files changed, 35 insertions(+) diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc index 09cab7618226..408166b8044b 100644 --- a/gcc/ipa-cp.cc +++ b/gcc/ipa-cp.cc @@ -1744,6 +1744,8 @@ ipa_value_range_from_jfunc (vrange , pointer type to hold the result instead of a boolean type. Avoid trapping in the sanity check in fold_range until this is fixed. */ + || srcvr.undefined_p () + || op_vr.undefined_p () || !handler.operand_check_p (vr_type, srcvr.type (), op_vr.type ()) || !handler.fold_range (op_res, vr_type, srcvr, op_vr)) op_res.set_varying (vr_type); @@ -2556,6 +2558,8 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc, pointer type to hold the result instead of a boolean type. Avoid trapping in the sanity check in fold_range until this is fixed. */ + || src_lats->m_value_range.m_vr.undefined_p () + || op_vr.undefined_p () || !handler.operand_check_p (operand_type, src_lats->m_value_range.m_vr.type (), op_vr.type ()) diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr115128.c b/gcc/testsuite/gcc.dg/tree-ssa/pr115128.c new file mode 100644 index ..14bd4dbd6e51 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr115128.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -w" } */ + +long XXH3_len_4to8_64b_len, XXH3_len_0to16_64b___trans_tmp_3, XXH3_mix2Accs_acc, +XXH3_64bits_internal___trans_tmp_8; +typedef unsigned long XXH3_hashLong64_f(); +void *XXH3_64bits_internal_input; +int XXH3_64bits_internal___trans_tmp_1; +void XXH3_mul128_fold64(); +static void XXH3_mergeAccs(unsigned long) { + for (;;) +XXH3_mul128_fold64(XXH3_mix2Accs_acc); +} +static __attribute__((noinline)) unsigned long +XXH3_hashLong_64b_default(void *, unsigned long len) { + XXH3_mergeAccs(len * 7); +} +__attribute__((always_inline)) long +XXH3_64bits_internal(unsigned long len, XXH3_hashLong64_f f_hashLong) { + if (len <= 16) { +long keyed = +XXH3_64bits_internal___trans_tmp_1 ^ XXH3_len_0to16_64b___trans_tmp_3; +XXH3_mul128_fold64(keyed, XXH3_len_4to8_64b_len); +return XXH3_64bits_internal___trans_tmp_8; + } + f_hashLong(XXH3_64bits_internal_input, len); +} +static void XXH_INLINE_XXH3_64bits(unsigned long len) { + XXH3_64bits_internal(len, XXH3_hashLong_64b_default); +} +void __cmplog_rtn_hook() { XXH_INLINE_XXH3_64bits(sizeof(long)); }
[gcc r15-575] Revert "Revert: "Enable prange support.""
https://gcc.gnu.org/g:da73261ce7731be7f2b164f1db796878cdc23365 commit r15-575-gda73261ce7731be7f2b164f1db796878cdc23365 Author: Aldy Hernandez Date: Fri May 10 00:38:51 2024 +0200 Revert "Revert: "Enable prange support."" This reverts commit d7bb8eaade3cd3aa70715c8567b4d7b08098e699 and enables prange support again. Diff: --- gcc/gimple-range-cache.cc | 4 ++-- gcc/gimple-range-fold.cc | 4 ++-- gcc/gimple-range-fold.h | 2 +- gcc/gimple-range-infer.cc | 2 +- gcc/gimple-range-op.cc| 2 +- gcc/gimple-range-path.cc | 2 +- gcc/gimple-ssa-warn-access.cc | 2 +- gcc/ipa-cp.h | 2 +- gcc/range-op-ptr.cc | 4 gcc/range-op.cc | 18 -- gcc/tree-ssa-structalias.cc | 2 +- gcc/value-range.cc| 1 + gcc/value-range.h | 4 ++-- 13 files changed, 18 insertions(+), 31 deletions(-) diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc index 72ac25523117..bdd2832873aa 100644 --- a/gcc/gimple-range-cache.cc +++ b/gcc/gimple-range-cache.cc @@ -274,10 +274,10 @@ sbr_sparse_bitmap::sbr_sparse_bitmap (tree t, vrange_allocator *allocator, // Pre-cache zero and non-zero values for pointers. if (POINTER_TYPE_P (t)) { - int_range<2> nonzero; + prange nonzero; nonzero.set_nonzero (t); m_range[1] = m_range_allocator->clone (nonzero); - int_range<2> zero; + prange zero; zero.set_zero (t); m_range[2] = m_range_allocator->clone (zero); } diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc index 9c4ad1ee7b91..a9c8c4d03e63 100644 --- a/gcc/gimple-range-fold.cc +++ b/gcc/gimple-range-fold.cc @@ -597,7 +597,7 @@ fold_using_range::fold_stmt (vrange , gimple *s, fur_source , tree name) // Process addresses. if (gimple_code (s) == GIMPLE_ASSIGN && gimple_assign_rhs_code (s) == ADDR_EXPR) -return range_of_address (as_a (r), s, src); +return range_of_address (as_a (r), s, src); gimple_range_op_handler handler (s); if (handler) @@ -757,7 +757,7 @@ fold_using_range::range_of_range_op (vrange , // If a range cannot be calculated, set it to VARYING and return true. bool -fold_using_range::range_of_address (irange , gimple *stmt, fur_source ) +fold_using_range::range_of_address (prange , gimple *stmt, fur_source ) { gcc_checking_assert (gimple_code (stmt) == GIMPLE_ASSIGN); gcc_checking_assert (gimple_assign_rhs_code (stmt) == ADDR_EXPR); diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h index 7cbe15d05e53..c7c599bfc939 100644 --- a/gcc/gimple-range-fold.h +++ b/gcc/gimple-range-fold.h @@ -157,7 +157,7 @@ protected: fur_source ); bool range_of_call (vrange , gcall *call, fur_source ); bool range_of_cond_expr (vrange , gassign* cond, fur_source ); - bool range_of_address (irange , gimple *s, fur_source ); + bool range_of_address (prange , gimple *s, fur_source ); bool range_of_phi (vrange , gphi *phi, fur_source ); void range_of_ssa_name_with_loop_info (vrange &, tree, class loop *, gphi *, fur_source ); diff --git a/gcc/gimple-range-infer.cc b/gcc/gimple-range-infer.cc index c8e8b9b60ac1..d5e1aa142758 100644 --- a/gcc/gimple-range-infer.cc +++ b/gcc/gimple-range-infer.cc @@ -123,7 +123,7 @@ gimple_infer_range::add_nonzero (tree name) { if (!gimple_range_ssa_p (name)) return; - int_range<2> nz; + prange nz; nz.set_nonzero (TREE_TYPE (name)); add_range (name, nz); } diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc index 7321342b00de..aec3f39ec0e8 100644 --- a/gcc/gimple-range-op.cc +++ b/gcc/gimple-range-op.cc @@ -1107,7 +1107,7 @@ class cfn_strlen : public range_operator { public: using range_operator::fold_range; - virtual bool fold_range (irange , tree type, const irange &, + virtual bool fold_range (irange , tree type, const prange &, const irange &, relation_trio) const { wide_int max = irange_val_max (ptrdiff_type_node); diff --git a/gcc/gimple-range-path.cc b/gcc/gimple-range-path.cc index 96c6ac6b6a50..f1a12f76144c 100644 --- a/gcc/gimple-range-path.cc +++ b/gcc/gimple-range-path.cc @@ -443,7 +443,7 @@ path_range_query::compute_ranges_in_block (basic_block bb) void path_range_query::adjust_for_non_null_uses (basic_block bb) { - int_range_max r; + prange r; bitmap_iterator bi; unsigned i; diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc index 2c10d19e7f36..0cd5b6d6ef48 100644 --- a/gcc/gimple-ssa-warn-access.cc +++ b/gcc/gimple-ssa-warn-access.cc @@ -4213,7 +4213,7 @@ pass_waccess::check_pointer_uses (gimple *stmt, tree ptr, where the realloc call is known to have failed are valid. Ignore pointers that nothing is known about. Those could have escaped along with their nullness. */ - value_range
[gcc r15-574] Cleanup prange sanity checks.
https://gcc.gnu.org/g:b8e3574e68310f68116f157a35d5650600d13718 commit r15-574-gb8e3574e68310f68116f157a35d5650600d13718 Author: Aldy Hernandez Date: Thu May 16 09:47:56 2024 +0200 Cleanup prange sanity checks. The pointers_handled_p() code was a temporary sanity check, and not even a good one, since we have a cleaner way of checking type mismatches with operand_check_p. This patch removes all the code, and adds an explicit type check for relational operators, which are the main problem in PR114985. Adding this check makes it clear where the type mismatch is happening in IPA, even without prange. I've added code to skip the range folding if the types don't match what the operator expects. In order to reproduce the latent bug, just remove the operand_check_p calls. Tested on x86-64 and ppc64le with and without prange support. gcc/ChangeLog: PR tree-optimization/114985 * gimple-range-op.cc: Remove pointers_handled_p. * ipa-cp.cc (ipa_value_range_from_jfunc): Skip range folding if operands don't match. (propagate_vr_across_jump_function): Same. * range-op-mixed.h: Remove pointers_handled_p and tweak operand_check_p. * range-op-ptr.cc (range_operator::pointers_handled_p): Remove. (pointer_plus_operator::pointers_handled_p): Remove. (class operator_pointer_diff): Remove pointers_handled_p. (operator_pointer_diff::pointers_handled_p): Remove. (operator_identity::pointers_handled_p): Remove. (operator_cst::pointers_handled_p): Remove. (operator_cast::pointers_handled_p): Remove. (operator_min::pointers_handled_p): Remove. (operator_max::pointers_handled_p): Remove. (operator_addr_expr::pointers_handled_p): Remove. (operator_bitwise_and::pointers_handled_p): Remove. (operator_bitwise_or::pointers_handled_p): Remove. (operator_equal::pointers_handled_p): Remove. (operator_not_equal::pointers_handled_p): Remove. (operator_lt::pointers_handled_p): Remove. (operator_le::pointers_handled_p): Remove. (operator_gt::pointers_handled_p): Remove. (operator_ge::pointers_handled_p): Remove. * range-op.cc (TRAP_ON_UNHANDLED_POINTER_OPERATORS): Remove. (range_op_handler::lhs_op1_relation): Remove pointers_handled_p checks. (range_op_handler::lhs_op2_relation): Same. (range_op_handler::op1_op2_relation): Same. * range-op.h: Remove RO_* declarations. Diff: --- gcc/gimple-range-op.cc | 24 - gcc/ipa-cp.cc | 12 +++ gcc/range-op-mixed.h | 38 +++- gcc/range-op-ptr.cc| 259 - gcc/range-op.cc| 43 +--- gcc/range-op.h | 17 6 files changed, 25 insertions(+), 368 deletions(-) diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc index 55dfbb23ce22..7321342b00de 100644 --- a/gcc/gimple-range-op.cc +++ b/gcc/gimple-range-op.cc @@ -329,19 +329,6 @@ public: r = lhs; return true; } - virtual bool pointers_handled_p (range_op_dispatch_type type, - unsigned dispatch) const - { -switch (type) - { - case DISPATCH_FOLD_RANGE: - return dispatch == RO_PPP; - case DISPATCH_OP1_RANGE: - return dispatch == RO_PPP; - default: - return true; - } - } } op_cfn_pass_through_arg1; // Implement range operator for CFN_BUILT_IN_SIGNBIT. @@ -1132,17 +1119,6 @@ public: r.set (type, wi::zero (TYPE_PRECISION (type)), max - 2); return true; } - virtual bool pointers_handled_p (range_op_dispatch_type type, - unsigned dispatch) const - { -switch (type) - { - case DISPATCH_FOLD_RANGE: - return dispatch == RO_IPI; - default: - return true; - } - } } op_cfn_strlen; diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc index 5781f50c8546..09cab7618226 100644 --- a/gcc/ipa-cp.cc +++ b/gcc/ipa-cp.cc @@ -1740,6 +1740,11 @@ ipa_value_range_from_jfunc (vrange , if (!handler || !op_res.supports_type_p (vr_type) + /* Sometimes we try to fold comparison operators using a +pointer type to hold the result instead of a boolean +type. Avoid trapping in the sanity check in +fold_range until this is fixed. */ + || !handler.operand_check_p (vr_type, srcvr.type (), op_vr.type ()) || !handler.fold_range (op_res, vr_type, srcvr, op_vr)) op_res.set_varying (vr_type); @@ -2547,6 +2552,13 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc, if (!handler || !ipa_supports_p (operand_type) +
[gcc r15-573] Use a boolean type when folding conditionals in simplify_using_ranges.
https://gcc.gnu.org/g:f6bed6d3fcc13880ffa786b6c616e2306efe2bf3 commit r15-573-gf6bed6d3fcc13880ffa786b6c616e2306efe2bf3 Author: Aldy Hernandez Date: Thu May 16 09:22:55 2024 +0200 Use a boolean type when folding conditionals in simplify_using_ranges. In adding some traps for PR114985 I noticed that the conditional folding code in simplify_using_ranges was using the wrong type. This cleans up the oversight. gcc/ChangeLog: PR tree-optimization/114985 * vr-values.cc (simplify_using_ranges::fold_cond_with_ops): Use boolean type when folding conditionals. Diff: --- gcc/vr-values.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gcc/vr-values.cc b/gcc/vr-values.cc index 0572bf6c8c73..e6ea9592574f 100644 --- a/gcc/vr-values.cc +++ b/gcc/vr-values.cc @@ -316,10 +316,9 @@ simplify_using_ranges::fold_cond_with_ops (enum tree_code code, || !query->range_of_expr (r1, op1, s)) return NULL_TREE; - tree type = TREE_TYPE (op0); int_range<1> res; range_op_handler handler (code); - if (handler && handler.fold_range (res, type, r0, r1)) + if (handler && handler.fold_range (res, boolean_type_node, r0, r1)) { if (res == range_true ()) return boolean_true_node;
[gcc r15-504] [prange] Default pointers_handled_p() to false.
https://gcc.gnu.org/g:c400b2100719d0a9e5989c63e0827b9e98919df3 commit r15-504-gc400b2100719d0a9e5989c63e0827b9e98919df3 Author: Aldy Hernandez Date: Tue May 14 16:21:50 2024 +0200 [prange] Default pointers_handled_p() to false. The pointers_handled_p() method is an internal range-op helper to help catch dispatch type mismatches for pointer operands. This is what caught the IPA mismatch in PR114985. This method is only a temporary measure to catch any incompatibilities in the current pointer range-op entries. This patch returns true for any *new* entries in the range-op table, as the current ones are already fleshed out. This keeps us from having to implement this boilerplate function for any new range-op entries. PR tree-optimization/114995 * range-op-ptr.cc (range_operator::pointers_handled_p): Default to true. Diff: --- gcc/range-op-ptr.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc index 65cca65103af..2f47f3354ed7 100644 --- a/gcc/range-op-ptr.cc +++ b/gcc/range-op-ptr.cc @@ -58,7 +58,7 @@ bool range_operator::pointers_handled_p (range_op_dispatch_type ATTRIBUTE_UNUSED, unsigned dispatch ATTRIBUTE_UNUSED) const { - return false; + return true; } bool
[gcc r15-379] [prange] Default unimplemented prange operators to false.
https://gcc.gnu.org/g:18c93c65a9fbaaf3762198e78fb3c24b9b6fd9fc commit r15-379-g18c93c65a9fbaaf3762198e78fb3c24b9b6fd9fc Author: Aldy Hernandez Date: Fri May 10 18:55:34 2024 +0200 [prange] Default unimplemented prange operators to false. The canonical way to indicate that a range operator is unsupported is to return false, which has the sematic meaning of VARYING. This patch cleans up a few default virtuals that were trying harder to set VARYING manually. gcc/ChangeLog: * range-op-ptr.cc (range_operator::fold_range): Return false. Diff: --- gcc/range-op-ptr.cc | 55 +++-- 1 file changed, 15 insertions(+), 40 deletions(-) diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc index 466edc6bf746..65cca65103af 100644 --- a/gcc/range-op-ptr.cc +++ b/gcc/range-op-ptr.cc @@ -62,63 +62,38 @@ range_operator::pointers_handled_p (range_op_dispatch_type ATTRIBUTE_UNUSED, } bool -range_operator::fold_range (prange , tree type, - const prange , - const prange , - relation_trio trio) const +range_operator::fold_range (prange &, tree, const prange &, const prange &, + relation_trio) const { - relation_kind rel = trio.op1_op2 (); - r.set_varying (type); - op1_op2_relation_effect (r, type, op1, op2, rel); - return true; + return false; } bool -range_operator::fold_range (prange , tree type, - const prange , - const irange , - relation_trio trio) const +range_operator::fold_range (prange &, tree, const prange &, const irange &, + relation_trio) const { - relation_kind rel = trio.op1_op2 (); - r.set_varying (type); - op1_op2_relation_effect (r, type, op1, op2, rel); - return true; + return false; } bool -range_operator::fold_range (irange , tree type, - const prange , - const prange , - relation_trio trio) const +range_operator::fold_range (irange &, tree, const prange &, const prange &, + relation_trio) const { - relation_kind rel = trio.op1_op2 (); - r.set_varying (type); - op1_op2_relation_effect (r, type, op1, op2, rel); - return true; + return false; } bool -range_operator::fold_range (prange , tree type, - const irange , - const prange , - relation_trio trio) const +range_operator::fold_range (prange &, tree, const irange &, const prange &, + relation_trio) const { - relation_kind rel = trio.op1_op2 (); - r.set_varying (type); - op1_op2_relation_effect (r, type, op1, op2, rel); - return true; + return false; } bool -range_operator::fold_range (irange , tree type, - const prange , - const irange , - relation_trio trio) const +range_operator::fold_range (irange &, tree, const prange &, const irange &, + relation_trio) const { - relation_kind rel = trio.op1_op2 (); - r.set_varying (type); - op1_op2_relation_effect (r, type, op1, op2, rel); - return true; + return false; } bool
[gcc r15-378] [prange] Do not trap by default on range dispatch mismatches.
https://gcc.gnu.org/g:45ef24f2702dac4f8707ca682ed364019ee90c44 commit r15-378-g45ef24f2702dac4f8707ca682ed364019ee90c44 Author: Aldy Hernandez Date: Fri May 10 23:21:29 2024 +0200 [prange] Do not trap by default on range dispatch mismatches. The trap in the range-op dispatch code is really an internal debugging aid, and only a temporary one for a few weeks while the dust settles. This patch turns it off by default, allowing problematic passes to turn it on for analysis. gcc/ChangeLog: * range-op.cc (TRAP_ON_UNHANDLED_POINTER_OPERATORS): New (range_op_handler::fold_range): Use it. (range_op_handler::op1_range): Same. (range_op_handler::op2_range): Same. (range_op_handler::lhs_op1_relation): Same. (range_op_handler::lhs_op2_relation): Same. (range_op_handler::op1_op2_relation): Same. Diff: --- gcc/range-op.cc | 23 +-- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/gcc/range-op.cc b/gcc/range-op.cc index a134af68141e..6a410ff656c5 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -49,6 +49,11 @@ along with GCC; see the file COPYING3. If not see #include "tree-ssa-ccp.h" #include "range-op-mixed.h" +// Set to 1 to trap on range-op entries that cannot handle the pointer +// combination being requested. This is a temporary sanity check to +// aid in debugging, and will be removed later in the release cycle. +#define TRAP_ON_UNHANDLED_POINTER_OPERATORS 0 + // Instantiate the operators which apply to multiple types here. operator_equal op_equal; @@ -233,7 +238,8 @@ range_op_handler::fold_range (vrange , tree type, #if CHECKING_P if (!lh.undefined_p () && !rh.undefined_p ()) gcc_assert (m_operator->operand_check_p (type, lh.type (), rh.type ())); - if (has_pointer_operand_p (r, lh, rh) + if (TRAP_ON_UNHANDLED_POINTER_OPERATORS + && has_pointer_operand_p (r, lh, rh) && !m_operator->pointers_handled_p (DISPATCH_FOLD_RANGE, dispatch_kind (r, lh, rh))) discriminator_fail (r, lh, rh); @@ -299,7 +305,8 @@ range_op_handler::op1_range (vrange , tree type, #if CHECKING_P if (!op2.undefined_p ()) gcc_assert (m_operator->operand_check_p (lhs.type (), type, op2.type ())); - if (has_pointer_operand_p (r, lhs, op2) + if (TRAP_ON_UNHANDLED_POINTER_OPERATORS + && has_pointer_operand_p (r, lhs, op2) && !m_operator->pointers_handled_p (DISPATCH_OP1_RANGE, dispatch_kind (r, lhs, op2))) discriminator_fail (r, lhs, op2); @@ -353,7 +360,8 @@ range_op_handler::op2_range (vrange , tree type, #if CHECKING_P if (!op1.undefined_p ()) gcc_assert (m_operator->operand_check_p (lhs.type (), op1.type (), type)); - if (has_pointer_operand_p (r, lhs, op1) + if (TRAP_ON_UNHANDLED_POINTER_OPERATORS + && has_pointer_operand_p (r, lhs, op1) && !m_operator->pointers_handled_p (DISPATCH_OP2_RANGE, dispatch_kind (r, lhs, op1))) discriminator_fail (r, lhs, op1); @@ -395,7 +403,8 @@ range_op_handler::lhs_op1_relation (const vrange , { gcc_checking_assert (m_operator); #if CHECKING_P - if (has_pointer_operand_p (lhs, op1, op2) + if (TRAP_ON_UNHANDLED_POINTER_OPERATORS + && has_pointer_operand_p (lhs, op1, op2) && !m_operator->pointers_handled_p (DISPATCH_LHS_OP1_RELATION, dispatch_kind (lhs, op1, op2))) discriminator_fail (lhs, op1, op2); @@ -442,7 +451,8 @@ range_op_handler::lhs_op2_relation (const vrange , { gcc_checking_assert (m_operator); #if CHECKING_P - if (has_pointer_operand_p (lhs, op1, op2) + if (TRAP_ON_UNHANDLED_POINTER_OPERATORS + && has_pointer_operand_p (lhs, op1, op2) && !m_operator->pointers_handled_p (DISPATCH_LHS_OP2_RELATION, dispatch_kind (lhs, op1, op2))) discriminator_fail (lhs, op1, op2); @@ -475,7 +485,8 @@ range_op_handler::op1_op2_relation (const vrange , { gcc_checking_assert (m_operator); #if CHECKING_P - if (has_pointer_operand_p (lhs, op1, op2) + if (TRAP_ON_UNHANDLED_POINTER_OPERATORS + && has_pointer_operand_p (lhs, op1, op2) && !m_operator->pointers_handled_p (DISPATCH_OP1_OP2_RELATION, dispatch_kind (lhs, op1, op2))) discriminator_fail (lhs, op1, op2);
[gcc r15-363] [prange] Fix thinko in prange::update_bitmask() [PR115026]
https://gcc.gnu.org/g:cbd420a1c3e2bb549dc83b53cc9a31aa6b23952c commit r15-363-gcbd420a1c3e2bb549dc83b53cc9a31aa6b23952c Author: Aldy Hernandez Date: Fri May 10 12:26:49 2024 +0200 [prange] Fix thinko in prange::update_bitmask() [PR115026] gcc/ChangeLog: PR tree-optimization/115026 * value-range.cc (prange::update_bitmask): Use operand bitmask. Diff: --- gcc/value-range.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 3e1ecf69517c..5bcb2c3f650b 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -686,7 +686,7 @@ prange::update_bitmask (const irange_bitmask ) // If all the bits are known, this is a singleton. if (bm.mask () == 0) { - set (type (), m_bitmask.value (), m_bitmask.value ()); + set (type (), bm.value (), bm.value ()); return; }
[gcc r15-357] [prange] Do not assume all pointers are the same size [PR115009]
https://gcc.gnu.org/g:ac255c7afeb8a558bd6224ff77277eebcd849d6e commit r15-357-gac255c7afeb8a558bd6224ff77277eebcd849d6e Author: Aldy Hernandez Date: Thu May 9 23:37:30 2024 +0200 [prange] Do not assume all pointers are the same size [PR115009] In a world with same sized pointers we can always reuse the storage slots, but since this is not always the case, we need to be more careful. However, we can always store an undefined, because that requires no extra storage. gcc/ChangeLog: PR tree-optimization/115009 * value-range-storage.cc (prange_storage::alloc): Do not assume all pointers are the same size. (prange_storage::prange_storage): Same. (prange_storage::fits_p): Same. Diff: --- gcc/value-range-storage.cc | 30 +++--- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/gcc/value-range-storage.cc b/gcc/value-range-storage.cc index bbae0da4772d..8e8d61d59350 100644 --- a/gcc/value-range-storage.cc +++ b/gcc/value-range-storage.cc @@ -593,12 +593,12 @@ frange_storage::fits_p (const frange &) const prange_storage * prange_storage::alloc (vrange_internal_alloc , const prange ) { - // Assume all pointers are the same size. - unsigned prec = TYPE_PRECISION (TREE_TYPE (null_pointer_node)); - gcc_checking_assert (r.undefined_p () || TYPE_PRECISION (r.type ()) == prec); - - typedef trailing_wide_ints twi; - size_t size = sizeof (prange_storage) + twi::extra_size (prec); + size_t size = sizeof (prange_storage); + if (!r.undefined_p ()) +{ + unsigned prec = TYPE_PRECISION (r.type ()); + size += trailing_wide_ints::extra_size (prec); +} prange_storage *p = static_cast (allocator.alloc (size)); new (p) prange_storage (r); return p; @@ -610,8 +610,12 @@ prange_storage::prange_storage (const prange ) { // It is the caller's responsibility to allocate enough space such // that the precision fits. - unsigned prec = TYPE_PRECISION (TREE_TYPE (null_pointer_node)); - m_trailing_ints.set_precision (prec); + if (r.undefined_p ()) +// Undefined ranges do not require any extra space for trailing +// wide ints. +m_trailing_ints.set_precision (0); + else +m_trailing_ints.set_precision (TYPE_PRECISION (r.type ())); set_prange (r); } @@ -669,10 +673,14 @@ prange_storage::equal_p (const prange ) const } bool -prange_storage::fits_p (const prange &) const +prange_storage::fits_p (const prange ) const { - // All pointers are the same size. - return true; + // Undefined ranges always fit, because they don't store anything in + // the trailing wide ints. + if (r.undefined_p ()) +return true; + + return TYPE_PRECISION (r.type ()) <= m_trailing_ints.get_precision (); }
[gcc r15-353] Revert: "Enable prange support." [PR114985]
https://gcc.gnu.org/g:d7bb8eaade3cd3aa70715c8567b4d7b08098e699 commit r15-353-gd7bb8eaade3cd3aa70715c8567b4d7b08098e699 Author: Aldy Hernandez Date: Fri May 10 00:29:13 2024 +0200 Revert: "Enable prange support." [PR114985] This reverts commit 36e877996936abd8bd08f8b1d983c8d1023a5842 until the IPA pass is fixed with regards to POINTER = POINTER POINTER. Diff: --- gcc/gimple-range-cache.cc | 4 ++-- gcc/gimple-range-fold.cc | 4 ++-- gcc/gimple-range-fold.h | 2 +- gcc/gimple-range-infer.cc | 2 +- gcc/gimple-range-op.cc| 2 +- gcc/gimple-range-path.cc | 2 +- gcc/gimple-ssa-warn-access.cc | 2 +- gcc/ipa-cp.h | 2 +- gcc/range-op-ptr.cc | 4 gcc/range-op.cc | 18 ++ gcc/tree-ssa-structalias.cc | 2 +- gcc/value-range.cc| 1 - gcc/value-range.h | 4 ++-- 13 files changed, 31 insertions(+), 18 deletions(-) diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc index bdd2832873aa..72ac25523117 100644 --- a/gcc/gimple-range-cache.cc +++ b/gcc/gimple-range-cache.cc @@ -274,10 +274,10 @@ sbr_sparse_bitmap::sbr_sparse_bitmap (tree t, vrange_allocator *allocator, // Pre-cache zero and non-zero values for pointers. if (POINTER_TYPE_P (t)) { - prange nonzero; + int_range<2> nonzero; nonzero.set_nonzero (t); m_range[1] = m_range_allocator->clone (nonzero); - prange zero; + int_range<2> zero; zero.set_zero (t); m_range[2] = m_range_allocator->clone (zero); } diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc index a9c8c4d03e63..9c4ad1ee7b91 100644 --- a/gcc/gimple-range-fold.cc +++ b/gcc/gimple-range-fold.cc @@ -597,7 +597,7 @@ fold_using_range::fold_stmt (vrange , gimple *s, fur_source , tree name) // Process addresses. if (gimple_code (s) == GIMPLE_ASSIGN && gimple_assign_rhs_code (s) == ADDR_EXPR) -return range_of_address (as_a (r), s, src); +return range_of_address (as_a (r), s, src); gimple_range_op_handler handler (s); if (handler) @@ -757,7 +757,7 @@ fold_using_range::range_of_range_op (vrange , // If a range cannot be calculated, set it to VARYING and return true. bool -fold_using_range::range_of_address (prange , gimple *stmt, fur_source ) +fold_using_range::range_of_address (irange , gimple *stmt, fur_source ) { gcc_checking_assert (gimple_code (stmt) == GIMPLE_ASSIGN); gcc_checking_assert (gimple_assign_rhs_code (stmt) == ADDR_EXPR); diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h index c7c599bfc939..7cbe15d05e53 100644 --- a/gcc/gimple-range-fold.h +++ b/gcc/gimple-range-fold.h @@ -157,7 +157,7 @@ protected: fur_source ); bool range_of_call (vrange , gcall *call, fur_source ); bool range_of_cond_expr (vrange , gassign* cond, fur_source ); - bool range_of_address (prange , gimple *s, fur_source ); + bool range_of_address (irange , gimple *s, fur_source ); bool range_of_phi (vrange , gphi *phi, fur_source ); void range_of_ssa_name_with_loop_info (vrange &, tree, class loop *, gphi *, fur_source ); diff --git a/gcc/gimple-range-infer.cc b/gcc/gimple-range-infer.cc index d5e1aa142758..c8e8b9b60ac1 100644 --- a/gcc/gimple-range-infer.cc +++ b/gcc/gimple-range-infer.cc @@ -123,7 +123,7 @@ gimple_infer_range::add_nonzero (tree name) { if (!gimple_range_ssa_p (name)) return; - prange nz; + int_range<2> nz; nz.set_nonzero (TREE_TYPE (name)); add_range (name, nz); } diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc index ddd13ec55942..55dfbb23ce22 100644 --- a/gcc/gimple-range-op.cc +++ b/gcc/gimple-range-op.cc @@ -1120,7 +1120,7 @@ class cfn_strlen : public range_operator { public: using range_operator::fold_range; - virtual bool fold_range (irange , tree type, const prange &, + virtual bool fold_range (irange , tree type, const irange &, const irange &, relation_trio) const { wide_int max = irange_val_max (ptrdiff_type_node); diff --git a/gcc/gimple-range-path.cc b/gcc/gimple-range-path.cc index f1a12f76144c..96c6ac6b6a50 100644 --- a/gcc/gimple-range-path.cc +++ b/gcc/gimple-range-path.cc @@ -443,7 +443,7 @@ path_range_query::compute_ranges_in_block (basic_block bb) void path_range_query::adjust_for_non_null_uses (basic_block bb) { - prange r; + int_range_max r; bitmap_iterator bi; unsigned i; diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc index 0cd5b6d6ef48..2c10d19e7f36 100644 --- a/gcc/gimple-ssa-warn-access.cc +++ b/gcc/gimple-ssa-warn-access.cc @@ -4213,7 +4213,7 @@ pass_waccess::check_pointer_uses (gimple *stmt, tree ptr, where the realloc call is known to have failed are valid. Ignore pointers that nothing is known about. Those could have escaped along with their
[gcc r15-336] [ranger] Force buffer alignment in Value_Range [PR114912]
https://gcc.gnu.org/g:d7ff8ae5313bea755f5960786b33a7b151e7b663 commit r15-336-gd7ff8ae5313bea755f5960786b33a7b151e7b663 Author: Aldy Hernandez Date: Fri May 3 11:17:32 2024 +0200 [ranger] Force buffer alignment in Value_Range [PR114912] gcc/ChangeLog: PR tree-optimization/114912 * value-range.h (class Value_Range): Use a union. Diff: --- gcc/value-range.h | 30 ++ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/gcc/value-range.h b/gcc/value-range.h index 6e24874c0a25..44cdbd717f4c 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -800,10 +800,14 @@ private: void init (const vrange &); vrange *m_vrange; - // The buffer must be at least the size of the largest range. - static_assert (sizeof (int_range_max) > sizeof (frange), ""); - static_assert (sizeof (int_range_max) > sizeof (prange), ""); - char m_buffer[sizeof (int_range_max)]; + union buffer_type { +int_range_max ints; +frange floats; +unsupported_range unsupported; +prange pointers; +buffer_type () { } +~buffer_type () { } + } m_buffer; }; // The default constructor is uninitialized and must be initialized @@ -811,6 +815,7 @@ private: inline Value_Range::Value_Range () + : m_buffer () { m_vrange = NULL; } @@ -877,13 +882,13 @@ Value_Range::init (tree type) gcc_checking_assert (TYPE_P (type)); if (irange::supports_p (type)) -m_vrange = new (_buffer) int_range_max (); +m_vrange = new (_buffer.ints) int_range_max (); else if (prange::supports_p (type)) -m_vrange = new (_buffer) prange (); +m_vrange = new (_buffer.pointers) prange (); else if (frange::supports_p (type)) -m_vrange = new (_buffer) frange (); +m_vrange = new (_buffer.floats) frange (); else -m_vrange = new (_buffer) unsupported_range (); +m_vrange = new (_buffer.unsupported) unsupported_range (); } // Initialize object with a copy of R. @@ -892,13 +897,14 @@ inline void Value_Range::init (const vrange ) { if (is_a (r)) -m_vrange = new (_buffer) int_range_max (as_a (r)); +m_vrange = new (_buffer.ints) int_range_max (as_a (r)); else if (is_a (r)) -m_vrange = new (_buffer) prange (as_a (r)); +m_vrange = new (_buffer.pointers) prange (as_a (r)); else if (is_a (r)) -m_vrange = new (_buffer) frange (as_a (r)); +m_vrange = new (_buffer.floats) frange (as_a (r)); else -m_vrange = new (_buffer) unsupported_range (as_a (r)); +m_vrange = new (_buffer.unsupported) + unsupported_range (as_a (r)); } // Assignment operator. Copying incompatible types is allowed. That
[gcc r15-335] [prange] Reword dispatch error message
https://gcc.gnu.org/g:be3df704ce7de417682d57bc3e819dfcf0fdd501 commit r15-335-gbe3df704ce7de417682d57bc3e819dfcf0fdd501 Author: Aldy Hernandez Date: Wed May 8 22:50:22 2024 +0200 [prange] Reword dispatch error message After reading the ICE for the PR, it's obvious the error message is rather cryptic. This makes it less so. gcc/ChangeLog: * range-op.cc (range_op_handler::discriminator_fail): Reword error message. Diff: --- gcc/range-op.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gcc/range-op.cc b/gcc/range-op.cc index 245385fe4876..e00136479a6d 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -197,7 +197,8 @@ range_op_handler::discriminator_fail (const vrange , gcc_checking_assert (r1.m_discriminator < sizeof (name) - 1); gcc_checking_assert (r2.m_discriminator < sizeof (name) - 1); gcc_checking_assert (r3.m_discriminator < sizeof (name) - 1); - fprintf (stderr, "DISCRIMINATOR FAIL. Dispatch > RO_%c%c%c <\n", + fprintf (stderr, + "Unsupported operand combination in dispatch: RO_%c%c%c\n", name[r1.m_discriminator], name[r2.m_discriminator], name[r3.m_discriminator]);
[gcc r15-312] Enable prange support.
https://gcc.gnu.org/g:36e877996936abd8bd08f8b1d983c8d1023a5842 commit r15-312-g36e877996936abd8bd08f8b1d983c8d1023a5842 Author: Aldy Hernandez Date: Tue May 7 14:05:50 2024 +0200 Enable prange support. This throws the switch on prange. After this patch, it is no longer valid to store a pointer in an irange (or vice versa). Instead, they must go in prange, which is faster and more memory efficient. I will push this now, so I have time to do any follow-up bugfixing before going on paternity leave. There are various cleanups we plan on doing after this patch (faster intersect/union, remove range-op-mixed.h, remove value_range in favor of int_range_max, reclaim the name for the Value_Range temporary, clean up range-ops, etc etc). But we will hold off on those for now to make it easier to revert this patch, if for some reason we need to do so while I'm away. Tested on x86-64 Linux. gcc/ChangeLog: * gimple-range-cache.cc (sbr_sparse_bitmap::sbr_sparse_bitmap): Change irange to prange. * gimple-range-fold.cc (fold_using_range::fold_stmt): Same. (fold_using_range::range_of_address): Same. * gimple-range-fold.h (range_of_address): Same. * gimple-range-infer.cc (gimple_infer_range::add_nonzero): Same. * gimple-range-op.cc (class cfn_strlen): Same. * gimple-range-path.cc (path_range_query::adjust_for_non_null_uses): Same. * gimple-ssa-warn-access.cc (pass_waccess::check_pointer_uses): Same. * tree-ssa-structalias.cc (find_what_p_points_to): Same. * range-op-ptr.cc (range_op_table::initialize_pointer_ops): Remove hybrid entries in table. * range-op.cc (range_op_table::range_op_table): Add pointer entries for bitwise and/or and min/max. * value-range.cc (irange::verify_range): Add assert. * value-range.h (irange::varying_compatible_p): Remove check for error_mark_node. (irange::supports_p): Remove pointer support. * ipa-cp.h (ipa_supports_p): Add prange support. Diff: --- gcc/gimple-range-cache.cc | 4 ++-- gcc/gimple-range-fold.cc | 4 ++-- gcc/gimple-range-fold.h | 2 +- gcc/gimple-range-infer.cc | 2 +- gcc/gimple-range-op.cc| 2 +- gcc/gimple-range-path.cc | 2 +- gcc/gimple-ssa-warn-access.cc | 2 +- gcc/ipa-cp.h | 2 +- gcc/range-op-ptr.cc | 4 gcc/range-op.cc | 18 -- gcc/tree-ssa-structalias.cc | 2 +- gcc/value-range.cc| 1 + gcc/value-range.h | 4 ++-- 13 files changed, 18 insertions(+), 31 deletions(-) diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc index 72ac25523117..bdd2832873aa 100644 --- a/gcc/gimple-range-cache.cc +++ b/gcc/gimple-range-cache.cc @@ -274,10 +274,10 @@ sbr_sparse_bitmap::sbr_sparse_bitmap (tree t, vrange_allocator *allocator, // Pre-cache zero and non-zero values for pointers. if (POINTER_TYPE_P (t)) { - int_range<2> nonzero; + prange nonzero; nonzero.set_nonzero (t); m_range[1] = m_range_allocator->clone (nonzero); - int_range<2> zero; + prange zero; zero.set_zero (t); m_range[2] = m_range_allocator->clone (zero); } diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc index 9c4ad1ee7b91..a9c8c4d03e63 100644 --- a/gcc/gimple-range-fold.cc +++ b/gcc/gimple-range-fold.cc @@ -597,7 +597,7 @@ fold_using_range::fold_stmt (vrange , gimple *s, fur_source , tree name) // Process addresses. if (gimple_code (s) == GIMPLE_ASSIGN && gimple_assign_rhs_code (s) == ADDR_EXPR) -return range_of_address (as_a (r), s, src); +return range_of_address (as_a (r), s, src); gimple_range_op_handler handler (s); if (handler) @@ -757,7 +757,7 @@ fold_using_range::range_of_range_op (vrange , // If a range cannot be calculated, set it to VARYING and return true. bool -fold_using_range::range_of_address (irange , gimple *stmt, fur_source ) +fold_using_range::range_of_address (prange , gimple *stmt, fur_source ) { gcc_checking_assert (gimple_code (stmt) == GIMPLE_ASSIGN); gcc_checking_assert (gimple_assign_rhs_code (stmt) == ADDR_EXPR); diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h index 7cbe15d05e53..c7c599bfc939 100644 --- a/gcc/gimple-range-fold.h +++ b/gcc/gimple-range-fold.h @@ -157,7 +157,7 @@ protected: fur_source ); bool range_of_call (vrange , gcall *call, fur_source ); bool range_of_cond_expr (vrange , gassign* cond, fur_source ); - bool range_of_address (irange , gimple *s, fur_source ); + bool range_of_address (prange , gimple *s, fur_source ); bool range_of_phi (vrange , gphi *phi, fur_source ); void range_of_ssa_name_with_loop_info (vrange &, tree,
[gcc r15-270] Minor range type fixes for IPA in preparation for prange.
https://gcc.gnu.org/g:24853cd854eb9b8a5c7b9706ad0908221bf964ce commit r15-270-g24853cd854eb9b8a5c7b9706ad0908221bf964ce Author: Aldy Hernandez Date: Tue Mar 19 17:55:58 2024 +0100 Minor range type fixes for IPA in preparation for prange. The polymorphic Value_Range object takes a tree type at construction so it can determine what type of range to use (currently irange or frange). It seems a few of the types are slightly off. This isn't a problem now, because IPA only cares about integers and pointers, which can both live in an irange. However, with prange coming about, we need to get the type right, because you can't store an integer in a pointer range or vice versa. Also, in preparation for prange, the irange::supports_p() idiom will become: irange::supports_p () || prange::supports_p() To avoid changing all these places, I've added an inline function we can later change and change everything at once. Finally, there's a Value_Range::supports_type_p() && irange::supports_p() in the code. The latter is a subset of the former, so there's no need to check both. gcc/ChangeLog: * ipa-cp.cc (ipa_vr_operation_and_type_effects): Use ipa_supports_p. (ipa_value_range_from_jfunc): Change Value_Range type. (propagate_vr_across_jump_function): Same. * ipa-cp.h (ipa_supports_p): New. * ipa-fnsummary.cc (evaluate_conditions_for_known_args): Change Value_Range type. * ipa-prop.cc (ipa_compute_jump_functions_for_edge): Use ipa_supports_p. (ipcp_get_parm_bits): Same. Diff: --- gcc/ipa-cp.cc| 14 +++--- gcc/ipa-cp.h | 8 gcc/ipa-fnsummary.cc | 2 +- gcc/ipa-prop.cc | 8 +++- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc index a688dced5c9..5781f50c854 100644 --- a/gcc/ipa-cp.cc +++ b/gcc/ipa-cp.cc @@ -1649,7 +1649,7 @@ ipa_vr_operation_and_type_effects (vrange _vr, enum tree_code operation, tree dst_type, tree src_type) { - if (!irange::supports_p (dst_type) || !irange::supports_p (src_type)) + if (!ipa_supports_p (dst_type) || !ipa_supports_p (src_type)) return false; range_op_handler handler (operation); @@ -1720,7 +1720,7 @@ ipa_value_range_from_jfunc (vrange , if (TREE_CODE_CLASS (operation) == tcc_unary) { - Value_Range res (vr_type); + Value_Range res (parm_type); if (ipa_vr_operation_and_type_effects (res, srcvr, @@ -1733,7 +1733,7 @@ ipa_value_range_from_jfunc (vrange , Value_Range op_res (vr_type); Value_Range res (vr_type); tree op = ipa_get_jf_pass_through_operand (jfunc); - Value_Range op_vr (vr_type); + Value_Range op_vr (TREE_TYPE (op)); range_op_handler handler (operation); ipa_range_set_and_normalize (op_vr, op); @@ -2527,7 +2527,7 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc, if (src_lats->m_value_range.bottom_p ()) return dest_lat->set_to_bottom (); - Value_Range vr (operand_type); + Value_Range vr (param_type); if (TREE_CODE_CLASS (operation) == tcc_unary) ipa_vr_operation_and_type_effects (vr, src_lats->m_value_range.m_vr, @@ -2540,16 +2540,16 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc, { tree op = ipa_get_jf_pass_through_operand (jfunc); Value_Range op_vr (TREE_TYPE (op)); - Value_Range op_res (operand_type); + Value_Range op_res (param_type); range_op_handler handler (operation); ipa_range_set_and_normalize (op_vr, op); if (!handler - || !op_res.supports_type_p (operand_type) + || !ipa_supports_p (operand_type) || !handler.fold_range (op_res, operand_type, src_lats->m_value_range.m_vr, op_vr)) - op_res.set_varying (operand_type); + op_res.set_varying (param_type); ipa_vr_operation_and_type_effects (vr, op_res, diff --git a/gcc/ipa-cp.h b/gcc/ipa-cp.h index 7ff74fb5c98..abeaaa4053e 100644 --- a/gcc/ipa-cp.h +++ b/gcc/ipa-cp.h @@ -291,4 +291,12 @@ public: bool values_equal_for_ipcp_p (tree x, tree y); +/* Return TRUE if IPA supports ranges of TYPE. */ + +static inline bool +ipa_supports_p (tree type) +{ + return irange::supports_p (type); +} + #endif /* IPA_CP_H */ diff --git a/gcc/ipa-fnsummary.cc b/gcc/ipa-fnsummary.cc index 668a01ef175..07a853f78e3 100644 --- a/gcc/ipa-fnsummary.cc +++ b/gcc/ipa-fnsummary.cc @@ -515,7 +515,7 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
[gcc r15-164] Add prange entries in gimple-range-op.cc.
https://gcc.gnu.org/g:6cec31d44a426fa031ca07266fd2723b0038de83 commit r15-164-g6cec31d44a426fa031ca07266fd2723b0038de83 Author: Aldy Hernandez Date: Wed Mar 20 11:27:21 2024 +0100 Add prange entries in gimple-range-op.cc. gcc/ChangeLog: * gimple-range-op.cc (class cfn_pass_through_arg1): Add overloads for prange operations. (cfn_strlen): Same. Diff: --- gcc/gimple-range-op.cc | 36 1 file changed, 36 insertions(+) diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc index 587de186db2..55dfbb23ce2 100644 --- a/gcc/gimple-range-op.cc +++ b/gcc/gimple-range-op.cc @@ -311,12 +311,37 @@ public: r = lh; return true; } + virtual bool fold_range (prange , tree, const prange , + const prange &, relation_trio) const + { +r = lh; +return true; + } virtual bool op1_range (irange , tree, const irange , const irange &, relation_trio) const { r = lhs; return true; } + virtual bool op1_range (prange , tree, const prange , + const prange &, relation_trio) const + { +r = lhs; +return true; + } + virtual bool pointers_handled_p (range_op_dispatch_type type, + unsigned dispatch) const + { +switch (type) + { + case DISPATCH_FOLD_RANGE: + return dispatch == RO_PPP; + case DISPATCH_OP1_RANGE: + return dispatch == RO_PPP; + default: + return true; + } + } } op_cfn_pass_through_arg1; // Implement range operator for CFN_BUILT_IN_SIGNBIT. @@ -1107,6 +1132,17 @@ public: r.set (type, wi::zero (TYPE_PRECISION (type)), max - 2); return true; } + virtual bool pointers_handled_p (range_op_dispatch_type type, + unsigned dispatch) const + { +switch (type) + { + case DISPATCH_FOLD_RANGE: + return dispatch == RO_IPI; + default: + return true; + } + } } op_cfn_strlen;
[gcc r15-163] Implement operator_ge for prange....
https://gcc.gnu.org/g:ff306c77b7cf5b7b09914f38b7351328835ac4ce commit r15-163-gff306c77b7cf5b7b09914f38b7351328835ac4ce Author: Aldy Hernandez Date: Wed Mar 20 11:15:03 2024 +0100 Implement operator_ge for prange gcc/ChangeLog: * range-op-mixed.h: Add overloaded declarations for pointer variants. * range-op-ptr.cc (operator_ge::fold_range): New. (operator_ge::op1_range): New. (operator_ge::op2_range): New. (operator_ge::op1_op2_relation): New. (operator_ge::pointers_handled_p): New. Diff: --- gcc/range-op-mixed.h | 12 ++ gcc/range-op-ptr.cc | 108 +++ 2 files changed, 120 insertions(+) diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h index f7a07b19635..44d51d68655 100644 --- a/gcc/range-op-mixed.h +++ b/gcc/range-op-mixed.h @@ -371,6 +371,9 @@ public: bool fold_range (irange , tree type, const irange , const irange , relation_trio = TRIO_VARYING) const final override; + bool fold_range (irange , tree type, + const prange , const prange , + relation_trio = TRIO_VARYING) const final override; bool fold_range (irange , tree type, const frange , const frange , relation_trio = TRIO_VARYING) const final override; @@ -378,6 +381,9 @@ public: bool op1_range (irange , tree type, const irange , const irange , relation_trio = TRIO_VARYING) const final override; + bool op1_range (prange , tree type, + const irange , const prange , + relation_trio = TRIO_VARYING) const final override; bool op1_range (frange , tree type, const irange , const frange , relation_trio = TRIO_VARYING) const final override; @@ -385,12 +391,17 @@ public: bool op2_range (irange , tree type, const irange , const irange , relation_trio = TRIO_VARYING) const final override; + bool op2_range (prange , tree type, + const irange , const prange , + relation_trio = TRIO_VARYING) const final override; bool op2_range (frange , tree type, const irange , const frange , relation_trio = TRIO_VARYING) const final override; relation_kind op1_op2_relation (const irange , const irange &, const irange &) const final override; + relation_kind op1_op2_relation (const irange , const prange &, + const prange &) const final override; relation_kind op1_op2_relation (const irange , const frange &, const frange &) const final override; void update_bitmask (irange , const irange , @@ -398,6 +409,7 @@ public: // Check op1 and op2 for compatibility. bool operand_check_p (tree, tree t1, tree t2) const final override { return range_compatible_p (t1, t2); } + bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override; }; class operator_identity : public range_operator diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc index 441a18c08c7..466edc6bf74 100644 --- a/gcc/range-op-ptr.cc +++ b/gcc/range-op-ptr.cc @@ -1853,6 +1853,114 @@ operator_gt::pointers_handled_p (range_op_dispatch_type type, } } +bool +operator_ge::fold_range (irange , tree type, +const prange , +const prange , +relation_trio rel) const +{ + if (relop_early_resolve (r, type, op1, op2, rel, VREL_GE)) +return true; + + signop sign = TYPE_SIGN (op1.type ()); + gcc_checking_assert (sign == TYPE_SIGN (op2.type ())); + + if (wi::ge_p (op1.lower_bound (), op2.upper_bound (), sign)) +r = range_true (); + else if (!wi::ge_p (op1.upper_bound (), op2.lower_bound (), sign)) +r = range_false (); + else +r = range_true_and_false (); + + //update_known_bitmask (r, GE_EXPR, op1, op2); + return true; +} + +bool +operator_ge::op1_range (prange , tree type, + const irange , + const prange , + relation_trio) const +{ + if (op2.undefined_p ()) +return false; + + switch (get_bool_state (r, lhs, type)) +{ +case BRS_TRUE: + build_ge (r, type, op2); + break; + +case BRS_FALSE: + build_lt (r, type, op2); + break; + +default: + break; +} + return true; +} + +bool +operator_ge::op2_range (prange , tree type, + const irange , + const prange , + relation_trio) const +{ + if (op1.undefined_p ()) +return false; + + switch (get_bool_state (r, lhs, type)) +{ +case BRS_TRUE: + build_le (r, type, op1); + break; + +case BRS_FALSE: + build_gt (r, type, op1); + break; + +
[gcc r15-162] Implement operator_gt for prange.
https://gcc.gnu.org/g:76fae4051a72b2d417d50f1980dff8ab0c50d0c5 commit r15-162-g76fae4051a72b2d417d50f1980dff8ab0c50d0c5 Author: Aldy Hernandez Date: Wed Mar 20 11:10:03 2024 +0100 Implement operator_gt for prange. gcc/ChangeLog: * range-op-mixed.h: Add overloaded declarations for pointer variants. * range-op-ptr.cc (operator_gt::fold_range): New. (operator_gt::op1_range): New. (operator_gt::op2_range): New. (operator_gt::op1_op2_relation): New. (operator_gt::pointers_handled_p): New. Diff: --- gcc/range-op-mixed.h | 12 ++ gcc/range-op-ptr.cc | 106 +++ 2 files changed, 118 insertions(+) diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h index 571729e2ab6..f7a07b19635 100644 --- a/gcc/range-op-mixed.h +++ b/gcc/range-op-mixed.h @@ -320,6 +320,9 @@ public: bool fold_range (irange , tree type, const irange , const irange , relation_trio = TRIO_VARYING) const final override; + bool fold_range (irange , tree type, + const prange , const prange , + relation_trio = TRIO_VARYING) const final override; bool fold_range (irange , tree type, const frange , const frange , relation_trio = TRIO_VARYING) const final override; @@ -327,6 +330,9 @@ public: bool op1_range (irange , tree type, const irange , const irange , relation_trio = TRIO_VARYING) const final override; + bool op1_range (prange , tree type, + const irange , const prange , + relation_trio = TRIO_VARYING) const final override; bool op1_range (frange , tree type, const irange , const frange , relation_trio = TRIO_VARYING) const final override; @@ -334,11 +340,16 @@ public: bool op2_range (irange , tree type, const irange , const irange , relation_trio = TRIO_VARYING) const final override; + bool op2_range (prange , tree type, + const irange , const prange , + relation_trio = TRIO_VARYING) const final override; bool op2_range (frange , tree type, const irange , const frange , relation_trio = TRIO_VARYING) const final override; relation_kind op1_op2_relation (const irange , const irange &, const irange &) const final override; + relation_kind op1_op2_relation (const irange , const prange &, + const prange &) const final override; relation_kind op1_op2_relation (const irange , const frange &, const frange &) const final override; void update_bitmask (irange , const irange , @@ -346,6 +357,7 @@ public: // Check op1 and op2 for compatibility. bool operand_check_p (tree, tree t1, tree t2) const final override { return range_compatible_p (t1, t2); } + bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override; }; class operator_ge : public range_operator diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc index eb28211b583..441a18c08c7 100644 --- a/gcc/range-op-ptr.cc +++ b/gcc/range-op-ptr.cc @@ -1747,6 +1747,112 @@ operator_le::pointers_handled_p (range_op_dispatch_type type, } } +bool +operator_gt::fold_range (irange , tree type, +const prange , const prange , +relation_trio rel) const +{ + if (relop_early_resolve (r, type, op1, op2, rel, VREL_GT)) +return true; + + signop sign = TYPE_SIGN (op1.type ()); + gcc_checking_assert (sign == TYPE_SIGN (op2.type ())); + + if (wi::gt_p (op1.lower_bound (), op2.upper_bound (), sign)) +r = range_true (); + else if (!wi::gt_p (op1.upper_bound (), op2.lower_bound (), sign)) +r = range_false (); + else +r = range_true_and_false (); + + //update_known_bitmask (r, GT_EXPR, op1, op2); + return true; +} + +bool +operator_gt::op1_range (prange , tree type, + const irange , const prange , + relation_trio) const +{ + if (op2.undefined_p ()) +return false; + + switch (get_bool_state (r, lhs, type)) +{ +case BRS_TRUE: + build_gt (r, type, op2); + break; + +case BRS_FALSE: + build_le (r, type, op2); + break; + +default: + break; +} + return true; +} + +bool +operator_gt::op2_range (prange , tree type, + const irange , + const prange , + relation_trio) const +{ + if (op1.undefined_p ()) +return false; + + switch (get_bool_state (r, lhs, type)) +{ +case BRS_TRUE: + build_lt (r, type, op1); + break; + +case BRS_FALSE: + build_ge (r, type, op1); + break; + +default: + break; +} + return true; +} + +relation_kind
[gcc r15-161] Implement operator_le for prange.
https://gcc.gnu.org/g:3a4ee6ea8627efe0d34a71d0ea4ce9b70d34df18 commit r15-161-g3a4ee6ea8627efe0d34a71d0ea4ce9b70d34df18 Author: Aldy Hernandez Date: Wed Mar 20 11:07:30 2024 +0100 Implement operator_le for prange. gcc/ChangeLog: * range-op-mixed.h: Add overloaded declarations for pointer variants. * range-op-ptr.cc (operator_le::fold_range): New. (operator_le::op1_range): New. (operator_le::op2_range): New. (operator_le::op1_op2_relation): New. (operator_le::pointers_handled_p): New. Diff: --- gcc/range-op-mixed.h | 12 ++ gcc/range-op-ptr.cc | 108 +++ 2 files changed, 120 insertions(+) diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h index b82d06572a7..571729e2ab6 100644 --- a/gcc/range-op-mixed.h +++ b/gcc/range-op-mixed.h @@ -268,6 +268,9 @@ public: bool fold_range (irange , tree type, const irange , const irange , relation_trio = TRIO_VARYING) const final override; + bool fold_range (irange , tree type, + const prange , const prange , + relation_trio = TRIO_VARYING) const final override; bool fold_range (irange , tree type, const frange , const frange , relation_trio rel = TRIO_VARYING) const final override; @@ -275,6 +278,9 @@ public: bool op1_range (irange , tree type, const irange , const irange , relation_trio = TRIO_VARYING) const final override; + bool op1_range (prange , tree type, + const irange , const prange , + relation_trio = TRIO_VARYING) const final override; bool op1_range (frange , tree type, const irange , const frange , relation_trio rel = TRIO_VARYING) const final override; @@ -282,12 +288,17 @@ public: bool op2_range (irange , tree type, const irange , const irange , relation_trio = TRIO_VARYING) const final override; + bool op2_range (prange , tree type, + const irange , const prange , + relation_trio = TRIO_VARYING) const final override; bool op2_range (frange , tree type, const irange , const frange , relation_trio rel = TRIO_VARYING) const final override; relation_kind op1_op2_relation (const irange , const irange &, const irange &) const final override; + relation_kind op1_op2_relation (const irange , const prange &, + const prange &) const final override; relation_kind op1_op2_relation (const irange , const frange &, const frange &) const final override; void update_bitmask (irange , const irange , @@ -295,6 +306,7 @@ public: // Check op1 and op2 for compatibility. bool operand_check_p (tree, tree t1, tree t2) const final override { return range_compatible_p (t1, t2); } + bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override; }; class operator_gt : public range_operator diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc index 11629ba6d8d..eb28211b583 100644 --- a/gcc/range-op-ptr.cc +++ b/gcc/range-op-ptr.cc @@ -1639,6 +1639,114 @@ operator_lt::pointers_handled_p (range_op_dispatch_type type, } } +bool +operator_le::fold_range (irange , tree type, +const prange , +const prange , +relation_trio rel) const +{ + if (relop_early_resolve (r, type, op1, op2, rel, VREL_LE)) +return true; + + signop sign = TYPE_SIGN (op1.type ()); + gcc_checking_assert (sign == TYPE_SIGN (op2.type ())); + + if (wi::le_p (op1.upper_bound (), op2.lower_bound (), sign)) +r = range_true (); + else if (!wi::le_p (op1.lower_bound (), op2.upper_bound (), sign)) +r = range_false (); + else +r = range_true_and_false (); + + //update_known_bitmask (r, LE_EXPR, op1, op2); + return true; +} + +bool +operator_le::op1_range (prange , tree type, + const irange , + const prange , + relation_trio) const +{ + if (op2.undefined_p ()) +return false; + + switch (get_bool_state (r, lhs, type)) +{ +case BRS_TRUE: + build_le (r, type, op2); + break; + +case BRS_FALSE: + build_gt (r, type, op2); + break; + +default: + break; +} + return true; +} + +bool +operator_le::op2_range (prange , tree type, + const irange , + const prange , + relation_trio) const +{ + if (op1.undefined_p ()) +return false; + + switch (get_bool_state (r, lhs, type)) +{ +case BRS_TRUE: + build_ge (r, type, op1); + break; + +case BRS_FALSE: + build_lt (r, type, op1); + break; + +
[gcc r15-160] Implement operator_lt for prange.
https://gcc.gnu.org/g:bfa2323d1ddf96a4f40a26aa39b8e1e3bd9b6d98 commit r15-160-gbfa2323d1ddf96a4f40a26aa39b8e1e3bd9b6d98 Author: Aldy Hernandez Date: Wed Mar 20 11:03:24 2024 +0100 Implement operator_lt for prange. gcc/ChangeLog: * range-op-mixed.h: Add overloaded declarations for pointer variants. * range-op-ptr.cc (max_limit): New. (min_limit): New. (build_lt): New. (build_le): New. (build_gt): New. (build_ge): New. (operator_lt::fold_range): New. (operator_lt::op1_range): New. (operator_lt::op2_range): New. (operator_lt::op1_op2_relation): New. (operator_lt::pointers_handled_p): New. Diff: --- gcc/range-op-mixed.h | 12 gcc/range-op-ptr.cc | 174 +++ 2 files changed, 186 insertions(+) diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h index ee8d9dd328f..b82d06572a7 100644 --- a/gcc/range-op-mixed.h +++ b/gcc/range-op-mixed.h @@ -219,23 +219,34 @@ public: bool fold_range (irange , tree type, const irange , const irange , relation_trio = TRIO_VARYING) const final override; + bool fold_range (irange , tree type, + const prange , const prange , + relation_trio = TRIO_VARYING) const final override; bool fold_range (irange , tree type, const frange , const frange , relation_trio = TRIO_VARYING) const final override; bool op1_range (irange , tree type, const irange , const irange , relation_trio = TRIO_VARYING) const final override; + bool op1_range (prange , tree type, + const irange , const prange , + relation_trio = TRIO_VARYING) const final override; bool op1_range (frange , tree type, const irange , const frange , relation_trio = TRIO_VARYING) const final override; bool op2_range (irange , tree type, const irange , const irange , relation_trio = TRIO_VARYING) const final override; + bool op2_range (prange , tree type, + const irange , const prange , + relation_trio = TRIO_VARYING) const final override; bool op2_range (frange , tree type, const irange , const frange , relation_trio = TRIO_VARYING) const final override; relation_kind op1_op2_relation (const irange , const irange &, const irange &) const final override; + relation_kind op1_op2_relation (const irange , const prange &, + const prange &) const final override; relation_kind op1_op2_relation (const irange , const frange &, const frange &) const final override; void update_bitmask (irange , const irange , @@ -243,6 +254,7 @@ public: // Check op1 and op2 for compatibility. bool operand_check_p (tree, tree t1, tree t2) const final override { return range_compatible_p (t1, t2); } + bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override; }; class operator_le : public range_operator diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc index fb2888bf079..11629ba6d8d 100644 --- a/gcc/range-op-ptr.cc +++ b/gcc/range-op-ptr.cc @@ -262,6 +262,69 @@ range_operator::update_bitmask (irange &, { } +// Return the upper limit for a type. + +static inline wide_int +max_limit (const_tree type) +{ + return wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type)); +} + +// Return the lower limit for a type. + +static inline wide_int +min_limit (const_tree type) +{ + return wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type)); +} + +// Build a range that is < VAL and store it in R. + +static void +build_lt (prange , tree type, const prange ) +{ + wi::overflow_type ov; + wide_int lim = wi::sub (val.upper_bound (), 1, UNSIGNED, ); + + // If val - 1 underflows, check if X < MIN, which is an empty range. + if (ov) +r.set_undefined (); + else +r.set (type, min_limit (type), lim); +} + +// Build a range that is <= VAL and store it in R. + +static void +build_le (prange , tree type, const prange ) +{ + r.set (type, min_limit (type), val.upper_bound ()); +} + +// Build a range that is > VAL and store it in R. + +static void +build_gt (prange , tree type, const prange ) +{ + wi::overflow_type ov; + wide_int lim = wi::add (val.lower_bound (), 1, UNSIGNED, ); + + // If val + 1 overflows, check is for X > MAX, which is an empty range. + if (ov) +r.set_undefined (); + else +r.set (type, lim, max_limit (type)); + +} + +// Build a range that is >= VAL and store it in R. + +static void +build_ge (prange , tree type, const prange ) +{ + r.set (type, val.lower_bound (), max_limit (type)); +} + class pointer_plus_operator : public
[gcc r15-158] Implement operator_not_equal for prange.
https://gcc.gnu.org/g:d1be4c907fa47d868d6ef31e8fd7ede0535420ca commit r15-158-gd1be4c907fa47d868d6ef31e8fd7ede0535420ca Author: Aldy Hernandez Date: Wed Mar 20 10:49:11 2024 +0100 Implement operator_not_equal for prange. gcc/ChangeLog: * range-op-mixed.h: Add overloaded declarations for pointer variants. * range-op-ptr.cc (operator_not_equal::fold_range): New. (operator_not_equal::op1_range): New. (operator_not_equal::op2_range): New. (operator_not_equal::op1_op2_relation): New. (operator_not_equal::pointers_handled_p): New. Diff: --- gcc/range-op-mixed.h | 12 ++ gcc/range-op-ptr.cc | 118 +++ 2 files changed, 130 insertions(+) diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h index c45aed93567..980611dc339 100644 --- a/gcc/range-op-mixed.h +++ b/gcc/range-op-mixed.h @@ -155,6 +155,9 @@ public: bool fold_range (irange , tree type, const irange , const irange , relation_trio = TRIO_VARYING) const final override; + bool fold_range (irange , tree type, + const prange , const prange , + relation_trio rel = TRIO_VARYING) const final override; bool fold_range (irange , tree type, const frange , const frange , relation_trio rel = TRIO_VARYING) const final override; @@ -162,6 +165,9 @@ public: bool op1_range (irange , tree type, const irange , const irange , relation_trio = TRIO_VARYING) const final override; + bool op1_range (prange , tree type, + const irange , const prange , + relation_trio = TRIO_VARYING) const final override; bool op1_range (frange , tree type, const irange , const frange , relation_trio = TRIO_VARYING) const final override; @@ -169,12 +175,17 @@ public: bool op2_range (irange , tree type, const irange , const irange , relation_trio = TRIO_VARYING) const final override; + bool op2_range (prange , tree type, + const irange , const prange , + relation_trio = TRIO_VARYING) const final override; bool op2_range (frange , tree type, const irange , const frange , relation_trio = TRIO_VARYING) const final override; relation_kind op1_op2_relation (const irange , const irange &, const irange &) const final override; + relation_kind op1_op2_relation (const irange , const prange &, + const prange &) const final override; relation_kind op1_op2_relation (const irange , const frange &, const frange &) const final override; void update_bitmask (irange , const irange , @@ -182,6 +193,7 @@ public: // Check op1 and op2 for compatibility. bool operand_check_p (tree, tree t1, tree t2) const final override { return range_compatible_p (t1, t2); } + bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override; }; class operator_lt : public range_operator diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc index 2f2f4bb2b5d..081e8fdba1f 100644 --- a/gcc/range-op-ptr.cc +++ b/gcc/range-op-ptr.cc @@ -1230,6 +1230,124 @@ operator_bitwise_or::pointers_handled_p (range_op_dispatch_type, return false; } +bool +operator_not_equal::fold_range (irange , tree type, + const prange , + const prange , + relation_trio rel) const +{ + if (relop_early_resolve (r, type, op1, op2, rel, VREL_NE)) +return true; + + // We can be sure the values are always equal or not if both ranges + // consist of a single value, and then compare them. + bool op1_const = wi::eq_p (op1.lower_bound (), op1.upper_bound ()); + bool op2_const = wi::eq_p (op2.lower_bound (), op2.upper_bound ()); + if (op1_const && op2_const) +{ + if (wi::ne_p (op1.lower_bound (), op2.upper_bound())) + r = range_true (); + else + r = range_false (); +} + else +{ + // If ranges do not intersect, we know the range is not equal, + // otherwise we don't know anything for sure. + prange tmp = op1; + tmp.intersect (op2); + if (tmp.undefined_p ()) + r = range_true (); + // Check if a constant cannot satisfy the bitmask requirements. + else if (op2_const && !op1.get_bitmask ().member_p (op2.lower_bound ())) +r = range_true (); + else if (op1_const && !op2.get_bitmask ().member_p (op1.lower_bound ())) +r = range_true (); + else + r = range_true_and_false (); +} + + //update_known_bitmask (r, NE_EXPR, op1, op2); + return true; +} + +bool +operator_not_equal::op1_range (prange , tree type, + const
[gcc r15-159] Implement operator_equal for prange.
https://gcc.gnu.org/g:bcb226924f50d9b84ca32b6f39abb63b43e23229 commit r15-159-gbcb226924f50d9b84ca32b6f39abb63b43e23229 Author: Aldy Hernandez Date: Wed Mar 20 10:54:39 2024 +0100 Implement operator_equal for prange. gcc/ChangeLog: * range-op-mixed.h: Add overloaded declarations for pointer variants. * range-op-ptr.cc (operator_equal::fold_range): New. (operator_equal::op1_range): New. (operator_equal::op2_range): New. (operator_equal::op1_op2_relation): New. (operator_equal::pointers_handled_p): New. Diff: --- gcc/range-op-mixed.h | 12 ++ gcc/range-op-ptr.cc | 117 +++ 2 files changed, 129 insertions(+) diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h index 980611dc339..ee8d9dd328f 100644 --- a/gcc/range-op-mixed.h +++ b/gcc/range-op-mixed.h @@ -115,6 +115,9 @@ public: bool fold_range (irange , tree type, const irange , const irange , relation_trio = TRIO_VARYING) const final override; + bool fold_range (irange , tree type, + const prange , const prange , + relation_trio = TRIO_VARYING) const final override; bool fold_range (irange , tree type, const frange , const frange , relation_trio = TRIO_VARYING) const final override; @@ -122,6 +125,9 @@ public: bool op1_range (irange , tree type, const irange , const irange , relation_trio = TRIO_VARYING) const final override; + bool op1_range (prange , tree type, + const irange , const prange , + relation_trio = TRIO_VARYING) const final override; bool op1_range (frange , tree type, const irange , const frange , relation_trio = TRIO_VARYING) const final override; @@ -129,12 +135,17 @@ public: bool op2_range (irange , tree type, const irange , const irange , relation_trio = TRIO_VARYING) const final override; + bool op2_range (prange , tree type, + const irange , const prange , + relation_trio = TRIO_VARYING) const final override; bool op2_range (frange , tree type, const irange , const frange , relation_trio rel = TRIO_VARYING) const final override; relation_kind op1_op2_relation (const irange , const irange &, const irange &) const final override; + relation_kind op1_op2_relation (const irange , const prange &, + const prange &) const final override; relation_kind op1_op2_relation (const irange , const frange &, const frange &) const final override; void update_bitmask (irange , const irange , @@ -142,6 +153,7 @@ public: // Check op1 and op2 for compatibility. bool operand_check_p (tree, tree t1, tree t2) const final override { return range_compatible_p (t1, t2); } + bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override; }; class operator_not_equal : public range_operator diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc index 081e8fdba1f..fb2888bf079 100644 --- a/gcc/range-op-ptr.cc +++ b/gcc/range-op-ptr.cc @@ -1230,6 +1230,123 @@ operator_bitwise_or::pointers_handled_p (range_op_dispatch_type, return false; } +bool +operator_equal::fold_range (irange , tree type, + const prange , + const prange , + relation_trio rel) const +{ + if (relop_early_resolve (r, type, op1, op2, rel, VREL_EQ)) +return true; + + // We can be sure the values are always equal or not if both ranges + // consist of a single value, and then compare them. + bool op1_const = wi::eq_p (op1.lower_bound (), op1.upper_bound ()); + bool op2_const = wi::eq_p (op2.lower_bound (), op2.upper_bound ()); + if (op1_const && op2_const) +{ + if (wi::eq_p (op1.lower_bound (), op2.upper_bound())) + r = range_true (); + else + r = range_false (); +} + else +{ + // If ranges do not intersect, we know the range is not equal, + // otherwise we don't know anything for sure. + prange tmp = op1; + tmp.intersect (op2); + if (tmp.undefined_p ()) + r = range_false (); + // Check if a constant cannot satisfy the bitmask requirements. + else if (op2_const && !op1.get_bitmask ().member_p (op2.lower_bound ())) +r = range_false (); + else if (op1_const && !op2.get_bitmask ().member_p (op1.lower_bound ())) +r = range_false (); + else + r = range_true_and_false (); +} + + //update_known_bitmask (r, EQ_EXPR, op1, op2); + return true; +} + +bool +operator_equal::op1_range (prange , tree type, + const irange , + const
[gcc r15-157] Implement operator_bitwise_or for prange.
https://gcc.gnu.org/g:6b9e640d49138183aaeee67f2dcf3de329318d27 commit r15-157-g6b9e640d49138183aaeee67f2dcf3de329318d27 Author: Aldy Hernandez Date: Wed Mar 20 10:29:50 2024 +0100 Implement operator_bitwise_or for prange. We seem to have a range-op entry for pointer bitwise OR that we've inherited from the original VRP implementation, but it never gets used. If this is not valid gimple, we can safely remove this entry. gcc/ChangeLog: * range-op-mixed.h: Add overloaded declarations for pointer variants. * range-op-ptr.cc (operator_bitwise_or::pointers_handled_p): New. Diff: --- gcc/range-op-mixed.h | 1 + gcc/range-op-ptr.cc | 11 +++ 2 files changed, 12 insertions(+) diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h index 6158fc51f8e..c45aed93567 100644 --- a/gcc/range-op-mixed.h +++ b/gcc/range-op-mixed.h @@ -762,6 +762,7 @@ public: // Check compatibility of all operands. bool operand_check_p (tree t1, tree t2, tree t3) const final override { return range_compatible_p (t1, t2) && range_compatible_p (t1, t3); } + bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override; protected: void wi_fold (irange , tree type, const wide_int _lb, const wide_int _ub, const wide_int _lb, diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc index 8d5049b1daf..2f2f4bb2b5d 100644 --- a/gcc/range-op-ptr.cc +++ b/gcc/range-op-ptr.cc @@ -1219,6 +1219,17 @@ operator_bitwise_and::pointers_handled_p (range_op_dispatch_type type, } } +bool +operator_bitwise_or::pointers_handled_p (range_op_dispatch_type, +unsigned) const +{ + // NOTE: It looks like we never generate bitwise OR with pointers. + // If this is indeed the case, we can move operator_bitwise_or from + // range-op-mixed.h to range-op.h. + gcc_unreachable (); + return false; +} + // Initialize any pointer operators to the primary table void
[gcc r15-156] Implement operator_bitwise_and for prange.
https://gcc.gnu.org/g:e58f14916954411628eb122da996383b8c996b57 commit r15-156-ge58f14916954411628eb122da996383b8c996b57 Author: Aldy Hernandez Date: Wed Mar 20 10:23:31 2024 +0100 Implement operator_bitwise_and for prange. gcc/ChangeLog: * range-op-mixed.h: Add overloaded declarations for pointer variants. * range-op-ptr.cc (operator_bitwise_and::fold_range): New. (operator_bitwise_and::pointers_handled_p): New. Diff: --- gcc/range-op-mixed.h | 6 ++ gcc/range-op-ptr.cc | 30 ++ 2 files changed, 36 insertions(+) diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h index 0df300781f1..6158fc51f8e 100644 --- a/gcc/range-op-mixed.h +++ b/gcc/range-op-mixed.h @@ -712,10 +712,15 @@ private: class operator_bitwise_and : public range_operator { public: + using range_operator::fold_range; using range_operator::op1_range; using range_operator::op2_range; using range_operator::lhs_op1_relation; using range_operator::update_bitmask; + bool fold_range (prange , tree type, + const prange , + const prange , + relation_trio) const final override; bool op1_range (irange , tree type, const irange , const irange , relation_trio rel = TRIO_VARYING) const override; @@ -730,6 +735,7 @@ public: // Check compatibility of all operands. bool operand_check_p (tree t1, tree t2, tree t3) const final override { return range_compatible_p (t1, t2) && range_compatible_p (t1, t3); } + bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override; protected: void wi_fold (irange , tree type, const wide_int _lb, const wide_int _ub, const wide_int _lb, diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc index b90b8bb9f65..8d5049b1daf 100644 --- a/gcc/range-op-ptr.cc +++ b/gcc/range-op-ptr.cc @@ -1189,6 +1189,36 @@ operator_addr_expr::pointers_handled_p (range_op_dispatch_type type, } } +bool +operator_bitwise_and::fold_range (prange , tree type, + const prange , + const prange ATTRIBUTE_UNUSED, + relation_trio) const +{ + // For pointer types, we are really only interested in asserting + // whether the expression evaluates to non-NULL. + if (op1.zero_p () || op2.zero_p ()) +r.set_zero (type); + else +r.set_varying (type); + + update_known_bitmask (r, BIT_AND_EXPR, op1, op2); + return true; +} + +bool +operator_bitwise_and::pointers_handled_p (range_op_dispatch_type type, + unsigned dispatch) const +{ + switch (type) +{ +case DISPATCH_FOLD_RANGE: + return dispatch == RO_PPP; +default: + return true; +} +} + // Initialize any pointer operators to the primary table void
[gcc r15-155] Implement operator_pointer_diff for prange.
https://gcc.gnu.org/g:f803b93feef60c8c2d4f7f7270bfc94650dbc8f5 commit r15-155-gf803b93feef60c8c2d4f7f7270bfc94650dbc8f5 Author: Aldy Hernandez Date: Wed Mar 20 10:12:47 2024 +0100 Implement operator_pointer_diff for prange. gcc/ChangeLog: * range-op-ptr.cc (operator_pointer_diff::op1_op2_relation_effect): New. (operator_pointer_diff::pointers_handled_p): New. Diff: --- gcc/range-op-ptr.cc | 32 1 file changed, 32 insertions(+) diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc index a4418215613..b90b8bb9f65 100644 --- a/gcc/range-op-ptr.cc +++ b/gcc/range-op-ptr.cc @@ -564,10 +564,42 @@ class operator_pointer_diff : public range_operator const irange _range, const irange _range, relation_kind rel) const; + virtual bool op1_op2_relation_effect (irange _range, + tree type, + const prange _range, + const prange _range, + relation_kind rel) const final override; void update_bitmask (irange , const irange , const irange ) const { update_known_bitmask (r, POINTER_DIFF_EXPR, lh, rh); } + void update_bitmask (irange , + const prange , const prange ) const final override + { update_known_bitmask (r, POINTER_DIFF_EXPR, lh, rh); } + bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override; } op_pointer_diff; +bool +operator_pointer_diff::op1_op2_relation_effect (irange _range, tree type, + const prange _range, + const prange _range, + relation_kind rel) const +{ + int_range<2> op1, op2, tmp; + range_op_handler cast (CONVERT_EXPR); + + if (!cast.fold_range (op1, type, op1_range, tmp) + || !cast.fold_range (op2, type, op2_range, tmp)) +return false; + + return minus_op1_op2_relation_effect (lhs_range, type, op1, op2, rel); +} + +bool +operator_pointer_diff::pointers_handled_p (range_op_dispatch_type, + unsigned) const +{ + return true; +} + bool operator_pointer_diff::op1_op2_relation_effect (irange _range, tree type, const irange _range,
[gcc r15-154] Implement pointer_plus_operator for prange.
https://gcc.gnu.org/g:86ff3c45ea82452888244476f26a4f628b148ace commit r15-154-g86ff3c45ea82452888244476f26a4f628b148ace Author: Aldy Hernandez Date: Wed Mar 20 10:04:41 2024 +0100 Implement pointer_plus_operator for prange. gcc/ChangeLog: * range-op-ptr.cc (class pointer_plus_operator): Add overloaded declarations for pointer variants. (pointer_plus_operator::fold_range): New. (pointer_plus_operator::op2_range): New. (pointer_plus_operator::pointers_handled_p): New. Diff: --- gcc/range-op-ptr.cc | 98 + 1 file changed, 98 insertions(+) diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc index 38d9f65566f..a4418215613 100644 --- a/gcc/range-op-ptr.cc +++ b/gcc/range-op-ptr.cc @@ -265,8 +265,17 @@ range_operator::update_bitmask (irange &, class pointer_plus_operator : public range_operator { using range_operator::update_bitmask; + using range_operator::fold_range; using range_operator::op2_range; public: + virtual bool fold_range (prange , tree type, + const prange , + const irange , + relation_trio) const final override; + virtual bool op2_range (irange , tree type, + const prange , + const prange , + relation_trio = TRIO_VARYING) const final override; virtual void wi_fold (irange , tree type, const wide_int _lb, const wide_int _ub, @@ -276,10 +285,99 @@ public: const irange , const irange , relation_trio = TRIO_VARYING) const; + bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override; void update_bitmask (irange , const irange , const irange ) const { update_known_bitmask (r, POINTER_PLUS_EXPR, lh, rh); } } op_pointer_plus; +bool +pointer_plus_operator::fold_range (prange , tree type, + const prange , + const irange , + relation_trio) const +{ + if (empty_range_varying (r, type, op1, op2)) +return true; + + const wide_int lh_lb = op1.lower_bound (); + const wide_int lh_ub = op1.upper_bound (); + const wide_int rh_lb = op2.lower_bound (); + const wide_int rh_ub = op2.upper_bound (); + + // Check for [0,0] + const, and simply return the const. + if (lh_lb == 0 && lh_ub == 0 && rh_lb == rh_ub) +{ + r.set (type, rh_lb, rh_lb); + return true; +} + + // For pointer types, we are really only interested in asserting + // whether the expression evaluates to non-NULL. + // + // With -fno-delete-null-pointer-checks we need to be more + // conservative. As some object might reside at address 0, + // then some offset could be added to it and the same offset + // subtracted again and the result would be NULL. + // E.g. + // static int a[12]; where [0] is NULL and + // ptr = [6]; + // ptr -= 6; + // ptr will be NULL here, even when there is POINTER_PLUS_EXPR + // where the first range doesn't include zero and the second one + // doesn't either. As the second operand is sizetype (unsigned), + // consider all ranges where the MSB could be set as possible + // subtractions where the result might be NULL. + if ((!wi_includes_zero_p (type, lh_lb, lh_ub) + || !wi_includes_zero_p (type, rh_lb, rh_ub)) + && !TYPE_OVERFLOW_WRAPS (type) + && (flag_delete_null_pointer_checks + || !wi::sign_mask (rh_ub))) +r.set_nonzero (type); + else if (lh_lb == lh_ub && lh_lb == 0 + && rh_lb == rh_ub && rh_lb == 0) +r.set_zero (type); + else + r.set_varying (type); + + update_known_bitmask (r, POINTER_PLUS_EXPR, op1, op2); + return true; +} + +bool +pointer_plus_operator::op2_range (irange , tree type, + const prange ATTRIBUTE_UNUSED, + const prange ATTRIBUTE_UNUSED, + relation_trio trio) const +{ + relation_kind rel = trio.lhs_op1 (); + r.set_varying (type); + + // If the LHS and OP1 are equal, the op2 must be zero. + if (rel == VREL_EQ) +r.set_zero (type); + // If the LHS and OP1 are not equal, the offset must be non-zero. + else if (rel == VREL_NE) +r.set_nonzero (type); + else +return false; + return true; +} + +bool +pointer_plus_operator::pointers_handled_p (range_op_dispatch_type type, + unsigned dispatch) const +{ + switch (type) +{ +case DISPATCH_FOLD_RANGE: + return dispatch == RO_PPI; +case DISPATCH_OP2_RANGE: + return dispatch == RO_IPP; +default: + return true; +} +} + void pointer_plus_operator::wi_fold (irange , tree type, const wide_int _lb,
[gcc r15-153] Implement operator_addr_expr for prange.
https://gcc.gnu.org/g:54d3fd6d9f5d029c23ab376df2f5decb4902907d commit r15-153-g54d3fd6d9f5d029c23ab376df2f5decb4902907d Author: Aldy Hernandez Date: Wed Mar 20 09:51:33 2024 +0100 Implement operator_addr_expr for prange. gcc/ChangeLog: * range-op-mixed.h: Add overloaded declarations for pointer variants. * range-op-ptr.cc (operator_addr_expr::op1_range): New. (operator_addr_expr::pointers_handled_p): New. Diff: --- gcc/range-op-mixed.h | 4 gcc/range-op-ptr.cc | 38 ++ 2 files changed, 42 insertions(+) diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h index b69e674a78b..0df300781f1 100644 --- a/gcc/range-op-mixed.h +++ b/gcc/range-op-mixed.h @@ -655,6 +655,10 @@ public: bool op1_range (irange , tree type, const irange , const irange , relation_trio rel = TRIO_VARYING) const final override; + bool op1_range (prange , tree type, + const prange , const prange , + relation_trio rel = TRIO_VARYING) const final override; + bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override; }; class operator_bitwise_not : public range_operator diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc index 0addd1096c2..38d9f65566f 100644 --- a/gcc/range-op-ptr.cc +++ b/gcc/range-op-ptr.cc @@ -1021,6 +1021,44 @@ operator_max::pointers_handled_p (range_op_dispatch_type type, } } +bool +operator_addr_expr::op1_range (prange , tree type, + const prange , + const prange , + relation_trio) const +{ + if (empty_range_varying (r, type, lhs, op2)) +return true; + + // Return a non-null pointer of the LHS type (passed in op2), but only + // if we cant overflow, eitherwise a no-zero offset could wrap to zero. + // See PR 111009. + if (!lhs.undefined_p () + && !range_includes_zero_p (lhs) + && TYPE_OVERFLOW_UNDEFINED (type)) +r.set_nonzero (type); + else +r.set_varying (type); + return true; +} + +bool +operator_addr_expr::pointers_handled_p (range_op_dispatch_type type, + unsigned dispatch) const +{ + switch (type) +{ +case DISPATCH_FOLD_RANGE: + // NOTE: It looks like we never generate this combination. + gcc_unreachable (); + return false; +case DISPATCH_OP1_RANGE: + return dispatch == RO_PPP; +default: + return true; +} +} + // Initialize any pointer operators to the primary table void
[gcc r15-152] Implement operator_min and operator_max for prange.
https://gcc.gnu.org/g:1a4f5d499109d3f2a06bfd1403b6d47d6f55e481 commit r15-152-g1a4f5d499109d3f2a06bfd1403b6d47d6f55e481 Author: Aldy Hernandez Date: Wed Mar 20 08:44:49 2024 +0100 Implement operator_min and operator_max for prange. gcc/ChangeLog: * range-op-mixed.h: Add overloaded declarations for pointer variants. * range-op-ptr.cc (operator_min::fold_range): New. (operator_min::pointers_handled_p): New. (operator_max::fold_range): New. (operator_max::pointers_handled_p): New. Diff: --- gcc/range-op-mixed.h | 12 + gcc/range-op-ptr.cc | 70 2 files changed, 82 insertions(+) diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h index 11b1bf0bca4..b69e674a78b 100644 --- a/gcc/range-op-mixed.h +++ b/gcc/range-op-mixed.h @@ -761,12 +761,18 @@ protected: class operator_min : public range_operator { public: + using range_operator::fold_range; using range_operator::update_bitmask; + bool fold_range (prange , tree type, + const prange , + const prange , + relation_trio) const final override; void update_bitmask (irange , const irange , const irange ) const override; // Check compatibility of all operands. bool operand_check_p (tree t1, tree t2, tree t3) const final override { return range_compatible_p (t1, t2) && range_compatible_p (t1, t3); } + bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override; protected: void wi_fold (irange , tree type, const wide_int _lb, const wide_int _ub, const wide_int _lb, @@ -776,12 +782,18 @@ protected: class operator_max : public range_operator { public: + using range_operator::fold_range; using range_operator::update_bitmask; + bool fold_range (prange , tree type, + const prange , + const prange , + relation_trio) const final override; void update_bitmask (irange , const irange , const irange ) const override; // Check compatibility of all operands. bool operand_check_p (tree t1, tree t2, tree t3) const final override { return range_compatible_p (t1, t2) && range_compatible_p (t1, t3); } + bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override; protected: void wi_fold (irange , tree type, const wide_int _lb, const wide_int _ub, const wide_int _lb, diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc index b8f86c8e838..0addd1096c2 100644 --- a/gcc/range-op-ptr.cc +++ b/gcc/range-op-ptr.cc @@ -951,6 +951,76 @@ operator_cast::pointers_handled_p (range_op_dispatch_type type, } } +bool +operator_min::fold_range (prange , tree type, + const prange , + const prange , + relation_trio) const +{ + // For MIN/MAX expressions with pointers, we only care about + // nullness. If both are non null, then the result is nonnull. + // If both are null, then the result is null. Otherwise they + // are varying. + if (!range_includes_zero_p (op1) + && !range_includes_zero_p (op2)) +r.set_nonzero (type); + else if (op1.zero_p () && op2.zero_p ()) +r.set_zero (type); + else +r.set_varying (type); + + update_known_bitmask (r, MIN_EXPR, op1, op2); + return true; +} + +bool +operator_min::pointers_handled_p (range_op_dispatch_type type, + unsigned dispatch) const +{ + switch (type) +{ +case DISPATCH_FOLD_RANGE: + return dispatch == RO_PPP; +default: + return true; +} +} + +bool +operator_max::fold_range (prange , tree type, + const prange , + const prange , + relation_trio) const +{ + // For MIN/MAX expressions with pointers, we only care about + // nullness. If both are non null, then the result is nonnull. + // If both are null, then the result is null. Otherwise they + // are varying. + if (!range_includes_zero_p (op1) + && !range_includes_zero_p (op2)) +r.set_nonzero (type); + else if (op1.zero_p () && op2.zero_p ()) +r.set_zero (type); + else +r.set_varying (type); + + update_known_bitmask (r, MAX_EXPR, op1, op2); + return true; +} + +bool +operator_max::pointers_handled_p (range_op_dispatch_type type, + unsigned dispatch) const +{ + switch (type) +{ +case DISPATCH_FOLD_RANGE: + return dispatch == RO_PPP; +default: + return true; +} +} + // Initialize any pointer operators to the primary table void
[gcc r15-151] Implement operator_cast for prange.
https://gcc.gnu.org/g:95fce0dc73002d5c9557fa7260c7ba1e761136ff commit r15-151-g95fce0dc73002d5c9557fa7260c7ba1e761136ff Author: Aldy Hernandez Date: Wed Mar 20 08:04:32 2024 +0100 Implement operator_cast for prange. gcc/ChangeLog: * range-op-mixed.h: Add overloaded declarations for pointer variants. * range-op-ptr.cc (operator_cast::fold_range): New. (operator_cast::op1_range): New. (operator_cast::lhs_op1_relation): New. (operator_cast::pointers_handled_p): New. Diff: --- gcc/range-op-mixed.h | 28 ++ gcc/range-op-ptr.cc | 245 +++ 2 files changed, 273 insertions(+) diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h index 04c8acbd94a..11b1bf0bca4 100644 --- a/gcc/range-op-mixed.h +++ b/gcc/range-op-mixed.h @@ -400,14 +400,42 @@ public: bool fold_range (irange , tree type, const irange , const irange , relation_trio rel = TRIO_VARYING) const final override; + bool fold_range (prange , tree type, + const prange , const prange , + relation_trio rel = TRIO_VARYING) const final override; + bool fold_range (irange , tree type, + const prange , const irange , + relation_trio rel = TRIO_VARYING) const final override; + bool fold_range (prange , tree type, + const irange , const prange , + relation_trio rel = TRIO_VARYING) const final override; bool op1_range (irange , tree type, const irange , const irange , relation_trio rel = TRIO_VARYING) const final override; + bool op1_range (prange , tree type, + const prange , const prange , + relation_trio rel = TRIO_VARYING) const final override; + bool op1_range (irange , tree type, + const prange , const irange , + relation_trio rel = TRIO_VARYING) const final override; + bool op1_range (prange , tree type, + const irange , const prange , + relation_trio rel = TRIO_VARYING) const final override; relation_kind lhs_op1_relation (const irange , const irange , const irange , relation_kind) const final override; + relation_kind lhs_op1_relation (const prange , + const prange , const prange , + relation_kind) const final override; + relation_kind lhs_op1_relation (const prange , + const irange , const irange , + relation_kind) const final override; + relation_kind lhs_op1_relation (const irange , + const prange , const prange , + relation_kind) const final override; void update_bitmask (irange , const irange , const irange ) const final override; + bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override; private: bool truncating_cast_p (const irange , const irange ) const; bool inside_domain_p (const wide_int , const wide_int , diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc index e59e278cbd7..b8f86c8e838 100644 --- a/gcc/range-op-ptr.cc +++ b/gcc/range-op-ptr.cc @@ -706,6 +706,251 @@ operator_cst::pointers_handled_p (range_op_dispatch_type type, } } +// Cast between pointers. + +bool +operator_cast::fold_range (prange , tree type, + const prange , + const prange , + relation_trio) const +{ + if (empty_range_varying (r, type, inner, outer)) +return true; + + r.set (type, inner.lower_bound (), inner.upper_bound ()); + r.update_bitmask (inner.get_bitmask ()); + return true; +} + +// Cast a pointer to an integer. + +bool +operator_cast::fold_range (irange , tree type, + const prange , + const irange , + relation_trio) const +{ + if (empty_range_varying (r, type, inner, outer)) +return true; + + // Represent INNER as an integer of the same size, and then cast it + // to the resulting integer type. + tree pointer_uint_type = make_unsigned_type (TYPE_PRECISION (inner.type ())); + r.set (pointer_uint_type, inner.lower_bound (), inner.upper_bound ()); + r.update_bitmask (inner.get_bitmask ()); + range_cast (r, type); + return true; +} + +// Cast an integer to a pointer. + +bool +operator_cast::fold_range (prange , tree type, + const irange , + const prange , + relation_trio) const +{ + if (empty_range_varying (r, type, inner, outer)) +return true; + + // Cast INNER to an integer of the same size as the pointer we want, + // and then copy the bounds to the resulting pointer
[gcc r15-150] Implement operator_cst for prange.
https://gcc.gnu.org/g:a91fd7b4342dbeaf1d2514beaee3af0bb5680b81 commit r15-150-ga91fd7b4342dbeaf1d2514beaee3af0bb5680b81 Author: Aldy Hernandez Date: Wed Mar 20 07:55:57 2024 +0100 Implement operator_cst for prange. gcc/ChangeLog: * range-op-mixed.h: Add overloaded declarations for pointer variants. * range-op-ptr.cc (operator_cst::fold_range): New. (operator_cst::pointers_handled_p): New. Diff: --- gcc/range-op-mixed.h | 4 gcc/range-op-ptr.cc | 23 +++ 2 files changed, 27 insertions(+) diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h index 60aaea9563d..04c8acbd94a 100644 --- a/gcc/range-op-mixed.h +++ b/gcc/range-op-mixed.h @@ -380,9 +380,13 @@ public: bool fold_range (irange , tree type, const irange , const irange , relation_trio rel = TRIO_VARYING) const final override; + bool fold_range (prange , tree type, + const prange , const prange , + relation_trio rel = TRIO_VARYING) const final override; bool fold_range (frange , tree type, const frange , const frange , relation_trio = TRIO_VARYING) const final override; + bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override; }; diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc index 08419bfc798..e59e278cbd7 100644 --- a/gcc/range-op-ptr.cc +++ b/gcc/range-op-ptr.cc @@ -683,6 +683,29 @@ operator_identity::pointers_handled_p (range_op_dispatch_type type, } } +bool +operator_cst::fold_range (prange , tree type ATTRIBUTE_UNUSED, + const prange , + const prange & ATTRIBUTE_UNUSED, + relation_trio) const +{ + r = lh; + return true; +} + +bool +operator_cst::pointers_handled_p (range_op_dispatch_type type, + unsigned dispatch) const +{ + switch (type) +{ +case DISPATCH_FOLD_RANGE: + return dispatch == RO_PPP; +default: + return true; +} +} + // Initialize any pointer operators to the primary table void
[gcc r15-149] Implement operator_identity for prange.
https://gcc.gnu.org/g:e7b6e9663e9b31e681fb0302338bcb4bb306a334 commit r15-149-ge7b6e9663e9b31e681fb0302338bcb4bb306a334 Author: Aldy Hernandez Date: Wed Mar 20 07:50:11 2024 +0100 Implement operator_identity for prange. gcc/ChangeLog: * range-op-mixed.h: Add overloaded declarations for fold_range, op1_range, lhs_op1_relation, pointers_handled_p. * range-op-ptr.cc (operator_identity::fold_range): New. (operator_identity::lhs_op1_relation): New. (operator_identity::op1_range): New. (operator_identity::pointers_handled_p): New. Diff: --- gcc/range-op-mixed.h | 10 ++ gcc/range-op-ptr.cc | 47 +++ 2 files changed, 57 insertions(+) diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h index 8163a4b53ca..60aaea9563d 100644 --- a/gcc/range-op-mixed.h +++ b/gcc/range-op-mixed.h @@ -349,18 +349,28 @@ public: bool fold_range (irange , tree type, const irange , const irange , relation_trio rel = TRIO_VARYING) const final override; + bool fold_range (prange , tree type, + const prange , const prange , + relation_trio rel = TRIO_VARYING) const final override; bool fold_range (frange , tree type ATTRIBUTE_UNUSED, const frange , const frange ATTRIBUTE_UNUSED, relation_trio = TRIO_VARYING) const final override; bool op1_range (irange , tree type, const irange , const irange , relation_trio rel = TRIO_VARYING) const final override; + bool op1_range (prange , tree type, + const prange , const prange , + relation_trio rel = TRIO_VARYING) const final override; bool op1_range (frange , tree type ATTRIBUTE_UNUSED, const frange , const frange ATTRIBUTE_UNUSED, relation_trio = TRIO_VARYING) const final override; relation_kind lhs_op1_relation (const irange , const irange , const irange , relation_kind rel) const final override; + relation_kind lhs_op1_relation (const prange , + const prange , const prange , + relation_kind rel) const final override; + bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override; }; class operator_cst : public range_operator diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc index 560c798b90a..08419bfc798 100644 --- a/gcc/range-op-ptr.cc +++ b/gcc/range-op-ptr.cc @@ -636,6 +636,53 @@ public: } } op_hybrid_max; +bool +operator_identity::fold_range (prange , tree type ATTRIBUTE_UNUSED, + const prange ATTRIBUTE_UNUSED, + const prange ATTRIBUTE_UNUSED, + relation_trio) const +{ + r = lh; + return true; +} + +relation_kind +operator_identity::lhs_op1_relation (const prange , +const prange ATTRIBUTE_UNUSED, +const prange ATTRIBUTE_UNUSED, +relation_kind) const +{ + if (lhs.undefined_p ()) +return VREL_VARYING; + // Simply a copy, so they are equivalent. + return VREL_EQ; +} + +bool +operator_identity::op1_range (prange , tree type ATTRIBUTE_UNUSED, + const prange , + const prange ATTRIBUTE_UNUSED, + relation_trio) const +{ + r = lhs; + return true; +} + +bool +operator_identity::pointers_handled_p (range_op_dispatch_type type, + unsigned dispatch) const +{ + switch (type) +{ +case DISPATCH_FOLD_RANGE: +case DISPATCH_OP1_RANGE: +case DISPATCH_LHS_OP1_RELATION: + return dispatch == RO_PPP; +default: + return true; +} +} + // Initialize any pointer operators to the primary table void
[gcc r15-147] Add prange implementation for get_legacy_range.
https://gcc.gnu.org/g:ddf039adef5e2695f1cb27e0b6e5056fef4be2ee commit r15-147-gddf039adef5e2695f1cb27e0b6e5056fef4be2ee Author: Aldy Hernandez Date: Wed Mar 20 06:39:48 2024 +0100 Add prange implementation for get_legacy_range. gcc/ChangeLog: * value-range.cc (get_legacy_range): New version for prange. Diff: --- gcc/value-range.cc | 35 +-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 62170a438bf..3e1ecf69517 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -1377,6 +1377,38 @@ get_legacy_range (const irange , tree , tree ) return VR_RANGE; } +static value_range_kind +get_legacy_range (const prange , tree , tree ) +{ + if (r.undefined_p ()) +{ + min = NULL_TREE; + max = NULL_TREE; + return VR_UNDEFINED; +} + + tree type = r.type (); + if (r.varying_p ()) +{ + min = r.lbound (); + max = r.ubound (); + return VR_VARYING; +} + if (r.zero_p ()) +{ + min = max = r.lbound (); + return VR_RANGE; +} + if (r.nonzero_p ()) +{ + min = max = build_zero_cst (type); + return VR_ANTI_RANGE; +} + min = r.lbound (); + max = r.ubound (); + return VR_RANGE; +} + // Given a range in V, return an old-style legacy range consisting of // a value_range_kind with a MIN/MAX. This is to maintain // compatibility with passes that still depend on VR_ANTI_RANGE, and @@ -1388,8 +1420,7 @@ get_legacy_range (const vrange , tree , tree ) if (is_a (v)) return get_legacy_range (as_a (v), min, max); - gcc_unreachable (); - return VR_UNDEFINED; + return get_legacy_range (as_a (v), min, max); } /* Set value range to the canonical form of {VRTYPE, MIN, MAX, EQUIV}.
[gcc r15-148] Implement range-op dispatch for prange.
https://gcc.gnu.org/g:31377eed515506c9e8ba2ac8fa3ab4e743f8c1f3 commit r15-148-g31377eed515506c9e8ba2ac8fa3ab4e743f8c1f3 Author: Aldy Hernandez Date: Wed Mar 20 07:19:45 2024 +0100 Implement range-op dispatch for prange. This patch adds the range-op dispatch code for prange, and adds some temporary sanity checks (for flag_checking only) to make sure we handle all the pointer/integer variants. In order to make sure I got all the combinations right, I started with a clean slate, trapping on all pointer operands. Then I added support for each one piecemeal. To verify the work, I added a pointers_handled_p() helper that is implemented for each range-op entry and returns TRUE iff the operator can handle a given combination of pointers. If this helper returns false, we will trap, because it indicates an operator that was not implemented. This is temporary checking code, and I will rip it out once the the dust has settled in a few days. gcc/ChangeLog: * range-op-mixed.h: Add using declarator for all classes. * range-op-ptr.cc (range_operator::pointers_handled_p): New. (range_operator::fold_range): New. (range_operator::op1_op2_relation_effect): New. (range_operator::op1_range): New. (range_operator::op2_range): New. (range_operator::op1_op2_relation): New. (range_operator::lhs_op1_relation): New. (range_operator::update_bitmask): New. (class pointer_plus_operator): New. (class operator_pointer_diff): New. (class hybrid_min_operator): New. (class hybrid_max_operator): New. * range-op.cc: Add RO_PPP, RO_PPI, RO_IPP, RO_IPI, RO_PIP, RO_PII. (range_op_handler::discriminator_fail): New. (has_pointer_operand_p): New. (range_op_handler::fold_range): Add pointer support. (range_op_handler::op1_range): Same. (range_op_handler::op2_range): Same. (range_op_handler::lhs_op1_relation): Same. (range_op_handler::lhs_op2_relation): Same. (range_op_handler::op1_op2_relation): Same. (class operator_div): Add using. (class operator_lshift): Add using. (class operator_rshift):Add using. (class operator_trunc_mod):Add using. (class operator_absu):Add using. * range-op.h (enum range_op_dispatch_type): New. Add extern definitions for RO_*. Diff: --- gcc/range-op-mixed.h | 19 + gcc/range-op-ptr.cc | 220 +++ gcc/range-op.cc | 124 + gcc/range-op.h | 111 ++ 4 files changed, 474 insertions(+) diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h index 3ee7c9d6e0d..8163a4b53ca 100644 --- a/gcc/range-op-mixed.h +++ b/gcc/range-op-mixed.h @@ -111,6 +111,7 @@ public: using range_operator::op1_range; using range_operator::op2_range; using range_operator::op1_op2_relation; + using range_operator::update_bitmask; bool fold_range (irange , tree type, const irange , const irange , relation_trio = TRIO_VARYING) const final override; @@ -150,6 +151,7 @@ public: using range_operator::op1_range; using range_operator::op2_range; using range_operator::op1_op2_relation; + using range_operator::update_bitmask; bool fold_range (irange , tree type, const irange , const irange , relation_trio = TRIO_VARYING) const final override; @@ -189,6 +191,7 @@ public: using range_operator::op1_range; using range_operator::op2_range; using range_operator::op1_op2_relation; + using range_operator::update_bitmask; bool fold_range (irange , tree type, const irange , const irange , relation_trio = TRIO_VARYING) const final override; @@ -225,6 +228,7 @@ public: using range_operator::op1_range; using range_operator::op2_range; using range_operator::op1_op2_relation; + using range_operator::update_bitmask; bool fold_range (irange , tree type, const irange , const irange , relation_trio = TRIO_VARYING) const final override; @@ -264,6 +268,7 @@ public: using range_operator::op1_range; using range_operator::op2_range; using range_operator::op1_op2_relation; + using range_operator::update_bitmask; bool fold_range (irange , tree type, const irange , const irange , relation_trio = TRIO_VARYING) const final override; @@ -302,6 +307,7 @@ public: using range_operator::op1_range; using range_operator::op2_range; using range_operator::op1_op2_relation; + using range_operator::update_bitmask; bool fold_range (irange , tree type, const irange , const irange ,
[gcc r15-146] Add hashing support for prange.
https://gcc.gnu.org/g:7c1b136630790eb34d57c45d9a816b32fd904e3f commit r15-146-g7c1b136630790eb34d57c45d9a816b32fd904e3f Author: Aldy Hernandez Date: Wed Mar 20 06:39:07 2024 +0100 Add hashing support for prange. gcc/ChangeLog: * value-range.cc (add_vrange): Add prange support. Diff: --- gcc/value-range.cc | 16 1 file changed, 16 insertions(+) diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 84113ccfbd0..62170a438bf 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -346,6 +346,22 @@ add_vrange (const vrange , inchash::hash , hstate.add_wide_int (bm.mask ()); return; } + if (is_a (v)) +{ + const prange = as_a (v); + if (r.varying_p ()) + hstate.add_int (VR_VARYING); + else + { + hstate.add_int (VR_RANGE); + hstate.add_wide_int (r.lower_bound ()); + hstate.add_wide_int (r.upper_bound ()); + irange_bitmask bm = r.get_bitmask (); + hstate.add_wide_int (bm.value ()); + hstate.add_wide_int (bm.mask ()); + } + return; +} if (is_a (v)) { const frange = as_a (v);
[gcc r15-145] Add storage support for prange.
https://gcc.gnu.org/g:f859996a976ca185f371a8ed395e9c8e459e05b0 commit r15-145-gf859996a976ca185f371a8ed395e9c8e459e05b0 Author: Aldy Hernandez Date: Wed Mar 20 06:38:06 2024 +0100 Add storage support for prange. gcc/ChangeLog: * value-range-storage.cc (vrange_allocator::clone_varying): Add prange support. (vrange_allocator::clone_undefined): Same. (vrange_storage::alloc): Same. (vrange_storage::set_vrange): Same. (vrange_storage::get_vrange): Same. (vrange_storage::fits_p): Same. (vrange_storage::equal_p): Same. (prange_storage::alloc): New. (prange_storage::prange_storage): New. (prange_storage::set_prange): New. (prange_storage::get_prange): New. (prange_storage::equal_p): New. (prange_storage::fits_p): New. * value-range-storage.h (class prange_storage): Add prange support. Diff: --- gcc/value-range-storage.cc | 117 + gcc/value-range-storage.h | 33 + 2 files changed, 150 insertions(+) diff --git a/gcc/value-range-storage.cc b/gcc/value-range-storage.cc index 09a29776a0e..bbae0da4772 100644 --- a/gcc/value-range-storage.cc +++ b/gcc/value-range-storage.cc @@ -118,6 +118,8 @@ vrange_allocator::clone_varying (tree type) { if (irange::supports_p (type)) return irange_storage::alloc (*m_alloc, int_range <1> (type)); + if (prange::supports_p (type)) +return prange_storage::alloc (*m_alloc, prange (type)); if (frange::supports_p (type)) return frange_storage::alloc (*m_alloc, frange (type)); return NULL; @@ -128,6 +130,8 @@ vrange_allocator::clone_undefined (tree type) { if (irange::supports_p (type)) return irange_storage::alloc (*m_alloc, int_range<1> ()); + if (prange::supports_p (type)) +return prange_storage::alloc (*m_alloc, prange ()); if (frange::supports_p (type)) return frange_storage::alloc (*m_alloc, frange ()); return NULL; @@ -141,6 +145,8 @@ vrange_storage::alloc (vrange_internal_alloc , const vrange ) { if (is_a (r)) return irange_storage::alloc (allocator, as_a (r)); + if (is_a (r)) +return prange_storage::alloc (allocator, as_a (r)); if (is_a (r)) return frange_storage::alloc (allocator, as_a (r)); return NULL; @@ -157,6 +163,12 @@ vrange_storage::set_vrange (const vrange ) gcc_checking_assert (s->fits_p (as_a (r))); s->set_irange (as_a (r)); } + else if (is_a (r)) +{ + prange_storage *s = static_cast (this); + gcc_checking_assert (s->fits_p (as_a (r))); + s->set_prange (as_a (r)); +} else if (is_a (r)) { frange_storage *s = static_cast (this); @@ -190,6 +202,11 @@ vrange_storage::get_vrange (vrange , tree type) const const irange_storage *s = static_cast (this); s->get_irange (as_a (r), type); } + else if (is_a (r)) +{ + const prange_storage *s = static_cast (this); + s->get_prange (as_a (r), type); +} else if (is_a (r)) { const frange_storage *s = static_cast (this); @@ -209,6 +226,11 @@ vrange_storage::fits_p (const vrange ) const const irange_storage *s = static_cast (this); return s->fits_p (as_a (r)); } + if (is_a (r)) +{ + const prange_storage *s = static_cast (this); + return s->fits_p (as_a (r)); +} if (is_a (r)) { const frange_storage *s = static_cast (this); @@ -230,6 +252,11 @@ vrange_storage::equal_p (const vrange ) const const irange_storage *s = static_cast (this); return s->equal_p (as_a (r)); } + if (is_a (r)) +{ + const prange_storage *s = static_cast (this); + return s->equal_p (as_a (r)); +} if (is_a (r)) { const frange_storage *s = static_cast (this); @@ -559,6 +586,96 @@ frange_storage::fits_p (const frange &) const return true; } +// +// prange_storage implementation +// + +prange_storage * +prange_storage::alloc (vrange_internal_alloc , const prange ) +{ + // Assume all pointers are the same size. + unsigned prec = TYPE_PRECISION (TREE_TYPE (null_pointer_node)); + gcc_checking_assert (r.undefined_p () || TYPE_PRECISION (r.type ()) == prec); + + typedef trailing_wide_ints twi; + size_t size = sizeof (prange_storage) + twi::extra_size (prec); + prange_storage *p = static_cast (allocator.alloc (size)); + new (p) prange_storage (r); + return p; +} + +// Initialize the storage with R. + +prange_storage::prange_storage (const prange ) +{ + // It is the caller's responsibility to allocate enough space such + // that the precision fits. + unsigned prec = TYPE_PRECISION (TREE_TYPE (null_pointer_node)); +
[gcc r15-144] Add streaming support for prange.
https://gcc.gnu.org/g:a7f1285380029d2928d61e61032c1948ccabc495 commit r15-144-ga7f1285380029d2928d61e61032c1948ccabc495 Author: Aldy Hernandez Date: Wed Mar 20 06:34:26 2024 +0100 Add streaming support for prange. gcc/ChangeLog: * data-streamer-in.cc (streamer_read_value_range): Add prange support. * data-streamer-out.cc (streamer_write_vrange): Same. Diff: --- gcc/data-streamer-in.cc | 12 gcc/data-streamer-out.cc | 10 ++ 2 files changed, 22 insertions(+) diff --git a/gcc/data-streamer-in.cc b/gcc/data-streamer-in.cc index 3a0d3c6ad0f..12cb10e42c0 100644 --- a/gcc/data-streamer-in.cc +++ b/gcc/data-streamer-in.cc @@ -268,6 +268,18 @@ streamer_read_value_range (class lto_input_block *ib, data_in *data_in, } return; } + if (is_a (vr)) +{ + prange = as_a (vr); + wide_int lb = streamer_read_wide_int (ib); + wide_int ub = streamer_read_wide_int (ib); + r.set (type, lb, ub); + wide_int value = streamer_read_wide_int (ib); + wide_int mask = streamer_read_wide_int (ib); + irange_bitmask bm (value, mask); + r.update_bitmask (bm); + return; +} gcc_unreachable (); } diff --git a/gcc/data-streamer-out.cc b/gcc/data-streamer-out.cc index 07cc6bd2018..c237e30f704 100644 --- a/gcc/data-streamer-out.cc +++ b/gcc/data-streamer-out.cc @@ -450,6 +450,16 @@ streamer_write_vrange (struct output_block *ob, const vrange ) } return; } + if (is_a (v)) +{ + const prange = as_a (v); + streamer_write_wide_int (ob, r.lower_bound ()); + streamer_write_wide_int (ob, r.upper_bound ()); + irange_bitmask bm = r.get_bitmask (); + streamer_write_wide_int (ob, bm.value ()); + streamer_write_wide_int (ob, bm.mask ()); + return; +} gcc_unreachable (); }
[gcc r15-143] Implement basic prange class.
https://gcc.gnu.org/g:64993a89ad75814ab69addade1b2c0020a180f41 commit r15-143-g64993a89ad75814ab69addade1b2c0020a180f41 Author: Aldy Hernandez Date: Wed Mar 20 06:25:52 2024 +0100 Implement basic prange class. This provides a bare prange class with bounds and bitmasks. It will be a drop-in replacement for pointer ranges, so we can pull their support from irange. The range-op code will be contributed as a follow-up. The code is disabled by default, as irange::supports_p still accepts pointers: inline bool irange::supports_p (const_tree type) { return INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type); } Once the prange operators are implemented in range-ops, pointer support will be removed from irange to activate pranges. gcc/ChangeLog: * value-range-pretty-print.cc (vrange_printer::visit): New. * value-range-pretty-print.h: Declare prange visit() method. * value-range.cc (vrange::operator=): Add prange support. (vrange::operator==): Same. (prange::accept): New. (prange::set_nonnegative): New. (prange::set): New. (prange::contains_p): New. (prange::singleton_p): New. (prange::lbound): New. (prange::ubound): New. (prange::union_): New. (prange::intersect): New. (prange::operator=): New. (prange::operator==): New. (prange::invert): New. (prange::verify_range): New. (prange::update_bitmask): New. (range_tests_misc): Use prange. * value-range.h (enum value_range_discriminator): Add VR_PRANGE. (class prange): New. (Value_Range::init): Add prange support. (Value_Range::operator=): Same. (Value_Range::supports_type_p): Same. (prange::prange): New. (prange::supports_p): New. (prange::supports_type_p): New. (prange::set_undefined): New. (prange::set_varying): New. (prange::set_nonzero): New. (prange::set_zero): New. (prange::contains_p): New. (prange::zero_p): New. (prange::nonzero_p): New. (prange::type): New. (prange::lower_bound): New. (prange::upper_bound): New. (prange::varying_compatible_p): New. (prange::get_bitmask): New. (prange::fits_p): New. Diff: --- gcc/value-range-pretty-print.cc | 25 gcc/value-range-pretty-print.h | 1 + gcc/value-range.cc | 303 +++- gcc/value-range.h | 199 +++--- 4 files changed, 500 insertions(+), 28 deletions(-) diff --git a/gcc/value-range-pretty-print.cc b/gcc/value-range-pretty-print.cc index b6d23dce6d2..b11d6494774 100644 --- a/gcc/value-range-pretty-print.cc +++ b/gcc/value-range-pretty-print.cc @@ -112,6 +112,31 @@ vrange_printer::visit (const irange ) const print_irange_bitmasks (pp, r.m_bitmask); } +void +vrange_printer::visit (const prange ) const +{ + pp_string (pp, "[prange] "); + if (r.undefined_p ()) +{ + pp_string (pp, "UNDEFINED"); + return; +} + dump_generic_node (pp, r.type (), 0, TDF_NONE | TDF_NOUID, false); + pp_character (pp, ' '); + if (r.varying_p ()) +{ + pp_string (pp, "VARYING"); + return; +} + + pp_character (pp, '['); + print_int_bound (pp, r.lower_bound (), r.type ()); + pp_string (pp, ", "); + print_int_bound (pp, r.upper_bound (), r.type ()); + pp_character (pp, ']'); + print_irange_bitmasks (pp, r.m_bitmask); +} + void vrange_printer::print_real_value (tree type, const REAL_VALUE_TYPE ) const { diff --git a/gcc/value-range-pretty-print.h b/gcc/value-range-pretty-print.h index 44cd6e81298..5522aad0673 100644 --- a/gcc/value-range-pretty-print.h +++ b/gcc/value-range-pretty-print.h @@ -27,6 +27,7 @@ public: vrange_printer (pretty_printer *pp_) : pp (pp_) { } void visit (const unsupported_range &) const override; void visit (const irange &) const override; + void visit (const prange &) const override; void visit (const frange &) const override; private: void print_frange_nan (const frange &) const; diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 7250115261f..84113ccfbd0 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -251,6 +251,8 @@ vrange::operator= (const vrange ) { if (is_a (src)) as_a (*this) = as_a (src); + else if (is_a (src)) +as_a (*this) = as_a (src); else if (is_a (src)) as_a (*this) = as_a (src); else @@ -268,6 +270,8 @@ vrange::operator== (const vrange ) const { if (is_a (src)) return as_a (*this) == as_a (src); + if (is_a (src)) +return as_a (*this) == as_a (src); if (is_a (src)) return as_a (*this) == as_a (src);
[gcc r15-142] Minimal prange class showing inlining degradation to VRP.
https://gcc.gnu.org/g:f5891967947562060076956bd953e5df4c7289bf commit r15-142-gf5891967947562060076956bd953e5df4c7289bf Author: Aldy Hernandez Date: Sat May 4 06:45:18 2024 +0200 Minimal prange class showing inlining degradation to VRP. There is a 2% slowdown to VRP unrelated to the work at hand. This patch is a skeleton implementation of prange that exhibits this degradation. It is meant as a place in the commit history we can return to in order to revisit the issue. The relevant discussion is here: https://gcc.gnu.org/pipermail/gcc/2024-May/243898.html gcc/ChangeLog: * value-range.h (class prange): New. Diff: --- gcc/value-range.h | 59 +++ 1 file changed, 59 insertions(+) diff --git a/gcc/value-range.h b/gcc/value-range.h index 934eec9e386..f52d5165707 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -378,6 +378,39 @@ private: wide_int m_ranges[N*2]; }; +class prange : public vrange +{ +public: + static bool supports_p (const_tree) { return false; } + virtual bool supports_type_p (const_tree) const final override { return false; } + virtual void accept (const vrange_visitor &) const final override {} + virtual void set_undefined () final override {} + virtual void set_varying (tree) final override {} + virtual void set_nonzero (tree) final override {} + virtual void set_zero (tree) final override; + virtual void set_nonnegative (tree) final override {} + virtual bool contains_p (tree) const final override { return false; } + virtual bool fits_p (const vrange &) const final override { return false; } + virtual bool singleton_p (tree * = NULL) const final override { return false; } + virtual bool zero_p () const final override { return false; } + virtual bool nonzero_p () const final override { return false; } + virtual void set (tree, tree, value_range_kind = VR_RANGE) final override {} + virtual tree type () const final override { return NULL; } + virtual bool union_ (const vrange &) final override { return false; } + virtual bool intersect (const vrange &) final override { return false; } + virtual tree lbound () const final override { return NULL; } + virtual tree ubound () const final override { return NULL; } + + wide_int lower_bound () const; + wide_int upper_bound () const; + irange_bitmask get_bitmask () const final override; + void update_bitmask (const irange_bitmask &) final override {} +private: + wide_int m_min; + wide_int m_max; + irange_bitmask m_bitmask; +}; + // Unsupported temporaries may be created by ranger before it's known // they're unsupported, or by vr_values::get_value_range. @@ -1187,6 +1220,32 @@ irange_val_max (const_tree type) return wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type)); } +inline void +prange::set_zero (tree type) +{ + wide_int zero = wi::zero (TYPE_PRECISION (type)); + m_min = m_max = zero; + m_bitmask = irange_bitmask (zero, zero); +} + +inline wide_int +prange::lower_bound () const +{ + return m_min; +} + +inline wide_int +prange::upper_bound () const +{ + return m_max; +} + +inline irange_bitmask +prange::get_bitmask () const +{ + return m_bitmask; +} + inline frange::frange () : vrange (VR_FRANGE)
[gcc r15-88] Reduce startup costs for Value_Range.
https://gcc.gnu.org/g:c60b3e211c555706cdc2dc8bfcdd540152cff350 commit r15-88-gc60b3e211c555706cdc2dc8bfcdd540152cff350 Author: Aldy Hernandez Date: Tue Apr 30 19:39:00 2024 +0200 Reduce startup costs for Value_Range. Value_Range is our polymorphic temporary that can hold any range. It is used for type agnostic code where it isn't known ahead of time, what the type of the range will be (irange, france, etc). Currently, there is a temporary of each type in the object, which means we need to construct each range for every temporary. This isn't scaling well now that prange is about to add yet another range type. This patch removes each range, opting to use in-place new for a byte buffer sufficiently large to hold ranges of any type. It reduces the memory footprint by 14% for every Value_Range temporary (from 792 to 680 bytes), and we are guaranteed it will never again grow as we add more range types (strings, complex numbers, etc). Surprisingly, it improves VRP performance by 6.61% and overall compilation by 0.44%, which is a lot more than we bargained for when we started working on prange performance. There is a slight change in semantics for Value_Range. The default constructor does not initialize the object at all. It must be manually initialized with either Value_Range::set_type(), or by assigning a range to it. This means that IPA's m_known_value_ranges must be initialized at allocation, instead of depending on the empty constructor to initialize it to VR_UNDEFINED for unsupported_range. I have taken the time to properly document both the class, and each method. If anything isn't clear, please let me know so I can adjust it accordingly. gcc/ChangeLog: * ipa-fnsummary.cc (evaluate_properties_for_edge): Initialize Value_Range's. * value-range.h (class Value_Range): Add a buffer and remove m_irange and m_frange. (Value_Range::Value_Range): Call init. (Value_Range::set_type): Same. (Value_Range::init): Use in place new to initialize buffer. (Value_Range::operator=): Tidy. Diff: --- gcc/ipa-fnsummary.cc | 8 +++- gcc/value-range.h| 127 --- 2 files changed, 76 insertions(+), 59 deletions(-) diff --git a/gcc/ipa-fnsummary.cc b/gcc/ipa-fnsummary.cc index dff40cd8aa5..668a01ef175 100644 --- a/gcc/ipa-fnsummary.cc +++ b/gcc/ipa-fnsummary.cc @@ -681,8 +681,12 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, if (!vr.undefined_p () && !vr.varying_p ()) { if (!avals->m_known_value_ranges.length ()) - avals->m_known_value_ranges.safe_grow_cleared (count, -true); + { + avals->m_known_value_ranges.safe_grow_cleared (count, + true); + for (int i = 0; i < count; ++i) + avals->m_known_value_ranges[i].set_type (void_type_node); + } avals->m_known_value_ranges[i] = vr; } } diff --git a/gcc/value-range.h b/gcc/value-range.h index 471f362f388..f1c638f8cd0 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -684,6 +684,16 @@ typedef int_range<2> value_range; // This is an "infinite" precision range object for use in temporary // calculations for any of the handled types. The object can be // transparently used as a vrange. +// +// Using any of the various constructors initializes the object +// appropriately, but the default constructor is uninitialized and +// must be initialized either with set_type() or by assigning into it. +// +// Assigning between incompatible types is allowed. For example if a +// temporary holds an irange, you can assign an frange into it, and +// all the right things will happen. However, before passing this +// object to a function accepting a vrange, the correct type must be +// set. If it isn't, you can do so with set_type(). class Value_Range { @@ -693,6 +703,7 @@ public: Value_Range (tree type); Value_Range (tree, tree, value_range_kind kind = VR_RANGE); Value_Range (const Value_Range &); + ~Value_Range (); void set_type (tree type); vrange& operator= (const vrange &); Value_Range& operator= (const Value_Range &); @@ -726,16 +737,29 @@ public: void accept (const vrange_visitor ) const { m_vrange->accept (v); } private: void init (tree type); - unsupported_range m_unsupported; + void init (const vrange &); + vrange *m_vrange; - int_range_max m_irange; - frange m_frange; + // The buffer must be at least the size of the
[gcc r15-87] Cleanups to unsupported_range.
https://gcc.gnu.org/g:1b5732de7e3980aa5197b1ac818f48f1ce9f87ab commit r15-87-g1b5732de7e3980aa5197b1ac818f48f1ce9f87ab Author: Aldy Hernandez Date: Tue Apr 30 18:54:11 2024 +0200 Cleanups to unsupported_range. Here are some cleanups to unsupported_range so the assignment operator takes an unsupported_range and behaves like the other ranges. This makes subsequent cleanups easier. gcc/ChangeLog: * value-range.cc (unsupported_range::union_): Cast vrange to unsupported_range. (unsupported_range::intersect): Same. (unsupported_range::operator=): Make argument an unsupported_range. * value-range.h: New constructor. Diff: --- gcc/value-range.cc | 10 +++--- gcc/value-range.h | 7 ++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/gcc/value-range.cc b/gcc/value-range.cc index ca6d521c625..7250115261f 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -147,8 +147,10 @@ unsupported_range::set_varying (tree) } bool -unsupported_range::union_ (const vrange ) +unsupported_range::union_ (const vrange ) { + const unsupported_range = as_a (v); + if (r.undefined_p () || varying_p ()) return false; if (undefined_p () || r.varying_p ()) @@ -161,8 +163,10 @@ unsupported_range::union_ (const vrange ) } bool -unsupported_range::intersect (const vrange ) +unsupported_range::intersect (const vrange ) { + const unsupported_range = as_a (v); + if (undefined_p () || r.varying_p ()) return false; if (r.undefined_p ()) @@ -216,7 +220,7 @@ unsupported_range::fits_p (const vrange &) const } unsupported_range & -unsupported_range::operator= (const vrange ) +unsupported_range::operator= (const unsupported_range ) { if (r.undefined_p ()) set_undefined (); diff --git a/gcc/value-range.h b/gcc/value-range.h index 11c73faca1b..471f362f388 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -389,6 +389,11 @@ public: { set_undefined (); } + unsupported_range (const unsupported_range ) +: vrange (VR_UNKNOWN) + { +unsupported_range::operator= (src); + } void set (tree min, tree, value_range_kind = VR_RANGE) final override; tree type () const final override; bool supports_type_p (const_tree) const final override; @@ -405,7 +410,7 @@ public: void set_zero (tree type) final override; void set_nonnegative (tree type) final override; bool fits_p (const vrange &) const final override; - unsupported_range& operator= (const vrange ); + unsupported_range& operator= (const unsupported_range ); tree lbound () const final override; tree ubound () const final override; };
[gcc r15-70] Change int_range<2> to infinite precision.
https://gcc.gnu.org/g:0b2735e0797fee9b4ec5cd74f22afe0483f888dd commit r15-70-g0b2735e0797fee9b4ec5cd74f22afe0483f888dd Author: Aldy Hernandez Date: Tue Apr 30 10:36:58 2024 +0200 Change int_range<2> to infinite precision. In my previous change I mistakenly changed Value_Range to int_range<2>. The former has "infinite" precision for integer ranges, whereas int_range<2> has two sub-ranges. This should have been int_range_max. gcc/ChangeLog: * gimple-ssa-warn-access.cc (check_nul_terminated_array): Change int_range<2> to int_range_max. (memmodel_to_uhwi): Same. * tree-ssa-loop-niter.cc (refine_value_range_using_guard): Same. (determine_value_range): Same. (infer_loop_bounds_from_signedness): Same. (scev_var_range_cant_overflow): Same. Diff: --- gcc/gimple-ssa-warn-access.cc | 4 ++-- gcc/tree-ssa-loop-niter.cc| 12 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc index 450c1caa765..2c10d19e7f3 100644 --- a/gcc/gimple-ssa-warn-access.cc +++ b/gcc/gimple-ssa-warn-access.cc @@ -330,7 +330,7 @@ check_nul_terminated_array (GimpleOrTree expr, tree src, tree bound) wide_int bndrng[2]; if (bound) { - int_range<2> r (TREE_TYPE (bound)); + int_range_max r (TREE_TYPE (bound)); get_range_query (cfun)->range_of_expr (r, bound); @@ -2816,7 +2816,7 @@ memmodel_to_uhwi (tree ord, gimple *stmt, unsigned HOST_WIDE_INT *cstval) { /* Use the range query to determine constant values in the absence of constant propagation (such as at -O0). */ - int_range<2> rng (TREE_TYPE (ord)); + int_range_max rng (TREE_TYPE (ord)); if (!get_range_query (cfun)->range_of_expr (rng, ord, stmt) || !rng.singleton_p ()) return false; diff --git a/gcc/tree-ssa-loop-niter.cc b/gcc/tree-ssa-loop-niter.cc index adbc1936982..0fde07e626f 100644 --- a/gcc/tree-ssa-loop-niter.cc +++ b/gcc/tree-ssa-loop-niter.cc @@ -214,7 +214,7 @@ refine_value_range_using_guard (tree type, tree var, get_type_static_bounds (type, mint, maxt); mpz_init (minc1); mpz_init (maxc1); - int_range<2> r (TREE_TYPE (varc1)); + int_range_max r (TREE_TYPE (varc1)); /* Setup range information for varc1. */ if (integer_zerop (varc1)) { @@ -368,7 +368,7 @@ determine_value_range (class loop *loop, tree type, tree var, mpz_t off, gphi_iterator gsi; /* Either for VAR itself... */ - int_range<2> var_range (TREE_TYPE (var)); + int_range_max var_range (TREE_TYPE (var)); get_range_query (cfun)->range_of_expr (var_range, var); if (var_range.varying_p () || var_range.undefined_p ()) rtype = VR_VARYING; @@ -382,7 +382,7 @@ determine_value_range (class loop *loop, tree type, tree var, mpz_t off, /* Or for PHI results in loop->header where VAR is used as PHI argument from the loop preheader edge. */ - int_range<2> phi_range (TREE_TYPE (var)); + int_range_max phi_range (TREE_TYPE (var)); for (gsi = gsi_start_phis (loop->header); !gsi_end_p (gsi); gsi_next ()) { gphi *phi = gsi.phi (); @@ -408,7 +408,7 @@ determine_value_range (class loop *loop, tree type, tree var, mpz_t off, involved. */ if (wi::gt_p (minv, maxv, sgn)) { - int_range<2> vr (TREE_TYPE (var)); + int_range_max vr (TREE_TYPE (var)); get_range_query (cfun)->range_of_expr (vr, var); if (vr.varying_p () || vr.undefined_p ()) rtype = VR_VARYING; @@ -4367,7 +4367,7 @@ infer_loop_bounds_from_signedness (class loop *loop, gimple *stmt) low = lower_bound_in_type (type, type); high = upper_bound_in_type (type, type); - int_range<2> r (TREE_TYPE (def)); + int_range_max r (TREE_TYPE (def)); get_range_query (cfun)->range_of_expr (r, def); if (!r.varying_p () && !r.undefined_p ()) { @@ -5426,7 +5426,7 @@ scev_var_range_cant_overflow (tree var, tree step, class loop *loop) if (!def_bb || !dominated_by_p (CDI_DOMINATORS, loop->latch, def_bb)) return false; - int_range<2> r (TREE_TYPE (var)); + int_range_max r (TREE_TYPE (var)); get_range_query (cfun)->range_of_expr (r, var); if (r.varying_p () || r.undefined_p ()) return false;
[gcc r15-41] Callers of irange_bitmask must normalize value/mask pairs.
https://gcc.gnu.org/g:d71308d5a681de00ea291136c162e5b46c7c commit r15-41-gd71308d5a681de00ea291136c162e5b46c7c Author: Aldy Hernandez Date: Tue Apr 23 10:12:56 2024 +0200 Callers of irange_bitmask must normalize value/mask pairs. As per the documentation, irange_bitmask must have the unknown bits in the mask set to 0 in the value field. Even though we say we must have normalized value/mask bits, we don't enforce it, opting to normalize on the fly in union and intersect. Avoiding this lazy enforcing as well as the extra saving/restoring involved in returning the changed status, gives us a performance increase of 1.25% for VRP and 1.51% for ipa-CP. gcc/ChangeLog: * tree-ssa-ccp.cc (ccp_finalize): Normalize before calling set_bitmask. * value-range.cc (irange::intersect_bitmask): Calculate changed irange_bitmask bits on our own. (irange::union_bitmask): Same. (irange_bitmask::verify_mask): Verify that bits are normalized. * value-range.h (irange_bitmask::union_): Do not normalize. Remove return value. (irange_bitmask::intersect): Same. Diff: --- gcc/tree-ssa-ccp.cc | 1 + gcc/value-range.cc | 7 +-- gcc/value-range.h | 24 ++-- 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/gcc/tree-ssa-ccp.cc b/gcc/tree-ssa-ccp.cc index f6a5cd0ee6e..3749126b5f7 100644 --- a/gcc/tree-ssa-ccp.cc +++ b/gcc/tree-ssa-ccp.cc @@ -1024,6 +1024,7 @@ ccp_finalize (bool nonzero_p) unsigned int precision = TYPE_PRECISION (TREE_TYPE (val->value)); wide_int value = wi::to_wide (val->value); wide_int mask = wide_int::from (val->mask, precision, UNSIGNED); + value = value & ~mask; set_bitmask (name, value, mask); } } diff --git a/gcc/value-range.cc b/gcc/value-range.cc index a27de5534e1..ca6d521c625 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -2067,7 +2067,8 @@ irange::intersect_bitmask (const irange ) irange_bitmask bm = get_bitmask (); irange_bitmask save = bm; - if (!bm.intersect (r.get_bitmask ())) + bm.intersect (r.get_bitmask ()); + if (save == bm) return false; m_bitmask = bm; @@ -2099,7 +2100,8 @@ irange::union_bitmask (const irange ) irange_bitmask bm = get_bitmask (); irange_bitmask save = bm; - if (!bm.union_ (r.get_bitmask ())) + bm.union_ (r.get_bitmask ()); + if (save == bm) return false; m_bitmask = bm; @@ -2133,6 +2135,7 @@ void irange_bitmask::verify_mask () const { gcc_assert (m_value.get_precision () == m_mask.get_precision ()); + gcc_checking_assert (wi::bit_and (m_mask, m_value) == 0); } void diff --git a/gcc/value-range.h b/gcc/value-range.h index 0ab717697f0..11c73faca1b 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -139,8 +139,8 @@ public: void set_unknown (unsigned prec); bool unknown_p () const; unsigned get_precision () const; - bool union_ (const irange_bitmask ); - bool intersect (const irange_bitmask ); + void union_ (const irange_bitmask ); + void intersect (const irange_bitmask ); bool operator== (const irange_bitmask ) const; bool operator!= (const irange_bitmask ) const { return !(*this == src); } void verify_mask () const; @@ -233,29 +233,18 @@ irange_bitmask::operator== (const irange_bitmask ) const return m_value == src.m_value && m_mask == src.m_mask; } -inline bool -irange_bitmask::union_ (const irange_bitmask _src) +inline void +irange_bitmask::union_ (const irange_bitmask ) { - // Normalize mask. - irange_bitmask src (orig_src.m_value & ~orig_src.m_mask, orig_src.m_mask); - m_value &= ~m_mask; - - irange_bitmask save (*this); m_mask = (m_mask | src.m_mask) | (m_value ^ src.m_value); m_value = m_value & src.m_value; if (flag_checking) verify_mask (); - return *this != save; } -inline bool -irange_bitmask::intersect (const irange_bitmask _src) +inline void +irange_bitmask::intersect (const irange_bitmask ) { - // Normalize mask. - irange_bitmask src (orig_src.m_value & ~orig_src.m_mask, orig_src.m_mask); - m_value &= ~m_mask; - - irange_bitmask save (*this); // If we have two known bits that are incompatible, the resulting // bit is undefined. It is unclear whether we should set the entire // range to UNDEFINED, or just a subset of it. For now, set the @@ -274,7 +263,6 @@ irange_bitmask::intersect (const irange_bitmask _src) } if (flag_checking) verify_mask (); - return *this != save; } // An integer range without any storage.
[gcc r15-40] Remove range_zero and range_nonzero.
https://gcc.gnu.org/g:3b9abfd2df5fe720798aab1e21b4a11876607561 commit r15-40-g3b9abfd2df5fe720798aab1e21b4a11876607561 Author: Aldy Hernandez Date: Wed Mar 20 05:51:55 2024 +0100 Remove range_zero and range_nonzero. Remove legacy range_zero and range_nonzero as they return by value, which make it not work in a separate irange and prange world. Also, we already have set_zero and set_nonzero methods in vrange. gcc/ChangeLog: * range-op-ptr.cc (pointer_plus_operator::wi_fold): Use method range setters instead of out of line functions. (pointer_min_max_operator::wi_fold): Same. (pointer_and_operator::wi_fold): Same. (pointer_or_operator::wi_fold): Same. * range-op.cc (operator_negate::fold_range): Same. (operator_addr_expr::fold_range): Same. (range_op_cast_tests): Same. * range.cc (range_zero): Remove. (range_nonzero): Remove. * range.h (range_zero): Remove. (range_nonzero): Remove. * value-range.cc (range_tests_misc): Use method instead of out of line function. Diff: --- gcc/range-op-ptr.cc | 14 +++--- gcc/range-op.cc | 14 -- gcc/range.cc| 14 -- gcc/range.h | 2 -- gcc/value-range.cc | 7 --- 5 files changed, 19 insertions(+), 32 deletions(-) diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc index 2c85d75b5e8..7343ef635f3 100644 --- a/gcc/range-op-ptr.cc +++ b/gcc/range-op-ptr.cc @@ -101,10 +101,10 @@ pointer_plus_operator::wi_fold (irange , tree type, && !TYPE_OVERFLOW_WRAPS (type) && (flag_delete_null_pointer_checks || !wi::sign_mask (rh_ub))) -r = range_nonzero (type); +r.set_nonzero (type); else if (lh_lb == lh_ub && lh_lb == 0 && rh_lb == rh_ub && rh_lb == 0) -r = range_zero (type); +r.set_zero (type); else r.set_varying (type); } @@ -150,9 +150,9 @@ pointer_min_max_operator::wi_fold (irange , tree type, // are varying. if (!wi_includes_zero_p (type, lh_lb, lh_ub) && !wi_includes_zero_p (type, rh_lb, rh_ub)) -r = range_nonzero (type); +r.set_nonzero (type); else if (wi_zero_p (type, lh_lb, lh_ub) && wi_zero_p (type, rh_lb, rh_ub)) -r = range_zero (type); +r.set_zero (type); else r.set_varying (type); } @@ -175,7 +175,7 @@ pointer_and_operator::wi_fold (irange , tree type, // For pointer types, we are really only interested in asserting // whether the expression evaluates to non-NULL. if (wi_zero_p (type, lh_lb, lh_ub) || wi_zero_p (type, lh_lb, lh_ub)) -r = range_zero (type); +r.set_zero (type); else r.set_varying (type); } @@ -236,9 +236,9 @@ pointer_or_operator::wi_fold (irange , tree type, // whether the expression evaluates to non-NULL. if (!wi_includes_zero_p (type, lh_lb, lh_ub) && !wi_includes_zero_p (type, rh_lb, rh_ub)) -r = range_nonzero (type); +r.set_nonzero (type); else if (wi_zero_p (type, lh_lb, lh_ub) && wi_zero_p (type, rh_lb, rh_ub)) -r = range_zero (type); +r.set_zero (type); else r.set_varying (type); } diff --git a/gcc/range-op.cc b/gcc/range-op.cc index 6ea7d624a9b..ab3a4f0b200 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -4364,9 +4364,11 @@ operator_negate::fold_range (irange , tree type, { if (empty_range_varying (r, type, lh, rh)) return true; - // -X is simply 0 - X. - return range_op_handler (MINUS_EXPR).fold_range (r, type, - range_zero (type), lh); + +// -X is simply 0 - X. + int_range<1> zero; + zero.set_zero (type); + return range_op_handler (MINUS_EXPR).fold_range (r, type, zero, lh); } bool @@ -4391,7 +4393,7 @@ operator_addr_expr::fold_range (irange , tree type, // Return a non-null pointer of the LHS type (passed in op2). if (lh.zero_p ()) -r = range_zero (type); +r.set_zero (type); else if (lh.undefined_p () || contains_zero_p (lh)) r.set_varying (type); else @@ -4675,7 +4677,7 @@ range_op_cast_tests () if (TYPE_PRECISION (integer_type_node) > TYPE_PRECISION (short_integer_type_node)) { - r0 = range_nonzero (integer_type_node); + r0.set_nonzero (integer_type_node); range_cast (r0, short_integer_type_node); r1 = int_range<1> (short_integer_type_node, min_limit (short_integer_type_node), @@ -4687,7 +4689,7 @@ range_op_cast_tests () // // NONZERO signed 16-bits is [-MIN_16,-1][1, +MAX_16]. // Converting this to 32-bits signed is [-MIN_16,-1][1, +MAX_16]. - r0 = range_nonzero (short_integer_type_node); + r0.set_nonzero (short_integer_type_node); range_cast (r0, integer_type_node); r1 = int_range<1> (integer_type_node, INT (-32768), INT (-1)); r2 = int_range<1> (integer_type_node, INT (1), INT (32767)); diff --git a/gcc/range.cc b/gcc/range.cc
[gcc r15-39] Move print_irange_* out of vrange_printer class.
https://gcc.gnu.org/g:df6a1bc59a355c9fee10d29f54c9dca81612afb6 commit r15-39-gdf6a1bc59a355c9fee10d29f54c9dca81612afb6 Author: Aldy Hernandez Date: Tue Mar 19 20:26:27 2024 +0100 Move print_irange_* out of vrange_printer class. Move some code out of the irange pretty printers so it can be shared with pointers. gcc/ChangeLog: * value-range-pretty-print.cc (print_int_bound): New. (print_irange_bitmasks): New. (vrange_printer::print_irange_bound): Remove. (vrange_printer::print_irange_bitmasks): Remove. * value-range-pretty-print.h: Remove print_irange_bitmasks and print_irange_bound Diff: --- gcc/value-range-pretty-print.cc | 83 - gcc/value-range-pretty-print.h | 2 - 2 files changed, 41 insertions(+), 44 deletions(-) diff --git a/gcc/value-range-pretty-print.cc b/gcc/value-range-pretty-print.cc index c75cbea3955..b6d23dce6d2 100644 --- a/gcc/value-range-pretty-print.cc +++ b/gcc/value-range-pretty-print.cc @@ -30,6 +30,44 @@ along with GCC; see the file COPYING3. If not see #include "gimple-range.h" #include "value-range-pretty-print.h" +static void +print_int_bound (pretty_printer *pp, const wide_int , tree type) +{ + wide_int type_min = wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type)); + wide_int type_max = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type)); + + if (INTEGRAL_TYPE_P (type) + && !TYPE_UNSIGNED (type) + && bound == type_min + && TYPE_PRECISION (type) != 1) +pp_string (pp, "-INF"); + else if (bound == type_max && TYPE_PRECISION (type) != 1) +pp_string (pp, "+INF"); + else +pp_wide_int (pp, bound, TYPE_SIGN (type)); +} + +static void +print_irange_bitmasks (pretty_printer *pp, const irange_bitmask ) +{ + if (bm.unknown_p ()) +return; + + pp_string (pp, " MASK "); + char buf[WIDE_INT_PRINT_BUFFER_SIZE], *p; + unsigned len_mask, len_val; + if (print_hex_buf_size (bm.mask (), _mask) + | print_hex_buf_size (bm.value (), _val)) +p = XALLOCAVEC (char, MAX (len_mask, len_val)); + else +p = buf; + print_hex (bm.mask (), p); + pp_string (pp, p); + pp_string (pp, " VALUE "); + print_hex (bm.value (), p); + pp_string (pp, p); +} + void vrange_printer::visit (const unsupported_range ) const { @@ -66,51 +104,12 @@ vrange_printer::visit (const irange ) const for (unsigned i = 0; i < r.num_pairs (); ++i) { pp_character (pp, '['); - print_irange_bound (r.lower_bound (i), r.type ()); + print_int_bound (pp, r.lower_bound (i), r.type ()); pp_string (pp, ", "); - print_irange_bound (r.upper_bound (i), r.type ()); + print_int_bound (pp, r.upper_bound (i), r.type ()); pp_character (pp, ']'); } - print_irange_bitmasks (r); -} - -void -vrange_printer::print_irange_bound (const wide_int , tree type) const -{ - wide_int type_min = wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type)); - wide_int type_max = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type)); - - if (INTEGRAL_TYPE_P (type) - && !TYPE_UNSIGNED (type) - && bound == type_min - && TYPE_PRECISION (type) != 1) -pp_string (pp, "-INF"); - else if (bound == type_max && TYPE_PRECISION (type) != 1) -pp_string (pp, "+INF"); - else -pp_wide_int (pp, bound, TYPE_SIGN (type)); -} - -void -vrange_printer::print_irange_bitmasks (const irange ) const -{ - irange_bitmask bm = r.m_bitmask; - if (bm.unknown_p ()) -return; - - pp_string (pp, " MASK "); - char buf[WIDE_INT_PRINT_BUFFER_SIZE], *p; - unsigned len_mask, len_val; - if (print_hex_buf_size (bm.mask (), _mask) - | print_hex_buf_size (bm.value (), _val)) -p = XALLOCAVEC (char, MAX (len_mask, len_val)); - else -p = buf; - print_hex (bm.mask (), p); - pp_string (pp, p); - pp_string (pp, " VALUE "); - print_hex (bm.value (), p); - pp_string (pp, p); + print_irange_bitmasks (pp, r.m_bitmask); } void diff --git a/gcc/value-range-pretty-print.h b/gcc/value-range-pretty-print.h index ca85fd6157c..44cd6e81298 100644 --- a/gcc/value-range-pretty-print.h +++ b/gcc/value-range-pretty-print.h @@ -29,8 +29,6 @@ public: void visit (const irange &) const override; void visit (const frange &) const override; private: - void print_irange_bound (const wide_int , tree type) const; - void print_irange_bitmasks (const irange &) const; void print_frange_nan (const frange &) const; void print_real_value (tree type, const REAL_VALUE_TYPE ) const;
[gcc r15-37] Make some integer specific ranges generic Value_Range's.
https://gcc.gnu.org/g:c284f8d2d16ce9c29defce3329419ccc54605ad4 commit r15-37-gc284f8d2d16ce9c29defce3329419ccc54605ad4 Author: Aldy Hernandez Date: Tue Mar 19 18:22:08 2024 +0100 Make some integer specific ranges generic Value_Range's. There are some irange uses that should be Value_Range, because they can be either integers or pointers. This will become a problem when prange comes live. gcc/ChangeLog: * tree-ssa-loop-split.cc (split_at_bb_p): Make int_range a Value_Range. * tree-ssa-strlen.cc (get_range): Same. * value-query.cc (range_query::get_tree_range): Handle both integers and pointers. * vr-values.cc (simplify_using_ranges::fold_cond_with_ops): Make r0 and r1 Value_Range's. Diff: --- gcc/tree-ssa-loop-split.cc | 6 +++--- gcc/tree-ssa-strlen.cc | 2 +- gcc/value-query.cc | 4 +--- gcc/vr-values.cc | 3 ++- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/gcc/tree-ssa-loop-split.cc b/gcc/tree-ssa-loop-split.cc index a770ea371a2..a6be0cef7b0 100644 --- a/gcc/tree-ssa-loop-split.cc +++ b/gcc/tree-ssa-loop-split.cc @@ -144,18 +144,18 @@ split_at_bb_p (class loop *loop, basic_block bb, tree *border, affine_iv *iv, value range. */ else { - int_range<2> r; + Value_Range r (TREE_TYPE (op0)); get_global_range_query ()->range_of_expr (r, op0, stmt); if (!r.varying_p () && !r.undefined_p () && TREE_CODE (op1) == INTEGER_CST) { wide_int val = wi::to_wide (op1); - if (known_eq (val, r.lower_bound ())) + if (known_eq (val, wi::to_wide (r.lbound ( { code = (code == EQ_EXPR) ? LE_EXPR : GT_EXPR; break; } - else if (known_eq (val, r.upper_bound ())) + else if (known_eq (val, wi::to_wide (r.ubound ( { code = (code == EQ_EXPR) ? GE_EXPR : LT_EXPR; break; diff --git a/gcc/tree-ssa-strlen.cc b/gcc/tree-ssa-strlen.cc index e09c9cc081f..61c3da22322 100644 --- a/gcc/tree-ssa-strlen.cc +++ b/gcc/tree-ssa-strlen.cc @@ -215,7 +215,7 @@ get_range (tree val, gimple *stmt, wide_int minmax[2], rvals = get_range_query (cfun); } - value_range vr; + Value_Range vr (TREE_TYPE (val)); if (!rvals->range_of_expr (vr, val, stmt)) return NULL_TREE; diff --git a/gcc/value-query.cc b/gcc/value-query.cc index eda71dc89d3..052b7511565 100644 --- a/gcc/value-query.cc +++ b/gcc/value-query.cc @@ -156,11 +156,9 @@ range_query::get_tree_range (vrange , tree expr, gimple *stmt) { case INTEGER_CST: { - irange = as_a (r); if (TREE_OVERFLOW_P (expr)) expr = drop_tree_overflow (expr); - wide_int w = wi::to_wide (expr); - i.set (TREE_TYPE (expr), w, w); + r.set (expr, expr); return true; } diff --git a/gcc/vr-values.cc b/gcc/vr-values.cc index ff68d40c355..0572bf6c8c7 100644 --- a/gcc/vr-values.cc +++ b/gcc/vr-values.cc @@ -310,7 +310,8 @@ tree simplify_using_ranges::fold_cond_with_ops (enum tree_code code, tree op0, tree op1, gimple *s) { - int_range_max r0, r1; + Value_Range r0 (TREE_TYPE (op0)); + Value_Range r1 (TREE_TYPE (op1)); if (!query->range_of_expr (r0, op0, s) || !query->range_of_expr (r1, op1, s)) return NULL_TREE;
[gcc r15-38] Accept any vrange in range_includes_zero_p.
https://gcc.gnu.org/g:b102633be7d0b763d106b0a883679bb1497ca17c commit r15-38-gb102633be7d0b763d106b0a883679bb1497ca17c Author: Aldy Hernandez Date: Tue Mar 19 18:29:21 2024 +0100 Accept any vrange in range_includes_zero_p. Accept a vrange, as this will be used for either integers or pointers. gcc/ChangeLog: * value-range.h (range_includes_zero_p): Accept vrange. Diff: --- gcc/value-range.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gcc/value-range.h b/gcc/value-range.h index ede90a496d8..0ab717697f0 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -970,7 +970,7 @@ irange::contains_p (tree cst) const } inline bool -range_includes_zero_p (const irange ) +range_includes_zero_p (const vrange ) { if (vr.undefined_p ()) return false; @@ -978,8 +978,7 @@ range_includes_zero_p (const irange ) if (vr.varying_p ()) return true; - wide_int zero = wi::zero (TYPE_PRECISION (vr.type ())); - return vr.contains_p (zero); + return vr.contains_p (build_zero_cst (vr.type ())); } // Constructors for irange
[gcc r15-36] Move get_bitmask_from_range out of irange class.
https://gcc.gnu.org/g:2caf7a50a6a9de80d2767d82b8cdb69d63469aaf commit r15-36-g2caf7a50a6a9de80d2767d82b8cdb69d63469aaf Author: Aldy Hernandez Date: Tue Mar 19 18:04:55 2024 +0100 Move get_bitmask_from_range out of irange class. prange will also have bitmasks, so it will need to use get_bitmask_from_range. gcc/ChangeLog: * value-range.cc (get_bitmask_from_range): Move out of irange class. (irange::get_bitmask): Call function instead of internal method. * value-range.h (class irange): Remove get_bitmask_from_range. Diff: --- gcc/value-range.cc | 52 ++-- gcc/value-range.h | 1 - 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 44929b210aa..d9689bd469f 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -31,6 +31,30 @@ along with GCC; see the file COPYING3. If not see #include "fold-const.h" #include "gimple-range.h" +// Return the bitmask inherent in a range. + +static irange_bitmask +get_bitmask_from_range (tree type, + const wide_int , const wide_int ) +{ + unsigned prec = TYPE_PRECISION (type); + + // All the bits of a singleton are known. + if (min == max) +{ + wide_int mask = wi::zero (prec); + wide_int value = min; + return irange_bitmask (value, mask); +} + + wide_int xorv = min ^ max; + + if (xorv != 0) +xorv = wi::mask (prec - wi::clz (xorv), false, prec); + + return irange_bitmask (wi::zero (prec), min | xorv); +} + void irange::accept (const vrange_visitor ) const { @@ -1881,31 +1905,6 @@ irange::invert () verify_range (); } -// Return the bitmask inherent in the range. - -irange_bitmask -irange::get_bitmask_from_range () const -{ - unsigned prec = TYPE_PRECISION (type ()); - wide_int min = lower_bound (); - wide_int max = upper_bound (); - - // All the bits of a singleton are known. - if (min == max) -{ - wide_int mask = wi::zero (prec); - wide_int value = lower_bound (); - return irange_bitmask (value, mask); -} - - wide_int xorv = min ^ max; - - if (xorv != 0) -xorv = wi::mask (prec - wi::clz (xorv), false, prec); - - return irange_bitmask (wi::zero (prec), min | xorv); -} - // Remove trailing ranges that this bitmask indicates can't exist. void @@ -2027,7 +2026,8 @@ irange::get_bitmask () const // in the mask. // // See also the note in irange_bitmask::intersect. - irange_bitmask bm = get_bitmask_from_range (); + irange_bitmask bm += get_bitmask_from_range (type (), lower_bound (), upper_bound ()); if (!m_bitmask.unknown_p ()) bm.intersect (m_bitmask); return bm; diff --git a/gcc/value-range.h b/gcc/value-range.h index d2e8fd5a4d9..ede90a496d8 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -352,7 +352,6 @@ private: bool varying_compatible_p () const; bool intersect_bitmask (const irange ); bool union_bitmask (const irange ); - irange_bitmask get_bitmask_from_range () const; bool set_range_from_bitmask (); bool intersect (const wide_int& lb, const wide_int& ub);
[gcc r15-34] Verify that reading back from vrange_storage doesn't drop bits.
https://gcc.gnu.org/g:92f74ee21218cab08d7bb7769004a65e8a291fa3 commit r15-34-g92f74ee21218cab08d7bb7769004a65e8a291fa3 Author: Aldy Hernandez Date: Tue Mar 19 16:35:41 2024 +0100 Verify that reading back from vrange_storage doesn't drop bits. We have a sanity check in the irange storage code to make sure that reading back a cache entry we have just written to yields exactly the same range. There's no need to do this only for integers. This patch moves the code to a more generic place. However, doing so tickles a latent bug in the frange code where a range is being pessimized from [0.0, 1.0] to [-0.0, 1.0]. Exclude checking frange's until this bug is fixed. gcc/ChangeLog: * value-range-storage.cc (irange_storage::set_irange): Move verification code from here... (vrange_storage::set_vrange): ...to here. Diff: --- gcc/value-range-storage.cc | 20 +--- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/gcc/value-range-storage.cc b/gcc/value-range-storage.cc index f00474ad0e6..09a29776a0e 100644 --- a/gcc/value-range-storage.cc +++ b/gcc/value-range-storage.cc @@ -165,6 +165,19 @@ vrange_storage::set_vrange (const vrange ) } else gcc_unreachable (); + + // Verify that reading back from the cache didn't drop bits. + if (flag_checking + // FIXME: Avoid checking frange, as it currently pessimizes some ranges: + // + // gfortran.dg/pr49472.f90 pessimizes [0.0, 1.0] into [-0.0, 1.0]. + && !is_a (r) + && !r.undefined_p ()) +{ + Value_Range tmp (r); + get_vrange (tmp, r.type ()); + gcc_checking_assert (tmp == r); +} } // Restore R from storage. @@ -306,13 +319,6 @@ irange_storage::set_irange (const irange ) irange_bitmask bm = r.m_bitmask; write_wide_int (val, len, bm.value ()); write_wide_int (val, len, bm.mask ()); - - if (flag_checking) -{ - int_range_max tmp; - get_irange (tmp, r.type ()); - gcc_checking_assert (tmp == r); -} } static inline void
[gcc r15-35] Accept a vrange in get_legacy_range.
https://gcc.gnu.org/g:9a2f0d152d98dd55efc9accd07ea507b929c3516 commit r15-35-g9a2f0d152d98dd55efc9accd07ea507b929c3516 Author: Aldy Hernandez Date: Tue Mar 19 17:17:53 2024 +0100 Accept a vrange in get_legacy_range. In preparation for prange, make get_legacy_range take a generic vrange, not just an irange. gcc/ChangeLog: * value-range.cc (get_legacy_range): Make static and add another version of get_legacy_range that takes a vrange. * value-range.h (class irange): Remove unnecessary friendship with get_legacy_range. (get_legacy_range): Accept a vrange. Diff: --- gcc/value-range.cc | 17 - gcc/value-range.h | 3 +-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/gcc/value-range.cc b/gcc/value-range.cc index b901c864a7b..44929b210aa 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -1004,7 +1004,7 @@ irange::operator= (const irange ) return *this; } -value_range_kind +static value_range_kind get_legacy_range (const irange , tree , tree ) { if (r.undefined_p ()) @@ -1041,6 +1041,21 @@ get_legacy_range (const irange , tree , tree ) return VR_RANGE; } +// Given a range in V, return an old-style legacy range consisting of +// a value_range_kind with a MIN/MAX. This is to maintain +// compatibility with passes that still depend on VR_ANTI_RANGE, and +// only works for integers and pointers. + +value_range_kind +get_legacy_range (const vrange , tree , tree ) +{ + if (is_a (v)) +return get_legacy_range (as_a (v), min, max); + + gcc_unreachable (); + return VR_UNDEFINED; +} + /* Set value range to the canonical form of {VRTYPE, MIN, MAX, EQUIV}. This means adjusting VRTYPE, MIN and MAX representing the case of a wrapping range with MAX < MIN covering [MIN, type_max] U [type_min, MAX] diff --git a/gcc/value-range.h b/gcc/value-range.h index 62f123e2a4b..d2e8fd5a4d9 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -281,7 +281,6 @@ irange_bitmask::intersect (const irange_bitmask _src) class irange : public vrange { - friend value_range_kind get_legacy_range (const irange &, tree &, tree &); friend class irange_storage; friend class vrange_printer; public: @@ -886,7 +885,7 @@ Value_Range::supports_type_p (const_tree type) return irange::supports_p (type) || frange::supports_p (type); } -extern value_range_kind get_legacy_range (const irange &, tree , tree ); +extern value_range_kind get_legacy_range (const vrange &, tree , tree ); extern void dump_value_range (FILE *, const vrange *); extern bool vrp_operand_equal_p (const_tree, const_tree); inline REAL_VALUE_TYPE frange_val_min (const_tree type);
[gcc r15-33] Change range_includes_zero_p argument to a reference.
https://gcc.gnu.org/g:d883fc7d00ed6bf5ee151de4fd3e05431582bd5f commit r15-33-gd883fc7d00ed6bf5ee151de4fd3e05431582bd5f Author: Aldy Hernandez Date: Tue Mar 19 16:33:47 2024 +0100 Change range_includes_zero_p argument to a reference. Make range_includes_zero_p take an argument instead of a pointer for consistency in the range-op code. gcc/ChangeLog: * gimple-range-op.cc (cfn_clz::fold_range): Change range_includes_zero_p argument to a reference. (cfn_ctz::fold_range): Same. * range-op.cc (operator_plus::lhs_op1_relation): Same. * value-range.h (range_includes_zero_p): Same. Diff: --- gcc/gimple-range-op.cc | 6 +++--- gcc/range-op.cc| 2 +- gcc/value-range.h | 10 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc index a98f7db62a7..9c50c00549e 100644 --- a/gcc/gimple-range-op.cc +++ b/gcc/gimple-range-op.cc @@ -853,7 +853,7 @@ public: // __builtin_ffs* and __builtin_popcount* return [0, prec]. int prec = TYPE_PRECISION (lh.type ()); // If arg is non-zero, then ffs or popcount are non-zero. -int mini = range_includes_zero_p () ? 0 : 1; +int mini = range_includes_zero_p (lh) ? 0 : 1; int maxi = prec; // If some high bits are known to be zero, decrease the maximum. @@ -945,7 +945,7 @@ cfn_clz::fold_range (irange , tree type, const irange , if (mini == -2) mini = 0; } - else if (!range_includes_zero_p ()) + else if (!range_includes_zero_p (lh)) { mini = 0; maxi = prec - 1; @@ -1007,7 +1007,7 @@ cfn_ctz::fold_range (irange , tree type, const irange , mini = -2; } // If arg is non-zero, then use [0, prec - 1]. - if (!range_includes_zero_p ()) + if (!range_includes_zero_p (lh)) { mini = 0; maxi = prec - 1; diff --git a/gcc/range-op.cc b/gcc/range-op.cc index aeff55cfd78..6ea7d624a9b 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -1657,7 +1657,7 @@ operator_plus::lhs_op1_relation (const irange , } // If op2 does not contain 0, then LHS and OP1 can never be equal. - if (!range_includes_zero_p ()) + if (!range_includes_zero_p (op2)) return VREL_NE; return VREL_VARYING; diff --git a/gcc/value-range.h b/gcc/value-range.h index 2650ded6d10..62f123e2a4b 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -972,16 +972,16 @@ irange::contains_p (tree cst) const } inline bool -range_includes_zero_p (const irange *vr) +range_includes_zero_p (const irange ) { - if (vr->undefined_p ()) + if (vr.undefined_p ()) return false; - if (vr->varying_p ()) + if (vr.varying_p ()) return true; - wide_int zero = wi::zero (TYPE_PRECISION (vr->type ())); - return vr->contains_p (zero); + wide_int zero = wi::zero (TYPE_PRECISION (vr.type ())); + return vr.contains_p (zero); } // Constructors for irange
[gcc r15-32] Make fold_cond_with_ops use a boolean type for range_true/range_false.
https://gcc.gnu.org/g:039e88b1aea5723221e8b0b926c35afb2f96a8a9 commit r15-32-g039e88b1aea5723221e8b0b926c35afb2f96a8a9 Author: Aldy Hernandez Date: Wed Feb 7 11:27:29 2024 +0100 Make fold_cond_with_ops use a boolean type for range_true/range_false. Conditional operators are always boolean, regardless of their operands. Getting the type wrong is not currently a problem, but will be when prange's can no longer store an integer. gcc/ChangeLog: * vr-values.cc (simplify_using_ranges::fold_cond_with_ops): Remove type from range_true and range_false. Diff: --- gcc/vr-values.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gcc/vr-values.cc b/gcc/vr-values.cc index a7e291a16e5..ff68d40c355 100644 --- a/gcc/vr-values.cc +++ b/gcc/vr-values.cc @@ -320,9 +320,9 @@ simplify_using_ranges::fold_cond_with_ops (enum tree_code code, range_op_handler handler (code); if (handler && handler.fold_range (res, type, r0, r1)) { - if (res == range_true (type)) + if (res == range_true ()) return boolean_true_node; - if (res == range_false (type)) + if (res == range_false ()) return boolean_false_node; } return NULL;
[gcc r15-31] Remove GTY support for vrange and derived classes.
https://gcc.gnu.org/g:eeef1f69c5e77ecf13fdcf44df5bcf592a9993e6 commit r15-31-geeef1f69c5e77ecf13fdcf44df5bcf592a9993e6 Author: Aldy Hernandez Date: Wed Feb 21 09:34:29 2024 +0100 Remove GTY support for vrange and derived classes. Now that we have a vrange storage class to save ranges in long-term memory, there is no need for GTY markers for any of the vrange classes, since they should never live in GC. gcc/ChangeLog: * value-range-storage.h: Remove friends. * value-range.cc (gt_ggc_mx): Remove. (gt_pch_nx): Remove. * value-range.h (class vrange): Remove GTY markers. (class irange): Same. (class int_range): Same. (class frange): Same. (gt_ggc_mx): Remove. (gt_pch_nx): Remove. Diff: --- gcc/value-range-storage.h | 4 --- gcc/value-range.cc| 73 --- gcc/value-range.h | 46 +++-- 3 files changed, 4 insertions(+), 119 deletions(-) diff --git a/gcc/value-range-storage.h b/gcc/value-range-storage.h index d94c520aa73..5756de7e32d 100644 --- a/gcc/value-range-storage.h +++ b/gcc/value-range-storage.h @@ -75,10 +75,6 @@ private: static size_t size (const irange ); const unsigned short *lengths_address () const; unsigned short *write_lengths_address (); - friend void gt_ggc_mx_irange_storage (void *); - friend void gt_pch_p_14irange_storage (void *, void *, - gt_pointer_operator, void *); - friend void gt_pch_nx_irange_storage (void *); // The shared precision of each number. unsigned short m_precision; diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 926f7b707ea..b901c864a7b 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -2165,79 +2165,6 @@ vrp_operand_equal_p (const_tree val1, const_tree val2) return true; } -void -gt_ggc_mx (irange *x) -{ - if (!x->undefined_p ()) -gt_ggc_mx (x->m_type); -} - -void -gt_pch_nx (irange *x) -{ - if (!x->undefined_p ()) -gt_pch_nx (x->m_type); -} - -void -gt_pch_nx (irange *x, gt_pointer_operator op, void *cookie) -{ - for (unsigned i = 0; i < x->m_num_ranges; ++i) -{ - op (>m_base[i * 2], NULL, cookie); - op (>m_base[i * 2 + 1], NULL, cookie); -} -} - -void -gt_ggc_mx (frange *x) -{ - gt_ggc_mx (x->m_type); -} - -void -gt_pch_nx (frange *x) -{ - gt_pch_nx (x->m_type); -} - -void -gt_pch_nx (frange *x, gt_pointer_operator op, void *cookie) -{ - op (>m_type, NULL, cookie); -} - -void -gt_ggc_mx (vrange *x) -{ - if (is_a (*x)) -return gt_ggc_mx ((irange *) x); - if (is_a (*x)) -return gt_ggc_mx ((frange *) x); - gcc_unreachable (); -} - -void -gt_pch_nx (vrange *x) -{ - if (is_a (*x)) -return gt_pch_nx ((irange *) x); - if (is_a (*x)) -return gt_pch_nx ((frange *) x); - gcc_unreachable (); -} - -void -gt_pch_nx (vrange *x, gt_pointer_operator op, void *cookie) -{ - if (is_a (*x)) -gt_pch_nx ((irange *) x, op, cookie); - else if (is_a (*x)) -gt_pch_nx ((frange *) x, op, cookie); - else -gcc_unreachable (); -} - #define DEFINE_INT_RANGE_INSTANCE(N) \ template int_range::int_range(tree_node *, \ const wide_int &,\ diff --git a/gcc/value-range.h b/gcc/value-range.h index 991ffeafcb8..2650ded6d10 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -72,7 +72,7 @@ enum value_range_discriminator // if (f.supports_type_p (type)) ... //} -class GTY((user)) vrange +class vrange { template friend bool is_a (vrange &); friend class Value_Range; @@ -279,7 +279,7 @@ irange_bitmask::intersect (const irange_bitmask _src) // An integer range without any storage. -class GTY((user)) irange : public vrange +class irange : public vrange { friend value_range_kind get_legacy_range (const irange &, tree &, tree &); friend class irange_storage; @@ -350,10 +350,6 @@ protected: // Hard limit on max ranges allowed. static const int HARD_MAX_RANGES = 255; private: - friend void gt_ggc_mx (irange *); - friend void gt_pch_nx (irange *); - friend void gt_pch_nx (irange *, gt_pointer_operator, void *); - bool varying_compatible_p () const; bool intersect_bitmask (const irange ); bool union_bitmask (const irange ); @@ -379,7 +375,7 @@ protected: // HARD_MAX_RANGES. This new storage is freed upon destruction. template -class GTY((user)) int_range : public irange +class int_range : public irange { public: int_range (); @@ -484,13 +480,10 @@ nan_state::neg_p () const // The representation is a type with a couple of endpoints, unioned // with the set of { -NAN, +Nan }. -class GTY((user)) frange : public vrange +class frange : public vrange { friend class frange_storage; friend class vrange_printer; - friend void gt_ggc_mx
[gcc r15-29] Add tree versions of lower and upper bounds to vrange.
https://gcc.gnu.org/g:ba1a8e8eed963c0253c6e5550c8bccc264c5d469 commit r15-29-gba1a8e8eed963c0253c6e5550c8bccc264c5d469 Author: Aldy Hernandez Date: Mon Apr 22 13:34:48 2024 +0200 Add tree versions of lower and upper bounds to vrange. This patch adds vrange::lbound() and vrange::ubound() that return trees. These can be used in generic code that is type agnostic, and avoids special casing for pointers and integers in places where we handle both. It also cleans up a wart in the Value_Range class. gcc/ChangeLog: * tree-ssa-loop-niter.cc (refine_value_range_using_guard): Convert bound to wide_int. * value-range.cc (Value_Range::lower_bound): Remove. (Value_Range::upper_bound): Remove. (unsupported_range::lbound): New. (unsupported_range::ubound): New. (frange::lbound): New. (frange::ubound): New. (irange::lbound): New. (irange::ubound): New. * value-range.h (class vrange): Add lbound() and ubound(). (class irange): Same. (class frange): Same. (class unsupported_range): Same. (class Value_Range): Rename lower_bound and upper_bound to lbound and ubound respectively. Diff: --- gcc/tree-ssa-loop-niter.cc | 4 ++-- gcc/value-range.cc | 56 +- gcc/value-range.h | 13 --- 3 files changed, 48 insertions(+), 25 deletions(-) diff --git a/gcc/tree-ssa-loop-niter.cc b/gcc/tree-ssa-loop-niter.cc index cbc9dbc5a1f..adbc1936982 100644 --- a/gcc/tree-ssa-loop-niter.cc +++ b/gcc/tree-ssa-loop-niter.cc @@ -4067,7 +4067,7 @@ record_nonwrapping_iv (class loop *loop, tree base, tree step, gimple *stmt, Value_Range base_range (TREE_TYPE (orig_base)); if (get_range_query (cfun)->range_of_expr (base_range, orig_base) && !base_range.undefined_p ()) - max = base_range.upper_bound (); + max = wi::to_wide (base_range.ubound ()); extreme = fold_convert (unsigned_type, low); if (TREE_CODE (orig_base) == SSA_NAME && TREE_CODE (high) == INTEGER_CST @@ -4090,7 +4090,7 @@ record_nonwrapping_iv (class loop *loop, tree base, tree step, gimple *stmt, Value_Range base_range (TREE_TYPE (orig_base)); if (get_range_query (cfun)->range_of_expr (base_range, orig_base) && !base_range.undefined_p ()) - min = base_range.lower_bound (); + min = wi::to_wide (base_range.lbound ()); extreme = fold_convert (unsigned_type, high); if (TREE_CODE (orig_base) == SSA_NAME && TREE_CODE (low) == INTEGER_CST diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 632d77305cc..ccac517d4c4 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -37,26 +37,6 @@ irange::accept (const vrange_visitor ) const v.visit (*this); } -// Convenience function only available for integers and pointers. - -wide_int -Value_Range::lower_bound () const -{ - if (is_a (*m_vrange)) -return as_a (*m_vrange).lower_bound (); - gcc_unreachable (); -} - -// Convenience function only available for integers and pointers. - -wide_int -Value_Range::upper_bound () const -{ - if (is_a (*m_vrange)) -return as_a (*m_vrange).upper_bound (); - gcc_unreachable (); -} - void Value_Range::dump (FILE *out) const { @@ -211,6 +191,18 @@ unsupported_range::operator= (const vrange ) return *this; } +tree +unsupported_range::lbound () const +{ + return NULL; +} + +tree +unsupported_range::ubound () const +{ + return NULL; +} + // Assignment operator for generic ranges. Copying incompatible types // is not allowed. @@ -957,6 +949,18 @@ frange::set_nonnegative (tree type) set (type, dconst0, frange_val_max (type)); } +tree +frange::lbound () const +{ + return build_real (type (), lower_bound ()); +} + +tree +frange::ubound () const +{ + return build_real (type (), upper_bound ()); +} + // Here we copy between any two irange's. irange & @@ -2086,6 +2090,18 @@ irange::union_bitmask (const irange ) return true; } +tree +irange::lbound () const +{ + return wide_int_to_tree (type (), lower_bound ()); +} + +tree +irange::ubound () const +{ + return wide_int_to_tree (type (), upper_bound ()); +} + void irange_bitmask::verify_mask () const { diff --git a/gcc/value-range.h b/gcc/value-range.h index b7c83982385..f216f1b82c1 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -96,6 +96,8 @@ public: virtual void set_nonnegative (tree type) = 0; virtual bool fits_p (const vrange ) const = 0; virtual ~vrange () { } + virtual tree lbound () const = 0; + virtual tree ubound () const = 0; bool varying_p () const; bool undefined_p () const; @@ -298,6 +300,8 @@ public: wide_int lower_bound (unsigned = 0) const; wide_int upper_bound (unsigned) const; wide_int upper_bound () const; + virtual tree lbound () const
[gcc r15-30] Move bitmask routines to vrange base class.
https://gcc.gnu.org/g:fd4cf7a092bb2ce21c0d8246c17c0b7f82de440c commit r15-30-gfd4cf7a092bb2ce21c0d8246c17c0b7f82de440c Author: Aldy Hernandez Date: Thu Feb 22 09:18:46 2024 +0100 Move bitmask routines to vrange base class. Any range can theoretically have a bitmask of set bits. This patch moves the bitmask accessors to the base class. This cleans up some users in IPA*, and will provide a cleaner interface when prange is in place. gcc/ChangeLog: * ipa-cp.cc (propagate_bits_across_jump_function): Access bitmask through base class. (ipcp_store_vr_results): Same. * ipa-prop.cc (ipa_compute_jump_functions_for_edge): Same. (ipcp_get_parm_bits): Same. (ipcp_update_vr): Same. * range-op-mixed.h (update_known_bitmask): Change argument to vrange. * range-op.cc (update_known_bitmask): Same. * value-range.cc (vrange::update_bitmask): New. (irange::set_nonzero_bits): Move to vrange class. (irange::get_nonzero_bits): Same. * value-range.h (class vrange): Add update_bitmask, get_bitmask, get_nonzero_bits, and set_nonzero_bits. (class irange): Make bitmask methods virtual overrides. (class Value_Range): Add get_bitmask and update_bitmask. Diff: --- gcc/ipa-cp.cc| 9 +++-- gcc/ipa-prop.cc | 10 -- gcc/range-op-mixed.h | 2 +- gcc/range-op.cc | 4 ++-- gcc/value-range.cc | 16 ++-- gcc/value-range.h| 14 +- 6 files changed, 33 insertions(+), 22 deletions(-) diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc index b7add455bd5..a688dced5c9 100644 --- a/gcc/ipa-cp.cc +++ b/gcc/ipa-cp.cc @@ -2485,8 +2485,7 @@ propagate_bits_across_jump_function (cgraph_edge *cs, int idx, jfunc->m_vr->get_vrange (vr); if (!vr.undefined_p () && !vr.varying_p ()) { - irange = as_a (vr); - irange_bitmask bm = r.get_bitmask (); + irange_bitmask bm = vr.get_bitmask (); widest_int mask = widest_int::from (bm.mask (), TYPE_SIGN (parm_type)); widest_int value @@ -6346,14 +6345,13 @@ ipcp_store_vr_results (void) { Value_Range tmp = plats->m_value_range.m_vr; tree type = ipa_get_type (info, i); - irange = as_a (tmp); irange_bitmask bm (wide_int::from (bits->get_value (), TYPE_PRECISION (type), TYPE_SIGN (type)), wide_int::from (bits->get_mask (), TYPE_PRECISION (type), TYPE_SIGN (type))); - r.update_bitmask (bm); + tmp.update_bitmask (bm); ipa_vr vr (tmp); ts->m_vr->quick_push (vr); } @@ -6368,14 +6366,13 @@ ipcp_store_vr_results (void) tree type = ipa_get_type (info, i); Value_Range tmp; tmp.set_varying (type); - irange = as_a (tmp); irange_bitmask bm (wide_int::from (bits->get_value (), TYPE_PRECISION (type), TYPE_SIGN (type)), wide_int::from (bits->get_mask (), TYPE_PRECISION (type), TYPE_SIGN (type))); - r.update_bitmask (bm); + tmp.update_bitmask (bm); ipa_vr vr (tmp); ts->m_vr->quick_push (vr); } diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc index 374e998aa64..b57f9750431 100644 --- a/gcc/ipa-prop.cc +++ b/gcc/ipa-prop.cc @@ -2381,8 +2381,7 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi, irange_bitmask bm (value, mask); if (!addr_nonzero) vr.set_varying (TREE_TYPE (arg)); - irange = as_a (vr); - r.update_bitmask (bm); + vr.update_bitmask (bm); ipa_set_jfunc_vr (jfunc, vr); } else if (addr_nonzero) @@ -5785,8 +5784,8 @@ ipcp_get_parm_bits (tree parm, tree *value, widest_int *mask) vr[i].get_vrange (tmp); if (tmp.undefined_p () || tmp.varying_p ()) return false; - irange = as_a (tmp); - irange_bitmask bm = r.get_bitmask (); + irange_bitmask bm; + bm = tmp.get_bitmask (); *mask = widest_int::from (bm.mask (), TYPE_SIGN (TREE_TYPE (parm))); *value = wide_int_to_tree (TREE_TYPE (parm), bm.value ()); return true; @@ -5857,8 +5856,7 @@ ipcp_update_vr (struct cgraph_node *node, ipcp_transformation *ts) if (POINTER_TYPE_P (TREE_TYPE (parm))
[gcc r15-28] Make some Value_Range's explicitly integer.
https://gcc.gnu.org/g:a46564e4876c9a863d9897d72963cc4f03689adc commit r15-28-ga46564e4876c9a863d9897d72963cc4f03689adc Author: Aldy Hernandez Date: Mon Apr 22 13:29:39 2024 +0200 Make some Value_Range's explicitly integer. Fix some Value_Range's that we know ahead of time will be only integers. This avoids using the polymorphic Value_Range unnecessarily gcc/ChangeLog: * gimple-ssa-warn-access.cc (check_nul_terminated_array): Make Value_Range an int_range. (memmodel_to_uhwi): Same * tree-ssa-loop-niter.cc (refine_value_range_using_guard): Same. (determine_value_range): Same. (infer_loop_bounds_from_signedness): Same. (scev_var_range_cant_overflow): Same. Diff: --- gcc/gimple-ssa-warn-access.cc | 4 ++-- gcc/tree-ssa-loop-niter.cc| 12 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc index dedaae27b31..450c1caa765 100644 --- a/gcc/gimple-ssa-warn-access.cc +++ b/gcc/gimple-ssa-warn-access.cc @@ -330,7 +330,7 @@ check_nul_terminated_array (GimpleOrTree expr, tree src, tree bound) wide_int bndrng[2]; if (bound) { - Value_Range r (TREE_TYPE (bound)); + int_range<2> r (TREE_TYPE (bound)); get_range_query (cfun)->range_of_expr (r, bound); @@ -2816,7 +2816,7 @@ memmodel_to_uhwi (tree ord, gimple *stmt, unsigned HOST_WIDE_INT *cstval) { /* Use the range query to determine constant values in the absence of constant propagation (such as at -O0). */ - Value_Range rng (TREE_TYPE (ord)); + int_range<2> rng (TREE_TYPE (ord)); if (!get_range_query (cfun)->range_of_expr (rng, ord, stmt) || !rng.singleton_p ()) return false; diff --git a/gcc/tree-ssa-loop-niter.cc b/gcc/tree-ssa-loop-niter.cc index c6d010f6d89..cbc9dbc5a1f 100644 --- a/gcc/tree-ssa-loop-niter.cc +++ b/gcc/tree-ssa-loop-niter.cc @@ -214,7 +214,7 @@ refine_value_range_using_guard (tree type, tree var, get_type_static_bounds (type, mint, maxt); mpz_init (minc1); mpz_init (maxc1); - Value_Range r (TREE_TYPE (varc1)); + int_range<2> r (TREE_TYPE (varc1)); /* Setup range information for varc1. */ if (integer_zerop (varc1)) { @@ -368,7 +368,7 @@ determine_value_range (class loop *loop, tree type, tree var, mpz_t off, gphi_iterator gsi; /* Either for VAR itself... */ - Value_Range var_range (TREE_TYPE (var)); + int_range<2> var_range (TREE_TYPE (var)); get_range_query (cfun)->range_of_expr (var_range, var); if (var_range.varying_p () || var_range.undefined_p ()) rtype = VR_VARYING; @@ -382,7 +382,7 @@ determine_value_range (class loop *loop, tree type, tree var, mpz_t off, /* Or for PHI results in loop->header where VAR is used as PHI argument from the loop preheader edge. */ - Value_Range phi_range (TREE_TYPE (var)); + int_range<2> phi_range (TREE_TYPE (var)); for (gsi = gsi_start_phis (loop->header); !gsi_end_p (gsi); gsi_next ()) { gphi *phi = gsi.phi (); @@ -408,7 +408,7 @@ determine_value_range (class loop *loop, tree type, tree var, mpz_t off, involved. */ if (wi::gt_p (minv, maxv, sgn)) { - Value_Range vr (TREE_TYPE (var)); + int_range<2> vr (TREE_TYPE (var)); get_range_query (cfun)->range_of_expr (vr, var); if (vr.varying_p () || vr.undefined_p ()) rtype = VR_VARYING; @@ -4367,7 +4367,7 @@ infer_loop_bounds_from_signedness (class loop *loop, gimple *stmt) low = lower_bound_in_type (type, type); high = upper_bound_in_type (type, type); - Value_Range r (TREE_TYPE (def)); + int_range<2> r (TREE_TYPE (def)); get_range_query (cfun)->range_of_expr (r, def); if (!r.varying_p () && !r.undefined_p ()) { @@ -5426,7 +5426,7 @@ scev_var_range_cant_overflow (tree var, tree step, class loop *loop) if (!def_bb || !dominated_by_p (CDI_DOMINATORS, loop->latch, def_bb)) return false; - Value_Range r (TREE_TYPE (var)); + int_range<2> r (TREE_TYPE (var)); get_range_query (cfun)->range_of_expr (r, var); if (r.varying_p () || r.undefined_p ()) return false;
[gcc r15-27] Add a virtual vrange destructor.
https://gcc.gnu.org/g:a78dfb0fc83606e9b83b76575deb7e43300254fa commit r15-27-ga78dfb0fc83606e9b83b76575deb7e43300254fa Author: Aldy Hernandez Date: Wed Feb 21 09:33:19 2024 +0100 Add a virtual vrange destructor. Richi mentioned in PR113476 that it would be cleaner to move the destructor from int_range to the base class. Although this isn't strictly necessary, as there are no users, it is good to future proof things, and the overall impact is miniscule. gcc/ChangeLog: * value-range.h (vrange::~vrange): New. (int_range::~int_range): Make final override. Diff: --- gcc/value-range.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gcc/value-range.h b/gcc/value-range.h index e7f61950a24..b7c83982385 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -95,6 +95,7 @@ public: virtual void set_zero (tree type) = 0; virtual void set_nonnegative (tree type) = 0; virtual bool fits_p (const vrange ) const = 0; + virtual ~vrange () { } bool varying_p () const; bool undefined_p () const; @@ -382,7 +383,7 @@ public: int_range (tree type); int_range (const int_range &); int_range (const irange &); - virtual ~int_range (); + ~int_range () final override; int_range& operator= (const int_range &); protected: int_range (tree, tree, value_range_kind = VR_RANGE);
[gcc r15-26] Make vrange an abstract class.
https://gcc.gnu.org/g:21713edf52974d14238cdda865fc662eca58302a commit r15-26-g21713edf52974d14238cdda865fc662eca58302a Author: Aldy Hernandez Date: Wed Feb 21 20:37:14 2024 +0100 Make vrange an abstract class. Explicitly make vrange an abstract class. This involves fleshing out the unsupported_range overrides which we were inheriting by default from vrange. gcc/ChangeLog: * value-range.cc (unsupported_range::accept): Move down. (vrange::contains_p): Rename to... (unsupported_range::contains_p): ...this. (vrange::singleton_p): Rename to... (unsupported_range::singleton_p): ...this. (vrange::set): Rename to... (unsupported_range::set): ...this. (vrange::type): Rename to... (unsupported_range::type): ...this. (vrange::supports_type_p): Rename to... (unsupported_range::supports_type_p): ...this. (vrange::set_undefined): Rename to... (unsupported_range::set_undefined): ...this. (vrange::set_varying): Rename to... (unsupported_range::set_varying): ...this. (vrange::union_): Rename to... (unsupported_range::union_): ...this. (vrange::intersect): Rename to... (unsupported_range::intersect): ...this. (vrange::zero_p): Rename to... (unsupported_range::zero_p): ...this. (vrange::nonzero_p): Rename to... (unsupported_range::nonzero_p): ...this. (vrange::set_nonzero): Rename to... (unsupported_range::set_nonzero): ...this. (vrange::set_zero): Rename to... (unsupported_range::set_zero): ...this. (vrange::set_nonnegative): Rename to... (unsupported_range::set_nonnegative): ...this. (vrange::fits_p): Rename to... (unsupported_range::fits_p): ...this. (unsupported_range::operator=): New. (frange::fits_p): New. * value-range.h (class vrange): Make an abstract class. (class unsupported_range): Declare override methods. Diff: --- gcc/value-range.cc | 62 +++--- gcc/value-range.h | 53 -- 2 files changed, 73 insertions(+), 42 deletions(-) diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 70375f7abf9..632d77305cc 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -37,12 +37,6 @@ irange::accept (const vrange_visitor ) const v.visit (*this); } -void -unsupported_range::accept (const vrange_visitor ) const -{ - v.visit (*this); -} - // Convenience function only available for integers and pointers. wide_int @@ -86,52 +80,58 @@ debug (const irange_bitmask ) fprintf (stderr, "\n"); } -// Default vrange definitions. +// Definitions for unsupported_range. + +void +unsupported_range::accept (const vrange_visitor ) const +{ + v.visit (*this); +} bool -vrange::contains_p (tree) const +unsupported_range::contains_p (tree) const { return varying_p (); } bool -vrange::singleton_p (tree *) const +unsupported_range::singleton_p (tree *) const { return false; } void -vrange::set (tree min, tree, value_range_kind) +unsupported_range::set (tree min, tree, value_range_kind) { set_varying (TREE_TYPE (min)); } tree -vrange::type () const +unsupported_range::type () const { return void_type_node; } bool -vrange::supports_type_p (const_tree) const +unsupported_range::supports_type_p (const_tree) const { return false; } void -vrange::set_undefined () +unsupported_range::set_undefined () { m_kind = VR_UNDEFINED; } void -vrange::set_varying (tree) +unsupported_range::set_varying (tree) { m_kind = VR_VARYING; } bool -vrange::union_ (const vrange ) +unsupported_range::union_ (const vrange ) { if (r.undefined_p () || varying_p ()) return false; @@ -145,7 +145,7 @@ vrange::union_ (const vrange ) } bool -vrange::intersect (const vrange ) +unsupported_range::intersect (const vrange ) { if (undefined_p () || r.varying_p ()) return false; @@ -164,41 +164,53 @@ vrange::intersect (const vrange ) } bool -vrange::zero_p () const +unsupported_range::zero_p () const { return false; } bool -vrange::nonzero_p () const +unsupported_range::nonzero_p () const { return false; } void -vrange::set_nonzero (tree type) +unsupported_range::set_nonzero (tree type) { set_varying (type); } void -vrange::set_zero (tree type) +unsupported_range::set_zero (tree type) { set_varying (type); } void -vrange::set_nonnegative (tree type) +unsupported_range::set_nonnegative (tree type) { set_varying (type); } bool -vrange::fits_p (const vrange &) const +unsupported_range::fits_p (const vrange &) const { return true; } +unsupported_range & +unsupported_range::operator= (const