public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 00/17] Move builtin functions to range-ops.
@ 2022-09-22 18:49 Andrew MacLeod
  2022-09-22 18:53 ` [PATCH 01/17] Replace another snippet with a call to, gimple_range_ssa_names Andrew MacLeod
                   ` (16 more replies)
  0 siblings, 17 replies; 18+ messages in thread
From: Andrew MacLeod @ 2022-09-22 18:49 UTC (permalink / raw)
  To: gcc-patches; +Cc: hernandez, aldy

Builtin functions have been handled until now as special cases in 
gimple-range-fold.cc. This set of patches makes the changes required to 
create a range_operator for those functions.  This allows them to behave 
like a normal unary/binary operation through out the ranger ecosystem.  
In particular, it will enable us to make GORI aware of them as we can 
now provide op1_range and op2_range routines, as well as registering an 
relations as needed.  None of these enhanced functions are provided yet, 
this is strictly a conversion.  This enables us to do this for any 
operation with 1 or 2 operands.

There are 17 patches, some are bug fixes, some are infrastructure, a 
couple are just missing functionality, but most are them are conversions 
of the builtins.  I did each builtin as a separate patch so if a 
regression triggers, we can pinpoint it faster.

Of note:

Patch 2 : Modifies the range_op_handler class to store an integer 
handler and a float handler rather than the old tree-code and type.  By 
looking up the handler immediately and storing the pointer, this opens 
up the possibility of processing handlers which are not in a tree-code 
table.

Patch 3 : Range-ops is suppose to be IL independent, designed to work in 
RTL land as well.  A little bit of gimple had crept in, and I needed a 
layer that is gimple aware.  This patch introduces a 
gimple_range_op_handler which inherits from range_op_handler, and acts 
as the connector between the gimple IL and range-ops. Some of that code 
was in range-ops, and a lot more was located in the GORI file.  All 
those bits and pieces have been moved into the new class.

Patch 7 : This patch adjusts gimple_range_op_handler constructor to also 
check if a builtin function call might have a range_operator object 
available, and if so, return that.  This initial conversion also adds 
CFN_BUILT_IN_CONSTANT_P as the first builtin, removing it from the big 
switch in gimple-range-fold.cc.

Patch 8-16 :  Moves SIGNBIT, TOUPPER/LOWER, POPCOUNT, CLZ, CTZ, CLRSB, 
UBSAN*, STRLEN, and GOACC to range-ops.

patch 17: Finally, moves CFA_BUILT_IN_PARITY to range-ops, and removes 
the builtin-function code checks from range_of_call in gimple_range-fold.cc

These patches all bootstrap on x86_64-pc-linux-gnu with no regressions. 
   Performance wise, it all ends up as approximately a wash. (VRP a hair 
slower, threading a hair faster)

Pushed.

Andrew


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 01/17] Replace another snippet with a call to, gimple_range_ssa_names.
  2022-09-22 18:49 [PATCH 00/17] Move builtin functions to range-ops Andrew MacLeod
@ 2022-09-22 18:53 ` Andrew MacLeod
  2022-09-22 18:55 ` [PATCH 02/17] Adjust range_op_handler to store the handler directly Andrew MacLeod
                   ` (15 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Andrew MacLeod @ 2022-09-22 18:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: hernandez, aldy

[-- Attachment #1: Type: text/plain, Size: 190 bytes --]

When the original patch was applied, I missed a spot which could
also be rewritten to use gimple_range_ssa_names.

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

Andrew

[-- Attachment #2: 0001-Replace-another-snippet-with-a-call-to-gimple_range_.patch --]
[-- Type: text/x-patch, Size: 1911 bytes --]

From 3cba5cd6e019182dbff756f621af048d55cdda98 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Wed, 31 Aug 2022 17:28:09 -0400
Subject: [PATCH 01/17] Replace another snippet with a call to
 gimple_range_ssa_names.

When the original patch was applied, I missed a spot which could
also be rewritten to use gimple_range_ssa_names.

	* tree-ssa-threadbackward.cc
	  (back_threader::find_paths_to_names): Replace sequence with
	  a call to gimple_range_ssa_names.
---
 gcc/tree-ssa-threadbackward.cc | 20 +++-----------------
 1 file changed, 3 insertions(+), 17 deletions(-)

diff --git a/gcc/tree-ssa-threadbackward.cc b/gcc/tree-ssa-threadbackward.cc
index 9725f50e639..2a8cfa3ee01 100644
--- a/gcc/tree-ssa-threadbackward.cc
+++ b/gcc/tree-ssa-threadbackward.cc
@@ -435,28 +435,14 @@ back_threader::find_paths_to_names (basic_block bb, bitmap interesting,
 		}
 	      /* For other local defs process their uses, amending
 		 imports on the way.  */
-	      else if (gassign *ass = dyn_cast <gassign *> (def_stmt))
+	      else
 		{
 		  tree ssa[3];
-		  if (range_op_handler (ass))
-		    {
-		      ssa[0] = gimple_range_ssa_p (gimple_range_operand1 (ass));
-		      ssa[1] = gimple_range_ssa_p (gimple_range_operand2 (ass));
-		      ssa[2] = NULL_TREE;
-		    }
-		  else if (gimple_assign_rhs_code (ass) == COND_EXPR)
-		    {
-		      ssa[0] = gimple_range_ssa_p (gimple_assign_rhs1 (ass));
-		      ssa[1] = gimple_range_ssa_p (gimple_assign_rhs2 (ass));
-		      ssa[2] = gimple_range_ssa_p (gimple_assign_rhs3 (ass));
-		    }
-		  else
-		    continue;
-		  for (unsigned j = 0; j < 3; ++j)
+		  unsigned lim = gimple_range_ssa_names (ssa, 3, def_stmt);
+		  for (unsigned j = 0; j < lim; ++j)
 		    {
 		      tree rhs = ssa[j];
 		      if (rhs
-			  && TREE_CODE (rhs) == SSA_NAME
 			  && bitmap_set_bit (m_imports,
 					     SSA_NAME_VERSION (rhs)))
 			{
-- 
2.37.3


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 02/17] Adjust range_op_handler to store the handler directly.
  2022-09-22 18:49 [PATCH 00/17] Move builtin functions to range-ops Andrew MacLeod
  2022-09-22 18:53 ` [PATCH 01/17] Replace another snippet with a call to, gimple_range_ssa_names Andrew MacLeod
@ 2022-09-22 18:55 ` Andrew MacLeod
  2022-09-22 18:56 ` [PATCH 03/17] Create gimple_range_op_handler in a new source file Andrew MacLeod
                   ` (14 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Andrew MacLeod @ 2022-09-22 18:55 UTC (permalink / raw)
  To: gcc-patches; +Cc: hernandez, aldy

[-- Attachment #1: Type: text/plain, Size: 297 bytes --]

Range_op_handler currently stores a tree code and a type.  It defers 
checking to see if there is a valid handler until asked.

This change checks at constructor time and store a pointer to the 
handler if there is one.

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

Andrew

[-- Attachment #2: 0002-Adjust-range_op_handler-to-store-the-handler-directl.patch --]
[-- Type: text/x-patch, Size: 11445 bytes --]

From 24c473a14d3cbe6fc44997122b532cb9406497cb Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Wed, 31 Aug 2022 14:07:13 -0400
Subject: [PATCH 02/17] Adjust range_op_handler to store the handler directly.

Range_op_handler currently stores a tree code and a type.  It defers
checking to see if there is a valid handler until asked.
This change checks at constuctor time and store a pointer to
the handler if there is one.

	* range-op.cc (range_op_handler::set_op_handler): Set new fields.
	(ange_op_handler::range_op_handler): Likewise.
	(range_op_handler::operator bool): Remove.
	(range_op_handler::fold_range): Use appropriate handler.
	(range_op_handler::op1_range): Likewise.
	(range_op_handler::op2_range): Likewise.
	(range_op_handler::lhs_op1_relation): Likewise.
	(range_op_handler::lhs_op2_relation): Likewise.
	(range_op_handler::op1_op2_relation): Likewise.
	* range-op.h (class range_op_handler): Store handler pointers.
	(range_op_handler:: operator bool): Inline.
---
 gcc/range-op.cc | 246 +++++++++++++++++++++---------------------------
 gcc/range-op.h  |   8 +-
 2 files changed, 114 insertions(+), 140 deletions(-)

diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 806edf1012e..f642b3f26de 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -4159,48 +4159,63 @@ get_float_handler (enum tree_code code, tree)
   return (*floating_tree_table)[code];
 }
 
+void
+range_op_handler::set_op_handler (tree_code code, tree type)
+{
+  if (irange::supports_p (type))
+    {
+      m_float = NULL;
+      m_int = get_handler (code, type);
+      m_valid = m_int != NULL;
+    }
+  else if (frange::supports_p (type))
+    {
+      m_int = NULL;
+      m_float = get_float_handler (code, type);
+      m_valid = m_float != NULL;
+    }
+  else
+    {
+      m_int = NULL;
+      m_float = NULL;
+      m_valid = false;
+    }
+}
+
 range_op_handler::range_op_handler (tree_code code, tree type)
-  : m_code (code), m_type (type)
 {
+  set_op_handler (code, type);
 }
 
 range_op_handler::range_op_handler (const gimple *s)
 {
+  tree_code code = NOP_EXPR;
+  tree type = NULL_TREE;
+
   if (const gassign *ass = dyn_cast<const gassign *> (s))
     {
-      m_code = gimple_assign_rhs_code (ass);
+      code = gimple_assign_rhs_code (ass);
       // The LHS of a comparison is always an int, so we must look at
       // the operands.
-      if (TREE_CODE_CLASS (m_code) == tcc_comparison)
-	m_type = TREE_TYPE (gimple_assign_rhs1 (ass));
+      if (TREE_CODE_CLASS (code) == tcc_comparison)
+	type = TREE_TYPE (gimple_assign_rhs1 (ass));
       else
-	m_type = TREE_TYPE (gimple_assign_lhs (ass));
+	type = TREE_TYPE (gimple_assign_lhs (ass));
     }
   else if (const gcond *cond = dyn_cast<const gcond *> (s))
     {
-      m_code = gimple_cond_code (cond);
-      m_type = TREE_TYPE (gimple_cond_lhs (cond));
+      code = gimple_cond_code (cond);
+      type = TREE_TYPE (gimple_cond_lhs (cond));
     }
-  else
+
+  if (!type)
     {
-      // A null type means there is no handler for this combination,
-      // but the decision whether there is one or not, is delayed
-      // until operator bool below is queried.
-      m_code = NOP_EXPR;
-      m_type = nullptr;
+      m_int = NULL;
+      m_float = NULL;
+      m_valid = false;
     }
-}
-
-// Return TRUE if there is a handler available for the current
-// combination of tree_code and type.
-
-range_op_handler::operator bool () const
-{
-  if (!m_type)
-    return false;
-  if (frange::supports_p (m_type))
-    return get_float_handler (m_code, m_type);
-  return get_handler (m_code, m_type);
+  else
+    set_op_handler (code, type);
 }
 
 bool
@@ -4209,26 +4224,19 @@ range_op_handler::fold_range (vrange &r, tree type,
 			      const vrange &rh,
 			      relation_kind rel) const
 {
-  if (irange::supports_p (m_type))
-    {
-      range_operator *op = get_handler (m_code, m_type);
-      return op->fold_range (as_a <irange> (r), type,
-			     as_a <irange> (lh),
-			     as_a <irange> (rh), rel);
-    }
-  if (frange::supports_p (m_type))
-    {
-      range_operator_float *op = get_float_handler (m_code, m_type);
-      if (is_a <irange> (r))
-	return op->fold_range (as_a <irange> (r), type,
-			       as_a <frange> (lh),
-			       as_a <frange> (rh), rel);
-      return op->fold_range (as_a <frange> (r), type,
-			     as_a <frange> (lh),
-			     as_a <frange> (rh), rel);
-    }
-  gcc_unreachable ();
-  return false;
+  gcc_checking_assert (m_valid);
+  if (m_int)
+    return m_int->fold_range (as_a <irange> (r), type,
+			   as_a <irange> (lh),
+			   as_a <irange> (rh), rel);
+
+  if (is_a <irange> (r))
+    return m_float->fold_range (as_a <irange> (r), type,
+				as_a <frange> (lh),
+				as_a <frange> (rh), rel);
+  return m_float->fold_range (as_a <frange> (r), type,
+			      as_a <frange> (lh),
+			      as_a <frange> (rh), rel);
 }
 
 bool
@@ -4237,26 +4245,19 @@ range_op_handler::op1_range (vrange &r, tree type,
 			     const vrange &op2,
 			     relation_kind rel) const
 {
-  if (irange::supports_p (m_type))
-    {
-      range_operator *op = get_handler (m_code, m_type);
-      return op->op1_range (as_a <irange> (r), type,
-			    as_a <irange> (lhs),
-			    as_a <irange> (op2), rel);
-    }
-  if (frange::supports_p (m_type))
-    {
-      range_operator_float *op = get_float_handler (m_code, m_type);
-      if (is_a <irange> (lhs))
-	return op->op1_range (as_a <frange> (r), type,
-			      as_a <irange> (lhs),
-			      as_a <frange> (op2), rel);
-      return op->op1_range (as_a <frange> (r), type,
-			    as_a <frange> (lhs),
-			    as_a <frange> (op2), rel);
-    }
-  gcc_unreachable ();
-  return false;
+  gcc_checking_assert (m_valid);
+  if (m_int)
+    return m_int->op1_range (as_a <irange> (r), type,
+			     as_a <irange> (lhs),
+			     as_a <irange> (op2), rel);
+
+  if (is_a <irange> (lhs))
+    return m_float->op1_range (as_a <frange> (r), type,
+			       as_a <irange> (lhs),
+			       as_a <frange> (op2), rel);
+  return m_float->op1_range (as_a <frange> (r), type,
+			     as_a <frange> (lhs),
+			     as_a <frange> (op2), rel);
 }
 
 bool
@@ -4265,26 +4266,19 @@ range_op_handler::op2_range (vrange &r, tree type,
 			     const vrange &op1,
 			     relation_kind rel) const
 {
-  if (irange::supports_p (m_type))
-    {
-      range_operator *op = get_handler (m_code, m_type);
-      return op->op2_range (as_a <irange> (r), type,
-			    as_a <irange> (lhs),
-			    as_a <irange> (op1), rel);
-    }
-  if (frange::supports_p (m_type))
-    {
-      range_operator_float *op = get_float_handler (m_code, m_type);
-      if (is_a <irange> (lhs))
-	return op->op2_range (as_a <frange> (r), type,
-			      as_a <irange> (lhs),
-			      as_a <frange> (op1), rel);
-      return op->op2_range (as_a <frange> (r), type,
-			    as_a <frange> (lhs),
-			    as_a <frange> (op1), rel);
-    }
-  gcc_unreachable ();
-  return false;
+  gcc_checking_assert (m_valid);
+  if (m_int)
+    return m_int->op2_range (as_a <irange> (r), type,
+			     as_a <irange> (lhs),
+			     as_a <irange> (op1), rel);
+
+  if (is_a <irange> (lhs))
+    return m_float->op2_range (as_a <frange> (r), type,
+			       as_a <irange> (lhs),
+			       as_a <frange> (op1), rel);
+  return m_float->op2_range (as_a <frange> (r), type,
+			     as_a <frange> (lhs),
+			     as_a <frange> (op1), rel);
 }
 
 relation_kind
@@ -4293,26 +4287,19 @@ range_op_handler::lhs_op1_relation (const vrange &lhs,
 				    const vrange &op2,
 				    relation_kind rel) const
 {
-  if (irange::supports_p (m_type))
-    {
-      range_operator *op = get_handler (m_code, m_type);
-      return op->lhs_op1_relation (as_a <irange> (lhs),
-				   as_a <irange> (op1),
-				   as_a <irange> (op2), rel);
-    }
-  if (frange::supports_p (m_type))
-    {
-      range_operator_float *op = get_float_handler (m_code, m_type);
-      if (is_a <irange> (lhs))
-	return op->lhs_op1_relation (as_a <irange> (lhs),
-				     as_a <frange> (op1),
-				     as_a <frange> (op2), rel);
-      return op->lhs_op1_relation (as_a <frange> (lhs),
-				   as_a <frange> (op1),
-				   as_a <frange> (op2), rel);
-    }
-  gcc_unreachable ();
-  return VREL_VARYING;
+  gcc_checking_assert (m_valid);
+  if (m_int)
+    return m_int->lhs_op1_relation (as_a <irange> (lhs),
+				    as_a <irange> (op1),
+				    as_a <irange> (op2), rel);
+
+  if (is_a <irange> (lhs))
+    return m_float->lhs_op1_relation (as_a <irange> (lhs),
+				 as_a <frange> (op1),
+				 as_a <frange> (op2), rel);
+  return m_float->lhs_op1_relation (as_a <frange> (lhs),
+			       as_a <frange> (op1),
+			       as_a <frange> (op2), rel);
 }
 
 relation_kind
@@ -4321,43 +4308,28 @@ range_op_handler::lhs_op2_relation (const vrange &lhs,
 				    const vrange &op2,
 				    relation_kind rel) const
 {
-  if (irange::supports_p (m_type))
-    {
-      range_operator *op = get_handler (m_code, m_type);
-      return op->lhs_op2_relation (as_a <irange> (lhs),
-				   as_a <irange> (op1),
-				   as_a <irange> (op2), rel);
-    }
-  if (frange::supports_p (m_type))
-    {
-      range_operator_float *op = get_float_handler (m_code, m_type);
-      if (is_a <irange> (lhs))
-	return op->lhs_op2_relation (as_a <irange> (lhs),
-				     as_a <frange> (op1),
-				     as_a <frange> (op2), rel);
-      return op->lhs_op2_relation (as_a <frange> (lhs),
-				   as_a <frange> (op1),
-				   as_a <frange> (op2), rel);
-    }
-  gcc_unreachable ();
-  return VREL_VARYING;
+  gcc_checking_assert (m_valid);
+  if (m_int)
+    return m_int->lhs_op2_relation (as_a <irange> (lhs),
+				    as_a <irange> (op1),
+				    as_a <irange> (op2), rel);
+
+  if (is_a <irange> (lhs))
+    return m_float->lhs_op2_relation (as_a <irange> (lhs),
+				      as_a <frange> (op1),
+				      as_a <frange> (op2), rel);
+  return m_float->lhs_op2_relation (as_a <frange> (lhs),
+				      as_a <frange> (op1),
+				      as_a <frange> (op2), rel);
 }
 
 relation_kind
 range_op_handler::op1_op2_relation (const vrange &lhs) const
 {
-  if (irange::supports_p (m_type))
-    {
-      range_operator *op = get_handler (m_code, m_type);
-      return op->op1_op2_relation (as_a <irange> (lhs));
-    }
-  if (frange::supports_p (m_type))
-    {
-      range_operator_float *op = get_float_handler (m_code, m_type);
-      return op->op1_op2_relation (as_a <irange> (lhs));
-    }
-  gcc_unreachable ();
-  return VREL_VARYING;
+  gcc_checking_assert (m_valid);
+  if (m_int)
+    return m_int->op1_op2_relation (as_a <irange> (lhs));
+  return m_float->op1_op2_relation (as_a <irange> (lhs));
 }
 
 // Cast the range in R to TYPE.
diff --git a/gcc/range-op.h b/gcc/range-op.h
index 37d9aa91c46..56c57c46a8e 100644
--- a/gcc/range-op.h
+++ b/gcc/range-op.h
@@ -162,7 +162,7 @@ class range_op_handler
 public:
   range_op_handler (enum tree_code code, tree type);
   range_op_handler (const gimple *s);
-  operator bool () const;
+  inline operator bool () const { return m_valid; }
 
   bool fold_range (vrange &r, tree type,
 		   const vrange &lh,
@@ -186,8 +186,10 @@ public:
 				  relation_kind = VREL_VARYING) const;
   relation_kind op1_op2_relation (const vrange &lhs) const;
 private:
-  enum tree_code m_code;
-  tree m_type;
+  void set_op_handler (enum tree_code code, tree type);
+  bool m_valid;
+  range_operator *m_int;
+  range_operator_float *m_float;
 };
 
 extern bool range_cast (vrange &, tree type);
-- 
2.37.3


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 03/17] Create gimple_range_op_handler in a new source file.
  2022-09-22 18:49 [PATCH 00/17] Move builtin functions to range-ops Andrew MacLeod
  2022-09-22 18:53 ` [PATCH 01/17] Replace another snippet with a call to, gimple_range_ssa_names Andrew MacLeod
  2022-09-22 18:55 ` [PATCH 02/17] Adjust range_op_handler to store the handler directly Andrew MacLeod
@ 2022-09-22 18:56 ` Andrew MacLeod
  2022-09-22 18:58 ` [PATCH 04/17] Fix calc_op1 for undefined op2_range Andrew MacLeod
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Andrew MacLeod @ 2022-09-22 18:56 UTC (permalink / raw)
  To: gcc-patches; +Cc: hernandez, aldy

[-- Attachment #1: Type: text/plain, Size: 286 bytes --]

  Range-ops is meant to be IL independent.  Some gimple processing has 
be placed in range-ops, and some is located in gori.  Split it all into 
a file and isolate it in a new class gimple_range_op_handler.

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

Andrew

[-- Attachment #2: 0003-Create-gimple_range_op_handler-in-a-new-source-file.patch --]
[-- Type: text/x-patch, Size: 39151 bytes --]

From 51ce06385bf259a092f830f1a6dcc4b98757919e Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Thu, 1 Sep 2022 10:34:55 -0400
Subject: [PATCH 03/17] Create gimple_range_op_handler in a new source file.

Range-ops is meant to be IL independent.  Some gimple processing has
be placed in range-ops, and some is located in gori.  Split it all into
a file and isolate it in a new class gimple_range_op_handler.

	* Makefile.in (OBJS): Add gimple-range-op.o.
	* gimple-range-edge.cc (gimple_outgoing_range_stmt_p): Use
	gimple_range_op_handler.
	* gimple-range-fold.cc (gimple_range_base_of_assignment): Move
	to a method in gimple_range_op_handler.
	(gimple_range_operand1): Ditto.
	(gimple_range_operand2): Ditto.
	(fold_using_range::fold_stmt): Use gimple_range_op_handler.
	(fold_using_range::range_of_range_op): Ditto.
	(fold_using_range::relation_fold_and_or): Ditto.
	(fur_source::register_outgoing_edges): Ditto.
	(gimple_range_ssa_names): Relocate to gimple-range-op.cc.
	* gimple-range-fold.h: Adjust prototypes.
	* gimple-range-gori.cc (gimple_range_calc_op1): Move
	to a method in gimple_range_op_handler.
	(gimple_range_calc_op2): Ditto.
	(gori_compute::compute_operand_range): Use
	gimple_range_op_handler.
	(gori_compute::compute_logical_operands): Ditto.
	(compute_operand1_range): Ditto.
	(gori_compute::compute_operand2_range): Ditto.
	(gori_compute::compute_operand1_and_operand2_range): Ditto.
	* gimple-range-gori.h: Adjust protoypes.
	* gimple-range-op.cc: New.  Supply gimple_range_op_handler methods.
	* gimple-range-op.h: New.  Supply gimple_range_op_handler class.
	* gimple-range.cc (gimple_ranger::prefill_name): Use
	gimple_range_op_handler.
	(gimple_ranger::prefill_stmt_dependencies): Ditto.
	* gimple-range.h: Include gimple-range-op.h.
	* range-op.cc (range_op_handler::range_op_handler): Adjust and
	remove gimple * parameter option.
	* range-op.h: Adjust prototypes.
---
 gcc/Makefile.in          |   1 +
 gcc/gimple-range-edge.cc |   2 +-
 gcc/gimple-range-fold.cc | 153 +++++-------------------
 gcc/gimple-range-fold.h  |  12 +-
 gcc/gimple-range-gori.cc | 134 ++++++---------------
 gcc/gimple-range-gori.h  |  27 ++---
 gcc/gimple-range-op.cc   | 245 +++++++++++++++++++++++++++++++++++++++
 gcc/gimple-range-op.h    |  51 ++++++++
 gcc/gimple-range.cc      |  11 +-
 gcc/gimple-range.h       |   2 +-
 gcc/range-op.cc          |  37 ++----
 gcc/range-op.h           |   4 +-
 12 files changed, 386 insertions(+), 293 deletions(-)
 create mode 100644 gcc/gimple-range-op.cc
 create mode 100644 gcc/gimple-range-op.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index a4689d52e36..59b67d99441 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1416,6 +1416,7 @@ OBJS = \
 	gimple-range-fold.o \
 	gimple-range-gori.o \
 	gimple-range-infer.o \
+	gimple-range-op.o \
 	gimple-range-trace.o \
 	gimple-ssa-backprop.o \
 	gimple-ssa-isolate-paths.o \
diff --git a/gcc/gimple-range-edge.cc b/gcc/gimple-range-edge.cc
index 194e8f87a4b..95deadffc55 100644
--- a/gcc/gimple-range-edge.cc
+++ b/gcc/gimple-range-edge.cc
@@ -43,7 +43,7 @@ gimple_outgoing_range_stmt_p (basic_block bb)
   if (!gsi_end_p (gsi))
     {
       gimple *s = gsi_stmt (gsi);
-      if (is_a<gcond *> (s) && range_op_handler (s))
+      if (is_a<gcond *> (s) && gimple_range_op_handler::supported_p (s))
 	return gsi_stmt (gsi);
       if (is_a <gswitch *> (s))
 	return gsi_stmt (gsi);
diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index a45fc7ad4c6..addf3e7f254 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -42,7 +42,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "vr-values.h"
 #include "range.h"
 #include "value-query.h"
-#include "range-op.h"
+#include "gimple-range-op.h"
 #include "gimple-range.h"
 // Construct a fur_source, and set the m_query field.
 
@@ -463,73 +463,6 @@ gimple_range_adjustment (vrange &res, const gimple *stmt)
     }
 }
 
-// Return the base of the RHS of an assignment.
-
-static tree
-gimple_range_base_of_assignment (const gimple *stmt)
-{
-  gcc_checking_assert (gimple_code (stmt) == GIMPLE_ASSIGN);
-  tree op1 = gimple_assign_rhs1 (stmt);
-  if (gimple_assign_rhs_code (stmt) == ADDR_EXPR)
-    return get_base_address (TREE_OPERAND (op1, 0));
-  return op1;
-}
-
-// Return the first operand of this statement if it is a valid operand
-// supported by ranges, otherwise return NULL_TREE.  Special case is
-// &(SSA_NAME expr), return the SSA_NAME instead of the ADDR expr.
-
-tree
-gimple_range_operand1 (const gimple *stmt)
-{
-  gcc_checking_assert (range_op_handler (stmt));
-
-  switch (gimple_code (stmt))
-    {
-      case GIMPLE_COND:
-	return gimple_cond_lhs (stmt);
-      case GIMPLE_ASSIGN:
-	{
-	  tree base = gimple_range_base_of_assignment (stmt);
-	  if (base && TREE_CODE (base) == MEM_REF)
-	    {
-	      // If the base address is an SSA_NAME, we return it
-	      // here.  This allows processing of the range of that
-	      // name, while the rest of the expression is simply
-	      // ignored.  The code in range_ops will see the
-	      // ADDR_EXPR and do the right thing.
-	      tree ssa = TREE_OPERAND (base, 0);
-	      if (TREE_CODE (ssa) == SSA_NAME)
-		return ssa;
-	    }
-	  return base;
-	}
-      default:
-	break;
-    }
-  return NULL;
-}
-
-// Return the second operand of statement STMT, otherwise return NULL_TREE.
-
-tree
-gimple_range_operand2 (const gimple *stmt)
-{
-  gcc_checking_assert (range_op_handler (stmt));
-
-  switch (gimple_code (stmt))
-    {
-    case GIMPLE_COND:
-      return gimple_cond_rhs (stmt);
-    case GIMPLE_ASSIGN:
-      if (gimple_num_ops (stmt) >= 3)
-	return gimple_assign_rhs2 (stmt);
-    default:
-      break;
-    }
-  return NULL_TREE;
-}
-
 // Calculate a range for statement S and return it in R. If NAME is provided it
 // represents the SSA_NAME on the LHS of the statement. It is only required
 // if there is more than one lhs/output.  If a range cannot
@@ -551,8 +484,9 @@ fold_using_range::fold_stmt (vrange &r, gimple *s, fur_source &src, tree name)
       && gimple_assign_rhs_code (s) == ADDR_EXPR)
     return range_of_address (as_a <irange> (r), s, src);
 
-  if (range_op_handler (s))
-    res = range_of_range_op (r, s, src);
+  gimple_range_op_handler handler (s);
+  if (handler)
+    res = range_of_range_op (r, handler, src);
   else if (is_a<gphi *>(s))
     res = range_of_phi (r, as_a<gphi *> (s), src);
   else if (is_a<gcall *>(s))
@@ -587,17 +521,19 @@ fold_using_range::fold_stmt (vrange &r, gimple *s, fur_source &src, tree name)
 // If a range cannot be calculated, return false.
 
 bool
-fold_using_range::range_of_range_op (vrange &r, gimple *s, fur_source &src)
+fold_using_range::range_of_range_op (vrange &r,
+				     gimple_range_op_handler &handler,
+				     fur_source &src)
 {
+  gcc_checking_assert (handler);
+  gimple *s = handler.stmt ();
   tree type = gimple_range_type (s);
   if (!type)
     return false;
-  range_op_handler handler (s);
-  gcc_checking_assert (handler);
 
-  tree lhs = gimple_get_lhs (s);
-  tree op1 = gimple_range_operand1 (s);
-  tree op2 = gimple_range_operand2 (s);
+  tree lhs = handler.lhs ();
+  tree op1 = handler.operand1 ();
+  tree op2 = handler.operand2 ();
   Value_Range range1 (TREE_TYPE (op1));
   Value_Range range2 (op2 ? TREE_TYPE (op2) : TREE_TYPE (op1));
 
@@ -1430,9 +1366,10 @@ fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s,
   else if (code != BIT_IOR_EXPR && code != TRUTH_OR_EXPR)
     return;
 
-  tree lhs = gimple_get_lhs (s);
-  tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (s));
-  tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (s));
+  gimple_range_op_handler handler (s);
+  tree lhs = handler.lhs ();
+  tree ssa1 = gimple_range_ssa_p (handler.operand1 ());
+  tree ssa2 = gimple_range_ssa_p (handler.operand2 ());
 
   // Deal with || and && only when there is a full set of symbolics.
   if (!lhs || !ssa1 || !ssa2
@@ -1448,18 +1385,18 @@ fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s,
   gimple *ssa1_stmt = SSA_NAME_DEF_STMT (ssa1);
   gimple *ssa2_stmt = SSA_NAME_DEF_STMT (ssa2);
 
-  range_op_handler handler1 (SSA_NAME_DEF_STMT (ssa1));
-  range_op_handler handler2 (SSA_NAME_DEF_STMT (ssa2));
+  gimple_range_op_handler handler1 (ssa1_stmt);
+  gimple_range_op_handler handler2 (ssa2_stmt);
 
   // If either handler is not present, no relation can be found.
   if (!handler1 || !handler2)
     return;
 
   // Both stmts will need to have 2 ssa names in the stmt.
-  tree ssa1_dep1 = gimple_range_ssa_p (gimple_range_operand1 (ssa1_stmt));
-  tree ssa1_dep2 = gimple_range_ssa_p (gimple_range_operand2 (ssa1_stmt));
-  tree ssa2_dep1 = gimple_range_ssa_p (gimple_range_operand1 (ssa2_stmt));
-  tree ssa2_dep2 = gimple_range_ssa_p (gimple_range_operand2 (ssa2_stmt));
+  tree ssa1_dep1 = gimple_range_ssa_p (handler1.operand1 ());
+  tree ssa1_dep2 = gimple_range_ssa_p (handler1.operand2 ());
+  tree ssa2_dep1 = gimple_range_ssa_p (handler2.operand1 ());
+  tree ssa2_dep2 = gimple_range_ssa_p (handler2.operand2 ());
 
   if (!ssa1_dep1 || !ssa1_dep2 || !ssa2_dep1 || !ssa2_dep2)
     return;
@@ -1516,7 +1453,7 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
   tree name;
   basic_block bb = gimple_bb (s);
 
-  range_op_handler handler (s);
+  gimple_range_op_handler handler (s);
   if (!handler)
     return;
 
@@ -1529,7 +1466,6 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
 	e0 = NULL;
     }
 
-
   if (e1)
     {
       // If this edge is never taken, ignore it.
@@ -1544,8 +1480,8 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
 
   // First, register the gcond itself.  This will catch statements like
   // if (a_2 < b_5)
-  tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (s));
-  tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (s));
+  tree ssa1 = gimple_range_ssa_p (handler.operand1 ());
+  tree ssa2 = gimple_range_ssa_p (handler.operand2 ());
   if (ssa1 && ssa2)
     {
       if (e0)
@@ -1575,11 +1511,11 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
       if (TREE_CODE (TREE_TYPE (name)) != BOOLEAN_TYPE)
 	continue;
       gimple *stmt = SSA_NAME_DEF_STMT (name);
-      range_op_handler handler (stmt);
+      gimple_range_op_handler handler (stmt);
       if (!handler)
 	continue;
-      tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (stmt));
-      tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (stmt));
+      tree ssa1 = gimple_range_ssa_p (handler.operand1 ());
+      tree ssa2 = gimple_range_ssa_p (handler.operand2 ());
       Value_Range r (TREE_TYPE (name));
       if (ssa1 && ssa2)
 	{
@@ -1600,36 +1536,3 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
 	}
     }
 }
-
-// Given stmt S, fill VEC, up to VEC_SIZE elements, with relevant ssa-names
-// on the statement.  For efficiency, it is an error to not pass in enough
-// elements for the vector.  Return the number of ssa-names.
-
-unsigned
-gimple_range_ssa_names (tree *vec, unsigned vec_size, gimple *stmt)
-{
-  tree ssa;
-  int count = 0;
-
-  if (range_op_handler (stmt))
-    {
-      gcc_checking_assert (vec_size >= 2);
-      if ((ssa = gimple_range_ssa_p (gimple_range_operand1 (stmt))))
-	vec[count++] = ssa;
-      if ((ssa = gimple_range_ssa_p (gimple_range_operand2 (stmt))))
-	vec[count++] = ssa;
-    }
-  else if (is_a<gassign *> (stmt)
-	   && gimple_assign_rhs_code (stmt) == COND_EXPR)
-    {
-      gcc_checking_assert (vec_size >= 3);
-      gassign *st = as_a<gassign *> (stmt);
-      if ((ssa = gimple_range_ssa_p (gimple_assign_rhs1 (st))))
-	vec[count++] = ssa;
-      if ((ssa = gimple_range_ssa_p (gimple_assign_rhs2 (st))))
-	vec[count++] = ssa;
-      if ((ssa = gimple_range_ssa_p (gimple_assign_rhs3 (st))))
-	vec[count++] = ssa;
-    }
-  return count;
-}
diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h
index f2eab720213..ce18c66b8e7 100644
--- a/gcc/gimple-range-fold.h
+++ b/gcc/gimple-range-fold.h
@@ -96,15 +96,6 @@ range_compatible_p (tree type1, tree type2)
 	  && TYPE_SIGN (type1) == TYPE_SIGN (type2));
 }
 
-extern tree gimple_range_operand1 (const gimple *s);
-extern tree gimple_range_operand2 (const gimple *s);
-
-// Given stmt S, fill VEC, up to VEC_SIZE elements, with relevant ssa-names
-// on the statement.  For efficiency, it is an error to not pass in enough
-// elements for the vector.  Return the number of ssa-names.
-
-unsigned gimple_range_ssa_names (tree *vec, unsigned vec_size, gimple *stmt);
-
 // 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.
@@ -169,7 +160,8 @@ public:
   bool fold_stmt (vrange &r, gimple *s, class fur_source &src,
 		  tree name = NULL_TREE);
 protected:
-  bool range_of_range_op (vrange &r, gimple *s, fur_source &src);
+  bool range_of_range_op (vrange &r, gimple_range_op_handler &handler,
+			  fur_source &src);
   bool range_of_call (vrange &r, gcall *call, fur_source &src);
   bool range_of_cond_expr (vrange &r, gassign* cond, fur_source &src);
   bool range_of_address (irange &r, gimple *s, fur_source &src);
diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc
index 957b8d543fa..40b2f2f6ae9 100644
--- a/gcc/gimple-range-gori.cc
+++ b/gcc/gimple-range-gori.cc
@@ -29,83 +29,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-pretty-print.h"
 #include "gimple-range.h"
 
-// Calculate what we can determine of the range of this unary
-// statement's operand if the lhs of the expression has the range
-// LHS_RANGE.  Return false if nothing can be determined.
-
-bool
-gimple_range_calc_op1 (vrange &r, const gimple *stmt, const vrange &lhs_range)
-{
-  gcc_checking_assert (gimple_num_ops (stmt) < 3);
-  // Give up on empty ranges.
-  if (lhs_range.undefined_p ())
-    return false;
-
-  // Unary operations require the type of the first operand in the
-  // second range position.
-  tree type = TREE_TYPE (gimple_range_operand1 (stmt));
-  Value_Range type_range (type);
-  type_range.set_varying (type);
-  return range_op_handler (stmt).op1_range (r, type, lhs_range, type_range);
-}
-
-// Calculate what we can determine of the range of this statement's
-// first operand if the lhs of the expression has the range LHS_RANGE
-// and the second operand has the range OP2_RANGE.  Return false if
-// nothing can be determined.
-
-bool
-gimple_range_calc_op1 (vrange &r, const gimple *stmt,
-		       const vrange &lhs_range, const vrange &op2_range)
-{
-  // Give up on empty ranges.
-  if (lhs_range.undefined_p ())
-    return false;
-
-  // Unary operation are allowed to pass a range in for second operand
-  // as there are often additional restrictions beyond the type which
-  // can be imposed.  See operator_cast::op1_range().
-  tree type = TREE_TYPE (gimple_range_operand1 (stmt));
-  // If op2 is undefined, solve as if it is varying.
-  if (op2_range.undefined_p ())
-    {
-      // This is sometimes invoked on single operand stmts.
-      if (gimple_num_ops (stmt) < 3)
-	return false;
-      tree op2_type = TREE_TYPE (gimple_range_operand2 (stmt));
-      Value_Range trange (op2_type);
-      trange.set_varying (op2_type);
-      return range_op_handler (stmt).op1_range (r, type, lhs_range, trange);
-    }
-  return range_op_handler (stmt).op1_range (r, type, lhs_range, op2_range);
-}
-
-// Calculate what we can determine of the range of this statement's
-// second operand if the lhs of the expression has the range LHS_RANGE
-// and the first operand has the range OP1_RANGE.  Return false if
-// nothing can be determined.
-
-bool
-gimple_range_calc_op2 (vrange &r, const gimple *stmt,
-		       const vrange &lhs_range, const vrange &op1_range)
-{
-  // Give up on empty ranges.
-  if (lhs_range.undefined_p ())
-    return false;
-
-  tree type = TREE_TYPE (gimple_range_operand2 (stmt));
-  // If op1 is undefined, solve as if it is varying.
-  if (op1_range.undefined_p ())
-    {
-      tree op1_type = TREE_TYPE (gimple_range_operand1 (stmt));
-      Value_Range trange (op1_type);
-      trange.set_varying (op1_type);
-      return range_op_handler (stmt).op2_range (r, type, lhs_range, trange);
-    }
-  return range_op_handler (stmt).op2_range (r, type, lhs_range,
-					    op1_range);
-}
-
 // Return TRUE if GS is a logical && or || expression.
 
 static inline bool
@@ -695,17 +618,18 @@ gori_compute::compute_operand_range (vrange &r, gimple *stmt,
   if (is_a<gswitch *> (stmt))
     return compute_operand_range_switch (r, as_a<gswitch *> (stmt), lhs, name,
 					 src);
-  if (!range_op_handler (stmt))
+  gimple_range_op_handler handler (stmt);
+  if (!handler)
     return false;
 
-  tree op1 = gimple_range_ssa_p (gimple_range_operand1 (stmt));
-  tree op2 = gimple_range_ssa_p (gimple_range_operand2 (stmt));
+  tree op1 = gimple_range_ssa_p (handler.operand1 ());
+  tree op2 = gimple_range_ssa_p (handler.operand2 ());
 
   // Handle end of lookup first.
   if (op1 == name)
-    return compute_operand1_range (r, stmt, lhs, name, src);
+    return compute_operand1_range (r, handler, lhs, name, src);
   if (op2 == name)
-    return compute_operand2_range (r, stmt, lhs, name, src);
+    return compute_operand2_range (r, handler, lhs, name, src);
 
   // NAME is not in this stmt, but one of the names in it ought to be
   // derived from it.
@@ -733,10 +657,10 @@ gori_compute::compute_operand_range (vrange &r, gimple *stmt,
       tree type = TREE_TYPE (name);
       Value_Range op1_trange (type), op1_frange (type);
       Value_Range op2_trange (type), op2_frange (type);
-      compute_logical_operands (op1_trange, op1_frange, stmt,
+      compute_logical_operands (op1_trange, op1_frange, handler,
 				as_a <irange> (lhs),
 				name, src, op1, op1_in_chain);
-      compute_logical_operands (op2_trange, op2_frange, stmt,
+      compute_logical_operands (op2_trange, op2_frange, handler,
 				as_a <irange> (lhs),
 				name, src, op2, op2_in_chain);
       res = logical_combine (r,
@@ -748,11 +672,11 @@ gori_compute::compute_operand_range (vrange &r, gimple *stmt,
     }
   // Follow the appropriate operands now.
   else if (op1_in_chain && op2_in_chain)
-    res = compute_operand1_and_operand2_range (r, stmt, lhs, name, src);
+    res = compute_operand1_and_operand2_range (r, handler, lhs, name, src);
   else if (op1_in_chain)
-    res = compute_operand1_range (r, stmt, lhs, name, src);
+    res = compute_operand1_range (r, handler, lhs, name, src);
   else if (op2_in_chain)
-    res = compute_operand2_range (r, stmt, lhs, name, src);
+    res = compute_operand2_range (r, handler, lhs, name, src);
   else
     gcc_unreachable ();
 
@@ -944,13 +868,14 @@ gori_compute::logical_combine (vrange &r, enum tree_code code,
 
 void
 gori_compute::compute_logical_operands (vrange &true_range, vrange &false_range,
-					gimple *stmt,
+					gimple_range_op_handler &handler,
 					const irange &lhs,
 					tree name, fur_source &src,
 					tree op, bool op_in_chain)
 {
+  gimple *stmt = handler.stmt ();
   gimple *src_stmt = gimple_range_ssa_p (op) ? SSA_NAME_DEF_STMT (op) : NULL;
-  if (!op_in_chain || !src_stmt || chain_import_p (gimple_get_lhs (stmt), op))
+  if (!op_in_chain || !src_stmt || chain_import_p (handler.lhs (), op))
     {
       // If op is not in the def chain, or defined in this block,
       // use its known value on entry to the block.
@@ -999,12 +924,15 @@ gori_compute::compute_logical_operands (vrange &true_range, vrange &false_range,
 // R, or false if no range could be calculated.
 
 bool
-gori_compute::compute_operand1_range (vrange &r, gimple *stmt,
+gori_compute::compute_operand1_range (vrange &r,
+				      gimple_range_op_handler &handler,
 				      const vrange &lhs, tree name,
 				      fur_source &src)
 {
-  tree op1 = gimple_range_operand1 (stmt);
-  tree op2 = gimple_range_operand2 (stmt);
+  gimple *stmt = handler.stmt ();
+  tree op1 = handler.operand1 ();
+  tree op2 = handler.operand2 ();
+
   Value_Range op1_range (TREE_TYPE (op1));
   Value_Range tmp (TREE_TYPE (op1));
   Value_Range op2_range (op2 ? TREE_TYPE (op2) : TREE_TYPE (op1));
@@ -1016,7 +944,7 @@ gori_compute::compute_operand1_range (vrange &r, gimple *stmt,
   if (op2)
     {
       src.get_operand (op2_range, op2);
-      if (!gimple_range_calc_op1 (tmp, stmt, lhs, op2_range))
+      if (!handler.calc_op1 (tmp, lhs, op2_range))
 	return false;
     }
   else
@@ -1024,7 +952,7 @@ gori_compute::compute_operand1_range (vrange &r, gimple *stmt,
       // We pass op1_range to the unary operation.  Nomally it's a
       // hidden range_for_type parameter, but sometimes having the
       // actual range can result in better information.
-      if (!gimple_range_calc_op1 (tmp, stmt, lhs, op1_range))
+      if (!handler.calc_op1 (tmp, lhs, op1_range))
 	return false;
     }
 
@@ -1079,12 +1007,15 @@ gori_compute::compute_operand1_range (vrange &r, gimple *stmt,
 // R, or false if no range could be calculated.
 
 bool
-gori_compute::compute_operand2_range (vrange &r, gimple *stmt,
+gori_compute::compute_operand2_range (vrange &r,
+				      gimple_range_op_handler &handler,
 				      const vrange &lhs, tree name,
 				      fur_source &src)
 {
-  tree op1 = gimple_range_operand1 (stmt);
-  tree op2 = gimple_range_operand2 (stmt);
+  gimple *stmt = handler.stmt ();
+  tree op1 = handler.operand1 ();
+  tree op2 = handler.operand2 ();
+
   Value_Range op1_range (TREE_TYPE (op1));
   Value_Range op2_range (TREE_TYPE (op2));
   Value_Range tmp (TREE_TYPE (op2));
@@ -1093,7 +1024,7 @@ gori_compute::compute_operand2_range (vrange &r, gimple *stmt,
   src.get_operand (op2_range, op2);
 
   // Intersect with range for op2 based on lhs and op1.
-  if (!gimple_range_calc_op2 (tmp, stmt, lhs, op1_range))
+  if (!handler.calc_op2 (tmp, lhs, op1_range))
     return false;
 
   unsigned idx;
@@ -1148,7 +1079,8 @@ gori_compute::compute_operand2_range (vrange &r, gimple *stmt,
 
 bool
 gori_compute::compute_operand1_and_operand2_range (vrange &r,
-						   gimple *stmt,
+						   gimple_range_op_handler
+								     &handler,
 						   const vrange &lhs,
 						   tree name,
 						   fur_source &src)
@@ -1157,11 +1089,11 @@ gori_compute::compute_operand1_and_operand2_range (vrange &r,
 
   // 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, stmt, lhs, name, src))
+  if (!compute_operand2_range (op_range, handler, lhs, name, src))
     return false;
 
   // Now get the range thru op1.
-  if (!compute_operand1_range (r, stmt, lhs, name, src))
+  if (!compute_operand1_range (r, handler, lhs, name, src))
     return false;
 
   // Both operands have to be simultaneously true, so perform an intersection.
diff --git a/gcc/gimple-range-gori.h b/gcc/gimple-range-gori.h
index 3d57ab94624..0c776ef853f 100644
--- a/gcc/gimple-range-gori.h
+++ b/gcc/gimple-range-gori.h
@@ -170,17 +170,18 @@ private:
 			      tree name, class fur_source &src);
   bool compute_operand_range_switch (vrange &r, gswitch *s, const vrange &lhs,
 				     tree name, fur_source &src);
-  bool compute_operand1_range (vrange &r, gimple *stmt, const vrange &lhs,
-			       tree name, fur_source &src);
-  bool compute_operand2_range (vrange &r, gimple *stmt, const vrange &lhs,
-			       tree name, fur_source &src);
-  bool compute_operand1_and_operand2_range (vrange &r, gimple *stmt,
+  bool compute_operand1_range (vrange &r, gimple_range_op_handler &handler,
+			       const vrange &lhs, tree name, fur_source &src);
+  bool compute_operand2_range (vrange &r, gimple_range_op_handler &handler,
+			       const vrange &lhs, tree name, fur_source &src);
+  bool compute_operand1_and_operand2_range (vrange &r,
+					    gimple_range_op_handler &handler,
 					    const vrange &lhs, tree name,
 					    fur_source &src);
   void compute_logical_operands (vrange &true_range, vrange &false_range,
-				 gimple *stmt, const irange &lhs,
-				 tree name, fur_source &src, tree op,
-				 bool op_in_chain);
+				 gimple_range_op_handler &handler,
+				 const irange &lhs, tree name, fur_source &src,
+				 tree op, bool op_in_chain);
   bool logical_combine (vrange &r, enum tree_code code, const irange &lhs,
 			const vrange &op1_true, const vrange &op1_false,
 			const vrange &op2_true, const vrange &op2_false);
@@ -192,16 +193,6 @@ private:
   int m_not_executable_flag;
 };
 
-// These routines provide a GIMPLE interface to the range-ops code.
-extern bool gimple_range_calc_op1 (vrange &r, const gimple *s,
-				   const vrange &lhs_range);
-extern bool gimple_range_calc_op1 (vrange &r, const gimple *s,
-				   const vrange &lhs_range,
-				   const vrange &op2_range);
-extern bool gimple_range_calc_op2 (vrange &r, const gimple *s,
-				   const vrange &lhs_range,
-				   const vrange &op1_range);
-
 // For each name that is an import into BB's exports..
 #define FOR_EACH_GORI_IMPORT_NAME(gori, bb, name)			\
   for (gori_export_iterator iter ((gori).imports ((bb)));	\
diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
new file mode 100644
index 00000000000..f03125a0fc5
--- /dev/null
+++ b/gcc/gimple-range-op.cc
@@ -0,0 +1,245 @@
+/* Code for GIMPLE range op related routines.
+   Copyright (C) 2019-2022 Free Software Foundation, Inc.
+   Contributed by Andrew MacLeod <amacleod@redhat.com>
+   and Aldy Hernandez <aldyh@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "insn-codes.h"
+#include "tree.h"
+#include "gimple.h"
+#include "ssa.h"
+#include "gimple-pretty-print.h"
+#include "optabs-tree.h"
+#include "gimple-iterator.h"
+#include "gimple-fold.h"
+#include "wide-int.h"
+#include "fold-const.h"
+#include "case-cfn-macros.h"
+#include "omp-general.h"
+#include "cfgloop.h"
+#include "tree-ssa-loop.h"
+#include "tree-scalar-evolution.h"
+#include "langhooks.h"
+#include "vr-values.h"
+#include "range.h"
+#include "value-query.h"
+#include "gimple-range.h"
+
+// Given stmt S, fill VEC, up to VEC_SIZE elements, with relevant ssa-names
+// on the statement.  For efficiency, it is an error to not pass in enough
+// elements for the vector.  Return the number of ssa-names.
+
+unsigned
+gimple_range_ssa_names (tree *vec, unsigned vec_size, gimple *stmt)
+{
+  tree ssa;
+  int count = 0;
+
+  gimple_range_op_handler handler (stmt);
+  if (handler)
+    {
+      gcc_checking_assert (vec_size >= 2);
+      if ((ssa = gimple_range_ssa_p (handler.operand1 ())))
+	vec[count++] = ssa;
+      if ((ssa = gimple_range_ssa_p (handler.operand2 ())))
+	vec[count++] = ssa;
+    }
+  else if (is_a<gassign *> (stmt)
+	   && gimple_assign_rhs_code (stmt) == COND_EXPR)
+    {
+      gcc_checking_assert (vec_size >= 3);
+      gassign *st = as_a<gassign *> (stmt);
+      if ((ssa = gimple_range_ssa_p (gimple_assign_rhs1 (st))))
+	vec[count++] = ssa;
+      if ((ssa = gimple_range_ssa_p (gimple_assign_rhs2 (st))))
+	vec[count++] = ssa;
+      if ((ssa = gimple_range_ssa_p (gimple_assign_rhs3 (st))))
+	vec[count++] = ssa;
+    }
+  return count;
+}
+
+// Return the base of the RHS of an assignment.
+
+static tree
+gimple_range_base_of_assignment (const gimple *stmt)
+{
+  gcc_checking_assert (gimple_code (stmt) == GIMPLE_ASSIGN);
+  tree op1 = gimple_assign_rhs1 (stmt);
+  if (gimple_assign_rhs_code (stmt) == ADDR_EXPR)
+    return get_base_address (TREE_OPERAND (op1, 0));
+  return op1;
+}
+
+// If statement is supported by range-ops, set the CODE and return the TYPE.
+
+static tree
+get_code_and_type (gimple *s, enum tree_code &code)
+{
+  tree type = NULL_TREE;
+  code = NOP_EXPR;
+
+  if (const gassign *ass = dyn_cast<const gassign *> (s))
+    {
+      code = gimple_assign_rhs_code (ass);
+      // The LHS of a comparison is always an int, so we must look at
+      // the operands.
+      if (TREE_CODE_CLASS (code) == tcc_comparison)
+	type = TREE_TYPE (gimple_assign_rhs1 (ass));
+      else
+	type = TREE_TYPE (gimple_assign_lhs (ass));
+    }
+  else if (const gcond *cond = dyn_cast<const gcond *> (s))
+    {
+      code = gimple_cond_code (cond);
+      type = TREE_TYPE (gimple_cond_lhs (cond));
+    }
+  return type;
+}
+
+// If statement S has a supported range_op handler return TRUE.
+
+bool
+gimple_range_op_handler::supported_p (gimple *s)
+{
+  enum tree_code code;
+  tree type = get_code_and_type (s, code);
+  return (type && range_op_handler (code, type));
+}
+
+// Construct a handler object for statement S.
+
+gimple_range_op_handler::gimple_range_op_handler (gimple *s)
+{
+  enum tree_code code;
+  tree type = get_code_and_type (s, code);
+  m_stmt = s;
+  if (type)
+    set_op_handler (code, type);
+
+  if (m_valid)
+    switch (gimple_code (m_stmt))
+      {
+	case GIMPLE_COND:
+	  m_op1 = gimple_cond_lhs (m_stmt);
+	  m_op2 = gimple_cond_rhs (m_stmt);
+	  break;
+	case GIMPLE_ASSIGN:
+	  m_op1 = gimple_range_base_of_assignment (m_stmt);
+	  if (m_op1 && TREE_CODE (m_op1) == MEM_REF)
+	    {
+	      // If the base address is an SSA_NAME, we return it
+	      // here.  This allows processing of the range of that
+	      // name, while the rest of the expression is simply
+	      // ignored.  The code in range_ops will see the
+	      // ADDR_EXPR and do the right thing.
+	      tree ssa = TREE_OPERAND (m_op1, 0);
+	      if (TREE_CODE (ssa) == SSA_NAME)
+		m_op1 = ssa;
+	    }
+	  if (gimple_num_ops (m_stmt) >= 3)
+	    m_op2 = gimple_assign_rhs2 (m_stmt);
+	  else
+	    m_op2 = NULL_TREE;
+	  break;
+	default:
+	  m_op1 = NULL_TREE;
+	  m_op2 = NULL_TREE;
+	  break;
+      }
+}
+
+// Calculate what we can determine of the range of this unary
+// statement's operand if the lhs of the expression has the range
+// LHS_RANGE.  Return false if nothing can be determined.
+
+bool
+gimple_range_op_handler::calc_op1 (vrange &r, const vrange &lhs_range)
+{
+  gcc_checking_assert (gimple_num_ops (m_stmt) < 3);
+  // Give up on empty ranges.
+  if (lhs_range.undefined_p ())
+    return false;
+
+  // Unary operations require the type of the first operand in the
+  // second range position.
+  tree type = TREE_TYPE (operand1 ());
+  Value_Range type_range (type);
+  type_range.set_varying (type);
+  return op1_range (r, type, lhs_range, type_range);
+}
+
+// Calculate what we can determine of the range of this statement's
+// first operand if the lhs of the expression has the range LHS_RANGE
+// and the second operand has the range OP2_RANGE.  Return false if
+// nothing can be determined.
+
+bool
+gimple_range_op_handler::calc_op1 (vrange &r, const vrange &lhs_range,
+				   const vrange &op2_range)
+{
+  // Give up on empty ranges.
+  if (lhs_range.undefined_p ())
+    return false;
+
+  // Unary operation are allowed to pass a range in for second operand
+  // as there are often additional restrictions beyond the type which
+  // can be imposed.  See operator_cast::op1_range().
+  tree type = TREE_TYPE (operand1 ());
+  // If op2 is undefined, solve as if it is varying.
+  if (op2_range.undefined_p ())
+    {
+      // This is sometimes invoked on single operand stmts.
+      if (gimple_num_ops (m_stmt) < 3)
+	return false;
+      tree op2_type = TREE_TYPE (operand2 ());
+      Value_Range trange (op2_type);
+      trange.set_varying (op2_type);
+      return op1_range (r, type, lhs_range, trange);
+    }
+  return op1_range (r, type, lhs_range, op2_range);
+}
+
+// Calculate what we can determine of the range of this statement's
+// second operand if the lhs of the expression has the range LHS_RANGE
+// and the first operand has the range OP1_RANGE.  Return false if
+// nothing can be determined.
+
+bool
+gimple_range_op_handler::calc_op2 (vrange &r, const vrange &lhs_range,
+				   const vrange &op1_range)
+{
+  // Give up on empty ranges.
+  if (lhs_range.undefined_p ())
+    return false;
+
+  tree type = TREE_TYPE (operand2 ());
+  // If op1 is undefined, solve as if it is varying.
+  if (op1_range.undefined_p ())
+    {
+      tree op1_type = TREE_TYPE (operand1 ());
+      Value_Range trange (op1_type);
+      trange.set_varying (op1_type);
+      return op2_range (r, type, lhs_range, trange);
+    }
+  return op2_range (r, type, lhs_range, op1_range);
+}
diff --git a/gcc/gimple-range-op.h b/gcc/gimple-range-op.h
new file mode 100644
index 00000000000..8bc0a8fbe11
--- /dev/null
+++ b/gcc/gimple-range-op.h
@@ -0,0 +1,51 @@
+/* Header file for the GIMPLE range-op interface.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   Contributed by Andrew MacLeod <amacleod@redhat.com>
+   and Aldy Hernandez <aldyh@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_GIMPLE_RANGE_OP_H
+#define GCC_GIMPLE_RANGE_OP_H
+
+#include "range-op.h"
+
+
+class gimple_range_op_handler : public range_op_handler
+{
+public:
+  static bool supported_p (gimple *s);
+  gimple_range_op_handler (gimple *s);
+  inline gimple *stmt () const { return m_stmt; }
+  inline tree lhs () const { return gimple_get_lhs (m_stmt); }
+  tree operand1 () const { gcc_checking_assert (m_valid); return m_op1; }
+  tree operand2 () const { gcc_checking_assert (m_valid); return m_op2; }
+  bool calc_op1 (vrange &r, const vrange &lhs_range);
+  bool calc_op1 (vrange &r, const vrange &lhs_range, const vrange &op2_range);
+  bool calc_op2 (vrange &r, const vrange &lhs_range, const vrange &op1_range);
+private:
+  gimple *m_stmt;
+  tree m_op1, m_op2;
+};
+
+// Given stmt S, fill VEC, up to VEC_SIZE elements, with relevant ssa-names
+// on the statement.  For efficiency, it is an error to not pass in enough
+// elements for the vector.  Return the number of ssa-names.
+
+unsigned gimple_range_ssa_names (tree *vec, unsigned vec_size, gimple *stmt);
+
+#endif // GCC_GIMPLE_RANGE_OP_H
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index eb347eee45b..d67d6499c78 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -341,7 +341,7 @@ gimple_ranger::prefill_name (vrange &r, tree name)
   if (!gimple_range_ssa_p (name))
     return;
   gimple *stmt = SSA_NAME_DEF_STMT (name);
-  if (!range_op_handler (stmt) && !is_a<gphi *> (stmt))
+  if (!gimple_range_op_handler::supported_p (stmt) && !is_a<gphi *> (stmt))
     return;
 
   bool current;
@@ -364,7 +364,7 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa)
   gcc_checking_assert (stmt && gimple_bb (stmt));
 
   // Only pre-process range-ops and phis.
-  if (!range_op_handler (stmt) && !is_a<gphi *> (stmt))
+  if (!gimple_range_op_handler::supported_p (stmt) && !is_a<gphi *> (stmt))
     return;
 
   // Mark where on the stack we are starting.
@@ -422,14 +422,15 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa)
 	}
       else
 	{
-	  gcc_checking_assert (range_op_handler (stmt));
-	  tree op = gimple_range_operand2 (stmt);
+	  gimple_range_op_handler handler (stmt);
+	  gcc_checking_assert (handler);
+	  tree op = handler.operand2 ();
 	  if (op)
 	    {
 	      Value_Range r (TREE_TYPE (op));
 	      prefill_name (r, op);
 	    }
-	  op = gimple_range_operand1 (stmt);
+	  op = handler.operand1 ();
 	  if (op)
 	    {
 	      Value_Range r (TREE_TYPE (op));
diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h
index 34f61025ac3..8b2ff5685e5 100644
--- a/gcc/gimple-range.h
+++ b/gcc/gimple-range.h
@@ -24,7 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 
 #include "range.h"
 #include "value-query.h"
-#include "range-op.h"
+#include "gimple-range-op.h"
 #include "gimple-range-trace.h"
 #include "gimple-range-edge.h"
 #include "gimple-range-fold.h"
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index f642b3f26de..9ae42b8331f 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -4182,42 +4182,19 @@ range_op_handler::set_op_handler (tree_code code, tree type)
     }
 }
 
-range_op_handler::range_op_handler (tree_code code, tree type)
+range_op_handler::range_op_handler ()
 {
-  set_op_handler (code, type);
+  m_int = NULL;
+  m_float = NULL;
+  m_valid = false;
 }
 
-range_op_handler::range_op_handler (const gimple *s)
+range_op_handler::range_op_handler (tree_code code, tree type)
 {
-  tree_code code = NOP_EXPR;
-  tree type = NULL_TREE;
-
-  if (const gassign *ass = dyn_cast<const gassign *> (s))
-    {
-      code = gimple_assign_rhs_code (ass);
-      // The LHS of a comparison is always an int, so we must look at
-      // the operands.
-      if (TREE_CODE_CLASS (code) == tcc_comparison)
-	type = TREE_TYPE (gimple_assign_rhs1 (ass));
-      else
-	type = TREE_TYPE (gimple_assign_lhs (ass));
-    }
-  else if (const gcond *cond = dyn_cast<const gcond *> (s))
-    {
-      code = gimple_cond_code (cond);
-      type = TREE_TYPE (gimple_cond_lhs (cond));
-    }
-
-  if (!type)
-    {
-      m_int = NULL;
-      m_float = NULL;
-      m_valid = false;
-    }
-  else
-    set_op_handler (code, type);
+  set_op_handler (code, type);
 }
 
+
 bool
 range_op_handler::fold_range (vrange &r, tree type,
 			      const vrange &lh,
diff --git a/gcc/range-op.h b/gcc/range-op.h
index 56c57c46a8e..b4b5101a9e0 100644
--- a/gcc/range-op.h
+++ b/gcc/range-op.h
@@ -160,8 +160,8 @@ public:
 class range_op_handler
 {
 public:
+  range_op_handler ();
   range_op_handler (enum tree_code code, tree type);
-  range_op_handler (const gimple *s);
   inline operator bool () const { return m_valid; }
 
   bool fold_range (vrange &r, tree type,
@@ -185,7 +185,7 @@ public:
 				  const vrange &op2,
 				  relation_kind = VREL_VARYING) const;
   relation_kind op1_op2_relation (const vrange &lhs) const;
-private:
+protected:
   void set_op_handler (enum tree_code code, tree type);
   bool m_valid;
   range_operator *m_int;
-- 
2.37.3


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 04/17] Fix calc_op1 for undefined op2_range.
  2022-09-22 18:49 [PATCH 00/17] Move builtin functions to range-ops Andrew MacLeod
                   ` (2 preceding siblings ...)
  2022-09-22 18:56 ` [PATCH 03/17] Create gimple_range_op_handler in a new source file Andrew MacLeod
@ 2022-09-22 18:58 ` Andrew MacLeod
  2022-09-22 18:59 ` [PATCH 05/17] Add missing float fold_range prototype for floats Andrew MacLeod
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Andrew MacLeod @ 2022-09-22 18:58 UTC (permalink / raw)
  To: gcc-patches; +Cc: hernandez, aldy

[-- Attachment #1: Type: text/plain, Size: 274 bytes --]

Unary operations pass the type of operand 1 into op1_range.  If that 
range is undefined, the routine blindly picks the type of operand 
2,which in the case of a unary op, does not exist and traps.

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

Andrew

[-- Attachment #2: 0004-Fix-calc_op1-for-undefined-op2_range.patch --]
[-- Type: text/x-patch, Size: 1468 bytes --]

From a7a6649f4e7c459a95dee1600554ad06aaeb1cf6 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Thu, 22 Sep 2022 10:27:17 -0400
Subject: [PATCH 04/17] Fix calc_op1 for undefined op2_range.

Unary operations pass the type of operand 1 into op1_range.  If that
range is undefined, the routine blindly picks the type of operand 2,
which in the case of a unary op, does not exist and traps.

	* gimple-range-op.cc (gimple_range_op_handler::calc_op1): Use
	  operand 1 for second range if there is no operand 2.
---
 gcc/gimple-range-op.cc | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index f03125a0fc5..ab5b389449d 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -208,10 +208,14 @@ gimple_range_op_handler::calc_op1 (vrange &r, const vrange &lhs_range,
   // If op2 is undefined, solve as if it is varying.
   if (op2_range.undefined_p ())
     {
-      // This is sometimes invoked on single operand stmts.
       if (gimple_num_ops (m_stmt) < 3)
 	return false;
-      tree op2_type = TREE_TYPE (operand2 ());
+      tree op2_type;
+      // This is sometimes invoked on single operand stmts.
+      if (operand2 ())
+	op2_type = TREE_TYPE (operand2 ());
+      else
+	op2_type = TREE_TYPE (operand1 ());
       Value_Range trange (op2_type);
       trange.set_varying (op2_type);
       return op1_range (r, type, lhs_range, trange);
-- 
2.37.3


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 05/17] Add missing float fold_range prototype for floats.
  2022-09-22 18:49 [PATCH 00/17] Move builtin functions to range-ops Andrew MacLeod
                   ` (3 preceding siblings ...)
  2022-09-22 18:58 ` [PATCH 04/17] Fix calc_op1 for undefined op2_range Andrew MacLeod
@ 2022-09-22 18:59 ` Andrew MacLeod
  2022-09-22 19:00 ` [PATCH 06/17] Always check the return value of fold_range Andrew MacLeod
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Andrew MacLeod @ 2022-09-22 18:59 UTC (permalink / raw)
  To: gcc-patches; +Cc: hernandez, aldy

[-- Attachment #1: Type: text/plain, Size: 258 bytes --]

Unary operations require op2 to be the range of the type of the LHS. 
This is so the type for the LHS can be properly set.  There are is a 
missing prototype for this combination.

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

Andrew


[-- Attachment #2: 0005-Add-missing-float-fold_range-prototype-for-floats.patch --]
[-- Type: text/x-patch, Size: 2701 bytes --]

From be2a25adbdc76a770f7470cc9f47892f7a4139ae Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Tue, 20 Sep 2022 12:34:08 -0400
Subject: [PATCH 05/17] Add missing float fold_range prototype for floats.

Unary operations require op2 to be the range of the type of the LHS.
This is so the type for the LHS can be properly set.

	* range-op-float.cc (range_operator_float::fold_range): New base
	  method for "int = float op int".
	* range-op.cc (range_op_handler::fold_range): New case.
	* range-op.h: Update prototypes.
---
 gcc/range-op-float.cc | 10 ++++++++++
 gcc/range-op.cc       | 13 ++++++++++---
 gcc/range-op.h        |  5 +++++
 3 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index 2bd3dc9253f..aa5b7ed073d 100644
--- a/gcc/range-op-float.cc
+++ b/gcc/range-op-float.cc
@@ -58,6 +58,16 @@ range_operator_float::fold_range (frange &r ATTRIBUTE_UNUSED,
   return false;
 }
 
+bool
+range_operator_float::fold_range (irange &r ATTRIBUTE_UNUSED,
+				  tree type ATTRIBUTE_UNUSED,
+				  const frange &lh ATTRIBUTE_UNUSED,
+				  const irange &rh ATTRIBUTE_UNUSED,
+				  relation_kind rel ATTRIBUTE_UNUSED) const
+{
+  return false;
+}
+
 bool
 range_operator_float::fold_range (irange &r ATTRIBUTE_UNUSED,
 				  tree type ATTRIBUTE_UNUSED,
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 9ae42b8331f..072ebd32109 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -4208,9 +4208,16 @@ range_op_handler::fold_range (vrange &r, tree type,
 			   as_a <irange> (rh), rel);
 
   if (is_a <irange> (r))
-    return m_float->fold_range (as_a <irange> (r), type,
-				as_a <frange> (lh),
-				as_a <frange> (rh), rel);
+    {
+      if (is_a <irange> (rh))
+	return m_float->fold_range (as_a <irange> (r), type,
+				    as_a <frange> (lh),
+				    as_a <irange> (rh), rel);
+      else
+	return m_float->fold_range (as_a <irange> (r), type,
+				    as_a <frange> (lh),
+				    as_a <frange> (rh), rel);
+    }
   return m_float->fold_range (as_a <frange> (r), type,
 			      as_a <frange> (lh),
 			      as_a <frange> (rh), rel);
diff --git a/gcc/range-op.h b/gcc/range-op.h
index b4b5101a9e0..b2f063afb07 100644
--- a/gcc/range-op.h
+++ b/gcc/range-op.h
@@ -117,6 +117,11 @@ public:
 			   const frange &lh,
 			   const frange &rh,
 			   relation_kind rel = VREL_VARYING) const;
+  // Unary operations have the range of the LHS as op2.
+  virtual bool fold_range (irange &r, tree type,
+			   const frange &lh,
+			   const irange &rh,
+			   relation_kind rel = VREL_VARYING) const;
   virtual bool fold_range (irange &r, tree type,
 			   const frange &lh,
 			   const frange &rh,
-- 
2.37.3


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 06/17] Always check the return value of fold_range.
  2022-09-22 18:49 [PATCH 00/17] Move builtin functions to range-ops Andrew MacLeod
                   ` (4 preceding siblings ...)
  2022-09-22 18:59 ` [PATCH 05/17] Add missing float fold_range prototype for floats Andrew MacLeod
@ 2022-09-22 19:00 ` Andrew MacLeod
  2022-09-22 19:01 ` [PATCH 07/17] Add range-ops support for builtin functions Andrew MacLeod
                   ` (10 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Andrew MacLeod @ 2022-09-22 19:00 UTC (permalink / raw)
  To: gcc-patches; +Cc: hernandez, aldy

[-- Attachment #1: Type: text/plain, Size: 235 bytes --]

The fold_range routine in range-ops returns FALSE if the operation 
fails.  There are a few places which assume the operation was 
successful.  Fix those.

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

Andrew



[-- Attachment #2: 0006-Always-check-the-return-value-of-fold_range.patch --]
[-- Type: text/x-patch, Size: 4620 bytes --]

From 2f92f685da2ef9e82ee6262519919180df8f2dd9 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Wed, 21 Sep 2022 16:15:02 -0400
Subject: [PATCH 06/17] Always check the return value of fold_range.

The fold_range routine in range-ops returns FALSE if the operation
fails.  There are a few places which assume the operation was
successful.  Fix those.

	* gimple-range-fold.cc (range_of_range_op): Set result to
	VARYING if the call to fold_range fails.
	* tree-data-ref.cc (compute_distributive_range): Ditto.
	* tree-vrp.cc (range_fold_binary_expr): Ditto.
	(range_fold_unary_expr): Ditto.
	* value-query.cc (range_query::get_tree_range): Ditto.
---
 gcc/gimple-range-fold.cc | 6 ++++--
 gcc/tree-data-ref.cc     | 6 ++++--
 gcc/tree-vrp.cc          | 6 ++++--
 gcc/value-query.cc       | 6 ++++--
 4 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index addf3e7f254..42408254c35 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -544,7 +544,8 @@ fold_using_range::range_of_range_op (vrange &r,
 	  // Fold range, and register any dependency if available.
 	  Value_Range r2 (type);
 	  r2.set_varying (type);
-	  handler.fold_range (r, type, range1, r2);
+	  if (!handler.fold_range (r, type, range1, r2))
+	    r.set_varying (type);
 	  if (lhs && gimple_range_ssa_p (op1))
 	    {
 	      if (src.gori ())
@@ -567,7 +568,8 @@ fold_using_range::range_of_range_op (vrange &r,
 	      fputc ('\n', dump_file);
 	    }
 	  // Fold range, and register any dependency if available.
-	  handler.fold_range (r, type, range1, range2, rel);
+	  if (!handler.fold_range (r, type, range1, range2, rel))
+	    r.set_varying (type);
 	  if (irange::supports_p (type))
 	    relation_fold_and_or (as_a <irange> (r), s, src);
 	  if (lhs)
diff --git a/gcc/tree-data-ref.cc b/gcc/tree-data-ref.cc
index ff9327f6deb..91bfb619d66 100644
--- a/gcc/tree-data-ref.cc
+++ b/gcc/tree-data-ref.cc
@@ -594,7 +594,8 @@ compute_distributive_range (tree type, value_range &op0_range,
   if (result_range)
     {
       range_op_handler op (code, type);
-      op.fold_range (*result_range, type, op0_range, op1_range);
+      if (!op.fold_range (*result_range, type, op0_range, op1_range))
+	result_range->set_varying (type);
     }
 
   /* The distributive property guarantees that if TYPE is no narrower
@@ -642,7 +643,8 @@ compute_distributive_range (tree type, value_range &op0_range,
   range_op_handler op (code, ssizetype);
   bool saved_flag_wrapv = flag_wrapv;
   flag_wrapv = 1;
-  op.fold_range (wide_range, ssizetype, op0_range, op1_range);
+  if (!op.fold_range (wide_range, ssizetype, op0_range, op1_range))
+    wide_range.set_varying (ssizetype);;
   flag_wrapv = saved_flag_wrapv;
   if (wide_range.num_pairs () != 1 || !range_int_cst_p (&wide_range))
     return false;
diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc
index c3030a1b130..93482e5d102 100644
--- a/gcc/tree-vrp.cc
+++ b/gcc/tree-vrp.cc
@@ -1069,7 +1069,8 @@ range_fold_binary_expr (value_range *vr,
     vr1.set_varying (expr_type);
   vr0.normalize_addresses ();
   vr1.normalize_addresses ();
-  op.fold_range (*vr, expr_type, vr0, vr1);
+  if (!op.fold_range (*vr, expr_type, vr0, vr1))
+    vr->set_varying (expr_type);
 }
 
 /* Perform a unary operation on a range.  */
@@ -1095,7 +1096,8 @@ range_fold_unary_expr (value_range *vr,
 
   value_range vr0_cst (*vr0);
   vr0_cst.normalize_addresses ();
-  op.fold_range (*vr, expr_type, vr0_cst, value_range (expr_type));
+  if (!op.fold_range (*vr, expr_type, vr0_cst, value_range (expr_type)))
+    vr->set_varying (expr_type);
 }
 
 /* If the range of values taken by OP can be inferred after STMT executes,
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index 0bdd670982b..296784be31d 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -252,7 +252,8 @@ range_query::get_tree_range (vrange &r, tree expr, gimple *stmt)
 	  Value_Range r1 (TREE_TYPE (TREE_OPERAND (expr, 1)));
 	  range_of_expr (r0, TREE_OPERAND (expr, 0), stmt);
 	  range_of_expr (r1, TREE_OPERAND (expr, 1), stmt);
-	  op.fold_range (r, type, r0, r1);
+	  if (!op.fold_range (r, type, r0, r1))
+	    r.set_varying (type);
 	}
       else
 	r.set_varying (type);
@@ -268,7 +269,8 @@ range_query::get_tree_range (vrange &r, tree expr, gimple *stmt)
 	  Value_Range r1 (type);
 	  r1.set_varying (type);
 	  range_of_expr (r0, TREE_OPERAND (expr, 0), stmt);
-	  op.fold_range (r, type, r0, r1);
+	  if (!op.fold_range (r, type, r0, r1))
+	    r.set_varying (type);
 	}
       else
 	r.set_varying (type);
-- 
2.37.3


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 07/17] Add range-ops support for builtin functions.
  2022-09-22 18:49 [PATCH 00/17] Move builtin functions to range-ops Andrew MacLeod
                   ` (5 preceding siblings ...)
  2022-09-22 19:00 ` [PATCH 06/17] Always check the return value of fold_range Andrew MacLeod
@ 2022-09-22 19:01 ` Andrew MacLeod
  2022-09-22 19:02 ` [PATCH 08/17] Convert CFN_BUILT_IN_SIGNBIT to range-ops Andrew MacLeod
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Andrew MacLeod @ 2022-09-22 19:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: hernandez, aldy

[-- Attachment #1: Type: text/plain, Size: 176 bytes --]

Check for builtins that can be a range-op entry and Convert 
CFN_BUILT_IN_CONSTANT_P as first POC.

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

Andrew


[-- Attachment #2: 0007-Add-range-ops-support-for-builtin-functions.patch --]
[-- Type: text/x-patch, Size: 6083 bytes --]

From b40b3035879cf695b72010858b9705a344292bdb Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Tue, 20 Sep 2022 16:53:37 -0400
Subject: [PATCH 07/17] Add range-ops support for builtin functions.

Convert CFN_BUILT_IN_CONSTANT_P as first POC.

	* gimple-range-fold.cc
	(fold_using_range::range_of_builtin_int_call): Remove case for
	CFN_BUILT_IN_CONSTANT_P.
	* gimple-range-op.cc (gimple_range_op_handler::supported_p):
	Check if a call also creates a range-op object.
	(gimple_range_op_handler): Also check builtin calls.
	(class cfn_constant_float_p): New.  Float CFN_BUILT_IN_CONSTANT_P.
	(class cfn_constant_p): New.  Integral CFN_BUILT_IN_CONSTANT_P.
	(gimple_range_op_handler::maybe_builtin_call): Set arguments and
	handler for supported built-in calls.
	* gimple-range-op.h (maybe_builtin_call): New prototype.
---
 gcc/gimple-range-fold.cc |  17 -------
 gcc/gimple-range-op.cc   | 104 ++++++++++++++++++++++++++++++++++++---
 gcc/gimple-range-op.h    |   1 +
 3 files changed, 97 insertions(+), 25 deletions(-)

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index 42408254c35..63a1f517d28 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -944,23 +944,6 @@ fold_using_range::range_of_builtin_int_call (irange &r, gcall *call,
 
   switch (func)
     {
-    case CFN_BUILT_IN_CONSTANT_P:
-      {
-	arg = gimple_call_arg (call, 0);
-	Value_Range tmp (TREE_TYPE (arg));
-	if (src.get_operand (tmp, arg) && tmp.singleton_p ())
-	  {
-	    r.set (build_one_cst (type), build_one_cst (type));
-	    return true;
-	  }
-	if (cfun->after_inlining)
-	  {
-	    r.set_zero (type);
-	    return true;
-	  }
-	break;
-      }
-
     case CFN_BUILT_IN_SIGNBIT:
       {
 	arg = gimple_call_arg (call, 0);
diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index ab5b389449d..bcc4c3d778c 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -123,7 +123,11 @@ gimple_range_op_handler::supported_p (gimple *s)
 {
   enum tree_code code;
   tree type = get_code_and_type (s, code);
-  return (type && range_op_handler (code, type));
+  if (type && range_op_handler (code, type))
+    return true;
+  if (is_a <gcall *> (s) && gimple_range_op_handler (s))
+    return true;
+  return false;
 }
 
 // Construct a handler object for statement S.
@@ -133,6 +137,8 @@ gimple_range_op_handler::gimple_range_op_handler (gimple *s)
   enum tree_code code;
   tree type = get_code_and_type (s, code);
   m_stmt = s;
+  m_op1 = NULL_TREE;
+  m_op2 = NULL_TREE;
   if (type)
     set_op_handler (code, type);
 
@@ -142,7 +148,7 @@ gimple_range_op_handler::gimple_range_op_handler (gimple *s)
 	case GIMPLE_COND:
 	  m_op1 = gimple_cond_lhs (m_stmt);
 	  m_op2 = gimple_cond_rhs (m_stmt);
-	  break;
+	  return;
 	case GIMPLE_ASSIGN:
 	  m_op1 = gimple_range_base_of_assignment (m_stmt);
 	  if (m_op1 && TREE_CODE (m_op1) == MEM_REF)
@@ -158,14 +164,15 @@ gimple_range_op_handler::gimple_range_op_handler (gimple *s)
 	    }
 	  if (gimple_num_ops (m_stmt) >= 3)
 	    m_op2 = gimple_assign_rhs2 (m_stmt);
-	  else
-	    m_op2 = NULL_TREE;
-	  break;
+	  return;
 	default:
-	  m_op1 = NULL_TREE;
-	  m_op2 = NULL_TREE;
-	  break;
+	  gcc_unreachable ();
+	  return;
       }
+  // If no range-op table entry handled this stmt, check for other supported
+  // statements.
+  if (is_a <gcall *> (m_stmt))
+    maybe_builtin_call ();
 }
 
 // Calculate what we can determine of the range of this unary
@@ -247,3 +254,84 @@ gimple_range_op_handler::calc_op2 (vrange &r, const vrange &lhs_range,
     }
   return op2_range (r, type, lhs_range, op1_range);
 }
+
+// --------------------------------------------------------------------
+
+// Implement range operator for float CFN_BUILT_IN_CONSTANT_P.
+class cfn_constant_float_p : public range_operator_float
+{
+public:
+  using range_operator_float::fold_range;
+  virtual bool fold_range (irange &r, tree type, const frange &lh,
+			   const irange &, relation_kind) const
+  {
+    if (lh.singleton_p ())
+      {
+	r.set (build_one_cst (type), build_one_cst (type));
+	return true;
+      }
+    if (cfun->after_inlining)
+      {
+	r.set_zero (type);
+	return true;
+      }
+    return false;
+  }
+} op_cfn_constant_float_p;
+
+// Implement range operator for integral CFN_BUILT_IN_CONSTANT_P.
+class cfn_constant_p : public range_operator
+{
+public:
+  using range_operator::fold_range;
+  virtual bool fold_range (irange &r, tree type, const irange &lh,
+			   const irange &, relation_kind) const
+  {
+    if (lh.singleton_p ())
+      {
+	r.set (build_one_cst (type), build_one_cst (type));
+	return true;
+      }
+    if (cfun->after_inlining)
+      {
+	r.set_zero (type);
+	return true;
+      }
+    return false;
+  }
+} op_cfn_constant_p;
+
+// Set up a gimple_range_op_handler for any built in function which can be
+// supported via range-ops.
+
+void
+gimple_range_op_handler::maybe_builtin_call ()
+{
+  gcc_checking_assert (is_a <gcall *> (m_stmt));
+
+  gcall *call = as_a <gcall *> (m_stmt);
+  combined_fn func = gimple_call_combined_fn (call);
+  if (func == CFN_LAST)
+    return;
+  tree type = gimple_range_type (call);
+  gcc_checking_assert (type);
+  if (!Value_Range::supports_type_p (type))
+    return;
+
+  switch (func)
+    {
+    case CFN_BUILT_IN_CONSTANT_P:
+      m_op1 = gimple_call_arg (call, 0);
+      m_valid = true;
+      if (irange::supports_p (TREE_TYPE (m_op1)))
+	m_int = &op_cfn_constant_p;
+      else if (frange::supports_p (TREE_TYPE (m_op1)))
+	m_float = &op_cfn_constant_float_p;
+      else
+	m_valid = false;
+      break;
+
+    default:
+      break;
+    }
+}
diff --git a/gcc/gimple-range-op.h b/gcc/gimple-range-op.h
index 8bc0a8fbe11..68764198bc0 100644
--- a/gcc/gimple-range-op.h
+++ b/gcc/gimple-range-op.h
@@ -38,6 +38,7 @@ public:
   bool calc_op1 (vrange &r, const vrange &lhs_range, const vrange &op2_range);
   bool calc_op2 (vrange &r, const vrange &lhs_range, const vrange &op1_range);
 private:
+  void maybe_builtin_call ();
   gimple *m_stmt;
   tree m_op1, m_op2;
 };
-- 
2.37.3


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 08/17] Convert CFN_BUILT_IN_SIGNBIT to range-ops.
  2022-09-22 18:49 [PATCH 00/17] Move builtin functions to range-ops Andrew MacLeod
                   ` (6 preceding siblings ...)
  2022-09-22 19:01 ` [PATCH 07/17] Add range-ops support for builtin functions Andrew MacLeod
@ 2022-09-22 19:02 ` Andrew MacLeod
  2022-09-22 19:05 ` [PATCH 09/17] Convert CFN_BUILT_IN_TOUPPER and TOLOWER " Andrew MacLeod
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Andrew MacLeod @ 2022-09-22 19:02 UTC (permalink / raw)
  To: gcc-patches; +Cc: hernandez, aldy

[-- Attachment #1: Type: text/plain, Size: 77 bytes --]

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

Andrew



[-- Attachment #2: 0008-Convert-CFN_BUILT_IN_SIGNBIT-to-range-ops.patch --]
[-- Type: text/x-patch, Size: 2384 bytes --]

From eb82b9f68eb8d0cc65a1a022154c8e729860ea59 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Wed, 21 Sep 2022 09:29:40 -0400
Subject: [PATCH 08/17] Convert CFN_BUILT_IN_SIGNBIT to range-ops.

	* gimple-range-fold.cc (range_of_builtin_int_call): Remove case
	for CFN_BUILT_IN_SIGNBIT.
	* gimple-range-op.cc (class cfn_signbit): New.
	(gimple_range_op_handler::maybe_builtin_call): Set arguments.
---
 gcc/gimple-range-fold.cc | 20 --------------------
 gcc/gimple-range-op.cc   | 27 +++++++++++++++++++++++++++
 2 files changed, 27 insertions(+), 20 deletions(-)

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index 63a1f517d28..417a925ac9f 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -944,26 +944,6 @@ fold_using_range::range_of_builtin_int_call (irange &r, gcall *call,
 
   switch (func)
     {
-    case CFN_BUILT_IN_SIGNBIT:
-      {
-	arg = gimple_call_arg (call, 0);
-	frange tmp;
-	if (src.get_operand (tmp, arg))
-	  {
-	    bool signbit;
-	    if (tmp.signbit_p (signbit))
-	      {
-		if (signbit)
-		  r.set_nonzero (type);
-		else
-		  r.set_zero (type);
-		return true;
-	      }
-	    return false;
-	  }
-	break;
-      }
-
     case CFN_BUILT_IN_TOUPPER:
       {
 	arg = gimple_call_arg (call, 0);
diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index bcc4c3d778c..d62dff5f92e 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -301,6 +301,27 @@ public:
   }
 } op_cfn_constant_p;
 
+// Implement range operator for CFN_BUILT_IN_SIGNBIT.
+class cfn_signbit : public range_operator_float
+{
+public:
+  using range_operator_float::fold_range;
+  virtual bool fold_range (irange &r, tree type, const frange &lh,
+			   const irange &, relation_kind) const
+  {
+    bool signbit;
+    if (lh.signbit_p (signbit))
+      {
+	if (signbit)
+	  r.set_nonzero (type);
+	else
+	  r.set_zero (type);
+	return true;
+      }
+   return false;
+  }
+} op_cfn_signbit;
+
 // Set up a gimple_range_op_handler for any built in function which can be
 // supported via range-ops.
 
@@ -331,6 +352,12 @@ gimple_range_op_handler::maybe_builtin_call ()
 	m_valid = false;
       break;
 
+    case CFN_BUILT_IN_SIGNBIT:
+      m_op1 = gimple_call_arg (call, 0);
+      m_float = &op_cfn_signbit;
+      m_valid = true;
+      break;
+
     default:
       break;
     }
-- 
2.37.3


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 09/17] Convert CFN_BUILT_IN_TOUPPER and TOLOWER to range-ops.
  2022-09-22 18:49 [PATCH 00/17] Move builtin functions to range-ops Andrew MacLeod
                   ` (7 preceding siblings ...)
  2022-09-22 19:02 ` [PATCH 08/17] Convert CFN_BUILT_IN_SIGNBIT to range-ops Andrew MacLeod
@ 2022-09-22 19:05 ` Andrew MacLeod
  2022-09-22 19:05 ` [PATCH 10/17] Convert CFN_BUILT_FFS and CFN_POPCOUNT " Andrew MacLeod
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Andrew MacLeod @ 2022-09-22 19:05 UTC (permalink / raw)
  To: gcc-patches; +Cc: hernandez, aldy

[-- Attachment #1: Type: text/plain, Size: 75 bytes --]

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

Andrew

[-- Attachment #2: 0009-Convert-CFN_BUILT_IN_TOUPPER-and-TOLOWER-to-range-op.patch --]
[-- Type: text/x-patch, Size: 5969 bytes --]

From 2f5da730f159de238500c82b0c6ef6c9ab91b1c2 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Tue, 20 Sep 2022 17:14:30 -0400
Subject: [PATCH 09/17] Convert CFN_BUILT_IN_TOUPPER and TOLOWER to range-ops.

	* gimple-range-fold.cc (get_letter_range): Move to new class.
	(range_of_builtin_int_call): Remove case for CFN_BUILT_IN_TOUPPER
	and CFN_BUILT_IN_TOLOWER.
	* gimple-range-op.cc (class cfn_toupper_tolower): New.
	(gimple_range_op_handler::maybe_builtin_call): Set arguments.
---
 gcc/gimple-range-fold.cc | 66 ----------------------------------
 gcc/gimple-range-op.cc   | 77 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 77 insertions(+), 66 deletions(-)

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index 417a925ac9f..af1f83f7409 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -887,28 +887,6 @@ fold_using_range::range_of_builtin_ubsan_call (irange &r, gcall *call,
     r.set_varying (type);
 }
 
-// Return TRUE if we recognize the target character set and return the
-// range for lower case and upper case letters.
-
-static bool
-get_letter_range (tree type, irange &lowers, irange &uppers)
-{
-  // ASCII
-  int a = lang_hooks.to_target_charset ('a');
-  int z = lang_hooks.to_target_charset ('z');
-  int A = lang_hooks.to_target_charset ('A');
-  int Z = lang_hooks.to_target_charset ('Z');
-
-  if ((z - a == 25) && (Z - A == 25))
-    {
-      lowers = int_range<2> (build_int_cst (type, a), build_int_cst (type, z));
-      uppers = int_range<2> (build_int_cst (type, A), build_int_cst (type, Z));
-      return true;
-    }
-  // Unknown character set.
-  return false;
-}
-
 // For a builtin in CALL, return a range in R if known and return
 // TRUE.  Otherwise return FALSE.
 
@@ -944,50 +922,6 @@ fold_using_range::range_of_builtin_int_call (irange &r, gcall *call,
 
   switch (func)
     {
-    case CFN_BUILT_IN_TOUPPER:
-      {
-	arg = gimple_call_arg (call, 0);
-	// If the argument isn't compatible with the LHS, do nothing.
-	if (!range_compatible_p (type, TREE_TYPE (arg)))
-	  return false;
-	if (!src.get_operand (r, arg))
-	  return false;
-
-	int_range<3> lowers;
-	int_range<3> uppers;
-	if (!get_letter_range (type, lowers, uppers))
-	  return false;
-
-	// Return the range passed in without any lower case characters,
-	// but including all the upper case ones.
-	lowers.invert ();
-	r.intersect (lowers);
-	r.union_ (uppers);
-	return true;
-      }
-
-     case CFN_BUILT_IN_TOLOWER:
-      {
-	arg = gimple_call_arg (call, 0);
-	// If the argument isn't compatible with the LHS, do nothing.
-	if (!range_compatible_p (type, TREE_TYPE (arg)))
-	  return false;
-	if (!src.get_operand (r, arg))
-	  return false;
-
-	int_range<3> lowers;
-	int_range<3> uppers;
-	if (!get_letter_range (type, lowers, uppers))
-	  return false;
-
-	// Return the range passed in without any upper case characters,
-	// but including all the lower case ones.
-	uppers.invert ();
-	r.intersect (uppers);
-	r.union_ (lowers);
-	return true;
-      }
-
     CASE_CFN_FFS:
     CASE_CFN_POPCOUNT:
       // __builtin_ffs* and __builtin_popcount* return [0, prec].
diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index d62dff5f92e..45384d990ae 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -322,6 +322,71 @@ public:
   }
 } op_cfn_signbit;
 
+// Implement range operator for CFN_BUILT_IN_TOUPPER and CFN_BUILT_IN_TOLOWER.
+class cfn_toupper_tolower : public range_operator
+{
+public:
+  using range_operator::fold_range;
+  cfn_toupper_tolower (bool toupper)  { m_toupper = toupper; }
+  virtual bool fold_range (irange &r, tree type, const irange &lh,
+			   const irange &, relation_kind) const;
+private:
+  bool get_letter_range (tree type, irange &lowers, irange &uppers) const;
+  bool m_toupper;
+} op_cfn_toupper (true), op_cfn_tolower (false);
+
+// Return TRUE if we recognize the target character set and return the
+// range for lower case and upper case letters.
+
+bool
+cfn_toupper_tolower::get_letter_range (tree type, irange &lowers,
+				       irange &uppers) const
+{
+  // ASCII
+  int a = lang_hooks.to_target_charset ('a');
+  int z = lang_hooks.to_target_charset ('z');
+  int A = lang_hooks.to_target_charset ('A');
+  int Z = lang_hooks.to_target_charset ('Z');
+
+  if ((z - a == 25) && (Z - A == 25))
+    {
+      lowers = int_range<2> (build_int_cst (type, a), build_int_cst (type, z));
+      uppers = int_range<2> (build_int_cst (type, A), build_int_cst (type, Z));
+      return true;
+    }
+  // Unknown character set.
+  return false;
+}
+
+bool
+cfn_toupper_tolower::fold_range (irange &r, tree type, const irange &lh,
+				 const irange &, relation_kind) const
+{
+  int_range<3> lowers;
+  int_range<3> uppers;
+  if (!get_letter_range (type, lowers, uppers))
+    return false;
+
+  r = lh;
+  if (m_toupper)
+    {
+      // Return the range passed in without any lower case characters,
+      // but including all the upper case ones.
+      lowers.invert ();
+      r.intersect (lowers);
+      r.union_ (uppers);
+    }
+  else
+    {
+      // Return the range passed in without any lower case characters,
+      // but including all the upper case ones.
+      uppers.invert ();
+      r.intersect (uppers);
+      r.union_ (lowers);
+    }
+  return true;
+}
+
 // Set up a gimple_range_op_handler for any built in function which can be
 // supported via range-ops.
 
@@ -358,6 +423,18 @@ gimple_range_op_handler::maybe_builtin_call ()
       m_valid = true;
       break;
 
+    case CFN_BUILT_IN_TOUPPER:
+    case CFN_BUILT_IN_TOLOWER:
+      // Only proceed If the argument is compatible with the LHS.
+      m_op1 = gimple_call_arg (call, 0);
+      if (range_compatible_p (type, TREE_TYPE (m_op1)))
+	{
+	  m_valid = true;
+	  m_int = (func == CFN_BUILT_IN_TOLOWER) ? &op_cfn_tolower
+						 : &op_cfn_toupper;
+	}
+      break;
+
     default:
       break;
     }
-- 
2.37.3


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 10/17] Convert CFN_BUILT_FFS and CFN_POPCOUNT to range-ops.
  2022-09-22 18:49 [PATCH 00/17] Move builtin functions to range-ops Andrew MacLeod
                   ` (8 preceding siblings ...)
  2022-09-22 19:05 ` [PATCH 09/17] Convert CFN_BUILT_IN_TOUPPER and TOLOWER " Andrew MacLeod
@ 2022-09-22 19:05 ` Andrew MacLeod
  2022-09-22 19:05 ` [PATCH 11/17] Convert CFN_CLZ builtins " Andrew MacLeod
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Andrew MacLeod @ 2022-09-22 19:05 UTC (permalink / raw)
  To: gcc-patches; +Cc: hernandez, aldy

[-- Attachment #1: Type: text/plain, Size: 77 bytes --]

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

Andrew

[-- Attachment #2: 0010-Convert-CFN_BUILT_FFS-and-CFN_POPCOUNT-to-range-ops.patch --]
[-- Type: text/x-patch, Size: 3402 bytes --]

From 5f730c650184d4c8bfad513a9e0e593f87a5bf0c Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Tue, 20 Sep 2022 18:07:14 -0400
Subject: [PATCH 10/17] Convert CFN_BUILT_FFS and CFN_POPCOUNT to range-ops.

	* gimple-range-fold.cc (range_of_builtin_int_call): Remove case
	for CFN_FFS and CFN_POPCOUNT.
	* gimple-range-op.cc (class cfn_pocount): New.
	(gimple_range_op_handler::maybe_builtin_call): Set arguments.
---
 gcc/gimple-range-fold.cc | 22 ----------------------
 gcc/gimple-range-op.cc   | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 34 insertions(+), 22 deletions(-)

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index af1f83f7409..ca531037e13 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -922,28 +922,6 @@ fold_using_range::range_of_builtin_int_call (irange &r, gcall *call,
 
   switch (func)
     {
-    CASE_CFN_FFS:
-    CASE_CFN_POPCOUNT:
-      // __builtin_ffs* and __builtin_popcount* return [0, prec].
-      arg = gimple_call_arg (call, 0);
-      prec = TYPE_PRECISION (TREE_TYPE (arg));
-      mini = 0;
-      maxi = prec;
-      src.get_operand (r, arg);
-      // If arg is non-zero, then ffs or popcount are non-zero.
-      if (!range_includes_zero_p (&r))
-	mini = 1;
-      // If some high bits are known to be zero, decrease the maximum.
-      if (!r.undefined_p ())
-	{
-	  if (TYPE_SIGN (r.type ()) == SIGNED)
-	    range_cast (r, unsigned_type_for (r.type ()));
-	  wide_int max = r.upper_bound ();
-	  maxi = wi::floor_log2 (max) + 1;
-	}
-      r.set (build_int_cst (type, mini), build_int_cst (type, maxi));
-      return true;
-
     CASE_CFN_PARITY:
       r.set (build_zero_cst (type), build_one_cst (type));
       return true;
diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index 45384d990ae..84837f8ee43 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -387,6 +387,33 @@ cfn_toupper_tolower::fold_range (irange &r, tree type, const irange &lh,
   return true;
 }
 
+// Implement range operator for CFN_BUILT_IN_FFS and CFN_BUILT_IN_POPCOUNT.
+class cfn_popcount : public range_operator
+{
+public:
+  using range_operator::fold_range;
+  virtual bool fold_range (irange &r, tree type, const irange &lh,
+			   const irange &, relation_kind) const
+  {
+    if (lh.undefined_p ())
+      return false;
+    // __builtin_ffs* and __builtin_popcount* return [0, prec].
+    int prec = TYPE_PRECISION (lh.type ());
+    // If arg is non-zero, then ffs or popcount are non-zero.
+    int mini = range_includes_zero_p (&lh) ? 0 : 1;
+    int maxi = prec;
+
+    // If some high bits are known to be zero, decrease the maximum.
+    int_range_max tmp = lh;
+    if (TYPE_SIGN (tmp.type ()) == SIGNED)
+      range_cast (tmp, unsigned_type_for (tmp.type ()));
+    wide_int max = tmp.upper_bound ();
+    maxi = wi::floor_log2 (max) + 1;
+    r.set (build_int_cst (type, mini), build_int_cst (type, maxi));
+    return true;
+  }
+} op_cfn_popcount;
+
 // Set up a gimple_range_op_handler for any built in function which can be
 // supported via range-ops.
 
@@ -435,6 +462,13 @@ gimple_range_op_handler::maybe_builtin_call ()
 	}
       break;
 
+    CASE_CFN_FFS:
+    CASE_CFN_POPCOUNT:
+      m_op1 = gimple_call_arg (call, 0);
+      m_int = &op_cfn_popcount;
+      m_valid = true;
+      break;
+
     default:
       break;
     }
-- 
2.37.3


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 11/17] Convert CFN_CLZ builtins to range-ops.
  2022-09-22 18:49 [PATCH 00/17] Move builtin functions to range-ops Andrew MacLeod
                   ` (9 preceding siblings ...)
  2022-09-22 19:05 ` [PATCH 10/17] Convert CFN_BUILT_FFS and CFN_POPCOUNT " Andrew MacLeod
@ 2022-09-22 19:05 ` Andrew MacLeod
  2022-09-22 19:05 ` [PATCH 12/17] Convert CFN_CTZ " Andrew MacLeod
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Andrew MacLeod @ 2022-09-22 19:05 UTC (permalink / raw)
  To: gcc-patches; +Cc: hernandez, aldy

[-- Attachment #1: Type: text/plain, Size: 76 bytes --]

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

Andrew


[-- Attachment #2: 0011-Convert-CFN_CLZ-builtins-to-range-ops.patch --]
[-- Type: text/x-patch, Size: 5823 bytes --]

From ae1669a98656cca594fcd2fef6bd2cd7308a361f Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Tue, 20 Sep 2022 18:12:25 -0400
Subject: [PATCH 11/17] Convert CFN_CLZ builtins to range-ops.

	* gimple-range-fold.cc (range_of_builtin_int_call): Remove case
	for CFN_CLZ.
	* gimple-range-op.cc (class cfn_clz): New.
	(gimple_range_op_handler::maybe_builtin_call): Set arguments.
---
 gcc/gimple-range-fold.cc | 61 -----------------------------
 gcc/gimple-range-op.cc   | 84 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 84 insertions(+), 61 deletions(-)

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index ca531037e13..63eaa90be96 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -926,67 +926,6 @@ fold_using_range::range_of_builtin_int_call (irange &r, gcall *call,
       r.set (build_zero_cst (type), build_one_cst (type));
       return true;
 
-    CASE_CFN_CLZ:
-      // __builtin_c[lt]z* return [0, prec-1], except when the
-      // argument is 0, but that is undefined behavior.
-      //
-      // For __builtin_c[lt]z* consider argument of 0 always undefined
-      // behavior, for internal fns depending on C?Z_DEFINED_VALUE_AT_ZERO.
-      arg = gimple_call_arg (call, 0);
-      prec = TYPE_PRECISION (TREE_TYPE (arg));
-      mini = 0;
-      maxi = prec - 1;
-      mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg));
-      if (gimple_call_internal_p (call))
-	{
-	  if (optab_handler (clz_optab, mode) != CODE_FOR_nothing
-	      && CLZ_DEFINED_VALUE_AT_ZERO (mode, zerov) == 2)
-	    {
-	      // Only handle the single common value.
-	      if (zerov == prec)
-		maxi = prec;
-	      else
-		// Magic value to give up, unless we can prove arg is non-zero.
-		mini = -2;
-	    }
-	}
-
-      src.get_operand (r, arg);
-      // From clz of minimum we can compute result maximum.
-      if (!r.undefined_p ())
-	{
-	  // From clz of minimum we can compute result maximum.
-	  if (wi::gt_p (r.lower_bound (), 0, TYPE_SIGN (r.type ())))
-	    {
-	      maxi = prec - 1 - wi::floor_log2 (r.lower_bound ());
-	      if (mini == -2)
-		mini = 0;
-	    }
-	  else if (!range_includes_zero_p (&r))
-	    {
-	      mini = 0;
-	      maxi = prec - 1;
-	    }
-	  if (mini == -2)
-	    break;
-	  // From clz of maximum we can compute result minimum.
-	  wide_int max = r.upper_bound ();
-	  int newmini = prec - 1 - wi::floor_log2 (max);
-	  if (max == 0)
-	    {
-	      // If CLZ_DEFINED_VALUE_AT_ZERO is 2 with VALUE of prec,
-	      // return [prec, prec], otherwise ignore the range.
-	      if (maxi == prec)
-		mini = prec;
-	    }
-	  else
-	    mini = newmini;
-	}
-      if (mini == -2)
-	break;
-      r.set (build_int_cst (type, mini), build_int_cst (type, maxi));
-      return true;
-
     CASE_CFN_CTZ:
       // __builtin_ctz* return [0, prec-1], except for when the
       // argument is 0, but that is undefined behavior.
diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index 84837f8ee43..caba49309f9 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -414,6 +414,81 @@ public:
   }
 } op_cfn_popcount;
 
+// Implement range operator for CFN_BUILT_IN_CLZ
+class cfn_clz : public range_operator
+{
+public:
+  cfn_clz (bool internal) { m_gimple_call_internal_p = internal; }
+  using range_operator::fold_range;
+  virtual bool fold_range (irange &r, tree type, const irange &lh,
+			   const irange &, relation_kind) const;
+private:
+  bool m_gimple_call_internal_p;
+} op_cfn_clz (false), op_cfn_clz_internal (true);
+
+bool
+cfn_clz::fold_range (irange &r, tree type, const irange &lh,
+		     const irange &, relation_kind) const
+{
+  // __builtin_c[lt]z* return [0, prec-1], except when the
+  // argument is 0, but that is undefined behavior.
+  //
+  // For __builtin_c[lt]z* consider argument of 0 always undefined
+  // behavior, for internal fns depending on C?Z_DEFINED_ALUE_AT_ZERO.
+  if (lh.undefined_p ())
+    return false;
+  int prec = TYPE_PRECISION (lh.type ());
+  int mini = 0;
+  int maxi = prec - 1;
+  int zerov = 0;
+  scalar_int_mode mode = SCALAR_INT_TYPE_MODE (lh.type ());
+  if (m_gimple_call_internal_p)
+    {
+      if (optab_handler (clz_optab, mode) != CODE_FOR_nothing
+	  && CLZ_DEFINED_VALUE_AT_ZERO (mode, zerov) == 2)
+	{
+	  // Only handle the single common value.
+	  if (zerov == prec)
+	    maxi = prec;
+	  else
+	    // Magic value to give up, unless we can prove arg is non-zero.
+	    mini = -2;
+	}
+    }
+
+  // From clz of minimum we can compute result maximum.
+  if (wi::gt_p (lh.lower_bound (), 0, TYPE_SIGN (lh.type ())))
+    {
+      maxi = prec - 1 - wi::floor_log2 (lh.lower_bound ());
+      if (mini == -2)
+	mini = 0;
+    }
+  else if (!range_includes_zero_p (&lh))
+    {
+      mini = 0;
+      maxi = prec - 1;
+    }
+  if (mini == -2)
+    return false;
+  // From clz of maximum we can compute result minimum.
+  wide_int max = lh.upper_bound ();
+  int newmini = prec - 1 - wi::floor_log2 (max);
+  if (max == 0)
+    {
+      // If CLZ_DEFINED_VALUE_AT_ZERO is 2 with VALUE of prec,
+      // return [prec, prec], otherwise ignore the range.
+      if (maxi == prec)
+	mini = prec;
+    }
+  else
+    mini = newmini;
+
+  if (mini == -2)
+    return false;
+  r.set (build_int_cst (type, mini), build_int_cst (type, maxi));
+  return true;
+}
+
 // Set up a gimple_range_op_handler for any built in function which can be
 // supported via range-ops.
 
@@ -469,6 +544,15 @@ gimple_range_op_handler::maybe_builtin_call ()
       m_valid = true;
       break;
 
+    CASE_CFN_CLZ:
+      m_op1 = gimple_call_arg (call, 0);
+      m_valid = true;
+      if (gimple_call_internal_p (call))
+	m_int = &op_cfn_clz_internal;
+      else
+	m_int = &op_cfn_clz;
+      break;
+
     default:
       break;
     }
-- 
2.37.3


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 12/17] Convert CFN_CTZ builtins to range-ops.
  2022-09-22 18:49 [PATCH 00/17] Move builtin functions to range-ops Andrew MacLeod
                   ` (10 preceding siblings ...)
  2022-09-22 19:05 ` [PATCH 11/17] Convert CFN_CLZ builtins " Andrew MacLeod
@ 2022-09-22 19:05 ` Andrew MacLeod
  2022-09-22 19:06 ` [PATCH 13/17] Convert CFN_BUILT_IN_CLRSB " Andrew MacLeod
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Andrew MacLeod @ 2022-09-22 19:05 UTC (permalink / raw)
  To: gcc-patches; +Cc: hernandez, aldy

[-- Attachment #1: Type: text/plain, Size: 75 bytes --]

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

Andrew

[-- Attachment #2: 0012-Convert-CFN_CTZ-builtins-to-range-ops.patch --]
[-- Type: text/x-patch, Size: 5945 bytes --]

From 55738d8d96bb4f39a72cf5e3739d35b39fc2146a Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Tue, 20 Sep 2022 18:19:30 -0400
Subject: [PATCH 12/17] Convert CFN_CTZ builtins to range-ops.

	* gimple-range-fold.cc (range_of_builtin_int_call): Remove case
	for CFN_CTZ.
	* gimple-range-op.cc (class cfn_ctz): New.
	(gimple_range_op_handler::maybe_builtin_call): Set arguments.
---
 gcc/gimple-range-fold.cc | 61 +------------------------------
 gcc/gimple-range-op.cc   | 79 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 80 insertions(+), 60 deletions(-)

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index 63eaa90be96..96a138a7a02 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -917,7 +917,7 @@ fold_using_range::range_of_builtin_int_call (irange &r, gcall *call,
 
   tree type = gimple_range_type (call);
   tree arg;
-  int mini, maxi, zerov = 0, prec;
+  int prec;
   scalar_int_mode mode;
 
   switch (func)
@@ -926,65 +926,6 @@ fold_using_range::range_of_builtin_int_call (irange &r, gcall *call,
       r.set (build_zero_cst (type), build_one_cst (type));
       return true;
 
-    CASE_CFN_CTZ:
-      // __builtin_ctz* return [0, prec-1], except for when the
-      // argument is 0, but that is undefined behavior.
-      //
-      // For __builtin_ctz* consider argument of 0 always undefined
-      // behavior, for internal fns depending on CTZ_DEFINED_VALUE_AT_ZERO.
-      arg = gimple_call_arg (call, 0);
-      prec = TYPE_PRECISION (TREE_TYPE (arg));
-      mini = 0;
-      maxi = prec - 1;
-      mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg));
-      if (gimple_call_internal_p (call))
-	{
-	  if (optab_handler (ctz_optab, mode) != CODE_FOR_nothing
-	      && CTZ_DEFINED_VALUE_AT_ZERO (mode, zerov) == 2)
-	    {
-	      // Handle only the two common values.
-	      if (zerov == -1)
-		mini = -1;
-	      else if (zerov == prec)
-		maxi = prec;
-	      else
-		// Magic value to give up, unless we can prove arg is non-zero.
-		mini = -2;
-	    }
-	}
-      src.get_operand (r, arg);
-      if (!r.undefined_p ())
-	{
-	  // If arg is non-zero, then use [0, prec - 1].
-	  if (!range_includes_zero_p (&r))
-	    {
-	      mini = 0;
-	      maxi = prec - 1;
-	    }
-	  // If some high bits are known to be zero, we can decrease
-	  // the maximum.
-	  wide_int max = r.upper_bound ();
-	  if (max == 0)
-	    {
-	      // Argument is [0, 0].  If CTZ_DEFINED_VALUE_AT_ZERO
-	      // is 2 with value -1 or prec, return [-1, -1] or [prec, prec].
-	      // Otherwise ignore the range.
-	      if (mini == -1)
-		maxi = -1;
-	      else if (maxi == prec)
-		mini = prec;
-	    }
-	  // If value at zero is prec and 0 is in the range, we can't lower
-	  // the upper bound.  We could create two separate ranges though,
-	  // [0,floor_log2(max)][prec,prec] though.
-	  else if (maxi != prec)
-	    maxi = wi::floor_log2 (max);
-	}
-      if (mini == -2)
-	break;
-      r.set (build_int_cst (type, mini), build_int_cst (type, maxi));
-      return true;
-
     CASE_CFN_CLRSB:
       arg = gimple_call_arg (call, 0);
       prec = TYPE_PRECISION (TREE_TYPE (arg));
diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index caba49309f9..801c2bb235e 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -489,6 +489,76 @@ cfn_clz::fold_range (irange &r, tree type, const irange &lh,
   return true;
 }
 
+// Implement range operator for CFN_BUILT_IN_CTZ
+class cfn_ctz : public range_operator
+{
+public:
+  cfn_ctz (bool internal) { m_gimple_call_internal_p = internal; }
+  using range_operator::fold_range;
+  virtual bool fold_range (irange &r, tree type, const irange &lh,
+			   const irange &, relation_kind) const;
+private:
+  bool m_gimple_call_internal_p;
+} op_cfn_ctz (false), op_cfn_ctz_internal (true);
+
+bool
+cfn_ctz::fold_range (irange &r, tree type, const irange &lh,
+		     const irange &, relation_kind) const
+{
+  if (lh.undefined_p ())
+    return false;
+  int prec = TYPE_PRECISION (lh.type ());
+  int mini = 0;
+  int maxi = prec - 1;
+  int zerov = 0;
+  scalar_int_mode mode = SCALAR_INT_TYPE_MODE (lh.type ());
+
+  if (m_gimple_call_internal_p)
+    {
+      if (optab_handler (ctz_optab, mode) != CODE_FOR_nothing
+	  && CTZ_DEFINED_VALUE_AT_ZERO (mode, zerov) == 2)
+	{
+	  // Handle only the two common values.
+	  if (zerov == -1)
+	    mini = -1;
+	  else if (zerov == prec)
+	    maxi = prec;
+	  else
+	    // Magic value to give up, unless we can prove arg is non-zero.
+	    mini = -2;
+	}
+    }
+  // If arg is non-zero, then use [0, prec - 1].
+  if (!range_includes_zero_p (&lh))
+    {
+      mini = 0;
+      maxi = prec - 1;
+    }
+  // If some high bits are known to be zero, we can decrease
+  // the maximum.
+  wide_int max = lh.upper_bound ();
+  if (max == 0)
+    {
+      // Argument is [0, 0].  If CTZ_DEFINED_VALUE_AT_ZERO
+      // is 2 with value -1 or prec, return [-1, -1] or [prec, prec].
+      // Otherwise ignore the range.
+      if (mini == -1)
+	maxi = -1;
+      else if (maxi == prec)
+	mini = prec;
+    }
+  // If value at zero is prec and 0 is in the range, we can't lower
+  // the upper bound.  We could create two separate ranges though,
+  // [0,floor_log2(max)][prec,prec] though.
+  else if (maxi != prec)
+    maxi = wi::floor_log2 (max);
+
+  if (mini == -2)
+    return false;
+  r.set (build_int_cst (type, mini), build_int_cst (type, maxi));
+  return true;
+}
+
 // Set up a gimple_range_op_handler for any built in function which can be
 // supported via range-ops.
 
@@ -553,6 +623,15 @@ gimple_range_op_handler::maybe_builtin_call ()
 	m_int = &op_cfn_clz;
       break;
 
+    CASE_CFN_CTZ:
+      m_op1 = gimple_call_arg (call, 0);
+      m_valid = true;
+      if (gimple_call_internal_p (call))
+	m_int = &op_cfn_ctz_internal;
+      else
+	m_int = &op_cfn_ctz;
+      break;
+
     default:
       break;
     }
-- 
2.37.3


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 13/17] Convert CFN_BUILT_IN_CLRSB to range-ops.
  2022-09-22 18:49 [PATCH 00/17] Move builtin functions to range-ops Andrew MacLeod
                   ` (11 preceding siblings ...)
  2022-09-22 19:05 ` [PATCH 12/17] Convert CFN_CTZ " Andrew MacLeod
@ 2022-09-22 19:06 ` Andrew MacLeod
  2022-09-22 19:06 ` [PATCH 14/17] Convert CFN_BUILT_IN_UBSAN_CHECK_* " Andrew MacLeod
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Andrew MacLeod @ 2022-09-22 19:06 UTC (permalink / raw)
  To: gcc-patches; +Cc: hernandez, aldy

[-- Attachment #1: Type: text/plain, Size: 77 bytes --]

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

Andrew

[-- Attachment #2: 0013-Convert-CFN_BUILT_IN_CLRSB-to-range-ops.patch --]
[-- Type: text/x-patch, Size: 2553 bytes --]

From f7e62b09300b6935bceaffb4c42f6edab80f52dc Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Tue, 20 Sep 2022 18:21:04 -0400
Subject: [PATCH 13/17] Convert CFN_BUILT_IN_CLRSB to range-ops.

	* gimple-range-fold.cc (range_of_builtin_int_call): Remove case
	for CFN_BUILT_IN_CLRSB.
	* gimple-range-op.cc (class cfn_clrsb): New.
	(gimple_range_op_handler::maybe_builtin_call): Set arguments.
---
 gcc/gimple-range-fold.cc |  7 -------
 gcc/gimple-range-op.cc   | 23 +++++++++++++++++++++++
 2 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index 96a138a7a02..1d7d1da7bbe 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -916,8 +916,6 @@ fold_using_range::range_of_builtin_int_call (irange &r, gcall *call,
     return false;
 
   tree type = gimple_range_type (call);
-  tree arg;
-  int prec;
   scalar_int_mode mode;
 
   switch (func)
@@ -926,11 +924,6 @@ fold_using_range::range_of_builtin_int_call (irange &r, gcall *call,
       r.set (build_zero_cst (type), build_one_cst (type));
       return true;
 
-    CASE_CFN_CLRSB:
-      arg = gimple_call_arg (call, 0);
-      prec = TYPE_PRECISION (TREE_TYPE (arg));
-      r.set (build_int_cst (type, 0), build_int_cst (type, prec - 1));
-      return true;
     case CFN_UBSAN_CHECK_ADD:
       range_of_builtin_ubsan_call (r, call, PLUS_EXPR, src);
       return true;
diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index 801c2bb235e..bee225431e8 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -559,6 +559,23 @@ cfn_ctz::fold_range (irange &r, tree type, const irange &lh,
   return true;
 }
 
+
+// Implement range operator for CFN_BUILT_IN_
+class cfn_clrsb : public range_operator
+{
+public:
+  using range_operator::fold_range;
+  virtual bool fold_range (irange &r, tree type, const irange &lh,
+			   const irange &, relation_kind) const
+  {
+    if (lh.undefined_p ())
+      return false;
+    int prec = TYPE_PRECISION (lh.type ());
+    r.set (build_int_cst (type, 0), build_int_cst (type, prec - 1));
+    return true;
+  }
+} op_cfn_clrsb;
+
 // Set up a gimple_range_op_handler for any built in function which can be
 // supported via range-ops.
 
@@ -632,6 +649,12 @@ gimple_range_op_handler::maybe_builtin_call ()
 	m_int = &op_cfn_ctz;
       break;
 
+    CASE_CFN_CLRSB:
+      m_op1 = gimple_call_arg (call, 0);
+      m_valid = true;
+      m_int = &op_cfn_clrsb;
+      break;
+
     default:
       break;
     }
-- 
2.37.3


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 14/17] Convert CFN_BUILT_IN_UBSAN_CHECK_* to range-ops.
  2022-09-22 18:49 [PATCH 00/17] Move builtin functions to range-ops Andrew MacLeod
                   ` (12 preceding siblings ...)
  2022-09-22 19:06 ` [PATCH 13/17] Convert CFN_BUILT_IN_CLRSB " Andrew MacLeod
@ 2022-09-22 19:06 ` Andrew MacLeod
  2022-09-22 19:08 ` [PATCH 15/17] Convert CFN_BUILT_IN_STRLEN " Andrew MacLeod
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Andrew MacLeod @ 2022-09-22 19:06 UTC (permalink / raw)
  To: gcc-patches; +Cc: hernandez, aldy

[-- Attachment #1: Type: text/plain, Size: 78 bytes --]

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

Andrew

[-- Attachment #2: 0014-Convert-CFN_BUILT_IN_UBSAN_CHECK_-to-range-ops.patch --]
[-- Type: text/x-patch, Size: 5516 bytes --]

From b6f670ff706e35dc51a62db4206cb241dcac4963 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Tue, 20 Sep 2022 18:48:05 -0400
Subject: [PATCH 14/17] Convert CFN_BUILT_IN_UBSAN_CHECK_* to range-ops.

	* gimple-range-fold.cc (range_of_builtin_ubsan_call): Delete.
	(range_of_builtin_int_call): Remove cases for
	CFN_BUILT_IN_UBSAN_CHECK.
	* gimple-range-op.cc (class cfn_ubsan): New.
	(gimple_range_op_handler::maybe_builtin_call): Set arguments.
---
 gcc/gimple-range-fold.cc | 47 +--------------------------------
 gcc/gimple-range-op.cc   | 56 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 57 insertions(+), 46 deletions(-)

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index 1d7d1da7bbe..d445270417a 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -852,41 +852,6 @@ fold_using_range::range_of_call (vrange &r, gcall *call, fur_source &src)
   return true;
 }
 
-// Return the range of a __builtin_ubsan* in CALL and set it in R.
-// CODE is the type of ubsan call (PLUS_EXPR, MINUS_EXPR or
-// MULT_EXPR).
-
-void
-fold_using_range::range_of_builtin_ubsan_call (irange &r, gcall *call,
-					       tree_code code, fur_source &src)
-{
-  gcc_checking_assert (code == PLUS_EXPR || code == MINUS_EXPR
-		       || code == MULT_EXPR);
-  tree type = gimple_range_type (call);
-  range_op_handler op (code, type);
-  gcc_checking_assert (op);
-  int_range_max ir0, ir1;
-  tree arg0 = gimple_call_arg (call, 0);
-  tree arg1 = gimple_call_arg (call, 1);
-  src.get_operand (ir0, arg0);
-  src.get_operand (ir1, arg1);
-  // Check for any relation between arg0 and arg1.
-  relation_kind relation = src.query_relation (arg0, arg1);
-
-  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;
-  op.fold_range (r, type, ir0, ir1, relation);
-  flag_wrapv = saved_flag_wrapv;
-
-  // If for both arguments vrp_valueize returned non-NULL, this should
-  // have been already folded and if not, it wasn't folded because of
-  // overflow.  Avoid removing the UBSAN_CHECK_* calls in that case.
-  if (r.singleton_p ())
-    r.set_varying (type);
-}
-
 // For a builtin in CALL, return a range in R if known and return
 // TRUE.  Otherwise return FALSE.
 
@@ -909,7 +874,7 @@ fold_using_range::range_of_builtin_call (vrange &r, gcall *call,
 
 bool
 fold_using_range::range_of_builtin_int_call (irange &r, gcall *call,
-					     fur_source &src)
+					     fur_source &)
 {
   combined_fn func = gimple_call_combined_fn (call);
   if (func == CFN_LAST)
@@ -924,16 +889,6 @@ fold_using_range::range_of_builtin_int_call (irange &r, gcall *call,
       r.set (build_zero_cst (type), build_one_cst (type));
       return true;
 
-    case CFN_UBSAN_CHECK_ADD:
-      range_of_builtin_ubsan_call (r, call, PLUS_EXPR, src);
-      return true;
-    case CFN_UBSAN_CHECK_SUB:
-      range_of_builtin_ubsan_call (r, call, MINUS_EXPR, src);
-      return true;
-    case CFN_UBSAN_CHECK_MUL:
-      range_of_builtin_ubsan_call (r, call, MULT_EXPR, src);
-      return true;
-
     case CFN_GOACC_DIM_SIZE:
     case CFN_GOACC_DIM_POS:
       // Optimizing these two internal functions helps the loop
diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index bee225431e8..09b7dd2add3 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -576,6 +576,41 @@ public:
   }
 } op_cfn_clrsb;
 
+
+// Implement range operator for CFN_BUILT_IN_
+class cfn_ubsan : public range_operator
+{
+public:
+  cfn_ubsan (enum tree_code code) { m_code = code; }
+  using range_operator::fold_range;
+  virtual bool fold_range (irange &r, tree type, const irange &lh,
+			   const irange &rh, relation_kind rel) const
+  {
+    range_op_handler handler (m_code, type);
+    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);
+    flag_wrapv = saved_flag_wrapv;
+
+    // If for both arguments vrp_valueize returned non-NULL, this should
+    // have been already folded and if not, it wasn't folded because of
+    // overflow.  Avoid removing the UBSAN_CHECK_* calls in that case.
+    if (result && r.singleton_p ())
+      r.set_varying (type);
+    return result;
+  }
+private:
+  enum tree_code m_code;
+};
+
+cfn_ubsan op_cfn_ubsan_add (PLUS_EXPR);
+cfn_ubsan op_cfn_ubsan_sub (MINUS_EXPR);
+cfn_ubsan op_cfn_ubsan_mul (MULT_EXPR);
+
 // Set up a gimple_range_op_handler for any built in function which can be
 // supported via range-ops.
 
@@ -655,6 +690,27 @@ gimple_range_op_handler::maybe_builtin_call ()
       m_int = &op_cfn_clrsb;
       break;
 
+    case CFN_UBSAN_CHECK_ADD:
+      m_op1 = gimple_call_arg (call, 0);
+      m_op2 = gimple_call_arg (call, 1);
+      m_valid = true;
+      m_int = &op_cfn_ubsan_add;
+      break;
+
+    case CFN_UBSAN_CHECK_SUB:
+      m_op1 = gimple_call_arg (call, 0);
+      m_op2 = gimple_call_arg (call, 1);
+      m_valid = true;
+      m_int = &op_cfn_ubsan_sub;
+      break;
+
+    case CFN_UBSAN_CHECK_MUL:
+      m_op1 = gimple_call_arg (call, 0);
+      m_op2 = gimple_call_arg (call, 1);
+      m_valid = true;
+      m_int = &op_cfn_ubsan_mul;
+      break;
+
     default:
       break;
     }
-- 
2.37.3


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 15/17] Convert CFN_BUILT_IN_STRLEN to range-ops.
  2022-09-22 18:49 [PATCH 00/17] Move builtin functions to range-ops Andrew MacLeod
                   ` (13 preceding siblings ...)
  2022-09-22 19:06 ` [PATCH 14/17] Convert CFN_BUILT_IN_UBSAN_CHECK_* " Andrew MacLeod
@ 2022-09-22 19:08 ` Andrew MacLeod
  2022-09-22 19:10 ` [PATCH 16/17] Convert CFN_BUILT_IN_GOACC_DIM_* " Andrew MacLeod
  2022-09-22 19:10 ` [PATCH 17/17] Convert CFN_BUILT_IN_PARITY " Andrew MacLeod
  16 siblings, 0 replies; 18+ messages in thread
From: Andrew MacLeod @ 2022-09-22 19:08 UTC (permalink / raw)
  To: gcc-patches; +Cc: hernandez, aldy

[-- Attachment #1: Type: text/plain, Size: 75 bytes --]

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

Andrew

[-- Attachment #2: 0015-Convert-CFN_BUILT_IN_STRLEN-to-range-ops.patch --]
[-- Type: text/x-patch, Size: 3470 bytes --]

From c750e675cb77f283ff991682db7740bc5f6d4cf4 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Tue, 20 Sep 2022 19:05:03 -0400
Subject: [PATCH 15/17] Convert CFN_BUILT_IN_STRLEN to range-ops.

	* gimple-range-fold.cc (range_of_builtin_int_call): Remove case
	for CFN_BUILT_IN_STRLEN.
	* gimple-range-op.cc (class cfn_strlen): New.
	(gimple_range_op_handler::maybe_builtin_call): Set arguments.
---
 gcc/gimple-range-fold.cc | 21 ---------------------
 gcc/gimple-range-op.cc   | 37 +++++++++++++++++++++++++++++++++++++
 2 files changed, 37 insertions(+), 21 deletions(-)

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index d445270417a..d22fb0e9352 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -908,27 +908,6 @@ fold_using_range::range_of_builtin_int_call (irange &r, gcall *call,
 	return true;
       }
 
-    case CFN_BUILT_IN_STRLEN:
-      if (tree lhs = gimple_call_lhs (call))
-	if (ptrdiff_type_node
-	    && (TYPE_PRECISION (ptrdiff_type_node)
-		== TYPE_PRECISION (TREE_TYPE (lhs))))
-	  {
-	    tree type = TREE_TYPE (lhs);
-	    tree max = vrp_val_max (ptrdiff_type_node);
-	    wide_int wmax
-	      = wi::to_wide (max, TYPE_PRECISION (TREE_TYPE (max)));
-	    tree range_min = build_zero_cst (type);
-	    // To account for the terminating NULL, the maximum length
-	    // is one less than the maximum array size, which in turn
-	    // is one less than PTRDIFF_MAX (or SIZE_MAX where it's
-	    // smaller than the former type).
-	    // FIXME: Use max_object_size() - 1 here.
-	    tree range_max = wide_int_to_tree (type, wmax - 2);
-	    r.set (range_min, range_max);
-	    return true;
-	  }
-      break;
     default:
       break;
     }
diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index 09b7dd2add3..f9161b5820f 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -611,6 +611,30 @@ cfn_ubsan op_cfn_ubsan_add (PLUS_EXPR);
 cfn_ubsan op_cfn_ubsan_sub (MINUS_EXPR);
 cfn_ubsan op_cfn_ubsan_mul (MULT_EXPR);
 
+
+// Implement range operator for CFN_BUILT_IN_STRLEN
+class cfn_strlen : public range_operator
+{
+public:
+  using range_operator::fold_range;
+  virtual bool fold_range (irange &r, tree type, const irange &,
+			   const irange &, relation_kind) const
+  {
+    tree max = vrp_val_max (ptrdiff_type_node);
+    wide_int wmax
+      = wi::to_wide (max, TYPE_PRECISION (TREE_TYPE (max)));
+    tree range_min = build_zero_cst (type);
+    // To account for the terminating NULL, the maximum length
+    // is one less than the maximum array size, which in turn
+    // is one less than PTRDIFF_MAX (or SIZE_MAX where it's
+    // smaller than the former type).
+    // FIXME: Use max_object_size() - 1 here.
+    tree range_max = wide_int_to_tree (type, wmax - 2);
+    r.set (range_min, range_max);
+    return true;
+  }
+} op_cfn_strlen;
+
 // Set up a gimple_range_op_handler for any built in function which can be
 // supported via range-ops.
 
@@ -711,6 +735,19 @@ gimple_range_op_handler::maybe_builtin_call ()
       m_int = &op_cfn_ubsan_mul;
       break;
 
+    case CFN_BUILT_IN_STRLEN:
+      {
+	tree lhs = gimple_call_lhs (call);
+	if (lhs && ptrdiff_type_node && (TYPE_PRECISION (ptrdiff_type_node)
+					 == TYPE_PRECISION (TREE_TYPE (lhs))))
+	  {
+	    m_op1 = gimple_call_arg (call, 0);
+	    m_valid = true;
+	    m_int = &op_cfn_strlen;
+	  }
+	break;
+      }
+
     default:
       break;
     }
-- 
2.37.3


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 16/17] Convert CFN_BUILT_IN_GOACC_DIM_* to range-ops.
  2022-09-22 18:49 [PATCH 00/17] Move builtin functions to range-ops Andrew MacLeod
                   ` (14 preceding siblings ...)
  2022-09-22 19:08 ` [PATCH 15/17] Convert CFN_BUILT_IN_STRLEN " Andrew MacLeod
@ 2022-09-22 19:10 ` Andrew MacLeod
  2022-09-22 19:10 ` [PATCH 17/17] Convert CFN_BUILT_IN_PARITY " Andrew MacLeod
  16 siblings, 0 replies; 18+ messages in thread
From: Andrew MacLeod @ 2022-09-22 19:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: hernandez, aldy

[-- Attachment #1: Type: text/plain, Size: 74 bytes --]

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

Andrew

[-- Attachment #2: 0016-Convert-CFN_BUILT_IN_GOACC_DIM_-to-range-ops.patch --]
[-- Type: text/x-patch, Size: 3647 bytes --]

From e7f035f66aa25e0537a0e3a76d43c71fe9531724 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Tue, 20 Sep 2022 19:19:30 -0400
Subject: [PATCH 16/17] Convert CFN_BUILT_IN_GOACC_DIM_* to range-ops.

	* gimple-range-fold.cc (range_of_builtin_int_call): Remove case
	for CFN_GOACC_DIM_*.
	* gimple-range-op.cc (class cfn_goacc_dim): New.
	(gimple_range_op_handler::maybe_builtin_call): Set arguments.
---
 gcc/gimple-range-fold.cc | 19 ----------------
 gcc/gimple-range-op.cc   | 47 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+), 19 deletions(-)

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index d22fb0e9352..5e8a13e7337 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -889,25 +889,6 @@ fold_using_range::range_of_builtin_int_call (irange &r, gcall *call,
       r.set (build_zero_cst (type), build_one_cst (type));
       return true;
 
-    case CFN_GOACC_DIM_SIZE:
-    case CFN_GOACC_DIM_POS:
-      // Optimizing these two internal functions helps the loop
-      // optimizer eliminate outer comparisons.  Size is [1,N]
-      // and pos is [0,N-1].
-      {
-	bool is_pos = func == CFN_GOACC_DIM_POS;
-	int axis = oacc_get_ifn_dim_arg (call);
-	int size = oacc_get_fn_dim_size (current_function_decl, axis);
-	if (!size)
-	  // If it's dynamic, the backend might know a hardware limitation.
-	  size = targetm.goacc.dim_limit (axis);
-
-	r.set (build_int_cst (type, is_pos ? 0 : 1),
-	       size
-	       ? build_int_cst (type, size - is_pos) : vrp_val_max (type));
-	return true;
-      }
-
     default:
       break;
     }
diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index f9161b5820f..76295466e65 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -635,6 +635,34 @@ public:
   }
 } op_cfn_strlen;
 
+
+// Implement range operator for CFN_BUILT_IN_GOACC_DIM
+class cfn_goacc_dim : public range_operator
+{
+public:
+  cfn_goacc_dim (bool is_pos) { m_is_pos = is_pos; }
+  using range_operator::fold_range;
+  virtual bool fold_range (irange &r, tree type, const irange &lh,
+			   const irange &, relation_kind) const
+  {
+    tree axis_tree;
+    if (!lh.singleton_p (&axis_tree))
+      return false;
+    HOST_WIDE_INT axis = TREE_INT_CST_LOW (axis_tree);
+    int size = oacc_get_fn_dim_size (current_function_decl, axis);
+    if (!size)
+      // If it's dynamic, the backend might know a hardware limitation.
+      size = targetm.goacc.dim_limit (axis);
+
+    r.set (build_int_cst (type, m_is_pos ? 0 : 1),
+	   size
+	   ? build_int_cst (type, size - m_is_pos) : vrp_val_max (type));
+    return true;
+  }
+private:
+  bool m_is_pos;
+} op_cfn_goacc_dim_size (false), op_cfn_goacc_dim_pos (true);
+
 // Set up a gimple_range_op_handler for any built in function which can be
 // supported via range-ops.
 
@@ -748,6 +776,25 @@ gimple_range_op_handler::maybe_builtin_call ()
 	break;
       }
 
+    // Optimizing these two internal functions helps the loop
+    // optimizer eliminate outer comparisons.  Size is [1,N]
+    // and pos is [0,N-1].
+    case CFN_GOACC_DIM_SIZE:
+      // This call will ensure all the asserts are triggered.
+      oacc_get_ifn_dim_arg (call);
+      m_op1 = gimple_call_arg (call, 0);
+      m_valid = true;
+      m_int = &op_cfn_goacc_dim_size;
+      break;
+
+    case CFN_GOACC_DIM_POS:
+      // This call will ensure all the asserts are triggered.
+      oacc_get_ifn_dim_arg (call);
+      m_op1 = gimple_call_arg (call, 0);
+      m_valid = true;
+      m_int = &op_cfn_goacc_dim_pos;
+      break;
+
     default:
       break;
     }
-- 
2.37.3


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 17/17] Convert CFN_BUILT_IN_PARITY to range-ops.
  2022-09-22 18:49 [PATCH 00/17] Move builtin functions to range-ops Andrew MacLeod
                   ` (15 preceding siblings ...)
  2022-09-22 19:10 ` [PATCH 16/17] Convert CFN_BUILT_IN_GOACC_DIM_* " Andrew MacLeod
@ 2022-09-22 19:10 ` Andrew MacLeod
  16 siblings, 0 replies; 18+ messages in thread
From: Andrew MacLeod @ 2022-09-22 19:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: hernandez, aldy

[-- Attachment #1: Type: text/plain, Size: 188 bytes --]


Also, as the last builtin remaining, also remove the builtin 
infrastructure routines from fold_using_range.


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

Andrew


[-- Attachment #2: 0017-Convert-CFN_BUILT_IN_PARITY-to-range-ops.patch --]
[-- Type: text/x-patch, Size: 5405 bytes --]

From 5608e410914ebb7c8cc9fa50afc8ada3b22cbf2c Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Tue, 20 Sep 2022 19:30:46 -0400
Subject: [PATCH 17/17] Convert CFN_BUILT_IN_PARITY to range-ops.

Also, as the last builtin remaining, also remove the builtin infrastrucure
routines from fold_using_range.

	* gimple-range-fold.cc (range_of_range_op): Handle no operands.
	(range_of_call): Do not check for builtins.
	(fold_using_range::range_of_builtin_call): Delete.
	(fold_using_range::range_of_builtin_int_call): Delete.
	* gimple-range-fold.h: Adjust prototypes.
	* gimple-range-op.cc (class cfn_parity): New.
	(gimple_range_op_handler::maybe_builtin_call): Set arguments.
---
 gcc/gimple-range-fold.cc | 60 ++++++++--------------------------------
 gcc/gimple-range-fold.h  |  4 ---
 gcc/gimple-range-op.cc   | 19 +++++++++++++
 3 files changed, 31 insertions(+), 52 deletions(-)

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index 5e8a13e7337..c381ef94087 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -534,6 +534,16 @@ fold_using_range::range_of_range_op (vrange &r,
   tree lhs = handler.lhs ();
   tree op1 = handler.operand1 ();
   tree op2 = handler.operand2 ();
+
+  // Certain types of builtin functions may have no arguments.
+  if (!op1)
+    {
+      Value_Range r1 (type);
+      if (!handler.fold_range (r, type, r1, r1))
+	r.set_varying (type);
+      return true;
+    }
+
   Value_Range range1 (TREE_TYPE (op1));
   Value_Range range2 (op2 ? TREE_TYPE (op2) : TREE_TYPE (op1));
 
@@ -823,7 +833,7 @@ fold_using_range::range_of_phi (vrange &r, gphi *phi, fur_source &src)
 // If a range cannot be calculated, return false.
 
 bool
-fold_using_range::range_of_call (vrange &r, gcall *call, fur_source &src)
+fold_using_range::range_of_call (vrange &r, gcall *call, fur_source &)
 {
   tree type = gimple_range_type (call);
   if (!type)
@@ -832,9 +842,7 @@ fold_using_range::range_of_call (vrange &r, gcall *call, fur_source &src)
   tree lhs = gimple_call_lhs (call);
   bool strict_overflow_p;
 
-  if (range_of_builtin_call (r, call, src))
-    ;
-  else if (gimple_stmt_nonnegative_warnv_p (call, &strict_overflow_p))
+  if (gimple_stmt_nonnegative_warnv_p (call, &strict_overflow_p))
     r.set_nonnegative (type);
   else if (gimple_call_nonnull_result_p (call)
 	   || gimple_call_nonnull_arg (call))
@@ -852,50 +860,6 @@ fold_using_range::range_of_call (vrange &r, gcall *call, fur_source &src)
   return true;
 }
 
-// For a builtin in CALL, return a range in R if known and return
-// TRUE.  Otherwise return FALSE.
-
-bool
-fold_using_range::range_of_builtin_call (vrange &r, gcall *call,
-					 fur_source &src)
-{
-  combined_fn func = gimple_call_combined_fn (call);
-  if (func == CFN_LAST)
-    return false;
-
-  tree type = gimple_range_type (call);
-  gcc_checking_assert (type);
-
-  if (irange::supports_p (type))
-    return range_of_builtin_int_call (as_a <irange> (r), call, src);
-
-  return false;
-}
-
-bool
-fold_using_range::range_of_builtin_int_call (irange &r, gcall *call,
-					     fur_source &)
-{
-  combined_fn func = gimple_call_combined_fn (call);
-  if (func == CFN_LAST)
-    return false;
-
-  tree type = gimple_range_type (call);
-  scalar_int_mode mode;
-
-  switch (func)
-    {
-    CASE_CFN_PARITY:
-      r.set (build_zero_cst (type), build_one_cst (type));
-      return true;
-
-    default:
-      break;
-    }
-  return false;
-}
-
-
 // Calculate a range for COND_EXPR statement S and return it in R.
 // If a range cannot be calculated, return false.
 
diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h
index ce18c66b8e7..d1ed2bca80f 100644
--- a/gcc/gimple-range-fold.h
+++ b/gcc/gimple-range-fold.h
@@ -165,10 +165,6 @@ protected:
   bool range_of_call (vrange &r, gcall *call, fur_source &src);
   bool range_of_cond_expr (vrange &r, gassign* cond, fur_source &src);
   bool range_of_address (irange &r, gimple *s, fur_source &src);
-  bool range_of_builtin_call (vrange &r, gcall *call, fur_source &src);
-  bool range_of_builtin_int_call (irange &r, gcall *call, fur_source &src);
-  void range_of_builtin_ubsan_call (irange &r, gcall *call, tree_code code,
-				    fur_source &src);
   bool range_of_phi (vrange &r, gphi *phi, fur_source &src);
   void range_of_ssa_name_with_loop_info (vrange &, tree, class loop *, gphi *,
 					 fur_source &src);
diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index 76295466e65..d7c6dfa933d 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -663,6 +663,20 @@ private:
   bool m_is_pos;
 } op_cfn_goacc_dim_size (false), op_cfn_goacc_dim_pos (true);
 
+
+// Implement range operator for CFN_BUILT_IN_
+class cfn_parity : public range_operator
+{
+public:
+  using range_operator::fold_range;
+  virtual bool fold_range (irange &r, tree type, const irange &,
+			   const irange &, relation_kind) const
+  {
+    r.set (build_zero_cst (type), build_one_cst (type));
+    return true;
+  }
+} op_cfn_parity;
+
 // Set up a gimple_range_op_handler for any built in function which can be
 // supported via range-ops.
 
@@ -795,6 +809,11 @@ gimple_range_op_handler::maybe_builtin_call ()
       m_int = &op_cfn_goacc_dim_pos;
       break;
 
+    CASE_CFN_PARITY:
+      m_valid = true;
+      m_int = &op_cfn_parity;
+      break;
+
     default:
       break;
     }
-- 
2.37.3


^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2022-09-22 19:10 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-22 18:49 [PATCH 00/17] Move builtin functions to range-ops Andrew MacLeod
2022-09-22 18:53 ` [PATCH 01/17] Replace another snippet with a call to, gimple_range_ssa_names Andrew MacLeod
2022-09-22 18:55 ` [PATCH 02/17] Adjust range_op_handler to store the handler directly Andrew MacLeod
2022-09-22 18:56 ` [PATCH 03/17] Create gimple_range_op_handler in a new source file Andrew MacLeod
2022-09-22 18:58 ` [PATCH 04/17] Fix calc_op1 for undefined op2_range Andrew MacLeod
2022-09-22 18:59 ` [PATCH 05/17] Add missing float fold_range prototype for floats Andrew MacLeod
2022-09-22 19:00 ` [PATCH 06/17] Always check the return value of fold_range Andrew MacLeod
2022-09-22 19:01 ` [PATCH 07/17] Add range-ops support for builtin functions Andrew MacLeod
2022-09-22 19:02 ` [PATCH 08/17] Convert CFN_BUILT_IN_SIGNBIT to range-ops Andrew MacLeod
2022-09-22 19:05 ` [PATCH 09/17] Convert CFN_BUILT_IN_TOUPPER and TOLOWER " Andrew MacLeod
2022-09-22 19:05 ` [PATCH 10/17] Convert CFN_BUILT_FFS and CFN_POPCOUNT " Andrew MacLeod
2022-09-22 19:05 ` [PATCH 11/17] Convert CFN_CLZ builtins " Andrew MacLeod
2022-09-22 19:05 ` [PATCH 12/17] Convert CFN_CTZ " Andrew MacLeod
2022-09-22 19:06 ` [PATCH 13/17] Convert CFN_BUILT_IN_CLRSB " Andrew MacLeod
2022-09-22 19:06 ` [PATCH 14/17] Convert CFN_BUILT_IN_UBSAN_CHECK_* " Andrew MacLeod
2022-09-22 19:08 ` [PATCH 15/17] Convert CFN_BUILT_IN_STRLEN " Andrew MacLeod
2022-09-22 19:10 ` [PATCH 16/17] Convert CFN_BUILT_IN_GOACC_DIM_* " Andrew MacLeod
2022-09-22 19:10 ` [PATCH 17/17] Convert CFN_BUILT_IN_PARITY " Andrew MacLeod

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).