[COMMITTED] tree-optimization/115221 - Do not invoke SCEV if it will use a different range query.

2024-05-28 Thread Andrew MacLeod
The original patch causing the PR made  ranger's cache re-entrant to 
enable SCEV to use the current range_query when called from within ranger..


SCEV uses the currently active range query (via get_range_query()) for 
picking up values.  fold_using_range is the general purpose stmt folder 
many  components use, and it takes a range_query to use for folding.   
When propagating values in the cache, we need to ensure no new queries 
are invoked, and when the cache is propagating and calculating outgoing 
edges, it switches to a read only range_query which uses what it knows 
about global values to come up with best result using current state.


SCEV is unaware of what the caller is using for a range_query, so when 
attempting to fold a PHI node, it is re-invoking the current query 
during propagation which is undesired behavior.   This patch tells 
fold_using_range to not use SCEV if the range_query being used is not 
the same as the one SCEV is going to use.


Bootstrapped on x86_64-pc-linux-gnu with no regressions. Pushed.

Andrew
From b814e390e7c87c14ce8d9cdea6c6cd127a4e6261 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Mon, 27 May 2024 11:00:57 -0400
Subject: [PATCH] Do not invoke SCEV if it will use a different range query.

SCEV always uses the current range_query object.
Ranger's cache uses a global value_query when propagating cache values to
avoid re-invoking ranger during simple vavhe propagations.
when folding a PHI value, SCEV can be invoked, and since it alwys uses
the current range_query object, when ranger is active this causes the
undesired re-invoking of ranger during cache propagation.

This patch checks to see if the fold_using_range specified range_query
object is the same as the one SCEV uses, and does not invoke SCEV if
they do not match.

	PR tree-optimization/115221
	gcc/
	* gimple-range-fold.cc (range_of_ssa_name_with_loop_info): Do
	not invoke SCEV is range_query's do not match.
	gcc/testsuite/
	* gcc.dg/pr115221.c: New.
---
 gcc/gimple-range-fold.cc|  6 +-
 gcc/testsuite/gcc.dg/pr115221.c | 29 +
 2 files changed, 34 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr115221.c

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index b3965b5ee50..98a4877ba18 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -1264,7 +1264,11 @@ fold_using_range::range_of_ssa_name_with_loop_info (vrange , tree name,
 		fur_source )
 {
   gcc_checking_assert (TREE_CODE (name) == SSA_NAME);
-  if (!range_of_var_in_loop (r, name, l, phi, src.query ()))
+  // SCEV currently invokes get_range_query () for values.  If the query
+  // being passed in is not the same SCEV will use, do not invoke SCEV.
+  // This can be remove if/when SCEV uses a passed in range-query.
+  if (src.query () != get_range_query (cfun)
+  || !range_of_var_in_loop (r, name, l, phi, src.query ()))
 r.set_varying (TREE_TYPE (name));
 }
 
diff --git a/gcc/testsuite/gcc.dg/pr115221.c b/gcc/testsuite/gcc.dg/pr115221.c
new file mode 100644
index 000..f139394e5c0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr115221.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+typedef unsigned uint32_t;
+int cde40_t;
+int offset;
+void aal_test_bit();
+uint32_t cde40_key_pol();
+long cde40_offset_check(uint32_t pos) {
+  cde40_key_pol();
+  if (cde40_t)
+return (offset - 2) % (((pos == 3) ? 18 : 26)) != 0;
+  return 0;
+}
+void cde40_check_struct() {
+  uint32_t i, j, to_compare;
+  for (;; i++) {
+cde40_offset_check(i);
+if (to_compare == 0) {
+  if (i && cde40_key_pol())
+	;
+  to_compare = i;
+  continue;
+}
+j = to_compare;
+for (; j < i; j++)
+  aal_test_bit();
+  }
+}
-- 
2.41.0



[COMMITTED] Strlen pass should set current range query.

2024-05-28 Thread Andrew MacLeod

Thanks.

Committed with the change to the testcase.

Bootstraps on x86_64-pc-linux-gnu with no regressions.

Andrew



On 5/28/24 02:49, Richard Biener wrote:

On Tue, May 28, 2024 at 1:24 AM Andrew MacLeod  wrote:

The strlen pass currently has a local ranger instance, but when it
invokes SCEV or any other shared component, SCEV will not be able to
access to this ranger as it uses get_range_query().  They will be stuck
with global ranges.

Enable/disable ranger should be used instead of a local version which
allows other components to use the current range_query.

Bootstraps on 86_64-pc-linux-gnu, but there is one regression. The
regression is from gcc.dg/Wstringop-overflow-10.c.  the function in
question:

void
baz (char *a)
{
char b[16] = "abcdefg";
__builtin_strncpy (a, b, __builtin_strnlen (b, 7));/* { dg-bogus
"specified bound depends on the length of the source argument" } */
}

when compiled with  -O2 -Wstringop-overflow -Wstringop-truncation

it now spits out:

b2.c: In function ‘baz’:
b2.c:24:3: warning: ‘__builtin_strncpy’ output 2 truncated before
terminating nul copying  bytes from a string of the same length
[-Wstringop-truncation]
 24 |   __builtin_strncpy (a, b, __builtin_strnlen (b, 7));   /* {
dg-bogus "specified bound depends on the length of the source argument" } */

It seems like maybe something got smarter by setting the current range
query and this is a legitimate warning for this line of code?   There
will indeed not be a NULL copied as there are 7 characters in the string...

Is this a testcase issue where this warning should have been issued
before, or am I misunderstanding the warning?

I think the warning makes sense in this case.  But I'm not sure why the
dg-bogus is there, that looks like a valid complaint as well?!

I think the patch is OK.

Richard.


Andrew

PS im afraid of adjusting the status quo in this pass... :-P  Not
allowing sSCEV to access the current ranger is causing me other issues
with the fix for 115221.  This *should* have been a harmless change
sigh. :-(  The whole mechanism should just use the current range-query
instad of passing a ranger pointer aorund. But that a much bigger
issue.  one thing at a time.


From c43236cb59e11cadda2654edc117d9270dff75c6 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Mon, 27 May 2024 13:20:13 -0400
Subject: [PATCH 1/5] Strlen pass should set current range query.

The strlen pass currently has a local ranger instance, but when it
invokes SCEV, scev will not be able to access to this ranger.

Enable/disable ranger shoud be used, allowing other components to use
the current range_query.

	gcc/
	* tree-ssa-strlen.cc (strlen_pass::strlen_pass): Add function
	pointer and initialize ptr_qry with current range_query.
	(strlen_pass::m_ranger): Remove.
	(printf_strlen_execute): Enable and disable ranger.
	gcc/testsuite/
	* gcc.dg/Wstringop-overflow-10.c: Add truncating warning.
---
 gcc/testsuite/gcc.dg/Wstringop-overflow-10.c |  2 +-
 gcc/tree-ssa-strlen.cc   | 10 +-
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-10.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-10.c
index bace08ad5d3..ddc27fc0580 100644
--- a/gcc/testsuite/gcc.dg/Wstringop-overflow-10.c
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-10.c
@@ -21,7 +21,7 @@ void
 baz (char *a)
 {
   char b[16] = "abcdefg";
-  __builtin_strncpy (a, b, __builtin_strnlen (b, 7));	/* { dg-bogus "specified bound depends on the length of the source argument" } */
+  __builtin_strncpy (a, b, __builtin_strnlen (b, 7));	/* { dg-warning "output truncated before terminating nul" } */
 }
 
 void fill (char *);
diff --git a/gcc/tree-ssa-strlen.cc b/gcc/tree-ssa-strlen.cc
index 7596dd80942..c43a2da2836 100644
--- a/gcc/tree-ssa-strlen.cc
+++ b/gcc/tree-ssa-strlen.cc
@@ -235,9 +235,9 @@ get_range (tree val, gimple *stmt, wide_int minmax[2],
 class strlen_pass : public dom_walker
 {
 public:
-  strlen_pass (cdi_direction direction)
+  strlen_pass (function *fun, cdi_direction direction)
 : dom_walker (direction),
-  ptr_qry (_ranger),
+  ptr_qry (get_range_query (fun)),
   m_cleanup_cfg (false)
   {
   }
@@ -299,8 +299,6 @@ public:
 			unsigned HOST_WIDE_INT lenrng[2],
 			unsigned HOST_WIDE_INT *size, bool *nulterm);
 
-  gimple_ranger m_ranger;
-
   /* A pointer_query object to store information about pointers and
  their targets in.  */
   pointer_query ptr_qry;
@@ -5912,9 +5910,10 @@ printf_strlen_execute (function *fun, bool warn_only)
   ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names, true);
   max_stridx = 1;
 
+  enable_ranger (fun);
   /* String length optimization is implemented as a walk of the dominator
  tree and a forward walk of statements within each block.  */
-  strlen_pass walker (CDI_DOMINATORS);
+  strlen_pass walker (fun, CDI_DOMINATORS);
   walker.walk (ENTRY_BLOCK_PTR_FOR_FN (fun));

[PATCH] Strlen pass should set current range query.

2024-05-27 Thread Andrew MacLeod
The strlen pass currently has a local ranger instance, but when it 
invokes SCEV or any other shared component, SCEV will not be able to 
access to this ranger as it uses get_range_query().  They will be stuck 
with global ranges.


Enable/disable ranger should be used instead of a local version which 
allows other components to use the current range_query.


Bootstraps on 86_64-pc-linux-gnu, but there is one regression. The 
regression is from gcc.dg/Wstringop-overflow-10.c.  the function in 
question:


void
baz (char *a)
{
  char b[16] = "abcdefg";
  __builtin_strncpy (a, b, __builtin_strnlen (b, 7));    /* { dg-bogus 
"specified bound depends on the length of the source argument" } */

}

when compiled with  -O2 -Wstringop-overflow -Wstringop-truncation

it now spits out:

b2.c: In function ‘baz’:
b2.c:24:3: warning: ‘__builtin_strncpy’ output 2 truncated before 
terminating nul copying  bytes from a string of the same length 
[-Wstringop-truncation]
   24 |   __builtin_strncpy (a, b, __builtin_strnlen (b, 7));   /* { 
dg-bogus "specified bound depends on the length of the source argument" } */


It seems like maybe something got smarter by setting the current range 
query and this is a legitimate warning for this line of code?   There 
will indeed not be a NULL copied as there are 7 characters in the string...


Is this a testcase issue where this warning should have been issued 
before, or am I misunderstanding the warning?


Andrew

PS im afraid of adjusting the status quo in this pass... :-P  Not 
allowing sSCEV to access the current ranger is causing me other issues 
with the fix for 115221.  This *should* have been a harmless change 
sigh. :-(  The whole mechanism should just use the current range-query 
instad of passing a ranger pointer aorund. But that a much bigger 
issue.  one thing at a time.




From 308d5a6b9937c36300e22fcab1ecb67af55dce9e Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Mon, 27 May 2024 13:20:13 -0400
Subject: [PATCH 1/2] Strlen pass should set current range query.

The strlen pass currently has a local ranger instance, but when it
invokes SCEV, scev will not be able to access to this ranger.

Enable/disable ranger shoud be used, allowing other components to use
the current range_query.

	* tree-ssa-strlen.cc (strlen_pass::strlen_pass): Add function
	pointer and initialize ptr_qry with current range_query.
	(strlen_pass::m_ranger): Remove.
	(printf_strlen_execute): Enable and disable ranger.
---
 gcc/tree-ssa-strlen.cc | 10 +-
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/gcc/tree-ssa-strlen.cc b/gcc/tree-ssa-strlen.cc
index 7596dd80942..c43a2da2836 100644
--- a/gcc/tree-ssa-strlen.cc
+++ b/gcc/tree-ssa-strlen.cc
@@ -235,9 +235,9 @@ get_range (tree val, gimple *stmt, wide_int minmax[2],
 class strlen_pass : public dom_walker
 {
 public:
-  strlen_pass (cdi_direction direction)
+  strlen_pass (function *fun, cdi_direction direction)
 : dom_walker (direction),
-  ptr_qry (_ranger),
+  ptr_qry (get_range_query (fun)),
   m_cleanup_cfg (false)
   {
   }
@@ -299,8 +299,6 @@ public:
 			unsigned HOST_WIDE_INT lenrng[2],
 			unsigned HOST_WIDE_INT *size, bool *nulterm);
 
-  gimple_ranger m_ranger;
-
   /* A pointer_query object to store information about pointers and
  their targets in.  */
   pointer_query ptr_qry;
@@ -5912,9 +5910,10 @@ printf_strlen_execute (function *fun, bool warn_only)
   ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names, true);
   max_stridx = 1;
 
+  enable_ranger (fun);
   /* String length optimization is implemented as a walk of the dominator
  tree and a forward walk of statements within each block.  */
-  strlen_pass walker (CDI_DOMINATORS);
+  strlen_pass walker (fun, CDI_DOMINATORS);
   walker.walk (ENTRY_BLOCK_PTR_FOR_FN (fun));
 
   if (dump_file && (dump_flags & TDF_DETAILS))
@@ -5939,6 +5938,7 @@ printf_strlen_execute (function *fun, bool warn_only)
   strlen_to_stridx = NULL;
 }
 
+  disable_ranger (fun);
   scev_finalize ();
   loop_optimizer_finalize ();
 
-- 
2.41.0



[COMMITTED] tree-optimization/115208 - Delete gori_map during destruction of GORI.

2024-05-25 Thread Andrew MacLeod

When a GORI object is constructed, we construct both GORI and a gori_map.

During destruction, I neglected to destruct the associated gori_map.  
doh!  sorry.


Bootstraps on x86_64-pc-linux-gnu with no regressions.  And hopefully 
resolves everyone's issues.


Andrew


From e98cf19c2be1ffaf65d625e1d8b927a42e77b009 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Sat, 25 May 2024 12:28:52 -0400
Subject: [PATCH 4/4] Delete gori_map during destruction of a GORI..

Forgot to free the gori_mpa object when a gori object is freed.

	PR tree-optimization/115208
	* value-query.cc (range_query::create_gori): Confirm gori_map is NULL.
	(range_query::destroy_gori): Free gori_map if one was allocated.
---
 gcc/value-query.cc | 4 
 1 file changed, 4 insertions(+)

diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index 0d0c0e8058e..556a0f39b09 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -188,6 +188,7 @@ void
 range_query::create_gori (int not_executable_flag, int sw_max_edges)
 {
   gcc_checking_assert (m_gori == _gori);
+  gcc_checking_assert (m_map == NULL);
   m_map = new gori_map ();
   gcc_checking_assert (m_map);
   m_gori = new gori_compute (*m_map, not_executable_flag, sw_max_edges);
@@ -199,6 +200,9 @@ range_query::destroy_gori ()
 {
   if (m_gori && m_gori != _gori)
 delete m_gori;
+  if (m_map)
+delete m_map;
+  m_map = NULL;
   m_gori= _gori;
 }
 
-- 
2.41.0



[COMMITTED 11/12] - Make gori_map a shared component.

2024-05-23 Thread Andrew MacLeod
This patch moves the gori_map object out of the gori object, and into 
the range query.   it is required by gori, and will be created 
simultaneously with gori.


The dependency data it manages has uses outside of GORI, and this makes 
it easier to access by the fold_using_range routines, and others.


Documentation is coming :-P,

Bootstrapped on x86_64-pc-linux-gnu with no regressions.  Pushed.
From e81eafd81d76cf4e8b03089a94857b4b52a66bc7 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Tue, 21 May 2024 14:20:52 -0400
Subject: [PATCH 11/12] Make gori_map a shared component.

Move gori_map dependency and import/export object into a range query and
construct it simultaneously with a gori object.

	* gimple-range-cache.cc (ranger_cache::ranger_cache): Use gori_ssa.
	(ranger_cache::dump): Likewise.
	(ranger_cache::get_global_range): Likewise.
	(ranger_cache::set_global_range): Likewise.
	(ranger_cache::register_inferred_value): Likewise.
	* gimple-range-edge.h (gimple_outgoing_range::map): Remove.
	* gimple-range-fold.cc (fold_using_range::range_of_range_op): Use
	gori_ssa.
	(fold_using_range::range_of_address): Likewise.
	(fold_using_range::range_of_phi): Likewise.
	(fur_source::register_outgoing_edges): Likewise.
	* gimple-range-fold.h (fur_source::query): Make const.
	(gori_ssa): New.
	* gimple-range-gori.cc (gori_map::dump): Use 'this' pointer.
	(gori_compute::gori_compute): Construct with a gori_map.
	* gimple-range-gori.h (gori_compute:gori_compute): Change
	prototype.
	(gori_compute::map): Delete.
	(gori_compute::m_map): Change to a reference.
	(FOR_EACH_GORI_IMPORT_NAME): Change parameter gori to gorimap.
	(FOR_EACH_GORI_EXPORT_NAME): Likewise.
	* gimple-range-path.cc (path_range_query::compute_ranges_in_block):
	Use gori_ssa method.
	(path_range_query::compute_exit_dependencies): Likewise.
	* gimple-range.cc (gimple_ranger::range_of_stmt): Likewise.
	(gimple_ranger::register_transitive_inferred_ranges): Likewise.
	* tree-ssa-dom.cc (set_global_ranges_from_unreachable_edges):
	Likewise.
	* tree-ssa-threadedge.cc (compute_exit_dependencies): Likewise.
	* tree-vrp.cc (remove_unreachable::handle_early): Likewise.
	(remove_unreachable::remove_and_update_globals): Likewise.
	* value-query.cc (range_query::create_gori): Create gori map.
	(range_query::share_query): Copy gori map member.
	(range_query::range_query): Initiialize gori_map member.
	* value-query.h (range_query::gori_ssa): New.
	(range_query::m_map): New.
---
 gcc/gimple-range-cache.cc  | 16 
 gcc/gimple-range-edge.h|  1 -
 gcc/gimple-range-fold.cc   | 22 +++---
 gcc/gimple-range-fold.h|  4 +++-
 gcc/gimple-range-gori.cc   |  9 +
 gcc/gimple-range-gori.h| 14 +++---
 gcc/gimple-range-path.cc   |  6 +++---
 gcc/gimple-range.cc|  6 +++---
 gcc/tree-ssa-dom.cc|  2 +-
 gcc/tree-ssa-threadedge.cc |  2 +-
 gcc/tree-vrp.cc|  8 
 gcc/value-query.cc |  6 +-
 gcc/value-query.h  |  2 ++
 13 files changed, 53 insertions(+), 45 deletions(-)

diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index e75cac66902..a511a2c3a4c 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -969,7 +969,7 @@ ranger_cache::ranger_cache (int not_executable_flag, bool use_imm_uses)
 {
   basic_block bb = BASIC_BLOCK_FOR_FN (cfun, x);
   if (bb)
-	gori ().map ()->exports (bb);
+	gori_ssa ()->exports (bb);
 }
   m_update = new update_list ();
 }
@@ -1000,7 +1000,7 @@ ranger_cache::dump (FILE *f)
 void
 ranger_cache::dump_bb (FILE *f, basic_block bb)
 {
-  gori ().map ()->dump (f, bb, false);
+  gori_ssa ()->dump (f, bb, false);
   m_on_entry.dump (f, bb);
   m_relation->dump (f, bb);
 }
@@ -1033,8 +1033,8 @@ ranger_cache::get_global_range (vrange , tree name, bool _p)
   current_p = false;
   if (had_global)
 current_p = r.singleton_p ()
-		|| m_temporal->current_p (name, gori ().map ()->depend1 (name),
-	  gori ().map ()->depend2 (name));
+		|| m_temporal->current_p (name, gori_ssa ()->depend1 (name),
+	  gori_ssa ()->depend2 (name));
   else
 {
   // If no global value has been set and value is VARYING, fold the stmt
@@ -1071,8 +1071,8 @@ ranger_cache::set_global_range (tree name, const vrange , bool changed)
   if (!changed)
 {
   // If there are dependencies, make sure this is not out of date.
-  if (!m_temporal->current_p (name, gori ().map ()->depend1 (name),
- gori ().map ()->depend2 (name)))
+  if (!m_temporal->current_p (name, gori_ssa ()->depend1 (name),
+ gori_ssa ()->depend2 (name)))
 	m_temporal->set_timestamp (name);
   return;
 }
@@ -1097,7 +1097,7 @@ ranger_cache::set_global_range (tree name, const vrange , bool changed)
 
   if (r.singleton_p ()
   || (POINTER_TYPE_P (TREE_TYPE (name)) && r.nonzero_p ()))
-gori ().map ()->set_range_invariant (name);
+gori_ssa (

[COMMITTED 06/12] tree-optimization/113879 - Add inferred ranges for range-ops based statements.

2024-05-23 Thread Andrew MacLeod
gimple_range_fold contains some shorthand fold_range routines for easy 
user consumption of the range-ops interface, but there is no equivalent

routines for op1_range and op2_range.  This patch provides basic versions.

I have started range-op documentation, but its very early days so not 
that useful yet: https://gcc.gnu.org/wiki/AndrewMacLeod/RangeOperator


Any range-op entry which has an op1_range or op2_range implemented can 
potentially also provide inferred ranges.  This is a step towards PR 
113879.  Default is currently OFF for performance reasons as it 
dramatically increases the number of inferred ranges past where the 
current engine is comfortable with, but the functionality will now be 
there to move towards fixing the PR.  It might be appropriate for -O3, 
but I'll hold of for the moment.


Bootstrapped on x86_64-pc-linux-gnu with no regressions.  Pushed.







From 985581b05f32b62df15b60833a8a57544dbbd739 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Thu, 2 May 2024 12:23:18 -0400
Subject: [PATCH 06/12] Add inferred ranges for range-ops based statements.

Gimple_range_fold contains some shorthand fold_range routines for
easy user consumption of that range-ops interface, but there is no equivalent
routines for op1_range and op2_range.  This patch provides basic versions.

Any range-op entry which has an op1_range or op2_range implemented can
potentially also provide inferred ranges.  This is a step towards
PR 113879.  Default is currently OFF for performance reasons as it
dramtically increases the number of inferred ranges.

	PR tree-optimization/113879
	* gimple-range-fold.cc (op1_range): New.
	(op2_range): New.
	* gimple-range-fold.h (op1_range): New prototypes.
	(op2_range): New prototypes.
	* gimple-range-infer.cc (gimple_infer_range::add_range): Do not
	add an inferred range if it is VARYING.
	(gimple_infer_range::gimple_infer_range): Add inferred ranges
	for any range-op statements if requested.
	* gimple-range-infer.h (gimple_infer_range): Add parameter.
---
 gcc/gimple-range-fold.cc  | 71 +++
 gcc/gimple-range-fold.h   |  7 
 gcc/gimple-range-infer.cc | 41 +-
 gcc/gimple-range-infer.h  |  2 +-
 4 files changed, 119 insertions(+), 2 deletions(-)

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index 357a1beabd1..9e9c5960972 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -328,6 +328,77 @@ fold_range (vrange , gimple *s, edge on_edge, range_query *q)
   return f.fold_stmt (r, s, src);
 }
 
+// Calculate op1 on statetemt S with LHS into range R using range query Q
+// to resolve any other operands.
+
+bool
+op1_range (vrange , gimple *s, const vrange , range_query *q)
+{
+  gimple_range_op_handler handler (s);
+  if (!handler)
+return false;
+
+  fur_stmt src (s, q);
+
+  tree op2_expr = handler.operand2 ();
+  if (!op2_expr)
+return handler.calc_op1 (r, lhs);
+
+  Value_Range op2 (TREE_TYPE (op2_expr));
+  if (!src.get_operand (op2, op2_expr))
+return false;
+
+  return handler.calc_op1 (r, lhs, op2);
+}
+
+// Calculate op1 on statetemt S into range R using range query Q.
+// LHS is set to VARYING in this case.
+
+bool
+op1_range (vrange , gimple *s, range_query *q)
+{
+  tree lhs_type = gimple_range_type (s);
+  if (!lhs_type)
+return false;
+  Value_Range lhs_range;
+  lhs_range.set_varying (lhs_type);
+  return op1_range (r, s, lhs_range, q);
+}
+
+// Calculate op2 on statetemt S with LHS into range R using range query Q
+// to resolve any other operands.
+
+bool
+op2_range (vrange , gimple *s, const vrange , range_query *q)
+{
+
+  gimple_range_op_handler handler (s);
+  if (!handler)
+return false;
+
+  fur_stmt src (s, q);
+
+  Value_Range op1 (TREE_TYPE (handler.operand1 ()));
+  if (!src.get_operand (op1, handler.operand1 ()))
+return false;
+
+  return handler.calc_op2 (r, lhs, op1);
+}
+
+// Calculate op2 on statetemt S into range R using range query Q.
+// LHS is set to VARYING in this case.
+
+bool
+op2_range (vrange , gimple *s, range_query *q)
+{
+  tree lhs_type = gimple_range_type (s);
+  if (!lhs_type)
+return false;
+  Value_Range lhs_range;
+  lhs_range.set_varying (lhs_type);
+  return op2_range (r, s, lhs_range, q);
+}
+
 // Provide a fur_source which can be used to determine any relations on
 // a statement.  It manages the callback from fold_using_ranges to determine
 // a relation_trio for a statement.
diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h
index 1925fb899e3..d974b0192c8 100644
--- a/gcc/gimple-range-fold.h
+++ b/gcc/gimple-range-fold.h
@@ -43,6 +43,13 @@ bool fold_range (vrange , gimple *s, vrange , vrange ,
 bool fold_range (vrange , gimple *s, unsigned num_elements, vrange **vector,
 		 range_query *q = NULL);
 
+// Calculate op1 on stmt S.
+bool op1_range (vrange &, gimple *s, range_query *q = NULL);
+bool op1_range (vrange &, gimple *s, const vrange , range_query *q = NULL);
+// Calcu

[COMMITTED 09/12] - Gori_compute inherits from gimple_outgoing_range.

2024-05-23 Thread Andrew MacLeod
This patch makes gimple_outgoing_range a base class for the GORI API, 
and provides basic routines for the SSA-NAME versions returning false.   
gori_compute now inherits from gimple_outgoing_range and no longer needs 
it as a private member. This makes far more sense as GORI is adding the 
ability to calculate SSA_NAMEs on edges in addition to the basic static 
edge ranges.  It also renames outgoing_edge_range_p to edge_range_p for 
consistency with the static edge range routine.


The basic API for static edges (including switch ranges) is documented 
here. https://gcc.gnu.org/wiki/AndrewMacLeod/GimpleOutgoingRange


The more advanced GORI ssa-name processing engine has not been written 
yet.  its on the to-do list :-)


Bootstrapped on x86_64-pc-linux-gnu with no regressions.  Pushed.


From 8feb69600dd696fb8a6e3b88b7d159ced5cb0eb9 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Thu, 9 May 2024 16:34:12 -0400
Subject: [PATCH 09/12] Gori_compute inherits from gimple_outgoing_range.

Make gimple_outgoing_range a base class for the GORI API, and provide
base routines returning false.   gori_compute inherits from
gimple_outgoing_range and no longer needs it as a private member.
Rename outgoing_edge_range_p to edge_range_p.

	* gimple-range-cache.cc (ranger_cache::ranger_cache): Adjust
	m_gori constructor.
	(ranger_cache::edge_range): Use renamed edge_range_p name.
	(ranger_cache::range_from_dom): Likewise.
	* gimple-range-edge.h (gimple_outgoing_range::condexpr_adjust): New.
	(gimple_outgoing_range::has_edge_range_p): New.
	(gimple_outgoing_range::dump): New.
	(gimple_outgoing_range::compute_operand_range): New.
	(gimple_outgoing_range::map): New.
	* gimple-range-fold.cc (fur_source::register_outgoing_edges ): Use
	renamed edge_range_p routine
	* gimple-range-gori.cc (gori_compute::gori_compute): Adjust
	constructor.
	(gori_compute::~gori_compute): New.
	(gori_compute::edge_range_p): Rename from outgoing_edge_range_p
	and use inherited routine instead of member method.
	* gimple-range-gori.h (class gori_compute): Inherit from
	gimple_outgoing_range, adjust protoypes.
	(gori_compute::outgpoing): Delete.
	* gimple-range-path.cc (path_range_query::compute_ranges_in_block): Use
	renamed edge_range_p routine.
	* tree-ssa-loop-unswitch.cc (evaluate_control_stmt_using_entry_checks):
	Likewise.
---
 gcc/gimple-range-cache.cc |  6 +++---
 gcc/gimple-range-edge.h   | 15 ++-
 gcc/gimple-range-fold.cc  |  4 ++--
 gcc/gimple-range-gori.cc  | 13 -
 gcc/gimple-range-gori.h   | 10 +-
 gcc/gimple-range-path.cc  |  4 ++--
 gcc/tree-ssa-loop-unswitch.cc |  4 ++--
 7 files changed, 36 insertions(+), 20 deletions(-)

diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index c52475852a9..40e4baa6289 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -950,7 +950,7 @@ update_list::pop ()
 // --
 
 ranger_cache::ranger_cache (int not_executable_flag, bool use_imm_uses)
-		: m_gori (not_executable_flag)
+  : m_gori (not_executable_flag, param_vrp_switch_limit)
 {
   m_workback.create (0);
   m_workback.safe_grow_cleared (last_basic_block_for_fn (cfun));
@@ -1178,7 +1178,7 @@ ranger_cache::edge_range (vrange , edge e, tree name, enum rfd_mode mode)
   if ((e->flags & (EDGE_EH | EDGE_ABNORMAL)) == 0)
 infer_oracle ().maybe_adjust_range (r, name, e->src);
   Value_Range er (TREE_TYPE (name));
-  if (m_gori.outgoing_edge_range_p (er, e, name, *this))
+  if (m_gori.edge_range_p (er, e, name, *this))
 r.intersect (er);
   return true;
 }
@@ -1738,7 +1738,7 @@ ranger_cache::range_from_dom (vrange , tree name, basic_block start_bb,
 
   edge e = single_pred_edge (prev_bb);
   bb = e->src;
-  if (m_gori.outgoing_edge_range_p (er, e, name, *this))
+  if (m_gori.edge_range_p (er, e, name, *this))
 	{
 	  r.intersect (er);
 	  // If this is a normal edge, apply any inferred ranges.
diff --git a/gcc/gimple-range-edge.h b/gcc/gimple-range-edge.h
index ce8b04f6bad..be1f0c2cc15 100644
--- a/gcc/gimple-range-edge.h
+++ b/gcc/gimple-range-edge.h
@@ -48,9 +48,22 @@ class gimple_outgoing_range
 {
 public:
   gimple_outgoing_range (int max_sw_edges = 0);
-  ~gimple_outgoing_range ();
+  virtual ~gimple_outgoing_range ();
   gimple *edge_range_p (irange , edge e);
   void set_switch_limit (int max_sw_edges = INT_MAX);
+
+  virtual bool edge_range_p (vrange &, edge, tree, range_query &)
+{ return false; }
+  virtual bool condexpr_adjust (vrange &, vrange &, gimple *, tree, tree, tree,
+class fur_source &) { return false; }
+  virtual bool has_edge_range_p (tree, basic_block = NULL) { return false; }
+  virtual bool has_edge_range_p (tree, edge ) { return false; }
+  virtual void dump (FILE *) { }
+  virtual bool compute_operand_range (vrange &, gimple *, const vrange &, tree,
+  fur_source &a

[COMMITTED 05/12] - Move infer_manager to a range_query oracle.

2024-05-23 Thread Andrew MacLeod
Turn the infer_manager class into an always available oracle accessible 
via a range_query object.   This will make it easier to share and query 
inferred range info between objects and also makes the information 
easily accessible to any pass that is interested. This again removes the 
need to check for a non-null object, and again makes for a slight 
performance improvement.


Documentation on the inferred range manager can be found at : 
https://gcc.gnu.org/wiki/AndrewMacLeod/InferredRanges


It also associates each inferred range with it's originating stmt which 
was missing before (we only knew what block it came from). Future 
functionality will make use of the more specific information.


Bootstrapped on x86_64-pc-linux-gnu with no regressions.  Pushed.
From 837ce8a2d75231b68f13da00d9be8d2fd404804e Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Fri, 17 May 2024 10:50:24 -0400
Subject: [PATCH 05/12] Move infer_manager to a range_query oracle.

Turn the infer_manager class into an always available oracle accessible via a
range_query object.  Also assocaite each inferrred range with it's
originating stmt.

	* gimple-range-cache.cc (ranger_cache::ranger_cache): Create an infer
	oracle instead of a local member.
	(ranger_cache::~ranger_cache): Destroy the oracle.
	(ranger_cache::edge_range): Use oracle.
	(ranger_cache::fill_block_cache): Likewise.
	(ranger_cache::range_from_dom): Likewise.
	(ranger_cache::apply_inferred_ranges): Likewise.
	* gimple-range-cache.h (ranger_cache::m_exit): Delete.
	* gimple-range-infer.cc (infer_oracle): New static object;
	(class infer_oracle): New.
	(non_null_wrapper::non_null_wrapper): New.
	(non_null_wrapper::add_nonzero): New.
	(non_null_wrapper::add_range): New.
	(non_null_loadstore): Use nonnull_wrapper.
	(gimple_infer_range::gimple_infer_range): New alternate constructor.
	(exit_range::stmt): New.
	(infer_range_manager::has_range_p): Combine seperate methods.
	(infer_range_manager::maybe_adjust_range): Adjust has_range_p call.
	(infer_range_manager::add_ranges): New.
	(infer_range_manager::add_range): Take stmt rather than BB.
	(infer_range_manager::add_nonzero): Adjust from BB to stmt.
	* gimple-range-infer.h (class gimple_infer_range): Adjust methods.
	(infer_range_oracle): New.
	(class infer_range_manager): Inherit from infer_range_oracle.
	Adjust methods.
	* gimple-range-path.cc (path_range_query::range_defined_in_block): Use
	oracle.
	(path_range_query::adjust_for_non_null_uses): Likewise.
	* gimple-range.cc (gimple_ranger::range_on_edge): Likewise
	(gimple_ranger::register_transitive_inferred_ranges): Likewise.
	* value-query.cc (default_infer_oracle): New.
	(range_query::create_infer_oracle): New.
	(range_query::destroy_infer_oracle): New.
	(range_query::share_query): Copy infer pointer.
	(range_query::range_query): Initialize infer pointer.
	(range_query::~range_query): destroy infer object.
	* value-query.h (range_query::infer_oracle): New.
	(range_query::create_infer_oracle): New prototype.
	(range_query::destroy_infer_oracle): New prototype.
	(range_query::m_infer): New.
---
 gcc/gimple-range-cache.cc | 24 +--
 gcc/gimple-range-cache.h  |  1 -
 gcc/gimple-range-infer.cc | 90 +++
 gcc/gimple-range-infer.h  | 31 ++
 gcc/gimple-range-path.cc  |  4 +-
 gcc/gimple-range.cc   | 14 +++---
 gcc/value-query.cc| 20 +
 gcc/value-query.h |  5 +++
 8 files changed, 131 insertions(+), 58 deletions(-)

diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index 55277ea8af1..34dc9c4a3ec 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -950,8 +950,7 @@ update_list::pop ()
 // --
 
 ranger_cache::ranger_cache (int not_executable_flag, bool use_imm_uses)
-		: m_gori (not_executable_flag),
-		  m_exit (use_imm_uses)
+		: m_gori (not_executable_flag)
 {
   m_workback.create (0);
   m_workback.safe_grow_cleared (last_basic_block_for_fn (cfun));
@@ -960,6 +959,7 @@ ranger_cache::ranger_cache (int not_executable_flag, bool use_imm_uses)
 
   // If DOM info is available, spawn an oracle as well.
   create_relation_oracle ();
+  create_infer_oracle (use_imm_uses);
 
   unsigned x, lim = last_basic_block_for_fn (cfun);
   // Calculate outgoing range info upfront.  This will fully populate the
@@ -977,6 +977,7 @@ ranger_cache::ranger_cache (int not_executable_flag, bool use_imm_uses)
 ranger_cache::~ranger_cache ()
 {
   delete m_update;
+  destroy_infer_oracle ();
   destroy_relation_oracle ();
   delete m_temporal;
   m_workback.release ();
@@ -1175,7 +1176,7 @@ ranger_cache::edge_range (vrange , edge e, tree name, enum rfd_mode mode)
   exit_range (r, name, e->src, mode);
   // If this is not an abnormal edge, check for inferred ranges on exit.
   if ((e->flags & (EDGE_EH | EDGE_ABNORMAL)) == 0)
-m_exit.maybe_adjust_range (r, name, e->src);
+   

[COMMITTED 12/12] - Move condexpr_adjust into gimple-range-fold

2024-05-23 Thread Andrew MacLeod
Certain components of GORI were needed in order to process a COND_EXPR 
expression and calculate the 2 operands as if they were true and false edges
based on the condition.   With GORI available from the range_query 
object now, this can be moved into the fold_using_range code where it 
really belongs.


Bootstrapped on x86_64-pc-linux-gnu with no regressions.  Pushed.
From eb66da78b896ad5e7f6a315413ed68273c83662f Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Tue, 21 May 2024 12:41:49 -0400
Subject: [PATCH 12/12] Move condexpr_adjust into gimple-range-fold

Certain components of GORI were needed in order to process a COND_EXPR
expression and calculate the 2 operands as if they were true and false edges
based on the condition.   With GORI available from the range_query
objcet now, this can be moved into the fold_using_range code where it
really belongs.

	* gimple-range-edge.h (range_query::condexpr_adjust): Delete.
	* gimpe-range-fold.cc (fold_using_range::range_of_range_op): Use
	gori_ssa routine.
	(fold_using_range::range_of_address): Likewise.
	(fold_using_range::range_of_phi): Likewise.
	(fold_using_range::condexpr_adjust): Relocated from gori_compute.
	(fold_using_range::range_of_cond_expr): Use local condexpr_adjust.
	(fur_source::register_outgoing_edges): Use gori_ssa routine.
	* gimple-range-fold.h (gori_ssa): Rename from gori_bb.
	(fold_using_range::condexpr_adjust): Add prototype.
	* gimple-range-gori.cc (gori_compute::condexpr_adjust): Relocate.
	* gimple-range-gori.h (gori_compute::condexpr_adjust): Delete.
---
 gcc/gimple-range-edge.h  |   4 +-
 gcc/gimple-range-fold.cc | 130 ---
 gcc/gimple-range-fold.h  |   4 +-
 gcc/gimple-range-gori.cc | 103 ---
 gcc/gimple-range-gori.h  |   2 -
 5 files changed, 113 insertions(+), 130 deletions(-)

diff --git a/gcc/gimple-range-edge.h b/gcc/gimple-range-edge.h
index 0096c02faf4..0de1cca4294 100644
--- a/gcc/gimple-range-edge.h
+++ b/gcc/gimple-range-edge.h
@@ -54,13 +54,11 @@ public:
 
   virtual bool edge_range_p (vrange &, edge, tree, range_query &)
 { return false; }
-  virtual bool condexpr_adjust (vrange &, vrange &, gimple *, tree, tree, tree,
-class fur_source &) { return false; }
   virtual bool has_edge_range_p (tree, basic_block = NULL) { return false; }
   virtual bool has_edge_range_p (tree, edge ) { return false; }
   virtual void dump (FILE *) { }
   virtual bool compute_operand_range (vrange &, gimple *, const vrange &, tree,
-  fur_source &,
+  class fur_source &,
   class value_relation * = NULL)
 { return false; }
 private:
diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index a0ff7f2b98b..b3965b5ee50 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -745,8 +745,8 @@ fold_using_range::range_of_range_op (vrange ,
 	r.set_varying (type);
 	  if (lhs && gimple_range_ssa_p (op1))
 	{
-	  if (src.gori_bb ())
-		src.gori_bb ()->register_dependency (lhs, op1);
+	  if (src.gori_ssa ())
+		src.gori_ssa ()->register_dependency (lhs, op1);
 	  relation_kind rel;
 	  rel = handler.lhs_op1_relation (r, range1, range1);
 	  if (rel != VREL_VARYING)
@@ -772,10 +772,10 @@ fold_using_range::range_of_range_op (vrange ,
 	relation_fold_and_or (as_a  (r), s, src, range1, range2);
 	  if (lhs)
 	{
-	  if (src.gori_bb ())
+	  if (src.gori_ssa ())
 		{
-		  src.gori_bb ()->register_dependency (lhs, op1);
-		  src.gori_bb ()->register_dependency (lhs, op2);
+		  src.gori_ssa ()->register_dependency (lhs, op1);
+		  src.gori_ssa ()->register_dependency (lhs, op2);
 		}
 	  if (gimple_range_ssa_p (op1))
 		{
@@ -843,8 +843,8 @@ fold_using_range::range_of_address (prange , gimple *stmt, fur_source )
 {
   tree ssa = TREE_OPERAND (base, 0);
   tree lhs = gimple_get_lhs (stmt);
-  if (lhs && gimple_range_ssa_p (ssa) && src.gori_bb ())
-	src.gori_bb ()->register_dependency (lhs, ssa);
+  if (lhs && gimple_range_ssa_p (ssa) && src.gori_ssa ())
+	src.gori_ssa ()->register_dependency (lhs, ssa);
   src.get_operand (r, ssa);
   range_cast (r, TREE_TYPE (gimple_assign_rhs1 (stmt)));
 
@@ -950,8 +950,8 @@ fold_using_range::range_of_phi (vrange , gphi *phi, fur_source )
 	  else
 	r.union_ (arg_range);
 
-	  if (gimple_range_ssa_p (arg) && src.gori_bb ())
-	src.gori_bb ()->register_dependency (phi_def, arg);
+	  if (gimple_range_ssa_p (arg) && src.gori_ssa ())
+	src.gori_ssa ()->register_dependency (phi_def, arg);
 	}
 
   // Track if all arguments are the same.
@@ -1114,6 +1114,95 @@ fold_using_range::range_of_call (vrange , gcall *call, fur_source &)
   return true;
 }
 
+// Given COND ? OP1 : OP2 with ranges R1 for OP1 and R2 for OP2, Use gori
+// to further resolve R1 and R2 if there are any dependencies b

[COMMITTED 10/12] - Make GORI a range_query component.

2024-05-23 Thread Andrew MacLeod
This patch moves the GORI component into the range_query object, and 
makes it generally available.  This makes it much easier to share 
between ranger, other range_queries, and the passes using them.


Bootstrapped on x86_64-pc-linux-gnu with no regressions.  Pushed.
From 59a3a0ad763bc03ad5ab630a62fbc78ae50b486f Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Fri, 17 May 2024 14:27:12 -0400
Subject: [PATCH 10/12] Make GORI a range_query component.

This patch moves the GORI component into the range_query object, and
makes it generally available.  This makes it much easier to share
between ranger and the passes.

	* gimple-range-cache.cc (ranger_cache::ranger_cache): Create
	GORi via the range_query instead of a local member.
	(ranger_cache::dump_bb): Use gori via from the range_query parent.
	(ranger_cache::get_global_range): Likewise.
	(ranger_cache::set_global_range): Likewise.
	(ranger_cache::edge_range): Likewise.
	(anger_cache::block_range): Likewise.
	(ranger_cache::fill_block_cache): Likewise.
	(ranger_cache::range_from_dom): Likewise.
	(ranger_cache::register_inferred_value): Likewise.
	* gimple-range-cache.h (ranger_cache::m_gori): Delete.
	* gimple-range-fold.cc (fur_source::fur_source): Set m_depend_p.
	(fur_depend::fur_depend): Remove gori parameter.
	* gimple-range-fold.h (fur_source::gori): Adjust.
	(fur_source::m_gori): Delete.
	(fur_source::m_depend): New.
	(fur_depend::fur_depend): Adjust prototype.
	* gimple-range-path.cc (path_range_query::path_range_query): Share
	ranger oracles.
	(path_range_query::range_defined_in_block): Use oracle directly.
	(path_range_query::compute_ranges_in_block): Use new gori() method.
	(path_range_query::adjust_for_non_null_uses): Use oracle directly.
	(path_range_query::compute_exit_dependencies): Likewise.
	(jt_fur_source::jt_fur_source): No gori in the parameters.
	(path_range_query::range_of_stmt): Likewise.
	(path_range_query::compute_outgoing_relations): Likewise.
	* gimple-range.cc (gimple_ranger::fold_range_internal): Likewise.
	(gimple_ranger::range_of_stmt): Access gori via gori () method.
	(assume_query::range_of_expr): Create a gori object.
	(assume_query::~assume_query): Destroy a gori object.
	(assume_query::calculate_op): Remove old gori() accessor.
	* gimple-range.h (gimple_ranger::gori): Delete.
	(assume_query::~assume_query): New.
	(assume_query::m_gori): Delete.
	* tree-ssa-dom.cc (set_global_ranges_from_unreachable_edges): use
	gori () method.
	* tree-ssa-threadedge.cc (compute_exit_dependencies): Likewise.
	* value-query.cc (default_gori): New.
	(range_query::create_gori): New.
	(range_query::destroy_gori): New.
	(range_query::share_oracles): Set m_gori.
	(range_query::range_query): Set m_gori to default.
	(range_query::~range_query): call destroy gori.
	* value-query.h (range_query): Adjust prototypes
	(range_query::m_gori): New.
---
 gcc/gimple-range-cache.cc  | 34 +-
 gcc/gimple-range-cache.h   |  1 -
 gcc/gimple-range-fold.cc   |  7 +++
 gcc/gimple-range-fold.h|  7 ---
 gcc/gimple-range-path.cc   | 28 ++--
 gcc/gimple-range.cc| 12 +---
 gcc/gimple-range.h |  3 +--
 gcc/tree-ssa-dom.cc|  3 +--
 gcc/tree-ssa-threadedge.cc |  4 +---
 gcc/value-query.cc | 20 
 gcc/value-query.h  |  5 +
 11 files changed, 75 insertions(+), 49 deletions(-)

diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index 40e4baa6289..e75cac66902 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -950,7 +950,6 @@ update_list::pop ()
 // --
 
 ranger_cache::ranger_cache (int not_executable_flag, bool use_imm_uses)
-  : m_gori (not_executable_flag, param_vrp_switch_limit)
 {
   m_workback.create (0);
   m_workback.safe_grow_cleared (last_basic_block_for_fn (cfun));
@@ -960,6 +959,7 @@ ranger_cache::ranger_cache (int not_executable_flag, bool use_imm_uses)
   // If DOM info is available, spawn an oracle as well.
   create_relation_oracle ();
   create_infer_oracle (use_imm_uses);
+  create_gori (not_executable_flag, param_vrp_switch_limit);
 
   unsigned x, lim = last_basic_block_for_fn (cfun);
   // Calculate outgoing range info upfront.  This will fully populate the
@@ -969,7 +969,7 @@ ranger_cache::ranger_cache (int not_executable_flag, bool use_imm_uses)
 {
   basic_block bb = BASIC_BLOCK_FOR_FN (cfun, x);
   if (bb)
-	m_gori.map ()->exports (bb);
+	gori ().map ()->exports (bb);
 }
   m_update = new update_list ();
 }
@@ -1000,7 +1000,7 @@ ranger_cache::dump (FILE *f)
 void
 ranger_cache::dump_bb (FILE *f, basic_block bb)
 {
-  m_gori.map ()->dump (f, bb, false);
+  gori ().map ()->dump (f, bb, false);
   m_on_entry.dump (f, bb);
   m_relation->dump (f, bb);
 }
@@ -1033,8 +1033,8 @@ ranger_cache::get_global_range (vrange , tree name, bool _p)
   current_p = false;
  

[COMMITTED 03/12] - Rename relation oracle and API.

2024-05-23 Thread Andrew MacLeod

Could have been combined with the previous patch, but eh

This changes the relation oracle accessed via a range_query to the name 
'relation', as there are more oracles coming, and this is more 
description.  it also renames the registering and querying routines to 
have less redundant rext. relation->register_relation and 
relation->query_relation seem a bit texty.  they are now  
relation.record () and relation.query ()


Bootstrapped on x86_64-pc-linux-gnu with no regressions.  Pushed.

From 3a5b702c4082950d614fe12a066609da23363246 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Fri, 17 May 2024 10:18:39 -0400
Subject: [PATCH 03/12] Rename relation oracle and API.

With more oracles incoming, rename the range_query oracle () method to
relation (), and remove the redundant 'relation' text from register and query
methods, resulting in calls that look like:
  relation ()->record (...)   and
  relation ()->query (...)

	* gimple-range-cache.cc (ranger_cache::dump_bb): Use m_relation.
	(ranger_cache::fill_block_cache): Likewise
	* gimple-range-fold.cc (fur_stmt::get_phi_operand): Use new names.
	(fur_depend::register_relation): Likewise.
	(fold_using_range::range_of_phi): Likewise.
	* gimple-range-path.cc (path_range_query::path_range_query): Likewise.
	(path_range_query::~path_range_query): Likewise.
	(ath_range_query::compute_ranges): Likewise.
	(jt_fur_source::register_relation): Likewise.
	(jt_fur_source::query_relation): Likewise.
	(path_range_query::maybe_register_phi_relation): Likewise.
	* gimple-range-path.h (get_path_oracle): Likewise.
	* value-query.cc (range_query::create_relation_oracle): Likewise.
	(range_query::destroy_relation_oracle): Likewise.
	(range_query::share_oracles): Likewise.
	(range_query::range_query): Likewise.
	* value-query.h (value_query::relation): Rename from oracle.
	(m_relation): Rename from m_oracle.
	* value-relation.cc (relation_oracle::query): Rename from
	query_relation.
	(equiv_oracle::query): Likewise.
	(equiv_oracle::record): Rename from register_relation.
	(relation_oracle::record): Likewise.
	(dom_oracle::record): Likewise.
	(dom_oracle::query): Rename from query_relation.
	(path_oracle::record): Rename from register_relation.
	(path_oracle::query): Rename from query_relation.
	* value-relation.h (*::record): Rename from register_relation.
	(*::query): Rename from query_relation.
---
 gcc/gimple-range-cache.cc |  4 +--
 gcc/gimple-range-fold.cc  | 10 
 gcc/gimple-range-path.cc  | 18 +++---
 gcc/gimple-range-path.h   |  2 +-
 gcc/gimple-range.cc   |  4 +--
 gcc/value-query.cc| 16 ++--
 gcc/value-query.h |  4 +--
 gcc/value-relation.cc | 51 ++-
 gcc/value-relation.h  | 39 +-
 9 files changed, 69 insertions(+), 79 deletions(-)

diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index 020069fd635..55277ea8af1 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -1001,7 +1001,7 @@ ranger_cache::dump_bb (FILE *f, basic_block bb)
 {
   m_gori.gori_map::dump (f, bb, false);
   m_on_entry.dump (f, bb);
-  m_oracle->dump (f, bb);
+  m_relation->dump (f, bb);
 }
 
 // Get the global range for NAME, and return in R.  Return false if the
@@ -1439,7 +1439,7 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb)
   tree equiv_name;
   relation_kind rel;
   int prec = TYPE_PRECISION (type);
-  FOR_EACH_PARTIAL_AND_FULL_EQUIV (m_oracle, bb, name, equiv_name, rel)
+  FOR_EACH_PARTIAL_AND_FULL_EQUIV (m_relation, bb, name, equiv_name, rel)
 	{
 	  basic_block equiv_bb = gimple_bb (SSA_NAME_DEF_STMT (equiv_name));
 
diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index eeffdce0b97..357a1beabd1 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -178,7 +178,7 @@ fur_stmt::get_phi_operand (vrange , tree expr, edge e)
 relation_kind
 fur_stmt::query_relation (tree op1, tree op2)
 {
-  return m_query->oracle ().query_relation (m_stmt, op1, op2);
+  return m_query->relation ().query (m_stmt, op1, op2);
 }
 
 // Instantiate a stmt based fur_source with a GORI object.
@@ -196,7 +196,7 @@ fur_depend::fur_depend (gimple *s, gori_compute *gori, range_query *q)
 void
 fur_depend::register_relation (gimple *s, relation_kind k, tree op1, tree op2)
 {
-  m_query->oracle ().register_relation (s, k, op1, op2);
+  m_query->relation ().record (s, k, op1, op2);
 }
 
 // Register a relation on an edge if there is an oracle.
@@ -204,7 +204,7 @@ fur_depend::register_relation (gimple *s, relation_kind k, tree op1, tree op2)
 void
 fur_depend::register_relation (edge e, relation_kind k, tree op1, tree op2)
 {
-  m_query->oracle ().register_relation (e, k, op1, op2);
+  m_query->relation ().record (e, k, op1, op2);
 }
 
 // This version of fur_source will pick a range up from a list of ranges
@@ -854,7 +854,7 @@ fold_using_ran

[COMMITTED 04/12] - Allow components to be shared among range-queries.

2024-05-23 Thread Andrew MacLeod
Ranger and ranger's cache are both range_query based, but they need to 
share some common components. The path ranger also needs to share the 
GORI component.   Up until now, they have simple copied pointers to 
share, but this patch provides a protected API to allow them to share 
without knowing what all components are involved.


Bootstrapped on x86_64-pc-linux-gnu with no regressions.  Pushed.


From ef99d19569a1c5fafa5784c2c2f7855b6e62ffd8 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Fri, 17 May 2024 10:44:27 -0400
Subject: [PATCH 04/12] Allow components to be shared among range-queries.

Ranger and the ranger cache need to share components, this provides a
blessed way to do so.

	* gimple-range.cc (gimple_ranger::gimple_ranger): Share the
	components from ranger_cache.
	(gimple_ranger::~gimple_ranger): Don't clear pointer.
	* value-query.cc (range_query::share_query): New.
	(range_query::range_query): Clear shared component flag.
	(range_query::~range_query): Don't free shared component copies.
	* value-query.h (share_query): New prototype.
	(m_shared_copy_p): New member.
---
 gcc/gimple-range.cc |  4 +---
 gcc/value-query.cc  | 11 +++
 gcc/value-query.h   |  5 +
 3 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 9664300a80b..4326976fc2a 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -44,7 +44,7 @@ gimple_ranger::gimple_ranger (bool use_imm_uses) :
 	current_bb (NULL)
 {
   // Share the oracle from the cache.
-  m_relation = _cache.relation ();
+  share_query (m_cache);
   if (dump_file && (param_ranger_debug & RANGER_DEBUG_TRACE))
 tracer.enable_trace ();
   m_stmt_list.create (0);
@@ -67,8 +67,6 @@ gimple_ranger::gimple_ranger (bool use_imm_uses) :
 
 gimple_ranger::~gimple_ranger ()
 {
-  // Restore the original oracle.
-  m_relation = NULL;
   m_stmt_list.release ();
 }
 
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index db64a95a284..adcc59cadbf 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -211,13 +211,24 @@ range_query::destroy_relation_oracle ()
 }
 }
 
+void
+range_query::share_query (range_query )
+{
+  m_relation = q.m_relation;
+  m_shared_copy_p = true;
+}
+
 range_query::range_query ()
 {
   m_relation = _relation_oracle;
+  m_shared_copy_p = false;
 }
 
 range_query::~range_query ()
 {
+  // Do not destroy anything if this is a shared copy.
+  if (m_shared_copy_p)
+return;
   destroy_relation_oracle ();
 }
 
diff --git a/gcc/value-query.h b/gcc/value-query.h
index a8688a099fa..a5735902af0 100644
--- a/gcc/value-query.h
+++ b/gcc/value-query.h
@@ -88,6 +88,11 @@ protected:
 			 basic_block bbentry, basic_block bbexit);
   bool get_arith_expr_range (vrange , tree expr, gimple *stmt);
   relation_oracle *m_relation;
+  // When multiple related range queries wish to share oracles.
+  // This is an internal interface
+  void share_query (range_query );
+  bool m_shared_copy_p;
+
 };
 
 // Global ranges for SSA names using SSA_NAME_RANGE_INFO.
-- 
2.41.0



[COMMITTED 07/12] - Default gimple_outgoing_range to not process switches.

2024-05-23 Thread Andrew MacLeod
This patch adjusts the way gimple_outgoing_range works.  This is the 
static edge calculator that provide ranges on edges for TRUE/FALSE 
edges, as well as calculated the ranges on switch edges.   It was a 
component of ranger before or something that could be included if a pass 
wanted it.


this adjusts the way it works in preparation for being more tightly 
integrated into GORI.  It now works by always working for TRUE/FALSE 
edges, and uses a set_sw_limit routine to enable or disable switch 
processing.   Functionally there is little difference, but it will allow 
it to be the base for a GORI object now.


Bootstrapped on x86_64-pc-linux-gnu with no regressions.  Pushed.
From 1ec8e2027a99a5ddca933a37b3cf5ef322208c5a Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Mon, 6 May 2024 12:04:24 -0400
Subject: [PATCH 07/12] Default gimple_outgoing_range to not process switches.

Change the default constructor to not process switches, add method to
enable/disable switch processing.

	* gimple-range-edge.cc (gimple_outgoing_range::gimple_outgoing_range):
	Do not allocate a range allocator at construction time.
	(gimple_outgoing_range::~gimple_outgoing_range): Delete allocator
	if one was allocated.
	(gimple_outgoing_range::set_switch_limit): New.
	(gimple_outgoing_range::switch_edge_range): Create an allocator if one
	does not exist.
	(gimple_outgoing_range::edge_range_p): Check for zero edges.
	* gimple-range-edge.h (class gimple_outgoing_range): Adjust prototypes.
---
 gcc/gimple-range-edge.cc | 23 +--
 gcc/gimple-range-edge.h  | 12 +++-
 2 files changed, 28 insertions(+), 7 deletions(-)

diff --git a/gcc/gimple-range-edge.cc b/gcc/gimple-range-edge.cc
index 3811a0995aa..0c75ad0519c 100644
--- a/gcc/gimple-range-edge.cc
+++ b/gcc/gimple-range-edge.cc
@@ -51,7 +51,6 @@ gimple_outgoing_range_stmt_p (basic_block bb)
   return NULL;
 }
 
-
 // Return a TRUE or FALSE range representing the edge value of a GCOND.
 
 void
@@ -64,22 +63,32 @@ gcond_edge_range (irange , edge e)
 r = range_false ();
 }
 
+// Construct a gimple_outgoing_range object.  No memory is allocated.
 
 gimple_outgoing_range::gimple_outgoing_range (int max_sw_edges)
 {
   m_edge_table = NULL;
+  m_range_allocator = NULL;
   m_max_edges = max_sw_edges;
-  m_range_allocator = new vrange_allocator;
 }
 
+// Destruct an edge object, disposing of any memory allocated.
 
 gimple_outgoing_range::~gimple_outgoing_range ()
 {
   if (m_edge_table)
 delete m_edge_table;
-  delete m_range_allocator;
+  if (m_range_allocator)
+delete m_range_allocator;
 }
 
+// Set a new switch limit.
+
+void
+gimple_outgoing_range::set_switch_limit (int max_sw_edges)
+{
+  m_max_edges = max_sw_edges;
+}
 
 // Get a range for a switch edge E from statement S and return it in R.
 // Use a cached value if it exists, or calculate it if not.
@@ -96,8 +105,10 @@ gimple_outgoing_range::switch_edge_range (irange , gswitch *sw, edge e)
   TYPE_PRECISION (TREE_TYPE (gimple_switch_index (sw
 return false;
 
-   if (!m_edge_table)
- m_edge_table = new hash_map (n_edges_for_fn (cfun));
+  if (!m_edge_table)
+m_edge_table = new hash_map (n_edges_for_fn (cfun));
+  if (!m_range_allocator)
+m_range_allocator = new vrange_allocator;
 
vrange_storage **val = m_edge_table->get (e);
if (!val)
@@ -202,7 +213,7 @@ gimple_outgoing_range::edge_range_p (irange , edge e)
 }
 
   // Only process switches if it within the size limit.
-  if (EDGE_COUNT (e->src->succs) > (unsigned)m_max_edges)
+  if (m_max_edges == 0 || (EDGE_COUNT (e->src->succs) > (unsigned)m_max_edges))
 return NULL;
 
   gcc_checking_assert (is_a (s));
diff --git a/gcc/gimple-range-edge.h b/gcc/gimple-range-edge.h
index 9ac0617f970..ce8b04f6bad 100644
--- a/gcc/gimple-range-edge.h
+++ b/gcc/gimple-range-edge.h
@@ -34,13 +34,23 @@ along with GCC; see the file COPYING3.  If not see
 // The API is simple, just ask for the range on the edge.
 // The return value is NULL for no range, or the branch statement which the
 // edge gets the range from, along with the range.
+//
+// THe switch_limit is the number of switch edges beyond which the switch
+// is ignored (ie, edge_range_p () will return NULL as if the sitch was not
+// there.  THis value can be adjusted any time via set_switch_limit ().
+// THe default is 0, no switches are precoessed until set_switch_limit () is
+// called, and then the default is INT_MAX.
+//
+// No memory is allocated until an edge for a switch is processed which also
+// falls under the edge limit criteria.
 
 class gimple_outgoing_range
 {
 public:
-  gimple_outgoing_range (int max_sw_edges = INT_MAX);
+  gimple_outgoing_range (int max_sw_edges = 0);
   ~gimple_outgoing_range ();
   gimple *edge_range_p (irange , edge e);
+  void set_switch_limit (int max_sw_edges = INT_MAX);
 private:
   void calc_switch_ranges (gswitch *sw);
   bool switch_edge_range (irange , gswitch *sw, edge e);
-- 
2.41.0



[COMMITTED 08/12] - Gori_compute no longer inherits from gori_map.

2024-05-23 Thread Andrew MacLeod
This patch moves the gori_compute object away from inheriting a gori_map 
object and instead it as a local member.  Export it via map ().


The gori_map object contains all the SSA name dependencies and 
import/export name lists for blocks.  GORI was inheriting from this 
originally as a convenient way to share the data, but it doesn't really 
belong there.  it is really a component that is used by GORI rather than 
part of what it is.  This more accurately reflects the relationship.


Bootstrapped on x86_64-pc-linux-gnu with no regressions.  Pushed.


From 9b42fafa0ec385bbc86be1d9f1a86c140e1045c3 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Thu, 9 May 2024 14:14:31 -0400
Subject: [PATCH 08/12] Gori_compute no longer inherits from gori_map.

This patch moves the gori_compute object away from inheriting a
gori_map object and instead it as a local member.  Export it via map ().

	* gimple-range-cache.cc (ranger_cache::ranger_cache): Access
	gori_map via member call.
	(ranger_cache::dump_bb): Likewise.
	(ranger_cache::get_global_range): Likewise.
	(ranger_cache::set_global_range): Likewise.
	(ranger_cache::register_inferred_value): Likewise.
	* gimple-range-fold.cc (fold_using_range::range_of_range_op): Likewise.
	(fold_using_range::range_of_address): Likewise.
	(fold_using_range::range_of_phi): Likewise.
	* gimple-range-gori.cc (gori_compute::compute_operand_range_switch):
	likewise.
	(gori_compute::compute_operand_range): Likewise.
	(gori_compute::compute_logical_operands): Likewise.
	(gori_compute::refine_using_relation): Likewise.
	(gori_compute::compute_operand1_and_operand2_range): Likewise.
	(gori_compute::may_recompute_p): Likewise.
	(gori_compute::has_edge_range_p): Likewise.
	(gori_compute::outgoing_edge_range_p): Likewise.
	(gori_compute::condexpr_adjust): Likewise.
	* gimple-range-gori.h (class gori_compute): Do not inherit from
	gori_map.
	(gori_compute::m_map): New.
	* gimple-range-path.cc (gimple-range-path.cc): Use gori_map member.
	(path_range_query::compute_exit_dependencies): Likewise.
	* gimple-range.cc (gimple_ranger::range_of_stmt): Likewise.
	(gimple_ranger::register_transitive_inferred_ranges): Likewise.
	* tree-ssa-dom.cc (set_global_ranges_from_unreachable_edges): Likewise.
	* tree-ssa-threadedge.cc
	  (hybrid_jt_simplifier::compute_exit_dependencies): Likewise.
	* tree-vrp.cc (remove_unreachable::handle_early): Likewise.
	(remove_unreachable::remove_and_update_globals): Likewise.
---
 gcc/gimple-range-cache.cc  | 16 ++---
 gcc/gimple-range-fold.cc   | 12 +-
 gcc/gimple-range-gori.cc   | 47 +++---
 gcc/gimple-range-gori.h|  4 +++-
 gcc/gimple-range-path.cc   |  6 ++---
 gcc/gimple-range.cc|  6 ++---
 gcc/tree-ssa-dom.cc|  2 +-
 gcc/tree-ssa-threadedge.cc |  2 +-
 gcc/tree-vrp.cc|  9 
 9 files changed, 54 insertions(+), 50 deletions(-)

diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index 34dc9c4a3ec..c52475852a9 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -969,7 +969,7 @@ ranger_cache::ranger_cache (int not_executable_flag, bool use_imm_uses)
 {
   basic_block bb = BASIC_BLOCK_FOR_FN (cfun, x);
   if (bb)
-	m_gori.exports (bb);
+	m_gori.map ()->exports (bb);
 }
   m_update = new update_list ();
 }
@@ -1000,7 +1000,7 @@ ranger_cache::dump (FILE *f)
 void
 ranger_cache::dump_bb (FILE *f, basic_block bb)
 {
-  m_gori.gori_map::dump (f, bb, false);
+  m_gori.map ()->dump (f, bb, false);
   m_on_entry.dump (f, bb);
   m_relation->dump (f, bb);
 }
@@ -1033,8 +1033,8 @@ ranger_cache::get_global_range (vrange , tree name, bool _p)
   current_p = false;
   if (had_global)
 current_p = r.singleton_p ()
-		|| m_temporal->current_p (name, m_gori.depend1 (name),
-	  m_gori.depend2 (name));
+		|| m_temporal->current_p (name, m_gori.map ()->depend1 (name),
+	  m_gori.map ()->depend2 (name));
   else
 {
   // If no global value has been set and value is VARYING, fold the stmt
@@ -1071,8 +1071,8 @@ ranger_cache::set_global_range (tree name, const vrange , bool changed)
   if (!changed)
 {
   // If there are dependencies, make sure this is not out of date.
-  if (!m_temporal->current_p (name, m_gori.depend1 (name),
- m_gori.depend2 (name)))
+  if (!m_temporal->current_p (name, m_gori.map ()->depend1 (name),
+ m_gori.map ()->depend2 (name)))
 	m_temporal->set_timestamp (name);
   return;
 }
@@ -1097,7 +1097,7 @@ ranger_cache::set_global_range (tree name, const vrange , bool changed)
 
   if (r.singleton_p ()
   || (POINTER_TYPE_P (TREE_TYPE (name)) && r.nonzero_p ()))
-m_gori.set_range_invariant (name);
+m_gori.map ()->set_range_invariant (name);
   m_temporal->set_timestamp (name);
 }
 
@@ -1783,7 +1783,7 @@ ranger_cache::register_inferred_value (const vrange , tree name,
   m_on_entry.set_bb_range (name, bb, r);
   // If

[COMMITTED 00/12] Cleanup some ranger components and make them available via range_query.

2024-05-23 Thread Andrew MacLeod
This set of 12 patches overhauls some structural component layouts in 
ranger and makes them available via a simple range_query API.


There are 3 main groups of patches.

 The first group overhauls the relation oracle a bit and makes it 
accessing it via range_query more transparent.


 The second bunch incorporates the inferred range manager into an 
oracle also accessible via a range_query object.


The third and final group  reorganizes the GORI component and the 
dependency information it provides with the static edge calculator and 
makes this also accessible via a range_query.


This cleans up a number of things, and to go with this new cleanup comes 
some documentation on how they work (!!!).  well, the GORI documentation 
is pending but the rest is there.   Whats been written is currently 
available from at the root page : 
https://gcc.gnu.org/wiki/AndrewMacLeod/Ranger3.0 In each individual 
patch I also mention the specific page for that component.


Over the remainder of the year I will be adding to documentation this 
until ranger is fully documented, including range-ops, internals, etc


More details on specifics in each patch.

All patches combined result in a slight performance improvement of 0.4% 
in VRP,  0.5% in threading, and 0.07% total compilation time.


Andrew



[COMMITTED 02/12] - Move to an always available relation oracle.

2024-05-23 Thread Andrew MacLeod
This patch provides a basic oracle which doesn't do anything, but will 
still respond when queried.  This allows passes to avoid the NULL check 
for an oracle pointer before they do anything, and results in a slight 
speedup in VRP, and a slightly more significant 0.3% speedup in jump 
threading..


It also unifies the register and query names to nor specify what is 
already apparent in the parameters.


Bootstrapped on x86_64-pc-linux-gnu with no regressions.  Pushed.

From 2f80eb1feb3f92c7e9e57d4726ec52ca7d27ce92 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Tue, 30 Apr 2024 09:35:23 -0400
Subject: [PATCH 02/12] Move to an always available relation oracle.

This eliminates the need to check if the relation oracle pointer is NULL
before every call by providing a default oracle which does nothing.
REmove unused routines, and Unify register_relation method names.

	* gimple-range-cache.cc (ranger_cache::dump_bb): Remove check for
	NULL oracle pointer.
	(ranger_cache::fill_block_cache): Likewise.
	* gimple-range-fold.cc (fur_stmt::get_phi_operand): Likewise.
	(fur_depend::fur_depend): Likewise.
	(fur_depend::register_relation): Likewise, use qury_relation.
	(fold_using_range::range_of_phi): Likewise.
	(fold_using_range::relation_fold_and_or): Likewise.
	* gimple-range-fold.h (fur_source::m_oracle): Delete.  Oracle
	can be accessed dirctly via m_query now.
	* gimple-range-path.cc (path_range_query::path_range_query):
	Adjust for oracle reference pointer.
	(path_range_query::compute_ranges): Likewise.
	(jt_fur_source::jt_fur_source): Adjust for no m_oracle member.
	(jt_fur_source::register_relation): Do not check for NULL
	pointer.
	(jt_fur_source::query_relation): Likewise.
	* gimple-range.cc (gimple_ranger::gimple_ranger):  Adjust for
	reference pointer.
	* value_query.cc (default_relation_oracle): New.
	(range_query::create_relation_oracle): Relocate from header.
	Ensure not being added to global query.
	(range_query::destroy_relation_oracle): Relocate from header.
	(range_query::range_query): Initailize to default oracle.
	(ange_query::~range_query): Call destroy_relation_oracle.
	* value-query.h (class range_query): Adjust prototypes.
	(range_query::create_relation_oracle): Move to source file.
	(range_query::destroy_relation_oracle): Move to source file.
	* value-relation.cc (relation_oracle::validate_relation): Delete.
	(relation_oracle::register_stmt): Rename to register_relation.
	(relation_oracle::register_edge): Likewise.
	* value-relation.h (register_stmt): Rename to register_relation and
	provide default function in base class.
	(register_edge): Likewise.
	(relation_oracle::query_relation): Provide default in base class.
	(relation_oracle::dump): Likewise.
	(relation_oracle::equiv_set): Likewise.
	(default_relation_oracle): New extenal reference.
	(partial_equiv_set, add_partial_equiv): Move to protected.
	* value-relation.h (relation_oracle::validate_relation): Delete.
---
 gcc/gimple-range-cache.cc | 98 +++
 gcc/gimple-range-fold.cc  | 22 +++--
 gcc/gimple-range-fold.h   |  2 -
 gcc/gimple-range-path.cc  | 22 +++--
 gcc/gimple-range.cc   |  5 +-
 gcc/value-query.cc| 38 +--
 gcc/value-query.h | 31 ++---
 gcc/value-relation.cc | 66 ++
 gcc/value-relation.h  | 32 ++---
 9 files changed, 119 insertions(+), 197 deletions(-)

diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index cf17a6af9db..020069fd635 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -1001,8 +1001,7 @@ ranger_cache::dump_bb (FILE *f, basic_block bb)
 {
   m_gori.gori_map::dump (f, bb, false);
   m_on_entry.dump (f, bb);
-  if (m_oracle)
-m_oracle->dump (f, bb);
+  m_oracle->dump (f, bb);
 }
 
 // Get the global range for NAME, and return in R.  Return false if the
@@ -1437,62 +1436,59 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb)
   // See if any equivalences can refine it.
   // PR 109462, like 108139 below, a one way equivalence introduced
   // by a PHI node can also be through the definition side.  Disallow it.
-  if (m_oracle)
+  tree equiv_name;
+  relation_kind rel;
+  int prec = TYPE_PRECISION (type);
+  FOR_EACH_PARTIAL_AND_FULL_EQUIV (m_oracle, bb, name, equiv_name, rel)
 	{
-	  tree equiv_name;
-	  relation_kind rel;
-	  int prec = TYPE_PRECISION (type);
-	  FOR_EACH_PARTIAL_AND_FULL_EQUIV (m_oracle, bb, name, equiv_name, rel)
-	{
-	  basic_block equiv_bb = gimple_bb (SSA_NAME_DEF_STMT (equiv_name));
+	  basic_block equiv_bb = gimple_bb (SSA_NAME_DEF_STMT (equiv_name));
 
-	  // Ignore partial equivs that are smaller than this object.
-	  if (rel != VREL_EQ && prec > pe_to_bits (rel))
-		continue;
+	  // Ignore partial equivs that are smaller than this object.
+	  if (rel != VREL_EQ && prec > pe_to_bits (rel))
+	continue;
 
-	   

[COMMITTED 01/12] - Move all relation queries into relation_oracle.

2024-05-23 Thread Andrew MacLeod
A range-query currently provides a couple of relation query routines, 
plus it also provides direct access to an oracle.   This patch moves 
those queries into the oracle where they should be, and ands the ability 
to create and destroy the basic dominance oracle ranger uses.  This is 
the usual oracle most passes would want, and this provides full access 
to it if ranger has been enabled.  It also allows passes which do not 
use ranger to turn on an oracle and work with it.


Full documentation  for relations and the oracle can be found at:   
https://gcc.gnu.org/wiki/AndrewMacLeod/Relations


Moving the queries into the oracle removes the need to check for a NULL 
pointer on every query, and results in speeding up VRP by about 0.7%


Bootstrapped on x86_64-pc-linux-gnu with no regressions.  Pushed.

From b0cbffd5655b9fc108691c6b15e8eaed4ab9746a Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Mon, 29 Apr 2024 13:32:00 -0400
Subject: [PATCH 01/12] Move all relation queries into relation_oracle.

Move relation queries from range_query object into the relation oracle.

	* gimple-range-cache.cc (ranger_cache::ranger_cache): Call
	create_relation_oracle.
	(ranger_cache::~ranger_cache): Call destroy_relation_oracle.
	* gimple-range-fold.cc (fur_stmt::get_phi_operand): Check for
	relation oracle bnefore calling query_relation.
	(fold_using_range::range_of_phi): Likewise.
	* gimple-range-path.cc (path_range_query::path_range_query): Set
	relation oracle pointer to NULL after deleting it.
	* value-query.cc (range_query::~range_query): Ensure any
	relation oracle is destroyed.
	(range_query::query_relation): relocate to relation_oracle object.
	* value-query.h (class range_query): Adjust method proototypes.
	(range_query::create_relation_oracle): New.
	(range_query::destroy_relation_oracle): New.
	* value-relation.cc (relation_oracle::query_relation): Relocate
	from range query class.
	* value-relation.h (Call relation_oracle): New prototypes.
---
 gcc/gimple-range-cache.cc |  9 +++
 gcc/gimple-range-fold.cc  |  9 +--
 gcc/gimple-range-path.cc  |  1 +
 gcc/gimple-range.cc   |  1 +
 gcc/value-query.cc| 52 ++-
 gcc/value-query.h | 32 +++-
 gcc/value-relation.cc | 33 +
 gcc/value-relation.h  |  4 ++-
 8 files changed, 76 insertions(+), 65 deletions(-)

diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index bdd2832873a..cf17a6af9db 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -957,11 +957,9 @@ ranger_cache::ranger_cache (int not_executable_flag, bool use_imm_uses)
   m_workback.safe_grow_cleared (last_basic_block_for_fn (cfun));
   m_workback.truncate (0);
   m_temporal = new temporal_cache;
+
   // If DOM info is available, spawn an oracle as well.
-  if (dom_info_available_p (CDI_DOMINATORS))
-  m_oracle = new dom_oracle ();
-else
-  m_oracle = NULL;
+  create_relation_oracle ();
 
   unsigned x, lim = last_basic_block_for_fn (cfun);
   // Calculate outgoing range info upfront.  This will fully populate the
@@ -979,8 +977,7 @@ ranger_cache::ranger_cache (int not_executable_flag, bool use_imm_uses)
 ranger_cache::~ranger_cache ()
 {
   delete m_update;
-  if (m_oracle)
-delete m_oracle;
+  destroy_relation_oracle ();
   delete m_temporal;
   m_workback.release ();
 }
diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index a9c8c4d03e6..41b6d350c40 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -178,7 +178,10 @@ fur_stmt::get_phi_operand (vrange , tree expr, edge e)
 relation_kind
 fur_stmt::query_relation (tree op1, tree op2)
 {
-  return m_query->query_relation (m_stmt, op1, op2);
+  relation_oracle *oracle = m_query->oracle ();
+  if (!oracle)
+return VREL_VARYING;
+  return oracle->query_relation (m_stmt, op1, op2);
 }
 
 // Instantiate a stmt based fur_source with a GORI object.
@@ -860,6 +863,7 @@ fold_using_range::range_of_phi (vrange , gphi *phi, fur_source )
   tree single_arg = NULL_TREE;
   bool seen_arg = false;
 
+  relation_oracle *oracle = src.query()->oracle ();
   // Start with an empty range, unioning in each argument's range.
   r.set_undefined ();
   for (x = 0; x < gimple_phi_num_args (phi); x++)
@@ -880,7 +884,8 @@ fold_using_range::range_of_phi (vrange , gphi *phi, fur_source )
 	  // Likewise, if the incoming PHI argument is equivalent to this
 	  // PHI definition, it provides no new info.  Accumulate these ranges
 	  // in case all arguments are equivalences.
-	  if (src.query ()->query_relation (e, arg, phi_def, false) == VREL_EQ)
+	  if (oracle
+	  && oracle->query_relation (e, arg, phi_def) == VREL_EQ)
 	equiv_range.union_(arg_range);
 	  else
 	r.union_ (arg_range);
diff --git a/gcc/gimple-range-path.cc b/gcc/gimple-range-path.cc
index f1a12f76144..ef3db10470e 100644
--- a/gcc/gimple-range-path.cc
+++ b/gcc/gimple

Re: [PATCHv2] Value range: Add range op for __builtin_isfinite

2024-05-14 Thread Andrew MacLeod



On 5/9/24 04:47, HAO CHEN GUI wrote:

Hi Mikael,

   Thanks for your comments.

在 2024/5/9 16:03, Mikael Morin 写道:

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.

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.

Should the varying be set by caller when fold_range returns false?
Just like following codes in value-query.cc.

   if (!op.fold_range (r, type, r0, r1))
 r.set_varying (type);

This would be dangerous in the general case.  fold_range may have 
returned false because 'type' is an unsupported range type. Generally 
this is why we prefer range-ops to return TRUE and VARYING rather than 
FALSE for unknown values.   When FALSE is returned, we should stop 
working with ranges because something is amok.


Andrew



Re: [PATCHv2] Value range: Add range op for __builtin_isfinite

2024-05-14 Thread Andrew MacLeod



On 5/13/24 22:16, HAO CHEN GUI wrote:

Hi Aldy,
   Thanks for your review comments.

在 2024/5/13 19:18, Aldy Hernandez 写道:

+//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.

So it's better to set varying here and return true?


In general, returning TRUE and VARYING is preferable for supported 
types.  Returning FALSE usually means you are trying to fold a statement 
which produced a type which is unsupported.  Or at least there is 
something in the statement we don't understand or want to deal with.


The primary functional difference is that when we have a chain of 
operations (which is more common with op1_range and op2_range calls) , 
we will often continue processing and feed a VARYING result into the 
next operation.  FALSE will usually terminate further processing.


That said, we probably aren't super consistent because there are grey 
areas, but we probably should try to follow that model.  In the end, you 
are unlikely to see much real difference between the 2 options.


Andrew



[COMMITTED][GCC12] Backport of 111009 patch.

2024-05-13 Thread Andrew MacLeod

Same patch for gcc12.

bootstraps and passes all tests on x86_64-pc-linux-gnu

On 5/9/24 10:32, Andrew MacLeod wrote:
As requested, backported the patch for 111009 to resolve incorrect 
ranges from addr_expr and committed to GCC 13 branch.


bootstraps and passes all tests on x86_64-pc-linux-gnu

Andrewcommit b5d079c37e9eee15c0bfe34ffcae31e551192777
Author: Andrew MacLeod 
Date:   Fri May 10 13:56:01 2024 -0400

Fix range-ops operator_addr.

Lack of symbolic information prevents op1_range from being able to draw
the same conclusions as fold_range can.

PR tree-optimization/111009
gcc/
* range-op.cc (operator_addr_expr::op1_range): Be more restrictive.
* value-range.h (contains_zero_p): New.

gcc/testsuite/
* gcc.dg/pr111009.c: New.

diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index bf95f5fbaa1..2e0d67b70b6 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -3825,7 +3825,17 @@ operator_addr_expr::op1_range (irange , tree type,
 			   const irange ,
 			   relation_kind rel ATTRIBUTE_UNUSED) const
 {
-  return operator_addr_expr::fold_range (r, type, lhs, op2);
+   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 (!contains_zero_p (lhs) && TYPE_OVERFLOW_UNDEFINED (type))
+r = range_nonzero (type);
+  else
+r.set_varying (type);
+  return true;
 }
 
 
diff --git a/gcc/testsuite/gcc.dg/pr111009.c b/gcc/testsuite/gcc.dg/pr111009.c
new file mode 100644
index 000..3accd9ac063
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr111009.c
@@ -0,0 +1,38 @@
+/* PR tree-optimization/111009 */
+/* { dg-do run } */
+/* { dg-options "-O3 -fno-strict-overflow" } */
+
+struct dso {
+ struct dso * next;
+ int maj;
+};
+
+__attribute__((noipa)) static void __dso_id__cmp_(void) {}
+
+__attribute__((noipa))
+static int bug(struct dso * d, struct dso *dso)
+{
+ struct dso **p = 
+ struct dso *curr = 0;
+
+ while (*p) {
+  curr = *p;
+  // prevent null deref below
+  if (!dso) return 1;
+  if (dso == curr) return 1;
+
+  int *a = >maj;
+  // null deref
+  if (!(a && *a)) __dso_id__cmp_();
+
+  p = >next;
+ }
+ return 0;
+}
+
+__attribute__((noipa))
+int main(void) {
+struct dso d = { 0, 0, };
+bug(, 0);
+}
+
diff --git a/gcc/value-range.h b/gcc/value-range.h
index d4cba22d540..22f5fc68d7c 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -605,6 +605,16 @@ irange::normalize_kind ()
 }
 }
 
+inline bool
+contains_zero_p (const irange )
+{
+  if (r.undefined_p ())
+return false;
+
+  tree zero = build_zero_cst (r.type ());
+  return r.contains_p (zero);
+}
+
 // Return the maximum value for TYPE.
 
 inline tree


[COMMITTED][GCC13] Backport of 111009 patch.

2024-05-09 Thread Andrew MacLeod
As requested, backported the patch for 111009 to resolve incorrect 
ranges from addr_expr and committed to GCC 13 branch.


bootstraps and passes all tests on x86_64-pc-linux-gnu

Andrew
commit 7a0b2d5aad263beb9babebf2b96c9660d090607e
Author: Andrew MacLeod 
Date:   Wed May 8 10:22:23 2024 -0400

Fix range-ops operator_addr.

Lack of symbolic information prevents op1_range from being able to draw
the same conclusions as fold_range can.

PR tree-optimization/111009
gcc/
* range-op.cc (operator_addr_expr::op1_range): Be more restrictive.
* value-range.h (contains_zero_p): New.

gcc/testsuite/
* gcc.dg/pr111009.c: New.

diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index f90e78dcfbc..97a88dc7efa 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -4357,7 +4357,17 @@ operator_addr_expr::op1_range (irange , tree type,
 			   const irange ,
 			   relation_trio) const
 {
-  return operator_addr_expr::fold_range (r, type, lhs, op2);
+   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 (!contains_zero_p (lhs) && TYPE_OVERFLOW_UNDEFINED (type))
+r = range_nonzero (type);
+  else
+r.set_varying (type);
+  return true;
 }
 
 
diff --git a/gcc/testsuite/gcc.dg/pr111009.c b/gcc/testsuite/gcc.dg/pr111009.c
new file mode 100644
index 000..3accd9ac063
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr111009.c
@@ -0,0 +1,38 @@
+/* PR tree-optimization/111009 */
+/* { dg-do run } */
+/* { dg-options "-O3 -fno-strict-overflow" } */
+
+struct dso {
+ struct dso * next;
+ int maj;
+};
+
+__attribute__((noipa)) static void __dso_id__cmp_(void) {}
+
+__attribute__((noipa))
+static int bug(struct dso * d, struct dso *dso)
+{
+ struct dso **p = 
+ struct dso *curr = 0;
+
+ while (*p) {
+  curr = *p;
+  // prevent null deref below
+  if (!dso) return 1;
+  if (dso == curr) return 1;
+
+  int *a = >maj;
+  // null deref
+  if (!(a && *a)) __dso_id__cmp_();
+
+  p = >next;
+ }
+ return 0;
+}
+
+__attribute__((noipa))
+int main(void) {
+struct dso d = { 0, 0, };
+bug(, 0);
+}
+
diff --git a/gcc/value-range.h b/gcc/value-range.h
index 96e59ecfa72..0284d6cedf4 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -,6 +,16 @@ irange::normalize_kind ()
 }
 }
 
+inline bool
+contains_zero_p (const irange )
+{
+  if (r.undefined_p ())
+return false;
+
+  tree zero = build_zero_cst (r.type ());
+  return r.contains_p (zero);
+}
+
 // Return the maximum value for TYPE.
 
 inline tree


[COMMITTED 5/5] Remove incorrect asserts.

2024-04-30 Thread Andrew MacLeod
while working on some new range-op enhancements, I found a couple of 
developing asserts that no longer apply.  This removed them.


Bootstrapped on x86_64-pc-linux-gnu with no regressions.  pushed.

Andrew
From a89de3a24d2312438848e513a0b02b480d52c81e Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Tue, 13 Feb 2024 10:07:11 -0500
Subject: [PATCH 5/9] Remove incorrect asserts.

Gimple_range_op handles builtin functions, and a couple of asserts that
are in place are incorrect in this context, so just remove them.

	* gimple-range-op.cc (gimple_range_op_handler::calc_op1): Don't
	assert that here are less than 3 operands.
	(gimple_range_op_handler::maybe_builtin_call): Simply return if
	there is no type for the function call.
---
 gcc/gimple-range-op.cc | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index 9c50c00549e..587de186db2 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -178,7 +178,6 @@ gimple_range_op_handler::gimple_range_op_handler (gimple *s)
 bool
 gimple_range_op_handler::calc_op1 (vrange , const vrange _range)
 {
-  gcc_checking_assert (gimple_num_ops (m_stmt) < 3);
   // Give up on empty ranges.
   if (lhs_range.undefined_p ())
 return false;
@@ -1213,7 +1212,8 @@ gimple_range_op_handler::maybe_builtin_call ()
   if (func == CFN_LAST)
 return;
   tree type = gimple_range_type (call);
-  gcc_checking_assert (type);
+  if (!type)
+return;
   if (!Value_Range::supports_type_p (type))
 return;
 
-- 
2.41.0



[COMMITTED 2/5] Fix ranger when called from SCEV.

2024-04-30 Thread Andrew MacLeod
Also during stage 3/4, we discovered that it is unsafe to call ranger 
from within SCEV.  This is because ranger uses SCEV to resolve PHIS, and 
we can end up in a bad loop under the right conditions.


The fix is for ranger's cache to NOT try to pre-evaluate PHIs (which is 
kind of waste anyway since they rarely resolve based on known incoming 
ranges to anything interesting).


Combined with this, it is now safe to make filling the block cache 
re-entrant (which can also happen if called from SCEV).


Turns out not wasting time pre-evaluating PHIs was also a time win.. so 
this patch also provides some modest speedups.


Bootstrapped on x86_64-pc-linux-gnu with no regressions.  pushed.

Andrew


From 83e95c10ed822270e39cb8da8c09f607ad65abbd Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Wed, 13 Mar 2024 14:10:41 -0400
Subject: [PATCH 2/9] Fix ranger when called from SCEV.

Do not pre-evaluate PHIs in the cache, and allow fill_block_cache to
be re-entrant.  This allows SCEV to call into ranger with a context
and not produce cycles or loops.

	* gimple-range-cache.cc (ranger_cache::get_global_range): Do not
	pre-evaluate PHI nodes from the cache.
	(ranger_cache::fill_block_cache): Make re-entrant.
---
 gcc/gimple-range-cache.cc | 10 ++
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index a33b7a73872..72ac2552311 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -1047,7 +1047,9 @@ ranger_cache::get_global_range (vrange , tree name, bool _p)
   if (r.varying_p () && !cfun->after_inlining)
 	{
 	  gimple *s = SSA_NAME_DEF_STMT (name);
-	  if (gimple_get_lhs (s) == name)
+	  // Do not process PHIs as SCEV may be in use and it can
+	  // spawn cyclic lookups.
+	  if (gimple_get_lhs (s) == name && !is_a (s))
 	{
 	  if (!fold_range (r, s, get_global_range_query ()))
 		gimple_range_global (r, name);
@@ -1413,7 +1415,7 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb)
 
   // At this point we shouldn't be looking at the def, entry block.
   gcc_checking_assert (bb != def_bb && bb != ENTRY_BLOCK_PTR_FOR_FN (cfun));
-  gcc_checking_assert (m_workback.length () == 0);
+  unsigned start_length = m_workback.length ();
 
   // If the block cache is set, then we've already visited this block.
   if (m_on_entry.bb_range_p (name, bb))
@@ -1500,7 +1502,7 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb)
 	}
 
   m_on_entry.set_bb_range (name, bb, block_result);
-  gcc_checking_assert (m_workback.length () == 0);
+  gcc_checking_assert (m_workback.length () == start_length);
   return;
 }
 
@@ -1512,7 +1514,7 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb)
   m_on_entry.set_bb_range (name, bb, undefined);
   gcc_checking_assert (m_update->empty_p ());
 
-  while (m_workback.length () > 0)
+  while (m_workback.length () > start_length)
 {
   basic_block node = m_workback.pop ();
   if (DEBUG_RANGE_CACHE)
-- 
2.41.0



[COMMITTED 4/5] - Add range_on_entry/exit to value_query API.

2024-04-30 Thread Andrew MacLeod
It was also requested that I make range_on_entry() and range_on_exit () 
part of the fomal API for a range_query.  These are now provided along 
with the orignal range_of_expr (), range_of_stmt (), and range_on_edge 
().  The routines were already there, just not published for consumption 
in the API.


Bootstrapped on x86_64-pc-linux-gnu with no regressions.  pushed.

Andrew
From 4b955ac10f3d978a9be491d9c528da005895 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Wed, 13 Mar 2024 14:18:48 -0400
Subject: [PATCH 4/9] Add range_on_entry/exit to value_query API.

Add range_on_entry and range_on_exit to the value_query API.  These will
also work with generic trees like range_of_expr does.

	* gimple-range.cc (gimple_ranger::range_on_entry): Adjust for new
	API and support non-SSA expressions.
	(gimple_ranger::range_on_exit): Ditto.
	* gimple-range.h (range_on_entry, range_on_exit): Adjust API.
	* value-query.cc (range_query::range_on_entry): New.
	(range_query::range_on_exit): New.
	(range_query::value_on_entry): New.
	(range_query::value_on_exit): New.
	(range_query::invoke_range_of_expr): New.
	(range_query::get_tree_range): Allow stmt, on_entry or on_exit
	range queries.
	SSA_NAMES should invoke range_of_expr if possible.
	* value-query.h (class range_query): Adjust prototypes.
---
 gcc/gimple-range.cc |  14 ---
 gcc/gimple-range.h  |   4 +-
 gcc/value-query.cc  | 100 
 gcc/value-query.h   |   9 +++-
 4 files changed, 112 insertions(+), 15 deletions(-)

diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 3966cfbd14c..e75e2e17dc3 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -152,11 +152,13 @@ gimple_ranger::range_of_expr (vrange , tree expr, gimple *stmt)
 
 // Return the range of NAME on entry to block BB in R.
 
-void
+bool
 gimple_ranger::range_on_entry (vrange , basic_block bb, tree name)
 {
+  if (!gimple_range_ssa_p (name))
+return get_tree_range (r, name, NULL, bb, NULL);
+
   Value_Range entry_range (TREE_TYPE (name));
-  gcc_checking_assert (gimple_range_ssa_p (name));
 
   unsigned idx;
   if ((idx = tracer.header ("range_on_entry (")))
@@ -174,16 +176,17 @@ gimple_ranger::range_on_entry (vrange , basic_block bb, tree name)
 
   if (idx)
 tracer.trailer (idx, "range_on_entry", true, name, r);
+  return true;
 }
 
 // Calculate the range for NAME at the end of block BB and return it in R.
 // Return false if no range can be calculated.
 
-void
+bool
 gimple_ranger::range_on_exit (vrange , basic_block bb, tree name)
 {
-  // on-exit from the exit block?
-  gcc_checking_assert (gimple_range_ssa_p (name));
+  if (!gimple_range_ssa_p (name))
+return get_tree_range (r, name, NULL, NULL, bb);
 
   unsigned idx;
   if ((idx = tracer.header ("range_on_exit (")))
@@ -208,6 +211,7 @@ gimple_ranger::range_on_exit (vrange , basic_block bb, tree name)
   
   if (idx)
 tracer.trailer (idx, "range_on_exit", true, name, r);
+  return true;
 }
 
 // Calculate a range for NAME on edge E and return it in R.
diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h
index 8739ab6a2ef..167b54b2a37 100644
--- a/gcc/gimple-range.h
+++ b/gcc/gimple-range.h
@@ -52,8 +52,8 @@ public:
   virtual bool range_of_stmt (vrange , gimple *, tree name = NULL) override;
   virtual bool range_of_expr (vrange , tree name, gimple * = NULL) override;
   virtual bool range_on_edge (vrange , edge e, tree name) override;
-  void range_on_entry (vrange , basic_block bb, tree name);
-  void range_on_exit (vrange , basic_block bb, tree name);
+  virtual bool range_on_entry (vrange , basic_block bb, tree name) override;
+  virtual bool range_on_exit (vrange , basic_block bb, tree name) override;
   void export_global_ranges ();
   inline gori_compute  ()  { return m_cache.m_gori; }
   virtual void dump (FILE *f) override;
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index e88c8e25789..c2ab745a466 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -41,6 +41,18 @@ range_query::range_on_edge (vrange , edge, tree expr)
   return range_of_expr (r, expr);
 }
 
+bool
+range_query::range_on_entry (vrange , basic_block, tree expr)
+{
+  return range_of_expr (r, expr);
+}
+
+bool
+range_query::range_on_exit (vrange , basic_block, tree expr)
+{
+  return range_of_expr (r, expr);
+}
+
 bool
 range_query::range_of_stmt (vrange , gimple *stmt, tree name)
 {
@@ -54,6 +66,9 @@ range_query::range_of_stmt (vrange , gimple *stmt, tree name)
   return false;
 }
 
+// If the range of expr EXPR at STMT is a single value, return it.
+// Otherwise return NULL_TREE.
+
 tree
 range_query::value_of_expr (tree expr, gimple *stmt)
 {
@@ -76,6 +91,9 @@ range_query::value_of_expr (tree expr, gimple *stmt)
   return NULL_TREE;
 }
 
+// If the range on edge E for EXPR is a single value, return it.
+// Otherwise return NULL_TREE.
+
 tree
 range_query::value_on_edge (edge e, tree expr)
 {
@@ -94,9 +112,11 @@ range_query::valu

[COMMITTED 3/5] Invoke range_of_stmt on ssa_names with no context.

2024-04-30 Thread Andrew MacLeod
If range_of_expr is called on an ssa-name with no context, ranger just 
grabs whatever the global value is.


It was pointed out we can do better than this.  If the name is in the 
IL, there is no reason for ranger to not try to fold the statement and 
see if we get a better result for it.   It removes an unnecessary 
penalty when there is no statement given for context.


This requires a tiny bit more work, sometimes for no benefit. However, 
the slowdown is also marginal.


Bootstrapped on x86_64-pc-linux-gnu with no regressions.  pushed.

Andrew
From cca3c4f2e7075fe613ac1cd67a3e1743faf33505 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Wed, 13 Mar 2024 14:13:28 -0400
Subject: [PATCH 3/9] Invoke range_of_stmt on ssa_names with no context.

Evalaute ssa-names when range_of_expr is called with no context statement
by calling range_of_stmt to get an initial value.

	* gimple-range.cc (gimple_ranger::range_of_expr): Call range_of_stmt
	when there is no context stmt.
---
 gcc/gimple-range.cc | 10 +-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 4d3b1ce8588..3966cfbd14c 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -102,7 +102,15 @@ gimple_ranger::range_of_expr (vrange , tree expr, gimple *stmt)
   if (!stmt)
 {
   Value_Range tmp (TREE_TYPE (expr));
-  m_cache.get_global_range (r, expr);
+  // If there is no global range for EXPR yet, try to evaluate it.
+  // This call sets R to a global range regardless.
+  if (!m_cache.get_global_range (r, expr))
+	{
+	  gimple *s = SSA_NAME_DEF_STMT (expr);
+	  // Calculate a range for S if it is safe to do so.
+	  if (s && gimple_bb (s) && gimple_get_lhs (s) == expr)
+	return range_of_stmt (r, s);
+	}
   // Pick up implied context information from the on-entry cache
   // if current_bb is set.  Do not attempt any new calculations.
   if (current_bb && m_cache.block_range (tmp, current_bb, expr, false))
-- 
2.41.0



[COMMITTED 1/5] Remove wrapper around gimple_range_global.

2024-04-30 Thread Andrew MacLeod
This came up during stage 4 when someone noticed a comment that said 
when legacy EVRP was removed, the wrapper around accessing 
SSA_NAME_RANGES for initial values could be removed.


To be clearer, the original discussion is here: 
https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571709.html


We couldn't prime ranger's initial use of an ssa-name before inlining, 
or we would end up removing builtin_unreachable calls. These conditions 
are no longer present, and its safe to simple always pick up whatever 
the best value we can find.


It even provides a modest speedup with less condition checking on every 
access to a global.


Bootstrapped on x86_64-pc-linux-gnu with no regressions.  pushed.

Andrew
From f3571462b581e1b57d563268483207bc929de952 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Tue, 20 Feb 2024 12:27:51 -0500
Subject: [PATCH 1/9] Remove wrapper around gimple_range_global.

Now that legacy EVRP has been removed, we can remove the wrapper which
prevented us from using global names before inlining except under
some specific conditions.  See discussion:
 https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571709.html

	* value-query.cc (get_range_global): Rename to gimple_range_global.
	(gimple_range_global): Remove wrapper function.
	(global_range_query::range_of_expr): Call gimple_range_global.
---
 gcc/value-query.cc | 40 +++-
 1 file changed, 7 insertions(+), 33 deletions(-)

diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index 052b7511565..e88c8e25789 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -280,11 +280,15 @@ get_ssa_name_ptr_info_nonnull (const_tree name)
 // Update the global range for NAME into the SSA_RANGE_NAME_INFO and
 // Return the legacy global range for NAME if it has one, otherwise
 // return VARYING.
+// See discussion here regarding why there use to be a wrapper function:
+// https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571709.html
+// Legacy EVRP has been removed, leaving just this function.
 
-static void
-get_range_global (vrange , tree name, struct function *fun = cfun)
+void
+gimple_range_global (vrange , tree name, struct function *fun)
 {
   tree type = TREE_TYPE (name);
+  gcc_checking_assert (TREE_CODE (name) == SSA_NAME);
 
   if (SSA_NAME_IS_DEFAULT_DEF (name))
 {
@@ -332,36 +336,6 @@ get_range_global (vrange , tree name, struct function *fun = cfun)
 r.set_varying (type);
 }
 
-// This is where the ranger picks up global info to seed initial
-// requests.  It is a slightly restricted version of
-// get_range_global() above.
-//
-// The reason for the difference is that we can always pick the
-// default definition of an SSA with no adverse effects, but for other
-// SSAs, if we pick things up to early, we may prematurely eliminate
-// builtin_unreachables.
-//
-// Without this restriction, the test in g++.dg/tree-ssa/pr61034.C has
-// all of its unreachable calls removed too early.
-//
-// See discussion here:
-// https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571709.html
-
-void
-gimple_range_global (vrange , tree name, struct function *fun)
-{
-  tree type = TREE_TYPE (name);
-  gcc_checking_assert (TREE_CODE (name) == SSA_NAME);
-
-  if (SSA_NAME_IS_DEFAULT_DEF (name) || (fun && fun->after_inlining)
-  || is_a (SSA_NAME_DEF_STMT (name)))
-{
-  get_range_global (r, name, fun);
-  return;
-}
-  r.set_varying (type);
-}
-
 // --
 // global_range_query implementation.
 
@@ -373,7 +347,7 @@ global_range_query::range_of_expr (vrange , tree expr, gimple *stmt)
   if (!gimple_range_ssa_p (expr))
 return get_tree_range (r, expr, stmt);
 
-  get_range_global (r, expr);
+  gimple_range_global (r, expr);
 
   return true;
 }
-- 
2.41.0



Re: PING^1 [PATCH] range: Workaround different type precision issue between _Float128 and long double [PR112788]

2023-12-12 Thread Andrew MacLeod
I leave this for the release managers, but I am not opposed to it for 
this release... It would be nice to remove it for the next release


Andrew



On 12/12/23 01:07, Kewen.Lin wrote:

Hi,

Gentle ping this:

https://gcc.gnu.org/pipermail/gcc-patches/2023-December/639140.html

BR,
Kewen

on 2023/12/4 17:49, Kewen.Lin wrote:

Hi,

As PR112788 shows, on rs6000 with -mabi=ieeelongdouble type _Float128
has the different type precision (128) from that (127) of type long
double, but actually they has the same underlying mode, so they have
the same precision as the mode indicates the same real type format
ieee_quad_format.

It's not sensible to have such two types which have the same mode but
different type precisions, some fix attempt was posted at [1].
As the discussion there, there are some historical reasons and
practical issues.  Considering we passed stage 1 and it also affected
the build as reported, this patch is trying to temporarily workaround
it.  I thought to introduce a hookpod but that seems a bit overkill,
assuming scalar float type with the same mode should have the same
precision looks sensible.

Bootstrapped and regtested on powerpc64-linux-gnu P7/P8/P9 and
powerpc64le-linux-gnu P9/P10.

Is it ok for trunk?

[1] 
https://inbox.sourceware.org/gcc-patches/718677e7-614d-7977-312d-05a75e1fd...@linux.ibm.com/

BR,
Kewen

PR tree-optimization/112788

gcc/ChangeLog:

* value-range.h (range_compatible_p): Workaround same type mode but
different type precision issue for rs6000 scalar float types
_Float128 and long double.
---
  gcc/value-range.h | 10 --
  1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/gcc/value-range.h b/gcc/value-range.h
index 33f204a7171..d0a84754a10 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -1558,7 +1558,13 @@ 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_PRECISION (type1) == TYPE_PRECISION (type2)
- && TYPE_SIGN (type1) == TYPE_SIGN (type2));
+  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)));
  }
  #endif // GCC_VALUE_RANGE_H
--
2.42.0





Re: [Patch] OpenMP: Minor '!$omp allocators' cleanup - and still: Re: [patch] OpenMP/Fortran: Implement omp allocators/allocate for ptr/allocatables

2023-12-11 Thread Andrew MacLeod



On 12/11/23 17:12, Thomas Schwinge wrote:

Hi!

This issue would've been prevented if we'd actually use a distinct C++
data type for GCC types, checkable at compile time -- I'm thus CCing
Andrew MacLeod for amusement or crying, "one more for the list!".  ;-\


Perhaps the time has come  It is definitely under re-consideration 
for next stage 1...


Andrew


(See
<https://inbox.sourceware.org/1acd7994-2440-4092-897f-97f14d3fb...@redhat.com>
"[TTYPE] Strongly typed tree project. Original document circa 2017".)

On 2023-12-11T12:45:27+0100, Tobias Burnus  wrote:

I included a minor cleanup patch [...]

I intent to commit that patch as obvious, unless there are further comments.
OpenMP: Minor '!$omp allocators' cleanup
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -8361,8 +8361,10 @@ gfc_omp_call_add_alloc (tree ptr)
if (fn == NULL_TREE)
  {
fn = build_function_type_list (void_type_node, ptr_type_node, 
NULL_TREE);
+  tree att = build_tree_list (NULL_TREE, build_string (4, ". R "));
+  att = tree_cons (get_identifier ("fn spec"), att, TYPE_ATTRIBUTES (fn));
+  fn = build_type_attribute_variant (fn, att);
fn = build_fn_decl ("GOMP_add_alloc", fn);
-/* FIXME: attributes.  */
  }
return build_call_expr_loc (input_location, fn, 1, ptr);
  }
@@ -8380,7 +8382,9 @@ gfc_omp_call_is_alloc (tree ptr)
fn = build_function_type_list (boolean_type_node, ptr_type_node,
NULL_TREE);
fn = build_fn_decl ("GOMP_is_alloc", fn);
-/* FIXME: attributes.  */
+  tree att = build_tree_list (NULL_TREE, build_string (4, ". R "));
+  att = tree_cons (get_identifier ("fn spec"), att, TYPE_ATTRIBUTES (fn));
+  fn = build_type_attribute_variant (fn, att);
  }
return build_call_expr_loc (input_location, fn, 1, ptr);
  }

Pushed to master branch commit 453e0f45a49f425992bc47ff8909ed8affc29d2e
"Resolve ICE in 'gcc/fortran/trans-openmp.cc:gfc_omp_call_is_alloc'", see
attached.


Grüße
  Thomas


-
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 
München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas 
Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht 
München, HRB 106955




Re: [PATCH] tree-optimization/112843 - update_stmt doing wrong things

2023-12-05 Thread Andrew MacLeod

On 12/5/23 03:27, Richard Biener wrote:

The following removes range_query::update_stmt and its single
invocation from update_stmt_operands.  That function is not
supposed to look beyond the raw stmt contents of the passed
stmt since there's no guarantee about the rest of the IL.

I've successfully bootstrapped & tested the update_stmt_operands
hunk, now testing removal of the actual routine as well.  The
testcase that was added when introducing range_query::update_stmt
still passes.

OK to remove the implementation?  I don't see any way around
removing the call though.


Im ok removing it.  Now that we are enabling ranger during a lot of IL 
updating, it probably doesn't make sense for the few cases it use to 
help with with, and may well be dangerous.


the testcase in question that was added appears to be threaded now which 
it wasn't before.  If a similar situation occurs and we need some sort 
of updating, I'll just mark the ssa-name on the LHS as out-of-date, and 
then it'll get lazily updated if need be.


Thanks.

Andrew


Thanks,
Richard.

PR tree-optimization/112843
* tree-ssa-operands.cc (update_stmt_operands): Do not call
update_stmt from ranger.
* value-query.h (range_query::update_stmt): Remove.
* gimple-range.h (gimple_ranger::update_stmt): Likewise.
* gimple-range.cc (gimple_ranger::update_stmt): Likewise.
---
  gcc/gimple-range.cc  | 34 --
  gcc/gimple-range.h   |  1 -
  gcc/tree-ssa-operands.cc |  3 ---
  gcc/value-query.h|  3 ---
  4 files changed, 41 deletions(-)

diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 5e9bb397a20..84d2c7516e6 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -544,40 +544,6 @@ gimple_ranger::register_transitive_inferred_ranges 
(basic_block bb)
  }
  }
  
-// When a statement S has changed since the result was cached, re-evaluate

-// and update the global cache.
-
-void
-gimple_ranger::update_stmt (gimple *s)
-{
-  tree lhs = gimple_get_lhs (s);
-  if (!lhs || !gimple_range_ssa_p (lhs))
-return;
-  Value_Range r (TREE_TYPE (lhs));
-  // Only update if it already had a value.
-  if (m_cache.get_global_range (r, lhs))
-{
-  // Re-calculate a new value using just cache values.
-  Value_Range tmp (TREE_TYPE (lhs));
-  fold_using_range f;
-  fur_stmt src (s, _cache);
-  f.fold_stmt (tmp, s, src, lhs);
-
-  // Combine the new value with the old value to check for a change.
-  if (r.intersect (tmp))
-   {
- if (dump_file && (dump_flags & TDF_DETAILS))
-   {
- print_generic_expr (dump_file, lhs, TDF_SLIM);
- fprintf (dump_file, " : global value re-evaluated to ");
- r.dump (dump_file);
- fputc ('\n', dump_file);
-   }
- m_cache.set_global_range (lhs, r);
-   }
-}
-}
-
  // This routine will export whatever global ranges are known to GCC
  // SSA_RANGE_NAME_INFO and SSA_NAME_PTR_INFO fields.
  
diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h

index 5807a2b80e5..6b0835c4ca1 100644
--- a/gcc/gimple-range.h
+++ b/gcc/gimple-range.h
@@ -52,7 +52,6 @@ public:
virtual bool range_of_stmt (vrange , gimple *, tree name = NULL) override;
virtual bool range_of_expr (vrange , tree name, gimple * = NULL) override;
virtual bool range_on_edge (vrange , edge e, tree name) override;
-  virtual void update_stmt (gimple *) override;
void range_on_entry (vrange , basic_block bb, tree name);
void range_on_exit (vrange , basic_block bb, tree name);
void export_global_ranges ();
diff --git a/gcc/tree-ssa-operands.cc b/gcc/tree-ssa-operands.cc
index 57e393ae164..b0516a00d64 100644
--- a/gcc/tree-ssa-operands.cc
+++ b/gcc/tree-ssa-operands.cc
@@ -30,7 +30,6 @@ along with GCC; see the file COPYING3.  If not see
  #include "stmt.h"
  #include "print-tree.h"
  #include "dumpfile.h"
-#include "value-query.h"
  
  
  /* This file contains the code required to manage the operands cache of the

@@ -1146,8 +1145,6 @@ update_stmt_operands (struct function *fn, gimple *stmt)
gcc_assert (gimple_modified_p (stmt));
operands_scanner (fn, stmt).build_ssa_operands ();
gimple_set_modified (stmt, false);
-  // Inform the active range query an update has happened.
-  get_range_query (fn)->update_stmt (stmt);
  
timevar_pop (TV_TREE_OPS);

  }
diff --git a/gcc/value-query.h b/gcc/value-query.h
index 429446b32eb..0a6f18b03f6 100644
--- a/gcc/value-query.h
+++ b/gcc/value-query.h
@@ -71,9 +71,6 @@ public:
virtual bool range_on_edge (vrange , edge, tree expr);
virtual bool range_of_stmt (vrange , gimple *, tree name = NULL);
  
-  // When the IL in a stmt is changed, call this for better results.

-  virtual void update_stmt (gimple *) { }
-
// Query if there is any relation between SSA1 and SSA2.
relation_kind query_relation (gimple *s, tree ssa1, tree ssa2,
bool get_range 

[COMMITTED] Use range_compatible_p in check_operands_p.

2023-12-01 Thread Andrew MacLeod
Comments in PR 112788 correctly brought up that the new 
check_operands_p() routine is directly checking precision rather than 
calling range_compatible_p().


Most earlier iterations of the original patch had ranges as arguments, 
and it wasn't primarily a CHECKING_P only call then...   Regardless, it 
makes total sense to call range_compatible_p so this patch does exactly 
that.  It required moving range_compatible_p() into value-range.h and 
then adjusting each check_operands_p() routine.


Now range type compatibility is centralized again :-P

Bootstraps on x86_64-pc-linux-gnu with no new regressions.

Andrew

From c6bb413eeb9d13412e8101e3029099d7fd746708 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Fri, 1 Dec 2023 11:15:33 -0500
Subject: [PATCH] Use range_compatible_p in check_operands_p.

Instead of directly checking type precision, check_operands_p should
invoke range_compatible_p to keep the range checking centralized.

	* gimple-range-fold.h (range_compatible_p): Relocate.
	* value-range.h (range_compatible_p): Here.
	* range-op-mixed.h (operand_equal::operand_check_p): Call
	range_compatible_p rather than comparing precision.
	(operand_not_equal::operand_check_p): Ditto.
	(operand_not_lt::operand_check_p): Ditto.
	(operand_not_le::operand_check_p): Ditto.
	(operand_not_gt::operand_check_p): Ditto.
	(operand_not_ge::operand_check_p): Ditto.
	(operand_plus::operand_check_p): Ditto.
	(operand_abs::operand_check_p): Ditto.
	(operand_minus::operand_check_p): Ditto.
	(operand_negate::operand_check_p): Ditto.
	(operand_mult::operand_check_p): Ditto.
	(operand_bitwise_not::operand_check_p): Ditto.
	(operand_bitwise_xor::operand_check_p): Ditto.
	(operand_bitwise_and::operand_check_p): Ditto.
	(operand_bitwise_or::operand_check_p): Ditto.
	(operand_min::operand_check_p): Ditto.
	(operand_max::operand_check_p): Ditto.
	* range-op.cc (operand_lshift::operand_check_p): Ditto.
	(operand_rshift::operand_check_p): Ditto.
	(operand_logical_and::operand_check_p): Ditto.
	(operand_logical_or::operand_check_p): Ditto.
	(operand_logical_not::operand_check_p): Ditto.
---
 gcc/gimple-range-fold.h | 12 
 gcc/range-op-mixed.h| 43 -
 gcc/range-op.cc | 12 +---
 gcc/value-range.h   | 11 +++
 4 files changed, 33 insertions(+), 45 deletions(-)

diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h
index fcbe1626790..0094b4e3f35 100644
--- a/gcc/gimple-range-fold.h
+++ b/gcc/gimple-range-fold.h
@@ -89,18 +89,6 @@ gimple_range_ssa_p (tree exp)
   return NULL_TREE;
 }
 
-// Return true if TYPE1 and TYPE2 are compatible range types.
-
-inline bool
-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_PRECISION (type1) == TYPE_PRECISION (type2)
-	  && TYPE_SIGN (type1) == TYPE_SIGN (type2));
-}
-
 // Source of all operands for fold_using_range and gori_compute.
 // It abstracts out the source of an operand so it can come from a stmt or
 // and edge or anywhere a derived class of fur_source wants.
diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 4386a68e946..7e3ee17ccbd 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -140,7 +140,7 @@ public:
 		   const irange ) const final override;
   // Check op1 and op2 for compatibility.
   bool operand_check_p (tree, tree t1, tree t2) const final override
-{ return TYPE_PRECISION (t1) == TYPE_PRECISION (t2); }
+{ return range_compatible_p (t1, t2); }
 };
 
 class operator_not_equal : public range_operator
@@ -179,7 +179,7 @@ public:
 		   const irange ) const final override;
   // Check op1 and op2 for compatibility.
   bool operand_check_p (tree, tree t1, tree t2) const final override
-{ return TYPE_PRECISION (t1) == TYPE_PRECISION (t2); }
+{ return range_compatible_p (t1, t2); }
 };
 
 class operator_lt :  public range_operator
@@ -215,7 +215,7 @@ public:
 		   const irange ) const final override;
   // Check op1 and op2 for compatibility.
   bool operand_check_p (tree, tree t1, tree t2) const final override
-{ return TYPE_PRECISION (t1) == TYPE_PRECISION (t2); }
+{ return range_compatible_p (t1, t2); }
 };
 
 class operator_le :  public range_operator
@@ -254,7 +254,7 @@ public:
 		   const irange ) const final override;
   // Check op1 and op2 for compatibility.
   bool operand_check_p (tree, tree t1, tree t2) const final override
-{ return TYPE_PRECISION (t1) == TYPE_PRECISION (t2); }
+{ return range_compatible_p (t1, t2); }
 };
 
 class operator_gt :  public range_operator
@@ -292,7 +292,7 @@ public:
 		   const irange ) const final override;
   // Check op1 and op2 for compatibility.
   bool operand_check_p (tree, tree t1, tree t2) const final override
-{ return TYPE_P

[COMMITTED 2/2] PR tree-optimization/111922 - Check operands before invoking fold_range.

2023-11-29 Thread Andrew MacLeod
This patch utilizes the new check_operands_p() routine in range-ops to 
verify the operands are compatible before IPA tries to call 
fold_range().   I do not know if there are other places in IPA that 
should be checking this, but we have a bug report for this place at least.


The other option would be to have fold_range simply return false when 
operands don't match, but then we lose the compile time checking that 
everything is as it should be and bugs may sneak thru.


Bootstraps on x86_64-pc-linux-gnu with  no regressions. Committed.

Andrew


From 5f0c0f02702eba568374a7d82ec9463edd1a905c Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Tue, 28 Nov 2023 13:02:35 -0500
Subject: [PATCH 2/2] Check operands before invoking fold_range.

Call check_operands_p before fold_range to make sure it is a valid operation.

	PR tree-optimization/111922
	gcc/
	* ipa-cp.cc (ipa_vr_operation_and_type_effects): Check the
	operands are valid before calling fold_range.

	gcc/testsuite/
	* gcc.dg/pr111922.c: New.
---
 gcc/ipa-cp.cc   |  3 ++-
 gcc/testsuite/gcc.dg/pr111922.c | 29 +
 2 files changed, 31 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr111922.c

diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
index 34fae065454..649ad536161 100644
--- a/gcc/ipa-cp.cc
+++ b/gcc/ipa-cp.cc
@@ -1926,7 +1926,8 @@ ipa_vr_operation_and_type_effects (vrange _vr,
   Value_Range varying (dst_type);
   varying.set_varying (dst_type);
 
-  return (handler.fold_range (dst_vr, dst_type, src_vr, varying)
+  return (handler.operand_check_p (dst_type, src_type, dst_type)
+	  && handler.fold_range (dst_vr, dst_type, src_vr, varying)
 	  && !dst_vr.varying_p ()
 	  && !dst_vr.undefined_p ());
 }
diff --git a/gcc/testsuite/gcc.dg/pr111922.c b/gcc/testsuite/gcc.dg/pr111922.c
new file mode 100644
index 000..4f429d741c7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr111922.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-tree-fre" } */
+
+void f2 (void);
+void f4 (int, int, int);
+struct A { int a; };
+struct B { struct A *b; int c; } v;
+
+static int
+f1 (x, y)
+  struct C *x;
+  struct A *y;
+{
+  (v.c = v.b->a) || (v.c = v.b->a);
+  f2 ();
+}
+
+static void
+f3 (int x, int y)
+{
+  int b = f1 (0, ~x);
+  f4 (0, 0, v.c);
+}
+
+void
+f5 (void)
+{
+  f3 (0, 0);
+}
-- 
2.41.0



[COMMITTED 1/2] Add operand_check_p to range-ops.

2023-11-29 Thread Andrew MacLeod
I've been going back and forth with this for the past week, and finally 
settled on a solution


This patch adds an operand_check_p() (lhs_type, op1_type, op2_type) 
method to range_ops which will confirm whether the types of the operands 
being passed to fold_range, op1_range, and op2_range  are properly 
compatible.   For range-ops this basically means the precision matches.


It was a bit tricky to do it any other way because various operations 
allow different precision or even different types in some operand positions.


This patch sets up the operand_check_p to return true by default, which 
means there is no variation from what we do today.  However, I have gone 
in to all the integral/mixed range operators, and added checks for 
things like  X = Y + Z requiring the precision to be the same for all 3 
operands.   however x = y && z only requires OP1 and OP2 to be the same 
precision, and  x = ~y only requires the LHS and OP1 to match.


This call is utilized in a gcc_assert when CHECKING_P is on for 
fold_range(), op1_range() and op2_range() to provide compilation time 
verification while not costing anything for a release build.


Bootstraps on x86_64-pc-linux-gnu with no regressions. committed.

Andrew

From 9f1149ef823b64ead6115f79f99ddf8eead1c2f4 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Tue, 28 Nov 2023 09:39:30 -0500
Subject: [PATCH 1/2] Add operand_check_p to range-ops.

Add an optional method to verify operands are compatible, and check
the operands before all range operations.

	* range-op-mixed.h (operator_equal::operand_check_p): New.
	(operator_not_equal::operand_check_p): New.
	(operator_lt::operand_check_p): New.
	(operator_le::operand_check_p): New.
	(operator_gt::operand_check_p): New.
	(operator_ge::operand_check_p): New.
	(operator_plus::operand_check_p): New.
	(operator_abs::operand_check_p): New.
	(operator_minus::operand_check_p): New.
	(operator_negate::operand_check_p): New.
	(operator_mult::operand_check_p): New.
	(operator_bitwise_not::operand_check_p): New.
	(operator_bitwise_xor::operand_check_p): New.
	(operator_bitwise_and::operand_check_p): New.
	(operator_bitwise_or::operand_check_p): New.
	(operator_min::operand_check_p): New.
	(operator_max::operand_check_p): New.
	* range-op.cc (range_op_handler::fold_range): Check operand
	parameter types.
	(range_op_handler::op1_range): Ditto.
	(range_op_handler::op2_range): Ditto.
	(range_op_handler::operand_check_p): New.
	(range_operator::operand_check_p): New.
	(operator_lshift::operand_check_p): New.
	(operator_rshift::operand_check_p): New.
	(operator_logical_and::operand_check_p): New.
	(operator_logical_or::operand_check_p): New.
	(operator_logical_not::operand_check_p): New.
	* range-op.h (range_operator::operand_check_p): New.
	(range_op_handler::operand_check_p): New.
---
 gcc/range-op-mixed.h | 63 +---
 gcc/range-op.cc  | 53 ++---
 gcc/range-op.h   |  5 
 3 files changed, 114 insertions(+), 7 deletions(-)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 45e11df57df..4386a68e946 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -138,6 +138,9 @@ public:
   const frange &) const final override;
   void update_bitmask (irange , const irange ,
 		   const irange ) const final override;
+  // Check op1 and op2 for compatibility.
+  bool operand_check_p (tree, tree t1, tree t2) const final override
+{ return TYPE_PRECISION (t1) == TYPE_PRECISION (t2); }
 };
 
 class operator_not_equal : public range_operator
@@ -174,6 +177,9 @@ public:
   const frange &) const final override;
   void update_bitmask (irange , const irange ,
 		   const irange ) const final override;
+  // Check op1 and op2 for compatibility.
+  bool operand_check_p (tree, tree t1, tree t2) const final override
+{ return TYPE_PRECISION (t1) == TYPE_PRECISION (t2); }
 };
 
 class operator_lt :  public range_operator
@@ -207,6 +213,9 @@ public:
   const frange &) const final override;
   void update_bitmask (irange , const irange ,
 		   const irange ) const final override;
+  // Check op1 and op2 for compatibility.
+  bool operand_check_p (tree, tree t1, tree t2) const final override
+{ return TYPE_PRECISION (t1) == TYPE_PRECISION (t2); }
 };
 
 class operator_le :  public range_operator
@@ -243,6 +252,9 @@ public:
   const frange &) const final override;
   void update_bitmask (irange , const irange ,
 		   const irange ) const final override;
+  // Check op1 and op2 for compatibility.
+  bool operand_check_p (tree, tree t1, tree t2) const final override
+{ return TYPE_PRECISION (t1) == TYPE_PRECISION (t2); }
 };
 
 class operator_gt :  public range_operator
@@ -278,6 +290,9 @@ public:
   const frange &) const final override;
   void update_bitmask (irange , const irange ,
 		   const irange ) const final override;
+  // Check op1 and op2 for compatibil

[PATCH] PR tree-optimization/111922 - Ensure wi_fold arguments match precisions.

2023-11-24 Thread Andrew MacLeod
This problem here is that IPA is calling something like operator_minus 
with 2 operands, one with precision 32 (int) and one with precision 64 
(pointer). There are various ways this can happen as mentioned in the PR.


Regardless of whether IPA should be doing promoting types or not calling 
into range-ops,  range-ops does not support mis-matched precision in its 
arguments and it does not have to context to know what should be 
promoted/changed.   It is expected that the caller will ensure the 
operands are compatible.


However, It is not really practical for the caller to know this with 
more context. Some operations support different precision or even 
types.. ie, shifts, or casts, etc.    It seems silly to require IPA to 
have a big switch to see what the tree code is and match up/promote/or 
bail if operands don't match...


Range-ops routines probably shouldn't crash when this happens either, so 
this patch takes the conservative approach  and returns VARYING if there 
is a mismatch in the arguments precision.


Fixes the problem and bootstraps on x86_64-pc-linux-gnu with no new 
regressions.


OK for trunk?

Andrew

PS  If you would rather we trap in these cases and fix the callers, then 
I'd suggest we change these to checking_asserts instead.  I have also 
prepared a version that does a gcc_checking_assert instead of returning 
varying and done a bootstrap/testrun.    Of course, the callers will 
have to be changed..


It bootstraps fine in that variation too, and all the testcases (except  
this one of course) pass.   Its clearly not a common occurrence, and my 
inclination is to apply this patch so we silently move on and simply 
don't provide useful range info.. that is all the callers in these cases 
are likely to do anyway...





From f9cddb4cf931826f09197ed0fc2d6d64e6ccc3c3 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Wed, 22 Nov 2023 17:24:42 -0500
Subject: [PATCH] Ensure wi_fold arguments match precisions.

Return VARYING if any of the required operands or types to wi_fold do
not match expected precisions.

	PR tree-optimization/111922
	gcc/
	* range-op.cc (operator_plus::wi_fold): Check that precisions of
	arguments and result type match.
	(operator_widen_plus_signed::wi_fold): Ditto.
	(operator_widen_plus_unsigned::wi_fold): Ditto.
	(operator_minus::wi_fold): Ditto.
	(operator_min::wi_fold): Ditto.
	(operator_max::wi_fold): Ditto.
	(operator_mult::wi_fold): Ditto.
	(operator_widen_mult_signed::wi_fold): Ditto.
	(operator_widen_mult_unsigned::wi_fold): Ditto.
	(operator_div::wi_fold): Ditto.
	(operator_lshift::wi_fold): Ditto.
	(operator_rshift::wi_fold): Ditto.
	(operator_bitwise_and::wi_fold): Ditto.
	(operator_bitwise_or::wi_fold): Ditto.
	(operator_bitwise_xor::wi_fold): Ditto.
	(operator_trunc_mod::wi_fold): Ditto.
	(operator_abs::wi_fold): Ditto.
	(operator_absu::wi_fold): Ditto.

	gcc/testsuite/
	* gcc.dg/pr111922.c: New.
---
 gcc/range-op.cc | 119 
 gcc/testsuite/gcc.dg/pr111922.c |  29 
 2 files changed, 148 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/pr111922.c

diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 6137f2aeed3..ddb7339c075 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -1651,6 +1651,13 @@ operator_plus::wi_fold (irange , tree type,
 			const wide_int _lb, const wide_int _ub,
 			const wide_int _lb, const wide_int _ub) const
 {
+  // This operation requires all types to be the same precision.
+  if (lh_lb.get_precision () != rh_lb.get_precision ()
+  || lh_lb.get_precision () != TYPE_PRECISION (type))
+{
+  r.set_varying (type);
+  return;
+}
   wi::overflow_type ov_lb, ov_ub;
   signop s = TYPE_SIGN (type);
   wide_int new_lb = wi::add (lh_lb, rh_lb, s, _lb);
@@ -1797,6 +1804,12 @@ operator_widen_plus_signed::wi_fold (irange , tree type,
  const wide_int _lb,
  const wide_int _ub) const
 {
+  // This operation requires both sides to be the same precision.
+  if (lh_lb.get_precision () != rh_lb.get_precision ())
+{
+  r.set_varying (type);
+  return;
+}
wi::overflow_type ov_lb, ov_ub;
signop s = TYPE_SIGN (type);
 
@@ -1830,6 +1843,12 @@ operator_widen_plus_unsigned::wi_fold (irange , tree type,
    const wide_int _lb,
    const wide_int _ub) const
 {
+  // This operation requires both sides to be the same precision.
+  if (lh_lb.get_precision () != rh_lb.get_precision ())
+{
+  r.set_varying (type);
+  return;
+}
wi::overflow_type ov_lb, ov_ub;
signop s = TYPE_SIGN (type);
 
@@ -1858,6 +1877,14 @@ operator_minus::wi_fold (irange , tree type,
 			 const wide_int _lb, const wide_int _ub,
 			 const wide_int _lb, const wide_int _ub) const
 {
+  // This operation requires all ranges and types to be the same precision.
+  if (lh_lb.get_precision () != rh_lb.get_precision ()
+  || lh_lb.get_precision () != TYPE_PRECISION (type))
+{
+  r.set_varying (type);
+  return

Re: Propagate value ranges of return values

2023-11-20 Thread Andrew MacLeod



On 11/18/23 20:21, Jan Hubicka wrote:

Hi,
this patch implements very basic propaation of return value ranges from VRP
pass.  This helps std::vector's push_back since we work out value range of
allocated block.  This propagates only within single translation unit.  I hoped
we will also do the propagation at WPA stage, but that needs more work on
ipa-cp side.

I also added code auto-detecting return_nonnull and corresponding 
-Wsuggest-attribute

Variant of this patch bootstrapped/regtested x86_64-linux, testing with
this version is running.  I plan to commit the patch at Monday provided
there are no issues.


I see no obvious issues with the ranger/vrp changes...

My only comment is that execute_ranger_vrp is called 3 times... EVRP,  
VRP1 and VRP2.. perhaps more someday.  As long as that is OK with the 
call to warn_function_returns_nonnull().


Andrew




[COMMITTED] PR tree-optimization/112509 - Use case label type to create case range.

2023-11-14 Thread Andrew MacLeod
We should create a range from the case labels directly, and then cast it 
to the type we care about rather than trying to convert it to the switch 
index type and then the type we care about.


Bootstraps on x86_64-pc-linux-gnu  with no regressions.   Pushed.

Andrew
From 4553a0496458a712dfd2f04b9803b611fdc777cc Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Mon, 13 Nov 2023 09:58:10 -0500
Subject: [PATCH] Use case label type to create case range.

Create a range from the label type, and cast it to the required type.

	PR tree-optimization/112509
	gcc/
	* tree-vrp.cc (find_case_label_range): Create range from case labels.

	gcc/testsuite/
	* gcc.dg/pr112509.c: New.
---
 gcc/testsuite/gcc.dg/pr112509.c | 22 ++
 gcc/tree-vrp.cc |  6 +-
 2 files changed, 23 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr112509.c

diff --git a/gcc/testsuite/gcc.dg/pr112509.c b/gcc/testsuite/gcc.dg/pr112509.c
new file mode 100644
index 000..b733780bdc7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr112509.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-tree-vrp -fno-tree-fre -fno-tree-forwprop" } */
+
+struct S {
+  unsigned j : 3;
+};
+int k, l, m_1 = {0};
+void f(int l, struct S x) {
+  unsigned int k_1;
+  while (m_1 % 8) switch (x.j) {
+case 1:
+case 3:
+case 4:
+case 6:
+case 2:
+case 5: l = m_1;
+case 7:
+case 0: k_1 = 0;
+default: break;
+}
+}
+void foo(struct S x) { f(l, x); }
diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc
index 19d8f995d70..917fa873714 100644
--- a/gcc/tree-vrp.cc
+++ b/gcc/tree-vrp.cc
@@ -886,8 +886,6 @@ find_case_label_range (gswitch *switch_stmt, const irange *range_of_op)
   size_t i, j;
   tree op = gimple_switch_index (switch_stmt);
   tree type = TREE_TYPE (op);
-  unsigned prec = TYPE_PRECISION (type);
-  signop sign = TYPE_SIGN (type);
   tree tmin = wide_int_to_tree (type, range_of_op->lower_bound ());
   tree tmax = wide_int_to_tree (type, range_of_op->upper_bound ());
   find_case_label_range (switch_stmt, tmin, tmax, , );
@@ -900,9 +898,7 @@ find_case_label_range (gswitch *switch_stmt, const irange *range_of_op)
 	= CASE_HIGH (label) ? CASE_HIGH (label) : CASE_LOW (label);
   wide_int wlow = wi::to_wide (CASE_LOW (label));
   wide_int whigh = wi::to_wide (case_high);
-  int_range_max label_range (type,
- wide_int::from (wlow, prec, sign),
- wide_int::from (whigh, prec, sign));
+  int_range_max label_range (TREE_TYPE (case_high), wlow, whigh);
   if (!types_compatible_p (label_range.type (), range_of_op->type ()))
 	range_cast (label_range, range_of_op->type ());
   label_range.intersect (*range_of_op);
-- 
2.41.0



[PATCH][GCC13] PR tree-optimization/105834 - Choose better initial values for ranger.

2023-11-06 Thread Andrew MacLeod

As requested porting this patch from trunk resolves this PR in GCC 13.

Bootstraps on x86_64-pc-linux-gnu with no regressions.  OK for the gcc 
13 branch?


Andrew



From 0182a25607fa353274c27ec57ca497c00f1d1b76 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Mon, 6 Nov 2023 11:33:32 -0500
Subject: [PATCH] Choose better initial values for ranger.

Instead of defaulting to VARYING, fold the stmt using just global ranges.

	PR tree-optimization/105834
	gcc/
	* gimple-range-cache.cc (ranger_cache::get_global_range): Call
	fold_range with global query to choose an initial value.

	gcc/testsuite/
	* gcc.dg/pr105834.c
---
 gcc/gimple-range-cache.cc   | 17 -
 gcc/testsuite/gcc.dg/pr105834.c | 17 +
 2 files changed, 33 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr105834.c

diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index e4e75943632..b09df6c81bf 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -846,7 +846,22 @@ ranger_cache::get_global_range (vrange , tree name, bool _p)
 		|| m_temporal->current_p (name, m_gori.depend1 (name),
 	  m_gori.depend2 (name));
   else
-m_globals.set_global_range (name, r);
+{
+  // If no global value has been set and value is VARYING, fold the stmt
+  // using just global ranges to get a better initial value.
+  // After inlining we tend to decide some things are constant, so
+  // do not do this evaluation after inlining.
+  if (r.varying_p () && !cfun->after_inlining)
+	{
+	  gimple *s = SSA_NAME_DEF_STMT (name);
+	  if (gimple_get_lhs (s) == name)
+	{
+	  if (!fold_range (r, s, get_global_range_query ()))
+		gimple_range_global (r, name);
+	}
+	}
+  m_globals.set_global_range (name, r);
+}
 
   // If the existing value was not current, mark it as always current.
   if (!current_p)
diff --git a/gcc/testsuite/gcc.dg/pr105834.c b/gcc/testsuite/gcc.dg/pr105834.c
new file mode 100644
index 000..d0eda03ef8b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr105834.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+static int a, b;
+
+void foo();
+
+int main() {
+for (int c = 0; c < 2; c = c + (unsigned)3)
+if (a)
+for (;;)
+if (c > 0)
+b = 0;
+if (b)
+foo();
+}
+/* { dg-final { scan-tree-dump-not "foo" "optimized" } }  */
-- 
2.41.0



[COMMITTED 2/2] PR tree-optimization/111766 - Adjust operators equal and not_equal to check bitmasks against constants

2023-11-03 Thread Andrew MacLeod
When we compare a range against a constant for equality or inequality, 
there is currently no attempt made to utilize the known bits.


This patch adds a method to the irange_bitmask class to ask if a 
specific value satisfies the known bit pattern.  Operators equal and 
not_equal then utilize it when comparing to a constant eliiminating a 
class of cases we don;t currently get. ie.


if (x & 1) return;
if (x == 97657) foo()

will eliminate the call to foo, even though we do not remove all the odd 
numbers from the range.  THe bit pattern comparison for
  [irange] unsigned int [0, 0] [2, +INF] MASK 0xfffe VALUE 0x1  
will indicate that any even constants will be false.


Bootstraps on x86_64-pc-linux-gnu with no regressions.  Pushed.

Andrew

From eb899fee35b8326b2105c04f58fd58bbdeca9d3b Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Wed, 25 Oct 2023 09:46:50 -0400
Subject: [PATCH 2/2] Adjust operators equal and not_equal to check bitmasks
 against constants

Check to see if a comparison to a constant can be determined to always
be not-equal based on the bitmask.

	PR tree-optimization/111766
	gcc/
	* range-op.cc (operator_equal::fold_range): Check constants
	against the bitmask.
	(operator_not_equal::fold_range): Ditto.
	* value-range.h (irange_bitmask::member_p): New.

	gcc/testsuite/
	* gcc.dg/pr111766.c: New.
---
 gcc/range-op.cc | 20 
 gcc/testsuite/gcc.dg/pr111766.c | 13 +
 gcc/value-range.h   | 14 ++
 3 files changed, 43 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr111766.c

diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 33b193be7d0..6137f2aeed3 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -931,8 +931,9 @@ operator_equal::fold_range (irange , tree type,
 
   // We can be sure the values are always equal or not if both ranges
   // consist of a single value, and then compare them.
-  if (wi::eq_p (op1.lower_bound (), op1.upper_bound ())
-  && wi::eq_p (op2.lower_bound (), op2.upper_bound ()))
+  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 (type);
@@ -947,6 +948,11 @@ operator_equal::fold_range (irange , tree type,
   tmp.intersect (op2);
   if (tmp.undefined_p ())
 	r = range_false (type);
+  // Check if a constant cannot satisfy the bitmask requirements.
+  else if (op2_const && !op1.get_bitmask ().member_p (op2.lower_bound ()))
+	 r = range_false (type);
+  else if (op1_const && !op2.get_bitmask ().member_p (op1.lower_bound ()))
+	 r = range_false (type);
   else
 	r = range_true_and_false (type);
 }
@@ -1033,8 +1039,9 @@ operator_not_equal::fold_range (irange , tree type,
 
   // We can be sure the values are always equal or not if both ranges
   // consist of a single value, and then compare them.
-  if (wi::eq_p (op1.lower_bound (), op1.upper_bound ())
-  && wi::eq_p (op2.lower_bound (), op2.upper_bound ()))
+  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 (type);
@@ -1049,6 +1056,11 @@ operator_not_equal::fold_range (irange , tree type,
   tmp.intersect (op2);
   if (tmp.undefined_p ())
 	r = range_true (type);
+  // Check if a constant cannot satisfy the bitmask requirements.
+  else if (op2_const && !op1.get_bitmask ().member_p (op2.lower_bound ()))
+	 r = range_true (type);
+  else if (op1_const && !op2.get_bitmask ().member_p (op1.lower_bound ()))
+	 r = range_true (type);
   else
 	r = range_true_and_false (type);
 }
diff --git a/gcc/testsuite/gcc.dg/pr111766.c b/gcc/testsuite/gcc.dg/pr111766.c
new file mode 100644
index 000..c27a029c772
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr111766.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int
+foo3n(int c, int bb)
+{
+  if ((bb & ~3)!=0) __builtin_unreachable(); // bb = [0,3]
+  if ((bb & 1)==0) __builtin_unreachable(); // bb&1 == 0 // [0],[3]
+  if(bb == 2) __builtin_trap();
+  return bb;
+}
+
+/* { dg-final { scan-tree-dump-not "trap" "evrp" } } */
diff --git a/gcc/value-range.h b/gcc/value-range.h
index 84f65ffb591..330e6f70c6b 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -139,6 +139,7 @@ public:
   void verify_mask () const;
   void dump (FILE *) const;
 
+  bool member_p (const wide_int ) const;
   void adjust_range (irange ) const;
 
   // Convenience functions for nonzero bitmask compatibility.
@@ -202,6 +203,19 @@ irange_bitmask::set_nonzero_bits (const wide_i

[COMMITTED 1/2] Remove simple ranges from trailing zero bitmasks.

2023-11-03 Thread Andrew MacLeod
WHen we set bitmasks indicating known zero or one bits, we see some 
"obvious" things once in a while that are easy to prevent. ie


unsigned int [2, +INF] MASK 0xfffe VALUE 0x1

the range [2, 2] is obviously impossible since the final bit must be a 
one.   This doesn't usually cause us too much trouble, but the 
subsequent patch triggers some more interesting situations in which it 
helps to remove the obvious ranges when we have  mask that is trailing 
zeros.


Its too much of a performance impact to constantly be checking the range 
every time we set the bitmask, but it turns out that if we simply try to 
take care of it during intersection operations (which happen at most key 
times, like changing an existing value), the impact is pretty minimal.. 
like 0.6% of VRP.


This patch looks for trailing zeros in the mask, and replaces the low 
end range covered by those bits with those bits from the value field.


Bootstraps on build-x86_64-pc-linux-gnu with no regressions. Pushed.

Andrew



From b20f1dce46fb8bb1b142e9087530e546a40edec8 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Tue, 31 Oct 2023 11:51:34 -0400
Subject: [PATCH 1/2] Remove simple ranges from trailing zero bitmasks.

During the intersection operation, it can be helpful to remove any
low-end ranges when the bitmask has trailing zeros.  This prevents
obviously incorrect ranges from appearing without requiring a bitmask
check.

	* value-range.cc (irange_bitmask::adjust_range): New.
	(irange::intersect_bitmask): Call adjust_range.
	* value-range.h (irange_bitmask::adjust_range): New prototype.
---
 gcc/value-range.cc | 30 ++
 gcc/value-range.h  |  2 ++
 2 files changed, 32 insertions(+)

diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index fcf53efa1dd..a1e72c78f8b 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -1857,6 +1857,35 @@ irange::get_bitmask_from_range () const
   return irange_bitmask (wi::zero (prec), min | xorv);
 }
 
+// Remove trailing ranges that this bitmask indicates can't exist.
+
+void
+irange_bitmask::adjust_range (irange ) const
+{
+  if (unknown_p () || r.undefined_p ())
+return;
+
+  int_range_max range;
+  tree type = r.type ();
+  int prec = TYPE_PRECISION (type);
+  // If there are trailing zeros, create a range representing those bits.
+  gcc_checking_assert (m_mask != 0);
+  int z = wi::ctz (m_mask);
+  if (z)
+{
+  wide_int ub = (wi::one (prec) << z) - 1;
+  range = int_range<5> (type, wi::zero (prec), ub);
+  // Then remove the specific value these bits contain from the range.
+  wide_int value = m_value & ub;
+  range.intersect (int_range<2> (type, value, value, VR_ANTI_RANGE));
+  // Inverting produces a list of ranges which can be valid.
+  range.invert ();
+  // And finally select R from only those valid values.
+  r.intersect (range);
+  return;
+}
+}
+
 // If the the mask can be trivially converted to a range, do so and
 // return TRUE.
 
@@ -2002,6 +2031,7 @@ irange::intersect_bitmask (const irange )
 
   if (!set_range_from_bitmask ())
 normalize_kind ();
+  m_bitmask.adjust_range (*this);
   if (flag_checking)
 verify_range ();
   return true;
diff --git a/gcc/value-range.h b/gcc/value-range.h
index e9d81d22cd0..84f65ffb591 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -139,6 +139,8 @@ public:
   void verify_mask () const;
   void dump (FILE *) const;
 
+  void adjust_range (irange ) const;
+
   // Convenience functions for nonzero bitmask compatibility.
   wide_int get_nonzero_bits () const;
   void set_nonzero_bits (const wide_int );
-- 
2.41.0



[COMMITTED] Faster irange union for appending ranges.

2023-10-25 Thread Andrew MacLeod
Its a common idiom to build a range by unioning other ranges into 
another one.  If this is done sequentially, those new ranges can be 
simply appended to the end of the existing range, avoiding some 
expensive processing fro the general case.


This patch identifies and optimizes this situation.  The result is a 
2.1% speedup in VRP and a 0.8% speedup in threading, with a overall 
compile time improvement of 0.14% across the GCC build.


Bootstrapped on  x86_64-pc-linux-gnu with no regressions. Pushed.

Andrew
commit f7dbf6230453c76a19921607601eff968bb70169
Author: Andrew MacLeod 
Date:   Mon Oct 23 14:52:45 2023 -0400

Faster irange union for appending ranges.

A common pattern to to append a range to an existing range via union.
This optimizes that process.

* value-range.cc (irange::union_append): New.
(irange::union_): Call union_append when appropriate.
* value-range.h (irange::union_append): New prototype.

diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index f507ec57536..fcf53efa1dd 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -1291,6 +1291,45 @@ irange::irange_single_pair_union (const irange )
   return true;
 }
 
+// Append R to this range, knowing that R occurs after all of these subranges.
+// Return TRUE as something must have changed.
+
+bool
+irange::union_append (const irange )
+{
+  // Check if the first range in R is an immmediate successor to the last
+  // range, ths requiring a merge.
+  signop sign = TYPE_SIGN (m_type);
+  wide_int lb = r.lower_bound ();
+  wide_int ub = upper_bound ();
+  unsigned start = 0;
+  if (widest_int::from (ub, sign) + 1
+  == widest_int::from (lb, sign))
+{
+  m_base[m_num_ranges * 2 - 1] = r.m_base[1];
+  start = 1;
+}
+  maybe_resize (m_num_ranges + r.m_num_ranges - start);
+  for ( ; start < r.m_num_ranges; start++)
+{
+  // Merge the last ranges if it exceeds the maximum size.
+  if (m_num_ranges + 1 > m_max_ranges)
+   {
+ m_base[m_max_ranges * 2 - 1] = r.m_base[r.m_num_ranges * 2 - 1];
+ break;
+   }
+  m_base[m_num_ranges * 2] = r.m_base[start * 2];
+  m_base[m_num_ranges * 2 + 1] = r.m_base[start * 2 + 1];
+  m_num_ranges++;
+}
+
+  if (!union_bitmask (r))
+normalize_kind ();
+  if (flag_checking)
+verify_range ();
+  return true;
+}
+
 // Return TRUE if anything changes.
 
 bool
@@ -1322,6 +1361,11 @@ irange::union_ (const vrange )
   if (m_num_ranges == 1 && r.m_num_ranges == 1)
 return irange_single_pair_union (r);
 
+  signop sign = TYPE_SIGN (m_type);
+  // Check for an append to the end.
+  if (m_kind == VR_RANGE && wi::gt_p (r.lower_bound (), upper_bound (), sign))
+return union_append (r);
+
   // If this ranges fully contains R, then we need do nothing.
   if (irange_contains_p (r))
 return union_bitmask (r);
@@ -1340,7 +1384,6 @@ irange::union_ (const vrange )
   // [Xi,Yi]..[Xn,Yn]  U  [Xj,Yj]..[Xm,Ym]   -->  [Xk,Yk]..[Xp,Yp]
   auto_vec res (m_num_ranges * 2 + r.m_num_ranges * 2);
   unsigned i = 0, j = 0, k = 0;
-  signop sign = TYPE_SIGN (m_type);
 
   while (i < m_num_ranges * 2 && j < r.m_num_ranges * 2)
 {
diff --git a/gcc/value-range.h b/gcc/value-range.h
index c00b15194c4..e9d81d22cd0 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -339,6 +339,7 @@ private:
   bool set_range_from_bitmask ();
 
   bool intersect (const wide_int& lb, const wide_int& ub);
+  bool union_append (const irange );
   unsigned char m_num_ranges;
   bool m_resizable;
   unsigned char m_max_ranges;


Re: [COMMITTED] PR tree-optimization/111622 - Do not add partial equivalences with no uses.

2023-10-13 Thread Andrew MacLeod

of course the patch would be handy...


On 10/13/23 09:23, Andrew MacLeod wrote:
Technically PR 111622 exposes a bug in GCC 13, but its been papered 
over on trunk by this:


commit 9ea74d235c7e7816b996a17c61288f02ef767985
Author: Richard Biener 
Date:   Thu Sep 14 09:31:23 2023 +0200
        tree-optimization/111294 - better DCE after forwprop

This removes a lot of dead statements, but those statements were being 
added to the list of partial equivalences and causing some serious 
compile time issues.


Rangers cache loops through equivalences when its propagating on-entry 
values, so if the partial equivalence list is very large, it can 
consume a lot of time.  Typically, partial equivalence lists are 
small.   In this case, a lot of dead stmts were not removed, so there 
was no redundancy elimination and it was causing an issue.   This 
patch actually speeds things up a hair in the normal case too.


Bootstrapped on x86_64-pc-linux-gnu with no regressions.  pushed.

Andrew


From 4eea3c1872a941089cafa105a11d8e40b1a55929 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Thu, 12 Oct 2023 17:06:36 -0400
Subject: [PATCH] Do not add partial equivalences with no uses.

	PR tree-optimization/111622
	* value-relation.cc (equiv_oracle::add_partial_equiv): Do not
	register a partial equivalence if an operand has no uses.
---
 gcc/value-relation.cc | 9 +
 1 file changed, 9 insertions(+)

diff --git a/gcc/value-relation.cc b/gcc/value-relation.cc
index 0326fe7cde6..c0f513a0eb1 100644
--- a/gcc/value-relation.cc
+++ b/gcc/value-relation.cc
@@ -392,6 +392,9 @@ equiv_oracle::add_partial_equiv (relation_kind r, tree op1, tree op2)
   // In either case, if PE2 has an entry, we simply do nothing.
   if (pe2.members)
 	return;
+  // If there are no uses of op2, do not register.
+  if (has_zero_uses (op2))
+	return;
   // PE1 is the LHS and already has members, so everything in the set
   // should be a slice of PE2 rather than PE1.
   pe2.code = pe_min (r, pe1.code);
@@ -409,6 +412,9 @@ equiv_oracle::add_partial_equiv (relation_kind r, tree op1, tree op2)
 }
   if (pe2.members)
 {
+  // If there are no uses of op1, do not register.
+  if (has_zero_uses (op1))
+	return;
   pe1.ssa_base = pe2.ssa_base;
   // If pe2 is a 16 bit value, but only an 8 bit copy, we can't be any
   // more than an 8 bit equivalence here, so choose MIN value.
@@ -418,6 +424,9 @@ equiv_oracle::add_partial_equiv (relation_kind r, tree op1, tree op2)
 }
   else
 {
+  // If there are no uses of either operand, do not register.
+  if (has_zero_uses (op1) || has_zero_uses (op2))
+	return;
   // Neither name has an entry, simply create op1 as slice of op2.
   pe2.code = bits_to_pe (TYPE_PRECISION (TREE_TYPE (op2)));
   if (pe2.code == VREL_VARYING)
-- 
2.41.0



[COMMITTED] [GCC13] PR tree-optimization/111622 - Do not add partial equivalences with no uses.

2023-10-13 Thread Andrew MacLeod
There are a lot of dead statements in this testcase which a casts. These 
were being added to the list of partial equivalences and causing some 
serious compile time issues.


Rangers cache loops through equivalences when its propagating on-entry 
values, so if the partial equivalence list is very large, it can consume 
a lot of time.  Typically, partial equivalence lists are small.   In 
this case, a lot of dead stmts were not removed, so there was no 
redundancy elimination and it was causing an issue.


Bootstrapped on x86_64-pc-linux-gnu with no regressions. Pushed.

Andrew
From 425964b77ab5b9631e914965a7397303215c77a1 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Thu, 12 Oct 2023 17:06:36 -0400
Subject: [PATCH] Do not add partial equivalences with no uses.

	PR tree-optimization/111622
	* value-relation.cc (equiv_oracle::add_partial_equiv): Do not
	register a partial equivalence if an operand has no uses.
---
 gcc/value-relation.cc | 9 +
 1 file changed, 9 insertions(+)

diff --git a/gcc/value-relation.cc b/gcc/value-relation.cc
index fc792a4d5bc..0ed5f93d184 100644
--- a/gcc/value-relation.cc
+++ b/gcc/value-relation.cc
@@ -389,6 +389,9 @@ equiv_oracle::add_partial_equiv (relation_kind r, tree op1, tree op2)
   // In either case, if PE2 has an entry, we simply do nothing.
   if (pe2.members)
 	return;
+  // If there are no uses of op2, do not register.
+  if (has_zero_uses (op2))
+	return;
   // PE1 is the LHS and already has members, so everything in the set
   // should be a slice of PE2 rather than PE1.
   pe2.code = pe_min (r, pe1.code);
@@ -406,6 +409,9 @@ equiv_oracle::add_partial_equiv (relation_kind r, tree op1, tree op2)
 }
   if (pe2.members)
 {
+  // If there are no uses of op1, do not register.
+  if (has_zero_uses (op1))
+	return;
   pe1.ssa_base = pe2.ssa_base;
   // If pe2 is a 16 bit value, but only an 8 bit copy, we can't be any
   // more than an 8 bit equivalence here, so choose MIN value.
@@ -415,6 +421,9 @@ equiv_oracle::add_partial_equiv (relation_kind r, tree op1, tree op2)
 }
   else
 {
+  // If there are no uses of either operand, do not register.
+  if (has_zero_uses (op1) || has_zero_uses (op2))
+	return;
   // Neither name has an entry, simply create op1 as slice of op2.
   pe2.code = bits_to_pe (TYPE_PRECISION (TREE_TYPE (op2)));
   if (pe2.code == VREL_VARYING)
-- 
2.41.0



[COMMITTED] PR tree-optimization/111622 - Do not add partial equivalences with no uses.

2023-10-13 Thread Andrew MacLeod
Technically PR 111622 exposes a bug in GCC 13, but its been papered over 
on trunk by this:


commit 9ea74d235c7e7816b996a17c61288f02ef767985
Author: Richard Biener 
Date:   Thu Sep 14 09:31:23 2023 +0200

tree-optimization/111294 - better DCE after forwprop


This removes a lot of dead statements, but those statements were being 
added to the list of partial equivalences and causing some serious 
compile time issues.


Rangers cache loops through equivalences when its propagating on-entry 
values, so if the partial equivalence list is very large, it can consume 
a lot of time.  Typically, partial equivalence lists are small.   In 
this case, a lot of dead stmts were not removed, so there was no 
redundancy elimination and it was causing an issue.   This patch 
actually speeds things up a hair in the normal case too.


Bootstrapped on x86_64-pc-linux-gnu with no regressions.  pushed.

Andrew





[COMMITTED][GCC13] PR tree-optimization/111694 - Ensure float equivalences include + and - zero.

2023-10-11 Thread Andrew MacLeod
Similar patch which was checked into trunk last week.   slight tweak 
needed as dconstm0 was not exported in gcc 13, otherwise functionally 
the same


Bootstrapped on x86_64-pc-linux-gnu.  pushed.

Andrew
commit f0efc4b25cba1bd35b08b7dfbab0f8fc81b55c66
Author: Andrew MacLeod 
Date:   Mon Oct 9 13:40:15 2023 -0400

Ensure float equivalences include + and - zero.

A floating point equivalence may not properly reflect both signs of
zero, so be pessimsitic and ensure both signs are included.

PR tree-optimization/111694
gcc/
* gimple-range-cache.cc (ranger_cache::fill_block_cache): Adjust
equivalence range.
* value-relation.cc (adjust_equivalence_range): New.
* value-relation.h (adjust_equivalence_range): New prototype.

gcc/testsuite/
* gcc.dg/pr111694.c: New.

diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index 2314478d558..e4e75943632 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -1258,6 +1258,9 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb)
 		{
 		  if (rel != VREL_EQ)
 		range_cast (equiv_range, type);
+		  else
+		adjust_equivalence_range (equiv_range);
+
 		  if (block_result.intersect (equiv_range))
 		{
 		  if (DEBUG_RANGE_CACHE)
diff --git a/gcc/testsuite/gcc.dg/pr111694.c b/gcc/testsuite/gcc.dg/pr111694.c
new file mode 100644
index 000..a70b03069dc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr111694.c
@@ -0,0 +1,19 @@
+/* PR tree-optimization/111009 */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+#define signbit(x) __builtin_signbit(x)
+
+static void test(double l, double r)
+{
+  if (l == r && (signbit(l) || signbit(r)))
+;
+  else
+__builtin_abort();
+}
+
+int main()
+{
+  test(0.0, -0.0);
+}
+
diff --git a/gcc/value-relation.cc b/gcc/value-relation.cc
index 30a02d3c9d3..fc792a4d5bc 100644
--- a/gcc/value-relation.cc
+++ b/gcc/value-relation.cc
@@ -183,6 +183,25 @@ relation_transitive (relation_kind r1, relation_kind r2)
   return relation_kind (rr_transitive_table[r1][r2]);
 }
 
+// When one name is an equivalence of another, ensure the equivalence
+// range is correct.  Specifically for floating point, a +0 is also
+// equivalent to a -0 which may not be reflected.  See PR 111694.
+
+void
+adjust_equivalence_range (vrange )
+{
+  if (range.undefined_p () || !is_a (range))
+return;
+
+  frange fr = as_a (range);
+  REAL_VALUE_TYPE dconstm0 = dconst0;
+  dconstm0.sign = 1;
+  frange zeros (range.type (), dconstm0, dconst0);
+  // If range includes a 0 make sure both signs of zero are included.
+  if (fr.intersect (zeros) && !fr.undefined_p ())
+range.union_ (zeros);
+ }
+
 // This vector maps a relation to the equivalent tree code.
 
 static const tree_code relation_to_code [VREL_LAST] = {
diff --git a/gcc/value-relation.h b/gcc/value-relation.h
index 3177ecb1ad0..6412cbbe98b 100644
--- a/gcc/value-relation.h
+++ b/gcc/value-relation.h
@@ -91,6 +91,9 @@ inline bool relation_equiv_p (relation_kind r)
 
 void print_relation (FILE *f, relation_kind rel);
 
+// Adjust range as an equivalence.
+void adjust_equivalence_range (vrange );
+
 class relation_oracle
 {
 public:


[COMMITTED] PR tree-optimization/111694 - Ensure float equivalences include + and - zero.

2023-10-09 Thread Andrew MacLeod
When ranger propagates ranges in the on-entry cache, it also check for 
equivalences and incorporates the equivalence into the range for a name 
if it is known.


With floating point values, the equivalence that is generated by 
comparison must also take into account that if the equivalence contains 
zero, both positive and negative zeros could be in the range.


This PR demonstrates that once we establish an equivalence, even though 
we know one value may only have a positive zero, the equivalence may 
have been formed earlier and included a negative zero  This patch 
pessimistically assumes that if the equivalence contains zero, we should 
include both + and - 0 in the equivalence that we utilize.


I audited the other places, and found no other place where this issue 
might arise.  Cache propagation is the only place where we augment the 
range with random equivalences.


Bootstrapped on x86_64-pc-linux-gnu with no regressions. Pushed.

Andrew
From b0892b1fc637fadf14d7016858983bc5776a1e69 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Mon, 9 Oct 2023 10:15:07 -0400
Subject: [PATCH 2/2] Ensure float equivalences include + and - zero.

A floating point equivalence may not properly reflect both signs of
zero, so be pessimsitic and ensure both signs are included.

	PR tree-optimization/111694
	gcc/
	* gimple-range-cache.cc (ranger_cache::fill_block_cache): Adjust
	equivalence range.
	* value-relation.cc (adjust_equivalence_range): New.
	* value-relation.h (adjust_equivalence_range): New prototype.

	gcc/testsuite/
	* gcc.dg/pr111694.c: New.
---
 gcc/gimple-range-cache.cc   |  3 +++
 gcc/testsuite/gcc.dg/pr111694.c | 19 +++
 gcc/value-relation.cc   | 19 +++
 gcc/value-relation.h|  3 +++
 4 files changed, 44 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/pr111694.c

diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index 3c819933c4e..89c0845457d 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -1470,6 +1470,9 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb)
 		{
 		  if (rel != VREL_EQ)
 		range_cast (equiv_range, type);
+		  else
+		adjust_equivalence_range (equiv_range);
+
 		  if (block_result.intersect (equiv_range))
 		{
 		  if (DEBUG_RANGE_CACHE)
diff --git a/gcc/testsuite/gcc.dg/pr111694.c b/gcc/testsuite/gcc.dg/pr111694.c
new file mode 100644
index 000..a70b03069dc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr111694.c
@@ -0,0 +1,19 @@
+/* PR tree-optimization/111009 */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+#define signbit(x) __builtin_signbit(x)
+
+static void test(double l, double r)
+{
+  if (l == r && (signbit(l) || signbit(r)))
+;
+  else
+__builtin_abort();
+}
+
+int main()
+{
+  test(0.0, -0.0);
+}
+
diff --git a/gcc/value-relation.cc b/gcc/value-relation.cc
index a2ae39692a6..0326fe7cde6 100644
--- a/gcc/value-relation.cc
+++ b/gcc/value-relation.cc
@@ -183,6 +183,25 @@ relation_transitive (relation_kind r1, relation_kind r2)
   return relation_kind (rr_transitive_table[r1][r2]);
 }
 
+// When one name is an equivalence of another, ensure the equivalence
+// range is correct.  Specifically for floating point, a +0 is also
+// equivalent to a -0 which may not be reflected.  See PR 111694.
+
+void
+adjust_equivalence_range (vrange )
+{
+  if (range.undefined_p () || !is_a (range))
+return;
+
+  frange fr = as_a (range);
+  // If range includes 0 make sure both signs of zero are included.
+  if (fr.contains_p (dconst0) || fr.contains_p (dconstm0))
+{
+  frange zeros (range.type (), dconstm0, dconst0);
+  range.union_ (zeros);
+}
+ }
+
 // This vector maps a relation to the equivalent tree code.
 
 static const tree_code relation_to_code [VREL_LAST] = {
diff --git a/gcc/value-relation.h b/gcc/value-relation.h
index be6e277421b..31d48908678 100644
--- a/gcc/value-relation.h
+++ b/gcc/value-relation.h
@@ -91,6 +91,9 @@ inline bool relation_equiv_p (relation_kind r)
 
 void print_relation (FILE *f, relation_kind rel);
 
+// Adjust range as an equivalence.
+void adjust_equivalence_range (vrange );
+
 class relation_oracle
 {
 public:
-- 
2.41.0



[COMMITTED] Remove unused get_identity_relation.

2023-10-09 Thread Andrew MacLeod
I added this routine for Aldy when he thought we were going to have to 
add explicit versions for unordered relations.


It seems that with accurate tracking of NANs, we do not need the 
explicit versions in the oracle, so we will not need this identity 
routine to pick the appropriate version of VREL_EQ... as there is only 
one.  As it stands, always returns VREL_EQ, so simply use VREL_EQ in the 
2 calling locations.


Bootstrapped on x86_64-pc-linux-gnu with no regressions. Pushed.

Andrew
From 5ee51119d1345f3f13af784455a4ae466766912b Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Mon, 9 Oct 2023 10:01:11 -0400
Subject: [PATCH 1/2] Remove unused get_identity_relation.

Turns out we didnt need this as there is no unordered relations
managed by the oracle.

	* gimple-range-gori.cc (gori_compute::compute_operand1_range): Do
	not call get_identity_relation.
	(gori_compute::compute_operand2_range): Ditto.
	* value-relation.cc (get_identity_relation): Remove.
	* value-relation.h (get_identity_relation): Remove protyotype.
---
 gcc/gimple-range-gori.cc | 10 ++
 gcc/value-relation.cc| 14 --
 gcc/value-relation.h |  3 ---
 3 files changed, 2 insertions(+), 25 deletions(-)

diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc
index 1b5eda43390..887da0ff094 100644
--- a/gcc/gimple-range-gori.cc
+++ b/gcc/gimple-range-gori.cc
@@ -1146,10 +1146,7 @@ gori_compute::compute_operand1_range (vrange ,
 
   // If op1 == op2, create a new trio for just this call.
   if (op1 == op2 && gimple_range_ssa_p (op1))
-	{
-	  relation_kind k = get_identity_relation (op1, op1_range);
-	  trio = relation_trio (trio.lhs_op1 (), trio.lhs_op2 (), k);
-	}
+	trio = relation_trio (trio.lhs_op1 (), trio.lhs_op2 (), VREL_EQ);
   if (!handler.calc_op1 (r, lhs, op2_range, trio))
 	return false;
 }
@@ -1225,10 +1222,7 @@ gori_compute::compute_operand2_range (vrange ,
 
   // If op1 == op2, create a new trio for this stmt.
   if (op1 == op2 && gimple_range_ssa_p (op1))
-{
-  relation_kind k = get_identity_relation (op1, op1_range);
-  trio = relation_trio (trio.lhs_op1 (), trio.lhs_op2 (), k);
-}
+trio = relation_trio (trio.lhs_op1 (), trio.lhs_op2 (), VREL_EQ);
   // Intersect with range for op2 based on lhs and op1.
   if (!handler.calc_op2 (r, lhs, op1_range, trio))
 return false;
diff --git a/gcc/value-relation.cc b/gcc/value-relation.cc
index 8fea4aad345..a2ae39692a6 100644
--- a/gcc/value-relation.cc
+++ b/gcc/value-relation.cc
@@ -183,20 +183,6 @@ relation_transitive (relation_kind r1, relation_kind r2)
   return relation_kind (rr_transitive_table[r1][r2]);
 }
 
-// When operands of a statement are identical ssa_names, return the
-// approriate relation between operands for NAME == NAME, given RANGE.
-//
-relation_kind
-get_identity_relation (tree name, vrange  ATTRIBUTE_UNUSED)
-{
-  // Return VREL_UNEQ when it is supported for floats as appropriate.
-  if (frange::supports_p (TREE_TYPE (name)))
-return VREL_EQ;
-
-  // Otherwise return VREL_EQ.
-  return VREL_EQ;
-}
-
 // This vector maps a relation to the equivalent tree code.
 
 static const tree_code relation_to_code [VREL_LAST] = {
diff --git a/gcc/value-relation.h b/gcc/value-relation.h
index f00f84f93b6..be6e277421b 100644
--- a/gcc/value-relation.h
+++ b/gcc/value-relation.h
@@ -91,9 +91,6 @@ inline bool relation_equiv_p (relation_kind r)
 
 void print_relation (FILE *f, relation_kind rel);
 
-// Return relation for NAME == NAME with RANGE.
-relation_kind get_identity_relation (tree name, vrange );
-
 class relation_oracle
 {
 public:
-- 
2.41.0



[COMMITTED 0/3] Add a FAST VRP pass.

2023-10-05 Thread Andrew MacLeod
the following set of 3 patches provide the infrastructure for a fast vrp 
pass.


The pass is currently not invoked anywhere, but I wanted to get the 
infrastructure bits in place now... just in case we want to use it 
somewhere.


It clearly bootstraps with no regressions since it isn't being invoked 
:-)   I have however bootstrapped it with calls to the new fast-vrp pass 
immediately following the EVRP, and as an EVRP replacement .  This is to 
primarily ensure it isn't doing anything harmful.  That is a test of 
sorts :-).


I also ran it instead of EVRP, and it bootstraps, but does trigger a few 
regressions, all related to relation processing, which it doesn't do.


Patch one provides a new API for GORI which simply provides a list of 
all the ranges that it can generate on an outgoing edge. It utilizes the 
sparse ssa-cache, and simply sets the outgoing range as determines by 
the edge.  Its very efficient, only walking up the chain once and not 
generating any other utillity structures.  This provides fats an easy 
access to any info an edge may provide.  There is a second API for 
querying a specific name instead of asking for all the ranges.   It 
should be pretty solid as is simply invokes ranges-ops and other 
components the same way the larger GORI engine does, it just puts them 
together in a different way


Patch 2 is the new DOM ranger.  It assumes it will be called in DOM 
order, and evaluates the statements, and tracks any ranges on outgoing 
edges.  Queries for ranges walk the dom tree looking for a range until 
it finds one on an edge or hits the definition block.   There are 
additional efficiencies that can be employed, and I'll eventually get 
back to them.


Patch 3 is the FAST VRP pass and folder.  Its pretty straightforward, 
invokes the new DOM ranger, and enables  you to add  MAKE_PASS 
(pass_fast_vrp)  in passes. def.


Timewise, it is currently about twice as fast as EVRP.  It does basic 
range evaluation and fold PHIs, etc. It does *not* do relation 
processing or any of the fancier things we do (like statement side 
effects).   A little additional  work can reduce the memory footprint 
further too.  I have done no experiments as yet as to the cot of adding 
relations, but it would be pretty straightforward as it is just reusing 
all the same components the main ranger does


Andrew






[COMMITTED 3/3] Create a fast VRP pass

2023-10-05 Thread Andrew MacLeod
This patch adds a fast VRP pass.  It is not invoked from anywhere, so 
should cause no issues.


If you want to utilize it, simply add a new pass, ie:

--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -92,6 +92,7 @@ along with GCC; see the file COPYING3.  If not see
  NEXT_PASS (pass_phiprop);
  NEXT_PASS (pass_fre, true /* may_iterate */);
  NEXT_PASS (pass_early_vrp);
+ NEXT_PASS (pass_fast_vrp);
  NEXT_PASS (pass_merge_phi);
   NEXT_PASS (pass_dse);
  NEXT_PASS (pass_cd_dce, false /* update_address_taken_p */);

it will generate a dump file with the extension .fvrp.


pushed.

From f4e2dac53fd62fbf2af95e0bf26d24e929fa1f66 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Mon, 2 Oct 2023 18:32:49 -0400
Subject: [PATCH 3/3] Create a fast VRP pass

	* timevar.def (TV_TREE_FAST_VRP): New.
	* tree-pass.h (make_pass_fast_vrp): New prototype.
	* tree-vrp.cc (class fvrp_folder): New.
	(fvrp_folder::fvrp_folder): New.
	(fvrp_folder::~fvrp_folder): New.
	(fvrp_folder::value_of_expr): New.
	(fvrp_folder::value_on_edge): New.
	(fvrp_folder::value_of_stmt): New.
	(fvrp_folder::pre_fold_bb): New.
	(fvrp_folder::post_fold_bb): New.
	(fvrp_folder::pre_fold_stmt): New.
	(fvrp_folder::fold_stmt): New.
	(execute_fast_vrp): New.
	(pass_data_fast_vrp): New.
	(pass_vrp:execute): Check for fast VRP pass.
	(make_pass_fast_vrp): New.
---
 gcc/timevar.def |   1 +
 gcc/tree-pass.h |   1 +
 gcc/tree-vrp.cc | 124 
 3 files changed, 126 insertions(+)

diff --git a/gcc/timevar.def b/gcc/timevar.def
index 9523598f60e..d21b08c030d 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -160,6 +160,7 @@ DEFTIMEVAR (TV_TREE_TAIL_MERGE   , "tree tail merge")
 DEFTIMEVAR (TV_TREE_VRP  , "tree VRP")
 DEFTIMEVAR (TV_TREE_VRP_THREADER , "tree VRP threader")
 DEFTIMEVAR (TV_TREE_EARLY_VRP, "tree Early VRP")
+DEFTIMEVAR (TV_TREE_FAST_VRP , "tree Fast VRP")
 DEFTIMEVAR (TV_TREE_COPY_PROP, "tree copy propagation")
 DEFTIMEVAR (TV_FIND_REFERENCED_VARS  , "tree find ref. vars")
 DEFTIMEVAR (TV_TREE_PTA		 , "tree PTA")
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index eba2d54ac76..9c4b1e4185c 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -470,6 +470,7 @@ extern gimple_opt_pass *make_pass_check_data_deps (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_copy_prop (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_isolate_erroneous_paths (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_early_vrp (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_fast_vrp (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_vrp (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_assumptions (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_uncprop (gcc::context *ctxt);
diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc
index 4f8c7745461..19d8f995d70 100644
--- a/gcc/tree-vrp.cc
+++ b/gcc/tree-vrp.cc
@@ -1092,6 +1092,106 @@ execute_ranger_vrp (struct function *fun, bool warn_array_bounds_p,
   return 0;
 }
 
+// Implement a Fast VRP folder.  Not quite as effective but faster.
+
+class fvrp_folder : public substitute_and_fold_engine
+{
+public:
+  fvrp_folder (dom_ranger *dr) : substitute_and_fold_engine (),
+ m_simplifier (dr)
+  { m_dom_ranger = dr; }
+
+  ~fvrp_folder () { }
+
+  tree value_of_expr (tree name, gimple *s = NULL) override
+  {
+// Shortcircuit subst_and_fold callbacks for abnormal ssa_names.
+if (TREE_CODE (name) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name))
+  return NULL;
+return m_dom_ranger->value_of_expr (name, s);
+  }
+
+  tree value_on_edge (edge e, tree name) override
+  {
+// Shortcircuit subst_and_fold callbacks for abnormal ssa_names.
+if (TREE_CODE (name) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name))
+  return NULL;
+return m_dom_ranger->value_on_edge (e, name);
+  }
+
+  tree value_of_stmt (gimple *s, tree name = NULL) override
+  {
+// Shortcircuit subst_and_fold callbacks for abnormal ssa_names.
+if (TREE_CODE (name) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name))
+  return NULL;
+return m_dom_ranger->value_of_stmt (s, name);
+  }
+
+  void pre_fold_bb (basic_block bb) override
+  {
+m_dom_ranger->pre_bb (bb);
+// Now process the PHIs in advance.
+gphi_iterator psi = gsi_start_phis (bb);
+for ( ; !gsi_end_p (psi); gsi_next ())
+  {
+	tree name = gimple_range_ssa_p (PHI_RESULT (psi.phi ()));
+	if (name)
+	  {
+	Value_Range vr(TREE_TYPE (name));
+	m_dom_ranger->range_of_stmt (vr, psi.phi (), name);
+	  }
+  }
+  }
+
+  void post_fold_bb (basic_block bb) override
+  {
+m_dom_ranger->post_bb (bb);
+  }
+
+  void pre_fold_stmt (gimple *s) override
+  {
+// Ensure range_of_stmt has been called.
+ 

[COMMITTED 1/3] Add outgoing range vector calculation API.

2023-10-05 Thread Andrew MacLeod

This patch adds 2 routine that can be called to generate GORI information.

The primar API is:
bool gori_on_edge (class ssa_cache , edge e, range_query *query = 
NULL, gimple_outgoing_range *ogr = NULL);


This will populate an ssa-cache R with any ranges that are generated by 
edge E.   It will use QUERY, if provided, to satisfy any incoming 
values.  if OGR is provided, it is used to pick up hard edge values.. 
like TRUE, FALSE, or switch edges.


It currently only works for TRUE/FALSE conditionals, and doesn't try to 
solve complex logical combinations.  ie (a <6 && b > 6) || (a>10 || b < 
3) as those can get exponential and require multiple evaluations of the 
IL to satisfy.  It will fully utilize range-ops however and so comes up 
with many ranges ranger does.


It also provides the "raw" ranges on the edge.. ie. it doesn't try to 
figure out anything outside the current basic block, but rather reflects 
exactly what the edge indicates.


ie:

   :
  x.0_1 = (unsigned int) x_20(D);
  _2 = x.0_1 + 4294967292;
  if (_2 > 4)
    goto ; [INV]
  else
    goto ; [INV]

produces

Edge ranges BB 2->3
x.0_1  : [irange] unsigned int [0, 3][9, +INF]
_2  : [irange] unsigned int [5, +INF]
x_20(D)  : [irange] int [-INF, 3][9, +INF]

Edge ranges BB 2->4
x.0_1  : [irange] unsigned int [4, 8] MASK 0xf VALUE 0x0
_2  : [irange] unsigned int [0, 4]
x_20(D)  : [irange] int [4, 8] MASK 0xf VALUE 0x0

It performs a linear walk through juts the required statements, so each 
of the the above vectors are generated by visiting each of the 3 
statements exactly once, so its pretty quick.



The other entry point is:
bool gori_name_on_edge (vrange , tree name, edge e, range_query *q);

This does basically the same thing, except it only looks at whether NAME 
has a range, and returns it if it does.  not other overhead.


Pushed.
From 52c1e2c805bc2fd7a30583dce3608b738f3a5ce4 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Tue, 15 Aug 2023 17:29:58 -0400
Subject: [PATCH 1/3] Add outgoing range vector calcualtion API

Provide a GORI API which can produce a range vector for all outgoing
ranges on an edge without any of the other infratructure.

	* gimple-range-gori.cc (gori_stmt_info::gori_stmt_info): New.
	(gori_calc_operands): New.
	(gori_on_edge): New.
	(gori_name_helper): New.
	(gori_name_on_edge): New.
	* gimple-range-gori.h (gori_on_edge): New prototype.
	(gori_name_on_edge): New prototype.
---
 gcc/gimple-range-gori.cc | 213 +++
 gcc/gimple-range-gori.h  |  15 +++
 2 files changed, 228 insertions(+)

diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc
index 2694e551d73..1b5eda43390 100644
--- a/gcc/gimple-range-gori.cc
+++ b/gcc/gimple-range-gori.cc
@@ -1605,3 +1605,216 @@ gori_export_iterator::get_name ()
 }
   return NULL_TREE;
 }
+
+// This is a helper class to set up STMT with a known LHS for further GORI
+// processing.
+
+class gori_stmt_info : public gimple_range_op_handler
+{
+public:
+  gori_stmt_info (vrange , gimple *stmt, range_query *q);
+  Value_Range op1_range;
+  Value_Range op2_range;
+  tree ssa1;
+  tree ssa2;
+};
+
+
+// Uses query Q to get the known ranges on STMT with a LHS range
+// for op1_range and op2_range and set ssa1 and ssa2 if either or both of
+// those operands are SSA_NAMES.
+
+gori_stmt_info::gori_stmt_info (vrange , gimple *stmt, range_query *q)
+  : gimple_range_op_handler (stmt)
+{
+  ssa1 = NULL;
+  ssa2 = NULL;
+  // Don't handle switches as yet for vector processing.
+  if (is_a (stmt))
+return;
+
+  // No frther processing for VARYING or undefined.
+  if (lhs.undefined_p () || lhs.varying_p ())
+return;
+
+  // If there is no range-op handler, we are also done.
+  if (!*this)
+return;
+
+  // Only evaluate logical cases if both operands must be the same as the LHS.
+  // Otherwise its becomes exponential in time, as well as more complicated.
+  if (is_gimple_logical_p (stmt))
+{
+  gcc_checking_assert (range_compatible_p (lhs.type (), boolean_type_node));
+  enum tree_code code = gimple_expr_code (stmt);
+  if (code == TRUTH_OR_EXPR ||  code == BIT_IOR_EXPR)
+	{
+	  // [0, 0] = x || y  means both x and y must be zero.
+	  if (!lhs.singleton_p () || !lhs.zero_p ())
+	return;
+	}
+  else if (code == TRUTH_AND_EXPR ||  code == BIT_AND_EXPR)
+	{
+	  // [1, 1] = x && y  means both x and y must be one.
+	  if (!lhs.singleton_p () || lhs.zero_p ())
+	return;
+	}
+}
+
+  tree op1 = operand1 ();
+  tree op2 = operand2 ();
+  ssa1 = gimple_range_ssa_p (op1);
+  ssa2 = gimple_range_ssa_p (op2);
+  // If both operands are the same, only process one of them.
+  if (ssa1 && ssa1 == ssa2)
+ssa2 = NULL_TREE;
+
+  // Extract current ranges for the operands.
+  fur_stmt src (stmt, q);
+  if (op1)
+{
+  op1_range.set_type (TREE_TYPE (op1));
+  src.get_operand (op1_range, op1);
+}
+
+  // And satisfy

[COMMITTED 2/3] Add a dom based ranger for fast VRP.

2023-10-05 Thread Andrew MacLeod
This patch adds a DOM based ranger that is intended to be used by a dom 
walk pass and provides basic ranges.


It utilizes the new GORI edge API to find outgoing ranges on edges, and 
combines these with any ranges calculated during the walk up to this 
point.  When a query is made for a range not defined in the current 
block, a quick dom walk is performed looking for a range either on a 
single-pred  incoming  edge or defined in the block.


Its about twice the speed of current EVRP, and although there is a bit 
of room to improve both memory usage and speed, I'll leave that until I 
either get around to it or we elect to use it and it becomes more 
important.   It also serves as a POC for anyone wanting to use the new 
GORI API to use edge ranges, as well as a potentially different fast VRP 
more similar to the old EVRP. This version performs more folding of PHI 
nodes as it has all the info on incoming edges, but at a slight cost, 
mostly memory.  It does no relation processing as yet.


It has been bootstrapped running right after EVRP, and as a replacement 
for EVRP, and since it uses existing machinery, should be reasonably 
solid.   It is currently not invoked from anywhere.


Pushed.

Andrew



From ad8cd713b4e489826e289551b8b8f8f708293a5b Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Fri, 28 Jul 2023 13:18:15 -0400
Subject: [PATCH 2/3] Add a dom based ranger for fast VRP.

Provide a dominator based implementation of a range query.

	* gimple_range.cc (dom_ranger::dom_ranger): New.
	(dom_ranger::~dom_ranger): New.
	(dom_ranger::range_of_expr): New.
	(dom_ranger::edge_range): New.
	(dom_ranger::range_on_edge): New.
	(dom_ranger::range_in_bb): New.
	(dom_ranger::range_of_stmt): New.
	(dom_ranger::maybe_push_edge): New.
	(dom_ranger::pre_bb): New.
	(dom_ranger::post_bb): New.
	* gimple-range.h (class dom_ranger): New.
---
 gcc/gimple-range.cc | 300 
 gcc/gimple-range.h  |  28 +
 2 files changed, 328 insertions(+)

diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 13c3308d537..5e9bb397a20 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -928,3 +928,303 @@ assume_query::dump (FILE *f)
 }
   fprintf (f, "--\n");
 }
+
+// ---
+
+
+// Create a DOM based ranger for use by a DOM walk pass.
+
+dom_ranger::dom_ranger () : m_global (), m_out ()
+{
+  m_freelist.create (0);
+  m_freelist.truncate (0);
+  m_e0.create (0);
+  m_e0.safe_grow_cleared (last_basic_block_for_fn (cfun));
+  m_e1.create (0);
+  m_e1.safe_grow_cleared (last_basic_block_for_fn (cfun));
+  m_pop_list = BITMAP_ALLOC (NULL);
+  if (dump_file && (param_ranger_debug & RANGER_DEBUG_TRACE))
+tracer.enable_trace ();
+}
+
+// Dispose of a DOM ranger.
+
+dom_ranger::~dom_ranger ()
+{
+  if (dump_file && (dump_flags & TDF_DETAILS))
+{
+  fprintf (dump_file, "Non-varying global ranges:\n");
+  fprintf (dump_file, "=:\n");
+  m_global.dump (dump_file);
+}
+  BITMAP_FREE (m_pop_list);
+  m_e1.release ();
+  m_e0.release ();
+  m_freelist.release ();
+}
+
+// Implement range of EXPR on stmt S, and return it in R.
+// Return false if no range can be calculated.
+
+bool
+dom_ranger::range_of_expr (vrange , tree expr, gimple *s)
+{
+  unsigned idx;
+  if (!gimple_range_ssa_p (expr))
+return get_tree_range (r, expr, s);
+
+  if ((idx = tracer.header ("range_of_expr ")))
+{
+  print_generic_expr (dump_file, expr, TDF_SLIM);
+  if (s)
+	{
+	  fprintf (dump_file, " at ");
+	  print_gimple_stmt (dump_file, s, 0, TDF_SLIM);
+	}
+  else
+	  fprintf (dump_file, "\n");
+}
+
+  if (s)
+range_in_bb (r, gimple_bb (s), expr);
+  else
+m_global.range_of_expr (r, expr, s);
+
+  if (idx)
+tracer.trailer (idx, " ", true, expr, r);
+  return true;
+}
+
+
+// Return TRUE and the range if edge E has a range set for NAME in
+// block E->src.
+
+bool
+dom_ranger::edge_range (vrange , edge e, tree name)
+{
+  bool ret = false;
+  basic_block bb = e->src;
+
+  // Check if BB has any outgoing ranges on edge E.
+  ssa_lazy_cache *out = NULL;
+  if (EDGE_SUCC (bb, 0) == e)
+out = m_e0[bb->index];
+  else if (EDGE_SUCC (bb, 1) == e)
+out = m_e1[bb->index];
+
+  // If there is an edge vector and it has a range, pick it up.
+  if (out && out->has_range (name))
+ret = out->get_range (r, name);
+
+  return ret;
+}
+
+
+// Return the range of EXPR on edge E in R.
+// Return false if no range can be calculated.
+
+bool
+dom_ranger::range_on_edge (vrange , edge e, tree expr)
+{
+  basic_block bb = e->src;
+  unsigned idx;
+  if ((idx = tracer.header ("range_on_edge ")))
+{
+  fprintf (dump_file, "%d->%d for ",e->src->index, e->dest->index);
+  

[COMMITTED] Don't use range_info_get_range for pointers.

2023-10-03 Thread Andrew MacLeod

Properly check for pointers instead of just using range_info_get_range.

bootstrapped on 86_64-pc-linux-gnu (and presumably AIX too :-) with no 
regressions.


On 10/3/23 12:53, David Edelsohn wrote:

AIX bootstrap is happier with the patch.

Thanks, David

commit d8808c37d29110872fa51b98e71aef9e160b4692
Author: Andrew MacLeod 
Date:   Tue Oct 3 12:32:10 2023 -0400

Don't use range_info_get_range for pointers.

Pointers only track null and nonnull, so we need to handle them
specially.

* tree-ssanames.cc (set_range_info): Use get_ptr_info for
pointers rather than range_info_get_range.

diff --git a/gcc/tree-ssanames.cc b/gcc/tree-ssanames.cc
index 1eae411ac1c..0a32444fbdf 100644
--- a/gcc/tree-ssanames.cc
+++ b/gcc/tree-ssanames.cc
@@ -420,15 +420,11 @@ set_range_info (tree name, const vrange )
 
   // Pick up the current range, or VARYING if none.
   tree type = TREE_TYPE (name);
-  Value_Range tmp (type);
-  if (range_info_p (name))
-range_info_get_range (name, tmp);
-  else
-tmp.set_varying (type);
-
   if (POINTER_TYPE_P (type))
 {
-  if (r.nonzero_p () && !tmp.nonzero_p ())
+  struct ptr_info_def *pi = get_ptr_info (name);
+  // If R is nonnull and pi is not, set nonnull.
+  if (r.nonzero_p () && (!pi || pi->pt.null))
{
  set_ptr_nonnull (name);
  return true;
@@ -436,6 +432,11 @@ set_range_info (tree name, const vrange )
   return false;
 }
 
+  Value_Range tmp (type);
+  if (range_info_p (name))
+range_info_get_range (name, tmp);
+  else
+tmp.set_varying (type);
   // If the result doesn't change, or is undefined, return false.
   if (!tmp.intersect (r) || tmp.undefined_p ())
 return false;


Re: [COMMITTED] Remove pass counting in VRP.

2023-10-03 Thread Andrew MacLeod


On 10/3/23 13:02, David Malcolm wrote:

On Tue, 2023-10-03 at 10:32 -0400, Andrew MacLeod wrote:

Pass counting in VRP is used to decide when to call early VRP, pass
the
flag to enable warnings, and when the final pass is.

If you try to add additional passes, this becomes quite fragile. This
patch simply chooses the pass based on the data pointer passed in,
and
remove the pass counter.   The first FULL VRP pass invokes the
warning
code, and the flag passed in now represents the FINAL pass of VRP.
There is no longer a global flag which, as it turns out, wasn't
working
well with the JIT compiler, but when undetected.  (Thanks to dmalcolm
for helping me sort out what was going on there)


Bootstraps  on x86_64-pc-linux-gnu with no regressions.   Pushed.

[CCing jit mailing list]

I'm worried that this patch may have "papered over" an issue with
libgccjit.  Specifically:


well, that isnt the patch that was checked in :-P

Im not sure how the old version got into the commit note.

Attached is the version checked in.

commit 7eb5ce7f58ed4a48641e1786e4fdeb2f7fb8c5ff
Author: Andrew MacLeod 
Date:   Thu Sep 28 09:19:32 2023 -0400

Remove pass counting in VRP.

Rather than using a pass count to decide which parameters are passed to
VRP, makemit explicit.

* passes.def (pass_vrp): Pass "final pass" flag as parameter.
* tree-vrp.cc (vrp_pass_num): Remove.
(pass_vrp::my_pass): Remove.
(pass_vrp::pass_vrp): Add warn_p as a parameter.
(pass_vrp::final_p): New.
(pass_vrp::set_pass_param): Set final_p param.
(pass_vrp::execute): Call execute_range_vrp with no conditions.
(make_pass_vrp): Pass additional parameter.
(make_pass_early_vrp): Ditto.

diff --git a/gcc/passes.def b/gcc/passes.def
index 4110a472914..2bafd60bbfb 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -221,7 +221,7 @@ along with GCC; see the file COPYING3.  If not see
   NEXT_PASS (pass_fre, true /* may_iterate */);
   NEXT_PASS (pass_merge_phi);
   NEXT_PASS (pass_thread_jumps_full, /*first=*/true);
-  NEXT_PASS (pass_vrp, true /* warn_array_bounds_p */);
+  NEXT_PASS (pass_vrp, false /* final_p*/);
   NEXT_PASS (pass_dse);
   NEXT_PASS (pass_dce);
   /* pass_stdarg is always run and at this point we execute
@@ -348,7 +348,7 @@ along with GCC; see the file COPYING3.  If not see
   NEXT_PASS (pass_dominator, false /* may_peel_loop_headers_p */);
   NEXT_PASS (pass_strlen);
   NEXT_PASS (pass_thread_jumps_full, /*first=*/false);
-  NEXT_PASS (pass_vrp, false /* warn_array_bounds_p */);
+  NEXT_PASS (pass_vrp, true /* final_p */);
   /* Run CCP to compute alignment and nonzero bits.  */
   NEXT_PASS (pass_ccp, true /* nonzero_p */);
   NEXT_PASS (pass_warn_restrict);
diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc
index d7b194f5904..4f8c7745461 100644
--- a/gcc/tree-vrp.cc
+++ b/gcc/tree-vrp.cc
@@ -1120,36 +1120,32 @@ const pass_data pass_data_early_vrp =
   ( TODO_cleanup_cfg | TODO_update_ssa | TODO_verify_all ),
 };
 
-static int vrp_pass_num = 0;
 class pass_vrp : public gimple_opt_pass
 {
 public:
-  pass_vrp (gcc::context *ctxt, const pass_data _)
-: gimple_opt_pass (data_, ctxt), data (data_), warn_array_bounds_p (false),
-  my_pass (vrp_pass_num++)
-  {}
+  pass_vrp (gcc::context *ctxt, const pass_data _, bool warn_p)
+: gimple_opt_pass (data_, ctxt), data (data_),
+  warn_array_bounds_p (warn_p), final_p (false)
+{ }
 
   /* opt_pass methods: */
-  opt_pass * clone () final override { return new pass_vrp (m_ctxt, data); }
+  opt_pass * clone () final override
+{ return new pass_vrp (m_ctxt, data, false); }
   void set_pass_param (unsigned int n, bool param) final override
 {
   gcc_assert (n == 0);
-  warn_array_bounds_p = param;
+  final_p = param;
 }
   bool gate (function *) final override { return flag_tree_vrp != 0; }
   unsigned int execute (function *fun) final override
 {
-  // Early VRP pass.
-  if (my_pass == 0)
-	return execute_ranger_vrp (fun, /*warn_array_bounds_p=*/false, false);
-
-  return execute_ranger_vrp (fun, warn_array_bounds_p, my_pass == 2);
+  return execute_ranger_vrp (fun, warn_array_bounds_p, final_p);
 }
 
  private:
   const pass_data 
   bool warn_array_bounds_p;
-  int my_pass;
+  bool final_p;
 }; // class pass_vrp
 
 const pass_data pass_data_assumptions =
@@ -1219,13 +1215,13 @@ public:
 gimple_opt_pass *
 make_pass_vrp (gcc::context *ctxt)
 {
-  return new pass_vrp (ctxt, pass_data_vrp);
+  return new pass_vrp (ctxt, pass_data_vrp, true);
 }
 
 gimple_opt_pass *
 make_pass_early_vrp (gcc::context *ctxt)
 {
-  return new pass_vrp (ctxt, pass_data_early_vrp);
+  return new pass_vrp (ctxt, pass_data_early_vrp, false);
 }
 
 gimple_opt_pass *


Re: [COMMITTED] Return TRUE only when a global value is updated.

2023-10-03 Thread Andrew MacLeod

perfect.  I'll check it in when my testrun is done.

Thanks  .. .  and sorry :-)

Andrew

On 10/3/23 12:53, David Edelsohn wrote:

AIX bootstrap is happier with the patch.

Thanks, David

On Tue, Oct 3, 2023 at 12:30 PM Andrew MacLeod  
wrote:


Give this a try..  I'm testing it here, but x86 doesn't seem to
show it
anyway for some reason :-P

I think i needed to handle pointers special since SSA_NAMES handle
pointer ranges different.

Andrew

On 10/3/23 11:47, David Edelsohn wrote:
> This patch caused a bootstrap failure on AIX.
>
> during GIMPLE pass: evrp
>
> /nasfarm/edelsohn/src/src/libgcc/libgcc2.c: In function
'__gcc_bcmp':
>
> /nasfarm/edelsohn/src/src/libgcc/libgcc2.c:2910:1: internal
compiler
> error: in get_irange, at value-range-storage.cc:343
>
> 2910 | }
>
> | ^
>
>
> 0x11b7f4b7 irange_storage::get_irange(irange&, tree_node*) const
>
> /nasfarm/edelsohn/src/src/gcc/value-range-storage.cc:343
>
> 0x11b7e7af vrange_storage::get_vrange(vrange&, tree_node*) const
>
> /nasfarm/edelsohn/src/src/gcc/value-range-storage.cc:178
>
> 0x139f3d77 range_info_get_range(tree_node const*, vrange&)
>
> /nasfarm/edelsohn/src/src/gcc/tree-ssanames.cc:118
>
> 0x1134b463 set_range_info(tree_node*, vrange const&)
>
> /nasfarm/edelsohn/src/src/gcc/tree-ssanames.cc:425
>
> 0x116a7333 gimple_ranger::register_inferred_ranges(gimple*)
>
> /nasfarm/edelsohn/src/src/gcc/gimple-range.cc:487
>
> 0x125cef27 rvrp_folder::fold_stmt(gimple_stmt_iterator*)
>
> /nasfarm/edelsohn/src/src/gcc/tree-vrp.cc:1033
>
> 0x123dd063
>
substitute_and_fold_dom_walker::before_dom_children(basic_block_def*)
>
> /nasfarm/edelsohn/src/src/gcc/tree-ssa-propagate.cc:876
>
> 0x1176cc43 dom_walker::walk(basic_block_def*)
>
> /nasfarm/edelsohn/src/src/gcc/domwalk.cc:311
>
> 0x123dd733
> substitute_and_fold_engine::substitute_and_fold(basic_block_def*)
>
> /nasfarm/edelsohn/src/src/gcc/tree-ssa-propagate.cc:999
>
> 0x123d0f5f execute_ranger_vrp(function*, bool, bool)
>
> /nasfarm/edelsohn/src/src/gcc/tree-vrp.cc:1062
>
> 0x123d14ef execute
>
> /nasfarm/edelsohn/src/src/gcc/tree-vrp.cc:1142
>





Re: [COMMITTED] Return TRUE only when a global value is updated.

2023-10-03 Thread Andrew MacLeod
Give this a try..  I'm testing it here, but x86 doesn't seem to show it 
anyway for some reason :-P


I think i needed to handle pointers special since SSA_NAMES handle 
pointer ranges different.


Andrew

On 10/3/23 11:47, David Edelsohn wrote:

This patch caused a bootstrap failure on AIX.

during GIMPLE pass: evrp

/nasfarm/edelsohn/src/src/libgcc/libgcc2.c: In function '__gcc_bcmp':

/nasfarm/edelsohn/src/src/libgcc/libgcc2.c:2910:1: internal compiler 
error: in get_irange, at value-range-storage.cc:343


2910 | }

| ^


0x11b7f4b7 irange_storage::get_irange(irange&, tree_node*) const

/nasfarm/edelsohn/src/src/gcc/value-range-storage.cc:343

0x11b7e7af vrange_storage::get_vrange(vrange&, tree_node*) const

/nasfarm/edelsohn/src/src/gcc/value-range-storage.cc:178

0x139f3d77 range_info_get_range(tree_node const*, vrange&)

/nasfarm/edelsohn/src/src/gcc/tree-ssanames.cc:118

0x1134b463 set_range_info(tree_node*, vrange const&)

/nasfarm/edelsohn/src/src/gcc/tree-ssanames.cc:425

0x116a7333 gimple_ranger::register_inferred_ranges(gimple*)

/nasfarm/edelsohn/src/src/gcc/gimple-range.cc:487

0x125cef27 rvrp_folder::fold_stmt(gimple_stmt_iterator*)

/nasfarm/edelsohn/src/src/gcc/tree-vrp.cc:1033

0x123dd063 
substitute_and_fold_dom_walker::before_dom_children(basic_block_def*)


/nasfarm/edelsohn/src/src/gcc/tree-ssa-propagate.cc:876

0x1176cc43 dom_walker::walk(basic_block_def*)

/nasfarm/edelsohn/src/src/gcc/domwalk.cc:311

0x123dd733 
substitute_and_fold_engine::substitute_and_fold(basic_block_def*)


/nasfarm/edelsohn/src/src/gcc/tree-ssa-propagate.cc:999

0x123d0f5f execute_ranger_vrp(function*, bool, bool)

/nasfarm/edelsohn/src/src/gcc/tree-vrp.cc:1062

0x123d14ef execute

/nasfarm/edelsohn/src/src/gcc/tree-vrp.cc:1142
diff --git a/gcc/tree-ssanames.cc b/gcc/tree-ssanames.cc
index 1eae411ac1c..1401f67c781 100644
--- a/gcc/tree-ssanames.cc
+++ b/gcc/tree-ssanames.cc
@@ -420,15 +420,11 @@ set_range_info (tree name, const vrange )
 
   // Pick up the current range, or VARYING if none.
   tree type = TREE_TYPE (name);
-  Value_Range tmp (type);
-  if (range_info_p (name))
-range_info_get_range (name, tmp);
-  else
-tmp.set_varying (type);
-
   if (POINTER_TYPE_P (type))
 {
-  if (r.nonzero_p () && !tmp.nonzero_p ())
+  struct ptr_info_def *pi = get_ptr_info (name);
+  // If R is nonnull and pi is not, set nonnull.
+  if (r.nonzero_p () && (!pi || !pi->pt.null))
 	{
 	  set_ptr_nonnull (name);
 	  return true;
@@ -436,6 +432,11 @@ set_range_info (tree name, const vrange )
   return false;
 }
 
+  Value_Range tmp (type);
+  if (range_info_p (name))
+range_info_get_range (name, tmp);
+  else
+tmp.set_varying (type);
   // If the result doesn't change, or is undefined, return false.
   if (!tmp.intersect (r) || tmp.undefined_p ())
 return false;


Re: [COMMITTED] Return TRUE only when a global value is updated.

2023-10-03 Thread Andrew MacLeod

huh.  thanks,  I'll have a look.


Andrew

On 10/3/23 11:47, David Edelsohn wrote:

This patch caused a bootstrap failure on AIX.

during GIMPLE pass: evrp

/nasfarm/edelsohn/src/src/libgcc/libgcc2.c: In function '__gcc_bcmp':

/nasfarm/edelsohn/src/src/libgcc/libgcc2.c:2910:1: internal compiler 
error: in get_irange, at value-range-storage.cc:343


2910 | }

| ^


0x11b7f4b7 irange_storage::get_irange(irange&, tree_node*) const

/nasfarm/edelsohn/src/src/gcc/value-range-storage.cc:343

0x11b7e7af vrange_storage::get_vrange(vrange&, tree_node*) const

/nasfarm/edelsohn/src/src/gcc/value-range-storage.cc:178

0x139f3d77 range_info_get_range(tree_node const*, vrange&)

/nasfarm/edelsohn/src/src/gcc/tree-ssanames.cc:118

0x1134b463 set_range_info(tree_node*, vrange const&)

/nasfarm/edelsohn/src/src/gcc/tree-ssanames.cc:425

0x116a7333 gimple_ranger::register_inferred_ranges(gimple*)

/nasfarm/edelsohn/src/src/gcc/gimple-range.cc:487

0x125cef27 rvrp_folder::fold_stmt(gimple_stmt_iterator*)

/nasfarm/edelsohn/src/src/gcc/tree-vrp.cc:1033

0x123dd063 
substitute_and_fold_dom_walker::before_dom_children(basic_block_def*)


/nasfarm/edelsohn/src/src/gcc/tree-ssa-propagate.cc:876

0x1176cc43 dom_walker::walk(basic_block_def*)

/nasfarm/edelsohn/src/src/gcc/domwalk.cc:311

0x123dd733 
substitute_and_fold_engine::substitute_and_fold(basic_block_def*)


/nasfarm/edelsohn/src/src/gcc/tree-ssa-propagate.cc:999

0x123d0f5f execute_ranger_vrp(function*, bool, bool)

/nasfarm/edelsohn/src/src/gcc/tree-vrp.cc:1062

0x123d14ef execute

/nasfarm/edelsohn/src/src/gcc/tree-vrp.cc:1142





[COMMITTED] Remove pass counting in VRP.

2023-10-03 Thread Andrew MacLeod
Pass counting in VRP is used to decide when to call early VRP, pass the 
flag to enable warnings, and when the final pass is.


If you try to add additional passes, this becomes quite fragile. This 
patch simply chooses the pass based on the data pointer passed in, and 
remove the pass counter.   The first FULL VRP pass invokes the warning 
code, and the flag passed in now represents the FINAL pass of VRP.  
There is no longer a global flag which, as it turns out, wasn't working 
well with the JIT compiler, but when undetected.  (Thanks to dmalcolm 
for helping me sort out what was going on there)



Bootstraps  on x86_64-pc-linux-gnu with no regressions.   Pushed.

Andrew
From 29abc475a360ad14d5f692945f2805fba1fdc679 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Thu, 28 Sep 2023 09:19:32 -0400
Subject: [PATCH 2/5] Remove pass counting in VRP.

Rather than using a pass count to decide which parameters are passed to
VRP, makemit explicit.

	* passes.def (pass_vrp): Use parameter for final pass flag..
	* tree-vrp.cc (vrp_pass_num): Remove.
	(run_warning_pass): New.
	(pass_vrp::my_pass): Remove.
	(pass_vrp::final_p): New.
	(pass_vrp::set_pass_param): Set final_p param.
	(pass_vrp::execute): Choose specific pass based on data pointer.
---
 gcc/passes.def  |  4 ++--
 gcc/tree-vrp.cc | 26 +-
 2 files changed, 19 insertions(+), 11 deletions(-)

diff --git a/gcc/passes.def b/gcc/passes.def
index 4110a472914..2bafd60bbfb 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -221,7 +221,7 @@ along with GCC; see the file COPYING3.  If not see
   NEXT_PASS (pass_fre, true /* may_iterate */);
   NEXT_PASS (pass_merge_phi);
   NEXT_PASS (pass_thread_jumps_full, /*first=*/true);
-  NEXT_PASS (pass_vrp, true /* warn_array_bounds_p */);
+  NEXT_PASS (pass_vrp, false /* final_p*/);
   NEXT_PASS (pass_dse);
   NEXT_PASS (pass_dce);
   /* pass_stdarg is always run and at this point we execute
@@ -348,7 +348,7 @@ along with GCC; see the file COPYING3.  If not see
   NEXT_PASS (pass_dominator, false /* may_peel_loop_headers_p */);
   NEXT_PASS (pass_strlen);
   NEXT_PASS (pass_thread_jumps_full, /*first=*/false);
-  NEXT_PASS (pass_vrp, false /* warn_array_bounds_p */);
+  NEXT_PASS (pass_vrp, true /* final_p */);
   /* Run CCP to compute alignment and nonzero bits.  */
   NEXT_PASS (pass_ccp, true /* nonzero_p */);
   NEXT_PASS (pass_warn_restrict);
diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc
index d7b194f5904..05266dfe34a 100644
--- a/gcc/tree-vrp.cc
+++ b/gcc/tree-vrp.cc
@@ -1120,36 +1120,44 @@ const pass_data pass_data_early_vrp =
   ( TODO_cleanup_cfg | TODO_update_ssa | TODO_verify_all ),
 };
 
-static int vrp_pass_num = 0;
+static bool run_warning_pass = true;
 class pass_vrp : public gimple_opt_pass
 {
 public:
   pass_vrp (gcc::context *ctxt, const pass_data _)
-: gimple_opt_pass (data_, ctxt), data (data_), warn_array_bounds_p (false),
-  my_pass (vrp_pass_num++)
-  {}
+: gimple_opt_pass (data_, ctxt), data (data_),
+  warn_array_bounds_p (false), final_p (false)
+  {
+// Only the frst VRP pass should run warnings.
+if ( == _data_vrp)
+  {
+	warn_array_bounds_p = run_warning_pass;
+	run_warning_pass = false;
+  }
+  }
 
   /* opt_pass methods: */
   opt_pass * clone () final override { return new pass_vrp (m_ctxt, data); }
   void set_pass_param (unsigned int n, bool param) final override
 {
   gcc_assert (n == 0);
-  warn_array_bounds_p = param;
+  final_p = param;
 }
   bool gate (function *) final override { return flag_tree_vrp != 0; }
   unsigned int execute (function *fun) final override
 {
   // Early VRP pass.
-  if (my_pass == 0)
-	return execute_ranger_vrp (fun, /*warn_array_bounds_p=*/false, false);
+  if ( == _data_early_vrp)
+	return execute_ranger_vrp (fun, /*warn_array_bounds_p=*/false,
+   /*final_p=*/false);
 
-  return execute_ranger_vrp (fun, warn_array_bounds_p, my_pass == 2);
+  return execute_ranger_vrp (fun, warn_array_bounds_p, final_p);
 }
 
  private:
   const pass_data 
   bool warn_array_bounds_p;
-  int my_pass;
+  bool final_p;
 }; // class pass_vrp
 
 const pass_data pass_data_assumptions =
-- 
2.41.0



[COMMITTED] Return TRUE only when a global value is updated.

2023-10-03 Thread Andrew MacLeod
set_range_info should return TRUE only when it sets a new value. It was 
currently returning true whenever it set a value, whether it was 
different or not.


With this change,  VRP no longer overwrites global ranges DOM has set.  
2 testcases needed adjusting that were expecting VRP2 to set a range but 
turns out it was really being set in DOM2.   Instead they check for the 
range in the final listing...


Bootstrapped on  x86_64-pc-linux-gnu with no regressions. Pushed.

Andrew
From dae5de2a2353b928cc7099a78d88a40473abefd2 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Wed, 27 Sep 2023 12:34:16 -0400
Subject: [PATCH 1/5] Return TRUE only when a global value is updated.

set_range_info should return TRUE only when it sets a new value.  VRP no
longer overwrites global ranges DOM has set.  Check for ranges in the
final listing.

	gcc/
	* tree-ssanames.cc (set_range_info): Return true only if the
	current value changes.

	gcc/testsuite/
	* gcc.dg/pr93917.c: Check for ranges in final optimized listing.
	* gcc.dg/tree-ssa/vrp-unreachable.c: Ditto.
---
 gcc/testsuite/gcc.dg/pr93917.c|  4 ++--
 .../gcc.dg/tree-ssa/vrp-unreachable.c |  4 ++--
 gcc/tree-ssanames.cc  | 24 +--
 3 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/pr93917.c b/gcc/testsuite/gcc.dg/pr93917.c
index f09e1c41ae8..f636b77f45d 100644
--- a/gcc/testsuite/gcc.dg/pr93917.c
+++ b/gcc/testsuite/gcc.dg/pr93917.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1 -fdump-tree-vrp2" } */
+/* { dg-options "-O2 -fdump-tree-vrp1 -fdump-tree-vrp2 -fdump-tree-optimized-alias" } */
 
 void f3(int n);
 
@@ -19,5 +19,5 @@ void f2(int*n)
 
 /* { dg-final { scan-tree-dump-times "Global Export.*0, \\+INF" 1 "vrp1" } } */
 /* { dg-final { scan-tree-dump-times "__builtin_unreachable" 1 "vrp1" } } */
-/* { dg-final { scan-tree-dump-times "Global Export.*0, \\+INF" 1 "vrp2" } } */
 /* { dg-final { scan-tree-dump-times "__builtin_unreachable" 0 "vrp2" } } */
+/* { dg-final { scan-tree-dump-times "0, \\+INF" 2 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-unreachable.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-unreachable.c
index 5835dfc8dbc..4aad7f1be5d 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp-unreachable.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-unreachable.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1-alias -fdump-tree-vrp2-alias" } */
+/* { dg-options "-O2 -fdump-tree-vrp1 -fdump-tree-vrp2 -fdump-tree-optimized-alias" } */
 
 void dead (unsigned n);
 void alive (unsigned n);
@@ -39,4 +39,4 @@ void func (unsigned n, unsigned m)
 /* { dg-final { scan-tree-dump-not "dead" "vrp1" } } */
 /* { dg-final { scan-tree-dump-times "builtin_unreachable" 1 "vrp1" } } */
 /* { dg-final { scan-tree-dump-not "builtin_unreachable" "vrp2" } } */
-/* { dg-final { scan-tree-dump-times "fff8 VALUE 0x0" 4 "vrp2" } } */
+/* { dg-final { scan-tree-dump-times "fff8 VALUE 0x0" 2 "optimized" } } */
diff --git a/gcc/tree-ssanames.cc b/gcc/tree-ssanames.cc
index 23387b90fe3..1eae411ac1c 100644
--- a/gcc/tree-ssanames.cc
+++ b/gcc/tree-ssanames.cc
@@ -418,10 +418,17 @@ set_range_info (tree name, const vrange )
   if (r.undefined_p () || r.varying_p ())
 return false;
 
+  // Pick up the current range, or VARYING if none.
   tree type = TREE_TYPE (name);
+  Value_Range tmp (type);
+  if (range_info_p (name))
+range_info_get_range (name, tmp);
+  else
+tmp.set_varying (type);
+
   if (POINTER_TYPE_P (type))
 {
-  if (r.nonzero_p ())
+  if (r.nonzero_p () && !tmp.nonzero_p ())
 	{
 	  set_ptr_nonnull (name);
 	  return true;
@@ -429,18 +436,11 @@ set_range_info (tree name, const vrange )
   return false;
 }
 
-  /* If a global range already exists, incorporate it.  */
-  if (range_info_p (name))
-{
-  Value_Range tmp (type);
-  range_info_get_range (name, tmp);
-  tmp.intersect (r);
-  if (tmp.undefined_p ())
-	return false;
+  // If the result doesn't change, or is undefined, return false.
+  if (!tmp.intersect (r) || tmp.undefined_p ())
+return false;
 
-  return range_info_set_range (name, tmp);
-}
-  return range_info_set_range (name, r);
+  return range_info_set_range (name, tmp);
 }
 
 /* Set nonnull attribute to pointer NAME.  */
-- 
2.41.0



[COMMITTED] PR tree-optimization/111599 - Ensure ssa_name is still valid.

2023-09-26 Thread Andrew MacLeod
When processing an equivalence list, I neglected to make sure the 
ssa-name is still valid.  This patch simply checks to make sure it 
non-null and not in the free-list.


Bootstraps on x86_64-pc-linux-gnu with no regressions.   Pushed.

Andrew
From 9df0f6bd582ceee53bfed8769cf156329ae33bd0 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Tue, 26 Sep 2023 09:27:52 -0400
Subject: [PATCH] Ensure ssa_name is still valid.

When the IL changes, an equivalence set may contain ssa_names that no
longer exist.  Ensure names are still valid and not in the free list.

	PR tree-optimization/111599
	gcc/
	* value-relation.cc (relation_oracle::valid_equivs): Ensure
	ssa_name is valid.

	gcc/testsuite/
	* gcc.dg/pr111599.c: New.
---
 gcc/testsuite/gcc.dg/pr111599.c | 16 
 gcc/value-relation.cc   |  9 ++---
 2 files changed, 22 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr111599.c

diff --git a/gcc/testsuite/gcc.dg/pr111599.c b/gcc/testsuite/gcc.dg/pr111599.c
new file mode 100644
index 000..25880b759f7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr111599.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fno-inline-functions-called-once -fno-inline-small-functions -fno-tree-dce -fno-tree-forwprop -fno-tree-fre" } */
+
+int h(void);
+void l(int);
+void func_56(int p_57, unsigned p_58) {
+ // p_57 = 0x101BC642L;
+  if (p_57 || h()) {
+int *l_105[2];
+l_105[0] = _57;
+l(p_57);
+  }
+}
+void func_31(int p_33) {
+  func_56(0x101BC642L, (p_33));
+}
diff --git a/gcc/value-relation.cc b/gcc/value-relation.cc
index f2c668a0193..8fea4aad345 100644
--- a/gcc/value-relation.cc
+++ b/gcc/value-relation.cc
@@ -274,9 +274,12 @@ relation_oracle::valid_equivs (bitmap b, const_bitmap equivs, basic_block bb)
   EXECUTE_IF_SET_IN_BITMAP (equivs, 0, i, bi)
 {
   tree ssa = ssa_name (i);
-  const_bitmap ssa_equiv = equiv_set (ssa, bb);
-  if (ssa_equiv == equivs)
-	bitmap_set_bit (b, i);
+  if (ssa && !SSA_NAME_IN_FREE_LIST (ssa))
+	{
+	  const_bitmap ssa_equiv = equiv_set (ssa, bb);
+	  if (ssa_equiv == equivs)
+	bitmap_set_bit (b, i);
+	}
 }
 }
 
-- 
2.41.0



[COMMITTED][GCC13] PR tree-optimization/110315 - Reduce the initial size of int_range_max.

2023-09-26 Thread Andrew MacLeod
This patch adds the ability to resize ranges as needed, defaulting to no 
resizing.  int_range_max now defaults to 3 sub-ranges (instead of 255) 
and grows to 255 when the range being calculated does not fit.


Bootstraps on x86_64-pc-linux-gnu with no regressions.   Pushed.

Andrew
From 70639014a69cf50fe11dc1adbfe1db4c7760ce69 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Tue, 26 Sep 2023 09:44:39 -0400
Subject: [PATCH] Reduce the initial size of int_range_max.

This patch adds the ability to resize ranges as needed, defaulting to no
resizing.  int_range_max now defaults to 3 sub-ranges (instead of 255)
and grows to 255 when the range being calculated does not fit.

	PR tree-optimization/110315
	* value-range-storage.h (vrange_allocator::alloc_irange): Adjust
	new params.
	* value-range.cc (irange::operator=): Resize range.
	(irange::irange_union): Same.
	(irange::irange_intersect): Same.
	(irange::invert): Same.
	* value-range.h (irange::maybe_resize): New.
	(~int_range): New.
	(int_range_max): Default to 3 sub-ranges and resize as needed.
	(int_range::int_range): Adjust for resizing.
	(int_range::operator=): Same.
---
 gcc/value-range-storage.h |  2 +-
 gcc/value-range.cc| 15 ++
 gcc/value-range.h | 96 +++
 3 files changed, 83 insertions(+), 30 deletions(-)

diff --git a/gcc/value-range-storage.h b/gcc/value-range-storage.h
index 6da377ebd2e..1ed6f1ccd61 100644
--- a/gcc/value-range-storage.h
+++ b/gcc/value-range-storage.h
@@ -184,7 +184,7 @@ vrange_allocator::alloc_irange (unsigned num_pairs)
   // Allocate the irange and required memory for the vector.
   void *r = alloc (sizeof (irange));
   tree *mem = static_cast  (alloc (nbytes));
-  return new (r) irange (mem, num_pairs);
+  return new (r) irange (mem, num_pairs, /*resizable=*/false);
 }
 
 inline frange *
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index ec826c2fe1b..753f5e8cc76 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -831,6 +831,10 @@ irange::operator= (const irange )
   copy_to_legacy (src);
   return *this;
 }
+
+  int needed = src.num_pairs ();
+  maybe_resize (needed);
+
   if (src.legacy_mode_p ())
 {
   copy_legacy_to_multi_range (src);
@@ -2506,6 +2510,7 @@ irange::irange_union (const irange )
   // Now it simply needs to be copied, and if there are too many
   // ranges, merge some.  We wont do any analysis as to what the
   // "best" merges are, simply combine the final ranges into one.
+  maybe_resize (i / 2);
   if (i > m_max_ranges * 2)
 {
   res[m_max_ranges * 2 - 1] = res[i - 1];
@@ -2605,6 +2610,11 @@ irange::irange_intersect (const irange )
   if (r.irange_contains_p (*this))
 return intersect_nonzero_bits (r);
 
+  // ?? We could probably come up with something smarter than the
+  // worst case scenario here.
+  int needed = num_pairs () + r.num_pairs ();
+  maybe_resize (needed);
+
   signop sign = TYPE_SIGN (TREE_TYPE(m_base[0]));
   unsigned bld_pair = 0;
   unsigned bld_lim = m_max_ranges;
@@ -2831,6 +2841,11 @@ irange::invert ()
   m_num_ranges = 1;
   return;
 }
+
+  // At this point, we need one extra sub-range to represent the
+  // inverse.
+  maybe_resize (m_num_ranges + 1);
+
   // The algorithm is as follows.  To calculate INVERT ([a,b][c,d]), we
   // generate [-MIN, a-1][b+1, c-1][d+1, MAX].
   //
diff --git a/gcc/value-range.h b/gcc/value-range.h
index 969b2b68418..96e59ecfa72 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -172,7 +172,8 @@ public:
   bool legacy_verbose_intersect (const irange *);	// DEPRECATED
 
 protected:
-  irange (tree *, unsigned);
+  void maybe_resize (int needed);
+  irange (tree *, unsigned nranges, bool resizable);
   // potential promotion to public?
   tree tree_lower_bound (unsigned = 0) const;
   tree tree_upper_bound (unsigned) const;
@@ -200,6 +201,8 @@ protected:
   void copy_to_legacy (const irange &);
   void copy_legacy_to_multi_range (const irange &);
 
+  // Hard limit on max ranges allowed.
+  static const int HARD_MAX_RANGES = 255;
 private:
   friend void gt_ggc_mx (irange *);
   friend void gt_pch_nx (irange *);
@@ -214,15 +217,21 @@ private:
 
   bool intersect (const wide_int& lb, const wide_int& ub);
   unsigned char m_num_ranges;
+  bool m_resizable;
   unsigned char m_max_ranges;
   tree m_nonzero_mask;
+protected:
   tree *m_base;
 };
 
 // Here we describe an irange with N pairs of ranges.  The storage for
 // the pairs is embedded in the class as an array.
+//
+// If RESIZABLE is true, the storage will be resized on the heap when
+// the number of ranges needed goes past N up to a max of
+// HARD_MAX_RANGES.  This new storage is freed upon destruction.
 
-template
+template
 class GTY((user)) int_range : public irange
 {
 public:
@@ -233,7 +242,7 @@ public:
   int_range (tree type);
   int_range (const int_range &);
   int_range (const irange &);
-  virtual ~int_rang

Re: [PATCH] Add missing return in gori_compute::logical_combine

2023-09-25 Thread Andrew MacLeod
OK for trunk at least.   Thanks.  I presume it'll be fine for the other 
releases.


Andrew

On 9/25/23 11:51, Eric Botcazou wrote:

Hi,

the varying case currently falls through to the 1/true case.

Tested on x86_64-suse-linux, OK for mainline, 13 and 12 branches?


2023-09-25  Eric Botcazou  

* gimple-range-gori.cc (gori_compute::logical_combine): Add missing
return statement in the varying case.


2023-09-25  Eric Botcazou  

* gnat.dg/opt102.adb:New test.
* gnat.dg/opt102_pkg.adb, gnat.dg/opt102_pkg.ads: New helper.





[COMMITTED] Tweak ssa_cache::merge_range API.

2023-09-20 Thread Andrew MacLeod
Merge_range use to return TRUE if there was already a range in the 
cache.   This patches change the meaning of the return value such that 
it returns TRUE if the range in the cache changes..  ie, it either set a 
range where there wasn't one before, or updates an existing range when 
the old one intersects with the new one results in a different range.


It also tweaks the debug output for the cache to no longer output the 
header text "non-varying Global Ranges" in the class, as the class is 
now used for other purpoises as well.   The text is moved to when the 
dump is actually from a global table.


Bootstraps on 86_64-pc-linux-gnu with no regressions.   Pushed.

Andrew
commit 0885e96272f1335c324f99fd2d1e9b0b3da9090c
Author: Andrew MacLeod 
Date:   Wed Sep 20 12:53:04 2023 -0400

Tweak merge_range API.

merge_range use to return TRUE if ter was already a arange.  Now it
returns TRUE if it adds a new range, OR updates and existing range
with a new value.  FALSE is returned when the range already matches.

* gimple-range-cache.cc (ssa_cache::merge_range): Change meaning
of the return value.
(ssa_cache::dump): Don't print GLOBAL RANGE header.
(ssa_lazy_cache::merge_range): Adjust return value meaning.
(ranger_cache::dump): Print GLOBAL RANGE header.

diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index 5b74681b61a..3c819933c4e 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -606,7 +606,7 @@ ssa_cache::set_range (tree name, const vrange )
 }
 
 // If NAME has a range, intersect it with R, otherwise set it to R.
-// Return TRUE if there was already a range set, otherwise false.
+// Return TRUE if the range is new or changes.
 
 bool
 ssa_cache::merge_range (tree name, const vrange )
@@ -616,19 +616,23 @@ ssa_cache::merge_range (tree name, const vrange )
 m_tab.safe_grow_cleared (num_ssa_names + 1);
 
   vrange_storage *m = m_tab[v];
-  if (m)
+  // Check if this is a new value.
+  if (!m)
+m_tab[v] = m_range_allocator->clone (r);
+  else
 {
   Value_Range curr (TREE_TYPE (name));
   m->get_vrange (curr, TREE_TYPE (name));
-  curr.intersect (r);
+  // If there is no change, return false.
+  if (!curr.intersect (r))
+   return false;
+
   if (m->fits_p (curr))
m->set_vrange (curr);
   else
m_tab[v] = m_range_allocator->clone (curr);
 }
-  else
-m_tab[v] = m_range_allocator->clone (r);
-  return m != NULL;
+  return true;
 }
 
 // Set the range for NAME to R in the ssa cache.
@@ -656,27 +660,14 @@ ssa_cache::clear ()
 void
 ssa_cache::dump (FILE *f)
 {
-  /* Cleared after the table header has been printed.  */
-  bool print_header = true;
   for (unsigned x = 1; x < num_ssa_names; x++)
 {
   if (!gimple_range_ssa_p (ssa_name (x)))
continue;
   Value_Range r (TREE_TYPE (ssa_name (x)));
-  // Invoke dump_range_query which is a private virtual version of
-  // get_range.   This avoids performance impacts on general queries,
-  // but allows sharing of the dump routine.
+  // Dump all non-varying ranges.
   if (get_range (r, ssa_name (x)) && !r.varying_p ())
{
- if (print_header)
-   {
- /* Print the header only when there's something else
-to print below.  */
- fprintf (f, "Non-varying global ranges:\n");
- fprintf (f, "=:\n");
- print_header = false;
-   }
-
  print_generic_expr (f, ssa_name (x), TDF_NONE);
  fprintf (f, "  : ");
  r.dump (f);
@@ -684,8 +675,6 @@ ssa_cache::dump (FILE *f)
}
 }
 
-  if (!print_header)
-fputc ('\n', f);
 }
 
 // Return true if NAME has an active range in the cache.
@@ -716,7 +705,7 @@ ssa_lazy_cache::set_range (tree name, const vrange )
 }
 
 // If NAME has a range, intersect it with R, otherwise set it to R.
-// Return TRUE if there was already a range set, otherwise false.
+// Return TRUE if the range is new or changes.
 
 bool
 ssa_lazy_cache::merge_range (tree name, const vrange )
@@ -731,7 +720,7 @@ ssa_lazy_cache::merge_range (tree name, const vrange )
   if (v >= m_tab.length ())
 m_tab.safe_grow (num_ssa_names + 1);
   m_tab[v] = m_range_allocator->clone (r);
-  return false;
+  return true;
 }
 
 // Return TRUE if NAME has a range, and return it in R.
@@ -996,6 +985,8 @@ ranger_cache::~ranger_cache ()
 void
 ranger_cache::dump (FILE *f)
 {
+  fprintf (f, "Non-varying global ranges:\n");
+  fprintf (f, "=:\n");
   m_globals.dump (f);
   fprintf (f, "\n");
 }


Re: [PATCH] [RFC] New early __builtin_unreachable processing.

2023-09-19 Thread Andrew MacLeod



On 9/19/23 08:56, Richard Biener wrote:

On Mon, Sep 18, 2023 at 3:48 PM Andrew MacLeod  wrote:


OK.

I dont see anything in the early VRP processing now that would allow a
later pass to remove the unreachable unless it does its own analysis
like DOM might do.

Isn't it as simple as

   if (i_2 > 5) __builtin_unreachable ();

registering a global range of [6, INF] for i_2 and then the next time
we fold if (i_2 > 5) using range info will eliminate it?  Yes, historically
that required VRP or DOM since nothing else looked at ranges, not
sure how it behaves now given more match.pd patterns do look
at (global) ranges.


if we set the range yes.   What I meant was in the cases where we decide 
it can't be removed, we do NOT set the range globally in vrp1 now. This 
means  unless some other pass determines the range is [6, +INF] the 
unreachcable call will remain in the IL and any ranger aware pass will 
still get the contextual range info resulting from the unreachable.  We 
were sometimes removing the unreachable without being able to update 
every affected global/future optimization opportunity, which this fixes. 
Hopefully :-)   Its certainly much better at least.


In theory, if inlining were aware of global ranges and propagated them, 
we could also now remove these some of these unreachables in EVRP rather 
than VRP1...   as I think we're now sure there is no benefit to keeping 
the unreachable call when we remove it.





In any case, thanks for the explanation and OK for the patch.


Will check it in shortly.

Andrew



Re: [PATCH] [RFC] New early __builtin_unreachable processing.

2023-09-18 Thread Andrew MacLeod via Gcc-patches



On 9/18/23 02:53, Richard Biener wrote:

On Fri, Sep 15, 2023 at 4:45 PM Andrew MacLeod  wrote:

Ive been looking at __builtin_unreachable () regressions.  The
fundamental problem seems to be  a lack of consistent expectation for
when we remove it earlier than the final pass of VRP.After looking
through them, I think this provides a sensible approach.

Ranger is pretty good at providing ranges in blocks dominated by the
__builtin_unreachable  branch, so removing it isn't quite a critical as
it once was.  Its also pretty good at identifying what in the block can
be affected by the branch.

This patch provide an alternate removal algorithm for earlier passes.
it looks at *all* the exports from the block, and if the branch
dominates every use of all the exports, AND none of those values access
memory, VRP will remove the unreachable call, rewrite the branch, update
all the values globally, and finally perform the simple DCE on the
branch's ssa-name.   This is kind of what it did before, but it wasn't
as stringent on the requirements.

The memory access check is required because there are a couple of test
cases for PRE in which there is a series of instruction leading to an
unreachable call, and none of those ssa names are ever used in the IL
again. The whole chunk is dead, and we update globals, however
pointlessly.  However, one of ssa_names loads from memory, and a later
passes commons this value with a later load, and then  the unreachable
call provides additional information about the later load.This is
evident in tree-ssa/ssa-pre-34.c.   The only way I see to avoid this
situation is to not remove the unreachable if there is a load feeding it.

What this does is a more sophisticated version of what DOM does in
all_uses_feed_or_dominated_by_stmt.  THe feeding instructions dont have
to be single use, but they do have to be dominated by the branch or be
single use within the branches block..

If there are multiple uses in the same block as the branch, this does
not remove the unreachable call.  If we could be sure there are no
intervening calls or side effects, it would be allowable, but this a
more expensive checking operation.  Ranger gets the ranges right anyway,
so with more passes using ranger, Im not sure we'd see much benefit from
the additional analysis.   It could always be added later.

This fixes at least 110249 and 110080 (and probably others).  The only
regression is 93917 for which I changed the testcase to adjust
expectations:

// PR 93917
void f1(int n)
{
if(n<0)
  __builtin_unreachable();
f3(n);
}

void f2(int*n)
{
if(*n<0)
  __builtin_unreachable();
f3 (*n);
}

We were removing both unreachable calls in VRP1, but only updating the
global values in the first case, meaning we lose information.   With the
change in semantics, we only update the global in the first case, but we
leave the unreachable call in the second case now (due to the load from
memory).  Ranger still calculates the contextual range correctly as [0,
+INF] in the second case, it just doesn't set the global value until
VRP2 when it is removed.

Does this seem reasonable?

I wonder how this addresses the fundamental issue we always faced
in that when we apply the range this range info in itself allows the
branch to the __builtin_unreachable () to be statically determined,
so when the first VRP pass sets the range the next pass evaluating
the condition will remove it (and the guarded __builtin_unreachable ()).

In principle there's nothing wrong with that if we don't lose the range
info during optimizations, but that unfortunately happens more often
than wanted and with the __builtin_unreachable () gone we've lost
the ability to re-compute them.

I think it's good to explicitly remove the branch at the point we want
rather than relying on the "next" visitor to pick up the global range.

As I read the patch we now remove __builtin_unreachable () explicitly
as soon as possible but don't really address the fundamental issue
in any way?



I think it pretty much addresses the issue completely.  No globals are 
updated by the unreachable branch unless it is removed.  We remove the 
unreachable early ONLY if every use of all the exports is dominated by 
the branch...    with the exception of a single use in the block used to 
define a different export. and those have to all have no other uses 
which are not dominated.  ie


  [local count: 1073741824]:
  y_2 = x_1(D) >> 1;
  t_3 = y_2 + 1;
  if (t_3 > 100)
    goto ; [0.00%]
  else
    goto ; [100.00%]

   [count: 0]:
  __builtin_unreachable ();

   [local count: 1073741824]:
  func (x_1(D), y_2, t_3);


In this case we will remove the unreachable call because we can provide 
an accurate global range for all values used in the definition chain for 
the program.


Global Exported (via early unreachable): x_1(D) = [irange] unsigned int 
[0, 199] MASK 0xff VALUE 0x0
Global Exported (via early unreachable): y_2 = [irange] u

[PATCH] [RFC] New early __builtin_unreachable processing.

2023-09-15 Thread Andrew MacLeod via Gcc-patches
Ive been looking at __builtin_unreachable () regressions.  The 
fundamental problem seems to be  a lack of consistent expectation for 
when we remove it earlier than the final pass of VRP.    After looking 
through them, I think this provides a sensible approach.


Ranger is pretty good at providing ranges in blocks dominated by the 
__builtin_unreachable  branch, so removing it isn't quite a critical as 
it once was.  Its also pretty good at identifying what in the block can 
be affected by the branch.


This patch provide an alternate removal algorithm for earlier passes.  
it looks at *all* the exports from the block, and if the branch 
dominates every use of all the exports, AND none of those values access 
memory, VRP will remove the unreachable call, rewrite the branch, update 
all the values globally, and finally perform the simple DCE on the 
branch's ssa-name.   This is kind of what it did before, but it wasn't 
as stringent on the requirements.


The memory access check is required because there are a couple of test 
cases for PRE in which there is a series of instruction leading to an 
unreachable call, and none of those ssa names are ever used in the IL 
again. The whole chunk is dead, and we update globals, however 
pointlessly.  However, one of ssa_names loads from memory, and a later 
passes commons this value with a later load, and then  the unreachable 
call provides additional information about the later load.    This is 
evident in tree-ssa/ssa-pre-34.c.   The only way I see to avoid this 
situation is to not remove the unreachable if there is a load feeding it.


What this does is a more sophisticated version of what DOM does in 
all_uses_feed_or_dominated_by_stmt.  THe feeding instructions dont have 
to be single use, but they do have to be dominated by the branch or be 
single use within the branches block..


If there are multiple uses in the same block as the branch, this does 
not remove the unreachable call.  If we could be sure there are no 
intervening calls or side effects, it would be allowable, but this a 
more expensive checking operation.  Ranger gets the ranges right anyway, 
so with more passes using ranger, Im not sure we'd see much benefit from 
the additional analysis.   It could always be added later.


This fixes at least 110249 and 110080 (and probably others).  The only 
regression is 93917 for which I changed the testcase to adjust 
expectations:


// PR 93917
void f1(int n)
{
  if(n<0)
    __builtin_unreachable();
  f3(n);
}

void f2(int*n)
{
  if(*n<0)
    __builtin_unreachable();
  f3 (*n);
}

We were removing both unreachable calls in VRP1, but only updating the 
global values in the first case, meaning we lose information.   With the 
change in semantics, we only update the global in the first case, but we 
leave the unreachable call in the second case now (due to the load from 
memory).  Ranger still calculates the contextual range correctly as [0, 
+INF] in the second case, it just doesn't set the global value until 
VRP2 when it is removed.


Does this seem reasonable?

Bootstraps on x86_64-pc-linux-gnu with no regressions.  OK?

Andrew


From 87072ebfcd4f51276fc6ed1fb0557257d51ec446 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Wed, 13 Sep 2023 11:52:15 -0400
Subject: [PATCH 3/3] New early __builtin_unreachable processing.

in VRP passes before __builtin_unreachable MUST be removed, only remove it
if all exports affected by the unreachable can have global values updated, and
do not involve loads from memory.

	PR tree-optimization/110080
	PR tree-optimization/110249
	gcc/
	* tree-vrp.cc (remove_unreachable::final_p): New.
	(remove_unreachable::maybe_register): Rename from
	maybe_register_block and call early or final routine.
	(fully_replaceable): New.
	(remove_unreachable::handle_early): New.
	(remove_unreachable::remove_and_update_globals): Remove
	non-final processing.
	(rvrp_folder::rvrp_folder): Add final flag to constructor.
	(rvrp_folder::post_fold_bb): Remove unreachable registration.
	(rvrp_folder::pre_fold_stmt): Move unreachable processing to here.
	(execute_ranger_vrp): Adjust some call parameters.

	gcc/testsuite/
	* g++.dg/pr110249.C: New.
	* gcc.dg/pr110080.c: New.
	* gcc.dg/pr93917.c: Adjust.

Tweak vuse case

Adjusted testcase 93917
---
 gcc/testsuite/g++.dg/pr110249.C |  16 +++
 gcc/testsuite/gcc.dg/pr110080.c |  27 +
 gcc/testsuite/gcc.dg/pr93917.c  |   7 +-
 gcc/tree-vrp.cc | 203 ++--
 4 files changed, 214 insertions(+), 39 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/pr110249.C
 create mode 100644 gcc/testsuite/gcc.dg/pr110080.c

diff --git a/gcc/testsuite/g++.dg/pr110249.C b/gcc/testsuite/g++.dg/pr110249.C
new file mode 100644
index 000..2b737618bdb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr110249.C
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-vrp1-alias" } */
+
+#include 
+#include 
+
+uint64_t read64

[COMMITTED 2/2] Always do PHI analysis before loop analysis.

2023-09-15 Thread Andrew MacLeod via Gcc-patches
The original invocation of phi_analysis was only invoked if there was no 
loop information available.  I have found situations where phi analysis 
enhances existing loop information, and as such this patch moves the phi 
analysis block to before loop analysis is invoked (in case a query is 
made from within that area), and does it unconditionally.  There is 
minimal impact on compilation time.


Bootstrapped on x86_64-pc-linux-gnu with no regressions.  Pushed.

Andrew
From 5d5f90ec3b4a939cae5ce4f33b76849f6b08e3a9 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Wed, 13 Sep 2023 10:09:16 -0400
Subject: [PATCH 2/3] Always do PHI analysis and before loop analysis.

PHI analysis wasn't being done if loop analysis found a value.  Always
do the PHI analysis, and run it for an iniital value before invoking
loop analysis.

	* gimple-range-fold.cc (fold_using_range::range_of_phi): Always
	run phi analysis, and do it before loop analysis.
---
 gcc/gimple-range-fold.cc | 53 
 1 file changed, 26 insertions(+), 27 deletions(-)

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index 03805d88d9b..d1945ccb554 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -939,7 +939,32 @@ fold_using_range::range_of_phi (vrange , gphi *phi, fur_source )
 	}
 }
 
-  bool loop_info_p = false;
+  // If PHI analysis is available, see if there is an iniital range.
+  if (phi_analysis_available_p ()
+  && irange::supports_p (TREE_TYPE (phi_def)))
+{
+  phi_group *g = (phi_analysis())[phi_def];
+  if (g && !(g->range ().varying_p ()))
+	{
+	  if (dump_file && (dump_flags & TDF_DETAILS))
+	{
+	  fprintf (dump_file, "PHI GROUP query for ");
+	  print_generic_expr (dump_file, phi_def, TDF_SLIM);
+	  fprintf (dump_file, " found : ");
+	  g->range ().dump (dump_file);
+	  fprintf (dump_file, " and adjusted original range from :");
+	  r.dump (dump_file);
+	}
+	  r.intersect (g->range ());
+	  if (dump_file && (dump_flags & TDF_DETAILS))
+	{
+	  fprintf (dump_file, " to :");
+	  r.dump (dump_file);
+	  fprintf (dump_file, "\n");
+	}
+	}
+}
+
   // If SCEV is available, query if this PHI has any known values.
   if (scev_initialized_p ()
   && !POINTER_TYPE_P (TREE_TYPE (phi_def)))
@@ -962,32 +987,6 @@ fold_using_range::range_of_phi (vrange , gphi *phi, fur_source )
 		  fprintf (dump_file, "\n");
 		}
 	  r.intersect (loop_range);
-	  loop_info_p = true;
-	}
-	}
-}
-
-  if (!loop_info_p && phi_analysis_available_p ()
-  && irange::supports_p (TREE_TYPE (phi_def)))
-{
-  phi_group *g = (phi_analysis())[phi_def];
-  if (g && !(g->range ().varying_p ()))
-	{
-	  if (dump_file && (dump_flags & TDF_DETAILS))
-	{
-	  fprintf (dump_file, "PHI GROUP query for ");
-	  print_generic_expr (dump_file, phi_def, TDF_SLIM);
-	  fprintf (dump_file, " found : ");
-	  g->range ().dump (dump_file);
-	  fprintf (dump_file, " and adjusted original range from :");
-	  r.dump (dump_file);
-	}
-	  r.intersect (g->range ());
-	  if (dump_file && (dump_flags & TDF_DETAILS))
-	{
-	  fprintf (dump_file, " to :");
-	  r.dump (dump_file);
-	  fprintf (dump_file, "\n");
 	}
 	}
 }
-- 
2.41.0



[COMMITTED 1/2] Fix indentation in range_of_phi.

2023-09-15 Thread Andrew MacLeod via Gcc-patches
Somewhere along the way a large sequence of code in range_of_phi() ended 
up with the same indentation of the preceeding loop.. this simply fixes it.


committed as obvious.

Andrew
From e35c3b5335879afb616c6ead0f41bf6c275ee941 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Wed, 13 Sep 2023 09:58:39 -0400
Subject: [PATCH 1/3] Fix indentation.

No functio0nal change, indentation was incorrect.

	* gimple-range-fold.cc (fold_using_range::range_of_phi): Fix
	indentation.
---
 gcc/gimple-range-fold.cc | 80 
 1 file changed, 40 insertions(+), 40 deletions(-)

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index 8ebff7f5980..03805d88d9b 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -898,46 +898,46 @@ fold_using_range::range_of_phi (vrange , gphi *phi, fur_source )
 	break;
 }
 
-// If all arguments were equivalences, use the equivalence ranges as no
-// arguments were processed.
-if (r.undefined_p () && !equiv_range.undefined_p ())
-  r = equiv_range;
-
-// If the PHI boils down to a single effective argument, look at it.
-if (single_arg)
-  {
-	// Symbolic arguments can be equivalences.
-	if (gimple_range_ssa_p (single_arg))
-	  {
-	// Only allow the equivalence if the PHI definition does not
-	// dominate any incoming edge for SINGLE_ARG.
-	// See PR 108139 and 109462.
-	basic_block bb = gimple_bb (phi);
-	if (!dom_info_available_p (CDI_DOMINATORS))
-	  single_arg = NULL;
-	else
-	  for (x = 0; x < gimple_phi_num_args (phi); x++)
-		if (gimple_phi_arg_def (phi, x) == single_arg
-		&& dominated_by_p (CDI_DOMINATORS,
-	gimple_phi_arg_edge (phi, x)->src,
-	bb))
-		  {
-		single_arg = NULL;
-		break;
-		  }
-	if (single_arg)
-	  src.register_relation (phi, VREL_EQ, phi_def, single_arg);
-	  }
-	else if (src.get_operand (arg_range, single_arg)
-		 && arg_range.singleton_p ())
-	  {
-	// Numerical arguments that are a constant can be returned as
-	// the constant. This can help fold later cases where even this
-	// constant might have been UNDEFINED via an unreachable edge.
-	r = arg_range;
-	return true;
-	  }
-  }
+  // If all arguments were equivalences, use the equivalence ranges as no
+  // arguments were processed.
+  if (r.undefined_p () && !equiv_range.undefined_p ())
+r = equiv_range;
+
+  // If the PHI boils down to a single effective argument, look at it.
+  if (single_arg)
+{
+  // Symbolic arguments can be equivalences.
+  if (gimple_range_ssa_p (single_arg))
+	{
+	  // Only allow the equivalence if the PHI definition does not
+	  // dominate any incoming edge for SINGLE_ARG.
+	  // See PR 108139 and 109462.
+	  basic_block bb = gimple_bb (phi);
+	  if (!dom_info_available_p (CDI_DOMINATORS))
+	single_arg = NULL;
+	  else
+	for (x = 0; x < gimple_phi_num_args (phi); x++)
+	  if (gimple_phi_arg_def (phi, x) == single_arg
+		  && dominated_by_p (CDI_DOMINATORS,
+  gimple_phi_arg_edge (phi, x)->src,
+  bb))
+		{
+		  single_arg = NULL;
+		  break;
+		}
+	  if (single_arg)
+	src.register_relation (phi, VREL_EQ, phi_def, single_arg);
+	}
+  else if (src.get_operand (arg_range, single_arg)
+	   && arg_range.singleton_p ())
+	{
+	  // Numerical arguments that are a constant can be returned as
+	  // the constant. This can help fold later cases where even this
+	  // constant might have been UNDEFINED via an unreachable edge.
+	  r = arg_range;
+	  return true;
+	}
+}
 
   bool loop_info_p = false;
   // If SCEV is available, query if this PHI has any known values.
-- 
2.41.0



Re: [PATCH] Checking undefined_p before using the vr

2023-09-15 Thread Andrew MacLeod via Gcc-patches



On 9/14/23 22:07, Jiufu Guo wrote:


undefined is a perfectly acceptable range.  It can be used to
represent either values which has not been initialized, or more
frequently it identifies values that cannot occur due to
conflicting/unreachable code.  VARYING means it can be any range,
UNDEFINED means this is unusable, so treat it accordingly.  Its
propagated like any other range.

"undefined" means the ranger is unusable. So, for this ranger, it
seems only "undefined_p ()" can be checked, and it seems no other
functions of this ranger can be called.


not at all. It means ranger has determined that there is no valid range 
for the item you are asking about probably due to conflicting 
conditions, which imparts important information about the range.. or 
lack of range :-)


Quite frequently it means you are looking at a block of code that ranger 
knows is unreachable, but a pass of the compiler which removes such 
blocks has not been called yet.. so the awareness imparted is that there 
isn't much point in doing optimizations on it because its probably going 
to get thrown away by a following pass.




I'm thinking that it may be ok to let "range_of_expr" return false
if the "vr" is "undefined_p".  I know this may change the meaning
of "range_of_expr" slightly :)


No.  That would be like saying NULL is not a valid value for a pointer.  
undefined_p has very specific meaning that we use.. it just has no type.


Andrew



Re: [PATCH] Checking undefined_p before using the vr

2023-09-13 Thread Andrew MacLeod via Gcc-patches



On 9/12/23 21:42, Jiufu Guo wrote:

Hi,

Richard Biener  writes:


On Thu, 7 Sep 2023, Jiufu Guo wrote:


Hi,

As discussed in PR111303:

For pattern "(X + C) / N": "div (plus@3 @0 INTEGER_CST@1) INTEGER_CST@2)",
Even if "X" has value-range and "X + C" does not overflow, "@3" may still
be undefined. Like below example:

_3 = _2 + -5;
if (0 != 0)
   goto ; [34.00%]
else
   goto ; [66.00%]
;;  succ:   3
;;  4

;; basic block 3, loop depth 0
;;  pred:   2
_5 = _3 / 5;
;;  succ:   4

The whole pattern "(_2 + -5 ) / 5" is in "bb 3", but "bb 3" would be
unreachable (because "if (0 != 0)" is always false).
And "get_range_query (cfun)->range_of_expr (vr3, @3)" is checked in
"bb 3", "range_of_expr" gets an "undefined vr3". Where "@3" is "_5".

So, before using "vr3", it would be safe to check "!vr3.undefined_p ()".

Bootstrap & regtest pass on ppc64{,le} and x86_64.
Is this ok for trunk?

OK, but I wonder why ->range_of_expr () doesn't return false for
undefined_p ()?  While "undefined" technically means we can treat
it as nonnegative_p (or not, maybe but maybe not both), we seem to
not want to do that.  So why expose it at all to ranger users
(yes, internally we in some places want to handle undefined).

I guess, currently, it returns true and then lets the user check
undefined_p, maybe because it tries to only return false if the
type of EXPR is unsupported.


false is returned if no range can be calculated for any reason. The most 
common ones are unsupported types or in some cases, statements that are 
not understood.  FALSE means you cannot use the range being passed in.




Let "range_of_expr" return false for undefined_p would save checking
undefined_p again when using the APIs.

undefined is a perfectly acceptable range.  It can be used to represent 
either values which has not been initialized, or more frequently it 
identifies values that cannot occur due to conflicting/unreachable 
code.  VARYING means it can be any range, UNDEFINED means this is 
unusable, so treat it accordingly.  Its propagated like any other range.


The only reason you are having issues is you are then asking for the 
type of the range, and an undefined range currently has no type, for 
historical reasons.


Andrew

Andrew




[COMMITTED] PR tree-optimization/110875 - Some ssa-names get incorrectly marked as always_current.

2023-09-07 Thread Andrew MacLeod via Gcc-patches
When range_of_stmt invokes prefill_name to evaluate unvisited 
dependneciesit should not mark visited names as always_current.


when raner_cache::get_globaL_range() is invoked with the optional  
"current_p" flag, it triggers additional functionality. This call is 
meant to be from within ranger and it is understood that if the current 
value is not current,  set_global_range will always be called later with 
a value.  Thus it sets the always_current flag in the temporal cache to 
avoid computation cycles.


the prefill_stmt_dependencies () mechanism within ranger is intended to 
emulate the bahaviour od range_of_stmt on an arbitrarily long series of 
unresolved dependencies without triggering the overhead of huge call 
chains from the range_of_expr/range_on_entry/range_on_exit routines.  
Rather, it creates a stack of unvisited names, and invokes range_of_stmt 
on them directly in order to get initial cache values for each ssa-name.


The issue in this PR was that routine was incorrectly invoking the 
get_global_cache to determine whether there was a global value.  If 
there was, it would move on to the next dependency without invoking 
set_global_range to clear the always_current flag.


What it soudl have been doing was simply checking if there as a global 
value, and if there was not, add the name for processingand THEN invoke 
get_global_value to do all the special processing.


Bootstraps on x86_64-pc-linux-gnu with no regressions.  Pushed.

Andrew




From e9be59f7d2dc6b302cf85ad69b0a77dee89ec809 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Thu, 7 Sep 2023 11:15:50 -0400
Subject: [PATCH] Some ssa-names get incorrectly marked as always_current.

When range_of_stmt invokes prefill_name to evaluate unvisited dependencies
it should not mark already visited names as always_current.

	PR tree-optimization/110875
	gcc/
	* gimple-range.cc (gimple_ranger::prefill_name): Only invoke
	cache-prefilling routine when the ssa-name has no global value.

	gcc/testsuite/
	* gcc.dg/pr110875.c: New.
---
 gcc/gimple-range.cc | 10 +++---
 gcc/testsuite/gcc.dg/pr110875.c | 34 +
 2 files changed, 41 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr110875.c

diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 01173c58f02..13c3308d537 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -351,10 +351,14 @@ gimple_ranger::prefill_name (vrange , tree name)
   if (!gimple_range_op_handler::supported_p (stmt) && !is_a (stmt))
 return;
 
-  bool current;
   // If this op has not been processed yet, then push it on the stack
-  if (!m_cache.get_global_range (r, name, current))
-m_stmt_list.safe_push (name);
+  if (!m_cache.get_global_range (r, name))
+{
+  bool current;
+  // Set the global cache value and mark as alway_current.
+  m_cache.get_global_range (r, name, current);
+  m_stmt_list.safe_push (name);
+}
 }
 
 // This routine will seed the global cache with most of the dependencies of
diff --git a/gcc/testsuite/gcc.dg/pr110875.c b/gcc/testsuite/gcc.dg/pr110875.c
new file mode 100644
index 000..4d6ecbca0c8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr110875.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-vrp2" } */
+
+void foo(void);
+static int a, b;
+static int *c = , *d;
+static unsigned e;
+static short f;
+static unsigned g(unsigned char h, char i) { return h + i; }
+int main() {
+d = 
+int *j = d;
+e = -27;
+for (; e > 18; e = g(e, 6)) {
+a = 0;
+for (; a != -3; a--) {
+if (0 != a ^ *j)
+for (; b; b++) f = -f;
+else if (*c) {
+foo();
+break;
+}
+if (!(((e) >= 235) && ((e) <= 4294967269))) {
+__builtin_unreachable();
+}
+b = 0;
+}
+}
+}
+
+
+/* { dg-final { scan-tree-dump-not "foo" "vrp2" } } */
+
+
-- 
2.41.0



Re: [PATCH 2/2] VR-VALUES: Rewrite test_for_singularity using range_op_handler

2023-09-07 Thread Andrew MacLeod via Gcc-patches



On 9/1/23 02:40, Andrew Pinski wrote:

On Fri, Aug 11, 2023 at 8:08 AM Andrew MacLeod via Gcc-patches
 wrote:


If this is only going to work with integers, you might want to check
that somewhere or switch to irange and int_range_max..

You can make it work with any kind (if you know op1 is a constant) by
simply doing

Value_Range op1_range (TREE_TYPE (op1))
get_global_range_query->range_of_expr (op1_range, op1)

That will convert trees to a the appropriate range...  THis is also true
for integer constants... but you can also just do the WI conversion like
you do.

The routine also get confusing to read because it passes in op0 and
op1,  but of course ranger uses op1 and op2 nomenclature, and it looks a
bit confusing :-P   I'd change the operands passed in to op1 and op2 if
we are rewriting the routine.

Ranger using the nomenclature of op1/op2 and gimple is inconsistent
with trees and other parts of GCC.
It seems like we have to live with this inconsistency now too.
Renaming things in this one function to op1/op2 might be ok but the
rest of the file uses op0/op1 too; most likely because it was
originally written before gimple.

I think it would be good to have this written in the coding style,
which way should we have it for new code; if we start at 0 or 1 for
operands. It might reduce differences based on who wrote which part
(and even to some extent when). I don't really care which one is
picked as long as we pick one.

Thanks,
Andrew Pinski

I certainly wont argue it would be good to be consistent, but of course 
its quite prevalent. Perhaps we should rewrite vr-values.cc to change 
the terminology in one patch?


long term some of it is likely to get absorbed into rangeops, and what 
isn't could/should be made vrange/irange  aware...  no one has gotten to 
it yet. we could change the terminology as the routines are reworked too...


Andrew




[COMMITTED 2/2] tree-optimization/110918 - Phi analyzer - Initialize with a range instead of a tree.

2023-08-23 Thread Andrew MacLeod via Gcc-patches
Rangers PHI analyzer currently only allows a single initializing value 
to a group. This patch changes that to use an initialization range, which is
cumulative of all integer constants, plus a single symbolic value.  
There were many times when there were multiple constants feeding into 
PHIs and there is no reason to disqualify those from determining if 
there is a better starting range for a PHI,


This patch also changes the way PHI groups are printed so they show up 
in the listing as they are encountered, rather than as a list at the 
end.  It was quite difficult to see what was going on when it simply 
dumped the groups at the end of processing.


Bootstraps on x86_64-pc-linux-gnu with no regressions.  Pushed.

Andrew
From bd50bbfa95e51edf51392f147e9a860adb5f495e Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Thu, 17 Aug 2023 12:34:59 -0400
Subject: [PATCH 2/4] Phi analyzer - Initialize with range instead of a tree.

Rangers PHI analyzer currently only allows a single initializer to a group.
This patch changes that to use an inialization range, which is
cumulative of all integer constants, plus a single symbolic value.  There is no other change to group functionality.

This patch also changes the way PHI groups are printed so they show up in the
listing as they are encountered, rather than as a list at the end.  It
was more difficult to see what was going on previously.

	PR tree-optimization/110918 - Initialize with range instead of a tree.
	gcc/
	* gimple-range-fold.cc (fold_using_range::range_of_phi): Tweak output.
	* gimple-range-phi.cc (phi_group::phi_group): Remove unused members.
	Initialize using a range instead of value and edge.
	(phi_group::calculate_using_modifier): Use initializer value and
	process for relations after trying for iteration convergence.
	(phi_group::refine_using_relation): Use initializer range.
	(phi_group::dump): Rework the dump output.
	(phi_analyzer::process_phi): Allow multiple constant initilizers.
	Dump groups immediately as created.
	(phi_analyzer::dump): Tweak output.
	* gimple-range-phi.h (phi_group::phi_group): Adjust prototype.
	(phi_group::initial_value): Delete.
	(phi_group::refine_using_relation): Adjust prototype.
	(phi_group::m_initial_value): Delete.
	(phi_group::m_initial_edge): Delete.
	(phi_group::m_vr): Use int_range_max.
	* tree-vrp.cc (execute_ranger_vrp): Don't dump phi groups.

	gcc/testsuite/
	* gcc.dg/pr102983.c: Adjust output expectations.
	* gcc.dg/pr110918.c: New.
---
 gcc/gimple-range-fold.cc|   6 +-
 gcc/gimple-range-phi.cc | 186 
 gcc/gimple-range-phi.h  |   9 +-
 gcc/testsuite/gcc.dg/pr102983.c |   2 +-
 gcc/testsuite/gcc.dg/pr110918.c |  26 +
 gcc/tree-vrp.cc |   5 +-
 6 files changed, 129 insertions(+), 105 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr110918.c

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index 7fa5a27cb12..8ebff7f5980 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -953,7 +953,7 @@ fold_using_range::range_of_phi (vrange , gphi *phi, fur_source )
 	{
 	  if (dump_file && (dump_flags & TDF_DETAILS))
 		{
-		  fprintf (dump_file, "   Loops range found for ");
+		  fprintf (dump_file, "Loops range found for ");
 		  print_generic_expr (dump_file, phi_def, TDF_SLIM);
 		  fprintf (dump_file, ": ");
 		  loop_range.dump (dump_file);
@@ -975,9 +975,9 @@ fold_using_range::range_of_phi (vrange , gphi *phi, fur_source )
 	{
 	  if (dump_file && (dump_flags & TDF_DETAILS))
 	{
-	  fprintf (dump_file, "   PHI group range found for ");
+	  fprintf (dump_file, "PHI GROUP query for ");
 	  print_generic_expr (dump_file, phi_def, TDF_SLIM);
-	  fprintf (dump_file, ": ");
+	  fprintf (dump_file, " found : ");
 	  g->range ().dump (dump_file);
 	  fprintf (dump_file, " and adjusted original range from :");
 	  r.dump (dump_file);
diff --git a/gcc/gimple-range-phi.cc b/gcc/gimple-range-phi.cc
index a94b90a4660..9884a0ebbb0 100644
--- a/gcc/gimple-range-phi.cc
+++ b/gcc/gimple-range-phi.cc
@@ -79,39 +79,33 @@ phi_analyzer _analysis ()
 phi_group::phi_group (const phi_group )
 {
   m_group = g.m_group;
-  m_initial_value = g.m_initial_value;
-  m_initial_edge = g.m_initial_edge;
   m_modifier = g.m_modifier;
   m_modifier_op = g.m_modifier_op;
   m_vr = g.m_vr;
 }
 
-// Create a new phi_group with members BM, initialvalue INIT_VAL, modifier
-// statement MOD, and resolve values using query Q.
-// Calculate the range for the gropup if possible, otherwise set it to
-// VARYING.
+// Create a new phi_group with members BM, initial range INIT_RANGE, modifier
+// statement MOD on edge MOD_EDGE, and resolve values using query Q.  Calculate
+// the range for the group if possible, otherwise set it to VARYING.
 
-phi_group::phi_group (bitmap bm, tree init_val,

[COMMITTED 1/2] Phi analyzer - Do not create phi groups with a single phi.

2023-08-23 Thread Andrew MacLeod via Gcc-patches
Rangers Phi Analyzer was creating a group consisting of a single PHI, 
which was problematic.  It didn't really help anything, and it prevented 
larger groups from including those PHIs and stopped some useful things 
from happening.


Bootstrapped on x86_64-pc-linux-gnu  with no regressions. Pushed.

Andrew
From 9855b3f0a2869d456f0ee34a94a1231eb6d44c4a Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Wed, 16 Aug 2023 13:23:06 -0400
Subject: [PATCH 1/4] Don't process phi groups with one phi.

The phi analyzer should not create a phi group containing a single phi.

	* gimple-range-phi.cc (phi_analyzer::operator[]): Return NULL if
	no group was created.
	(phi_analyzer::process_phi): Do not create groups of one phi node.
---
 gcc/gimple-range-phi.cc | 16 +++-
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/gcc/gimple-range-phi.cc b/gcc/gimple-range-phi.cc
index ffb4691d06b..a94b90a4660 100644
--- a/gcc/gimple-range-phi.cc
+++ b/gcc/gimple-range-phi.cc
@@ -344,9 +344,10 @@ phi_analyzer::operator[] (tree name)
   process_phi (as_a (SSA_NAME_DEF_STMT (name)));
   if (bitmap_bit_p (m_simple, v))
 	return  NULL;
-  // If m_simple bit isn't set, then process_phi allocated the table
-  // and should have a group.
-  gcc_checking_assert (v < m_tab.length ());
+ // If m_simple bit isn't set, and process_phi didn't allocated the table
+ // no group was created, so return NULL.
+ if (v >= m_tab.length ())
+  return NULL;
 }
   return m_tab[v];
 }
@@ -363,6 +364,7 @@ phi_analyzer::process_phi (gphi *phi)
   unsigned x;
   m_work.truncate (0);
   m_work.safe_push (gimple_phi_result (phi));
+  unsigned phi_count = 1;
   bitmap_clear (m_current);
 
   // We can only have 2 externals: an initial value and a modifier.
@@ -407,6 +409,7 @@ phi_analyzer::process_phi (gphi *phi)
 	  gimple *arg_stmt = SSA_NAME_DEF_STMT (arg);
 	  if (arg_stmt && is_a (arg_stmt))
 		{
+		  phi_count++;
 		  m_work.safe_push (arg);
 		  continue;
 		}
@@ -430,9 +433,12 @@ phi_analyzer::process_phi (gphi *phi)
 	}
 }
 
-  // If there are no names in the group, we're done.
-  if (bitmap_empty_p (m_current))
+  // If there are less than 2 names, just return.  This PHI may be included
+  // by another PHI, making it simple or a group of one will prevent a larger
+  // group from being formed.
+  if (phi_count < 2)
 return;
+  gcc_checking_assert (!bitmap_empty_p (m_current));
 
   phi_group *g = NULL;
   if (cycle_p)
-- 
2.41.0



[COMMITTED] PR tree-optimization/111009 - Fix range-ops operator_addr.

2023-08-17 Thread Andrew MacLeod via Gcc-patches
operator_addr was simply calling fold_range() to implement op1_range, 
but it turns out op1_range needs to be more restrictive.


take for example  from the PR :

   _13 = >maj

when folding,  getting a value of 0 for op1 means dso->maj resolved to a 
value of [0,0].  fold_using_range::range_of_address will have processed 
the symbolics, or at least we know that op1 is 0.  Likewise if it is 
non-zero, we can also conclude the LHS is non-zero.


however, when working from the LHS, we cannot make the same 
conclusions.  GORI has no concept of symblics, so knowing the expressions is


[0,0]  = & 

 we cannot conclude the op1 is also 0.. in particular >maj wouldnt 
be unless dso was zero and maj was also a zero offset.
Likewise if the LHS is [1,1] we cant be sure op1 is nonzero unless we 
know the type cannot wrap.


This patch simply implements op1_range with these rules instead of 
calling fold_range.


Bootstrapped on x86_64-pc-linux-gnu with no regressions.  Pushed.

Andrew
From dc48d1d1d4458773f89f21b2f019f66ddf88f2e5 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Thu, 17 Aug 2023 11:13:14 -0400
Subject: [PATCH] Fix range-ops operator_addr.

Lack of symbolic information prevents op1_range from beig able to draw
the same conclusions as fold_range can.

PR tree-optimization/111009
gcc/
* range-op.cc (operator_addr_expr::op1_range): Be more restrictive.

gcc/testsuite/
* gcc.dg/pr111009.c: New.
---
 gcc/range-op.cc | 12 ++-
 gcc/testsuite/gcc.dg/pr111009.c | 38 +
 2 files changed, 49 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr111009.c

diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 086c6c19735..268f6b6f025 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -4325,7 +4325,17 @@ operator_addr_expr::op1_range (irange , tree type,
   const irange ,
   relation_trio) const
 {
-  return operator_addr_expr::fold_range (r, type, lhs, op2);
+   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 (!contains_zero_p (lhs) && TYPE_OVERFLOW_UNDEFINED (type))
+r = range_nonzero (type);
+  else
+r.set_varying (type);
+  return true;
 }
 
 // Initialize any integral operators to the primary table
diff --git a/gcc/testsuite/gcc.dg/pr111009.c b/gcc/testsuite/gcc.dg/pr111009.c
new file mode 100644
index 000..3accd9ac063
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr111009.c
@@ -0,0 +1,38 @@
+/* PR tree-optimization/111009 */
+/* { dg-do run } */
+/* { dg-options "-O3 -fno-strict-overflow" } */
+
+struct dso {
+ struct dso * next;
+ int maj;
+};
+
+__attribute__((noipa)) static void __dso_id__cmp_(void) {}
+
+__attribute__((noipa))
+static int bug(struct dso * d, struct dso *dso)
+{
+ struct dso **p = 
+ struct dso *curr = 0;
+
+ while (*p) {
+  curr = *p;
+  // prevent null deref below
+  if (!dso) return 1;
+  if (dso == curr) return 1;
+
+  int *a = >maj;
+  // null deref
+  if (!(a && *a)) __dso_id__cmp_();
+
+  p = >next;
+ }
+ return 0;
+}
+
+__attribute__((noipa))
+int main(void) {
+struct dso d = { 0, 0, };
+bug(, 0);
+}
+
-- 
2.41.0



Re: [PATCH 2/2] VR-VALUES: Rewrite test_for_singularity using range_op_handler

2023-08-11 Thread Andrew MacLeod via Gcc-patches



On 8/11/23 05:51, Richard Biener wrote:

On Fri, Aug 11, 2023 at 11:17 AM Andrew Pinski via Gcc-patches
 wrote:

So it turns out there was a simplier way of starting to
improve VRP to start to fix PR 110131, PR 108360, and PR 108397.
That was rewrite test_for_singularity to use range_op_handler
and Value_Range.

This patch implements that and

OK? Bootstrapped and tested on x86_64-linux-gnu with no regressions.

I'm hoping Andrew/Aldy can have a look here.

Richard.


gcc/ChangeLog:

 * vr-values.cc (test_for_singularity): Add edge argument
 and rewrite using range_op_handler.
 (simplify_compare_using_range_pairs): Use Value_Range
 instead of value_range and update test_for_singularity call.

gcc/testsuite/ChangeLog:

 * gcc.dg/tree-ssa/vrp124.c: New test.
 * gcc.dg/tree-ssa/vrp125.c: New test.
---
  gcc/testsuite/gcc.dg/tree-ssa/vrp124.c | 44 +
  gcc/testsuite/gcc.dg/tree-ssa/vrp125.c | 44 +
  gcc/vr-values.cc   | 91 --
  3 files changed, 114 insertions(+), 65 deletions(-)
  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp124.c
  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp125.c

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp124.c 
b/gcc/testsuite/gcc.dg/tree-ssa/vrp124.c
new file mode 100644
index 000..6ccbda35d1b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp124.c
@@ -0,0 +1,44 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+/* Should be optimized to a == -100 */
+int g(int a)
+{
+  if (a == -100 || a >= 0)
+;
+  else
+return 0;
+  return a < 0;
+}
+
+/* Should optimize to a == 0 */
+int f(int a)
+{
+  if (a == 0 || a > 100)
+;
+  else
+return 0;
+  return a < 50;
+}
+
+/* Should be optimized to a == 0. */
+int f2(int a)
+{
+  if (a == 0 || a > 100)
+;
+  else
+return 0;
+  return a < 100;
+}
+
+/* Should optimize to a == 100 */
+int f1(int a)
+{
+  if (a < 0 || a == 100)
+;
+  else
+return 0;
+  return a > 50;
+}
+
+/* { dg-final { scan-tree-dump-not "goto " "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp125.c 
b/gcc/testsuite/gcc.dg/tree-ssa/vrp125.c
new file mode 100644
index 000..f6c2f8e35f1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp125.c
@@ -0,0 +1,44 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+/* Should be optimized to a == -100 */
+int g(int a)
+{
+  if (a == -100 || a == -50 || a >= 0)
+;
+  else
+return 0;
+  return a < -50;
+}
+
+/* Should optimize to a == 0 */
+int f(int a)
+{
+  if (a == 0 || a == 50 || a > 100)
+;
+  else
+return 0;
+  return a < 50;
+}
+
+/* Should be optimized to a == 0. */
+int f2(int a)
+{
+  if (a == 0 || a == 50 || a > 100)
+;
+  else
+return 0;
+  return a < 25;
+}
+
+/* Should optimize to a == 100 */
+int f1(int a)
+{
+  if (a < 0 || a == 50 || a == 100)
+;
+  else
+return 0;
+  return a > 50;
+}
+
+/* { dg-final { scan-tree-dump-not "goto " "optimized" } } */
diff --git a/gcc/vr-values.cc b/gcc/vr-values.cc
index a4fddd62841..7004b0224bd 100644
--- a/gcc/vr-values.cc
+++ b/gcc/vr-values.cc
@@ -907,66 +907,30 @@ simplify_using_ranges::simplify_bit_ops_using_ranges
 a known value range VR.

 If there is one and only one value which will satisfy the
-   conditional, then return that value.  Else return NULL.
-
-   If signed overflow must be undefined for the value to satisfy
-   the conditional, then set *STRICT_OVERFLOW_P to true.  */
+   conditional on the EDGE, then return that value.
+   Else return NULL.  */

  static tree
  test_for_singularity (enum tree_code cond_code, tree op0,
- tree op1, const value_range *vr)
+ tree op1, Value_Range vr, bool edge)


VR should be a "vrange &".   THis is the top level base class for all 
ranges of all types/kinds, and what we usually pass values around as if 
we want tohem to be any kind.   If this is inetger only, we'd pass a an 
'irange &'


Value_Range is the opposite. Its the sink that contains one of each kind 
of range and can switch around between them as needed. You do not want 
to pass that by value!   The generic engine uses these so it can suppose 
floats. int, pointers, whatever...



  {
-  tree min = NULL;
-  tree max = NULL;
-
-  /* Extract minimum/maximum values which satisfy the conditional as it was
- written.  */
-  if (cond_code == LE_EXPR || cond_code == LT_EXPR)
+  /* This is already a singularity.  */
+  if (cond_code == NE_EXPR || cond_code == EQ_EXPR)
+return NULL;
+  auto range_op = range_op_handler (cond_code);
+  int_range<2> op1_range (TREE_TYPE (op0));
+  wide_int w = wi::to_wide (op1);
+  op1_range.set (TREE_TYPE (op1), w, w);


If this is only going to work with integers, you might want to check 
that somewhere or switch to irange and int_range_max..


You can make it work with any kind (if you know op1 is a constant) by 

[COMMITTED] Add operand ranges to op1_op2_relation API.

2023-08-03 Thread Andrew MacLeod via Gcc-patches
We're looking to add the unordered relations for floating point, and as 
a result, we can no longer determine the relation between op1 and op2 in 
a statement based purely on the LHS... we also need to know the type of 
the operands on the RHS.


This patch adjusts op1_op2_relation to fit the same mold as 
fold_range... ie, takes 3 vrange instead of just a LHS.


It also copies the functionality of the integral relations to the 
floating point counterparts, and when the unordered relations are added, 
those floating point routines can be adjusted to do the right thing.


This results in no current functional changes.

Bootstraps on  x86_64-pc-linux-gnu with no regressions.   Pushed.

Andrew
From de7ae277f497ed5b533af877fe26d8f133760f8b Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Tue, 1 Aug 2023 14:33:09 -0400
Subject: [PATCH 3/3] Add operand ranges to op1_op2_relation API.

With additional floating point relations in the pipeline, we can no
longer tell based on the LHS what the relation of X < Y is without knowing
the type of X and Y.

	* gimple-range-fold.cc (fold_using_range::range_of_range_op): Add
	ranges to the call to relation_fold_and_or.
	(fold_using_range::relation_fold_and_or): Add op1 and op2 ranges.
	(fur_source::register_outgoing_edges): Add op1 and op2 ranges.
	* gimple-range-fold.h (relation_fold_and_or): Adjust params.
	* gimple-range-gori.cc (gori_compute::compute_operand_range): Add
	a varying op1 and op2 to call.
	* range-op-float.cc (range_operator::op1_op2_relation): New dafaults.
	(operator_equal::op1_op2_relation): New float version.
	(operator_not_equal::op1_op2_relation): Ditto.
	(operator_lt::op1_op2_relation): Ditto.
	(operator_le::op1_op2_relation): Ditto.
	(operator_gt::op1_op2_relation): Ditto.
	(operator_ge::op1_op2_relation) Ditto.
	* range-op-mixed.h (operator_equal::op1_op2_relation): New float
	prototype.
	(operator_not_equal::op1_op2_relation): Ditto.
	(operator_lt::op1_op2_relation): Ditto.
	(operator_le::op1_op2_relation): Ditto.
	(operator_gt::op1_op2_relation): Ditto.
	(operator_ge::op1_op2_relation): Ditto.
	* range-op.cc (range_op_handler::op1_op2_relation): Dispatch new
	variations.
	(range_operator::op1_op2_relation): Add extra params.
	(operator_equal::op1_op2_relation): Ditto.
	(operator_not_equal::op1_op2_relation): Ditto.
	(operator_lt::op1_op2_relation): Ditto.
	(operator_le::op1_op2_relation): Ditto.
	(operator_gt::op1_op2_relation): Ditto.
	(operator_ge::op1_op2_relation): Ditto.
	* range-op.h (range_operator): New prototypes.
	(range_op_handler): Ditto.
---
 gcc/gimple-range-fold.cc |  26 +---
 gcc/gimple-range-fold.h  |   3 +-
 gcc/gimple-range-gori.cc |   5 +-
 gcc/range-op-float.cc| 129 ++-
 gcc/range-op-mixed.h |  30 +++--
 gcc/range-op.cc  |  41 +
 gcc/range-op.h   |  15 -
 7 files changed, 216 insertions(+), 33 deletions(-)

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index ab2d996c4eb..7fa5a27cb12 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -700,7 +700,7 @@ fold_using_range::range_of_range_op (vrange ,
    relation_trio::op1_op2 (rel)))
 	r.set_varying (type);
 	  if (irange::supports_p (type))
-	relation_fold_and_or (as_a  (r), s, src);
+	relation_fold_and_or (as_a  (r), s, src, range1, range2);
 	  if (lhs)
 	{
 	  if (src.gori ())
@@ -1103,7 +1103,8 @@ fold_using_range::range_of_ssa_name_with_loop_info (vrange , tree name,
 
 void
 fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s,
-	fur_source )
+	fur_source , vrange ,
+	vrange )
 {
   // No queries or already folded.
   if (!src.gori () || !src.query ()->oracle () || lhs_range.singleton_p ())
@@ -1164,9 +1165,8 @@ fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s,
 return;
 
   int_range<2> bool_one = range_true ();
-
-  relation_kind relation1 = handler1.op1_op2_relation (bool_one);
-  relation_kind relation2 = handler2.op1_op2_relation (bool_one);
+  relation_kind relation1 = handler1.op1_op2_relation (bool_one, op1, op2);
+  relation_kind relation2 = handler2.op1_op2_relation (bool_one, op1, op2);
   if (relation1 == VREL_VARYING || relation2 == VREL_VARYING)
 return;
 
@@ -1201,7 +1201,8 @@ fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s,
 // Register any outgoing edge relations from a conditional branch.
 
 void
-fur_source::register_outgoing_edges (gcond *s, irange _range, edge e0, edge e1)
+fur_source::register_outgoing_edges (gcond *s, irange _range,
+ edge e0, edge e1)
 {
   int_range<2> e0_range, e1_range;
   tree name;
@@ -1236,17 +1237,20 @@ fur_source::register_outgoing_edges (gcond *s, irange _range, edge e0, edge
   // if (a_2 < b_5)
   tree ssa1 = gimple_range_ssa_p (handler.operand1 ());
   tree ssa2 = gimple_range_ssa_p (handler.operand2 ());
+  Value_Range r1,r2;
   if (ssa1 && ssa2

[COMMITTED] Provide a routine for NAME == NAME relation.

2023-08-03 Thread Andrew MacLeod via Gcc-patches
We've been assuming x == x is always VREL_EQ in GORI, but this is not 
always going to be true with floating point.  Provide an API to return 
the relation.


Bootstraps on  x86_64-pc-linux-gnu with no regressions.   Pushed.

Andrew
From 430ff4f3e670e02185991190a5e2d90e61b39e07 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Wed, 2 Aug 2023 10:58:37 -0400
Subject: [PATCH 2/3] Provide a routine for NAME == NAME relation.

We've been assuming x == x s VREL_EQ in GORI, but this is not always going to
be true with floating point.  Provide an API to return the relation.

	* gimple-range-gori.cc (gori_compute::compute_operand1_range):
	Use identity relation.
	(gori_compute::compute_operand2_range): Ditto.
	* value-relation.cc (get_identity_relation): New.
	* value-relation.h (get_identity_relation): New prototype.
---
 gcc/gimple-range-gori.cc | 10 --
 gcc/value-relation.cc| 14 ++
 gcc/value-relation.h |  3 +++
 3 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc
index 6dc15a0ce3f..c37e54bcf84 100644
--- a/gcc/gimple-range-gori.cc
+++ b/gcc/gimple-range-gori.cc
@@ -1142,7 +1142,10 @@ gori_compute::compute_operand1_range (vrange ,
 
   // If op1 == op2, create a new trio for just this call.
   if (op1 == op2 && gimple_range_ssa_p (op1))
-	trio = relation_trio (trio.lhs_op1 (), trio.lhs_op2 (), VREL_EQ);
+	{
+	  relation_kind k = get_identity_relation (op1, op1_range);
+	  trio = relation_trio (trio.lhs_op1 (), trio.lhs_op2 (), k);
+	}
   if (!handler.calc_op1 (r, lhs, op2_range, trio))
 	return false;
 }
@@ -1218,7 +1221,10 @@ gori_compute::compute_operand2_range (vrange ,
 
   // If op1 == op2, create a new trio for this stmt.
   if (op1 == op2 && gimple_range_ssa_p (op1))
-trio = relation_trio (trio.lhs_op1 (), trio.lhs_op2 (), VREL_EQ);
+{
+  relation_kind k = get_identity_relation (op1, op1_range);
+  trio = relation_trio (trio.lhs_op1 (), trio.lhs_op2 (), k);
+}
   // Intersect with range for op2 based on lhs and op1.
   if (!handler.calc_op2 (r, lhs, op1_range, trio))
 return false;
diff --git a/gcc/value-relation.cc b/gcc/value-relation.cc
index 7df2cd6e961..f2c668a0193 100644
--- a/gcc/value-relation.cc
+++ b/gcc/value-relation.cc
@@ -183,6 +183,20 @@ relation_transitive (relation_kind r1, relation_kind r2)
   return relation_kind (rr_transitive_table[r1][r2]);
 }
 
+// When operands of a statement are identical ssa_names, return the
+// approriate relation between operands for NAME == NAME, given RANGE.
+//
+relation_kind
+get_identity_relation (tree name, vrange  ATTRIBUTE_UNUSED)
+{
+  // Return VREL_UNEQ when it is supported for floats as appropriate.
+  if (frange::supports_p (TREE_TYPE (name)))
+return VREL_EQ;
+
+  // Otherwise return VREL_EQ.
+  return VREL_EQ;
+}
+
 // This vector maps a relation to the equivalent tree code.
 
 static const tree_code relation_to_code [VREL_LAST] = {
diff --git a/gcc/value-relation.h b/gcc/value-relation.h
index be6e277421b..f00f84f93b6 100644
--- a/gcc/value-relation.h
+++ b/gcc/value-relation.h
@@ -91,6 +91,9 @@ inline bool relation_equiv_p (relation_kind r)
 
 void print_relation (FILE *f, relation_kind rel);
 
+// Return relation for NAME == NAME with RANGE.
+relation_kind get_identity_relation (tree name, vrange );
+
 class relation_oracle
 {
 public:
-- 
2.40.1



[COMMITTED] Automatically set type is certain Value_Range routines.

2023-08-03 Thread Andrew MacLeod via Gcc-patches
When you use a Value_Range, you need to set it's type first so it knows 
whether it will be an irange or an frange or whatever.


There are a few set routines which take a type, and you shouldn't need 
to set the type first in those cases..  For instance set_varying() takes 
a type, so it seems pointless to specify the type twice.  ie


Value_Range r1 (TREE_TYPE (name));
r1.set_varying (TREE_TYPE (name));

this patch automatically sets the kind based on the type in the routines 
set_varying(), set_zero(), and set_nonzero().. All of which take a type 
parameter.  Now it is simply:


Value_Range r1;
r1.set_varying (TREE_TYPE (name));

Bootstraps on  x86_64-pc-linux-gnu with no regressions.   Pushed.

Andrew
From 1fbde4cc5fb7ad4b08f0f7ae1f247f9b35124f99 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Wed, 2 Aug 2023 17:46:58 -0400
Subject: [PATCH 1/3] Automatically set type is certain Value_Range routines.

Set routines which take a type shouldn't have to pre-set the type of the
underlying range as it is specified as a parameter already.

	* value-range.h (Value_Range::set_varying): Set the type.
	(Value_Range::set_zero): Ditto.
	(Value_Range::set_nonzero): Ditto.
---
 gcc/value-range.h | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/gcc/value-range.h b/gcc/value-range.h
index d8af6fca7d7..622b68863d2 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -679,15 +679,16 @@ public:
   tree type () { return m_vrange->type (); }
   bool varying_p () const { return m_vrange->varying_p (); }
   bool undefined_p () const { return m_vrange->undefined_p (); }
-  void set_varying (tree type) { m_vrange->set_varying (type); }
+  void set_varying (tree type) { init (type); m_vrange->set_varying (type); }
   void set_undefined () { m_vrange->set_undefined (); }
   bool union_ (const vrange ) { return m_vrange->union_ (r); }
   bool intersect (const vrange ) { return m_vrange->intersect (r); }
   bool contains_p (tree cst) const { return m_vrange->contains_p (cst); }
   bool singleton_p (tree *result = NULL) const
 { return m_vrange->singleton_p (result); }
-  void set_zero (tree type) { return m_vrange->set_zero (type); }
-  void set_nonzero (tree type) { return m_vrange->set_nonzero (type); }
+  void set_zero (tree type) { init (type); return m_vrange->set_zero (type); }
+  void set_nonzero (tree type)
+{ init (type); return m_vrange->set_nonzero (type); }
   bool nonzero_p () const { return m_vrange->nonzero_p (); }
   bool zero_p () const { return m_vrange->zero_p (); }
   wide_int lower_bound () const; // For irange/prange comparability.
-- 
2.40.1



Re: [PATCH V5 1/2] Add overflow API for plus minus mult on range

2023-08-03 Thread Andrew MacLeod via Gcc-patches

This is OK.


On 8/2/23 22:18, Jiufu Guo wrote:

Hi,

I would like to have a ping on this patch.

BR,
Jeff (Jiufu Guo)


Jiufu Guo  writes:


Hi,

As discussed in previous reviews, adding overflow APIs to range-op
would be useful. Those APIs could help to check if overflow happens
when operating between two 'range's, like: plus, minus, and mult.

Previous discussions are here:
https://gcc.gnu.org/pipermail/gcc-patches/2023-July/624067.html
https://gcc.gnu.org/pipermail/gcc-patches/2023-July/624701.html

Bootstrap & regtest pass on ppc64{,le} and x86_64.
Is this patch ok for trunk?

BR,
Jeff (Jiufu Guo)

gcc/ChangeLog:

* range-op-mixed.h (operator_plus::overflow_free_p): New declare.
(operator_minus::overflow_free_p): New declare.
(operator_mult::overflow_free_p): New declare.
* range-op.cc (range_op_handler::overflow_free_p): New function.
(range_operator::overflow_free_p): New default function.
(operator_plus::overflow_free_p): New function.
(operator_minus::overflow_free_p): New function.
(operator_mult::overflow_free_p): New function.
* range-op.h (range_op_handler::overflow_free_p): New declare.
(range_operator::overflow_free_p): New declare.
* value-range.cc (irange::nonnegative_p): New function.
(irange::nonpositive_p): New function.
* value-range.h (irange::nonnegative_p): New declare.
(irange::nonpositive_p): New declare.

---
  gcc/range-op-mixed.h |  11 
  gcc/range-op.cc  | 124 +++
  gcc/range-op.h   |   5 ++
  gcc/value-range.cc   |  12 +
  gcc/value-range.h|   2 +
  5 files changed, 154 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 6944742ecbc..42157ed9061 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -383,6 +383,10 @@ public:
  relation_kind rel) const final override;
void update_bitmask (irange , const irange ,
   const irange ) const final override;
+
+  virtual bool overflow_free_p (const irange , const irange ,
+   relation_trio = TRIO_VARYING) const;
+
  private:
void wi_fold (irange , tree type, const wide_int _lb,
const wide_int _ub, const wide_int _lb,
@@ -446,6 +450,10 @@ public:
relation_kind rel) const final override;
void update_bitmask (irange , const irange ,
   const irange ) const final override;
+
+  virtual bool overflow_free_p (const irange , const irange ,
+   relation_trio = TRIO_VARYING) const;
+
  private:
void wi_fold (irange , tree type, const wide_int _lb,
const wide_int _ub, const wide_int _lb,
@@ -525,6 +533,9 @@ public:
const REAL_VALUE_TYPE _lb, const REAL_VALUE_TYPE _ub,
const REAL_VALUE_TYPE _lb, const REAL_VALUE_TYPE _ub,
relation_kind kind) const final override;
+  virtual bool overflow_free_p (const irange , const irange ,
+   relation_trio = TRIO_VARYING) const;
+
  };
  
  class operator_addr_expr : public range_operator

diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index cb584314f4c..632b044331b 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -366,6 +366,22 @@ range_op_handler::op1_op2_relation (const vrange ) 
const
  }
  }
  
+bool

+range_op_handler::overflow_free_p (const vrange ,
+  const vrange ,
+  relation_trio rel) const
+{
+  gcc_checking_assert (m_operator);
+  switch (dispatch_kind (lh, lh, rh))
+{
+  case RO_III:
+   return m_operator->overflow_free_p(as_a  (lh),
+  as_a  (rh),
+  rel);
+  default:
+   return false;
+}
+}
  
  // Convert irange bitmasks into a VALUE MASK pair suitable for calling CCP.
  
@@ -688,6 +704,13 @@ range_operator::op1_op2_relation_effect (irange _range ATTRIBUTE_UNUSED,

return false;
  }
  
+bool

+range_operator::overflow_free_p (const irange &, const irange &,
+relation_trio) const
+{
+  return false;
+}
+
  // Apply any known bitmask updates based on this operator.
  
  void

@@ -4311,6 +4334,107 @@ range_op_table::initialize_integral_ops ()
  
  }
  
+bool

+operator_plus::overflow_free_p (const irange , const irange ,
+   relation_trio) const
+{
+  if (lh.undefined_p () || rh.undefined_p ())
+return false;
+
+  tree type = lh.type ();
+  if (TYPE_OVERFLOW_UNDEFINED (type))
+return true;
+
+  wi::overflow_type ovf;
+  signop sgn = TYPE_SIGN (type);
+  wide_int wmax0 = lh.upper_bound ();
+  wide_int wmax1 = rh.upper_bound ();
+  wi::add (wmax0, wmax1, sgn, );
+  if (ovf != wi::OVF_NONE)
+return false;
+
+  if (TYPE_UNSIGNED (type))
+return true;
+
+  

[COMMITTED] PR tree-optimization/110582 - fur_list should not use the range vector for non-ssa, operands.

2023-07-31 Thread Andrew MacLeod via Gcc-patches
The fold_using_range operand fetching mechanism has a variety of modes.  
The "normal" mechanism simply invokes the current or supplied 
range_query to satisfy fetching current range info for any ssa-names 
used during the evalaution of the statement,


I also added support for fur_list which allows a list of ranges to be 
supplied which is used to satisfy ssa-names as they appear in the stmt.  
Once the list is exhausted, then it reverts to using the range query.


This allows us to fold a stmt using whatever values we want. ie,

a_2 = b_3 + c_4


i can call fold_stmt (r, stmt, [1,2],  [4,5])

and a_2 would be calculated using [1,2] for the first ssa_name, and 
[4,5] for the second encountered name.  This allows us to manually fold 
stmts when we desire.


There was a bug in the implementation of fur_list where it was using the 
supplied values for *any* encountered operand, not just ssa_names.


The PHI analyzer is the first consumer of the fur_list API, and was 
tripping over this.



     [local count: 1052266993]:
  # a_lsm.12_29 = PHI 
  iftmp.1_15 = 3 / a_lsm.12_29;

   [local count: 1063004408]:
  # iftmp.1_11 = PHI 
  # ivtmp_2 = PHI 
  ivtmp_36 = ivtmp_2 - 1;
  if (ivtmp_36 != 0)
    goto ; [98.99%]
  else
    goto ; [1.01%]

It detemined that the initial value of iftmp.1_11 was [2, 2] (from the 
edge 2->4), and that the only modifying statement is

iftmp.1_15 = 3 / a_lsm.12_29;

One of the things it tries to do is determine is if a few iterations 
feeding the initial value and combining it with the result of the 
statement converge, thus providing a complete initial range.  Its uses 
fold_range supplying the value for the ssa-operand directly..  but 
tripped over the bug.


So for the first iteration, instead of calculating   _15 = 3 / [2,2]  
and coming up with [1,1],   it was instead calculating [2,2]/VARYING, 
and coming up with [-2, 2].  Next pass of the iteration checker then 
erroneously calculated [-2,2]/VARYING and the result was [-2,2] and 
convergence was achieved, and the initial value of the PHI set to[-2, 2] 
... incorrectly.  and of course bad things happened.


This patch fixes fur_list::get_operand to check for an ssa-name before 
it pulling a value from the supplied list.  With this, no partlculary 
good starting value for the PHI node can be determined.


Andrew

From 914fa35a7f7db76211ca259606578193773a254e Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Mon, 31 Jul 2023 10:08:51 -0400
Subject: [PATCH] fur_list should not use the range vector for non-ssa
 operands.

	gcc/
	PR tree-optimization/110582
	* gimple-range-fold.cc (fur_list::get_operand): Do not use the
	range vector for non-ssa names.

	gcc/testsuite/
	* gcc.dg/pr110582.c: New.
---
 gcc/gimple-range-fold.cc|  3 ++-
 gcc/testsuite/gcc.dg/pr110582.c | 18 ++
 2 files changed, 20 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr110582.c

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index d07246008f0..ab2d996c4eb 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -262,7 +262,8 @@ fur_list::fur_list (unsigned num, vrange **list, range_query *q)
 bool
 fur_list::get_operand (vrange , tree expr)
 {
-  if (m_index >= m_limit)
+  // Do not use the vector for non-ssa-names, or if it has been emptied.
+  if (TREE_CODE (expr) != SSA_NAME || m_index >= m_limit)
 return m_query->range_of_expr (r, expr);
   r = *m_list[m_index++];
   gcc_checking_assert (range_compatible_p (TREE_TYPE (expr), r.type ()));
diff --git a/gcc/testsuite/gcc.dg/pr110582.c b/gcc/testsuite/gcc.dg/pr110582.c
new file mode 100644
index 000..ae0650d3ae7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr110582.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-vrp2" } */
+
+int a, b;
+int main() {
+  char c = a = 0;
+  for (; c != -3; c++) {
+int d = 2;
+d ^= 2 && a;
+b = a == 0 ? d : d / a;
+a = b;
+  }
+  for (; (1 + 95 << 24) + b + 1 + 686658714L + b - 2297271457;)
+;
+}
+
+/* { dg-final { scan-tree-dump-not "Folding predicate" "vrp2" } } */
+
-- 
2.40.1



[COMMITTED] Remove value_query, push into sub class.

2023-07-28 Thread Andrew MacLeod via Gcc-patches
When we first introduced range_query, we provided a base class for 
constants rather than range queries.  Then inherioted from that and 
modified the value queries for a range-specific engine. .   At the time, 
we figured there would be other consumers of the value_query class.


When all the dust settled, it turned out that subsitute_and_fold is the 
only consumer, and all the other places we perceived there to be value 
clients actually use substitute_and_fold.


This patch simplifies everything by providing only a range-query class, 
and moving the old value_range functionality into substitute_and_fold, 
the only place that uses it.


Bootstrapped on x86_64-pc-linux-gnu with no regressions. Pushed.

Andrew

From 619641397a558bf65c24b99a4c52878bd940fcbe Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Sun, 16 Jul 2023 12:46:00 -0400
Subject: [PATCH 2/3] Remove value_query, push into sub class

	* tree-ssa-propagate.cc (substitute_and_fold_engine::value_on_edge):
	Move from value-query.cc.
	(substitute_and_fold_engine::value_of_stmt): Ditto.
	(substitute_and_fold_engine::range_of_expr): New.
	* tree-ssa-propagate.h (substitute_and_fold_engine): Inherit from
	range_query.  New prototypes.
	* value-query.cc (value_query::value_on_edge): Relocate.
	(value_query::value_of_stmt): Ditto.
	* value-query.h (class value_query): Remove.
	(class range_query): Remove base class.  Adjust prototypes.
---
 gcc/tree-ssa-propagate.cc | 28 
 gcc/tree-ssa-propagate.h  |  8 +++-
 gcc/value-query.cc| 21 -
 gcc/value-query.h | 30 --
 4 files changed, 39 insertions(+), 48 deletions(-)

diff --git a/gcc/tree-ssa-propagate.cc b/gcc/tree-ssa-propagate.cc
index 174d19890f9..cb68b419b8c 100644
--- a/gcc/tree-ssa-propagate.cc
+++ b/gcc/tree-ssa-propagate.cc
@@ -532,6 +532,34 @@ struct prop_stats_d
 
 static struct prop_stats_d prop_stats;
 
+// range_query default methods to drive from a value_of_expr() ranther than
+// range_of_expr.
+
+tree
+substitute_and_fold_engine::value_on_edge (edge, tree expr)
+{
+  return value_of_expr (expr);
+}
+
+tree
+substitute_and_fold_engine::value_of_stmt (gimple *stmt, tree name)
+{
+  if (!name)
+name = gimple_get_lhs (stmt);
+
+  gcc_checking_assert (!name || name == gimple_get_lhs (stmt));
+
+  if (name)
+return value_of_expr (name);
+  return NULL_TREE;
+}
+
+bool
+substitute_and_fold_engine::range_of_expr (vrange &, tree, gimple *)
+{
+  return false;
+}
+
 /* Replace USE references in statement STMT with the values stored in
PROP_VALUE. Return true if at least one reference was replaced.  */
 
diff --git a/gcc/tree-ssa-propagate.h b/gcc/tree-ssa-propagate.h
index be4cb457873..29bde37add9 100644
--- a/gcc/tree-ssa-propagate.h
+++ b/gcc/tree-ssa-propagate.h
@@ -96,11 +96,17 @@ class ssa_propagation_engine
   void simulate_block (basic_block);
 };
 
-class substitute_and_fold_engine : public value_query
+class substitute_and_fold_engine : public range_query
 {
  public:
   substitute_and_fold_engine (bool fold_all_stmts = false)
 : fold_all_stmts (fold_all_stmts) { }
+
+  virtual tree value_of_expr (tree expr, gimple * = NULL) = 0;
+  virtual tree value_on_edge (edge, tree expr) override;
+  virtual tree value_of_stmt (gimple *, tree name = NULL) override;
+  virtual bool range_of_expr (vrange , tree expr, gimple * = NULL);
+
   virtual ~substitute_and_fold_engine (void) { }
   virtual bool fold_stmt (gimple_stmt_iterator *) { return false; }
 
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index adef93415b7..0870d6c60a6 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -33,27 +33,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-range.h"
 #include "value-range-storage.h"
 
-// value_query default methods.
-
-tree
-value_query::value_on_edge (edge, tree expr)
-{
-  return value_of_expr (expr);
-}
-
-tree
-value_query::value_of_stmt (gimple *stmt, tree name)
-{
-  if (!name)
-name = gimple_get_lhs (stmt);
-
-  gcc_checking_assert (!name || name == gimple_get_lhs (stmt));
-
-  if (name)
-return value_of_expr (name);
-  return NULL_TREE;
-}
-
 // range_query default methods.
 
 bool
diff --git a/gcc/value-query.h b/gcc/value-query.h
index d10c3eac1e2..429446b32eb 100644
--- a/gcc/value-query.h
+++ b/gcc/value-query.h
@@ -37,28 +37,6 @@ along with GCC; see the file COPYING3.  If not see
 // Proper usage of the correct query in passes will enable other
 // valuation mechanisms to produce more precise results.
 
-class value_query
-{
-public:
-  value_query () { }
-  // Return the singleton expression for EXPR at a gimple statement,
-  // or NULL if none found.
-  virtual tree value_of_expr (tree expr, gimple * = NULL) = 0;
-  // Return the singleton expression for EXPR at an edge, or NULL if
-  // none found.
-  virtual tree value_on_edge (edge, tree expr);
-  // Return the singleton expression for the LHS of 

[COMMITTED] Add a merge_range to ssa_cache and use it.

2023-07-28 Thread Andrew MacLeod via Gcc-patches

This adds some tweaks to the ssa-range cache.

1)   Adds a new merge_range which works like set_range, except if there 
is already a value, the two values are merged via intersection and 
stored.   THis avpoids having to check if there is a value, load it, 
intersect it then store that in the client. There is one usage pattern 
(but more to come) in the code base.. change to use it.


2)  The range_of_expr() method in ssa_cache does not set the stmt to a 
default of NULL.  Correct that oversight.


3)  the method empty_p() is added to the ssa_lazy_cache class so we can 
detect if the lazy cache has any active elements in it or not.


Bootstrapped on 86_64-pc-linux-gnu with no regressions.   Pushed.

Andrew

From 72fb44ca53fda15024e0c272052b74b1f32735b1 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Fri, 28 Jul 2023 11:00:57 -0400
Subject: [PATCH 3/3] Add a merge_range to ssa_cache and use it.  add empty_p
 and param tweaks.

	* gimple-range-cache.cc (ssa_cache::merge_range): New.
	(ssa_lazy_cache::merge_range): New.
	* gimple-range-cache.h (class ssa_cache): Adjust protoypes.
	(class ssa_lazy_cache): Ditto.
	* gimple-range.cc (assume_query::calculate_op): Use merge_range.
---
 gcc/gimple-range-cache.cc | 45 +++
 gcc/gimple-range-cache.h  |  6 --
 gcc/gimple-range.cc   |  6 ++
 3 files changed, 51 insertions(+), 6 deletions(-)

diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index 52165d2405b..5b74681b61a 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -605,6 +605,32 @@ ssa_cache::set_range (tree name, const vrange )
   return m != NULL;
 }
 
+// If NAME has a range, intersect it with R, otherwise set it to R.
+// Return TRUE if there was already a range set, otherwise false.
+
+bool
+ssa_cache::merge_range (tree name, const vrange )
+{
+  unsigned v = SSA_NAME_VERSION (name);
+  if (v >= m_tab.length ())
+m_tab.safe_grow_cleared (num_ssa_names + 1);
+
+  vrange_storage *m = m_tab[v];
+  if (m)
+{
+  Value_Range curr (TREE_TYPE (name));
+  m->get_vrange (curr, TREE_TYPE (name));
+  curr.intersect (r);
+  if (m->fits_p (curr))
+	m->set_vrange (curr);
+  else
+	m_tab[v] = m_range_allocator->clone (curr);
+}
+  else
+m_tab[v] = m_range_allocator->clone (r);
+  return m != NULL;
+}
+
 // Set the range for NAME to R in the ssa cache.
 
 void
@@ -689,6 +715,25 @@ ssa_lazy_cache::set_range (tree name, const vrange )
   return false;
 }
 
+// If NAME has a range, intersect it with R, otherwise set it to R.
+// Return TRUE if there was already a range set, otherwise false.
+
+bool
+ssa_lazy_cache::merge_range (tree name, const vrange )
+{
+  unsigned v = SSA_NAME_VERSION (name);
+  if (!bitmap_set_bit (active_p, v))
+{
+  // There is already an entry, simply merge it.
+  gcc_checking_assert (v < m_tab.length ());
+  return ssa_cache::merge_range (name, r);
+}
+  if (v >= m_tab.length ())
+m_tab.safe_grow (num_ssa_names + 1);
+  m_tab[v] = m_range_allocator->clone (r);
+  return false;
+}
+
 // Return TRUE if NAME has a range, and return it in R.
 
 bool
diff --git a/gcc/gimple-range-cache.h b/gcc/gimple-range-cache.h
index a0f436b5723..bbb9b18a10c 100644
--- a/gcc/gimple-range-cache.h
+++ b/gcc/gimple-range-cache.h
@@ -61,11 +61,11 @@ public:
   virtual bool has_range (tree name) const;
   virtual bool get_range (vrange , tree name) const;
   virtual bool set_range (tree name, const vrange );
+  virtual bool merge_range (tree name, const vrange );
   virtual void clear_range (tree name);
   virtual void clear ();
   void dump (FILE *f = stderr);
-  virtual bool range_of_expr (vrange , tree expr, gimple *stmt);
-
+  virtual bool range_of_expr (vrange , tree expr, gimple *stmt = NULL);
 protected:
   vec m_tab;
   vrange_allocator *m_range_allocator;
@@ -80,8 +80,10 @@ class ssa_lazy_cache : public ssa_cache
 public:
   inline ssa_lazy_cache () { active_p = BITMAP_ALLOC (NULL); }
   inline ~ssa_lazy_cache () { BITMAP_FREE (active_p); }
+  inline bool empty_p () const { return bitmap_empty_p (active_p); }
   virtual bool has_range (tree name) const;
   virtual bool set_range (tree name, const vrange );
+  virtual bool merge_range (tree name, const vrange );
   virtual bool get_range (vrange , tree name) const;
   virtual void clear_range (tree name);
   virtual void clear ();
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 01e62d3ff39..01173c58f02 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -809,10 +809,8 @@ assume_query::calculate_op (tree op, gimple *s, vrange , fur_source )
   if (m_gori.compute_operand_range (op_range, s, lhs, op, src)
   && !op_range.varying_p ())
 {
-  Value_Range range (TREE_TYPE (op));
-  if (global.get_range (range, op))
-	op_range.intersect (range);
-  global.set_range (op, op_range);
+  // Set the global range, merging if there is already a r

[COMMITTED] PR tree-optimization/110205 -Fix some warnings

2023-07-28 Thread Andrew MacLeod via Gcc-patches

This patch simply fixes the code up a little to remove potential warnings.

Bootstrapped on x86_64-pc-linux-gnu with no regressions. Pushed.

Andrew

From 7905c071c35070fff3397b1e24f140c128c08e64 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Mon, 10 Jul 2023 13:58:22 -0400
Subject: [PATCH 1/3] Fix some warnings

	PR tree-optimization/110205
	* gimple-range-cache.h (ranger_cache::m_estimate): Delete.
	* range-op-mixed.h (operator_bitwise_xor::op1_op2_relation_effect):
	Add final override.
	* range-op.cc (operator_lshift): Add missing final overrides.
	(operator_rshift): Ditto.
---
 gcc/gimple-range-cache.h |  1 -
 gcc/range-op-mixed.h |  2 +-
 gcc/range-op.cc  | 44 ++--
 3 files changed, 21 insertions(+), 26 deletions(-)

diff --git a/gcc/gimple-range-cache.h b/gcc/gimple-range-cache.h
index 93d16294d2e..a0f436b5723 100644
--- a/gcc/gimple-range-cache.h
+++ b/gcc/gimple-range-cache.h
@@ -137,7 +137,6 @@ private:
   void exit_range (vrange , tree expr, basic_block bb, enum rfd_mode);
   bool edge_range (vrange , edge e, tree name, enum rfd_mode);
 
-  phi_analyzer *m_estimate;
   vec m_workback;
   class update_list *m_update;
 };
diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 3cb904f9d80..b623a88cc71 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -574,7 +574,7 @@ public:
 	tree type,
 	const irange _range,
 	const irange _range,
-	relation_kind rel) const;
+	relation_kind rel) const final override;
   void update_bitmask (irange , const irange ,
 		   const irange ) const final override;
 private:
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 615e5fe0036..19fdff0eb64 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -2394,22 +2394,21 @@ class operator_lshift : public cross_product_operator
   using range_operator::fold_range;
   using range_operator::op1_range;
 public:
-  virtual bool op1_range (irange , tree type,
-			  const irange ,
-			  const irange ,
-			  relation_trio rel = TRIO_VARYING) const;
-  virtual bool fold_range (irange , tree type,
-			   const irange ,
-			   const irange ,
-			   relation_trio rel = TRIO_VARYING) const;
+  virtual bool op1_range (irange , tree type, const irange ,
+			  const irange , relation_trio rel = TRIO_VARYING)
+const final override;
+  virtual bool fold_range (irange , tree type, const irange ,
+			   const irange , relation_trio rel = TRIO_VARYING)
+const final override;
 
   virtual void wi_fold (irange , tree type,
 			const wide_int _lb, const wide_int _ub,
-			const wide_int _lb, const wide_int _ub) const;
+			const wide_int _lb,
+			const wide_int _ub) const final override;
   virtual bool wi_op_overflows (wide_int ,
 tree type,
 const wide_int &,
-const wide_int &) const;
+const wide_int &) const final override;
   void update_bitmask (irange , const irange ,
 		   const irange ) const final override
 { update_known_bitmask (r, LSHIFT_EXPR, lh, rh); }
@@ -2421,27 +2420,24 @@ class operator_rshift : public cross_product_operator
   using range_operator::op1_range;
   using range_operator::lhs_op1_relation;
 public:
-  virtual bool fold_range (irange , tree type,
-			   const irange ,
-			   const irange ,
-			   relation_trio rel = TRIO_VARYING) const;
+  virtual bool fold_range (irange , tree type, const irange ,
+			   const irange , relation_trio rel = TRIO_VARYING)
+   const final override;
   virtual void wi_fold (irange , tree type,
 			const wide_int _lb,
 			const wide_int _ub,
 			const wide_int _lb,
-			const wide_int _ub) const;
+			const wide_int _ub) const final override;
   virtual bool wi_op_overflows (wide_int ,
 tree type,
 const wide_int ,
-const wide_int ) const;
-  virtual bool op1_range (irange &, tree type,
-			  const irange ,
-			  const irange ,
-			  relation_trio rel = TRIO_VARYING) const;
-  virtual relation_kind lhs_op1_relation (const irange ,
-	   const irange ,
-	   const irange ,
-	   relation_kind rel) const;
+const wide_int ) const final override;
+  virtual bool op1_range (irange &, tree type, const irange ,
+			  const irange , relation_trio rel = TRIO_VARYING)
+const final override;
+  virtual relation_kind lhs_op1_relation (const irange , const irange ,
+	  const irange , relation_kind rel)
+const final override;
   void update_bitmask (irange , const irange ,
 		   const irange ) const final override
 { update_known_bitmask (r, RSHIFT_EXPR, lh, rh); }
-- 
2.40.1



Re: [PATCH] [GCC13] PR tree-optimization/110315 - Add auto-resizing capability to irange's

2023-07-24 Thread Andrew MacLeod via Gcc-patches



On 7/24/23 12:49, Richard Biener wrote:



Am 24.07.2023 um 16:40 schrieb Andrew MacLeod via Gcc-patches 
:

Aldy has ported his irange reduction patch to GCC 13.  It resolves this PR.

I have bootstrapped it and it passes regression tests.

Do we want to check it into the GCC 13 branch?  The patch has all his comments 
in it.

Please wait until the branch is open again, then yes , I think we want this 
there.  Was there any work reducing the recursion depth that’s worth 
backporting as well?


I think most of the recursion depth work is in GCC13.  Im looking at a 
few more tweaks for GCC14, but they are fairly minor at the moment.  
reduction of the size of the stack was the huge win.




[PATCH] [GCC13] PR tree-optimization/110315 - Add auto-resizing capability to irange's

2023-07-24 Thread Andrew MacLeod via Gcc-patches

Aldy has ported his irange reduction patch to GCC 13.  It resolves this PR.

I have bootstrapped it and it passes regression tests.

Do we want to check it into the GCC 13 branch?  The patch has all his 
comments in it.


Andrew
From 777aa930b106fea2dd6ed9fe22b42a2717f1472d Mon Sep 17 00:00:00 2001
From: Aldy Hernandez 
Date: Mon, 15 May 2023 12:25:58 +0200
Subject: [PATCH] [GCC13] Add auto-resizing capability to irange's [PR109695]

Backport the following from trunk.

	Note that the patch has been adapted to trees.

	The numbers for various sub-ranges on GCC13 are:
		< 2> =  64 bytes, -3.02% for VRP.
		< 3> =  80 bytes, -2.67% for VRP.
		< 8> = 160 bytes, -2.46% for VRP.
		<16> = 288 bytes, -2.40% for VRP.


We can now have int_range for automatically
resizable ranges.  int_range_max is now int_range<3, true>
for a 69X reduction in size from current trunk, and 6.9X reduction from
GCC12.  This incurs a 5% performance penalty for VRP that is more than
covered by our > 13% improvements recently.


int_range_max is the temporary range object we use in the ranger for
integers.  With the conversion to wide_int, this structure bloated up
significantly because wide_ints are huge (80 bytes a piece) and are
about 10 times as big as a plain tree.  Since the temporary object
requires 255 sub-ranges, that's 255 * 80 * 2, plus the control word.
This means the structure grew from 4112 bytes to 40912 bytes.

This patch adds the ability to resize ranges as needed, defaulting to
no resizing, while int_range_max now defaults to 3 sub-ranges (instead
of 255) and grows to 255 when the range being calculated does not fit.

For example:

int_range<1> foo;	// 1 sub-range with no resizing.
int_range<5> foo;	// 5 sub-ranges with no resizing.
int_range<5, true> foo;	// 5 sub-ranges with resizing.

I ran some tests and found that 3 sub-ranges cover 99% of cases, so
I've set the int_range_max default to that:

	typedef int_range<3, /*RESIZABLE=*/true> int_range_max;

We don't bother growing incrementally, since the default covers most
cases and we have a 255 hard-limit.  This hard limit could be reduced
to 128, since my tests never saw a range needing more than 124, but we
could do that as a follow-up if needed.

With 3-subranges, int_range_max is now 592 bytes versus 40912 for
trunk, and versus 4112 bytes for GCC12!  The penalty is 5.04% for VRP
and 3.02% for threading, with no noticeable change in overall
compilation (0.27%).  This is more than covered by our 13.26%
improvements for the legacy removal + wide_int conversion.

I think this approach is a good alternative, while providing us with
flexibility going forward.  For example, we could try defaulting to a
8 sub-ranges for a noticeable improvement in VRP.  We could also use
large sub-ranges for switch analysis to avoid resizing.

Another approach I tried was always resizing.  With this, we could
drop the whole int_range nonsense, and have irange just hold a
resizable range.  This simplified things, but incurred a 7% penalty on
ipa_cp.  This was hard to pinpoint, and I'm not entirely convinced
this wasn't some artifact of valgrind.  However, until we're sure,
let's avoid massive changes, especially since IPA changes are coming
up.

For the curious, a particular hot spot for IPA in this area was:

ipcp_vr_lattice::meet_with_1 (const value_range *other_vr)
{
...
...
  value_range save (m_vr);
  m_vr.union_ (*other_vr);
  return m_vr != save;
}

The problem isn't the resizing (since we do that at most once) but the
fact that for some functions with lots of callers we end up a huge
range that gets copied and compared for every meet operation.  Maybe
the IPA algorithm could be adjusted somehow??.

Anywhooo... for now there is nothing to worry about, since value_range
still has 2 subranges and is not resizable.  But we should probably
think what if anything we want to do here, as I envision IPA using
infinite ranges here (well, int_range_max) and handling frange's, etc.

gcc/ChangeLog:

	PR tree-optimization/109695
	* value-range.cc (irange::operator=): Resize range.
	(irange::union_): Same.
	(irange::intersect): Same.
	(irange::invert): Same.
	(int_range_max): Default to 3 sub-ranges and resize as needed.
	* value-range.h (irange::maybe_resize): New.
	(~int_range): New.
	(int_range::int_range): Adjust for resizing.
	(int_range::operator=): Same.
---
 gcc/value-range-storage.h |  2 +-
 gcc/value-range.cc| 15 ++
 gcc/value-range.h | 96 +++
 3 files changed, 83 insertions(+), 30 deletions(-)

diff --git a/gcc/value-range-storage.h b/gcc/value-range-storage.h
index 6da377ebd2e..1ed6f1ccd61 100644
--- a/gcc/value-range-storage.h
+++ b/gcc/value-range-storage.h
@@ -184,7 +184,7 @@ vrange_allocator::alloc_irange (unsigned num_pairs)
   // Allocate the irange and required memory for the vector.
   void *r = alloc (sizeof (irange));
   tree *mem = static_cast  (alloc (nbytes));
-  return new (r) irange (mem, num_pairs);
+  return new 

Re: [PATCH V4] Optimize '(X - N * M) / N' to 'X / N - M' if valid

2023-07-17 Thread Andrew MacLeod via Gcc-patches


On 7/17/23 09:45, Jiufu Guo wrote:



Should we decide we would like it in general, it wouldnt be hard to add to
irange.  wi_fold() cuurently returns null, it could easily return a bool
indicating if an overflow happened, and wi_fold_in_parts and fold_range would
simply OR the results all together of the compoent wi_fold() calls.  It would
require updating/audfiting  a number of range-op entries and adding an
overflowed_p()  query to irange.

Ah, yeah - the folding APIs would be a good fit I guess.  I was
also looking to have the "new" helpers to be somewhat consistent
with the ranger API.

So if we had a fold_range overload with either an output argument
or a flag that makes it return false on possible overflow that
would work I guess?  Since we have a virtual class setup we
might be able to provide a default failing method and implement
workers for plus and mult (as needed for this patch) as the need
arises?

Thanks for your comments!
Here is a concern.  The patterns in match.pd may be supported by
'vrp' passes. At that time, the range info would be computed (via
the value-range machinery) and cached for each SSA_NAME. In the
patterns, when range_of_expr is called for a capture, the range
info is retrieved from the cache, and no need to fold_range again.
This means the overflow info may also need to be cached together
with other range info.  There may be additional memory and time
cost.



I've been thinking about this a little bit, and how to make the info 
available in a useful way.


I wonder if maybe we just add another entry point  to range-ops that 
looks a bit like fold_range ..


  Attached is an (untested) patch which ads overflow_free_p(op1, op2, 
relation)  to rangeops.   It defaults to returning false.  If you want 
to implement it for say plus,  you'd add to operator_plus in 
range-ops.cc  something like


operator_plus::overflow_free_p (irange, irange& op2, relation_kind)
{
   // stuff you do in plus_without_overflow
}

I added relation_kind as  param, but you can ignore it.  maybe it wont 
ever help, but it seems like if we know there is a relation between op1 
and op2 we might be able to someday determine something else? if 
not, remove it.


Then all you need to do too access it is to go thru range-op_handler.. 
so for instance:


range_op_handler (PLUS_EXPR).overflow_free_p (op1, op2)

It'll work for all types an all tree codes. the dispatch machinery will 
return false unless both op1 and op2 are integral ranges, and then it 
will invoke the appropriate handler, defaulting to returning FALSE.


I also am not a fan of the get_range  routine.  It would be better to 
generally just call range_of_expr, get the results, then handle 
undefined in the new overflow_free_p() routine and return false.  
varying should not need anything special since it will trigger the 
overflow when you do the calculation.


The auxillary routines could go in vr-values.h/cc.  They seem like 
things that simplify_using_ranges could utilize, and when we get to 
integrating simplify_using_ranges better,  what you are doing may end up 
there anyway


Does that work?

Andrew
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index d1c735ee6aa..f2a863db286 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -366,6 +366,24 @@ range_op_handler::op1_op2_relation (const vrange ) const
 }
 }
 
+bool
+range_op_handler::overflow_free_p (const vrange ,
+   const vrange ,
+   relation_trio rel) const
+{
+  gcc_checking_assert (m_operator);
+  switch (dispatch_kind (lh, lh, rh))
+{
+  case RO_III:
+	return m_operator->overflow_free_p(as_a  (lh),
+	   as_a  (rh),
+	   rel);
+  default:
+	return false;
+}
+}
+
+
 
 // Convert irange bitmasks into a VALUE MASK pair suitable for calling CCP.
 
@@ -688,6 +706,13 @@ range_operator::op1_op2_relation_effect (irange _range ATTRIBUTE_UNUSED,
   return false;
 }
 
+bool
+range_operator::overflow_free_p (const irange &, const irange &,
+ relation_trio) const
+{
+  return false;
+}
+
 // Apply any known bitmask updates based on this operator.
 
 void
diff --git a/gcc/range-op.h b/gcc/range-op.h
index af94c2756a7..db3b03f28a5 100644
--- a/gcc/range-op.h
+++ b/gcc/range-op.h
@@ -147,6 +147,9 @@ public:
 
   virtual relation_kind op1_op2_relation (const irange ) const;
   virtual relation_kind op1_op2_relation (const frange ) const;
+
+  virtual bool overflow_free_p (const irange , const irange ,
+relation_trio = TRIO_VARYING) const;
 protected:
   // Perform an integral operation between 2 sub-ranges and return it.
   virtual void wi_fold (irange , tree type,
@@ -214,6 +217,8 @@ public:
   const vrange ,
   relation_kind = VREL_VARYING) const;
   relation_kind op1_op2_relation (const vrange ) const;
+  bool overflow_free_p (const vrange , const vrange ,
+			relation_trio = TRIO_VARYING) const;
 protected:
   unsigned dispatch_kind (const vrange , const vrange ,
 			  const vrange& op2) const;


Re: [PATCH V4] Optimize '(X - N * M) / N' to 'X / N - M' if valid

2023-07-14 Thread Andrew MacLeod via Gcc-patches



On 7/14/23 09:37, Richard Biener wrote:

On Fri, 14 Jul 2023, Aldy Hernandez wrote:


I don't know what you're trying to accomplish here, as I haven't been
following the PR, but adding all these helper functions to the ranger header
file seems wrong, especially since there's only one use of them. I see you're
tweaking the irange API, adding helper functions to range-op (which is only
for code dealing with implementing range operators for tree codes), etc etc.

If you need these helper functions, I suggest you put them closer to their
uses (i.e. wherever the match.pd support machinery goes).

Note I suggested the opposite beacuse I thought these kind of helpers
are closer to value-range support than to match.pd.



probably vr-values.{cc.h} and  the simply_using_ranges paradigm would be 
the most sensible place to put these kinds of auxiliary routines?





But I take away from your answer that there's nothing close in the
value-range machinery that answers the question whether A op B may
overflow?


we dont track it in ranges themselves.   During calculation of a range 
we obviously know, but propagating that generally when we rarely care 
doesn't seem worthwhile.  The very first generation of irange 6 years 
ago had an overflow_p() flag, but it was removed as not being worth 
keeping.     easier to simply ask the question when it matters


As the routines show, it pretty easy to figure out when the need arises 
so I think that should suffice.  At least for now,


Should we decide we would like it in general, it wouldnt be hard to add 
to irange.  wi_fold() cuurently returns null, it could easily return a 
bool indicating if an overflow happened, and wi_fold_in_parts and 
fold_range would simply OR the results all together of the compoent 
wi_fold() calls.  It would require updating/audfiting  a number of 
range-op entries and adding an overflowed_p()  query to irange.


Andrew



[COMMITTED 5/5] Make compute_operand_range a tail call.

2023-07-05 Thread Andrew MacLeod via Gcc-patches
This simply tweaks cmpute_operand_range a little so the recursion is a 
tail call.


With this, the patchset produces a modest speedup of 0.2% in VRP and 
0.4% in threading.  It will also have a much smaller stack profile.


Bootstraps on  x86_64-pc-linux-gnu  with no regressions.  Pushed.

Andrew

From 51ed3a6ce432e7e6226bb62125ef8a09b2ebf60c Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Wed, 5 Jul 2023 14:26:00 -0400
Subject: [PATCH 5/6] Make compute_operand_range a tail call.

Tweak the routine so it is making a tail call.

	* gimple-range-gori.cc (compute_operand_range): Convert to a tail
	call.
---
 gcc/gimple-range-gori.cc | 34 --
 1 file changed, 16 insertions(+), 18 deletions(-)

diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc
index b036ed56f02..6dc15a0ce3f 100644
--- a/gcc/gimple-range-gori.cc
+++ b/gcc/gimple-range-gori.cc
@@ -725,36 +725,34 @@ gori_compute::compute_operand_range (vrange , gimple *stmt,
 			 op1_trange, op1_frange, op2_trange, op2_frange);
   if (idx)
 	tracer.trailer (idx, "compute_operand", res, name, r);
+  return res;
 }
   // Follow the appropriate operands now.
-  else if (op1_in_chain && op2_in_chain)
-res = compute_operand1_and_operand2_range (r, handler, lhs, name, src,
-	   vrel_ptr);
-  else if (op1_in_chain)
+  if (op1_in_chain && op2_in_chain)
+return compute_operand1_and_operand2_range (r, handler, lhs, name, src,
+		vrel_ptr);
+  Value_Range vr;
+  gimple *src_stmt;
+  if (op1_in_chain)
 {
-  Value_Range vr (TREE_TYPE (op1));
+  vr.set_type (TREE_TYPE (op1));
   if (!compute_operand1_range (vr, handler, lhs, src, vrel_ptr))
 	return false;
-  gimple *src_stmt = SSA_NAME_DEF_STMT (op1);
-  gcc_checking_assert (src_stmt);
-  // Then feed this range back as the LHS of the defining statement.
-  return compute_operand_range (r, src_stmt, vr, name, src, vrel_ptr);
+  src_stmt = SSA_NAME_DEF_STMT (op1);
 }
-  else if (op2_in_chain)
+  else
 {
-  Value_Range vr (TREE_TYPE (op2));
+  gcc_checking_assert (op2_in_chain);
+  vr.set_type (TREE_TYPE (op2));
   if (!compute_operand2_range (vr, handler, lhs, src, vrel_ptr))
 	return false;
-  gimple *src_stmt = SSA_NAME_DEF_STMT (op2);
-  gcc_checking_assert (src_stmt);
-  // Then feed this range back as the LHS of the defining statement.
-  return compute_operand_range (r, src_stmt, vr, name, src, vrel_ptr);
+  src_stmt = SSA_NAME_DEF_STMT (op2);
 }
-  else
-gcc_unreachable ();
 
+  gcc_checking_assert (src_stmt);
+  // Then feed this range back as the LHS of the defining statement.
+  return compute_operand_range (r, src_stmt, vr, name, src, vrel_ptr);
   // If neither operand is derived, this statement tells us nothing.
-  return res;
 }
 
 
-- 
2.40.1



[COMMITTED 4/5] Make compute_operand2_range a leaf call.

2023-07-05 Thread Andrew MacLeod via Gcc-patches
now operand2 alone is resolved, and returned as the result.  much 
cleaner, and removes it from the recursion stack.


compute_operand_range() will decide if further evaluation is required.

Bootstraps on  x86_64-pc-linux-gnu  with no regressions.  Pushed.

Andrew
From 298952bcf05d298892e99adba1f4a75af17bc65a Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Wed, 5 Jul 2023 13:52:21 -0400
Subject: [PATCH 4/6] Make compute_operand2_range a leaf call.

Rather than creating long call chains, put the onus for finishing
the evlaution on the caller.

	* gimple-range-gori.cc (compute_operand_range): After calling
	compute_operand2_range, recursively call self if needed.
	(compute_operand2_range): Turn into a leaf function.
	(gori_compute::compute_operand1_and_operand2_range): Finish
	operand2 calculation.
	* gimple-range-gori.h (compute_operand2_range): Remove name param.
---
 gcc/gimple-range-gori.cc | 52 +++-
 gcc/gimple-range-gori.h  |  2 +-
 2 files changed, 26 insertions(+), 28 deletions(-)

diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc
index b66b9b0398c..b036ed56f02 100644
--- a/gcc/gimple-range-gori.cc
+++ b/gcc/gimple-range-gori.cc
@@ -639,7 +639,7 @@ gori_compute::compute_operand_range (vrange , gimple *stmt,
   if (op1 == name)
 return compute_operand1_range (r, handler, lhs, src, vrel_ptr);
   if (op2 == name)
-return compute_operand2_range (r, handler, lhs, name, src, vrel_ptr);
+return compute_operand2_range (r, handler, lhs, src, vrel_ptr);
 
   // NAME is not in this stmt, but one of the names in it ought to be
   // derived from it.
@@ -741,7 +741,15 @@ gori_compute::compute_operand_range (vrange , gimple *stmt,
   return compute_operand_range (r, src_stmt, vr, name, src, vrel_ptr);
 }
   else if (op2_in_chain)
-res = compute_operand2_range (r, handler, lhs, name, src, vrel_ptr);
+{
+  Value_Range vr (TREE_TYPE (op2));
+  if (!compute_operand2_range (vr, handler, lhs, src, vrel_ptr))
+	return false;
+  gimple *src_stmt = SSA_NAME_DEF_STMT (op2);
+  gcc_checking_assert (src_stmt);
+  // Then feed this range back as the LHS of the defining statement.
+  return compute_operand_range (r, src_stmt, vr, name, src, vrel_ptr);
+}
   else
 gcc_unreachable ();
 
@@ -1188,7 +1196,7 @@ gori_compute::compute_operand1_range (vrange ,
 bool
 gori_compute::compute_operand2_range (vrange ,
   gimple_range_op_handler ,
-  const vrange , tree name,
+  const vrange ,
   fur_source , value_relation *rel)
 {
   gimple *stmt = handler.stmt ();
@@ -1198,7 +1206,6 @@ gori_compute::compute_operand2_range (vrange ,
 
   Value_Range op1_range (TREE_TYPE (op1));
   Value_Range op2_range (TREE_TYPE (op2));
-  Value_Range tmp (TREE_TYPE (op2));
 
   src.get_operand (op1_range, op1);
   src.get_operand (op2_range, op2);
@@ -1215,7 +1222,7 @@ gori_compute::compute_operand2_range (vrange ,
   if (op1 == op2 && gimple_range_ssa_p (op1))
 trio = relation_trio (trio.lhs_op1 (), trio.lhs_op2 (), VREL_EQ);
   // Intersect with range for op2 based on lhs and op1.
-  if (!handler.calc_op2 (tmp, lhs, op1_range, trio))
+  if (!handler.calc_op2 (r, lhs, op1_range, trio))
 return false;
 
   unsigned idx;
@@ -1237,31 +1244,16 @@ gori_compute::compute_operand2_range (vrange ,
   tracer.print (idx, "Computes ");
   print_generic_expr (dump_file, op2, TDF_SLIM);
   fprintf (dump_file, " = ");
-  tmp.dump (dump_file);
+  r.dump (dump_file);
   fprintf (dump_file, " intersect Known range : ");
   op2_range.dump (dump_file);
   fputc ('\n', dump_file);
 }
   // Intersect the calculated result with the known result and return if done.
-  if (op2 == name)
-{
-  tmp.intersect (op2_range);
-  r = tmp;
-  if (idx)
-	tracer.trailer (idx, " produces ", true, NULL_TREE, r);
-  return true;
-}
-  // If the calculation continues, we're using op2_range as the new LHS.
-  op2_range.intersect (tmp);
-
+  r.intersect (op2_range);
   if (idx)
-tracer.trailer (idx, " produces ", true, op2, op2_range);
-  gimple *src_stmt = SSA_NAME_DEF_STMT (op2);
-  gcc_checking_assert (src_stmt);
-//  gcc_checking_assert (!is_import_p (op2, find.bb));
-
-  // Then feed this range back as the LHS of the defining statement.
-  return compute_operand_range (r, src_stmt, op2_range, name, src, rel);
+tracer.trailer (idx, " produces ", true, op2, r);
+  return true;
 }
 
 // Calculate a range for NAME from both operand positions of S
@@ -1279,15 +1271,21 @@ gori_compute::compute_operand1_and_operand2_range (vrange ,
 {
   Value_Range op_range (TREE_TYPE (name));
 
+  Value_Range vr (TREE_TYPE (handler.operand2 ()));
   // Calculate a good a range through op2.
-  if (!compute_operand2_range (r, handler, lhs, name, src, rel))
+  if (!compute_operand2_range (vr, handler, lhs, src, rel))
+ret

[COMMITTED 3/5] Make compute_operand1_range a leaf call.

2023-07-05 Thread Andrew MacLeod via Gcc-patches
now operand1 alone is resolved, and returned as the result.  much 
cleaner, and removes it from the recursion stack.


compute_operand_range() will decide if further evaluation is required.

Bootstraps on  x86_64-pc-linux-gnu  with no regressions.  Pushed.

Andrew

From 912b5ac49677160aada7a2d862273251406dfca5 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Wed, 5 Jul 2023 13:41:50 -0400
Subject: [PATCH 3/6] Make compute_operand1_range a leaf call.

Rather than creating long call chains, put the onus for finishing
the evlaution on the caller.

	* gimple-range-gori.cc (compute_operand_range): After calling
	compute_operand1_range, recursively call self if needed.
	(compute_operand1_range): Turn into a leaf function.
	(gori_compute::compute_operand1_and_operand2_range): Finish
	operand1 calculation.
	* gimple-range-gori.h (compute_operand1_range): Remove name param.
---
 gcc/gimple-range-gori.cc | 49 
 gcc/gimple-range-gori.h  |  2 +-
 2 files changed, 25 insertions(+), 26 deletions(-)

diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc
index 5429c6e3c1a..b66b9b0398c 100644
--- a/gcc/gimple-range-gori.cc
+++ b/gcc/gimple-range-gori.cc
@@ -637,7 +637,7 @@ gori_compute::compute_operand_range (vrange , gimple *stmt,
 
   // Handle end of lookup first.
   if (op1 == name)
-return compute_operand1_range (r, handler, lhs, name, src, vrel_ptr);
+return compute_operand1_range (r, handler, lhs, src, vrel_ptr);
   if (op2 == name)
 return compute_operand2_range (r, handler, lhs, name, src, vrel_ptr);
 
@@ -731,7 +731,15 @@ gori_compute::compute_operand_range (vrange , gimple *stmt,
 res = compute_operand1_and_operand2_range (r, handler, lhs, name, src,
 	   vrel_ptr);
   else if (op1_in_chain)
-res = compute_operand1_range (r, handler, lhs, name, src, vrel_ptr);
+{
+  Value_Range vr (TREE_TYPE (op1));
+  if (!compute_operand1_range (vr, handler, lhs, src, vrel_ptr))
+	return false;
+  gimple *src_stmt = SSA_NAME_DEF_STMT (op1);
+  gcc_checking_assert (src_stmt);
+  // Then feed this range back as the LHS of the defining statement.
+  return compute_operand_range (r, src_stmt, vr, name, src, vrel_ptr);
+}
   else if (op2_in_chain)
 res = compute_operand2_range (r, handler, lhs, name, src, vrel_ptr);
   else
@@ -1099,7 +1107,7 @@ gori_compute::refine_using_relation (tree op1, vrange _range,
 bool
 gori_compute::compute_operand1_range (vrange ,
   gimple_range_op_handler ,
-  const vrange , tree name,
+  const vrange ,
   fur_source , value_relation *rel)
 {
   gimple *stmt = handler.stmt ();
@@ -1112,7 +1120,6 @@ gori_compute::compute_operand1_range (vrange ,
 trio = rel->create_trio (lhs_name, op1, op2);
 
   Value_Range op1_range (TREE_TYPE (op1));
-  Value_Range tmp (TREE_TYPE (op1));
   Value_Range op2_range (op2 ? TREE_TYPE (op2) : TREE_TYPE (op1));
 
   // Fetch the known range for op1 in this block.
@@ -1130,7 +1137,7 @@ gori_compute::compute_operand1_range (vrange ,
   // If op1 == op2, create a new trio for just this call.
   if (op1 == op2 && gimple_range_ssa_p (op1))
 	trio = relation_trio (trio.lhs_op1 (), trio.lhs_op2 (), VREL_EQ);
-  if (!handler.calc_op1 (tmp, lhs, op2_range, trio))
+  if (!handler.calc_op1 (r, lhs, op2_range, trio))
 	return false;
 }
   else
@@ -1138,7 +1145,7 @@ gori_compute::compute_operand1_range (vrange ,
   // We pass op1_range to the unary operation.  Normally it's a
   // hidden range_for_type parameter, but sometimes having the
   // actual range can result in better information.
-  if (!handler.calc_op1 (tmp, lhs, op1_range, trio))
+  if (!handler.calc_op1 (r, lhs, op1_range, trio))
 	return false;
 }
 
@@ -1161,30 +1168,16 @@ gori_compute::compute_operand1_range (vrange ,
   tracer.print (idx, "Computes ");
   print_generic_expr (dump_file, op1, TDF_SLIM);
   fprintf (dump_file, " = ");
-  tmp.dump (dump_file);
+  r.dump (dump_file);
   fprintf (dump_file, " intersect Known range : ");
   op1_range.dump (dump_file);
   fputc ('\n', dump_file);
 }
-  // Intersect the calculated result with the known result and return if done.
-  if (op1 == name)
-{
-  tmp.intersect (op1_range);
-  r = tmp;
-  if (idx)
-	tracer.trailer (idx, "produces ", true, name, r);
-  return true;
-}
-  // If the calculation continues, we're using op1_range as the new LHS.
-  op1_range.intersect (tmp);
 
+  r.intersect (op1_range);
   if (idx)
-tracer.trailer (idx, "produces ", true, op1, op1_range);
-  gimple *src_stmt = SSA_NAME_DEF_STMT (op1);
-  gcc_checking_assert (src_stmt);
-
-  // Then feed this range back as the LHS of the defining statement.
-  return compute_operand_range (r, src_stmt, op1_range, name, src, rel);
+tracer.trailer (idx, "produces ", tr

[COMMITTED 2/5] Simplify compute_operand_range for op1 and op2 case.

2023-07-05 Thread Andrew MacLeod via Gcc-patches
This patch simplifies compute_operand1_and_operand2() such that it only 
calls each routine one. This will simplify the next couple of patches.


It also allows moves the determination that op1 and op2 have an 
interdependence to  compute_operand_range().


Bootstraps on  x86_64-pc-linux-gnu  with no regressions.  Pushed.

Andrew
From 7276248946d3eae83e5e08fc023163614c9ea9ab Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Wed, 5 Jul 2023 13:36:27 -0400
Subject: [PATCH 2/6] Simplify compute_operand_range for op1 and op2 case.

Move the check for co-dependency between 2 operands into
compute_operand_range, resulting in a much cleaner
compute_operand1_and_operand2_range routine.

	* gimple-range-gori.cc (compute_operand_range): Check for
	operand interdependence when both op1 and op2 are computed.
	(compute_operand1_and_operand2_range): No checks required now.
---
 gcc/gimple-range-gori.cc | 25 +++--
 1 file changed, 11 insertions(+), 14 deletions(-)

diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc
index b0d13a8ac53..5429c6e3c1a 100644
--- a/gcc/gimple-range-gori.cc
+++ b/gcc/gimple-range-gori.cc
@@ -650,6 +650,17 @@ gori_compute::compute_operand_range (vrange , gimple *stmt,
   if (!op1_in_chain && !op2_in_chain)
 return false;
 
+  // If either operand is in the def chain of the other (or they are equal), it
+  // will be evaluated twice and can result in an exponential time calculation.
+  // Instead just evaluate the one operand.
+  if (op1_in_chain && op2_in_chain)
+{
+  if (in_chain_p (op1, op2) || op1 == op2)
+	op1_in_chain = false;
+  else if (in_chain_p (op2, op1))
+	op2_in_chain = false;
+}
+
   bool res = false;
   // If the lhs doesn't tell us anything only a relation can possibly enhance
   // the result.
@@ -1275,24 +1286,10 @@ gori_compute::compute_operand1_and_operand2_range (vrange ,
 {
   Value_Range op_range (TREE_TYPE (name));
 
-  // If op1 is in the def chain of op2, we'll do the work twice to evalaute
-  // op1.  This can result in an exponential time calculation.
-  // Instead just evaluate op2, which will eventualy get to op1.
-  if (in_chain_p (handler.operand1 (), handler.operand2 ()))
-return compute_operand2_range (r, handler, lhs, name, src, rel);
-
-  // Likewise if op2 is in the def chain of op1.
-  if (in_chain_p (handler.operand2 (), handler.operand1 ()))
-return compute_operand1_range (r, handler, lhs, name, src, rel);
-
   // Calculate a good a range through op2.
   if (!compute_operand2_range (r, handler, lhs, name, src, rel))
 return false;
 
-  // If op1 == op2 there is again no need to go further.
-  if (handler.operand1 () == handler.operand2 ())
-return true;
-
   // Now get the range thru op1.
   if (!compute_operand1_range (op_range, handler, lhs, name, src, rel))
 return false;
-- 
2.40.1



[COMMITTED 1/5] Move relation discovery into compute_operand_range

2023-07-05 Thread Andrew MacLeod via Gcc-patches

This is a set of 5 patches which cleans up GORIs compute_operand routines.

This is the mechanism GORI uses to calculate ranges from the bottom of 
the routine back thru definitions in the block to the name that is 
requested.


Currently, compute_operand_range() is called on a stmt, and it divides 
the work based on which operands are used to get back to the requested 
name.  It calls compute_operand1_range or compute_operand2_range or 
compute_operand1_and_operand2_range. If the specified name is not on 
this statement, then a call back to compute_operand_range on the 
definition statement is made.


this means the call chain is recursive, but involves alternating 
functions.  This patch sets changes the compute_operand1_range and 
compute_operand2_range to be leaf functions, and then 
compute_operand_range is still recursive, but has a much smaller stack 
footprint, and is also becomes a tailcall.


I tried removing the recursion, but at this point, removing the 
recursion is a performance hit :-P   stay tuned on that one.


This patch moves some common code for relation discovery from 
compute_operand[12]range into compute_operand_range.


Bootstraps on  x86_64-pc-linux-gnu  with no regressions.  Pushed.

Andrew
From 290798faef706c335bd346b13771f977ddedb415 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Tue, 4 Jul 2023 11:28:52 -0400
Subject: [PATCH 1/6] Move relation discovery into compute_operand_range

compute_operand1_range and compute_operand2_range were both doing
relation discovery between the 2 operands... move it into a common area.

	* gimple-range-gori.cc (compute_operand_range): Check for
	a relation between op1 and op2 and use that instead.
	(compute_operand1_range): Don't look for a relation override.
	(compute_operand2_range): Ditto.
---
 gcc/gimple-range-gori.cc | 42 +---
 1 file changed, 13 insertions(+), 29 deletions(-)

diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc
index 4ee0ae36014..b0d13a8ac53 100644
--- a/gcc/gimple-range-gori.cc
+++ b/gcc/gimple-range-gori.cc
@@ -623,6 +623,18 @@ gori_compute::compute_operand_range (vrange , gimple *stmt,
   tree op1 = gimple_range_ssa_p (handler.operand1 ());
   tree op2 = gimple_range_ssa_p (handler.operand2 ());
 
+  // If there is a relation betwen op1 and op2, use it instead as it is
+  // likely to be more applicable.
+  if (op1 && op2)
+{
+  relation_kind k = handler.op1_op2_relation (lhs);
+  if (k != VREL_VARYING)
+	{
+	  vrel.set_relation (k, op1, op2);
+	  vrel_ptr = 
+	}
+}
+
   // Handle end of lookup first.
   if (op1 == name)
 return compute_operand1_range (r, handler, lhs, name, src, vrel_ptr);
@@ -1079,7 +1091,6 @@ gori_compute::compute_operand1_range (vrange ,
   const vrange , tree name,
   fur_source , value_relation *rel)
 {
-  value_relation local_rel;
   gimple *stmt = handler.stmt ();
   tree op1 = handler.operand1 ();
   tree op2 = handler.operand2 ();
@@ -1088,7 +1099,6 @@ gori_compute::compute_operand1_range (vrange ,
   relation_trio trio;
   if (rel)
 trio = rel->create_trio (lhs_name, op1, op2);
-  relation_kind op_op = trio.op1_op2 ();
 
   Value_Range op1_range (TREE_TYPE (op1));
   Value_Range tmp (TREE_TYPE (op1));
@@ -1102,19 +1112,7 @@ gori_compute::compute_operand1_range (vrange ,
 {
   src.get_operand (op2_range, op2);
 
-  // If there is a relation betwen op1 and op2, use it instead.
-  // This allows multiple relations to be processed in compound logicals.
-  if (gimple_range_ssa_p (op1) && gimple_range_ssa_p (op2))
-	{
-	  relation_kind k = handler.op1_op2_relation (lhs);
-	  if (k != VREL_VARYING)
-	{
-	  op_op = k;
-	  local_rel.set_relation (op_op, op1, op2);
-	  rel = _rel;
-	}
-	}
-
+  relation_kind op_op = trio.op1_op2 ();
   if (op_op != VREL_VARYING)
 	refine_using_relation (op1, op1_range, op2, op2_range, src, op_op);
 
@@ -1189,7 +1187,6 @@ gori_compute::compute_operand2_range (vrange ,
   const vrange , tree name,
   fur_source , value_relation *rel)
 {
-  value_relation local_rel;
   gimple *stmt = handler.stmt ();
   tree op1 = handler.operand1 ();
   tree op2 = handler.operand2 ();
@@ -1207,19 +1204,6 @@ gori_compute::compute_operand2_range (vrange ,
 trio = rel->create_trio (lhs_name, op1, op2);
   relation_kind op_op = trio.op1_op2 ();
 
-  // If there is a relation betwen op1 and op2, use it instead.
-  // This allows multiple relations to be processed in compound logicals.
-  if (gimple_range_ssa_p (op1) && gimple_range_ssa_p (op2))
-{
-  relation_kind k = handler.op1_op2_relation (lhs);
-  if (k != VREL_VARYING)
-	{
-	  op_op = k;
-	  local_rel.set_relation (op_op, op1, op2);
-	  rel = _rel;
-	}
-}
-
   if (op_op != VREL_VARYING)
 refine_using_relation (op1, op1_range, op2, op2_range, src, op_op);
 
-- 
2.40.1



Re: Enable ranger for ipa-prop

2023-06-27 Thread Andrew MacLeod via Gcc-patches



On 6/27/23 12:24, Jan Hubicka wrote:

On 6/27/23 09:19, Jan Hubicka wrote:

Hi,
as shown in the testcase (which would eventually be useful for
optimizing std::vector's push_back), ipa-prop can use context dependent ranger
queries for better value range info.

Bootstrapped/regtested x86_64-linux, OK?

Quick question.

When you call enable_ranger(), its gives you a ranger back, but it also sets
the range query for the specified context to that same instance.  So from
that point forward  all existing calls to get_range_query(fun) will now use
the context ranger

enable_ranger (struct function *fun, bool use_imm_uses)
<...>
   gcc_checking_assert (!fun->x_range_query);
   r = new gimple_ranger (use_imm_uses);
   fun->x_range_query = r;
   return r;

So you probably dont have to pass a ranger around?  or is that ranger you
are passing for a different context?

I don't need passing ranger around - I just did not know that.  I tought
the default one is the context insensitive one, I will simplify the
patch.  I need to look more into how ranger works.



No need. Its magic!

Andrew


PS. well, we tried to provide an interface to make it as seamless as 
possible with the whole range-query thing.

10,000 foot view:

The range_query object (value-range.h) replaces the old 
SSA_NAME_RANGE_INFO macros.  It adds the ability to provide an optional 
context in the form of a stmt or edge to any query.  If no context is 
provided, it simply provides the global value. There are basically 3 
queries:


  virtual bool range_of_expr (vrange , tree expr, gimple * = NULL) ;
  virtual bool range_on_edge (vrange , edge, tree expr);
  virtual bool range_of_stmt (vrange , gimple *, tree name = NULL);

- range_of_stmt evaluates the DEF of the stmt, but can also evaluate 
things like  "if (x < y)" that have an implicit boolean LHS.  If NAME is 
provided, it needs to match the DEF. Thats mostly flexibility for 
dealing with something like multiple defs, you can specify which def.
- range_on_edge provides the range of an ssa-name as it would be valued 
on a specific edge.
- range_of_expr is used to ask for the range of any ssa_name or tree 
expression as it occurs on entry to a specific stmt. Normally we use 
this to ask for the range of an ssa-name as its used on a stmt,  but it 
can evaluate expression trees as well.


These requests are not limited to names which occur on a stmt.. we can 
recompute values by asking for the range of value as they occur at other 
locations in the IL.  ie

x_2 = b_3 + 5
<...>
if (b_3 > 7)
   blah (x_2)
When we ask for the range of x_2 at the call to blah, ranger actually 
recomputes x_2 = b_3 + 5 at the call site by asking for the range of b_3 
on the outgoing edge leading to the block with the call to blah, and 
thus uses b_3 == [8, +INF] to re-evaluate x_2


Internally, ranger uses the exact same API to evaluate everything that 
external clients use.



The default query object is global_range_query, which ignores any 
location (stmt or edge) information provided, and simply returns the 
global value. This amounts to an identical result as the old 
SSA_NAME_RANGE_INFO request, and when get_range_query () is called, this 
is the default range_query that is provided.


When a pass calls enable_ranger(), the default query is changed to this 
new instance (which supports context information), and any further calls 
to get_range_query() will now invoke ranger instead of the 
global_range_query.  It uses its on-demand support to go and answer the 
range question by looking at only what it needs to in order to answer 
the question.  This is the exact same ranger code base that all the VRP 
passes use, so you get almost the same level of power to answer 
questions.  There are just a couple of little things that VRP enables 
because it does a DOM walk, but they are fairly minor for most cases.


if you use the range_query API, and do not provide a stmt or an edge, 
then we can't provide contextual range information, and you'll go back 
to getting just global information again.


I think Aldy has converted everything to the new range_query API...  
which means any pass that could benefit from contextual range 
information , in theory, only needs to enable_ranger() and provide a 
context stmt or edge on the range query call.


Just remember to disable it when done :-)

Andrew



Re: Enable ranger for ipa-prop

2023-06-27 Thread Andrew MacLeod via Gcc-patches



On 6/27/23 09:19, Jan Hubicka wrote:

Hi,
as shown in the testcase (which would eventually be useful for
optimizing std::vector's push_back), ipa-prop can use context dependent ranger
queries for better value range info.

Bootstrapped/regtested x86_64-linux, OK?


Quick question.

When you call enable_ranger(), its gives you a ranger back, but it also 
sets the range query for the specified context to that same instance.  
So from that point forward  all existing calls to get_range_query(fun) 
will now use the context ranger


enable_ranger (struct function *fun, bool use_imm_uses)
<...>
  gcc_checking_assert (!fun->x_range_query);
  r = new gimple_ranger (use_imm_uses);
  fun->x_range_query = r;
  return r;

So you probably dont have to pass a ranger around?  or is that ranger 
you are passing for a different context?



Andrew




[COMMITTED] PR tree-optimization/110251 - Avoid redundant GORI calcuations.

2023-06-26 Thread Andrew MacLeod via Gcc-patches
When calculating ranges, GORI evaluates the chain of definitions until 
it finds the desired name.


  _4 = (short unsigned int) c.2_1;
  _5 = _4 + 65535;
  a_lsm.19_30 = a;
  _49 = _4 + 65534;
  _12 = _5 & _49;
  _46 = _12 + 65535;
  _48 = _12 & _46;    <<--
  if (_48 != 0)

When evaluating c.2_1 on the true edge, GORI starts with _48 with a 
range of [1, +INF]


Looking at _48's operands (_12 and _46), note that it depends both  _12 
and _46.  Also note that _46 is also dependent on _12.


GORI currently simply calculates c.2_1 through both operands. this means 
_12 will be evaluates back thru to c.2_1, and then _46 will do the same 
and the results will be combined.  that means the statements from _12 
back to c.2_1 are actually calculated twice.


This PR produces a sequence of code which is quite long, with cascading 
chains of dependencies like this that feed each other. This becomes a 
geometric/exponential growth in calculation time, over and over.


This patch identifies the situation of one operand depending on the 
other, and simply evaluates only  the one which includes the other.  In 
the above case, it simply winds back thru _46 ignoring the _12 operand 
in the definition of _48.    During the process of evaluating _46, we 
eventually get to evaluating _12 anyway, so we don't lose much, if 
anything.    This results in a much more consistently linear time 
evaluation.


Bootstraps on x86_64-pc-linux-gnu with no regressions.   Pushed.

Andrew







commit 6246ee062062b53275c229daf8676ccaa535f419
Author: Andrew MacLeod 
Date:   Thu Jun 22 10:00:12 2023 -0400

Avoid redundant GORI calcuations.

When GORI evaluates a statement, if operand 1 and 2 are both in the
dependency chain, GORI evaluates the name through both operands sequentially
and combines the results.

If either operand is in the dependency chain of the other, this
evaluation will do the same work twice, for questionable gain.
Instead, simple evaluate only the operand which depends on the other
and keep the evaluation linear in time.

* gimple-range-gori.cc (compute_operand1_and_operand2_range):
Check for interdependence between operands 1 and 2.

diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc
index abc70cd54ee..4ee0ae36014 100644
--- a/gcc/gimple-range-gori.cc
+++ b/gcc/gimple-range-gori.cc
@@ -1291,13 +1291,26 @@ gori_compute::compute_operand1_and_operand2_range (vrange ,
 {
   Value_Range op_range (TREE_TYPE (name));
 
-  // Calculate a good a range for op2.  Since op1 == op2, this will
-  // have already included whatever the actual range of name is.
-  if (!compute_operand2_range (op_range, handler, lhs, name, src, rel))
+  // If op1 is in the def chain of op2, we'll do the work twice to evalaute
+  // op1.  This can result in an exponential time calculation.
+  // Instead just evaluate op2, which will eventualy get to op1.
+  if (in_chain_p (handler.operand1 (), handler.operand2 ()))
+return compute_operand2_range (r, handler, lhs, name, src, rel);
+
+  // Likewise if op2 is in the def chain of op1.
+  if (in_chain_p (handler.operand2 (), handler.operand1 ()))
+return compute_operand1_range (r, handler, lhs, name, src, rel);
+
+  // Calculate a good a range through op2.
+  if (!compute_operand2_range (r, handler, lhs, name, src, rel))
 return false;
 
+  // If op1 == op2 there is again no need to go further.
+  if (handler.operand1 () == handler.operand2 ())
+return true;
+
   // Now get the range thru op1.
-  if (!compute_operand1_range (r, handler, lhs, name, src, rel))
+  if (!compute_operand1_range (op_range, handler, lhs, name, src, rel))
 return false;
 
   // Both operands have to be simultaneously true, so perform an intersection.


[PATCH] PR tree-optimization/110266 - Check for integer only complex

2023-06-15 Thread Andrew MacLeod via Gcc-patches
With the expanded capabilities of range-op dispatch, floating point 
complex objects can appear when folding, whic they couldn't before. In 
the processing for extracting integers from complex int's, make sure it 
actually is an integer.


Bootstraps on x86_64-pc-linux-gnu.  Regtesting currently under way.  
Assuming there are no issues, I will push this.


Andrew

From 2ba20a9e7b41fbcf1f03d5447e14b9b7b174fead Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Thu, 15 Jun 2023 11:59:55 -0400
Subject: [PATCH] Check for integer only complex.

With the expanded capabilities of range-op dispatch, floating point
complex objects can appear when folding, whic they couldn't before.
In the processig for extracting integers from complex ints, make sure it
is an integer complex.

	PR tree-optimization/110266
	gcc/
	* gimple-range-fold.cc (adjust_imagpart_expr): Check for integer
	complex type.
	(adjust_realpart_expr): Ditto.

	gcc/testsuite/
	* gcc.dg/pr110266.c: New.
---
 gcc/gimple-range-fold.cc|  6 --
 gcc/testsuite/gcc.dg/pr110266.c | 20 
 2 files changed, 24 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr110266.c

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index 173d9f386c5..b4018d08d2b 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -506,7 +506,8 @@ adjust_imagpart_expr (vrange , const gimple *stmt)
   && gimple_assign_rhs_code (def_stmt) == COMPLEX_CST)
 {
   tree cst = gimple_assign_rhs1 (def_stmt);
-  if (TREE_CODE (cst) == COMPLEX_CST)
+  if (TREE_CODE (cst) == COMPLEX_CST
+	  && TREE_CODE (TREE_TYPE (TREE_TYPE (cst))) == INTEGER_TYPE)
 	{
 	  wide_int w = wi::to_wide (TREE_IMAGPART (cst));
 	  int_range<1> imag (TREE_TYPE (TREE_IMAGPART (cst)), w, w);
@@ -533,7 +534,8 @@ adjust_realpart_expr (vrange , const gimple *stmt)
   && gimple_assign_rhs_code (def_stmt) == COMPLEX_CST)
 {
   tree cst = gimple_assign_rhs1 (def_stmt);
-  if (TREE_CODE (cst) == COMPLEX_CST)
+  if (TREE_CODE (cst) == COMPLEX_CST
+	  && TREE_CODE (TREE_TYPE (TREE_TYPE (cst))) == INTEGER_TYPE)
 	{
 	  wide_int imag = wi::to_wide (TREE_REALPART (cst));
 	  int_range<2> tmp (TREE_TYPE (TREE_REALPART (cst)), imag, imag);
diff --git a/gcc/testsuite/gcc.dg/pr110266.c b/gcc/testsuite/gcc.dg/pr110266.c
new file mode 100644
index 000..0b2acb5a791
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr110266.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+#include 
+
+int Hann_i, PsyBufferUpdate_psyInfo_0, PsyBufferUpdate_i;
+double *mdct_data;
+double PsyBufferUpdate_sfreq;
+void PsyBufferUpdate() {
+  if (PsyBufferUpdate_psyInfo_0 == 4)
+for (; Hann_i;)
+  ;
+  {
+double xr_0 = cos(PsyBufferUpdate_psyInfo_0);
+PsyBufferUpdate_sfreq = sin(PsyBufferUpdate_psyInfo_0);
+for (; PsyBufferUpdate_psyInfo_0; PsyBufferUpdate_i++)
+  mdct_data[PsyBufferUpdate_i] = xr_0 * PsyBufferUpdate_sfreq;
+  }
+}
+
-- 
2.40.1



[COMMITTED 12/17] - Add a hybrid MAX_EXPR operator for integer and pointer.

2023-06-12 Thread Andrew MacLeod via Gcc-patches
Add a hybrid operator to choose between integer and pointer versions at 
runtime.


This is the last use of the pointer table, so it is also removed.

Bootstraps on x86_64-pc-linux-gnu with no regressions.  Pushed.

Andrew
From cd194f582c5be3cc91e025e304e2769f61ceb6b6 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Sat, 10 Jun 2023 16:35:18 -0400
Subject: [PATCH 12/17] Add a hybrid MAX_EXPR operator for integer and pointer.

This adds an operator to the unified table for MAX_EXPR which will
select either the pointer or integer version based on the type passed
to the method.   This is for use until we have a seperate PRANGE class.

THIs also removes the pointer table which is no longer needed.

	* range-op-mixed.h (operator_max): Remove final.
	* range-op-ptr.cc (pointer_table::pointer_table): Remove MAX_EXPR.
	(pointer_table::pointer_table): Remove.
	(class hybrid_max_operator): New.
	(range_op_table::initialize_pointer_ops): Add hybrid_max_operator.
	* range-op.cc (pointer_tree_table): Remove.
	(unified_table::unified_table): Comment out MAX_EXPR.
	(get_op_handler): Remove check of pointer table.
	* range-op.h (class pointer_table): Remove.
---
 gcc/range-op-mixed.h |  6 +++---
 gcc/range-op-ptr.cc  | 30 --
 gcc/range-op.cc  | 10 ++
 gcc/range-op.h   |  9 -
 4 files changed, 25 insertions(+), 30 deletions(-)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index a65935435c2..bdc488b8754 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -636,10 +636,10 @@ class operator_max : public range_operator
 {
 public:
   void update_bitmask (irange , const irange ,
-  const irange ) const final override;
-private:
+  const irange ) const override;
+protected:
   void wi_fold (irange , tree type, const wide_int _lb,
 		const wide_int _ub, const wide_int _lb,
-		const wide_int _ub) const final override;
+		const wide_int _ub) const override;
 };
 #endif // GCC_RANGE_OP_MIXED_H
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index 483e43ca994..ea66fe9056b 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -157,7 +157,6 @@ pointer_min_max_operator::wi_fold (irange , tree type,
 r.set_varying (type);
 }
 
-
 class pointer_and_operator : public range_operator
 {
 public:
@@ -265,14 +264,6 @@ operator_pointer_diff::op1_op2_relation_effect (irange _range, tree type,
 	rel);
 }
 
-// When PRANGE is implemented, these are all the opcodes which are currently
-// expecting routines with PRANGE signatures.
-
-pointer_table::pointer_table ()
-{
-  set (MAX_EXPR, op_ptr_min_max);
-}
-
 // --
 // Hybrid operators for the 4 operations which integer and pointers share,
 // but which have different implementations.  Simply check the type in
@@ -404,8 +395,26 @@ public:
 }
 } op_hybrid_min;
 
+class hybrid_max_operator : public operator_max
+{
+public:
+  void update_bitmask (irange , const irange ,
+		   const irange ) const final override
+{
+  if (!r.undefined_p () && INTEGRAL_TYPE_P (r.type ()))
+	operator_max::update_bitmask (r, lh, rh);
+}
 
-
+  void wi_fold (irange , tree type, const wide_int _lb,
+		const wide_int _ub, const wide_int _lb,
+		const wide_int _ub) const final override
+{
+  if (INTEGRAL_TYPE_P (type))
+	return operator_max::wi_fold (r, type, lh_lb, lh_ub, rh_lb, rh_ub);
+  else
+	return op_ptr_min_max.wi_fold (r, type, lh_lb, lh_ub, rh_lb, rh_ub);
+}
+} op_hybrid_max;
 
 // Initialize any pointer operators to the primary table
 
@@ -417,4 +426,5 @@ range_op_table::initialize_pointer_ops ()
   set (BIT_AND_EXPR, op_hybrid_and);
   set (BIT_IOR_EXPR, op_hybrid_or);
   set (MIN_EXPR, op_hybrid_min);
+  set (MAX_EXPR, op_hybrid_max);
 }
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 481f3b1324d..046b7691bb6 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -49,8 +49,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-ccp.h"
 #include "range-op-mixed.h"
 
-pointer_table pointer_tree_table;
-
 // Instantiate a range_op_table for unified operations.
 class unified_table : public range_op_table
 {
@@ -124,18 +122,14 @@ unified_table::unified_table ()
   // set (BIT_AND_EXPR, op_bitwise_and);
   // set (BIT_IOR_EXPR, op_bitwise_or);
   // set (MIN_EXPR, op_min);
-  set (MAX_EXPR, op_max);
+  // set (MAX_EXPR, op_max);
 }
 
 // The tables are hidden and accessed via a simple extern function.
 
 range_operator *
-get_op_handler (enum tree_code code, tree type)
+get_op_handler (enum tree_code code, tree)
 {
-  // If this is pointer type and there is pointer specifc routine, use it.
-  if (POINTER_TYPE_P (type) && pointer_tree_table[code])
-return pointer_tree_table[code];
-
   return unified_tree_table[code];
 }
 
diff --git a/gcc/range-op.h b/gcc/range-op.h
index 08c51bace40..15c45137af2 100644
--- a/gcc/range-op.h
+++ b/gcc/range-op.h

[COMMITTED 17/17] PR tree-optimization/110205 - Add some overrides.

2023-06-12 Thread Andrew MacLeod via Gcc-patches
Add some missing overrides, and add the diaptch pattern for FII which 
will be used for integer to float conversion.


Bootstraps on x86_64-pc-linux-gnu with no regressions.  Pushed.

Andrew
From 1bed4b49302e2fd7bf89426117331ae89ebdc90b Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Mon, 12 Jun 2023 09:47:43 -0400
Subject: [PATCH 17/17] Add some overrides.

	PR tree-optimization/110205
	* range-op-float.cc (range_operator::fold_range): Add default FII
	fold routine.
	(Class operator_gt): Add missing final overrides.
	* range-op.cc (range_op_handler::fold_range): Add RO_FII case.
	(operator_lshift ::update_bitmask): Add final override.
	(operator_rshift ::update_bitmask): Add final override.
	* range-op.h (range_operator::fold_range): Add FII prototype.
---
 gcc/range-op-float.cc | 10 ++
 gcc/range-op-mixed.h  |  9 +
 gcc/range-op.cc   | 10 --
 gcc/range-op.h|  4 
 4 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index 24f2235884f..f5c0cec75c4 100644
--- a/gcc/range-op-float.cc
+++ b/gcc/range-op-float.cc
@@ -157,6 +157,16 @@ range_operator::fold_range (irange  ATTRIBUTE_UNUSED,
   return false;
 }
 
+bool
+range_operator::fold_range (frange  ATTRIBUTE_UNUSED,
+			tree type ATTRIBUTE_UNUSED,
+			const irange  ATTRIBUTE_UNUSED,
+			const irange  ATTRIBUTE_UNUSED,
+			relation_trio) const
+{
+  return false;
+}
+
 bool
 range_operator::op1_range (frange  ATTRIBUTE_UNUSED,
  tree type ATTRIBUTE_UNUSED,
diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index bdc488b8754..6944742ecbc 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -239,26 +239,27 @@ public:
   using range_operator::op1_op2_relation;
   bool fold_range (irange , tree type,
 		   const irange , const irange ,
-		   relation_trio = TRIO_VARYING) const;
+		   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;
+		  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;
+		  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 final override;
-  void update_bitmask (irange , const irange , const irange ) const;
+  void update_bitmask (irange , const irange ,
+		   const irange ) const final override;
 };
 
 class operator_ge :  public range_operator
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 8a661fdb042..f0dff53ec1e 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -219,6 +219,10 @@ range_op_handler::fold_range (vrange , tree type,
 	return m_operator->fold_range (as_a  (r), type,
    as_a  (lh),
    as_a  (rh), rel);
+  case RO_FII:
+	return m_operator->fold_range (as_a  (r), type,
+   as_a  (lh),
+   as_a  (rh), rel);
   default:
 	return false;
 }
@@ -2401,7 +2405,8 @@ public:
 tree type,
 const wide_int &,
 const wide_int &) const;
-  void update_bitmask (irange , const irange , const irange ) const
+  void update_bitmask (irange , const irange ,
+		   const irange ) const final override
 { update_known_bitmask (r, LSHIFT_EXPR, lh, rh); }
 } op_lshift;
 
@@ -2432,7 +2437,8 @@ public:
 	   const irange ,
 	   const irange ,
 	   relation_kind rel) const;
-  void update_bitmask (irange , const irange , const irange ) const
+  void update_bitmask (irange , const irange ,
+		   const irange ) const final override
 { update_known_bitmask (r, RSHIFT_EXPR, lh, rh); }
 } op_rshift;
 
diff --git a/gcc/range-op.h b/gcc/range-op.h
index 3602bc4e123..af94c2756a7 100644
--- a/gcc/range-op.h
+++ b/gcc/range-op.h
@@ -72,6 +72,10 @@ public:
 			   const frange ,
 			   const frange ,
 			   relation_trio = TRIO_VARYING) const;
+  virtual bool fold_range (frange , tree type,
+			   const irange ,
+			   const irange ,
+			   relation_trio = TRIO_VARYING) const;
 
   // Return the range for op[12] in the general case.  LHS is the range for
   // the LHS of the expression, OP[12]is the range for the other
-- 
2.40.1



[COMMITTED 10/17] - Add a hybrid BIT_IOR_EXPR operator for integer and pointer.

2023-06-12 Thread Andrew MacLeod via Gcc-patches
Add a hybrid operator to choose between integer and pointer versions at 
runtime.


Bootstraps on x86_64-pc-linux-gnu with no regressions.  Pushed.

Andrew
From 80f402e832a2ce402ee1562030d5c67ebc276f7c Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Sat, 10 Jun 2023 16:33:17 -0400
Subject: [PATCH 10/17] Add a hybrid BIT_IOR_EXPR operator for integer and
 pointer.

This adds an operator to the unified table for BIT_IOR_EXPR which will
select either the pointer or integer version based on the type passed
to the method.   This is for use until we have a seperate PRANGE class.

	* range-op-mixed.h (operator_bitwise_or): Remove final.
	* range-op-ptr.cc (pointer_table::pointer_table): Remove BIT_IOR_EXPR.
	(class hybrid_or_operator): New.
	(range_op_table::initialize_pointer_ops): Add hybrid_or_operator.
	* range-op.cc (unified_table::unified_table): Comment out BIT_IOR_EXPR.
---
 gcc/range-op-mixed.h | 10 -
 gcc/range-op-ptr.cc  | 52 ++--
 gcc/range-op.cc  |  4 ++--
 3 files changed, 57 insertions(+), 9 deletions(-)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 4177818e4b9..e4852e974c4 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -609,16 +609,16 @@ public:
   using range_operator::op2_range;
   bool op1_range (irange , tree type,
 		  const irange , const irange ,
-		  relation_trio rel = TRIO_VARYING) const final override;
+		  relation_trio rel = TRIO_VARYING) const override;
   bool op2_range (irange , tree type,
 		  const irange , const irange ,
-		  relation_trio rel = TRIO_VARYING) const final override;
+		  relation_trio rel = TRIO_VARYING) const override;
   void update_bitmask (irange , const irange ,
-		   const irange ) const final override;
-private:
+		   const irange ) const override;
+protected:
   void wi_fold (irange , tree type, const wide_int _lb,
 		const wide_int _ub, const wide_int _lb,
-		const wide_int _ub) const final override;
+		const wide_int _ub) const override;
 };
 
 class operator_min : public range_operator
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index 941026994ed..7b22d0bf05b 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -184,9 +184,9 @@ pointer_and_operator::wi_fold (irange , tree type,
 
 class pointer_or_operator : public range_operator
 {
+public:
   using range_operator::op1_range;
   using range_operator::op2_range;
-public:
   virtual bool op1_range (irange , tree type,
 			  const irange ,
 			  const irange ,
@@ -270,7 +270,6 @@ operator_pointer_diff::op1_op2_relation_effect (irange _range, tree type,
 
 pointer_table::pointer_table ()
 {
-  set (BIT_IOR_EXPR, op_pointer_or);
   set (MIN_EXPR, op_ptr_min_max);
   set (MAX_EXPR, op_ptr_min_max);
 }
@@ -334,6 +333,54 @@ public:
 }
 } op_hybrid_and;
 
+// Temporary class which dispatches routines to either the INT version or
+// the pointer version depending on the type.  Once PRANGE is a range
+// class, we can remove the hybrid.
+
+class hybrid_or_operator : public operator_bitwise_or
+{
+public:
+  using range_operator::op1_range;
+  using range_operator::op2_range;
+  using range_operator::lhs_op1_relation;
+  bool op1_range (irange , tree type,
+		  const irange , const irange ,
+		  relation_trio rel = TRIO_VARYING) const final override
+{
+  if (INTEGRAL_TYPE_P (type))
+	return operator_bitwise_or::op1_range (r, type, lhs, op2, rel);
+  else
+	return op_pointer_or.op1_range (r, type, lhs, op2, rel);
+}
+  bool op2_range (irange , tree type,
+		  const irange , const irange ,
+		  relation_trio rel = TRIO_VARYING) const final override
+{
+  if (INTEGRAL_TYPE_P (type))
+	return operator_bitwise_or::op2_range (r, type, lhs, op1, rel);
+  else
+	return op_pointer_or.op2_range (r, type, lhs, op1, rel);
+}
+  void update_bitmask (irange , const irange ,
+		   const irange ) const final override
+{
+  if (!r.undefined_p () && INTEGRAL_TYPE_P (r.type ()))
+	operator_bitwise_or::update_bitmask (r, lh, rh);
+}
+
+  void wi_fold (irange , tree type, const wide_int _lb,
+		const wide_int _ub, const wide_int _lb,
+		const wide_int _ub) const final override
+{
+  if (INTEGRAL_TYPE_P (type))
+	return operator_bitwise_or::wi_fold (r, type, lh_lb, lh_ub,
+	  rh_lb, rh_ub);
+  else
+	return op_pointer_or.wi_fold (r, type, lh_lb, lh_ub, rh_lb, rh_ub);
+}
+} op_hybrid_or;
+
+
 
 // Initialize any pointer operators to the primary table
 
@@ -343,4 +390,5 @@ range_op_table::initialize_pointer_ops ()
   set (POINTER_PLUS_EXPR, op_pointer_plus);
   set (POINTER_DIFF_EXPR, op_pointer_diff);
   set (BIT_AND_EXPR, op_hybrid_and);
+  set (BIT_IOR_EXPR, op_hybrid_or);
 }
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index dcb922143ce..0a9a3297de7 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -121,8 +121,8 @@ unified_table::unified_table ()
   // is used until there is a pointer range class.  Then we can simply
   // u

[COMMITTED 15/17] - Provide a default range_operator via range_op_handler.

2023-06-12 Thread Andrew MacLeod via Gcc-patches
This provides range_op_handler with a default range_operator, so you no 
longer need to check if it has a valid handler or not.


The valid check now turns into a "is this something other than a default 
operator" check.   IT means you can now simply invoke fold without 
checking.. ie instead of


range_op_handler handler(CONVERT_EXPR);
if (handler &&  handler.fold_range (..))

we can simply write
if (range_op_handler(CONVERT_EXPR).fold_range ())

The new method range_op() will return the a pointer to the custom 
range_operator, or NULL if its the default.   THis allos use of 
range_op_handler() to behave as if you were indexing a range table/ if 
that happens to be needed.


Bootstraps on x86_64-pc-linux-gnu with no regressions.  Pushed.

Andrew
From 3c4399657d35a0b5bf7caeb88c6ddc0461322d3f Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Sat, 10 Jun 2023 16:59:38 -0400
Subject: [PATCH 15/17] Provide a default range_operator via range_op_handler.

range_op_handler now provides a default range_operator for any opcode,
so there is no longer a need to check for a valid operator.

	* gimple-range-op.cc (gimple_range_op_handler): Set m_operator
	manually as there is no access to the default operator.
	(cfn_copysign::fold_range): Don't check for validity.
	(cfn_ubsan::fold_range): Ditto.
	(gimple_range_op_handler::maybe_builtin_call): Don't set to NULL.
	* range-op.cc (default_operator): New.
	(range_op_handler::range_op_handler): Use default_operator
	instead of NULL.
	(range_op_handler::operator bool): Move from header, compare
	against default operator.
	(range_op_handler::range_op): New.
	* range-op.h (range_op_handler::operator bool): Move.
---
 gcc/gimple-range-op.cc | 28 +---
 gcc/range-op.cc| 32 ++--
 gcc/range-op.h |  3 ++-
 3 files changed, 45 insertions(+), 18 deletions(-)

diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index 4cbc981ee04..021a9108ecf 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -120,21 +120,22 @@ gimple_range_op_handler::supported_p (gimple *s)
 // Construct a handler object for statement S.
 
 gimple_range_op_handler::gimple_range_op_handler (gimple *s)
-  : range_op_handler (get_code (s))
 {
+  range_op_handler oper (get_code (s));
   m_stmt = s;
   m_op1 = NULL_TREE;
   m_op2 = NULL_TREE;
 
-  if (m_operator)
+  if (oper)
 switch (gimple_code (m_stmt))
   {
 	case GIMPLE_COND:
 	  m_op1 = gimple_cond_lhs (m_stmt);
 	  m_op2 = gimple_cond_rhs (m_stmt);
 	  // Check that operands are supported types.  One check is enough.
-	  if (!Value_Range::supports_type_p (TREE_TYPE (m_op1)))
-	m_operator = NULL;
+	  if (Value_Range::supports_type_p (TREE_TYPE (m_op1)))
+	m_operator = oper.range_op ();
+	  gcc_checking_assert (m_operator);
 	  return;
 	case GIMPLE_ASSIGN:
 	  m_op1 = gimple_range_base_of_assignment (m_stmt);
@@ -153,7 +154,9 @@ gimple_range_op_handler::gimple_range_op_handler (gimple *s)
 	m_op2 = gimple_assign_rhs2 (m_stmt);
 	  // Check that operands are supported types.  One check is enough.
 	  if ((m_op1 && !Value_Range::supports_type_p (TREE_TYPE (m_op1
-	m_operator = NULL;
+	return;
+	  m_operator = oper.range_op ();
+	  gcc_checking_assert (m_operator);
 	  return;
 	default:
 	  gcc_unreachable ();
@@ -165,6 +168,7 @@ gimple_range_op_handler::gimple_range_op_handler (gimple *s)
 maybe_builtin_call ();
   else
 maybe_non_standard ();
+  gcc_checking_assert (m_operator);
 }
 
 // Calculate what we can determine of the range of this unary
@@ -364,11 +368,10 @@ public:
 			   const frange , relation_trio) const override
   {
 frange neg;
-range_op_handler abs_op (ABS_EXPR);
-range_op_handler neg_op (NEGATE_EXPR);
-if (!abs_op || !abs_op.fold_range (r, type, lh, frange (type)))
+if (!range_op_handler (ABS_EXPR).fold_range (r, type, lh, frange (type)))
   return false;
-if (!neg_op || !neg_op.fold_range (neg, type, r, frange (type)))
+if (!range_op_handler (NEGATE_EXPR).fold_range (neg, type, r,
+		frange (type)))
   return false;
 
 bool signbit;
@@ -1073,14 +1076,11 @@ public:
   virtual bool fold_range (irange , tree type, const irange ,
 			   const irange , relation_trio rel) const
   {
-range_op_handler handler (m_code);
-gcc_checking_assert (handler);
-
 bool saved_flag_wrapv = flag_wrapv;
 // Pretend the arithmetic is wrapping.  If there is any overflow,
 // we'll complain, but will actually do wrapping operation.
 flag_wrapv = 1;
-bool result = handler.fold_range (r, type, lh, rh, rel);
+bool result = range_op_handler (m_code).fold_range (r, type, lh, rh, rel);
 flag_wrapv = saved_flag_wrapv;
 
 // If for both arguments vrp_valueize returned non-NULL, this should
@@ -1230,8 +1230,6 @@ gimple_range_op_handler::maybe_builtin_call ()
 	m_operator = _cfn_constant_p;
   else if (frange::su

[COMMITTED 9/17] - Add a hybrid BIT_AND_EXPR operator for integer and pointer.

2023-06-12 Thread Andrew MacLeod via Gcc-patches
Add a hybrid operator to choose between integer and pointer versions at 
runtime.


Bootstraps on x86_64-pc-linux-gnu with no regressions.  Pushed.

Andrew
From 8adb8b2fd5797706e9fbb353d52fda123545431d Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Sat, 10 Jun 2023 16:28:40 -0400
Subject: [PATCH 09/17] Add a hybrid BIT_AND_EXPR operator for integer and
 pointer.

This adds an operator to the unified table for BIT_AND_EXPR which will
select either the pointer or integer version based on the type passed
to the method.   This is for use until we have a seperate PRANGE class.

	* range-op-mixed.h (operator_bitwise_and): Remove final.
	* range-op-ptr.cc (pointer_table::pointer_table): Remove BIT_AND_EXPR.
	(class hybrid_and_operator): New.
	(range_op_table::initialize_pointer_ops): Add hybrid_and_operator.
	* range-op.cc (unified_table::unified_table): Comment out BIT_AND_EXPR.
---
 gcc/range-op-mixed.h | 12 -
 gcc/range-op-ptr.cc  | 62 +++-
 gcc/range-op.cc  |  9 ---
 3 files changed, 73 insertions(+), 10 deletions(-)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index b188f5a516e..4177818e4b9 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -584,19 +584,19 @@ public:
   using range_operator::lhs_op1_relation;
   bool op1_range (irange , tree type,
 		  const irange , const irange ,
-		  relation_trio rel = TRIO_VARYING) const final override;
+		  relation_trio rel = TRIO_VARYING) const override;
   bool op2_range (irange , tree type,
 		  const irange , const irange ,
-		  relation_trio rel = TRIO_VARYING) const final override;
+		  relation_trio rel = TRIO_VARYING) const override;
   relation_kind lhs_op1_relation (const irange ,
   const irange , const irange ,
-  relation_kind) const final override;
+  relation_kind) const override;
   void update_bitmask (irange , const irange ,
-		   const irange ) const final override;
-private:
+		   const irange ) const override;
+protected:
   void wi_fold (irange , tree type, const wide_int _lb,
 		const wide_int _ub, const wide_int _lb,
-		const wide_int _ub) const final override;
+		const wide_int _ub) const override;
   void simple_op1_range_solver (irange , tree type,
 const irange ,
 const irange ) const;
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index 55c37cc8c86..941026994ed 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -270,12 +270,71 @@ operator_pointer_diff::op1_op2_relation_effect (irange _range, tree type,
 
 pointer_table::pointer_table ()
 {
-  set (BIT_AND_EXPR, op_pointer_and);
   set (BIT_IOR_EXPR, op_pointer_or);
   set (MIN_EXPR, op_ptr_min_max);
   set (MAX_EXPR, op_ptr_min_max);
 }
 
+// --
+// Hybrid operators for the 4 operations which integer and pointers share,
+// but which have different implementations.  Simply check the type in
+// the call and choose the appropriate method.
+// Once there is a PRANGE signature, simply add the appropriate
+// prototypes in the rmixed range class, and remove these hybrid classes.
+
+class hybrid_and_operator : public operator_bitwise_and
+{
+public:
+  using range_operator::op1_range;
+  using range_operator::op2_range;
+  using range_operator::lhs_op1_relation;
+  bool op1_range (irange , tree type,
+		  const irange , const irange ,
+		  relation_trio rel = TRIO_VARYING) const final override
+{
+  if (INTEGRAL_TYPE_P (type))
+	return operator_bitwise_and::op1_range (r, type, lhs, op2, rel);
+  else
+	return false;
+}
+  bool op2_range (irange , tree type,
+		  const irange , const irange ,
+		  relation_trio rel = TRIO_VARYING) const final override
+{
+  if (INTEGRAL_TYPE_P (type))
+	return operator_bitwise_and::op2_range (r, type, lhs, op1, rel);
+  else
+	return false;
+}
+  relation_kind lhs_op1_relation (const irange ,
+  const irange , const irange ,
+  relation_kind rel) const final override
+{
+  if (!lhs.undefined_p () && INTEGRAL_TYPE_P (lhs.type ()))
+	return operator_bitwise_and::lhs_op1_relation (lhs, op1, op2, rel);
+  else
+	return VREL_VARYING;
+}
+  void update_bitmask (irange , const irange ,
+		   const irange ) const final override
+{
+  if (!r.undefined_p () && INTEGRAL_TYPE_P (r.type ()))
+	operator_bitwise_and::update_bitmask (r, lh, rh);
+}
+
+  void wi_fold (irange , tree type, const wide_int _lb,
+		const wide_int _ub, const wide_int _lb,
+		const wide_int _ub) const final override
+{
+  if (INTEGRAL_TYPE_P (type))
+	return operator_bitwise_and::wi_fold (r, type, lh_lb, lh_ub,
+	  rh_lb, rh_ub);
+  else
+	return op_pointer_and.wi_fold (r, type, lh_lb, lh_ub, rh_lb, rh_ub);
+}
+} op_hybrid_and;
+
+
 // Initialize any pointer operators to the primary table
 
 void
@@ -283,4 +342,5 @@ range_op_table::initialize_pointer_ops ()
 {
   set (POINTER_PLUS_EXPR,

[COMMITTED 16/17] - Provide interface for non-standard operators.

2023-06-12 Thread Andrew MacLeod via Gcc-patches
This patch removes the hack introduced late last year for the 
non-standard range-op support.


Instead of adding a a pointer to a range_operator in the header file, 
and then setting the operator from another file via that pointer, the 
table itself is extended and  we provide new #defines to declare new 
operators.


Bootstraps on x86_64-pc-linux-gnu with no regressions.  Pushed.

Andrew
From 6d3b6847bcb36221185a6259d19d743f4cfe1b5a Mon Sep 17 00:00:00 2001
From: Andrew MacLeod 
Date: Sat, 10 Jun 2023 17:06:36 -0400
Subject: [PATCH 16/17] Provide interface for non-standard operators.

THis removes the hack introduced for WIDEN_MULT which exported a pointer
to the operator and the gimple-range-op.cc set the operator to this
pointer whenn it was appropriate.

Instead, we simple change the range-op table to be unsigned indexed,
and add new opcodes to the end of the table, allowing them to be indexed
directly via range_op_handler::range_op.

	* gimple-range-op.cc (gimple_range_op_handler::maybe_non_standard):
	Use range_op_handler directly.
	* range-op.cc (range_op_handler::range_op_handler): Unsigned
	param instead of tree-code.
	(ptr_op_widen_plus_signed): Delete.
	(ptr_op_widen_plus_unsigned): Delete.
	(ptr_op_widen_mult_signed): Delete.
	(ptr_op_widen_mult_unsigned): Delete.
	(range_op_table::initialize_integral_ops): Add new opcodes.
	* range-op.h (range_op_handler): Use unsigned.
	(OP_WIDEN_MULT_SIGNED): New.
	(OP_WIDEN_MULT_UNSIGNED): New.
	(OP_WIDEN_PLUS_SIGNED): New.
	(OP_WIDEN_PLUS_UNSIGNED): New.
	(RANGE_OP_TABLE_SIZE): New.
	(range_op_table::operator []): Use unsigned.
	(range_op_table::set): Use unsigned.
	(m_range_tree): Make unsigned.
	(ptr_op_widen_mult_signed): Remove.
	(ptr_op_widen_mult_unsigned): Remove.
	(ptr_op_widen_plus_signed): Remove.
	(ptr_op_widen_plus_unsigned): Remove.
---
 gcc/gimple-range-op.cc | 11 +++
 gcc/range-op.cc| 11 ++-
 gcc/range-op.h | 26 --
 3 files changed, 29 insertions(+), 19 deletions(-)

diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index 021a9108ecf..72c7b866f90 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -1168,8 +1168,11 @@ public:
 void
 gimple_range_op_handler::maybe_non_standard ()
 {
-  range_operator *signed_op = ptr_op_widen_mult_signed;
-  range_operator *unsigned_op = ptr_op_widen_mult_unsigned;
+  range_op_handler signed_op (OP_WIDEN_MULT_SIGNED);
+  gcc_checking_assert (signed_op);
+  range_op_handler unsigned_op (OP_WIDEN_MULT_UNSIGNED);
+  gcc_checking_assert (unsigned_op);
+
   if (gimple_code (m_stmt) == GIMPLE_ASSIGN)
 switch (gimple_assign_rhs_code (m_stmt))
   {
@@ -1195,9 +1198,9 @@ gimple_range_op_handler::maybe_non_standard ()
 	std::swap (m_op1, m_op2);
 
 	  if (signed1 || signed2)
-	m_operator = signed_op;
+	m_operator = signed_op.range_op ();
 	  else
-	m_operator = unsigned_op;
+	m_operator = unsigned_op.range_op ();
 	  break;
 	}
 	default:
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index a271e00fa07..8a661fdb042 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -135,7 +135,7 @@ range_op_handler::range_op_handler ()
 // Create a range_op_handler for CODE.  Use a default operatoer if CODE
 // does not have an entry.
 
-range_op_handler::range_op_handler (tree_code code)
+range_op_handler::range_op_handler (unsigned code)
 {
   m_operator = operator_table[code];
   if (!m_operator)
@@ -1726,7 +1726,6 @@ public:
 			const wide_int _lb,
 			const wide_int _ub) const;
 } op_widen_plus_signed;
-range_operator *ptr_op_widen_plus_signed = _widen_plus_signed;
 
 void
 operator_widen_plus_signed::wi_fold (irange , tree type,
@@ -1760,7 +1759,6 @@ public:
 			const wide_int _lb,
 			const wide_int _ub) const;
 } op_widen_plus_unsigned;
-range_operator *ptr_op_widen_plus_unsigned = _widen_plus_unsigned;
 
 void
 operator_widen_plus_unsigned::wi_fold (irange , tree type,
@@ -2184,7 +2182,6 @@ public:
 			const wide_int _ub)
 const;
 } op_widen_mult_signed;
-range_operator *ptr_op_widen_mult_signed = _widen_mult_signed;
 
 void
 operator_widen_mult_signed::wi_fold (irange , tree type,
@@ -2217,7 +2214,6 @@ public:
 			const wide_int _ub)
 const;
 } op_widen_mult_unsigned;
-range_operator *ptr_op_widen_mult_unsigned = _widen_mult_unsigned;
 
 void
 operator_widen_mult_unsigned::wi_fold (irange , tree type,
@@ -4298,6 +4294,11 @@ range_op_table::initialize_integral_ops ()
   set (IMAGPART_EXPR, op_unknown);
   set (REALPART_EXPR, op_unknown);
   set (ABSU_EXPR, op_absu);
+  set (OP_WIDEN_MULT_SIGNED, op_widen_mult_signed);
+  set (OP_WIDEN_MULT_UNSIGNED, op_widen_mult_unsigned);
+  set (OP_WIDEN_PLUS_SIGNED, op_widen_plus_signed);
+  set (OP_WIDEN_PLUS_UNSIGNED, op_widen_plus_unsigned);
+
 }
 
 #if CHECKING_P
diff --git a/gcc/range-op.h b/gcc/range-op.h
index 8243258eea5..3602bc4e123 100644
--- a/gcc/range-op.h
+++ b/gcc/range-op.h
@@ -185,7 +185,7 @@ class range_op_handler
 {
 public:
   range_op_handler

  1   2   3   4   5   6   7   8   9   10   >