[COMMITTED] [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. --- gcc/testsuite/gcc.dg/tree-ssa/pr115191.c | 10 ++ gcc/tree-ssa-phiopt.cc | 5 ++--- 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr115191.c 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); -- 2.45.0
[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);
[COMMITTED] [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. --- gcc/value-range.cc | 21 + 1 file changed, 21 insertions(+) diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 334ffb70fbc..b38d6159a85 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); -- 2.45.0
[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);
[COMMITTED] [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. --- gcc/ipa-cp.cc| 4 +++ gcc/testsuite/gcc.dg/tree-ssa/pr115128.c | 31 2 files changed, 35 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr115128.c diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc index 09cab761822..408166b8044 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 000..14bd4dbd6e5 --- /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)); } -- 2.45.0
[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)); }
Re: [COMMITTED] Revert "Revert: "Enable prange support.""
Wait, what's the preferred way of reverting a patch? I followed what I saw in: commit 04ee1f788ceaa4c7f777ff3b9441ae076191439c Author: Jeff Law Date: Mon May 13 21:42:38 2024 -0600 Revert "[PATCH v2 1/3] RISC-V: movmem for RISCV with V extension" This reverts commit df15eb15b5f820321c81efc75f0af13ff8c0dd5b. and here: commit 0c6dd4b0973738ce43e76b468a002ab5eb58aaf4 Author: YunQiang Su Date: Mon May 13 14:15:38 2024 +0800 Revert "MIPS: Support constraint 'w' for MSA instruction" This reverts commit 9ba01240864ac446052d97692e2199539b7c76d8. and here: commit f6ce85502eb2e4e7bbd9b3c6c1c065a004f8f531 Author: Hans-Peter Nilsson Date: Wed May 8 04:11:20 2024 +0200 Revert "Revert "testsuite/gcc.target/cris/pr93372-2.c: Handle xpass from combine improvement"" This reverts commit 39f81924d88e3cc197fc3df74204c9b5e01e12f7. etc etc. Next time, would you like me to add manual changelog entries? My apologies, I thought what I did was the blessed way of doing things. Aldy On Thu, May 16, 2024 at 12:08 PM Jakub Jelinek wrote: > > On Thu, May 16, 2024 at 12:01:01PM +0200, Aldy Hernandez wrote: > > This reverts commit d7bb8eaade3cd3aa70715c8567b4d7b08098e699 and enables > > prange > > support again. > > Please don't do this. > This breaks ChangeLog generation, will need to handle it tomorrow by hand > again. > Both the ammendments to the git (cherry-pick -x or revert) added message > lines > This reverts commit COMMITHASH. > and > (cherry picked from commit COMMITHASH) > and revert of revert. > > Jakub >
[COMMITTED] Revert "Revert: "Enable prange support.""
This reverts commit d7bb8eaade3cd3aa70715c8567b4d7b08098e699 and enables prange support again. --- 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 72ac2552311..bdd2832873a 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 9c4ad1ee7b9..a9c8c4d03e6 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 7cbe15d05e5..c7c599bfc93 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 c8e8b9b60ac..d5e1aa14275 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 7321342b00d..aec3f39ec0e 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 96c6ac6b6a5..f1a12f76144 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 2c10d19e7f3..0cd5b6d6ef4 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 vr; + prange vr; if (m_ptr_qry.rvals->range_of_expr (vr, realloc_lhs, use_stmt)) { if (vr.zero_p ()) diff --git a/gcc/ipa-cp.h b/gcc/ipa-cp.h index abeaaa4053e..e62a09f38af 100644 --- a/gcc/ipa-cp.h +++
[COMMITTED] 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. --- 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 0572bf6c8c7..e6ea9592574 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; -- 2.45.0
[COMMITTED] 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. --- 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 55dfbb23ce2..7321342b00d 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 5781f50c854..09cab761822 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) + /* 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 (operand_type, + src_lats->m_value_range.m_vr.type (), +
[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 h
[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;
Re: [PATCH] Adjust range type of calls into fold_range for IPA passes [PR114985]
Any thoughts on this? If no one objects, I'll re-enable prange tomorrow. Aldy On Sat, May 11, 2024 at 11:43 AM Aldy Hernandez wrote: > > I have pushed a few cleanups to make it easier to move forward without > disturbing passes which are affected by IPA's mixing up the range > types. As I explained in my previous patch, this restores the default > behavior of silently returning VARYING when a range operator is > unsupported in either a particular operator, or in the dispatch code. > > I would like to re-enable prange support, as IPA was already broken > before the prange work, and the debugging trap can be turned off to > analyze (#define TRAP_ON_UNHANDLED_POINTER_OPERATORS 1). > > I have re-tested the effects of re-enabling prange in current trunk: > > 1. x86-64/32 bootstraps with no regressions with and without the trap. > 2. ppc64le bootstraps with no regressions, but fails with the trap. > 3. aarch64 bootstraps, but fails with the trap (no space on compile > farm to run tests) > 4. sparc: bootstrap already broken, so I can't test. > > So, for the above 4 architectures things work as before, and we have a > PR to track the IPA problem which doesn't seem to affect neither > bootstrap nor tests. > > Does this sound reasonable? > > Aldy > > On Fri, May 10, 2024 at 12:26 PM Richard Biener > wrote: > > > > On Fri, May 10, 2024 at 11:24 AM Aldy Hernandez wrote: > > > > > > There are various calls into fold_range() that have the wrong type > > > associated with the range temporary used to hold the result. This > > > used to work, because we could store either integers or pointers in a > > > Value_Range, but is no longer the case with prange's. Now you must > > > explicitly state which type of range the temporary will hold before > > > storing into it. You can change this at a later time with set_type(), > > > but you must always have a type before using the temporary, and it > > > must match what fold_range() returns. > > > > > > This patch adjusts the IPA code to restore the previous functionality, > > > so I can re-enable the prange code, but I do question whether the > > > previous code was correct. I have added appropriate comments to help > > > the maintainers, but someone with more knowledge should revamp this > > > going forward. > > > > > > The basic problem is that pointer comparisons return a boolean, but > > > the IPA code is initializing the resulting range as a pointer. This > > > wasn't a problem, because fold_range() would previously happily force > > > the range into an integer one, and everything would work. But now we > > > must initialize the range to an integer before calling into > > > fold_range. The thing is, that the failing case sets the result back > > > into a pointer, which is just weird but existing behavior. I have > > > documented this in the code. > > > > > > if (!handler > > > || !op_res.supports_type_p (vr_type) > > > || !handler.fold_range (op_res, vr_type, srcvr, op_vr)) > > > /* For comparison operators, the type here may be > > >different than the range type used in fold_range above. > > >For example, vr_type may be a pointer, whereas the type > > >returned by fold_range will always be a boolean. > > > > > >This shouldn't cause any problems, as the set_varying > > >below will happily change the type of the range in > > >op_res, and then the cast operation in > > >ipa_vr_operation_and_type_effects will ultimately leave > > >things in the desired type, but it is confusing. > > > > > >Perhaps the original intent was to use the type of > > >op_res here? */ > > > op_res.set_varying (vr_type); > > > > > > BTW, this is not to say that the original gimple IR was wrong, but that > > > IPA is setting the range type of the result of fold_range() to the type of > > > the operands, which does not necessarily match in the case of a > > > comparison. > > > > > > I am just restoring previous behavior here, but I do question whether it > > > was right to begin with. > > > > > > Testing currently in progress on x86-64 and ppc64le with prange enabled. > > > > > > OK pending tests? > > > > I think this "intermediate" patch is unnecessary and instead
[COMMITTED] [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. --- 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 65cca65103a..2f47f3354ed 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 -- 2.45.0
[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
Re: [PATCHv2] Value range: Add range op for __builtin_isfinite
On Thu, May 9, 2024 at 10:05 AM Mikael Morin wrote: > > Hello, > > Le 07/05/2024 à 04:37, HAO CHEN GUI a écrit : > > Hi, > >The former patch adds isfinite optab for __builtin_isfinite. > > https://gcc.gnu.org/pipermail/gcc-patches/2024-April/649339.html > > > >Thus the builtin might not be folded at front end. The range op for > > isfinite is needed for value range analysis. This patch adds them. > > > >Compared to last version, this version fixes a typo. > > > >Bootstrapped and tested on x86 and powerpc64-linux BE and LE with no > > regressions. Is it OK for the trunk? > > > > Thanks > > Gui Haochen > > > > ChangeLog > > Value Range: Add range op for builtin isfinite > > > > The former patch adds optab for builtin isfinite. Thus builtin isfinite > > might > > not be folded at front end. So the range op for isfinite is needed for > > value > > range analysis. This patch adds range op for builtin isfinite. > > > > gcc/ > > * gimple-range-op.cc (class cfn_isfinite): New. > > (op_cfn_finite): New variables. > > (gimple_range_op_handler::maybe_builtin_call): Handle > > CFN_BUILT_IN_ISFINITE. > > > > gcc/testsuite/ > > * gcc/testsuite/gcc.dg/tree-ssa/range-isfinite.c: New test. > > > > patch.diff > > diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc > > index 9de130b4022..99c511728d3 100644 > > --- a/gcc/gimple-range-op.cc > > +++ b/gcc/gimple-range-op.cc > > @@ -1192,6 +1192,56 @@ public: > > } > > } op_cfn_isinf; > > > > +//Implement range operator for CFN_BUILT_IN_ISFINITE > > +class cfn_isfinite : public range_operator > > +{ > > +public: > > + using range_operator::fold_range; > > + using range_operator::op1_range; > > + virtual bool fold_range (irange , tree type, const frange , > > +const irange &, relation_trio) const override > > + { > > +if (op1.undefined_p ()) > > + return false; > > + > > +if (op1.known_isfinite ()) > > + { > > + r.set_nonzero (type); > > + return true; > > + } > > + > > +if (op1.known_isnan () > > + || op1.known_isinf ()) > > + { > > + r.set_zero (type); > > + return true; > > + } > > + > > +return false; > I think the canonical API behaviour sets R to varying and returns true > instead of just returning false if nothing is known about the range. Correct. If we know it's varying, we just set varying and return true. Returning false is usually reserved for "I have no idea". However, every caller of fold_range() should know to ignore a return of false, so you should be safe. > > I'm not sure whether it makes any difference; Aldy can probably tell. > But if the type is bool, varying is [0,1] which is better than unknown > range. Also, I see you're setting zero/nonzero. Is the return type known to be boolean, because if so, we usually prefer to one of: r = range_true () r = range_false () r = range_true_and_false (); It doesn't matter either way, but it's probably best to use these as they force boolean_type_node automatically. I don't have a problem with this patch, but I would prefer the floating point savvy people to review this, as there are no members of the ranger team that are floating point experts :). Also, I see you mention in your original post that this patch was needed as a follow-up to this one: https://gcc.gnu.org/pipermail/gcc-patches/2024-April/649339.html I don't see the above patch in the source tree currently: Thanks. Aldy > > > + } > > + virtual bool op1_range (frange , tree type, const irange , > > + const frange &, relation_trio) const override > > + { > > +if (lhs.zero_p ()) > > + { > > + // The range is [-INF,-INF][+INF,+INF] NAN, but it can't be > > represented. > > + // Set range to varying > > + r.set_varying (type); > > + return true; > > + } > > + > > +if (!range_includes_zero_p ()) > > + { > > + nan_state nan (false); > > + r.set (type, real_min_representable (type), > > +real_max_representable (type), nan); > > + return true; > > + } > > + > > +return false; > Same here. > > > + } > > +} op_cfn_isfinite; > > + > > // Implement range operator for CFN_BUILT_IN_ > > class cfn_parity : public range_operator > > { >
Re: [PATCH] Adjust range type of calls into fold_range for IPA passes [PR114985]
I have pushed a few cleanups to make it easier to move forward without disturbing passes which are affected by IPA's mixing up the range types. As I explained in my previous patch, this restores the default behavior of silently returning VARYING when a range operator is unsupported in either a particular operator, or in the dispatch code. I would like to re-enable prange support, as IPA was already broken before the prange work, and the debugging trap can be turned off to analyze (#define TRAP_ON_UNHANDLED_POINTER_OPERATORS 1). I have re-tested the effects of re-enabling prange in current trunk: 1. x86-64/32 bootstraps with no regressions with and without the trap. 2. ppc64le bootstraps with no regressions, but fails with the trap. 3. aarch64 bootstraps, but fails with the trap (no space on compile farm to run tests) 4. sparc: bootstrap already broken, so I can't test. So, for the above 4 architectures things work as before, and we have a PR to track the IPA problem which doesn't seem to affect neither bootstrap nor tests. Does this sound reasonable? Aldy On Fri, May 10, 2024 at 12:26 PM Richard Biener wrote: > > On Fri, May 10, 2024 at 11:24 AM Aldy Hernandez wrote: > > > > There are various calls into fold_range() that have the wrong type > > associated with the range temporary used to hold the result. This > > used to work, because we could store either integers or pointers in a > > Value_Range, but is no longer the case with prange's. Now you must > > explicitly state which type of range the temporary will hold before > > storing into it. You can change this at a later time with set_type(), > > but you must always have a type before using the temporary, and it > > must match what fold_range() returns. > > > > This patch adjusts the IPA code to restore the previous functionality, > > so I can re-enable the prange code, but I do question whether the > > previous code was correct. I have added appropriate comments to help > > the maintainers, but someone with more knowledge should revamp this > > going forward. > > > > The basic problem is that pointer comparisons return a boolean, but > > the IPA code is initializing the resulting range as a pointer. This > > wasn't a problem, because fold_range() would previously happily force > > the range into an integer one, and everything would work. But now we > > must initialize the range to an integer before calling into > > fold_range. The thing is, that the failing case sets the result back > > into a pointer, which is just weird but existing behavior. I have > > documented this in the code. > > > > if (!handler > > || !op_res.supports_type_p (vr_type) > > || !handler.fold_range (op_res, vr_type, srcvr, op_vr)) > > /* For comparison operators, the type here may be > >different than the range type used in fold_range above. > >For example, vr_type may be a pointer, whereas the type > >returned by fold_range will always be a boolean. > > > >This shouldn't cause any problems, as the set_varying > >below will happily change the type of the range in > >op_res, and then the cast operation in > >ipa_vr_operation_and_type_effects will ultimately leave > >things in the desired type, but it is confusing. > > > >Perhaps the original intent was to use the type of > >op_res here? */ > > op_res.set_varying (vr_type); > > > > BTW, this is not to say that the original gimple IR was wrong, but that > > IPA is setting the range type of the result of fold_range() to the type of > > the operands, which does not necessarily match in the case of a > > comparison. > > > > I am just restoring previous behavior here, but I do question whether it > > was right to begin with. > > > > Testing currently in progress on x86-64 and ppc64le with prange enabled. > > > > OK pending tests? > > I think this "intermediate" patch is unnecessary and instead the code should > be fixed correctly, avoiding missed-optimization regressions. > > Richard. > > > gcc/ChangeLog: > > > > PR tree-optimization/114985 > > * ipa-cp.cc (ipa_value_range_from_jfunc): Adjust type of op_res. > > (propagate_vr_across_jump_function): Same. > > * ipa-fnsummary.cc (evaluate_conditions_for_known_args): Adjust > > type for res. > > * ipa-prop.h (ipa_type_for_fold_range): New. > > --- > > gcc/ipa-cp.cc| 18
Re: [COMMITTED] [prange] Do not trap by default on range dispatch mismatches.
For the record, we have always returned false (VARYING) for unsupported range operators. This patch just restores the behavior we've always had, while adding a knob for further analysis (for example. IPA which is getting its range types mixed up). Aldy On Sat, May 11, 2024 at 11:28 AM Aldy Hernandez wrote: > > 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. > --- > 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 a134af68141..6a410ff656c 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); > -- > 2.45.0 >
[COMMITTED] [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. --- 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 466edc6bf74..65cca65103a 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 -- 2.45.0
[COMMITTED] [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. --- 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 a134af68141..6a410ff656c 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); -- 2.45.0
[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);
[COMMITTED] [prange] Fix thinko in prange::update_bitmask() [PR115026]
gcc/ChangeLog: PR tree-optimization/115026 * value-range.cc (prange::update_bitmask): Use operand bitmask. --- 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 3e1ecf69517..5bcb2c3f650 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; } -- 2.45.0
[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; }
Re: [PATCH] Adjust range type of calls into fold_range for IPA passes [PR114985]
I would much prefer the IPA experts to fix the pass, but I'm afraid I don't understand the code enough to do so. Could someone lend a hand here? Aldy On Fri, May 10, 2024 at 12:26 PM Richard Biener wrote: > > On Fri, May 10, 2024 at 11:24 AM Aldy Hernandez wrote: > > > > There are various calls into fold_range() that have the wrong type > > associated with the range temporary used to hold the result. This > > used to work, because we could store either integers or pointers in a > > Value_Range, but is no longer the case with prange's. Now you must > > explicitly state which type of range the temporary will hold before > > storing into it. You can change this at a later time with set_type(), > > but you must always have a type before using the temporary, and it > > must match what fold_range() returns. > > > > This patch adjusts the IPA code to restore the previous functionality, > > so I can re-enable the prange code, but I do question whether the > > previous code was correct. I have added appropriate comments to help > > the maintainers, but someone with more knowledge should revamp this > > going forward. > > > > The basic problem is that pointer comparisons return a boolean, but > > the IPA code is initializing the resulting range as a pointer. This > > wasn't a problem, because fold_range() would previously happily force > > the range into an integer one, and everything would work. But now we > > must initialize the range to an integer before calling into > > fold_range. The thing is, that the failing case sets the result back > > into a pointer, which is just weird but existing behavior. I have > > documented this in the code. > > > > if (!handler > > || !op_res.supports_type_p (vr_type) > > || !handler.fold_range (op_res, vr_type, srcvr, op_vr)) > > /* For comparison operators, the type here may be > >different than the range type used in fold_range above. > >For example, vr_type may be a pointer, whereas the type > >returned by fold_range will always be a boolean. > > > >This shouldn't cause any problems, as the set_varying > >below will happily change the type of the range in > >op_res, and then the cast operation in > >ipa_vr_operation_and_type_effects will ultimately leave > >things in the desired type, but it is confusing. > > > >Perhaps the original intent was to use the type of > >op_res here? */ > > op_res.set_varying (vr_type); > > > > BTW, this is not to say that the original gimple IR was wrong, but that > > IPA is setting the range type of the result of fold_range() to the type of > > the operands, which does not necessarily match in the case of a > > comparison. > > > > I am just restoring previous behavior here, but I do question whether it > > was right to begin with. > > > > Testing currently in progress on x86-64 and ppc64le with prange enabled. > > > > OK pending tests? > > I think this "intermediate" patch is unnecessary and instead the code should > be fixed correctly, avoiding missed-optimization regressions. > > Richard. > > > gcc/ChangeLog: > > > > PR tree-optimization/114985 > > * ipa-cp.cc (ipa_value_range_from_jfunc): Adjust type of op_res. > > (propagate_vr_across_jump_function): Same. > > * ipa-fnsummary.cc (evaluate_conditions_for_known_args): Adjust > > type for res. > > * ipa-prop.h (ipa_type_for_fold_range): New. > > --- > > gcc/ipa-cp.cc| 18 -- > > gcc/ipa-fnsummary.cc | 6 +- > > gcc/ipa-prop.h | 13 + > > 3 files changed, 34 insertions(+), 3 deletions(-) > > > > diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc > > index 5781f50c854..3c395632364 100644 > > --- a/gcc/ipa-cp.cc > > +++ b/gcc/ipa-cp.cc > > @@ -1730,7 +1730,7 @@ ipa_value_range_from_jfunc (vrange , > > } > >else > > { > > - Value_Range op_res (vr_type); > > + Value_Range op_res (ipa_type_for_fold_range (operation, vr_type)); > > Value_Range res (vr_type); > > tree op = ipa_get_jf_pass_through_operand (jfunc); > > Value_Range op_vr (TREE_TYPE (op)); > > @@ -1741,6 +1741,19 @@ ipa_value_range_from_jfunc (vrange , > > if (!handler > > || !op_res.supports_type_p (vr_
[PATCH] Adjust range type of calls into fold_range for IPA passes [PR114985]
There are various calls into fold_range() that have the wrong type associated with the range temporary used to hold the result. This used to work, because we could store either integers or pointers in a Value_Range, but is no longer the case with prange's. Now you must explicitly state which type of range the temporary will hold before storing into it. You can change this at a later time with set_type(), but you must always have a type before using the temporary, and it must match what fold_range() returns. This patch adjusts the IPA code to restore the previous functionality, so I can re-enable the prange code, but I do question whether the previous code was correct. I have added appropriate comments to help the maintainers, but someone with more knowledge should revamp this going forward. The basic problem is that pointer comparisons return a boolean, but the IPA code is initializing the resulting range as a pointer. This wasn't a problem, because fold_range() would previously happily force the range into an integer one, and everything would work. But now we must initialize the range to an integer before calling into fold_range. The thing is, that the failing case sets the result back into a pointer, which is just weird but existing behavior. I have documented this in the code. if (!handler || !op_res.supports_type_p (vr_type) || !handler.fold_range (op_res, vr_type, srcvr, op_vr)) /* For comparison operators, the type here may be different than the range type used in fold_range above. For example, vr_type may be a pointer, whereas the type returned by fold_range will always be a boolean. This shouldn't cause any problems, as the set_varying below will happily change the type of the range in op_res, and then the cast operation in ipa_vr_operation_and_type_effects will ultimately leave things in the desired type, but it is confusing. Perhaps the original intent was to use the type of op_res here? */ op_res.set_varying (vr_type); BTW, this is not to say that the original gimple IR was wrong, but that IPA is setting the range type of the result of fold_range() to the type of the operands, which does not necessarily match in the case of a comparison. I am just restoring previous behavior here, but I do question whether it was right to begin with. Testing currently in progress on x86-64 and ppc64le with prange enabled. OK pending tests? gcc/ChangeLog: PR tree-optimization/114985 * ipa-cp.cc (ipa_value_range_from_jfunc): Adjust type of op_res. (propagate_vr_across_jump_function): Same. * ipa-fnsummary.cc (evaluate_conditions_for_known_args): Adjust type for res. * ipa-prop.h (ipa_type_for_fold_range): New. --- gcc/ipa-cp.cc| 18 -- gcc/ipa-fnsummary.cc | 6 +- gcc/ipa-prop.h | 13 + 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc index 5781f50c854..3c395632364 100644 --- a/gcc/ipa-cp.cc +++ b/gcc/ipa-cp.cc @@ -1730,7 +1730,7 @@ ipa_value_range_from_jfunc (vrange , } else { - Value_Range op_res (vr_type); + Value_Range op_res (ipa_type_for_fold_range (operation, vr_type)); Value_Range res (vr_type); tree op = ipa_get_jf_pass_through_operand (jfunc); Value_Range op_vr (TREE_TYPE (op)); @@ -1741,6 +1741,19 @@ ipa_value_range_from_jfunc (vrange , if (!handler || !op_res.supports_type_p (vr_type) || !handler.fold_range (op_res, vr_type, srcvr, op_vr)) + /* For comparison operators, the type here may be + different than the range type used in fold_range above. + For example, vr_type may be a pointer, whereas the type + returned by fold_range will always be a boolean. + + This shouldn't cause any problems, as the set_varying + below will happily change the type of the range in + op_res, and then the cast operation in + ipa_vr_operation_and_type_effects will ultimately leave + things in the desired type, but it is confusing. + + Perhaps the original intent was to use the type of + op_res here? */ op_res.set_varying (vr_type); if (ipa_vr_operation_and_type_effects (res, @@ -2540,7 +2553,7 @@ 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 (param_type); + Value_Range op_res (ipa_type_for_fold_range (operation, param_type)); range_op_handler handler (operation);
[COMMITTED] [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. --- 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 bbae0da4772..8e8d61d5935 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 (); } -- 2.45.0
[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 (); }
[COMMITTED] Revert: "Enable prange support." [PR114985]
This reverts commit 36e877996936abd8bd08f8b1d983c8d1023a5842 until the IPA pass is fixed with regards to POINTER = POINTER POINTER. --- 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 bdd2832873a..72ac2552311 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 a9c8c4d03e6..9c4ad1ee7b9 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 c7c599bfc93..7cbe15d05e5 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 d5e1aa14275..c8e8b9b60ac 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 ddd13ec5594..55dfbb23ce2 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 f1a12f76144..96c6ac6b6a5 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 0cd5b6d6ef4..2c10d19e7f3 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. */ - prange vr; + value_range vr; if (m_ptr_qry.rvals->range_of_expr (vr, realloc_lhs, use_stmt)) { if (vr.zero_p ()) diff --git a/gcc/ipa-cp.h b/gcc/ipa-cp.h index
[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 kno
Re: [COMMITTED] Enable prange support.
This is: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114985 I have proposed a patch but need confirmation from the IPA folks. Aldy On Thu, May 9, 2024 at 10:08 AM Andreas Schwab wrote: > > Breaks bootstrap on aarch64. > > $ /opt/gcc/gcc-20240509/Build/./prev-gcc/xg++ > -B/opt/gcc/gcc-20240509/Build/./prev-gcc/ -B/usr/aarch64-suse-linux/bin/ > -nostdinc++ > -B/opt/gcc/gcc-20240509/Build/prev-aarch64-suse-linux/libstdc++-v3/src/.libs > -B/opt/gcc/gcc-20240509/Build/prev-aarch64-suse-linux/libstdc++-v3/libsupc++/.libs > > -I/opt/gcc/gcc-20240509/Build/prev-aarch64-suse-linux/libstdc++-v3/include/aarch64-suse-linux > -I/opt/gcc/gcc-20240509/Build/prev-aarch64-suse-linux/libstdc++-v3/include > -I/opt/gcc/gcc-20240509/libstdc++-v3/libsupc++ > -L/opt/gcc/gcc-20240509/Build/prev-aarch64-suse-linux/libstdc++-v3/src/.libs > -L/opt/gcc/gcc-20240509/Build/prev-aarch64-suse-linux/libstdc++-v3/libsupc++/.libs > -fno-PIE -c -g -O2 -fno-checking -gtoggle -DIN_GCC-fno-exceptions > -fno-rtti -fasynchronous-unwind-tables -W -Wall -Wno-narrowing > -Wwrite-strings -Wcast-qual -Wmissing-format-attribute > -Wconditionally-supported -Woverloaded-virtual -pedantic -Wno-long-long > -Wno-variadic-macros -Wno-overlength-strings -Werror -fno-common > -DHAVE_CONFIG_H -fno-PIE -I. -I. -I../../gcc -I../../gcc/. > -I../../gcc/../include -I../../gcc/../libcpp/include -I../../gcc/../libcody > -I../../gcc/../libdecnumber -I../../gcc/../libdecnumber/bid -I../libdecnumber > -I../../gcc/../libbacktrace -o tree-vect-stmts.o -MT tree-vect-stmts.o -MMD > -MP -MF ./.deps/tree-vect-stmts.TPo ../../gcc/tree-vect-stmts.cc > DISCRIMINATOR FAIL. Dispatch > RO_PPP < > during IPA pass: inline > ../../gcc/tree-vect-stmts.cc:14792:1: internal compiler error: in > discriminator_fail, at range-op.cc:204 > 14792 | } > | ^ > 0x1145513 range_op_handler::discriminator_fail(vrange const&, vrange const&, > vrange const&) const > ../../gcc/range-op.cc:204 > 0x114592b range_op_handler::fold_range(vrange&, tree_node*, vrange const&, > vrange const&, relation_trio) const > ../../gcc/range-op.cc:228 > 0x1fe978b ipa_value_range_from_jfunc(vrange&, ipa_node_params*, cgraph_edge*, > ipa_jump_func*, tree_node*) > ../../gcc/ipa-cp.cc:1743 > 0xf5e0d7 evaluate_properties_for_edge(cgraph_edge*, bool, unsigned int*, > unsigned int*, ipa_auto_call_arg_values*, bool) > ../../gcc/ipa-fnsummary.cc:680 > 0xf6fedf do_estimate_edge_size(cgraph_edge*) > ../../gcc/ipa-inline-analysis.cc:337 > 0xf72acf estimate_edge_size(cgraph_edge*) > ../../gcc/ipa-inline.h:79 > 0xf72acf estimate_edge_growth(cgraph_edge*) > ../../gcc/ipa-inline.h:100 > 0xf713cf do_estimate_growth_1 > ../../gcc/ipa-inline-analysis.cc:436 > 0xf714ff cgraph_node::call_for_symbol_and_aliases(bool (*)(cgraph_node*, > void*), void*, bool) > ../../gcc/cgraph.h:3429 > 0xf714ff estimate_growth(cgraph_node*) > ../../gcc/ipa-inline-analysis.cc:474 > 0x200d153 inline_small_functions > ../../gcc/ipa-inline.cc:2081 > 0x200d153 ipa_inline > ../../gcc/ipa-inline.cc:2850 > 0x200d153 execute > ../../gcc/ipa-inline.cc:3248 > > -- > Andreas Schwab, sch...@linux-m68k.org > GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510 2552 DF73 E780 A9DA AEC1 > "And now for something completely different." >
Re: [PATCH] [ranger] Force buffer alignment in Value_Range [PR114912]
Pushed to trunk to unblock sparc. On Fri, May 3, 2024 at 4:24 PM Aldy Hernandez wrote: > > Ahh, that is indeed cleaner, and there's no longer a need to assert > the sizeof of individual ranges. > > It looks like a default constructor is needed for the buffer now, but > only for the default constructor of Value_Range. > > I have verified that the individual range constructors are not called > on initialization to Value_Range, which was the original point of the > patch. I have also run our performance suite, and there are no > changes to VRP or overall. > > I would appreciate a review from someone more C++ savvy than me :). > > OK for trunk? > > On Fri, May 3, 2024 at 11:32 AM Andrew Pinski wrote: > > > > On Fri, May 3, 2024 at 2:24 AM Aldy Hernandez wrote: > > > > > > Sparc requires strict alignment and is choking on the byte vector in > > > Value_Range. Is this the right approach, or is there a more canonical > > > way of forcing alignment? > > > > I think the suggestion was to change over to use an union and use the > > types directly in the union (anonymous unions and unions containing > > non-PODs are part of C++11). > > That is: > > union { > > int_range_max int_range; > > frange fload_range; > > unsupported_range un_range; > > }; > > ... > > m_vrange = new (_range) int_range_max (); > > ... > > > > Also the canonical way of forcing alignment in C++ is to use aliagnas > > as my patch in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114912 > > did. > > Also I suspect the alignment is not word alignment but rather the > > alignment of HOST_WIDE_INT which is not always the same as the > > alignment of the pointer but bigger and that is why it is failing on > > sparc (32bit rather than 64bit). > > > > Thanks, > > Andrew Pinski > > > > > > > > If this is correct, OK for trunk? > > > > > > gcc/ChangeLog: > > > > > > * value-range.h (class Value_Range): Use a union. > > > --- > > > gcc/value-range.h | 24 +++- > > > 1 file changed, 15 insertions(+), 9 deletions(-) > > > > > > diff --git a/gcc/value-range.h b/gcc/value-range.h > > > index 934eec9e386..31af7888018 100644 > > > --- a/gcc/value-range.h > > > +++ b/gcc/value-range.h > > > @@ -740,9 +740,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), ""); > > > - char m_buffer[sizeof (int_range_max)]; > > > + union { > > > +// The buffer must be at least the size of the largest range, and > > > +// be aligned on a word boundary for strict alignment targets > > > +// such as sparc. > > > +static_assert (sizeof (int_range_max) > sizeof (frange), ""); > > > +char m_buffer[sizeof (int_range_max)]; > > > +void *align; > > > + } u; > > > }; > > > > > > // The default constructor is uninitialized and must be initialized > > > @@ -816,11 +821,11 @@ 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) int_range_max (); > > >else if (frange::supports_p (type)) > > > -m_vrange = new (_buffer) frange (); > > > +m_vrange = new (_buffer) frange (); > > >else > > > -m_vrange = new (_buffer) unsupported_range (); > > > +m_vrange = new (_buffer) unsupported_range (); > > > } > > > > > > // Initialize object with a copy of R. > > > @@ -829,11 +834,12 @@ 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) int_range_max (as_a (r)); > > >else if (is_a (r)) > > > -m_vrange = new (_buffer) frange (as_a (r)); > > > +m_vrange = new (_buffer) frange (as_a (r)); > > >else > > > -m_vrange = new (_buffer) unsupported_range (as_a > > > (r)); > > > +m_vrange > > > + = new (_buffer) unsupported_range (as_a > > > (r)); > > > } > > > > > > // Assignment operator. Copying incompatible types is allowed. That > > > -- > > > 2.44.0 > > > > >
[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]);
[COMMITTED] [prange] Reword dispatch error message [PR114985]
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. --- 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 65f3843227d..a134af68141 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -207,7 +207,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]); -- 2.45.0
Re: [PATCH 3/4] ranger: Revert the workaround introduced in PR112788 [PR112993]
I'll defer to the PPC maintainers, but LGTM. The less special casing, the better. Aldy On Wed, May 8, 2024, 07:33 Kewen.Lin wrote: > Hi, > > This reverts commit r14-6478-gfda8e2f8292a90 "range: > Workaround different type precision between _Float128 and > long double [PR112788]" as the fixes for PR112993 make > all 128 bits scalar floating point have the same 128 bit > precision, this workaround isn't needed any more. > > Bootstrapped and regress-tested on: > - powerpc64-linux-gnu P8/P9 (with ibm128 by default) > - powerpc64le-linux-gnu P9/P10 (with ibm128 by default) > - powerpc64le-linux-gnu P9 (with ieee128 by default) > > Is it OK for trunk if {1,2}/4 in this series get landed? > > BR, > Kewen > - > > PR target/112993 > > gcc/ChangeLog: > > * value-range.h (range_compatible_p): Remove the workaround on > different type precision between _Float128 and long double. > --- > gcc/value-range.h | 10 ++ > 1 file changed, 2 insertions(+), 8 deletions(-) > > diff --git a/gcc/value-range.h b/gcc/value-range.h > index 9531df56988..39de7daf3d9 100644 > --- a/gcc/value-range.h > +++ b/gcc/value-range.h > @@ -1558,13 +1558,7 @@ range_compatible_p (tree type1, tree type2) >// types_compatible_p requires conversion in both directions to be > useless. >// GIMPLE only requires a cast one way in order to be compatible. >// Ranges really only need the sign and precision to be the same. > - return TYPE_SIGN (type1) == TYPE_SIGN (type2) > -&& (TYPE_PRECISION (type1) == TYPE_PRECISION (type2) > -// FIXME: As PR112788 shows, for now on rs6000 _Float128 has > -// type precision 128 while long double has type precision 127 > -// but both have the same mode so their precision is actually > -// the same, workaround it temporarily. > -|| (SCALAR_FLOAT_TYPE_P (type1) > -&& TYPE_MODE (type1) == TYPE_MODE (type2))); > + return (TYPE_PRECISION (type1) == TYPE_PRECISION (type2) > + && TYPE_SIGN (type1) == TYPE_SIGN (type2)); > } > #endif // GCC_VALUE_RANGE_H > -- > 2.39.1 > >
[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
[COMMITTED] 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. --- 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 72ac2552311..bdd2832873a 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 9c4ad1ee7b9..a9c8c4d03e6 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 7cbe15d05e5..c7c599bfc93 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 c8e8b9b60ac..d5e1aa14275 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; +
Re: [PATCH] Minor range type fixes for IPA in preparation for prange.
Pushed to trunk. On Sun, Apr 28, 2024 at 10:10 PM Aldy Hernandez wrote: > > 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 palces, 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. > > OK for trunk? > > 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. > --- > 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) > +{ > +
[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 (struc
Re: [PATCH] Minor range type fixes for IPA in preparation for prange.
PING. I can probably commit this patchlet as a ranger maintainer, but I'd prefer a nod from a global or IPA maintainer. It is the one patch that's needed before I can throw the switch on prange support later this week. Thanks. Aldy On Sun, Apr 28, 2024 at 10:10 PM Aldy Hernandez wrote: > > 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 palces, 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. > > OK for trunk? > > 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. > --- > 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,
[COMMITTED 21/23] 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. --- 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 +operator_gt::op1_op2_relation (const irange , const prange &, + const prange &) const +{ + if (lhs.undefined_p ()) +return VREL_UNDEFINED; + + // FALSE = op1 > op2 indicates LE_EXPR. + if (lhs.zero_p ()) +return VREL_LE; + + // TRUE =
[COMMITTED 18/23] 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. --- 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 prange , + relation_trio) const +{ + switch (get_bool_state (r, lhs, type)) +{ +case BRS_TRUE: + // If it's true, the result is the same as OP2. + r = op2; + break; + +case BRS_FALSE: + // If the result is false, the only time
[COMMITTED 22/23] 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. --- 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; + +default: + break; +} + return true; +} + +relation_kind +operator_ge::op1_op2_relation (const irange , const prange &, + const prange &) const +{ + if (lhs.undefined_p ()) +return VREL_UNDEFINED; + + // FALSE = op1 >= op2 indicates LT_EXPR.
[COMMITTED 08/23] 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. --- 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 -- 2.44.0
[COMMITTED 14/23] 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. --- 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, -- 2.44.0
[COMMITTED 23/23] 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. --- 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; -- 2.44.0
[COMMITTED 20/23] 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. --- 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; + +default: + break; +} + return true; +} + +relation_kind +operator_le::op1_op2_relation (const irange , const prange &, + const prange &) const +{ + if (lhs.undefined_p ()) +return VREL_UNDEFINED; + + // FALSE = op1 <= op2 indicates
[COMMITTED 11/23] 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. --- 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 -- 2.44.0
[COMMITTED 09/23] 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. --- 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 -- 2.44.0
[COMMITTED 17/23] 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. --- 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 irange , + const prange , + relation_trio) const +{ + switch (get_bool_state (r, lhs, type)) +{ +case BRS_TRUE: + // If the result is true, the only time we know anything is if + // OP2 is a constant. + if
[COMMITTED 06/23] Add prange implementation for get_legacy_range.
gcc/ChangeLog: * value-range.cc (get_legacy_range): New version for prange. --- 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}. -- 2.44.0
[COMMITTED 19/23] 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. --- 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 range_operator { using range_operator::update_bitmask; @@ -1465,6 +1528,117 @@ operator_not_equal::pointers_handled_p (range_op_dispatch_type type, } } +bool +operator_lt::fold_range (irange , tree type, +const prange , +const prange , +
[COMMITTED 12/23] 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. --- 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 -- 2.44.0
[COMMITTED 10/23] 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. --- 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 range. + int_range<2> tmp = inner; + tree pointer_uint_type = make_unsigned_type (TYPE_PRECISION (type)); + range_cast (tmp, pointer_uint_type); + r.set (type, tmp.lower_bound (), tmp.upper_bound ()); + r.update_bitmask (tmp.get_bitmask ()); + return true; +} + +bool
[COMMITTED 13/23] 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. --- 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, -- 2.44.0
[COMMITTED 15/23] 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. --- 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 -- 2.44.0
[COMMITTED 16/23] 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. --- 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 -- 2.44.0
[COMMITTED 05/23] Add hashing support for prange.
gcc/ChangeLog: * value-range.cc (add_vrange): Add prange support. --- 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); -- 2.44.0
[COMMITTED 01/23] 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. --- 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) -- 2.44.0
[COMMITTED 07/23] 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_*. --- 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 , relation_trio = TRIO_VARYING) const final override; @@ -376,6 +382,7 @@ public: using range_operator::fold_range; using range_operator::op1_range; using range_operator::lhs_op1_relation; + using range_operator::update_bitmask; bool fold_range (irange , tree type, const irange , const irange , relation_trio rel = TRIO_VARYING) const final override; @@ -402,6 +409,7 @@
[COMMITTED 02/23] 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. --- 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_unreachable (); @@ -397,6 +401,294 @@ irange::set_nonnegative (tree type) wi::to_wide (TYPE_MAX_VALUE (type))); } +// Prange implementation. + +void +prange::accept (const vrange_visitor ) const +{ + v.visit (*this); +} + +void +prange::set_nonnegative (tree type) +{ + set (type, + wi::zero (TYPE_PRECISION (type)), + wi::max_value (TYPE_PRECISION (type), UNSIGNED)); +} + +void +prange::set (tree min, tree max, value_range_kind kind) +{ + return
[COMMITTED 04/23] 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. --- 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)); + m_trailing_ints.set_precision (prec); + + set_prange (r); +} + +void +prange_storage::set_prange (const prange ) +{ + if (r.undefined_p ()) +m_kind = VR_UNDEFINED; + else if (r.varying_p ()) +m_kind = VR_VARYING; + else +{ + m_kind = VR_RANGE; + set_low (r.lower_bound ()); + set_high (r.upper_bound
[PATCH 00/23] prange: pointer ranges
This patchset implements prange, a range class for pointers. This is meant to be a drop-in replacement for pointer ranges, so we can pull them out of irange, simplifying both irange and prange in the process. Initially we have two integer endpoints and the usual value/mask bitmasks as this is how irange currently implements them, but the end goal is to provide points-to info to replace the hacky pointer equivalency we do in class pointer_equiv_analyzer. I have split up the patchset into tiny pieces to make it easier to track any problems. I have also disabled it by default, choosing to wait a few days until the dust has settled. In a few days I will throw the switch enabling pranges, which will make it invalid for irange's to hold pointers. Once pranges are enabled, I will do some minor cleanups like removing pointer support from range-ops, etc. The performance of prange is a wash for VRP and a 7% improvement for IPA-cp. This is taking into account the unrelated 2% hit we take due to inlining as discussed here: https://gcc.gnu.org/pipermail/gcc/2024-May/243898.html Also, as part of this work, we improved VRP by 6% (on top of the above numbers): https://gcc.gnu.org/pipermail/gcc-patches/2024-May/650320.html So things are looking relatively good. The memory usage will also decrease, both by the 14% reduction in Value_Range, and by prange's being smaller than say int_range_max or int_range<3>. Tested and benchmarked on x86-64 Linux. Aldy Hernandez (23): Minimal prange class showing inlining degradation to VRP. Implement basic prange class. Add streaming support for prange. Add storage support for prange. Add hashing support for prange. Add prange implementation for get_legacy_range. Implement range-op dispatch for prange. Implement operator_identity for prange. Implement operator_cst for prange. Implement operator_cast for prange. Implement operator_min and operator_max for prange. Implement operator_addr_expr for prange. Implement pointer_plus_operator for prange. Implement operator_pointer_diff for prange. Implement operator_bitwise_and for prange. Implement operator_bitwise_or for prange. Implement operator_not_equal for prange. Implement operator_equal for prange. Implement operator_lt for prange. Implement operator_le for prange. Implement operator_gt for prange. Implement operator_ge for prange Add prange entries in gimple-range-op.cc. gcc/data-streamer-in.cc | 12 + gcc/data-streamer-out.cc| 10 + gcc/gimple-range-op.cc | 36 + gcc/range-op-mixed.h| 156 gcc/range-op-ptr.cc | 1545 +++ gcc/range-op.cc | 124 +++ gcc/range-op.h | 111 +++ gcc/value-range-pretty-print.cc | 25 + gcc/value-range-pretty-print.h |1 + gcc/value-range-storage.cc | 117 +++ gcc/value-range-storage.h | 33 + gcc/value-range.cc | 354 ++- gcc/value-range.h | 214 - 13 files changed, 2730 insertions(+), 8 deletions(-) -- 2.44.0
[COMMITTED 03/23] 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. --- 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 (); } -- 2.44.0
[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,
[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 t
[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,
[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
[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 ,
[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, +
[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
[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);
[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)
Re: [PATCH] [ranger] Force buffer alignment in Value_Range [PR114912]
Ahh, that is indeed cleaner, and there's no longer a need to assert the sizeof of individual ranges. It looks like a default constructor is needed for the buffer now, but only for the default constructor of Value_Range. I have verified that the individual range constructors are not called on initialization to Value_Range, which was the original point of the patch. I have also run our performance suite, and there are no changes to VRP or overall. I would appreciate a review from someone more C++ savvy than me :). OK for trunk? On Fri, May 3, 2024 at 11:32 AM Andrew Pinski wrote: > > On Fri, May 3, 2024 at 2:24 AM Aldy Hernandez wrote: > > > > Sparc requires strict alignment and is choking on the byte vector in > > Value_Range. Is this the right approach, or is there a more canonical > > way of forcing alignment? > > I think the suggestion was to change over to use an union and use the > types directly in the union (anonymous unions and unions containing > non-PODs are part of C++11). > That is: > union { > int_range_max int_range; > frange fload_range; > unsupported_range un_range; > }; > ... > m_vrange = new (_range) int_range_max (); > ... > > Also the canonical way of forcing alignment in C++ is to use aliagnas > as my patch in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114912 > did. > Also I suspect the alignment is not word alignment but rather the > alignment of HOST_WIDE_INT which is not always the same as the > alignment of the pointer but bigger and that is why it is failing on > sparc (32bit rather than 64bit). > > Thanks, > Andrew Pinski > > > > > If this is correct, OK for trunk? > > > > gcc/ChangeLog: > > > > * value-range.h (class Value_Range): Use a union. > > --- > > gcc/value-range.h | 24 +++- > > 1 file changed, 15 insertions(+), 9 deletions(-) > > > > diff --git a/gcc/value-range.h b/gcc/value-range.h > > index 934eec9e386..31af7888018 100644 > > --- a/gcc/value-range.h > > +++ b/gcc/value-range.h > > @@ -740,9 +740,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), ""); > > - char m_buffer[sizeof (int_range_max)]; > > + union { > > +// The buffer must be at least the size of the largest range, and > > +// be aligned on a word boundary for strict alignment targets > > +// such as sparc. > > +static_assert (sizeof (int_range_max) > sizeof (frange), ""); > > +char m_buffer[sizeof (int_range_max)]; > > +void *align; > > + } u; > > }; > > > > // The default constructor is uninitialized and must be initialized > > @@ -816,11 +821,11 @@ 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) int_range_max (); > >else if (frange::supports_p (type)) > > -m_vrange = new (_buffer) frange (); > > +m_vrange = new (_buffer) frange (); > >else > > -m_vrange = new (_buffer) unsupported_range (); > > +m_vrange = new (_buffer) unsupported_range (); > > } > > > > // Initialize object with a copy of R. > > @@ -829,11 +834,12 @@ 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) int_range_max (as_a (r)); > >else if (is_a (r)) > > -m_vrange = new (_buffer) frange (as_a (r)); > > +m_vrange = new (_buffer) frange (as_a (r)); > >else > > -m_vrange = new (_buffer) unsupported_range (as_a > > (r)); > > +m_vrange > > + = new (_buffer) unsupported_range (as_a (r)); > > } > > > > // Assignment operator. Copying incompatible types is allowed. That > > -- > > 2.44.0 > > > From a022147e7a9a93d4fc8919aca77ed7fabc99eff7 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Fri, 3 May 2024 11:17:32 +0200 Subject: [PATCH] [ranger] Force buffer alignment in Value_Range [PR114912] gcc/ChangeLog: * value-range.h (class Value_Range): Use a union. --- gcc/value-range.h | 24 +++- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/gcc/value-range.h b/gcc/value-range.h index 934eec9e386..f124dca34be 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -740,9 +740,13 @@ private: void in
[PATCH] [ranger] Force buffer alignment in Value_Range [PR114912]
Sparc requires strict alignment and is choking on the byte vector in Value_Range. Is this the right approach, or is there a more canonical way of forcing alignment? If this is correct, OK for trunk? gcc/ChangeLog: * value-range.h (class Value_Range): Use a union. --- gcc/value-range.h | 24 +++- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/gcc/value-range.h b/gcc/value-range.h index 934eec9e386..31af7888018 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -740,9 +740,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), ""); - char m_buffer[sizeof (int_range_max)]; + union { +// The buffer must be at least the size of the largest range, and +// be aligned on a word boundary for strict alignment targets +// such as sparc. +static_assert (sizeof (int_range_max) > sizeof (frange), ""); +char m_buffer[sizeof (int_range_max)]; +void *align; + } u; }; // The default constructor is uninitialized and must be initialized @@ -816,11 +821,11 @@ 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) int_range_max (); else if (frange::supports_p (type)) -m_vrange = new (_buffer) frange (); +m_vrange = new (_buffer) frange (); else -m_vrange = new (_buffer) unsupported_range (); +m_vrange = new (_buffer) unsupported_range (); } // Initialize object with a copy of R. @@ -829,11 +834,12 @@ 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) int_range_max (as_a (r)); else if (is_a (r)) -m_vrange = new (_buffer) frange (as_a (r)); +m_vrange = new (_buffer) frange (as_a (r)); else -m_vrange = new (_buffer) unsupported_range (as_a (r)); +m_vrange + = new (_buffer) unsupported_range (as_a (r)); } // Assignment operator. Copying incompatible types is allowed. That -- 2.44.0
Re: 1.76% performance loss in VRP due to inlining
After some very painful analysis, I was able to reduce the degradation we are experiencing in VRP to a handful of lines in the new implementation of prange. What happens is that any series of small changes to a new prange class causes changes in the inlining of wide_int_storage elsewhere. With the attached patch, one difference lies in irange::singleton_p(tree *). Note that this is in irange, which is completely unrelated to the new (unused) code. Using trunk as the stage1 compiler, we can see the assembly for irange::singleton_p(tree *) in value-range.cc is different with and without my patch. The number of calls into wide_int within irange::singleton_p(tree *) changes: awk '/^_ZNK6irange11singleton_pEPP9tree_node/,/endproc/' value-range.s | grep call.*wide_int With mainline sources: call_ZN16wide_int_storageC2ERKS_ call _Z16wide_int_to_treeP9tree_nodeRK8poly_intILj1E16generic_wide_intI20wide_int_ref_storageILb0ELb1 With the attached patch: call_ZN16wide_int_storageC2ERKS_ call_ZN16wide_int_storageC2ERKS_ call _Z16wide_int_to_treeP9tree_nodeRK8poly_intILj1E16generic_wide_intI20wide_int_ref_storageILb0ELb1 call_ZN16wide_int_storageC2ERKS_ The additional calls correspond to the wide_int_storage constructor: $ c++filt _ZN16wide_int_storageC2ERKS_ wide_int_storage::wide_int_storage(wide_int_storage const&) Using -fno-semantic-interposition makes no difference. Here are the relevant bits in the difference from -Winline with and without my patch: > inlined from ‘virtual bool irange::singleton_p(tree_node**) const’ at > /home/aldyh/src/gcc/gcc/value-range.cc:1254:40: > /home/aldyh/src/gcc/gcc/wide-int.h:1196:8: warning: inlining failed in call > to ‘wide_int_storage::wide_int_storage(const wide_int_storage&)’: --param > inline-unit-growth limit reached [-Winline] > 1196 | inline wide_int_storage::wide_int_storage (const wide_int_storage ) > |^~~~ > /home/aldyh/src/gcc/gcc/wide-int.h:775:7: note: called from here > 775 | class GTY(()) generic_wide_int : public storage > | ^~~~ > /home/aldyh/src/gcc/gcc/wide-int.h:1196:8: warning: inlining failed in call > to ‘wide_int_storage::wide_int_storage(const wide_int_storage&)’: --param > inline-unit-growth limit reached [-Winline] > 1196 | inline wide_int_storage::wide_int_storage (const wide_int_storage ) > |^~~~ > /home/aldyh/src/gcc/gcc/wide-int.h:775:7: note: called from here > 775 | class GTY(()) generic_wide_int : public storage > | ^~~~ > In copy constructor > ‘generic_wide_int::generic_wide_int(const > generic_wide_int&)’, > inlined from ‘wide_int irange::lower_bound(unsigned int) const’ at > /home/aldyh/src/gcc/gcc/value-range.h:1122:25, Note that this is just one example. There are also inlining differences to irange::get_bitmask(), irange::union_bitmask(), irange::operator=, among others. Most of the inlining failures seem to be related to wide_int_storage. I am attaching the difference in -Winline for the curious. Tracking this down is tricky because the slightest change in the patch causes different inlining in irange. Even using a slightly different stage1 compiler produces different changes. For example, using GCC 13 as the stage1 compiler, VRP exhibits a slowdown of 2% with the full prange class. Although this is virtually identical to the slowdown for using trunk as the stage1 compiler, the inlining failures are a tad different. I am tempted to commit the attached to mainline, which slows down VRP by 0.3%, but is measurable enough to analyze, just so we have a base commit-point from where to do the analysis. My wife is about to give birth any day now, so I'm afraid if I drop off for a few months, we'll lose the analysis and the point in time from where to do it. One final thing. The full prange class patch, even when disabled, slows VRP by 2%. I tried to implement the class in small increments, and every small change caused a further slowdown. I don't know if this 2% is final, or if further tweaks in this space will slow us down more. On a positive note, with the entirety of prange implemented (not just the base class but range-ops implemented and prange enabled, there is no overall change to VRP, and IPA-cp speeds up by 7%. This is because holding pointers in prange is a net win that overcomes the 2% handicap the inliner is hitting us with. I would love to hear thoughts, and if y'all agree that committing a small skeleton now can help us track this down in the future. Aldy On Tue, Apr 30, 2024 at 11:37 PM Jason Merrill wrote: > > On 4/30/24 12:22, Jakub Jelinek wrote: > > On Tue, Apr 30, 2024 at 03:09:51PM -0400, Jason Merrill via Gcc wrote: > >> On Fri, Apr 26, 2024 at 5:44 AM Aldy Hernandez via Gcc &
[COMMITTED] 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. --- 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 largest range. + static_assert (sizeof (int_range_max) > sizeof (frange)); + char m_buffer[sizeof (int_range_max)]; }; +// The default constructor is uninitialized and must be initialized +// with either set_type() or with an assignment into it. + inline Value_Range::Value_Range () { - m_vrange = _unsupported; + m_vrange = NULL; +} + +// Copy constructor. + +inline
[COMMITTED] 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. --- 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; }; -- 2.44.0
[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_i
[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;
Re: [COMMITTED 03/16] Make some Value_Range's explicitly integer.
Ughhh, you're right. Thanks for spotting this. I'm testing the attached patch and will commit if it passes tests. Aldy On Tue, Apr 30, 2024 at 9:46 AM Richard Biener wrote: > > On Sun, Apr 28, 2024 at 9:07 PM Aldy Hernandez wrote: > > > > Fix some Value_Range's that we know ahead of time will be only > > integers. This avoids using the polymorphic Value_Range unnecessarily > > But isn't Value_Range a variable-size irange but int_range<2> doesn't > support more than two sub-ranges? > > So it doesn't look obvious that this isn't actually a regression? > > Richard. > > > 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. > > --- > > 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); >
Re: 1.76% performance loss in VRP due to inlining
On Tue, Apr 30, 2024 at 9:58 AM Richard Biener wrote: > > On Fri, Apr 26, 2024 at 11:45 AM Aldy Hernandez via Gcc > wrote: > > > > Hi folks! > > > > In implementing prange (pointer ranges), I have found a 1.74% slowdown > > in VRP, even without any code path actually using the code. I have > > tracked this down to irange::get_bitmask() being compiled differently > > with and without the bare bones patch. With the patch, > > irange::get_bitmask() has a lot of code inlined into it, particularly > > get_bitmask_from_range() and consequently the wide_int_storage code. > > > > I don't know whether this is expected behavior, and if it is, how to > > mitigate it. I have tried declaring get_bitmask_from_range() inline, > > but that didn't help. OTOH, using __attribute__((always_inline)) > > helps a bit, but not entirely. What does help is inlining > > irange::get_bitmask() entirely, but that seems like a big hammer. > > You can use -Winline to see why we don't inline an inline declared > function. I would guess the unit-growth limit kicks in? Ah, will do. Thanks. > > Did you check a release checking compiler? That might still > inline things. Yes, we only measure performance with release builds. Aldy
[PATCH] 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 palces, 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. OK for trunk? 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. --- 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 dff40cd8aa5..1dbf5278149 100644 --- a/gcc/ipa-fnsummary.cc +++ b/gcc/ipa-fnsummary.cc @@ -515,7 +515,7 @@ evaluate_conditions_for_known_args (struct cgraph_node *node, } else if (!op->val[1]) { - Value_Range op0 (op->type); + Value_Range op0 (TREE_TYPE (op->val[0])); range_op_handler handler (op->code); ipa_range_set_and_normalize (op0, op->val[0]); diff --git a/gcc/ipa-prop.cc