[COMMITTED] [prange] Use type agnostic range in phiopt [PR115191]

2024-05-23 Thread Aldy Hernandez
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]

2024-05-23 Thread Aldy Hernandez via Gcc-cvs
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]

2024-05-17 Thread Aldy Hernandez
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]

2024-05-17 Thread Aldy Hernandez via Gcc-cvs
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

2024-05-17 Thread Aldy Hernandez
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

2024-05-17 Thread Aldy Hernandez via Gcc-cvs
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.""

2024-05-16 Thread Aldy Hernandez
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.""

2024-05-16 Thread Aldy Hernandez
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.

2024-05-16 Thread Aldy Hernandez
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.

2024-05-16 Thread Aldy Hernandez
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.""

2024-05-16 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-16 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-16 Thread Aldy Hernandez via Gcc-cvs
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]

2024-05-15 Thread Aldy Hernandez
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.

2024-05-15 Thread Aldy Hernandez
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.

2024-05-15 Thread Aldy Hernandez via Gcc-cvs
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

2024-05-13 Thread Aldy Hernandez
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]

2024-05-11 Thread Aldy Hernandez
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.

2024-05-11 Thread Aldy Hernandez
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.

2024-05-11 Thread Aldy Hernandez
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.

2024-05-11 Thread Aldy Hernandez
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.

2024-05-11 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-11 Thread Aldy Hernandez via Gcc-cvs
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]

2024-05-10 Thread Aldy Hernandez
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]

2024-05-10 Thread Aldy Hernandez via Gcc-cvs
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]

2024-05-10 Thread Aldy Hernandez
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]

2024-05-10 Thread Aldy Hernandez
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]

2024-05-10 Thread Aldy Hernandez
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]

2024-05-10 Thread Aldy Hernandez via Gcc-cvs
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]

2024-05-09 Thread Aldy Hernandez
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]

2024-05-09 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-09 Thread Aldy Hernandez
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]

2024-05-08 Thread Aldy Hernandez
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]

2024-05-08 Thread Aldy Hernandez via Gcc-cvs
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

2024-05-08 Thread Aldy Hernandez via Gcc-cvs
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]

2024-05-08 Thread Aldy Hernandez
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]

2024-05-08 Thread Aldy Hernandez
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.

2024-05-08 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-08 Thread Aldy Hernandez
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.

2024-05-07 Thread Aldy Hernandez
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.

2024-05-07 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-05 Thread Aldy Hernandez
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.

2024-05-04 Thread Aldy Hernandez
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.

2024-05-04 Thread Aldy Hernandez
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....

2024-05-04 Thread Aldy Hernandez
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.

2024-05-04 Thread Aldy Hernandez
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.

2024-05-04 Thread Aldy Hernandez
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.

2024-05-04 Thread Aldy Hernandez
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.

2024-05-04 Thread Aldy Hernandez
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.

2024-05-04 Thread Aldy Hernandez
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.

2024-05-04 Thread Aldy Hernandez
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.

2024-05-04 Thread Aldy Hernandez
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.

2024-05-04 Thread Aldy Hernandez
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.

2024-05-04 Thread Aldy Hernandez
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.

2024-05-04 Thread Aldy Hernandez
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.

2024-05-04 Thread Aldy Hernandez
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.

2024-05-04 Thread Aldy Hernandez
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.

2024-05-04 Thread Aldy Hernandez
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.

2024-05-04 Thread Aldy Hernandez
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.

2024-05-04 Thread Aldy Hernandez
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.

2024-05-04 Thread Aldy Hernandez
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.

2024-05-04 Thread Aldy Hernandez
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.

2024-05-04 Thread Aldy Hernandez
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.

2024-05-04 Thread Aldy Hernandez
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

2024-05-04 Thread Aldy Hernandez
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.

2024-05-04 Thread Aldy Hernandez
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.

2024-05-04 Thread Aldy Hernandez via Gcc-cvs
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....

2024-05-04 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-04 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-04 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-04 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-04 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-04 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-04 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-04 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-04 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-04 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-04 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-04 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-04 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-04 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-04 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-04 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-04 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-04 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-04 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-04 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-04 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-04 Thread Aldy Hernandez via Gcc-cvs
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]

2024-05-03 Thread Aldy Hernandez
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]

2024-05-03 Thread Aldy Hernandez
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

2024-05-03 Thread Aldy Hernandez via Gcc
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.

2024-05-01 Thread Aldy Hernandez
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.

2024-05-01 Thread Aldy Hernandez
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.

2024-05-01 Thread Aldy Hernandez via Gcc-cvs
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.

2024-05-01 Thread Aldy Hernandez via Gcc-cvs
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.

2024-04-30 Thread Aldy Hernandez via Gcc-cvs
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.

2024-04-30 Thread Aldy Hernandez
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

2024-04-30 Thread Aldy Hernandez via Gcc
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.

2024-04-28 Thread Aldy Hernandez
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 

  1   2   3   4   5   6   7   8   9   10   >