[COMMITTED] [frange] Revert relation handling in LTGT_EXPR.

2023-09-08 Thread Aldy Hernandez via Gcc-patches
In trying to come up with a missing testcase for commit 979e0fbf53cd,
I've realized the patch doesn't catch anything.

A relation of VREL_EQ in foperator_ltgt::fold_range() is either both
arguments the same (x LTGT_EXPR x), which we should never emit, or two
arguments that are actually the same, in which case !NAN applies, and the
whole thing can be handled as NE_EXPR further down.

The whole FP relation thing is getting a face lift shortly, thanks to
comments from both Jakub and Andrew, but there's no need in keeping
useless code around.

gcc/ChangeLog:

* range-op-float.cc (foperator_ltgt::fold_range): Do not special
case VREL_EQ nor call frelop_early_resolve.
---
 gcc/range-op-float.cc | 15 ---
 1 file changed, 15 deletions(-)

diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index 89c401e040a..cc729e12a9e 100644
--- a/gcc/range-op-float.cc
+++ b/gcc/range-op-float.cc
@@ -2206,21 +2206,6 @@ public:
   const frange , const frange ,
   relation_trio trio = TRIO_VARYING) const final override
   {
-relation_kind rel = trio.op1_op2 ();
-
-// VREL_EQ is really VREL_(UN)EQ because we could have a NAN in
-// the operands, but since LTGT_EXPR is really a NE_EXPR without
-// the NAN, VREL_EQ & LTGT_EXPR is an impossibility.
-if (rel == VREL_EQ)
-  {
-   r = range_false (type);
-   return true;
-  }
-// ...otherwise pretend we're trying to resolve a NE_EXPR and
-// everything will "just work".
-if (frelop_early_resolve (r, type, op1, op2, trio, VREL_NE))
-  return true;
-
 if (op1.known_isnan () || op2.known_isnan ())
   {
r = range_false (type);
-- 
2.41.0



[COMMITTED] [irange] Fix typo in contains_zero_p.

2023-09-07 Thread Aldy Hernandez via Gcc-patches
In the conversion of iranges to wide_int (commit cb779afeff204f), I
mistakenly made contains_zero_p() return TRUE for undefined ranges.
This means the rest of the patch was adjusted for this stupidity.

For example, we ended up doing the following, to make up for the fact
that contains_zero_p was broken:

-  if (!lhs.contains_p (build_zero_cst (lhs.type (
+  if (lhs.undefined_p () || !contains_zero_p (lhs))

This patch fixes the thinko and adjusts all callers.

In places where a caller is not checking undefined_p(), it is because
either the caller has already handled undefined ranges in the
preceeding code, or the check is superfluous.

gcc/ChangeLog:

* value-range.h (contains_zero_p): Return false for undefined ranges.
* range-op-float.cc (operator_gt::op1_op2_relation): Adjust for
contains_zero_p change above.
(operator_ge::op1_op2_relation): Same.
* range-op.cc (operator_equal::op1_op2_relation): Same.
(operator_not_equal::op1_op2_relation): Same.
(operator_lt::op1_op2_relation): Same.
(operator_le::op1_op2_relation): Same.
(operator_cast::op1_range): Same.
(set_nonzero_range_from_mask): Same.
(operator_bitwise_xor::op1_range): Same.
(operator_addr_expr::fold_range): Same.
(operator_addr_expr::op1_range): Same.
* range-op-float.cc (operator_equal::op1_op2_relation): Same.
(operator_not_equal::op1_op2_relation): Same.
(operator_lt::op1_op2_relation): Same.
(operator_le::op1_op2_relation): Same.
(operator_gt::op1_op2_relation): Same.
(operator_ge::op1_op2_relation): Same.
---
 gcc/range-op-float.cc |  8 
 gcc/range-op.cc   | 30 +++---
 gcc/value-range.h |  2 +-
 3 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index eebc73f9918..89c401e040a 100644
--- a/gcc/range-op-float.cc
+++ b/gcc/range-op-float.cc
@@ -783,7 +783,7 @@ operator_equal::op1_op2_relation (const irange , const 
frange &,
 return VREL_NE;
 
   // TRUE = op1 == op2 indicates EQ_EXPR.
-  if (lhs.undefined_p () || !contains_zero_p (lhs))
+  if (!contains_zero_p (lhs))
 return VREL_EQ;
   return VREL_VARYING;
 }
@@ -915,7 +915,7 @@ operator_not_equal::op1_op2_relation (const irange , 
const frange &,
 return VREL_EQ;
 
   // TRUE = op1 != op2  indicates NE_EXPR.
-  if (lhs.undefined_p () || !contains_zero_p (lhs))
+  if (!contains_zero_p (lhs))
 return VREL_NE;
   return VREL_VARYING;
 }
@@ -1037,7 +1037,7 @@ operator_lt::op1_op2_relation (const irange , const 
frange &,
 return VREL_GE;
 
   // TRUE = op1 < op2 indicates LT_EXPR.
-  if (lhs.undefined_p () || !contains_zero_p (lhs))
+  if (!contains_zero_p (lhs))
 return VREL_LT;
   return VREL_VARYING;
 }
@@ -1144,7 +1144,7 @@ operator_le::op1_op2_relation (const irange , const 
frange &,
 return VREL_GT;
 
   // TRUE = op1 <= op2 indicates LE_EXPR.
-  if (lhs.undefined_p () || !contains_zero_p (lhs))
+  if (!contains_zero_p (lhs))
 return VREL_LE;
   return VREL_VARYING;
 }
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 619979f2f61..33b193be7d0 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -915,7 +915,7 @@ operator_equal::op1_op2_relation (const irange , const 
irange &,
 return VREL_NE;
 
   // TRUE = op1 == op2 indicates EQ_EXPR.
-  if (lhs.undefined_p () || !contains_zero_p (lhs))
+  if (!contains_zero_p (lhs))
 return VREL_EQ;
   return VREL_VARYING;
 }
@@ -1017,7 +1017,7 @@ operator_not_equal::op1_op2_relation (const irange , 
const irange &,
 return VREL_EQ;
 
   // TRUE = op1 != op2  indicates NE_EXPR.
-  if (lhs.undefined_p () || !contains_zero_p (lhs))
+  if (!contains_zero_p (lhs))
 return VREL_NE;
   return VREL_VARYING;
 }
@@ -1178,7 +1178,7 @@ operator_lt::op1_op2_relation (const irange , const 
irange &,
 return VREL_GE;
 
   // TRUE = op1 < op2 indicates LT_EXPR.
-  if (lhs.undefined_p () || !contains_zero_p (lhs))
+  if (!contains_zero_p (lhs))
 return VREL_LT;
   return VREL_VARYING;
 }
@@ -1279,7 +1279,7 @@ operator_le::op1_op2_relation (const irange , const 
irange &,
 return VREL_GT;
 
   // TRUE = op1 <= op2 indicates LE_EXPR.
-  if (lhs.undefined_p () || !contains_zero_p (lhs))
+  if (!contains_zero_p (lhs))
 return VREL_LE;
   return VREL_VARYING;
 }
@@ -2957,7 +2957,7 @@ operator_cast::op1_range (irange , tree type,
{
  // If the LHS is not a pointer nor a singleton, then it is
  // either VARYING or non-zero.
- if (!contains_zero_p (lhs))
+ if (!lhs.undefined_p () && !contains_zero_p (lhs))
r.set_nonzero (type);
  else
r.set_varying (type);
@@ -3368,10 +3368,10 @@ operator_bitwise_and::wi_fold (irange , tree type,
 static void
 set_nonzero_range_from_mask (irange , tree type, const irange )
 {
-  if (!contains_zero_p (lhs))
-r = range_nonzero (type);
-  else
+  

[COMMITTED] [frange] Handle relations in LTGT_EXPR.

2023-08-28 Thread Aldy Hernandez via Gcc-patches
LTGT_EXPR hasn't been handling relations, especially with NANs as a
possibility.  This handles them while documenting how relations work
in a world with NANs.

Basically we need to special case VREL_EQ before calling
frelop_early_resolve.  Note that VREL_EQ on entry to a range-op entry
is really VREL_EQ U NAN, but to make sure about the NAN possibility,
one must look at the operands.  However, even VREL_EQ U NAN is false
for LTGT_EXPR since the latter is just NE_EXPR without a NAN.

After we handle VREL_EQ, we drop down to frelop_early_resolve
pretending to be a NE_EXPR, and everything should just map correctly.

2023-08-28  Aldy Hernandez  

* range-op-float.cc (fold_range): Handle relations.
---
 gcc/range-op-float.cc | 19 +--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index 14199647744..eebc73f9918 100644
--- a/gcc/range-op-float.cc
+++ b/gcc/range-op-float.cc
@@ -2204,8 +2204,23 @@ class foperator_ltgt : public range_operator
 public:
   bool fold_range (irange , tree type,
   const frange , const frange ,
-  relation_trio rel = TRIO_VARYING) const final override
+  relation_trio trio = TRIO_VARYING) const final override
   {
+relation_kind rel = trio.op1_op2 ();
+
+// VREL_EQ is really VREL_(UN)EQ because we could have a NAN in
+// the operands, but since LTGT_EXPR is really a NE_EXPR without
+// the NAN, VREL_EQ & LTGT_EXPR is an impossibility.
+if (rel == VREL_EQ)
+  {
+   r = range_false (type);
+   return true;
+  }
+// ...otherwise pretend we're trying to resolve a NE_EXPR and
+// everything will "just work".
+if (frelop_early_resolve (r, type, op1, op2, trio, VREL_NE))
+  return true;
+
 if (op1.known_isnan () || op2.known_isnan ())
   {
r = range_false (type);
@@ -2218,7 +2233,7 @@ public:
 if (op2.maybe_isnan ())
   op2_no_nan.clear_nan ();
 if (!range_op_handler (NE_EXPR).fold_range (r, type, op1_no_nan,
-   op2_no_nan, rel))
+   op2_no_nan, trio))
   return false;
 // The result is the same as the ordered version when the
 // comparison is true or when the operands cannot be NANs.
-- 
2.41.0



[PATCH] [frange] Relax floating point relational folding.

2023-08-23 Thread Aldy Hernandez via Gcc-patches
[Jakub/Andrew: I've been staring at this for far too long and could
use another pair of eyes.]

This patch implements a new frelop_early_resolve() that handles the
NAN special cases instead of calling into the integer version which
can break for some combinations.  Relaxing FP conditional folding in
this matter allows ranger to do a better job resulting in more
threading opportunities, among other things.

In auditing ranger versus DOM scoped tables I've noticed we are too
cautious when folding floating point conditionals involving
relationals.  We refuse to fold anything if there is the possibility
of a NAN, but this is overly restrictive.

For example:

  if (x_5 != y_8)
if (x_5 != y_8)
  link_error ();

In range-ops, we fail to fold the second conditional because
frelop_early_resolve bails on anything that may have a NAN, but in the
above case the possibility of a NAN is inconsequential.

However, there are some cases where we must be careful, because a NAN
can complicate matters:

  if (x_5 == x_5)
   ...

Here the operands to EQ_EXPR are the same so we get VREL_EQ as the
relation.  However, we can't fold the conditional unless we know x_5
cannot be a NAN.

On the other hand, we can fold the second conditional here:

  if (x_5 == x_5)
if (x_5 > x_5)

Because on the TRUE side of the first conditional we are guaranteed to
be free of NANs.

This patch is basically an inline of the integer version of
relop_early_resolve() with special casing for floats.

The main thing to keep in mind is that the relation coming into a
range-op entry may have a NAN, and for that one must look at the
operands.  This makes the relations akin to unordered comparisons,
making VREL_LT behave like VREL_UNLT would.

The tricky corner cases are VREL_EQ and VREL_NE, as discussed above.
Apart from these that are special cased, the relation table for
intersect should work fine for returning a FALSE, even with NANs.  The
union table, not so much and is documented in the code.

This allows us to add some optimizations for the unordered operators.
For example, a relation of VREL_LT on entry to an operator allows us
to fold an UNLT_EXPR as true, even with NANs because in this case
VREL_LT is really VREL_UNLT which maps perfectly.

BTW, we batted some ideas on how to get this work, and it seems this
is the cleaner route with the special cases nestled in the operators
themselves.  Another idea is to add unordered relations, but that
would require bloating the various tables adding spots for VREL_UNEQ,
VREL_UNLT, etc, plus adding relations for VREL_UNORDERED so the
intersects work correctly.  I'm not wed to either one, and we can
certainly revisit this if it becomes burdensome to maintain (or to get
right).

I'll hold off until the end of the week to commit, to wait for
feedback.

Tested on x86-64 Linux.

gcc/ChangeLog:

* range-op-float.cc (frelop_early_resolve): Rewrite for better NAN
handling.
(operator_not_equal::fold_range): Adjust for relations.
(operator_lt::fold_range): Same.
(operator_gt::fold_range): Same.
(foperator_unordered_equal::fold_range): Same.
(foperator_unordered_lt::fold_range): Same.
(foperator_unordered_le::fold_range): Same.
(foperator_unordered_gt::fold_range): Same.
(foperator_unordered_ge::fold_range): Same.

gcc/testsuite/ChangeLog:

* gcc.dg/tree-ssa/vrp-float-12.c: New test.
---
 gcc/range-op-float.cc| 148 +++
 gcc/testsuite/gcc.dg/tree-ssa/vrp-float-12.c |  23 +++
 2 files changed, 143 insertions(+), 28 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-float-12.c

diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index e30b489c410..14199647744 100644
--- a/gcc/range-op-float.cc
+++ b/gcc/range-op-float.cc
@@ -268,22 +268,75 @@ maybe_isnan (const frange , const frange )
   return op1.maybe_isnan () || op2.maybe_isnan ();
 }
 
-// Floating version of relop_early_resolve that takes into account NAN
-// and -ffinite-math-only.
+// Floating point version of relop_early_resolve that takes NANs into
+// account.
+//
+// For relation opcodes, first try to see if the supplied relation
+// forces a true or false result, and return that.
+// Then check for undefined operands.  If none of this applies,
+// return false.
+//
+// TRIO are the relations between operands as they appear in the IL.
+// MY_REL is the relation that corresponds to the operator being
+// folded.  For example, when attempting to fold x_3 == y_5, MY_REL is
+// VREL_EQ, and if the statement is dominated by x_3 > y_5, then
+// TRIO.op1_op2() is VREL_GT.
+//
+// Relations in a floating point world are a bit tricky, as TRIO
+// behaves as the corresponding unordered variant if either operand
+// could be a NAN.  For example, when resolving "if (x_5 == x_5)", the
+// relation is VREL_EQ, but it behaves like VREL_UNEQ if NANs are a
+// possibility.  Similarly, the false edge of "if (x >= y)" 

[COMMITTED] [frange] Return false if nothing changed in union_nans().

2023-08-21 Thread Aldy Hernandez via Gcc-patches
When one operand is a known NAN, we always return TRUE from
union_nans(), even if no change occurred.  This patch fixes the
oversight.

gcc/ChangeLog:

* value-range.cc (frange::union_nans): Return false if nothing
changed.
(range_tests_floats): New test.
---
 gcc/value-range.cc | 36 +++-
 1 file changed, 31 insertions(+), 5 deletions(-)

diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 76f88d91046..60180c80e55 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -540,16 +540,26 @@ frange::union_nans (const frange )
 {
   gcc_checking_assert (known_isnan () || r.known_isnan ());
 
-  if (known_isnan ())
+  bool changed = false;
+  if (known_isnan () && m_kind != r.m_kind)
 {
   m_kind = r.m_kind;
   m_min = r.m_min;
   m_max = r.m_max;
+  changed = true;
 }
-  m_pos_nan |= r.m_pos_nan;
-  m_neg_nan |= r.m_neg_nan;
-  normalize_kind ();
-  return true;
+  if (m_pos_nan != r.m_pos_nan || m_neg_nan != r.m_neg_nan)
+{
+  m_pos_nan |= r.m_pos_nan;
+  m_neg_nan |= r.m_neg_nan;
+  changed = true;
+}
+  if (changed)
+{
+  normalize_kind ();
+  return true;
+}
+  return false;
 }
 
 bool
@@ -2715,6 +2725,22 @@ range_tests_nan ()
   ASSERT_TRUE (real_identical (, _bound ()));
   ASSERT_TRUE (!r0.signbit_p (signbit));
   ASSERT_TRUE (r0.maybe_isnan ());
+
+  // NAN U NAN shouldn't change anything.
+  r0.set_nan (float_type_node);
+  r1.set_nan (float_type_node);
+  ASSERT_FALSE (r0.union_ (r1));
+
+  // [3,5] NAN U NAN shouldn't change anything.
+  r0 = frange_float ("3", "5");
+  r1.set_nan (float_type_node);
+  ASSERT_FALSE (r0.union_ (r1));
+
+  // [3,5] U NAN *does* trigger a change.
+  r0 = frange_float ("3", "5");
+  r0.clear_nan ();
+  r1.set_nan (float_type_node);
+  ASSERT_TRUE (r0.union_ (r1));
 }
 
 static void
-- 
2.41.0



[COMMITTED] [irange] Return FALSE if updated bitmask is unchanged [PR110753]

2023-08-18 Thread Aldy Hernandez via Gcc-patches
The mask/value pair we track in the irange is a bit fickle in that it
can sometimes contradict the bitmask inherent in the range.  This can
happen when a series of calculations yield a combination such as:

[3, 1000] MASK 0xfffe VALUE 0x0

The mask/value above implies that the lowest bit is a known 0, which
would exclude the 3 in the range.  At one time we tried keeping mask
and ranges 100% consistent, but the performance penalty was too high
(5% in VRP).  Also, it's unclear whether the intersection of two
incompatible known bits should make the whole range undefined, or
just the contradicting bits.  This is all documented in
irange::get_bitmask().  We could revisit both of these assumptions
in the future.

In this testcase IPA ends up with a range where the lower 2 bits are
expected to be 0, but the range is [1,1].

[irange] long int [1, 1] MASK 0xfffc VALUE 0x0

This causes irange::union_bitmask() to think an update occurred, when
no semantic change happened, thus triggering an assert in IPA-cp.  We
could get rid of the assert, but it's cleaner to make
irange::{union,intersect}_bitmask always tell the truth.  Beside, the
ranger's cache also depends on union being truthful.

PR ipa/110753

gcc/ChangeLog:

* value-range.cc (irange::union_bitmask): Return FALSE if updated
bitmask is semantically equivalent to the original mask.
(irange::intersect_bitmask): Same.
(irange::get_bitmask): Add comment.

gcc/testsuite/ChangeLog:

* gcc.dg/tree-ssa/pr110753.c: New test.
---
 gcc/testsuite/gcc.dg/tree-ssa/pr110753.c | 15 +++
 gcc/value-range.cc   | 18 ++
 2 files changed, 33 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr110753.c

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr110753.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr110753.c
new file mode 100644
index 000..aa02487e2a7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr110753.c
@@ -0,0 +1,15 @@
+// { dg-do compile }
+// { dg-options "-O2" }
+
+int a, b, c;
+static int d(long e, long f) { return f == 0 || e && f == 1 ?: f; }
+int g(void) {static int t; return t;}
+static void h(long e) {
+  b = e - 1;
+  a = d(b || d(e, 8), g());
+}
+int tt;
+void i(void) {
+  c = (__SIZE_TYPE__)
+  h(c);
+}
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 2abf57bcee8..76f88d91046 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -1876,6 +1876,8 @@ irange::get_bitmask () const
   //
   // 3 is in the range endpoints, but is excluded per the known 0 bits
   // in the mask.
+  //
+  // See also the note in irange_bitmask::intersect.
   irange_bitmask bm = get_bitmask_from_range ();
   if (!m_bitmask.unknown_p ())
 bm.intersect (m_bitmask);
@@ -1915,10 +1917,18 @@ irange::intersect_bitmask (const irange )
 return false;
 
   irange_bitmask bm = get_bitmask ();
+  irange_bitmask save = bm;
   if (!bm.intersect (r.get_bitmask ()))
 return false;
 
   m_bitmask = bm;
+
+  // Updating m_bitmask may still yield a semantic bitmask (as
+  // returned by get_bitmask) which is functionally equivalent to what
+  // we originally had.  In which case, there's still no change.
+  if (save == get_bitmask ())
+return false;
+
   if (!set_range_from_bitmask ())
 normalize_kind ();
   if (flag_checking)
@@ -1938,10 +1948,18 @@ irange::union_bitmask (const irange )
 return false;
 
   irange_bitmask bm = get_bitmask ();
+  irange_bitmask save = bm;
   if (!bm.union_ (r.get_bitmask ()))
 return false;
 
   m_bitmask = bm;
+
+  // Updating m_bitmask may still yield a semantic bitmask (as
+  // returned by get_bitmask) which is functionally equivalent to what
+  // we originally had.  In which case, there's still no change.
+  if (save == get_bitmask ())
+return false;
+
   // No need to call set_range_from_mask, because we'll never
   // narrow the range.  Besides, it would cause endless recursion
   // because of the union_ in set_range_from_mask.
-- 
2.41.0



Re: [PATCH] Read global value/mask in IPA.

2023-08-03 Thread Aldy Hernandez via Gcc-patches



On 7/31/23 18:47, Martin Jambor wrote:

Hello,

On Tue, Jul 18 2023, Aldy Hernandez wrote:

On 7/17/23 15:14, Aldy Hernandez wrote:

Instead of reading the known zero bits in IPA, read the value/mask
pair which is available.

There is a slight change of behavior here.  I have removed the check
for SSA_NAME, as the ranger can calculate the range and value/mask for
INTEGER_CST.  This simplifies the code a bit, since there's no special
casing when setting the jfunc bits.  The default range for VR is
undefined, so I think it's safe just to check for undefined_p().


Final round of tests revealed a regression for which I've adjusted the
testcase.

It turns out g++.dg/ipa/pure-const-3.C fails because IPA can now pick up
value/mask from any pass that has an integrated ranger.  The test was
previously disabling evrp and CCP, but now VRP[12], jump threading, and
DOM can make value/mask adjustments visible to IPA so they must be
disabled as well.


So can this be then converted into a new testcase that would test that
we can now derive something we could not in the past?


Good idea.

This is what I'm testing.  I'm basically testing for "Propagated bits" 
in the ipa-cp pass which is where we are able to propagate more things.


I will commit if it succeeds.

Thanks.
AldyFrom 57fae00c11070545dd0eacaa5c04547cc553 Mon Sep 17 00:00:00 2001
From: Aldy Hernandez 
Date: Fri, 14 Jul 2023 12:38:16 +0200
Subject: [PATCH] Read global value/mask in IPA.

Instead of reading the known zero bits in IPA, read the value/mask
pair which is available.

There is a slight change of behavior here.  I have removed the check
for SSA_NAME, as the ranger can calculate the range and value/mask for
INTEGER_CST.  This simplifies the code a bit, since there's no special
casing when setting the jfunc bits.  The default range for VR is
undefined, so I think it's safe just to check for undefined_p().

gcc/ChangeLog:

	* ipa-prop.cc (ipa_compute_jump_functions_for_edge): Read global
	value/mask.

gcc/testsuite/ChangeLog:

	* g++.dg/ipa/pure-const-3.C: Move source to...
	* g++.dg/ipa/pure-const-3.h: ...here, and adjust original test
	accordingly.
	* g++.dg/ipa/pure-const-3b.C: New.
---
 gcc/ipa-prop.cc  | 18 ++---
 gcc/testsuite/g++.dg/ipa/pure-const-3.C  | 34 +++-
 gcc/testsuite/g++.dg/ipa/pure-const-3.h  | 29 
 gcc/testsuite/g++.dg/ipa/pure-const-3b.C |  6 +
 4 files changed, 47 insertions(+), 40 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ipa/pure-const-3.h
 create mode 100644 gcc/testsuite/g++.dg/ipa/pure-const-3b.C

diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
index 5d790ff1265..4f6ed7b89bd 100644
--- a/gcc/ipa-prop.cc
+++ b/gcc/ipa-prop.cc
@@ -2402,8 +2402,7 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
 	}
   else
 	{
-	  if (TREE_CODE (arg) == SSA_NAME
-	  && param_type
+	  if (param_type
 	  && Value_Range::supports_type_p (TREE_TYPE (arg))
 	  && Value_Range::supports_type_p (param_type)
 	  && irange::supports_p (TREE_TYPE (arg))
@@ -2422,15 +2421,14 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
 	gcc_assert (!jfunc->m_vr);
 	}
 
-  if (INTEGRAL_TYPE_P (TREE_TYPE (arg))
-	  && (TREE_CODE (arg) == SSA_NAME || TREE_CODE (arg) == INTEGER_CST))
+  if (INTEGRAL_TYPE_P (TREE_TYPE (arg)) && !vr.undefined_p ())
 	{
-	  if (TREE_CODE (arg) == SSA_NAME)
-	ipa_set_jfunc_bits (jfunc, 0,
-widest_int::from (get_nonzero_bits (arg),
-		  TYPE_SIGN (TREE_TYPE (arg;
-	  else
-	ipa_set_jfunc_bits (jfunc, wi::to_widest (arg), 0);
+	  irange  = as_a  (vr);
+	  irange_bitmask bm = r.get_bitmask ();
+	  signop sign = TYPE_SIGN (TREE_TYPE (arg));
+	  ipa_set_jfunc_bits (jfunc,
+			  widest_int::from (bm.value (), sign),
+			  widest_int::from (bm.mask (), sign));
 	}
   else if (POINTER_TYPE_P (TREE_TYPE (arg)))
 	{
diff --git a/gcc/testsuite/g++.dg/ipa/pure-const-3.C b/gcc/testsuite/g++.dg/ipa/pure-const-3.C
index b4a4673e86e..62d355b4ce7 100644
--- a/gcc/testsuite/g++.dg/ipa/pure-const-3.C
+++ b/gcc/testsuite/g++.dg/ipa/pure-const-3.C
@@ -1,32 +1,6 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-ipa-vrp -fdump-tree-optimized -fno-tree-ccp -fdisable-tree-evrp"  } */
-int *ptr;
-static int barvar;
-static int b(int a);
-/* We can not detect A to be const because it may be interposed by unoptimized
-   body.  */
-inline
-__attribute__ ((noinline))
-int a(int a)
-{
-  if (a>0)
-return b(a-1);
-  return *ptr == *ptr;
-}
-inline
-__attribute__ ((noinline))
-static int b(int p)
-{
-  if (p<0)
-return a(p+1);
-  return 1;
-}
-int main()
-{
-  int aa;
-  ptr = 
-  aa=!b(3);
-  ptr = 0;
-  return aa;
-}
+/* { dg-options "-O2 -fno-ipa-vrp -fdump-tree-optimized -fno-tree-ccp -fdisable-tree-evrp -fdisable-tree-vrp1 -fdisable-tree-vrp2 -fno-thread-jumps -fno-tree-dominator-opts"  } */
+
+#include "pure-const-3.h"
+
 /* { dg-final { scan-tree-dump 

Re: Fix profile upate after vectorizer peeling

2023-08-03 Thread Aldy Hernandez via Gcc-patches




On 8/3/23 16:29, Jeff Law wrote:



On 8/3/23 08:23, Jan Hubicka wrote:

Jeff, an help would be appreciated here :)

I will try to debug this.  One option would be to disable branch
prediciton on vect_check for time being - it is not inlined anyway
Not a lot of insight.  The backwards threader uses a totally 
different API
for the CFG/SSA updates and that API I don't think has made any 
significant

effort to keep the profile up-to-date.


OK, at least some hints where the missing profile updat should be, would
be good. There is update_profile in tree-ssa-threadupdate and
understaning what is missing would be nice
In general it would be nice to mind profile when updating CFG :)
THe backwards threader doesn't use much of the code in 
tree-ssa-threadupdate IIRC.  The bulk of the work for the backwards 
threader is done by copy_bbs.  I've actually suggested those two 
implementations be totally separated from each other to avoid confusion. 
  I just haven't had the time to do it (or much of anything with 
threading) myself.


A couple cycles ago I separated most of code to distinguish between the 
back and forward threaders.  There is class jt_path_registry that is 
common to both, and {fwd,back}_jt_path_registry for the forward and 
backward threaders respectively.  It's not perfect, but it's a start.


Aldy



Re: [PATCH] Read global value/mask in IPA.

2023-07-31 Thread Aldy Hernandez via Gcc-patches
PING * 2

On Tue, Jul 25, 2023 at 8:32 AM Aldy Hernandez  wrote:
>
> Ping
>
> On Mon, Jul 17, 2023, 15:14 Aldy Hernandez  wrote:
>>
>> Instead of reading the known zero bits in IPA, read the value/mask
>> pair which is available.
>>
>> There is a slight change of behavior here.  I have removed the check
>> for SSA_NAME, as the ranger can calculate the range and value/mask for
>> INTEGER_CST.  This simplifies the code a bit, since there's no special
>> casing when setting the jfunc bits.  The default range for VR is
>> undefined, so I think it's safe just to check for undefined_p().
>>
>> OK?
>>
>> gcc/ChangeLog:
>>
>> * ipa-prop.cc (ipa_compute_jump_functions_for_edge): Read global
>> value/mask.
>> ---
>>  gcc/ipa-prop.cc | 18 --
>>  1 file changed, 8 insertions(+), 10 deletions(-)
>>
>> diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
>> index 5d790ff1265..4f6ed7b89bd 100644
>> --- a/gcc/ipa-prop.cc
>> +++ b/gcc/ipa-prop.cc
>> @@ -2402,8 +2402,7 @@ ipa_compute_jump_functions_for_edge (struct 
>> ipa_func_body_info *fbi,
>> }
>>else
>> {
>> - if (TREE_CODE (arg) == SSA_NAME
>> - && param_type
>> + if (param_type
>>   && Value_Range::supports_type_p (TREE_TYPE (arg))
>>   && Value_Range::supports_type_p (param_type)
>>   && irange::supports_p (TREE_TYPE (arg))
>> @@ -2422,15 +2421,14 @@ ipa_compute_jump_functions_for_edge (struct 
>> ipa_func_body_info *fbi,
>> gcc_assert (!jfunc->m_vr);
>> }
>>
>> -  if (INTEGRAL_TYPE_P (TREE_TYPE (arg))
>> - && (TREE_CODE (arg) == SSA_NAME || TREE_CODE (arg) == INTEGER_CST))
>> +  if (INTEGRAL_TYPE_P (TREE_TYPE (arg)) && !vr.undefined_p ())
>> {
>> - if (TREE_CODE (arg) == SSA_NAME)
>> -   ipa_set_jfunc_bits (jfunc, 0,
>> -   widest_int::from (get_nonzero_bits (arg),
>> - TYPE_SIGN (TREE_TYPE 
>> (arg;
>> - else
>> -   ipa_set_jfunc_bits (jfunc, wi::to_widest (arg), 0);
>> + irange  = as_a  (vr);
>> + irange_bitmask bm = r.get_bitmask ();
>> + signop sign = TYPE_SIGN (TREE_TYPE (arg));
>> + ipa_set_jfunc_bits (jfunc,
>> + widest_int::from (bm.value (), sign),
>> + widest_int::from (bm.mask (), sign));
>> }
>>else if (POINTER_TYPE_P (TREE_TYPE (arg)))
>> {
>> --
>> 2.40.1
>>



[COMMITTED] [range-ops] Remove special case for handling bitmasks in casts.

2023-07-26 Thread Aldy Hernandez via Gcc-patches
Now that we can generically handle bitmasks for unary operators,
there's no need to special case them.

gcc/ChangeLog:

* range-op-mixed.h (class operator_cast): Add update_bitmask.
* range-op.cc (operator_cast::update_bitmask): New.
(operator_cast::fold_range): Call update_bitmask.
---
 gcc/range-op-mixed.h |  2 ++
 gcc/range-op.cc  | 23 ---
 2 files changed, 10 insertions(+), 15 deletions(-)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 6944742ecbc..91a4fcc3989 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -346,6 +346,8 @@ public:
   relation_kind lhs_op1_relation (const irange ,
  const irange , const irange ,
  relation_kind) const final override;
+  void update_bitmask (irange , const irange ,
+  const irange ) const final override;
 private:
   bool truncating_cast_p (const irange , const irange ) const;
   bool inside_domain_p (const wide_int , const wide_int ,
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 6b5d4f2accd..be8f8c48d7c 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -2867,24 +2867,17 @@ operator_cast::fold_range (irange , tree type 
ATTRIBUTE_UNUSED,
return true;
 }
 
-  // Update the bitmask.  Truncating casts are problematic unless
-  // the conversion fits in the resulting outer type.
-  irange_bitmask bm = inner.get_bitmask ();
-  if (truncating_cast_p (inner, outer)
-  && wi::rshift (bm.mask (),
-wi::uhwi (TYPE_PRECISION (outer.type ()),
-  TYPE_PRECISION (inner.type ())),
-TYPE_SIGN (inner.type ())) != 0)
-return true;
-  unsigned prec = TYPE_PRECISION (type);
-  signop sign = TYPE_SIGN (inner.type ());
-  bm = irange_bitmask (wide_int::from (bm.value (), prec, sign),
-  wide_int::from (bm.mask (), prec, sign));
-  r.update_bitmask (bm);
-
+  update_bitmask (r, inner, outer);
   return true;
 }
 
+void
+operator_cast::update_bitmask (irange , const irange ,
+  const irange ) const
+{
+  update_known_bitmask (r, CONVERT_EXPR, lh, rh);
+}
+
 bool
 operator_cast::op1_range (irange , tree type,
  const irange ,
-- 
2.41.0



[COMMITTED] [range-ops] Handle bitmasks for ABSU_EXPR.

2023-07-26 Thread Aldy Hernandez via Gcc-patches
gcc/ChangeLog:

* range-op.cc (class operator_absu): Add update_bitmask.
(operator_absu::update_bitmask): New.
---
 gcc/range-op.cc | 9 +
 1 file changed, 9 insertions(+)

diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index bfab53caea0..5653ca0d186 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -4221,6 +4221,8 @@ class operator_absu : public range_operator
   virtual void wi_fold (irange , tree type,
const wide_int _lb, const wide_int _ub,
const wide_int _lb, const wide_int _ub) const;
+  virtual void update_bitmask (irange , const irange ,
+  const irange ) const final override;
 } op_absu;
 
 void
@@ -4258,6 +4260,13 @@ operator_absu::wi_fold (irange , tree type,
   r = int_range<1> (type, new_lb, new_ub);
 }
 
+void
+operator_absu::update_bitmask (irange , const irange ,
+ const irange ) const
+{
+  update_known_bitmask (r, ABSU_EXPR, lh, rh);
+}
+
 
 bool
 operator_negate::fold_range (irange , tree type,
-- 
2.41.0



[COMMITTED] [range-ops] Handle bitmasks for ABS_EXPR.

2023-07-26 Thread Aldy Hernandez via Gcc-patches
gcc/ChangeLog:

* range-op-mixed.h (class operator_abs): Add update_bitmask.
* range-op.cc (operator_abs::update_bitmask): New.
---
 gcc/range-op-mixed.h | 2 ++
 gcc/range-op.cc  | 6 ++
 2 files changed, 8 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index ead41ed0515..70550c52232 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -408,6 +408,8 @@ class operator_abs : public range_operator
   bool op1_range (frange , tree type,
  const frange , const frange ,
  relation_trio rel = TRIO_VARYING) const final override;
+  void update_bitmask (irange , const irange ,
+  const irange ) const final override;
 private:
   void wi_fold (irange , tree type, const wide_int _lb,
const wide_int _ub, const wide_int _lb,
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 13ba973a08d..bfab53caea0 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -4208,6 +4208,12 @@ operator_abs::op1_range (irange , tree type,
   return true;
 }
 
+void
+operator_abs::update_bitmask (irange , const irange ,
+ const irange ) const
+{
+  update_known_bitmask (r, ABS_EXPR, lh, rh);
+}
 
 class operator_absu : public range_operator
 {
-- 
2.41.0



[COMMITTED] [range-ops] Handle bitmasks for BIT_NOT_EXPR.

2023-07-26 Thread Aldy Hernandez via Gcc-patches
gcc/ChangeLog:

* range-op-mixed.h (class operator_bitwise_not): Add update_bitmask.
* range-op.cc (operator_bitwise_not::update_bitmask): New.
---
 gcc/range-op-mixed.h | 2 ++
 gcc/range-op.cc  | 7 +++
 2 files changed, 9 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 6944742ecbc..ead41ed0515 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -551,6 +551,8 @@ public:
   bool op1_range (irange , tree type,
  const irange , const irange ,
  relation_trio rel = TRIO_VARYING) const final override;
+  void update_bitmask (irange , const irange ,
+  const irange ) const final override;
 };
 
 class operator_bitwise_xor : public range_operator
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index d959a3e93dc..13ba973a08d 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -4027,6 +4027,13 @@ operator_bitwise_not::op1_range (irange , tree type,
   return fold_range (r, type, lhs, op2);
 }
 
+void
+operator_bitwise_not::update_bitmask (irange , const irange ,
+ const irange ) const
+{
+  update_known_bitmask (r, BIT_NOT_EXPR, lh, rh);
+}
+
 
 bool
 operator_cst::fold_range (irange , tree type ATTRIBUTE_UNUSED,
-- 
2.41.0



[COMMITTED] [range-ops] Handle bitmasks for unary operators.

2023-07-26 Thread Aldy Hernandez via Gcc-patches
It looks like we missed out on bitmasks for unary operators because we
were using bit_value_binop exclusively.  This patch hands off to
bit_value_unop when appropriate, thus allowing us to handle ABS and
BIT_NOT_EXPR, and others.  Follow-up patches will add the tweaks for the
range-ops entries themselves.

gcc/ChangeLog:

* range-op.cc (update_known_bitmask): Handle unary operators.
---
 gcc/range-op.cc | 32 +++-
 1 file changed, 23 insertions(+), 9 deletions(-)

diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 6b5d4f2accd..d959a3e93dc 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -385,15 +385,29 @@ update_known_bitmask (irange , tree_code code,
   irange_bitmask lh_bits = lh.get_bitmask ();
   irange_bitmask rh_bits = rh.get_bitmask ();
 
-  bit_value_binop (code, sign, prec, _value, _mask,
-  TYPE_SIGN (lh.type ()),
-  TYPE_PRECISION (lh.type ()),
-  widest_int::from (lh_bits.value (), sign),
-  widest_int::from (lh_bits.mask (), sign),
-  TYPE_SIGN (rh.type ()),
-  TYPE_PRECISION (rh.type ()),
-  widest_int::from (rh_bits.value (), sign),
-  widest_int::from (rh_bits.mask (), sign));
+  switch (get_gimple_rhs_class (code))
+{
+case GIMPLE_UNARY_RHS:
+  bit_value_unop (code, sign, prec, _value, _mask,
+ TYPE_SIGN (lh.type ()),
+ TYPE_PRECISION (lh.type ()),
+ widest_int::from (lh_bits.value (), sign),
+ widest_int::from (lh_bits.mask (), sign));
+  break;
+case GIMPLE_BINARY_RHS:
+  bit_value_binop (code, sign, prec, _value, _mask,
+  TYPE_SIGN (lh.type ()),
+  TYPE_PRECISION (lh.type ()),
+  widest_int::from (lh_bits.value (), sign),
+  widest_int::from (lh_bits.mask (), sign),
+  TYPE_SIGN (rh.type ()),
+  TYPE_PRECISION (rh.type ()),
+  widest_int::from (rh_bits.value (), sign),
+  widest_int::from (rh_bits.mask (), sign));
+  break;
+default:
+  gcc_unreachable ();
+}
 
   wide_int mask = wide_int::from (widest_mask, prec, sign);
   wide_int value = wide_int::from (widest_value, prec, sign);
-- 
2.41.0



Re: [PATCH] range-op-float: Fix up -frounding-math frange_arithmetic +- handling [PR110755]

2023-07-25 Thread Aldy Hernandez via Gcc-patches
The frange bits look fine to me, so if you feel confident in the math 
logic, go right ahead :).


Thanks.
Aldy

On 7/24/23 18:01, Jakub Jelinek wrote:

Hi!

IEEE754 says that x + (-x) and x - x result in +0 in all rounding modes
but rounding towards negative infinity, in which case the result is -0
for all finite x.  x + x and x - (-x) if it is zero retain sign of x.
Now, range_arithmetic implements the normal rounds to even rounding,
and as the addition or subtraction in those cases is exact, we don't do any
further rounding etc. and e.g. on the testcase below distilled from glibc
compute a range [+0, +INF], which is fine for -fno-rounding-math or
if we'd have a guarantee that those statements aren't executed with rounding
towards negative infinity.

I believe it is only +- which has this problematic behavior and I think
it is best to deal with it in frange_arithmetic; if we know -frounding-math
is on, it is x + (-x) or x - x and we are asked to round to negative
infinity (i.e. want low bound rather than high bound), change +0 result to
-0.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk and
after a while for 13.3?  I'm afraid rushing this so late into 13.2...

2023-07-24  Jakub Jelinek  

PR tree-optimization/110755
* range-op-float.cc (frange_arithmetic): Change +0 result to -0
for PLUS_EXPR or MINUS_EXPR if -frounding-math, inf is negative and
it is exact op1 + (-op1) or op1 - op1.

* gcc.dg/pr110755.c: New test.

--- gcc/range-op-float.cc.jj2023-07-23 19:32:20.832434105 +0200
+++ gcc/range-op-float.cc   2023-07-24 09:41:26.231030258 +0200
@@ -324,6 +324,24 @@ frange_arithmetic (enum tree_code code,
bool inexact = real_arithmetic (, code, , );
real_convert (, mode, );
  
+  /* When rounding towards negative infinity, x + (-x) and

+ x - x is -0 rather than +0 real_arithmetic computes.
+ So, when we are looking for lower bound (inf is negative),
+ use -0 rather than +0.  */
+  if (flag_rounding_math
+  && (code == PLUS_EXPR || code == MINUS_EXPR)
+  && !inexact
+  && real_iszero ()
+  && !real_isneg ()
+  && real_isneg ())
+{
+  REAL_VALUE_TYPE op2a = op2;
+  if (code == PLUS_EXPR)
+   op2a.sign ^= 1;
+  if (real_isneg () == real_isneg () && real_equal (, ))
+   result.sign = 1;
+}
+
// Be extra careful if there may be discrepancies between the
// compile and runtime results.
bool round = false;
--- gcc/testsuite/gcc.dg/pr110755.c.jj  2023-07-21 10:34:05.037251433 +0200
+++ gcc/testsuite/gcc.dg/pr110755.c 2023-07-21 10:35:10.986326816 +0200
@@ -0,0 +1,29 @@
+/* PR tree-optimization/110755 */
+/* { dg-do run } */
+/* { dg-require-effective-target fenv } */
+/* { dg-require-effective-target hard_float } */
+/* { dg-options "-O2 -frounding-math" } */
+
+#include 
+
+__attribute__((noipa)) float
+foo (float x)
+{
+  if (x > 0.0)
+{
+  x += 0x1p+23;
+  x -= 0x1p+23;
+  x = __builtin_fabsf (x);
+}
+  return x;
+}
+
+int
+main ()
+{
+#ifdef FE_DOWNWARD
+  fesetround (FE_DOWNWARD);
+  if (__builtin_signbit (foo (0.5)))
+__builtin_abort ();
+#endif
+}

Jakub





[PATCH] Initialize value in bit_value_unop.

2023-07-25 Thread Aldy Hernandez via Gcc-patches
bit_value_binop initializes VAL regardless of the final mask.  It even
has a comment to that effect:

  /* Ensure that VAL is initialized (to any value).  */

However, bit_value_unop, which in theory shares the same API, does not.
This causes range-ops to choke on uninitialized VALs for some inputs to
ABS.

Instead of fixing the callers, it's cleaner to make bit_value_unop and
bit_value_binop consistent.

OK for trunk?

gcc/ChangeLog:

* tree-ssa-ccp.cc (bit_value_unop): Initialize val when appropriate.
---
 gcc/tree-ssa-ccp.cc | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/gcc/tree-ssa-ccp.cc b/gcc/tree-ssa-ccp.cc
index 73fb7c11c64..15e65f16008 100644
--- a/gcc/tree-ssa-ccp.cc
+++ b/gcc/tree-ssa-ccp.cc
@@ -1359,7 +1359,10 @@ bit_value_unop (enum tree_code code, signop type_sgn, 
int type_precision,
 case ABS_EXPR:
 case ABSU_EXPR:
   if (wi::sext (rmask, rtype_precision) == -1)
-   *mask = -1;
+   {
+ *mask = -1;
+ *val = 0;
+   }
   else if (wi::neg_p (rmask))
{
  /* Result is either rval or -rval.  */
@@ -1385,6 +1388,7 @@ bit_value_unop (enum tree_code code, signop type_sgn, int 
type_precision,
 
 default:
   *mask = -1;
+  *val = 0;
   break;
 }
 }
-- 
2.41.0



[COMMITTED] Make some functions in CCP static.

2023-07-25 Thread Aldy Hernandez via Gcc-patches
Committed as obvious.

gcc/ChangeLog:

* tree-ssa-ccp.cc (value_mask_to_min_max): Make static.
(bit_value_mult_const): Same.
(get_individual_bits): Same.
---
 gcc/tree-ssa-ccp.cc | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/gcc/tree-ssa-ccp.cc b/gcc/tree-ssa-ccp.cc
index 64d5fa81334..73fb7c11c64 100644
--- a/gcc/tree-ssa-ccp.cc
+++ b/gcc/tree-ssa-ccp.cc
@@ -1297,7 +1297,7 @@ ccp_fold (gimple *stmt)
represented by the mask pair VAL and MASK with signedness SGN and
precision PRECISION.  */
 
-void
+static void
 value_mask_to_min_max (widest_int *min, widest_int *max,
   const widest_int , const widest_int ,
   signop sgn, int precision)
@@ -1391,7 +1391,7 @@ bit_value_unop (enum tree_code code, signop type_sgn, int 
type_precision,
 
 /* Determine the mask pair *VAL and *MASK from multiplying the
argument mask pair RVAL, RMASK by the unsigned constant C.  */
-void
+static void
 bit_value_mult_const (signop sgn, int width,
  widest_int *val, widest_int *mask,
  const widest_int , const widest_int ,
@@ -1453,7 +1453,7 @@ bit_value_mult_const (signop sgn, int width,
bits in X (capped at the maximum value MAX).  For example, an X
value 11, places 1, 2 and 8 in BITS and returns the value 3.  */
 
-unsigned int
+static unsigned int
 get_individual_bits (widest_int *bits, widest_int x, unsigned int max)
 {
   unsigned int count = 0;
-- 
2.41.0



Re: [PATCH] Read global value/mask in IPA.

2023-07-25 Thread Aldy Hernandez via Gcc-patches
Ping

On Mon, Jul 17, 2023, 15:14 Aldy Hernandez  wrote:

> Instead of reading the known zero bits in IPA, read the value/mask
> pair which is available.
>
> There is a slight change of behavior here.  I have removed the check
> for SSA_NAME, as the ranger can calculate the range and value/mask for
> INTEGER_CST.  This simplifies the code a bit, since there's no special
> casing when setting the jfunc bits.  The default range for VR is
> undefined, so I think it's safe just to check for undefined_p().
>
> OK?
>
> gcc/ChangeLog:
>
> * ipa-prop.cc (ipa_compute_jump_functions_for_edge): Read global
> value/mask.
> ---
>  gcc/ipa-prop.cc | 18 --
>  1 file changed, 8 insertions(+), 10 deletions(-)
>
> diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
> index 5d790ff1265..4f6ed7b89bd 100644
> --- a/gcc/ipa-prop.cc
> +++ b/gcc/ipa-prop.cc
> @@ -2402,8 +2402,7 @@ ipa_compute_jump_functions_for_edge (struct
> ipa_func_body_info *fbi,
> }
>else
> {
> - if (TREE_CODE (arg) == SSA_NAME
> - && param_type
> + if (param_type
>   && Value_Range::supports_type_p (TREE_TYPE (arg))
>   && Value_Range::supports_type_p (param_type)
>   && irange::supports_p (TREE_TYPE (arg))
> @@ -2422,15 +2421,14 @@ ipa_compute_jump_functions_for_edge (struct
> ipa_func_body_info *fbi,
> gcc_assert (!jfunc->m_vr);
> }
>
> -  if (INTEGRAL_TYPE_P (TREE_TYPE (arg))
> - && (TREE_CODE (arg) == SSA_NAME || TREE_CODE (arg) ==
> INTEGER_CST))
> +  if (INTEGRAL_TYPE_P (TREE_TYPE (arg)) && !vr.undefined_p ())
> {
> - if (TREE_CODE (arg) == SSA_NAME)
> -   ipa_set_jfunc_bits (jfunc, 0,
> -   widest_int::from (get_nonzero_bits (arg),
> - TYPE_SIGN (TREE_TYPE
> (arg;
> - else
> -   ipa_set_jfunc_bits (jfunc, wi::to_widest (arg), 0);
> + irange  = as_a  (vr);
> + irange_bitmask bm = r.get_bitmask ();
> + signop sign = TYPE_SIGN (TREE_TYPE (arg));
> + ipa_set_jfunc_bits (jfunc,
> + widest_int::from (bm.value (), sign),
> + widest_int::from (bm.mask (), sign));
> }
>else if (POINTER_TYPE_P (TREE_TYPE (arg)))
> {
> --
> 2.40.1
>
>


Re: [PATCH] Read global value/mask in IPA.

2023-07-18 Thread Aldy Hernandez via Gcc-patches



On 7/17/23 15:14, Aldy Hernandez wrote:

Instead of reading the known zero bits in IPA, read the value/mask
pair which is available.

There is a slight change of behavior here.  I have removed the check
for SSA_NAME, as the ranger can calculate the range and value/mask for
INTEGER_CST.  This simplifies the code a bit, since there's no special
casing when setting the jfunc bits.  The default range for VR is
undefined, so I think it's safe just to check for undefined_p().


Final round of tests revealed a regression for which I've adjusted the 
testcase.


It turns out g++.dg/ipa/pure-const-3.C fails because IPA can now pick up 
value/mask from any pass that has an integrated ranger.  The test was 
previously disabling evrp and CCP, but now VRP[12], jump threading, and 
DOM can make value/mask adjustments visible to IPA so they must be 
disabled as well.


We've run into these scenarios multiple times in the past-- any 
improvements to the ranger pipeline causes everyone to get smarter, 
making changes visible earlier in the pipeline.


AldyFrom e1dfd4d6b3d3bf09d55b6ea3ac732462c7030802 Mon Sep 17 00:00:00 2001
From: Aldy Hernandez 
Date: Fri, 14 Jul 2023 12:38:16 +0200
Subject: [PATCH] Read global value/mask in IPA.

Instead of reading the known zero bits in IPA, read the value/mask
pair which is available.

There is a slight change of behavior here.  I have removed the check
for SSA_NAME, as the ranger can calculate the range and value/mask for
INTEGER_CST.  This simplifies the code a bit, since there's no special
casing when setting the jfunc bits.  The default range for VR is
undefined, so I think it's safe just to check for undefined_p().

gcc/ChangeLog:

	* ipa-prop.cc (ipa_compute_jump_functions_for_edge): Read global
	value/mask.

gcc/testsuite/ChangeLog:

	* g++.dg/ipa/pure-const-3.C: Adjust for smarter value/mask being
	read by ranger earlier than expected by test.
---
 gcc/ipa-prop.cc | 18 --
 gcc/testsuite/g++.dg/ipa/pure-const-3.C |  2 +-
 2 files changed, 9 insertions(+), 11 deletions(-)

diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
index 5d790ff1265..4f6ed7b89bd 100644
--- a/gcc/ipa-prop.cc
+++ b/gcc/ipa-prop.cc
@@ -2402,8 +2402,7 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
 	}
   else
 	{
-	  if (TREE_CODE (arg) == SSA_NAME
-	  && param_type
+	  if (param_type
 	  && Value_Range::supports_type_p (TREE_TYPE (arg))
 	  && Value_Range::supports_type_p (param_type)
 	  && irange::supports_p (TREE_TYPE (arg))
@@ -2422,15 +2421,14 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
 	gcc_assert (!jfunc->m_vr);
 	}
 
-  if (INTEGRAL_TYPE_P (TREE_TYPE (arg))
-	  && (TREE_CODE (arg) == SSA_NAME || TREE_CODE (arg) == INTEGER_CST))
+  if (INTEGRAL_TYPE_P (TREE_TYPE (arg)) && !vr.undefined_p ())
 	{
-	  if (TREE_CODE (arg) == SSA_NAME)
-	ipa_set_jfunc_bits (jfunc, 0,
-widest_int::from (get_nonzero_bits (arg),
-		  TYPE_SIGN (TREE_TYPE (arg;
-	  else
-	ipa_set_jfunc_bits (jfunc, wi::to_widest (arg), 0);
+	  irange  = as_a  (vr);
+	  irange_bitmask bm = r.get_bitmask ();
+	  signop sign = TYPE_SIGN (TREE_TYPE (arg));
+	  ipa_set_jfunc_bits (jfunc,
+			  widest_int::from (bm.value (), sign),
+			  widest_int::from (bm.mask (), sign));
 	}
   else if (POINTER_TYPE_P (TREE_TYPE (arg)))
 	{
diff --git a/gcc/testsuite/g++.dg/ipa/pure-const-3.C b/gcc/testsuite/g++.dg/ipa/pure-const-3.C
index b4a4673e86e..e43cf09af27 100644
--- a/gcc/testsuite/g++.dg/ipa/pure-const-3.C
+++ b/gcc/testsuite/g++.dg/ipa/pure-const-3.C
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-ipa-vrp -fdump-tree-optimized -fno-tree-ccp -fdisable-tree-evrp"  } */
+/* { dg-options "-O2 -fno-ipa-vrp -fdump-tree-optimized -fno-tree-ccp -fdisable-tree-evrp -fdisable-tree-vrp1 -fdisable-tree-vrp2 -fno-thread-jumps -fno-tree-dominator-opts"  } */
 int *ptr;
 static int barvar;
 static int b(int a);
-- 
2.40.1



[PATCH] Read global value/mask in IPA.

2023-07-17 Thread Aldy Hernandez via Gcc-patches
Instead of reading the known zero bits in IPA, read the value/mask
pair which is available.

There is a slight change of behavior here.  I have removed the check
for SSA_NAME, as the ranger can calculate the range and value/mask for
INTEGER_CST.  This simplifies the code a bit, since there's no special
casing when setting the jfunc bits.  The default range for VR is
undefined, so I think it's safe just to check for undefined_p().

OK?

gcc/ChangeLog:

* ipa-prop.cc (ipa_compute_jump_functions_for_edge): Read global
value/mask.
---
 gcc/ipa-prop.cc | 18 --
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
index 5d790ff1265..4f6ed7b89bd 100644
--- a/gcc/ipa-prop.cc
+++ b/gcc/ipa-prop.cc
@@ -2402,8 +2402,7 @@ ipa_compute_jump_functions_for_edge (struct 
ipa_func_body_info *fbi,
}
   else
{
- if (TREE_CODE (arg) == SSA_NAME
- && param_type
+ if (param_type
  && Value_Range::supports_type_p (TREE_TYPE (arg))
  && Value_Range::supports_type_p (param_type)
  && irange::supports_p (TREE_TYPE (arg))
@@ -2422,15 +2421,14 @@ ipa_compute_jump_functions_for_edge (struct 
ipa_func_body_info *fbi,
gcc_assert (!jfunc->m_vr);
}
 
-  if (INTEGRAL_TYPE_P (TREE_TYPE (arg))
- && (TREE_CODE (arg) == SSA_NAME || TREE_CODE (arg) == INTEGER_CST))
+  if (INTEGRAL_TYPE_P (TREE_TYPE (arg)) && !vr.undefined_p ())
{
- if (TREE_CODE (arg) == SSA_NAME)
-   ipa_set_jfunc_bits (jfunc, 0,
-   widest_int::from (get_nonzero_bits (arg),
- TYPE_SIGN (TREE_TYPE (arg;
- else
-   ipa_set_jfunc_bits (jfunc, wi::to_widest (arg), 0);
+ irange  = as_a  (vr);
+ irange_bitmask bm = r.get_bitmask ();
+ signop sign = TYPE_SIGN (TREE_TYPE (arg));
+ ipa_set_jfunc_bits (jfunc,
+ widest_int::from (bm.value (), sign),
+ widest_int::from (bm.mask (), sign));
}
   else if (POINTER_TYPE_P (TREE_TYPE (arg)))
{
-- 
2.40.1



[PATCH] Export value/mask known bits from IPA.

2023-07-17 Thread Aldy Hernandez via Gcc-patches
Currently IPA throws away the known 1 bits because VRP and irange have
traditionally only had a way of tracking known 0s (set_nonzero_bits).
With the ability to keep all the known bits in the irange, we can now
save this between passes.

OK?

gcc/ChangeLog:

* ipa-prop.cc (ipcp_update_bits): Export value/mask known bits.
---
 gcc/ipa-prop.cc | 7 +++
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
index d2b998f8af5..5d790ff1265 100644
--- a/gcc/ipa-prop.cc
+++ b/gcc/ipa-prop.cc
@@ -5853,10 +5853,9 @@ ipcp_update_bits (struct cgraph_node *node, 
ipcp_transformation *ts)
{
  unsigned prec = TYPE_PRECISION (TREE_TYPE (ddef));
  signop sgn = TYPE_SIGN (TREE_TYPE (ddef));
-
- wide_int nonzero_bits = wide_int::from (bits[i]->mask, prec, UNSIGNED)
- | wide_int::from (bits[i]->value, prec, sgn);
- set_nonzero_bits (ddef, nonzero_bits);
+ wide_int mask = wide_int::from (bits[i]->mask, prec, UNSIGNED);
+ wide_int value = wide_int::from (bits[i]->value, prec, sgn);
+ set_bitmask (ddef, value, mask);
}
   else
{
-- 
2.40.1



[PATCH] Export value/mask known bits from CCP.

2023-07-17 Thread Aldy Hernandez via Gcc-patches
Currently CCP throws away the known 1 bits because VRP and irange have
traditionally only had a way of tracking known 0s (set_nonzero_bits).
With the ability to keep all the known bits in the irange, we can now
save this between passes.

OK?

gcc/ChangeLog:

* tree-ssa-ccp.cc (ccp_finalize): Export value/mask known bits.
---
 gcc/tree-ssa-ccp.cc | 8 +++-
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/gcc/tree-ssa-ccp.cc b/gcc/tree-ssa-ccp.cc
index 0d0f02a8442..64d5fa81334 100644
--- a/gcc/tree-ssa-ccp.cc
+++ b/gcc/tree-ssa-ccp.cc
@@ -1020,11 +1020,9 @@ ccp_finalize (bool nonzero_p)
   else
{
  unsigned int precision = TYPE_PRECISION (TREE_TYPE (val->value));
- wide_int nonzero_bits
-   = (wide_int::from (val->mask, precision, UNSIGNED)
-  | wi::to_wide (val->value));
- nonzero_bits &= get_nonzero_bits (name);
- set_nonzero_bits (name, nonzero_bits);
+ wide_int value = wi::to_wide (val->value);
+ wide_int mask = wide_int::from (val->mask, precision, UNSIGNED);
+ set_bitmask (name, value, mask);
}
 }
 
-- 
2.40.1



[COMMITTED] Normalize irange_bitmask before union/intersect.

2023-07-17 Thread Aldy Hernandez via Gcc-patches
The bit twiddling in union/intersect for the value/mask pair must be
normalized to have the unknown bits with a value of 0 in order to make
the math simpler.  Normalizing at construction slowed VRP by 1.5% so I
opted to normalize before updating the bitmask in range-ops, since it
was the only user.  However, with upcoming changes there will be
multiple setters of the mask (IPA and CCP), so we need something more
general.

I played with various alternatives, and settled on normalizing before
union/intersect which were the ones needing the bits cleared.  With
this patch, there's no noticeable difference in performance either in
VRP or in overall compilation.

gcc/ChangeLog:

* value-range.cc (irange_bitmask::verify_mask): Mask need not be
normalized.
* value-range.h (irange_bitmask::union_): Normalize beforehand.
(irange_bitmask::intersect): Same.
---
 gcc/value-range.cc |  3 ---
 gcc/value-range.h  | 12 ++--
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 011bdbdeae6..2abf57bcee8 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -1953,9 +1953,6 @@ void
 irange_bitmask::verify_mask () const
 {
   gcc_assert (m_value.get_precision () == m_mask.get_precision ());
-  // Unknown bits must have their corresponding value bits cleared as
-  // it simplifies union and intersect.
-  gcc_assert (wi::bit_and (m_mask, m_value) == 0);
 }
 
 void
diff --git a/gcc/value-range.h b/gcc/value-range.h
index 0170188201b..d8af6fca7d7 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -211,8 +211,12 @@ irange_bitmask::operator== (const irange_bitmask ) 
const
 }
 
 inline bool
-irange_bitmask::union_ (const irange_bitmask )
+irange_bitmask::union_ (const irange_bitmask _src)
 {
+  // Normalize mask.
+  irange_bitmask src (orig_src.m_value & ~orig_src.m_mask, orig_src.m_mask);
+  m_value &= ~m_mask;
+
   irange_bitmask save (*this);
   m_mask = (m_mask | src.m_mask) | (m_value ^ src.m_value);
   m_value = m_value & src.m_value;
@@ -222,8 +226,12 @@ irange_bitmask::union_ (const irange_bitmask )
 }
 
 inline bool
-irange_bitmask::intersect (const irange_bitmask )
+irange_bitmask::intersect (const irange_bitmask _src)
 {
+  // Normalize mask.
+  irange_bitmask src (orig_src.m_value & ~orig_src.m_mask, orig_src.m_mask);
+  m_value &= ~m_mask;
+
   irange_bitmask save (*this);
   // If we have two known bits that are incompatible, the resulting
   // bit is undefined.  It is unclear whether we should set the entire
-- 
2.40.1



[COMMITTED] Add global setter for value/mask pair for SSA names.

2023-07-17 Thread Aldy Hernandez via Gcc-patches
This patch provides a way to set the value/mask pair of known bits
globally, similarly to how we can use set_nonzero_bits for known 0
bits.  This can then be used by CCP and IPA to set value/mask info
instead of throwing away the known 1 bits.

In further clean-ups, I will see if it makes sense to remove
set_nonzero_bits altogether, since it is subsumed by value/mask.

gcc/ChangeLog:

* tree-ssanames.cc (set_bitmask): New.
* tree-ssanames.h (set_bitmask): New.
---
 gcc/tree-ssanames.cc | 15 +++
 gcc/tree-ssanames.h  |  1 +
 2 files changed, 16 insertions(+)

diff --git a/gcc/tree-ssanames.cc b/gcc/tree-ssanames.cc
index 5fdb6a37e9f..f54394363a0 100644
--- a/gcc/tree-ssanames.cc
+++ b/gcc/tree-ssanames.cc
@@ -465,6 +465,21 @@ set_nonzero_bits (tree name, const wide_int )
   set_range_info (name, r);
 }
 
+/* Update the known bits of NAME.
+
+   Zero bits in MASK cover constant values.  Set bits in MASK cover
+   unknown values.  VALUE are the known bits.  */
+
+void
+set_bitmask (tree name, const wide_int , const wide_int )
+{
+  gcc_assert (!POINTER_TYPE_P (TREE_TYPE (name)));
+
+  int_range<2> r (TREE_TYPE (name));
+  r.update_bitmask (irange_bitmask (value, mask));
+  set_range_info (name, r);
+}
+
 /* Return a widest_int with potentially non-zero bits in SSA_NAME
NAME, the constant for INTEGER_CST, or -1 if unknown.  */
 
diff --git a/gcc/tree-ssanames.h b/gcc/tree-ssanames.h
index f3fa609208a..b5e3f228ee8 100644
--- a/gcc/tree-ssanames.h
+++ b/gcc/tree-ssanames.h
@@ -59,6 +59,7 @@ struct GTY(()) ptr_info_def
 /* Sets the value range to SSA.  */
 extern bool set_range_info (tree, const vrange &);
 extern void set_nonzero_bits (tree, const wide_int &);
+extern void set_bitmask (tree, const wide_int , const wide_int );
 extern wide_int get_nonzero_bits (const_tree);
 extern bool ssa_name_has_boolean_range (tree);
 extern void init_ssanames (struct function *, int);
-- 
2.40.1



Re: [PATCH V4] Optimize '(X - N * M) / N' to 'X / N - M' if valid

2023-07-14 Thread Aldy Hernandez via Gcc-patches




On 7/14/23 15:37, Richard Biener wrote:

On Fri, 14 Jul 2023, Aldy Hernandez wrote:


I don't know what you're trying to accomplish here, as I haven't been
following the PR, but adding all these helper functions to the ranger header
file seems wrong, especially since there's only one use of them. I see you're
tweaking the irange API, adding helper functions to range-op (which is only
for code dealing with implementing range operators for tree codes), etc etc.

If you need these helper functions, I suggest you put them closer to their
uses (i.e. wherever the match.pd support machinery goes).


Note I suggested the opposite beacuse I thought these kind of helpers
are closer to value-range support than to match.pd.


Oh sorry, I missed that.



But I take away from your answer that there's nothing close in the
value-range machinery that answers the question whether A op B may
overflow?


Not currently.

I vaguely recall we talked about some mechanism for doing range 
operations in a wider precision and comparing them with the result of 
doing it in the natural precision, and if the results differ, it must 
have overflowed.


*hunts down PR*

Comment 23 here:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100499#c23

Would something like that work?

I would prefer something more general, rather than having to re-invent 
every range-op entry to check for overflow.


Aldy



Re: [PATCH V4] Optimize '(X - N * M) / N' to 'X / N - M' if valid

2023-07-14 Thread Aldy Hernandez via Gcc-patches
I don't know what you're trying to accomplish here, as I haven't been 
following the PR, but adding all these helper functions to the ranger 
header file seems wrong, especially since there's only one use of them. 
I see you're tweaking the irange API, adding helper functions to 
range-op (which is only for code dealing with implementing range 
operators for tree codes), etc etc.


If you need these helper functions, I suggest you put them closer to 
their uses (i.e. wherever the match.pd support machinery goes).


Aldy

On 7/11/23 11:04, Jiufu Guo wrote:

Hi,

Integer expression "(X - N * M) / N" can be optimized to "X / N - M"
if there is no wrap/overflow/underflow and "X - N * M" has the same
sign with "X".

Compare the previous version:
https://gcc.gnu.org/pipermail/gcc-patches/2023-June/623028.html
- The APIs for checking overflow of range operation are moved to
other files: range-op and gimple-range.
- Improve the patterns with '(X + C)' for unsigned type.

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

BR,
Jeff (Jiufu Guo)


PR tree-optimization/108757

gcc/ChangeLog:

* gimple-range.cc (arith_without_overflow_p): New function.
(same_sign_p): New function.
* gimple-range.h (arith_without_overflow_p): New declare.
(same_sign_p): New declare.
* match.pd ((X - N * M) / N): New pattern.
((X + N * M) / N): New pattern.
((X + C) div_rshift N): New pattern.
* range-op.cc (plus_without_overflow_p): New function.
(minus_without_overflow_p): New function.
(mult_without_overflow_p): New function.
* range-op.h (plus_without_overflow_p): New declare.
(minus_without_overflow_p): New declare.
(mult_without_overflow_p): New declare.
* value-query.h (get_range): New function
* value-range.cc (irange::nonnegative_p): New function.
(irange::nonpositive_p): New function.
* value-range.h (irange::nonnegative_p): New declare.
(irange::nonpositive_p): New declare.

gcc/testsuite/ChangeLog:

* gcc.dg/pr108757-1.c: New test.
* gcc.dg/pr108757-2.c: New test.
* gcc.dg/pr108757.h: New test.

---
  gcc/gimple-range.cc   |  50 +++
  gcc/gimple-range.h|   2 +
  gcc/match.pd  |  64 
  gcc/range-op.cc   |  77 ++
  gcc/range-op.h|   4 +
  gcc/value-query.h |  10 ++
  gcc/value-range.cc|  12 ++
  gcc/value-range.h |   2 +
  gcc/testsuite/gcc.dg/pr108757-1.c |  18 +++
  gcc/testsuite/gcc.dg/pr108757-2.c |  19 +++
  gcc/testsuite/gcc.dg/pr108757.h   | 233 ++
  11 files changed, 491 insertions(+)
  create mode 100644 gcc/testsuite/gcc.dg/pr108757-1.c
  create mode 100644 gcc/testsuite/gcc.dg/pr108757-2.c
  create mode 100644 gcc/testsuite/gcc.dg/pr108757.h

diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 
01e62d3ff3901143bde33dc73c0debf41d0c0fdd..620fe32e85e5fe3847a933554fc656b2939cf02d
 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -926,3 +926,53 @@ assume_query::dump (FILE *f)
  }
fprintf (f, "--\n");
  }
+
+/* Return true if the operation "X CODE Y" in type does not overflow
+   underflow or wrap with value range info, otherwise return false.  */
+
+bool
+arith_without_overflow_p (tree_code code, tree x, tree y, tree type)
+{
+  gcc_assert (INTEGRAL_TYPE_P (type));
+
+  if (TYPE_OVERFLOW_UNDEFINED (type))
+return true;
+
+  value_range vr0;
+  value_range vr1;
+  if (!(get_range (vr0, x) && get_range (vr1, y)))
+return false;
+
+  switch (code)
+{
+case PLUS_EXPR:
+  return plus_without_overflow_p (vr0, vr1, type);
+case MINUS_EXPR:
+  return minus_without_overflow_p (vr0, vr1, type);
+case MULT_EXPR:
+  return mult_without_overflow_p (vr0, vr1, type);
+default:
+  gcc_unreachable ();
+}
+
+  return false;
+}
+
+/* Return true if "X" and "Y" have the same sign or zero.  */
+
+bool
+same_sign_p (tree x, tree y, tree type)
+{
+  gcc_assert (INTEGRAL_TYPE_P (type));
+
+  if (TYPE_UNSIGNED (type))
+return true;
+
+  value_range vr0;
+  value_range vr1;
+  if (!(get_range (vr0, x) && get_range (vr1, y)))
+return false;
+
+  return (vr0.nonnegative_p () && vr1.nonnegative_p ())
+|| (vr0.nonpositive_p () && vr1.nonpositive_p ());
+}
diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h
index 
6587e4923ff44e10826a697ecced237a0ad23c88..84eac87392b642ed3305011415c804f5b319e09f
 100644
--- a/gcc/gimple-range.h
+++ b/gcc/gimple-range.h
@@ -101,5 +101,7 @@ protected:
gori_compute m_gori;
  };
  
+bool arith_without_overflow_p (tree_code code, tree x, tree y, tree type);

+bool same_sign_p (tree x, tree y, tree type);
  
  #endif // GCC_GIMPLE_RANGE_H

diff --git a/gcc/match.pd b/gcc/match.pd
index 

Re: [COMMITTED] [range-op] Take known set bits into account in popcount [PR107053]

2023-07-14 Thread Aldy Hernandez via Gcc-patches




On 7/12/23 23:50, Jeff Law wrote:



On 7/12/23 15:15, Aldy Hernandez via Gcc-patches wrote:

This patch teaches popcount about known set bits which are now
available in the irange.

PR tree-optimization/107053

gcc/ChangeLog:

* gimple-range-op.cc (cfn_popcount): Use known set bits.

gcc/testsuite/ChangeLog:

* gcc.dg/tree-ssa/pr107053.c: New test.
You could probably play similar games with ctz/clz, though it's hard to 
know if it's worth the effort.


One way to find out might be to build jemalloc which uses those idioms 
heavily.  Similarly for deepsjeng from spec2017.


Jeff



See class cfn_clz and class cfn_ctz in gimple-range-op.cc.  There's 
already code for both of these, although they're throwback from the VRP 
era, so there's definitely room for improvement.  I think they came from 
vr-values.cc.


Aldy



[COMMITTED] [range-op] Take known set bits into account in popcount [PR107053]

2023-07-12 Thread Aldy Hernandez via Gcc-patches
This patch teaches popcount about known set bits which are now
available in the irange.

PR tree-optimization/107053

gcc/ChangeLog:

* gimple-range-op.cc (cfn_popcount): Use known set bits.

gcc/testsuite/ChangeLog:

* gcc.dg/tree-ssa/pr107053.c: New test.
---
 gcc/gimple-range-op.cc   | 11 +++
 gcc/testsuite/gcc.dg/tree-ssa/pr107053.c | 13 +
 2 files changed, 20 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr107053.c

diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index 72c7b866f90..67b3c3d015e 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -880,17 +880,20 @@ public:
 if (lh.undefined_p ())
   return false;
 unsigned prec = TYPE_PRECISION (type);
-wide_int nz = lh.get_nonzero_bits ();
-wide_int pop = wi::shwi (wi::popcount (nz), prec);
+irange_bitmask bm = lh.get_bitmask ();
+wide_int nz = bm.get_nonzero_bits ();
+wide_int high = wi::shwi (wi::popcount (nz), prec);
 // Calculating the popcount of a singleton is trivial.
 if (lh.singleton_p ())
   {
-   r.set (type, pop, pop);
+   r.set (type, high, high);
return true;
   }
 if (cfn_ffs::fold_range (r, type, lh, rh, rel))
   {
-   int_range<2> tmp (type, wi::zero (prec), pop);
+   wide_int known_ones = ~bm.mask () & bm.value ();
+   wide_int low = wi::shwi (wi::popcount (known_ones), prec);
+   int_range<2> tmp (type, low, high);
r.intersect (tmp);
return true;
   }
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr107053.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr107053.c
new file mode 100644
index 000..8195d0f57b4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr107053.c
@@ -0,0 +1,13 @@
+// { dg-do compile }
+// { dg-options "-O2 -fdump-tree-evrp" }
+
+void link_failure();
+void f(int a)
+{
+a |= 0x300;
+int b =  __builtin_popcount(a);
+if (b < 2)
+link_failure();
+}
+
+// { dg-final { scan-tree-dump-not "link_failure" "evrp" } }
-- 
2.40.1



[COMMITTED] [range-op] Take known mask into account for bitwise ands [PR107043]

2023-07-12 Thread Aldy Hernandez via Gcc-patches
PR tree-optimization/107043

gcc/ChangeLog:

* range-op.cc (operator_bitwise_and::op1_range): Update bitmask.

gcc/testsuite/ChangeLog:

* gcc.dg/tree-ssa/pr107043.c: New test.
---
 gcc/range-op.cc  |  8 
 gcc/testsuite/gcc.dg/tree-ssa/pr107043.c | 22 ++
 2 files changed, 30 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr107043.c

diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 56e80c9f3ae..6b5d4f2accd 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -3463,6 +3463,14 @@ operator_bitwise_and::op1_range (irange , tree type,
   if (r.undefined_p ())
 set_nonzero_range_from_mask (r, type, lhs);
 
+  // For MASK == op1 & MASK, all the bits in MASK must be set in op1.
+  wide_int mask;
+  if (lhs == op2 && lhs.singleton_p (mask))
+{
+  r.update_bitmask (irange_bitmask (mask, ~mask));
+  return true;
+}
+
   // For 0 = op1 & MASK, op1 is ~MASK.
   if (lhs.zero_p () && op2.singleton_p ())
 {
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr107043.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr107043.c
new file mode 100644
index 000..af5df225746
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr107043.c
@@ -0,0 +1,22 @@
+// { dg-do compile }
+// { dg-options "-O2 -fdump-tree-evrp" }
+
+int g0(int n)
+{
+  int n1 = n & 0x8000;
+  if (n1 == 0)
+return 1;
+  // n1 will be 0x8000 here.
+  return (n1 >> 15) & 0x1;
+}
+
+int g1(int n)
+{
+  int n1 = n & 0x8000;
+  if (n1 == 0)
+return 1;
+  // n>>15 will be xx1 here.
+  return (n >> 15) & 0x1;
+}
+
+// { dg-final { scan-tree-dump-times "return 1;" 2 "evrp" } }
-- 
2.40.1



[COMMITTED] [range-op] Enable value/mask propagation in range-op.

2023-07-12 Thread Aldy Hernandez via Gcc-patches
Throw the switch in range-ops to make full use of the value/mask
information instead of only the nonzero bits.  This will cause most of
the operators implemented in range-ops to use the value/mask
information calculated by CCP's bit_value_binop() function which
range-ops uses.  This opens up more optimization opportunities.

In follow-up patches I will change the global range setter
(set_range_info) to be able to save the value/mask pair, and make both
CCP and IPA be able to save the known ones bit info, instead of
throwing it away.

gcc/ChangeLog:

* range-op.cc (irange_to_masked_value): Remove.
(update_known_bitmask): Update irange value/mask pair instead of
only updating nonzero bits.

gcc/testsuite/ChangeLog:

* gcc.dg/pr83073.c: Adjust testcase.
---
 gcc/range-op.cc| 53 ++
 gcc/testsuite/gcc.dg/pr83073.c |  2 +-
 2 files changed, 23 insertions(+), 32 deletions(-)

diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index cb584314f4c..56e80c9f3ae 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -367,23 +367,6 @@ range_op_handler::op1_op2_relation (const vrange ) 
const
 }
 
 
-// Convert irange bitmasks into a VALUE MASK pair suitable for calling CCP.
-
-static void
-irange_to_masked_value (const irange , widest_int , widest_int )
-{
-  if (r.singleton_p ())
-{
-  mask = 0;
-  value = widest_int::from (r.lower_bound (), TYPE_SIGN (r.type ()));
-}
-  else
-{
-  mask = widest_int::from (r.get_nonzero_bits (), TYPE_SIGN (r.type ()));
-  value = 0;
-}
-}
-
 // Update the known bitmasks in R when applying the operation CODE to
 // LH and RH.
 
@@ -391,25 +374,33 @@ void
 update_known_bitmask (irange , tree_code code,
  const irange , const irange )
 {
-  if (r.undefined_p () || lh.undefined_p () || rh.undefined_p ())
+  if (r.undefined_p () || lh.undefined_p () || rh.undefined_p ()
+  || r.singleton_p ())
 return;
 
-  widest_int value, mask, lh_mask, rh_mask, lh_value, rh_value;
+  widest_int widest_value, widest_mask;
   tree type = r.type ();
   signop sign = TYPE_SIGN (type);
   int prec = TYPE_PRECISION (type);
-  signop lh_sign = TYPE_SIGN (lh.type ());
-  signop rh_sign = TYPE_SIGN (rh.type ());
-  int lh_prec = TYPE_PRECISION (lh.type ());
-  int rh_prec = TYPE_PRECISION (rh.type ());
-
-  irange_to_masked_value (lh, lh_value, lh_mask);
-  irange_to_masked_value (rh, rh_value, rh_mask);
-  bit_value_binop (code, sign, prec, , ,
-  lh_sign, lh_prec, lh_value, lh_mask,
-  rh_sign, rh_prec, rh_value, rh_mask);
-  wide_int tmp = wide_int::from (value | mask, prec, sign);
-  r.set_nonzero_bits (tmp);
+  irange_bitmask lh_bits = lh.get_bitmask ();
+  irange_bitmask rh_bits = rh.get_bitmask ();
+
+  bit_value_binop (code, sign, prec, _value, _mask,
+  TYPE_SIGN (lh.type ()),
+  TYPE_PRECISION (lh.type ()),
+  widest_int::from (lh_bits.value (), sign),
+  widest_int::from (lh_bits.mask (), sign),
+  TYPE_SIGN (rh.type ()),
+  TYPE_PRECISION (rh.type ()),
+  widest_int::from (rh_bits.value (), sign),
+  widest_int::from (rh_bits.mask (), sign));
+
+  wide_int mask = wide_int::from (widest_mask, prec, sign);
+  wide_int value = wide_int::from (widest_value, prec, sign);
+  // Bitmasks must have the unknown value bits cleared.
+  value &= ~mask;
+  irange_bitmask bm (value, mask);
+  r.update_bitmask (bm);
 }
 
 // Return the upper limit for a type.
diff --git a/gcc/testsuite/gcc.dg/pr83073.c b/gcc/testsuite/gcc.dg/pr83073.c
index 1168ae822a4..228e1890086 100644
--- a/gcc/testsuite/gcc.dg/pr83073.c
+++ b/gcc/testsuite/gcc.dg/pr83073.c
@@ -7,4 +7,4 @@ int f(int x)
 return x & 1;
 }
 
-/* { dg-final { scan-tree-dump "gimple_simplified to.* = 1" "evrp" } }  */
+/* { dg-final { scan-tree-dump "Folded into: return 1;" "evrp" } }  */
-- 
2.40.1



[COMMITTED] Implement value/mask tracking for irange.

2023-07-07 Thread Aldy Hernandez via Gcc-patches
Integer ranges (irange) currently track known 0 bits.  We've wanted to
track known 1 bits for some time, and instead of tracking known 0 and
known 1's separately, it has been suggested we track a value/mask pair
similarly to what we do for CCP and RTL.  This patch implements such a
thing.

With this we now track a VALUE integer which are the known values, and
a MASK which tells us which bits contain meaningful information.  This
allows us to fix a handful of enhancement requests, such as PR107043
and PR107053.

There is a 4.48% performance penalty for VRP and 0.42% in overall
compilation for this entire patchset.  It is expected and in line
with the loss incurred when we started tracking known 0 bits.

This patch just provides the value/mask tracking support.  All the
nonzero users (range-op, IPA, CCP, etc), are still using the nonzero
nomenclature.  For that matter, this patch reimplements the nonzero
accessors with the value/mask functionality.  In follow-up patches I
will enhance these passes to use the value/mask information, and
fix the aforementioned PRs.

gcc/ChangeLog:

* data-streamer-in.cc (streamer_read_value_range): Adjust for
value/mask.
* data-streamer-out.cc (streamer_write_vrange): Same.
* range-op.cc (operator_cast::fold_range): Same.
* value-range-pretty-print.cc
(vrange_printer::print_irange_bitmasks): Same.
* value-range-storage.cc (irange_storage::write_lengths_address):
Same.
(irange_storage::set_irange): Same.
(irange_storage::get_irange): Same.
(irange_storage::size): Same.
(irange_storage::dump): Same.
* value-range-storage.h: Same.
* value-range.cc (debug): New.
(irange_bitmask::dump): New.
(add_vrange): Adjust for value/mask.
(irange::operator=): Same.
(irange::set): Same.
(irange::verify_range): Same.
(irange::operator==): Same.
(irange::contains_p): Same.
(irange::irange_single_pair_union): Same.
(irange::union_): Same.
(irange::intersect): Same.
(irange::invert): Same.
(irange::get_nonzero_bits_from_range): Rename to...
(irange::get_bitmask_from_range): ...this.
(irange::set_range_from_nonzero_bits): Rename to...
(irange::set_range_from_bitmask): ...this.
(irange::set_nonzero_bits): Rename to...
(irange::update_bitmask): ...this.
(irange::get_nonzero_bits): Rename to...
(irange::get_bitmask): ...this.
(irange::intersect_nonzero_bits): Rename to...
(irange::intersect_bitmask): ...this.
(irange::union_nonzero_bits): Rename to...
(irange::union_bitmask): ...this.
(irange_bitmask::verify_mask): New.
* value-range.h (class irange_bitmask): New.
(irange_bitmask::set_unknown): New.
(irange_bitmask::unknown_p): New.
(irange_bitmask::irange_bitmask): New.
(irange_bitmask::get_precision): New.
(irange_bitmask::get_nonzero_bits): New.
(irange_bitmask::set_nonzero_bits): New.
(irange_bitmask::operator==): New.
(irange_bitmask::union_): New.
(irange_bitmask::intersect): New.
(class irange): Friend vrange_printer.
(irange::varying_compatible_p): Adjust for bitmask.
(irange::set_varying): Same.
(irange::set_nonzero): Same.

gcc/testsuite/ChangeLog:

* gcc.dg/tree-ssa/pr107009.c: Adjust irange dumping for
value/mask changes.
* gcc.dg/tree-ssa/vrp-unreachable.c: Same.
* gcc.dg/tree-ssa/vrp122.c: Same.
---
 gcc/data-streamer-in.cc   |   6 +-
 gcc/data-streamer-out.cc  |   5 +-
 gcc/range-op.cc   |  16 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr107009.c  |   2 +-
 .../gcc.dg/tree-ssa/vrp-unreachable.c |   2 +-
 gcc/testsuite/gcc.dg/tree-ssa/vrp122.c|   2 +-
 gcc/value-range-pretty-print.cc   |  11 +-
 gcc/value-range-storage.cc|  26 +-
 gcc/value-range-storage.h |   2 +-
 gcc/value-range.cc| 248 +++---
 gcc/value-range.h | 153 ++-
 11 files changed, 351 insertions(+), 122 deletions(-)

diff --git a/gcc/data-streamer-in.cc b/gcc/data-streamer-in.cc
index 578c328475f..6e36adc73cc 100644
--- a/gcc/data-streamer-in.cc
+++ b/gcc/data-streamer-in.cc
@@ -241,8 +241,10 @@ streamer_read_value_range (class lto_input_block *ib, 
data_in *data_in,
  int_range<2> tmp (type, lb, ub);
  r.union_ (tmp);
}
-  wide_int nz = streamer_read_wide_int (ib);
-  r.set_nonzero_bits (nz);
+  wide_int value = streamer_read_wide_int (ib);
+  wide_int mask = streamer_read_wide_int (ib);
+  irange_bitmask bm (value, mask);
+  r.update_bitmask (bm);
   return;
 }
   if (is_a  (vr))
diff --git a/gcc/data-streamer-out.cc 

[COMMITTED] The caller to irange::intersect (wide_int, wide_int) must normalize the range.

2023-07-07 Thread Aldy Hernandez via Gcc-patches
Per the function comment, the caller to intersect(wide_int, wide_int)
must handle the mask.  This means it must also normalize the range if
anything changed.

gcc/ChangeLog:

* value-range.cc (irange::intersect): Leave normalization to
caller.
---
 gcc/value-range.cc | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 8e5607a7eeb..fbc0c7a6f82 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -1475,6 +1475,8 @@ irange::intersect (const vrange )
return true;
 
   res |= intersect_bitmask (r);
+  if (res)
+   normalize_kind ();
   return res;
 }
 
@@ -1574,7 +1576,7 @@ irange::intersect (const vrange )
 // Multirange intersect for a specified wide_int [lb, ub] range.
 // Return TRUE if intersect changed anything.
 //
-// NOTE: It is the caller's responsibility to intersect the nonzero masks.
+// NOTE: It is the caller's responsibility to intersect the mask.
 
 bool
 irange::intersect (const wide_int& lb, const wide_int& ub)
@@ -1633,7 +1635,8 @@ irange::intersect (const wide_int& lb, const wide_int& ub)
 }
 
   m_kind = VR_RANGE;
-  normalize_kind ();
+  // The caller must normalize and verify the range, as the bitmask
+  // still needs to be handled.
   return true;
 }
 
-- 
2.40.1



[COMMITTED] A singleton irange has all known bits.

2023-07-07 Thread Aldy Hernandez via Gcc-patches
gcc/ChangeLog:

* value-range.cc (irange::get_bitmask_from_range): Return all the
known bits for a singleton.
(irange::set_range_from_bitmask): Set a range of a singleton when
all bits are known.
---
 gcc/value-range.cc | 19 ++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index fbc0c7a6f82..011bdbdeae6 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -1766,10 +1766,19 @@ irange::invert ()
 irange_bitmask
 irange::get_bitmask_from_range () const
 {
+  unsigned prec = TYPE_PRECISION (type ());
   wide_int min = lower_bound ();
   wide_int max = upper_bound ();
+
+  // All the bits of a singleton are known.
+  if (min == max)
+{
+  wide_int mask = wi::zero (prec);
+  wide_int value = lower_bound ();
+  return irange_bitmask (value, mask);
+}
+
   wide_int xorv = min ^ max;
-  unsigned prec = TYPE_PRECISION (type ());
 
   if (xorv != 0)
 xorv = wi::mask (prec - wi::clz (xorv), false, prec);
@@ -1786,6 +1795,14 @@ irange::set_range_from_bitmask ()
   gcc_checking_assert (!undefined_p ());
   if (m_bitmask.unknown_p ())
 return false;
+
+  // If all the bits are known, this is a singleton.
+  if (m_bitmask.mask () == 0)
+{
+  set (m_type, m_bitmask.value (), m_bitmask.value ());
+  return true;
+}
+
   unsigned popcount = wi::popcount (m_bitmask.get_nonzero_bits ());
 
   // If we have only one bit set in the mask, we can figure out the
-- 
2.40.1



[COMMITTED] Tidy up the range normalization code.

2023-06-29 Thread Aldy Hernandez via Gcc-patches
There's a few spots where a range is being altered in-place, but we
fail to call normalize the range.  This patch makes sure we always
call normalize_kind(), and that normalize_kind in turn, calls
verify_range to make sure verything is canonical.

gcc/ChangeLog:

* value-range.cc (frange::set): Do not call verify_range.
(frange::normalize_kind): Verify range.
(frange::union_nans): Do not call verify_range.
(frange::union_): Same.
(frange::intersect): Same.
(irange::irange_single_pair_union): Call normalize_kind if
necessary.
(irange::union_): Same.
(irange::intersect): Same.
(irange::set_range_from_nonzero_bits): Verify range.
(irange::set_nonzero_bits): Call normalize_kind if necessary.
(irange::get_nonzero_bits): Tweak comment.
(irange::intersect_nonzero_bits): Call normalize_kind if
necessary.
(irange::union_nonzero_bits): Same.
* value-range.h (irange::normalize_kind): Verify range.
---
 gcc/value-range.cc | 99 ++
 gcc/value-range.h  |  2 +
 2 files changed, 50 insertions(+), 51 deletions(-)

diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 6f46f7c9875..f5d4bf3bb4a 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -411,9 +411,6 @@ frange::set (tree type,
   gcc_checking_assert (real_compare (LE_EXPR, , ));
 
   normalize_kind ();
-
-  if (flag_checking)
-verify_range ();
 }
 
 // Setter for an frange defaulting the NAN possibility to +-NAN when
@@ -462,6 +459,8 @@ frange::normalize_kind ()
  m_kind = VR_RANGE;
  m_min = frange_val_min (m_type);
  m_max = frange_val_max (m_type);
+ if (flag_checking)
+   verify_range ();
  return true;
}
 }
@@ -524,8 +523,6 @@ frange::union_nans (const frange )
   m_pos_nan |= r.m_pos_nan;
   m_neg_nan |= r.m_neg_nan;
   normalize_kind ();
-  if (flag_checking)
-verify_range ();
   return true;
 }
 
@@ -569,8 +566,6 @@ frange::union_ (const vrange )
 changed |= combine_zeros (r, true);
 
   changed |= normalize_kind ();
-  if (flag_checking)
-verify_range ();
   return changed;
 }
 
@@ -648,8 +643,6 @@ frange::intersect (const vrange )
 changed |= combine_zeros (r, false);
 
   changed |= normalize_kind ();
-  if (flag_checking)
-verify_range ();
   return changed;
 }
 
@@ -1197,7 +1190,12 @@ irange::irange_single_pair_union (const irange )
  m_base[3] = r.m_base[1];
  m_num_ranges = 2;
}
-  union_nonzero_bits (r);
+  // The range has been altered, so normalize it even if nothing
+  // changed in the mask.
+  if (!union_nonzero_bits (r))
+   normalize_kind ();
+  if (flag_checking)
+   verify_range ();
   return true;
 }
 
@@ -1221,7 +1219,12 @@ irange::irange_single_pair_union (const irange )
   m_base[3] = m_base[1];
   m_base[1] = r.m_base[1];
 }
-  union_nonzero_bits (r);
+  // The range has been altered, so normalize it even if nothing
+  // changed in the mask.
+  if (!union_nonzero_bits (r))
+normalize_kind ();
+  if (flag_checking)
+verify_range ();
   return true;
 }
 
@@ -1351,7 +1354,12 @@ irange::union_ (const vrange )
   m_num_ranges = i / 2;
 
   m_kind = VR_RANGE;
-  union_nonzero_bits (r);
+  // The range has been altered, so normalize it even if nothing
+  // changed in the mask.
+  if (!union_nonzero_bits (r))
+normalize_kind ();
+  if (flag_checking)
+verify_range ();
   return true;
 }
 
@@ -1518,7 +1526,12 @@ irange::intersect (const vrange )
 }
 
   m_kind = VR_RANGE;
-  intersect_nonzero_bits (r);
+  // The range has been altered, so normalize it even if nothing
+  // changed in the mask.
+  if (!intersect_nonzero_bits (r))
+normalize_kind ();
+  if (flag_checking)
+verify_range ();
   return true;
 }
 
@@ -1585,10 +1598,7 @@ irange::intersect (const wide_int& lb, const wide_int& 
ub)
 }
 
   m_kind = VR_RANGE;
-  // No need to call normalize_kind(), as the caller will do this
-  // while intersecting the nonzero mask.
-  if (flag_checking)
-verify_range ();
+  normalize_kind ();
   return true;
 }
 
@@ -1758,6 +1768,8 @@ irange::set_range_from_nonzero_bits ()
  zero.set_zero (type ());
  union_ (zero);
}
+  if (flag_checking)
+   verify_range ();
   return true;
 }
   else if (popcount == 0)
@@ -1778,10 +1790,8 @@ irange::set_nonzero_bits (const wide_int )
 m_kind = VR_RANGE;
 
   m_nonzero_mask = bits;
-  if (set_range_from_nonzero_bits ())
-return;
-
-  normalize_kind ();
+  if (!set_range_from_nonzero_bits ())
+normalize_kind ();
   if (flag_checking)
 verify_range ();
 }
@@ -1807,8 +1817,8 @@ irange::get_nonzero_bits () const
 return m_nonzero_mask & get_nonzero_bits_from_range ();
 }
 
-// Intersect the nonzero bits in R into THIS and normalize the range.
-// Return TRUE if the intersection changed 

[COMMITTED] Move maybe_set_nonzero_bits() to its only user.

2023-06-29 Thread Aldy Hernandez via Gcc-patches
gcc/ChangeLog:

* tree-vrp.cc (maybe_set_nonzero_bits): Move from here...
* tree-ssa-dom.cc (maybe_set_nonzero_bits): ...to here.
* tree-vrp.h (maybe_set_nonzero_bits): Remove.
---
 gcc/tree-ssa-dom.cc | 65 +
 gcc/tree-vrp.cc | 65 -
 gcc/tree-vrp.h  |  1 -
 3 files changed, 65 insertions(+), 66 deletions(-)

diff --git a/gcc/tree-ssa-dom.cc b/gcc/tree-ssa-dom.cc
index 9f534b5a190..f7f8b730877 100644
--- a/gcc/tree-ssa-dom.cc
+++ b/gcc/tree-ssa-dom.cc
@@ -1338,6 +1338,71 @@ all_uses_feed_or_dominated_by_stmt (tree name, gimple 
*stmt)
   return true;
 }
 
+/* Handle
+   _4 = x_3 & 31;
+   if (_4 != 0)
+ goto ;
+   else
+ goto ;
+   :
+   __builtin_unreachable ();
+   :
+
+   If x_3 has no other immediate uses (checked by caller), var is the
+   x_3 var, we can clear low 5 bits from the non-zero bitmask.  */
+
+static void
+maybe_set_nonzero_bits (edge e, tree var)
+{
+  basic_block cond_bb = e->src;
+  gcond *cond = safe_dyn_cast  (*gsi_last_bb (cond_bb));
+  tree cst;
+
+  if (cond == NULL
+  || gimple_cond_code (cond) != ((e->flags & EDGE_TRUE_VALUE)
+? EQ_EXPR : NE_EXPR)
+  || TREE_CODE (gimple_cond_lhs (cond)) != SSA_NAME
+  || !integer_zerop (gimple_cond_rhs (cond)))
+return;
+
+  gimple *stmt = SSA_NAME_DEF_STMT (gimple_cond_lhs (cond));
+  if (!is_gimple_assign (stmt)
+  || gimple_assign_rhs_code (stmt) != BIT_AND_EXPR
+  || TREE_CODE (gimple_assign_rhs2 (stmt)) != INTEGER_CST)
+return;
+  if (gimple_assign_rhs1 (stmt) != var)
+{
+  gimple *stmt2;
+
+  if (TREE_CODE (gimple_assign_rhs1 (stmt)) != SSA_NAME)
+   return;
+  stmt2 = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt));
+  if (!gimple_assign_cast_p (stmt2)
+ || gimple_assign_rhs1 (stmt2) != var
+ || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt2))
+ || (TYPE_PRECISION (TREE_TYPE (gimple_assign_rhs1 (stmt)))
+ != TYPE_PRECISION (TREE_TYPE (var
+   return;
+}
+  cst = gimple_assign_rhs2 (stmt);
+  if (POINTER_TYPE_P (TREE_TYPE (var)))
+{
+  struct ptr_info_def *pi = SSA_NAME_PTR_INFO (var);
+  if (pi && pi->misalign)
+   return;
+  wide_int w = wi::bit_not (wi::to_wide (cst));
+  unsigned int bits = wi::ctz (w);
+  if (bits == 0 || bits >= HOST_BITS_PER_INT)
+   return;
+  unsigned int align = 1U << bits;
+  if (pi == NULL || pi->align < align)
+   set_ptr_info_alignment (get_ptr_info (var), align, 0);
+}
+  else
+set_nonzero_bits (var, wi::bit_and_not (get_nonzero_bits (var),
+   wi::to_wide (cst)));
+}
+
 /* Set global ranges that can be determined from the C->M edge:
 
:
diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc
index c52e9971faa..d61b087b730 100644
--- a/gcc/tree-vrp.cc
+++ b/gcc/tree-vrp.cc
@@ -633,71 +633,6 @@ overflow_comparison_p (tree_code code, tree name, tree 
val, tree *new_cst)
  true, new_cst);
 }
 
-/* Handle
-   _4 = x_3 & 31;
-   if (_4 != 0)
- goto ;
-   else
- goto ;
-   :
-   __builtin_unreachable ();
-   :
-
-   If x_3 has no other immediate uses (checked by caller), var is the
-   x_3 var, we can clear low 5 bits from the non-zero bitmask.  */
-
-void
-maybe_set_nonzero_bits (edge e, tree var)
-{
-  basic_block cond_bb = e->src;
-  gcond *cond = safe_dyn_cast  (*gsi_last_bb (cond_bb));
-  tree cst;
-
-  if (cond == NULL
-  || gimple_cond_code (cond) != ((e->flags & EDGE_TRUE_VALUE)
-? EQ_EXPR : NE_EXPR)
-  || TREE_CODE (gimple_cond_lhs (cond)) != SSA_NAME
-  || !integer_zerop (gimple_cond_rhs (cond)))
-return;
-
-  gimple *stmt = SSA_NAME_DEF_STMT (gimple_cond_lhs (cond));
-  if (!is_gimple_assign (stmt)
-  || gimple_assign_rhs_code (stmt) != BIT_AND_EXPR
-  || TREE_CODE (gimple_assign_rhs2 (stmt)) != INTEGER_CST)
-return;
-  if (gimple_assign_rhs1 (stmt) != var)
-{
-  gimple *stmt2;
-
-  if (TREE_CODE (gimple_assign_rhs1 (stmt)) != SSA_NAME)
-   return;
-  stmt2 = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt));
-  if (!gimple_assign_cast_p (stmt2)
- || gimple_assign_rhs1 (stmt2) != var
- || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt2))
- || (TYPE_PRECISION (TREE_TYPE (gimple_assign_rhs1 (stmt)))
- != TYPE_PRECISION (TREE_TYPE (var
-   return;
-}
-  cst = gimple_assign_rhs2 (stmt);
-  if (POINTER_TYPE_P (TREE_TYPE (var)))
-{
-  struct ptr_info_def *pi = SSA_NAME_PTR_INFO (var);
-  if (pi && pi->misalign)
-   return;
-  wide_int w = wi::bit_not (wi::to_wide (cst));
-  unsigned int bits = wi::ctz (w);
-  if (bits == 0 || bits >= HOST_BITS_PER_INT)
-   return;
-  unsigned int align = 1U << bits;
-  if (pi == NULL 

Re: [PATCH] Implement ipa_vr hashing.

2023-06-26 Thread Aldy Hernandez via Gcc-patches
Errr, sorry about this ping.  I was meant to re-ping my IPA patches
after 7 days, but just realized it had been only 4.  My bad.

Aldy

On Mon, Jun 26, 2023 at 11:22 AM Aldy Hernandez  wrote:
>
> PING*3
>
> On Thu, Jun 22, 2023 at 7:49 AM Aldy Hernandez  wrote:
> >
> > Ping*2
> >
> > On Wed, Jun 14, 2023, 14:11 Aldy Hernandez  wrote:
> >>
> >> PING
> >>
> >> On Sat, Jun 10, 2023 at 10:30 PM Aldy Hernandez  wrote:
> >> >
> >> >
> >> >
> >> > On 5/29/23 16:51, Martin Jambor wrote:
> >> > > Hi,
> >> > >
> >> > > On Mon, May 22 2023, Aldy Hernandez via Gcc-patches wrote:
> >> > >> Implement hashing for ipa_vr.  When all is said and done, all these
> >> > >> patches incurr a 7.64% slowdown for ipa-cp, with is entirely covered 
> >> > >> by
> >> > >> the similar 7% increase in this area last week.  So we get type 
> >> > >> agnostic
> >> > >> ranges with "infinite" range precision close to free.
> >> > >
> >> > > Do you know why/where this slow-down happens?  Do we perhaps want to
> >> > > limit the "infiniteness" a little somehow?
> >> >
> >> > I addressed the slow down in another mail.
> >> >
> >> > >
> >> > > Also, jump functions live for a long time, have you looked at how 
> >> > > memory
> >> > > hungry they become?  I hope that the hashing would be good at 
> >> > > preventing
> >> > > any issues.
> >> >
> >> > On a side-note, the caching does help.  On a (mistaken) hunch, I had
> >> > played around with removing caching for everything but UNDEFINED/VARYING
> >> > and zero/nonzero to simplify things, but the cache hit ratio was still
> >> > surprisingly high (+80%).  So good job there :-).
> >> >
> >> > >
> >> > > Generally, I think I OK with the patches if the impact on memory is not
> >> > > too bad, though I guess they depend on the one I looked at last week, 
> >> > > so
> >> > > we may focus on that one first.
> >> >
> >> > I'm not sure whether this was an OK for the other patches, given you
> >> > approved the first patch, so I'll hold off until you give the go-ahead.
> >> >
> >> > Thanks.
> >> > Aldy



Re: [PATCH] Implement ipa_vr hashing.

2023-06-26 Thread Aldy Hernandez via Gcc-patches
PING*3

On Thu, Jun 22, 2023 at 7:49 AM Aldy Hernandez  wrote:
>
> Ping*2
>
> On Wed, Jun 14, 2023, 14:11 Aldy Hernandez  wrote:
>>
>> PING
>>
>> On Sat, Jun 10, 2023 at 10:30 PM Aldy Hernandez  wrote:
>> >
>> >
>> >
>> > On 5/29/23 16:51, Martin Jambor wrote:
>> > > Hi,
>> > >
>> > > On Mon, May 22 2023, Aldy Hernandez via Gcc-patches wrote:
>> > >> Implement hashing for ipa_vr.  When all is said and done, all these
>> > >> patches incurr a 7.64% slowdown for ipa-cp, with is entirely covered by
>> > >> the similar 7% increase in this area last week.  So we get type agnostic
>> > >> ranges with "infinite" range precision close to free.
>> > >
>> > > Do you know why/where this slow-down happens?  Do we perhaps want to
>> > > limit the "infiniteness" a little somehow?
>> >
>> > I addressed the slow down in another mail.
>> >
>> > >
>> > > Also, jump functions live for a long time, have you looked at how memory
>> > > hungry they become?  I hope that the hashing would be good at preventing
>> > > any issues.
>> >
>> > On a side-note, the caching does help.  On a (mistaken) hunch, I had
>> > played around with removing caching for everything but UNDEFINED/VARYING
>> > and zero/nonzero to simplify things, but the cache hit ratio was still
>> > surprisingly high (+80%).  So good job there :-).
>> >
>> > >
>> > > Generally, I think I OK with the patches if the impact on memory is not
>> > > too bad, though I guess they depend on the one I looked at last week, so
>> > > we may focus on that one first.
>> >
>> > I'm not sure whether this was an OK for the other patches, given you
>> > approved the first patch, so I'll hold off until you give the go-ahead.
>> >
>> > Thanks.
>> > Aldy



Re: [PATCH] Implement ipa_vr hashing.

2023-06-21 Thread Aldy Hernandez via Gcc-patches
Ping*2

On Wed, Jun 14, 2023, 14:11 Aldy Hernandez  wrote:

> PING
>
> On Sat, Jun 10, 2023 at 10:30 PM Aldy Hernandez  wrote:
> >
> >
> >
> > On 5/29/23 16:51, Martin Jambor wrote:
> > > Hi,
> > >
> > > On Mon, May 22 2023, Aldy Hernandez via Gcc-patches wrote:
> > >> Implement hashing for ipa_vr.  When all is said and done, all these
> > >> patches incurr a 7.64% slowdown for ipa-cp, with is entirely covered
> by
> > >> the similar 7% increase in this area last week.  So we get type
> agnostic
> > >> ranges with "infinite" range precision close to free.
> > >
> > > Do you know why/where this slow-down happens?  Do we perhaps want to
> > > limit the "infiniteness" a little somehow?
> >
> > I addressed the slow down in another mail.
> >
> > >
> > > Also, jump functions live for a long time, have you looked at how
> memory
> > > hungry they become?  I hope that the hashing would be good at
> preventing
> > > any issues.
> >
> > On a side-note, the caching does help.  On a (mistaken) hunch, I had
> > played around with removing caching for everything but UNDEFINED/VARYING
> > and zero/nonzero to simplify things, but the cache hit ratio was still
> > surprisingly high (+80%).  So good job there :-).
> >
> > >
> > > Generally, I think I OK with the patches if the impact on memory is not
> > > too bad, though I guess they depend on the one I looked at last week,
> so
> > > we may focus on that one first.
> >
> > I'm not sure whether this was an OK for the other patches, given you
> > approved the first patch, so I'll hold off until you give the go-ahead.
> >
> > Thanks.
> > Aldy
>


Re: [PATCH] Convert ipa_jump_func to use ipa_vr instead of a value_range.

2023-06-21 Thread Aldy Hernandez via Gcc-patches
Ping*2

On Wed, Jun 14, 2023, 14:09 Aldy Hernandez  wrote:

> PING
>
> On Mon, May 22, 2023 at 8:56 PM Aldy Hernandez  wrote:
> >
> > This patch converts the ipa_jump_func code to use the type agnostic
> > ipa_vr suitable for GC instead of value_range which is integer specific.
> >
> > I've disabled the range cacheing to simplify the patch for review, but
> > it is handled in the next patch in the series.
> >
> > OK?
> >
> > gcc/ChangeLog:
> >
> > * ipa-cp.cc (ipa_vr_operation_and_type_effects): New.
> > * ipa-prop.cc (ipa_get_value_range): Adjust for ipa_vr.
> > (ipa_set_jfunc_vr): Take a range.
> > (ipa_compute_jump_functions_for_edge): Pass range to
> > ipa_set_jfunc_vr.
> > (ipa_write_jump_function): Call streamer write helper.
> > (ipa_read_jump_function): Call streamer read helper.
> > * ipa-prop.h (class ipa_vr): Change m_vr to an ipa_vr.
> > ---
> >  gcc/ipa-cp.cc   | 15 +++
> >  gcc/ipa-prop.cc | 70 ++---
> >  gcc/ipa-prop.h  |  5 +++-
> >  3 files changed, 44 insertions(+), 46 deletions(-)
> >
> > diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
> > index bdbc2184b5f..03273666ea2 100644
> > --- a/gcc/ipa-cp.cc
> > +++ b/gcc/ipa-cp.cc
> > @@ -1928,6 +1928,21 @@ ipa_vr_operation_and_type_effects (vrange _vr,
> >   && !dst_vr.undefined_p ());
> >  }
> >
> > +/* Same as above, but the SRC_VR argument is an IPA_VR which must
> > +   first be extracted onto a vrange.  */
> > +
> > +static bool
> > +ipa_vr_operation_and_type_effects (vrange _vr,
> > +  const ipa_vr _vr,
> > +  enum tree_code operation,
> > +  tree dst_type, tree src_type)
> > +{
> > +  Value_Range tmp;
> > +  src_vr.get_vrange (tmp);
> > +  return ipa_vr_operation_and_type_effects (dst_vr, tmp, operation,
> > +   dst_type, src_type);
> > +}
> > +
> >  /* Determine range of JFUNC given that INFO describes the caller node or
> > the one it is inlined to, CS is the call graph edge corresponding to
> JFUNC
> > and PARM_TYPE of the parameter.  */
> > diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
> > index bbfe0f8aa45..c46a89f1b49 100644
> > --- a/gcc/ipa-prop.cc
> > +++ b/gcc/ipa-prop.cc
> > @@ -2287,9 +2287,10 @@ ipa_set_jfunc_bits (ipa_jump_func *jf, const
> widest_int ,
> >  /* Return a pointer to a value_range just like *TMP, but either find it
> in
> > ipa_vr_hash_table or allocate it in GC memory.  TMP->equiv must be
> NULL.  */
> >
> > -static value_range *
> > -ipa_get_value_range (value_range *tmp)
> > +static ipa_vr *
> > +ipa_get_value_range (const vrange )
> >  {
> > +  /* FIXME: Add hashing support.
> >value_range **slot = ipa_vr_hash_table->find_slot (tmp, INSERT);
> >if (*slot)
> >  return *slot;
> > @@ -2297,40 +2298,27 @@ ipa_get_value_range (value_range *tmp)
> >value_range *vr = new (ggc_alloc ()) value_range;
> >*vr = *tmp;
> >*slot = vr;
> > +  */
> > +  ipa_vr *vr = new (ggc_alloc ()) ipa_vr (tmp);
> >
> >return vr;
> >  }
> >
> > -/* Return a pointer to a value range consisting of TYPE, MIN, MAX and
> an empty
> > -   equiv set. Use hash table in order to avoid creating multiple same
> copies of
> > -   value_ranges.  */
> > -
> > -static value_range *
> > -ipa_get_value_range (enum value_range_kind kind, tree min, tree max)
> > -{
> > -  value_range tmp (TREE_TYPE (min),
> > -  wi::to_wide (min), wi::to_wide (max), kind);
> > -  return ipa_get_value_range ();
> > -}
> > -
> > -/* Assign to JF a pointer to a value_range structure with TYPE, MIN and
> MAX and
> > -   a NULL equiv bitmap.  Use hash table in order to avoid creating
> multiple
> > -   same value_range structures.  */
> > +/* Assign to JF a pointer to a value_range just like TMP but either
> fetch a
> > +   copy from ipa_vr_hash_table or allocate a new on in GC memory.  */
> >
> >  static void
> > -ipa_set_jfunc_vr (ipa_jump_func *jf, enum value_range_kind type,
> > - tree min, tree max)
> > +ipa_set_jfunc_vr (ipa_jump_func *jf, const vrange )
> >  {
> > -  jf->m_vr = ipa_get_value_range (type, min, max);
> > +  jf->m_vr = ipa_get_value_range (tmp);
> >  }
> >
> > -/* Assign to JF a pointer to a value_range just like TMP but either
> fetch a
> > -   copy from ipa_vr_hash_table or allocate a new on in GC memory.  */
> > -
> >  static void
> > -ipa_set_jfunc_vr (ipa_jump_func *jf, value_range *tmp)
> > +ipa_set_jfunc_vr (ipa_jump_func *jf, const ipa_vr )
> >  {
> > -  jf->m_vr = ipa_get_value_range (tmp);
> > +  Value_Range tmp;
> > +  vr.get_vrange (tmp);
> > +  ipa_set_jfunc_vr (jf, tmp);
> >  }
> >
> >  /* Compute jump function for all arguments of callsite CS and insert the
> > @@ -2392,8 +2380,8 @@ ipa_compute_jump_functions_for_edge (struct
> ipa_func_body_info *fbi,
> >
> >   if (addr_nonzero)
> > {
> > -   

Re: [PATCH] Convert remaining uses of value_range in ipa-*.cc to Value_Range.

2023-06-21 Thread Aldy Hernandez via Gcc-patches
Ping*2

On Wed, Jun 14, 2023, 14:10 Aldy Hernandez  wrote:

> PING
>
> On Mon, May 22, 2023 at 8:56 PM Aldy Hernandez  wrote:
> >
> > Minor cleanups to get rid of value_range in IPA.  There's only one left,
> > but it's in the switch code which is integer specific.
> >
> > OK?
> >
> > gcc/ChangeLog:
> >
> > * ipa-cp.cc (decide_whether_version_node): Adjust comment.
> > * ipa-fnsummary.cc (evaluate_conditions_for_known_args): Adjust
> > for Value_Range.
> > (set_switch_stmt_execution_predicate): Same.
> > * ipa-prop.cc (ipa_compute_jump_functions_for_edge): Same.
> > ---
> >  gcc/ipa-cp.cc|  3 +--
> >  gcc/ipa-fnsummary.cc | 22 ++
> >  gcc/ipa-prop.cc  |  9 +++--
> >  3 files changed, 18 insertions(+), 16 deletions(-)
> >
> > diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
> > index 03273666ea2..2e64415096e 100644
> > --- a/gcc/ipa-cp.cc
> > +++ b/gcc/ipa-cp.cc
> > @@ -6287,8 +6287,7 @@ decide_whether_version_node (struct cgraph_node
> *node)
> > {
> >   /* If some values generated for self-recursive calls with
> >  arithmetic jump functions fall outside of the known
> > -value_range for the parameter, we can skip them.  VR
> interface
> > -supports this only for integers now.  */
> > +range for the parameter, we can skip them.  */
> >   if (TREE_CODE (val->value) == INTEGER_CST
> >   && !plats->m_value_range.bottom_p ()
> >   && !ipa_range_contains_p (plats->m_value_range.m_vr,
> > diff --git a/gcc/ipa-fnsummary.cc b/gcc/ipa-fnsummary.cc
> > index 0474af8991e..1ce8501fe85 100644
> > --- a/gcc/ipa-fnsummary.cc
> > +++ b/gcc/ipa-fnsummary.cc
> > @@ -488,19 +488,20 @@ evaluate_conditions_for_known_args (struct
> cgraph_node *node,
> >   if (vr.varying_p () || vr.undefined_p ())
> > break;
> >
> > - value_range res;
> > + Value_Range res (op->type);
> >   if (!op->val[0])
> > {
> > + Value_Range varying (op->type);
> > + varying.set_varying (op->type);
> >   range_op_handler handler (op->code, op->type);
> >   if (!handler
> >   || !res.supports_type_p (op->type)
> > - || !handler.fold_range (res, op->type, vr,
> > - value_range
> (op->type)))
> > + || !handler.fold_range (res, op->type, vr,
> varying))
> > res.set_varying (op->type);
> > }
> >   else if (!op->val[1])
> > {
> > - value_range op0;
> > + Value_Range op0 (op->type);
> >   range_op_handler handler (op->code, op->type);
> >
> >   ipa_range_set_and_normalize (op0, op->val[0]);
> > @@ -518,14 +519,14 @@ evaluate_conditions_for_known_args (struct
> cgraph_node *node,
> > }
> >   if (!vr.varying_p () && !vr.undefined_p ())
> > {
> > - value_range res;
> > - value_range val_vr;
> > + int_range<2> res;
> > + Value_Range val_vr (TREE_TYPE (c->val));
> >   range_op_handler handler (c->code, boolean_type_node);
> >
> >   ipa_range_set_and_normalize (val_vr, c->val);
> >
> >   if (!handler
> > - || !res.supports_type_p (boolean_type_node)
> > + || !val_vr.supports_type_p (TREE_TYPE (c->val))
> >   || !handler.fold_range (res, boolean_type_node,
> vr, val_vr))
> > res.set_varying (boolean_type_node);
> >
> > @@ -1687,12 +1688,17 @@ set_switch_stmt_execution_predicate (struct
> ipa_func_body_info *fbi,
> >int bound_limit = opt_for_fn (fbi->node->decl,
> > param_ipa_max_switch_predicate_bounds);
> >int bound_count = 0;
> > -  value_range vr;
> > +  // This can safely be an integer range, as switches can only hold
> > +  // integers.
> > +  int_range<2> vr;
> >
> >get_range_query (cfun)->range_of_expr (vr, op);
> >if (vr.undefined_p ())
> >  vr.set_varying (TREE_TYPE (op));
> >tree vr_min, vr_max;
> > +  // ?? This entire function could use a rewrite to use the irange
> > +  // API, instead of trying to recreate its intersection/union logic.
> > +  // Any use of get_legacy_range() is a serious code smell.
> >value_range_kind vr_type = get_legacy_range (vr, vr_min, vr_max);
> >wide_int vr_wmin = wi::to_wide (vr_min);
> >wide_int vr_wmax = wi::to_wide (vr_max);
> > diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
> > index 6383bc11e0a..5f9e6dbbff2 100644
> > --- a/gcc/ipa-prop.cc
> > +++ b/gcc/ipa-prop.cc
> > @@ 

Re: [PATCH] Implement ipa_vr hashing.

2023-06-14 Thread Aldy Hernandez via Gcc-patches
PING

On Sat, Jun 10, 2023 at 10:30 PM Aldy Hernandez  wrote:
>
>
>
> On 5/29/23 16:51, Martin Jambor wrote:
> > Hi,
> >
> > On Mon, May 22 2023, Aldy Hernandez via Gcc-patches wrote:
> >> Implement hashing for ipa_vr.  When all is said and done, all these
> >> patches incurr a 7.64% slowdown for ipa-cp, with is entirely covered by
> >> the similar 7% increase in this area last week.  So we get type agnostic
> >> ranges with "infinite" range precision close to free.
> >
> > Do you know why/where this slow-down happens?  Do we perhaps want to
> > limit the "infiniteness" a little somehow?
>
> I addressed the slow down in another mail.
>
> >
> > Also, jump functions live for a long time, have you looked at how memory
> > hungry they become?  I hope that the hashing would be good at preventing
> > any issues.
>
> On a side-note, the caching does help.  On a (mistaken) hunch, I had
> played around with removing caching for everything but UNDEFINED/VARYING
> and zero/nonzero to simplify things, but the cache hit ratio was still
> surprisingly high (+80%).  So good job there :-).
>
> >
> > Generally, I think I OK with the patches if the impact on memory is not
> > too bad, though I guess they depend on the one I looked at last week, so
> > we may focus on that one first.
>
> I'm not sure whether this was an OK for the other patches, given you
> approved the first patch, so I'll hold off until you give the go-ahead.
>
> Thanks.
> Aldy



Re: [PATCH] Convert remaining uses of value_range in ipa-*.cc to Value_Range.

2023-06-14 Thread Aldy Hernandez via Gcc-patches
PING

On Mon, May 22, 2023 at 8:56 PM Aldy Hernandez  wrote:
>
> Minor cleanups to get rid of value_range in IPA.  There's only one left,
> but it's in the switch code which is integer specific.
>
> OK?
>
> gcc/ChangeLog:
>
> * ipa-cp.cc (decide_whether_version_node): Adjust comment.
> * ipa-fnsummary.cc (evaluate_conditions_for_known_args): Adjust
> for Value_Range.
> (set_switch_stmt_execution_predicate): Same.
> * ipa-prop.cc (ipa_compute_jump_functions_for_edge): Same.
> ---
>  gcc/ipa-cp.cc|  3 +--
>  gcc/ipa-fnsummary.cc | 22 ++
>  gcc/ipa-prop.cc  |  9 +++--
>  3 files changed, 18 insertions(+), 16 deletions(-)
>
> diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
> index 03273666ea2..2e64415096e 100644
> --- a/gcc/ipa-cp.cc
> +++ b/gcc/ipa-cp.cc
> @@ -6287,8 +6287,7 @@ decide_whether_version_node (struct cgraph_node *node)
> {
>   /* If some values generated for self-recursive calls with
>  arithmetic jump functions fall outside of the known
> -value_range for the parameter, we can skip them.  VR 
> interface
> -supports this only for integers now.  */
> +range for the parameter, we can skip them.  */
>   if (TREE_CODE (val->value) == INTEGER_CST
>   && !plats->m_value_range.bottom_p ()
>   && !ipa_range_contains_p (plats->m_value_range.m_vr,
> diff --git a/gcc/ipa-fnsummary.cc b/gcc/ipa-fnsummary.cc
> index 0474af8991e..1ce8501fe85 100644
> --- a/gcc/ipa-fnsummary.cc
> +++ b/gcc/ipa-fnsummary.cc
> @@ -488,19 +488,20 @@ evaluate_conditions_for_known_args (struct cgraph_node 
> *node,
>   if (vr.varying_p () || vr.undefined_p ())
> break;
>
> - value_range res;
> + Value_Range res (op->type);
>   if (!op->val[0])
> {
> + Value_Range varying (op->type);
> + varying.set_varying (op->type);
>   range_op_handler handler (op->code, op->type);
>   if (!handler
>   || !res.supports_type_p (op->type)
> - || !handler.fold_range (res, op->type, vr,
> - value_range (op->type)))
> + || !handler.fold_range (res, op->type, vr, varying))
> res.set_varying (op->type);
> }
>   else if (!op->val[1])
> {
> - value_range op0;
> + Value_Range op0 (op->type);
>   range_op_handler handler (op->code, op->type);
>
>   ipa_range_set_and_normalize (op0, op->val[0]);
> @@ -518,14 +519,14 @@ evaluate_conditions_for_known_args (struct cgraph_node 
> *node,
> }
>   if (!vr.varying_p () && !vr.undefined_p ())
> {
> - value_range res;
> - value_range val_vr;
> + int_range<2> res;
> + Value_Range val_vr (TREE_TYPE (c->val));
>   range_op_handler handler (c->code, boolean_type_node);
>
>   ipa_range_set_and_normalize (val_vr, c->val);
>
>   if (!handler
> - || !res.supports_type_p (boolean_type_node)
> + || !val_vr.supports_type_p (TREE_TYPE (c->val))
>   || !handler.fold_range (res, boolean_type_node, vr, 
> val_vr))
> res.set_varying (boolean_type_node);
>
> @@ -1687,12 +1688,17 @@ set_switch_stmt_execution_predicate (struct 
> ipa_func_body_info *fbi,
>int bound_limit = opt_for_fn (fbi->node->decl,
> param_ipa_max_switch_predicate_bounds);
>int bound_count = 0;
> -  value_range vr;
> +  // This can safely be an integer range, as switches can only hold
> +  // integers.
> +  int_range<2> vr;
>
>get_range_query (cfun)->range_of_expr (vr, op);
>if (vr.undefined_p ())
>  vr.set_varying (TREE_TYPE (op));
>tree vr_min, vr_max;
> +  // ?? This entire function could use a rewrite to use the irange
> +  // API, instead of trying to recreate its intersection/union logic.
> +  // Any use of get_legacy_range() is a serious code smell.
>value_range_kind vr_type = get_legacy_range (vr, vr_min, vr_max);
>wide_int vr_wmin = wi::to_wide (vr_min);
>wide_int vr_wmax = wi::to_wide (vr_max);
> diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
> index 6383bc11e0a..5f9e6dbbff2 100644
> --- a/gcc/ipa-prop.cc
> +++ b/gcc/ipa-prop.cc
> @@ -2348,7 +2348,6 @@ ipa_compute_jump_functions_for_edge (struct 
> ipa_func_body_info *fbi,
>gcall *call = cs->call_stmt;
>int n, arg_num = gimple_call_num_args (call);
>bool useful_context = false;
> -  value_range vr;
>
>if (arg_num == 0 || 

Re: [PATCH] Convert ipa_jump_func to use ipa_vr instead of a value_range.

2023-06-14 Thread Aldy Hernandez via Gcc-patches
PING

On Mon, May 22, 2023 at 8:56 PM Aldy Hernandez  wrote:
>
> This patch converts the ipa_jump_func code to use the type agnostic
> ipa_vr suitable for GC instead of value_range which is integer specific.
>
> I've disabled the range cacheing to simplify the patch for review, but
> it is handled in the next patch in the series.
>
> OK?
>
> gcc/ChangeLog:
>
> * ipa-cp.cc (ipa_vr_operation_and_type_effects): New.
> * ipa-prop.cc (ipa_get_value_range): Adjust for ipa_vr.
> (ipa_set_jfunc_vr): Take a range.
> (ipa_compute_jump_functions_for_edge): Pass range to
> ipa_set_jfunc_vr.
> (ipa_write_jump_function): Call streamer write helper.
> (ipa_read_jump_function): Call streamer read helper.
> * ipa-prop.h (class ipa_vr): Change m_vr to an ipa_vr.
> ---
>  gcc/ipa-cp.cc   | 15 +++
>  gcc/ipa-prop.cc | 70 ++---
>  gcc/ipa-prop.h  |  5 +++-
>  3 files changed, 44 insertions(+), 46 deletions(-)
>
> diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
> index bdbc2184b5f..03273666ea2 100644
> --- a/gcc/ipa-cp.cc
> +++ b/gcc/ipa-cp.cc
> @@ -1928,6 +1928,21 @@ ipa_vr_operation_and_type_effects (vrange _vr,
>   && !dst_vr.undefined_p ());
>  }
>
> +/* Same as above, but the SRC_VR argument is an IPA_VR which must
> +   first be extracted onto a vrange.  */
> +
> +static bool
> +ipa_vr_operation_and_type_effects (vrange _vr,
> +  const ipa_vr _vr,
> +  enum tree_code operation,
> +  tree dst_type, tree src_type)
> +{
> +  Value_Range tmp;
> +  src_vr.get_vrange (tmp);
> +  return ipa_vr_operation_and_type_effects (dst_vr, tmp, operation,
> +   dst_type, src_type);
> +}
> +
>  /* Determine range of JFUNC given that INFO describes the caller node or
> the one it is inlined to, CS is the call graph edge corresponding to JFUNC
> and PARM_TYPE of the parameter.  */
> diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
> index bbfe0f8aa45..c46a89f1b49 100644
> --- a/gcc/ipa-prop.cc
> +++ b/gcc/ipa-prop.cc
> @@ -2287,9 +2287,10 @@ ipa_set_jfunc_bits (ipa_jump_func *jf, const 
> widest_int ,
>  /* Return a pointer to a value_range just like *TMP, but either find it in
> ipa_vr_hash_table or allocate it in GC memory.  TMP->equiv must be NULL.  
> */
>
> -static value_range *
> -ipa_get_value_range (value_range *tmp)
> +static ipa_vr *
> +ipa_get_value_range (const vrange )
>  {
> +  /* FIXME: Add hashing support.
>value_range **slot = ipa_vr_hash_table->find_slot (tmp, INSERT);
>if (*slot)
>  return *slot;
> @@ -2297,40 +2298,27 @@ ipa_get_value_range (value_range *tmp)
>value_range *vr = new (ggc_alloc ()) value_range;
>*vr = *tmp;
>*slot = vr;
> +  */
> +  ipa_vr *vr = new (ggc_alloc ()) ipa_vr (tmp);
>
>return vr;
>  }
>
> -/* Return a pointer to a value range consisting of TYPE, MIN, MAX and an 
> empty
> -   equiv set. Use hash table in order to avoid creating multiple same copies 
> of
> -   value_ranges.  */
> -
> -static value_range *
> -ipa_get_value_range (enum value_range_kind kind, tree min, tree max)
> -{
> -  value_range tmp (TREE_TYPE (min),
> -  wi::to_wide (min), wi::to_wide (max), kind);
> -  return ipa_get_value_range ();
> -}
> -
> -/* Assign to JF a pointer to a value_range structure with TYPE, MIN and MAX 
> and
> -   a NULL equiv bitmap.  Use hash table in order to avoid creating multiple
> -   same value_range structures.  */
> +/* Assign to JF a pointer to a value_range just like TMP but either fetch a
> +   copy from ipa_vr_hash_table or allocate a new on in GC memory.  */
>
>  static void
> -ipa_set_jfunc_vr (ipa_jump_func *jf, enum value_range_kind type,
> - tree min, tree max)
> +ipa_set_jfunc_vr (ipa_jump_func *jf, const vrange )
>  {
> -  jf->m_vr = ipa_get_value_range (type, min, max);
> +  jf->m_vr = ipa_get_value_range (tmp);
>  }
>
> -/* Assign to JF a pointer to a value_range just like TMP but either fetch a
> -   copy from ipa_vr_hash_table or allocate a new on in GC memory.  */
> -
>  static void
> -ipa_set_jfunc_vr (ipa_jump_func *jf, value_range *tmp)
> +ipa_set_jfunc_vr (ipa_jump_func *jf, const ipa_vr )
>  {
> -  jf->m_vr = ipa_get_value_range (tmp);
> +  Value_Range tmp;
> +  vr.get_vrange (tmp);
> +  ipa_set_jfunc_vr (jf, tmp);
>  }
>
>  /* Compute jump function for all arguments of callsite CS and insert the
> @@ -2392,8 +2380,8 @@ ipa_compute_jump_functions_for_edge (struct 
> ipa_func_body_info *fbi,
>
>   if (addr_nonzero)
> {
> - tree z = build_int_cst (TREE_TYPE (arg), 0);
> - ipa_set_jfunc_vr (jfunc, VR_ANTI_RANGE, z, z);
> + vr.set_nonzero (TREE_TYPE (arg));
> + ipa_set_jfunc_vr (jfunc, vr);
> }
>   else
> gcc_assert (!jfunc->m_vr);
> @@ -2412,7 +2400,7 @@ 

Re: [PATCH] Implement ipa_vr hashing.

2023-06-10 Thread Aldy Hernandez via Gcc-patches




On 5/29/23 16:51, Martin Jambor wrote:

Hi,

On Mon, May 22 2023, Aldy Hernandez via Gcc-patches wrote:

Implement hashing for ipa_vr.  When all is said and done, all these
patches incurr a 7.64% slowdown for ipa-cp, with is entirely covered by
the similar 7% increase in this area last week.  So we get type agnostic
ranges with "infinite" range precision close to free.


Do you know why/where this slow-down happens?  Do we perhaps want to
limit the "infiniteness" a little somehow?


I addressed the slow down in another mail.



Also, jump functions live for a long time, have you looked at how memory
hungry they become?  I hope that the hashing would be good at preventing
any issues.


On a side-note, the caching does help.  On a (mistaken) hunch, I had
played around with removing caching for everything but UNDEFINED/VARYING 
and zero/nonzero to simplify things, but the cache hit ratio was still 
surprisingly high (+80%).  So good job there :-).




Generally, I think I OK with the patches if the impact on memory is not
too bad, though I guess they depend on the one I looked at last week, so
we may focus on that one first.


I'm not sure whether this was an OK for the other patches, given you 
approved the first patch, so I'll hold off until you give the go-ahead.


Thanks.
Aldy



Re: [PATCH] Convert ipcp_vr_lattice to type agnostic framework.

2023-06-10 Thread Aldy Hernandez via Gcc-patches




On 6/10/23 10:49, Martin Jambor wrote:

Hi,

thanks for dealing with my requests.

On Wed, Jun 07 2023, Aldy Hernandez wrote:

On 5/26/23 18:17, Martin Jambor wrote:

Hello,

On Mon, May 22 2023, Aldy Hernandez wrote:

I've adjusted the patch with some minor cleanups that came up when I
implemented the rest of the IPA revamp.

Rested.  OK?

On Wed, May 17, 2023 at 4:31 PM Aldy Hernandez  wrote:


This converts the lattice to store ranges in Value_Range instead of
value_range (*) to make it type agnostic, and adjust all users
accordingly.

I think it is a good example on converting from static ranges to more
general, type agnostic ones.

I've been careful to make sure Value_Range never ends up on GC, since
it contains an int_range_max and can expand on-demand onto the heap.
Longer term storage for ranges should be done with vrange_storage, as
per the previous patch ("Provide an API for ipa_vr").

(*) I do know the Value_Range naming versus value_range is quite
annoying, but it was a judgement call last release for the eventual
migration to having "value_range" be a type agnostic range object.  We
will ultimately rename Value_Range to value_range.


[...]


diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
index d4b9d4ac27e..bd5b1da17b2 100644
--- a/gcc/ipa-cp.cc
+++ b/gcc/ipa-cp.cc
@@ -343,20 +343,29 @@ private:
   class ipcp_vr_lattice
   {
   public:
-  value_range m_vr;
+  Value_Range m_vr;

 inline bool bottom_p () const;
 inline bool top_p () const;
-  inline bool set_to_bottom ();
-  bool meet_with (const value_range *p_vr);
+  inline bool set_to_bottom (tree type);


Requiring a type when setting a lattice to bottom makes for a weird
interface, can't we set the underlying Value_Range to whatever... >

+  bool meet_with (const vrange _vr);
 bool meet_with (const ipcp_vr_lattice );
-  void init () { gcc_assert (m_vr.undefined_p ()); }
+  void init (tree type);
 void print (FILE * f);

   private:
-  bool meet_with_1 (const value_range *other_vr);
+  bool meet_with_1 (const vrange _vr);
   };

+inline void
+ipcp_vr_lattice::init (tree type)
+{
+  if (type)
+m_vr.set_type (type);
+
+  // Otherwise m_vr will default to unsupported_range.


...this does?

All users of the lattice check it for not being bottom first, so it
should be safe.

If it is not possible for some reason, then I guess we should add a bool
flag to ipcp_vr_lattice instead, rather than looking up types of
unusable lattices.  ipcp_vr_lattices don't live for long.


The type was my least favorite part of this work.  And yes, your
suggestion would work.  I have tweaked the patch to force a VARYING for
an unsupported range which seems to do the trick.  It looks much
cleaner.  Thanks.


This version is much better indeed.

[...]


@@ -1912,29 +1917,33 @@ ipa_vr_operation_and_type_effects (value_range *dst_vr,
   return false;

 range_op_handler handler (operation, dst_type);
-  return (handler
- && handler.fold_range (*dst_vr, dst_type,
-*src_vr, value_range (dst_type))
- && !dst_vr->varying_p ()
- && !dst_vr->undefined_p ());
+  if (!handler)
+return false;
+
+  Value_Range varying (dst_type);
+  varying.set_varying (dst_type);
+
+  return (handler.fold_range (dst_vr, dst_type, src_vr, varying)
+ && !dst_vr.varying_p ()
+ && !dst_vr.undefined_p ());
   }

   /* Determine value_range of JFUNC given that INFO describes the caller node 
or
  the one it is inlined to, CS is the call graph edge corresponding to JFUNC
  and PARM_TYPE of the parameter.  */

-value_range
-ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
+void
+ipa_value_range_from_jfunc (vrange ,
+   ipa_node_params *info, cgraph_edge *cs,
  ipa_jump_func *jfunc, tree parm_type)


I assume that you decided to return the value in a parameter passed by
reference instead of in return value for a good reason but then can we
at least...


vrange is an abstract type, plus it can be any size (int_range<3> has 3
sub-ranges, legacy value_range has 2 sub-ranges, frange is a totally
different object, etc).  Throughout all of ranger, returning a range is
done by passing by reference.  This has the added benefit that sometimes
we can set a return range by twiddling a few bits (foo.set_undefined())
instead of having to copy a full range back and forth.



I see, thanks.

[...]



How's this?


One minor observation below...



Aldy
 From 2fd0ae47aa094675a02763e72d7bb7404ed9334b Mon Sep 17 00:00:00 2001
From: Aldy Hernandez 
Date: Wed, 17 May 2023 11:29:34 +0200
Subject: [PATCH] Convert ipcp_vr_lattice to type agnostic framework.

This converts the lattice to store ranges in Value_Range instead of
value_range (*) to make it type agnostic, and adjust all users
accordingly.

I've been careful to make sure Value_Range never ends up on GC, since
it contains an int_range_max and can expand on-demand onto the heap.
Longer 

Re: [COMMITTED 2/4] - Remove tree_code from range-operator.

2023-06-09 Thread Aldy Hernandez via Gcc-patches




On 6/8/23 20:57, Andrew MacLeod wrote:
Range_operator had a tree code added last release to facilitate bitmask 
operations.  This was intended to be a temporary change until we could 
figure out something more strategic going forward.


This patch removes the tree_code and replaces it with a virtual routine 
to perform the masking. Each of the affected tree codes operators now 
call the bitmask routine via a virtual function.  At some point we may 
want to consolidate the code that CCP is using so that it resides in the 
range_operator, but the extensive parameter list used by that CCP 
routine makes that prohibitive to do at the moment.


It's on my radar for this release.  I will be changing the 
nonzero_bitmask field in irange for a value/mask pair, as CCP does, and 
if all goes well, consolidating CCP as well as the on-the-side bitmask 
tracking IPA does.


Thanks for tidying this up.

Aldy



Re: [PATCH] Convert ipcp_vr_lattice to type agnostic framework.

2023-06-07 Thread Aldy Hernandez via Gcc-patches



On 5/26/23 18:17, Martin Jambor wrote:

Hello,

On Mon, May 22 2023, Aldy Hernandez wrote:

I've adjusted the patch with some minor cleanups that came up when I
implemented the rest of the IPA revamp.

Rested.  OK?

On Wed, May 17, 2023 at 4:31 PM Aldy Hernandez  wrote:


This converts the lattice to store ranges in Value_Range instead of
value_range (*) to make it type agnostic, and adjust all users
accordingly.

I think it is a good example on converting from static ranges to more
general, type agnostic ones.

I've been careful to make sure Value_Range never ends up on GC, since
it contains an int_range_max and can expand on-demand onto the heap.
Longer term storage for ranges should be done with vrange_storage, as
per the previous patch ("Provide an API for ipa_vr").

(*) I do know the Value_Range naming versus value_range is quite
annoying, but it was a judgement call last release for the eventual
migration to having "value_range" be a type agnostic range object.  We
will ultimately rename Value_Range to value_range.


It is quite confusing for an unsuspecting reader indeed.



OK for trunk?


I guess I need to rely on that you know what you are doing :-)


I wouldn't go that far ;-).


I have seen in other messages that you measure the compile time
effects of your patches, do you look at memory use as well?


As per my message yesterday, the memory usage seems reasonable.



I am happy with the overall approach, I just have the following
comments, questions and a few concerns:




gcc/ChangeLog:

 * ipa-cp.cc (ipcp_vr_lattice::init): Take type argument.
 (ipcp_vr_lattice::print): Call dump method.
 (ipcp_vr_lattice::meet_with): Adjust for m_vr being a
 Value_Range.
 (ipcp_vr_lattice::meet_with_1): Make argument a reference.
 (ipcp_vr_lattice::set_to_bottom): Add type argument.
 (set_all_contains_variable): Same.
 (initialize_node_lattices): Pass type when appropriate.
 (ipa_vr_operation_and_type_effects): Make type agnostic.
 (ipa_value_range_from_jfunc): Same.
 (propagate_vr_across_jump_function): Same.
 (propagate_constants_across_call): Same.
 * ipa-fnsummary.cc (evaluate_conditions_for_known_args): Same.
 (evaluate_properties_for_edge): Same.
 * ipa-prop.cc (ipcp_update_vr): Same.
 * ipa-prop.h (ipa_value_range_from_jfunc): Same.
 (ipa_range_set_and_normalize): Same.
---
  gcc/ipa-cp.cc| 159 +++
  gcc/ipa-fnsummary.cc |  16 ++---
  gcc/ipa-prop.cc  |   2 +-
  gcc/ipa-prop.h   |  19 ++
  4 files changed, 101 insertions(+), 95 deletions(-)

diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
index d4b9d4ac27e..bd5b1da17b2 100644
--- a/gcc/ipa-cp.cc
+++ b/gcc/ipa-cp.cc
@@ -343,20 +343,29 @@ private:
  class ipcp_vr_lattice
  {
  public:
-  value_range m_vr;
+  Value_Range m_vr;

inline bool bottom_p () const;
inline bool top_p () const;
-  inline bool set_to_bottom ();
-  bool meet_with (const value_range *p_vr);
+  inline bool set_to_bottom (tree type);


Requiring a type when setting a lattice to bottom makes for a weird
interface, can't we set the underlying Value_Range to whatever... >

+  bool meet_with (const vrange _vr);
bool meet_with (const ipcp_vr_lattice );
-  void init () { gcc_assert (m_vr.undefined_p ()); }
+  void init (tree type);
void print (FILE * f);

  private:
-  bool meet_with_1 (const value_range *other_vr);
+  bool meet_with_1 (const vrange _vr);
  };

+inline void
+ipcp_vr_lattice::init (tree type)
+{
+  if (type)
+m_vr.set_type (type);
+
+  // Otherwise m_vr will default to unsupported_range.


...this does?

All users of the lattice check it for not being bottom first, so it
should be safe.

If it is not possible for some reason, then I guess we should add a bool
flag to ipcp_vr_lattice instead, rather than looking up types of
unusable lattices.  ipcp_vr_lattices don't live for long.


The type was my least favorite part of this work.  And yes, your 
suggestion would work.  I have tweaked the patch to force a VARYING for 
an unsupported range which seems to do the trick.  It looks much 
cleaner.  Thanks.





+}
+
  /* Structure containing lattices for a parameter itself and for pieces of
 aggregates that are passed in the parameter or by a reference in a 
parameter
 plus some other useful flags.  */
@@ -585,7 +594,7 @@ ipcp_bits_lattice::print (FILE *f)
  void
  ipcp_vr_lattice::print (FILE * f)
  {
-  dump_value_range (f, _vr);
+  m_vr.dump (f);
  }

  /* Print all ipcp_lattices of all functions to F.  */
@@ -1016,14 +1025,14 @@ set_agg_lats_contain_variable (class 
ipcp_param_lattices *plats)
  bool
  ipcp_vr_lattice::meet_with (const ipcp_vr_lattice )
  {
-  return meet_with_1 (_vr);
+  return meet_with_1 (other.m_vr);
  }

  /* Meet the current value of the lattice with value range described by VR
 lattice.  */

  bool
-ipcp_vr_lattice::meet_with 

Re: [PATCH] Implement ipa_vr hashing.

2023-06-07 Thread Aldy Hernandez via Gcc-patches




On 5/29/23 16:51, Martin Jambor wrote:

Hi,

On Mon, May 22 2023, Aldy Hernandez via Gcc-patches wrote:

Implement hashing for ipa_vr.  When all is said and done, all these
patches incurr a 7.64% slowdown for ipa-cp, with is entirely covered by
the similar 7% increase in this area last week.  So we get type agnostic
ranges with "infinite" range precision close to free.


Do you know why/where this slow-down happens?  Do we perhaps want to
limit the "infiniteness" a little somehow?


It happens in ipcp_vr_lattice::meet_with_1, because we have a lot more 
sub-ranges to union.  The latest numbers are 6.6%, and as I said I've 
already improved ipa-cp by the an equal amount, so we're good :).


The infiniteness is already capped.  We start at 3 sub-ranges, and grow 
up to 255.  I suppose if this is a problem, we could write a custom 
Value_Range temporary for IPA to fit specific needs, but I'd really like 
to avoid such special casing.




Also, jump functions live for a long time, have you looked at how memory
hungry they become?  I hope that the hashing would be good at preventing
any issues.


See my previous mail on memory usage.

Aldy



Re: [PATCH] Convert ipcp_vr_lattice to type agnostic framework.

2023-06-06 Thread Aldy Hernandez via Gcc-patches

My apologies for the delay.  I was on vacation.

On 5/26/23 18:17, Martin Jambor wrote:

Hello,

On Mon, May 22 2023, Aldy Hernandez wrote:

I've adjusted the patch with some minor cleanups that came up when I
implemented the rest of the IPA revamp.

Rested.  OK?

On Wed, May 17, 2023 at 4:31 PM Aldy Hernandez  wrote:


This converts the lattice to store ranges in Value_Range instead of
value_range (*) to make it type agnostic, and adjust all users
accordingly.

I think it is a good example on converting from static ranges to more
general, type agnostic ones.

I've been careful to make sure Value_Range never ends up on GC, since
it contains an int_range_max and can expand on-demand onto the heap.
Longer term storage for ranges should be done with vrange_storage, as
per the previous patch ("Provide an API for ipa_vr").

(*) I do know the Value_Range naming versus value_range is quite
annoying, but it was a judgement call last release for the eventual
migration to having "value_range" be a type agnostic range object.  We
will ultimately rename Value_Range to value_range.


It is quite confusing for an unsuspecting reader indeed.



OK for trunk?


I guess I need to rely on that you know what you are doing :-)
I have seen in other messages that you measure the compile time
effects of your patches, do you look at memory use as well?


Before going in depth into the rest of your review (thanks BTW), let's 
address memory usage.


To be honest, I didn't measure memory, but only because I had a pretty 
good inkling that it wouldn't make a difference, since vrange_storage is 
designed to take less space than value_range which you were using.  But 
you're right, I should've measured it.


First value_range is a derived-POD so it has a vtable pointer in there. 
vrange_storage does not.


Second, vrange_storage only uses the minimum number of bytes to 
represent the integers in the range.  vrange_storage uses a 
trailing_wide_int type mechanism to store the minimum amount of HWIs for 
a range.   See irange_storage::set_irange().


value_range is a typedef for int_range<2>.  Storing this in GC, which 
IPA currently does, takes 432 bytes.  I will be removing the GTY markers 
for irange, to keep anyone from even trying.


On the other hand, storing this same range in GC memory with 
vrange_storage takes 35 bytes for a [5, 10] range:


  unsigned prec = TYPE_PRECISION (integer_type_node);
  wide_int min = wi::shwi (5, prec);
  wide_int max = wi::shwi (10, prec);
  int_range<2> r (integer_type_node, min, max);
  vrange_storage *p = ggc_alloc_vrange_storage (r);

Breaking on irange_storage::alloc() you can see the size of the 
allocated object is 35 bytes.  This is far less than 432 bytes in trunk 
(due to the wide_int penalty in this release), but even so is comparable 
to GCC12 which took 32 bytes.  Note that GCC12 was using trees, so those 
32 bytes were deceptive, since there was another level of indirection 
involved for the actual HWIs.


Anywhoo... I tried comparing GCC 12 to current mainline plus these 
patches, but it was a royal PITA, because so much has changed, not just 
in the ranger world, but in the rest of the compiler.


However, comparing trunk against my patches is a total wash, even 
considering that IPA will now store a gazillion more ranges.


For measuring I built with --enable-gather-detailed-mem-stats and 
compared the "Total Allocated:" lines from -fmem-report for the 
aggregate of all .ii files in a bootstrap:


Before:
Total allocated: 73360474112.0 bytes

After:
Total allocated: 73354182656.0 bytes

So we use 0.00858% less memory.

To be honest, this is an unfair comparison because trunk IPA is 
streaming out the full value_range (wide_int's and all which changed in 
this release), but with these patches:


a) We don't stream out vtable pointer.
b) Even if the number of sub-ranges can be larger, we only store the 
bare minimum, and we're capped at 255 sub-ranges (which I've never seen 
in the wild).


I think we're good, but if this ever becomes a problem, the constructor 
for ipa_vr could just be tweaked to squish things down before allocating:


ipa_vr::ipa_vr (const vrange )
  : m_type (v.type ())
{
  if (is_a  (v))
{
  int_range<10> squish (as_a  (v));
  m_storage = ggc_alloc_vrange_storage (squish);
}
  else
m_storage = ggc_alloc_vrange_storage (v);
}

I'll address the rest of your comments in follow-up mails.
Aldy



Re: [COMMITTED 4/4] - Gimple range PHI analyzer and testcases

2023-05-25 Thread Aldy Hernandez via Gcc-patches

Some minor nits.


+// There can be only one running at a time.
+static phi_analyzer *phi_analysis_object = NULL;


Shouldn't this be phi_analyzer_object to be more consistent?  Similarly 
throughout.



+// Create a new phi_group with members BM, initialvalue INIT_VAL, modifier
+// statement MOD, and resolve values using query Q.
+// Calculate the range for the gropup if possible, otherwise set it to
+// VARYING.
+
+phi_group::phi_group (bitmap bm, tree init_val, edge e, gimple *mod,
+ range_query *q)


Could you document what this edge refers to?


+  // we dont expect a modifer and no inital value, so trap to have a look.
+  // perhaps they are dead cycles and we can just used UNDEFINED.


"We don't"...

"Perhaps..."

s/used/use


+// Return 0 if S is not a modifier statment for group members BM.
+// If it could be a modifier, return which operand position (1 or 2)
+// the phi member occurs in.
+unsigned
+phi_group::is_modifier_p (gimple *s, const bitmap bm)


"not" a modifier?  Or *is* a modifier?

s/statment/statement


+  // Look at the modifier for any relation


Missing final period.


+  for (unsigned x = 0; x< 10; x++)


Space before "<"


+  // Never converged, so bail for now. we could examine the pattern
+  // from m_initial to m_vr as an extension  Especially if we had a way
+  // to project the actual number of iterations (SCEV?)


s/we/We/

s/extension Especially/extension, especially/


+// IF the modifier statement has a relation K between the modifier and the


s/IF/If/


+  // If the type wraps, then relations dont tell us much.


s/dont/don't/


+//   m_tab.safe_grow_cleared (num_ssa_names + 100);


why is this commented out?


+ // Other non-ssa names that arent constants are not understood


s/arent/aren't/


+ // Try to create a group based on m_current. If a result comes back


Two spaces after period.


+  // If this dpoesn;t form a group, all members are instead simple phis.


doesn't


+// their arguemnts contain nothing but other PHI defintions, with at most


arguments
definitions


+// These are the APIs to start and stop a phi analyzerin a SCEV like manner.


analyzer

Thanks for working on this.
Aldy



[COMMITTED] Stream out NANs correctly.

2023-05-24 Thread Aldy Hernandez via Gcc-patches
NANs don't have bounds, so there's no need to stream them out.

gcc/ChangeLog:

* data-streamer-in.cc (streamer_read_value_range): Handle NANs.
* data-streamer-out.cc (streamer_write_vrange): Same.
* value-range.h (class vrange): Make streamer_write_vrange a friend.
---
 gcc/data-streamer-in.cc  | 16 
 gcc/data-streamer-out.cc | 17 -
 gcc/value-range.h|  1 +
 3 files changed, 25 insertions(+), 9 deletions(-)

diff --git a/gcc/data-streamer-in.cc b/gcc/data-streamer-in.cc
index 07728bef413..578c328475f 100644
--- a/gcc/data-streamer-in.cc
+++ b/gcc/data-streamer-in.cc
@@ -248,14 +248,22 @@ streamer_read_value_range (class lto_input_block *ib, 
data_in *data_in,
   if (is_a  (vr))
 {
   frange  = as_a  (vr);
-  REAL_VALUE_TYPE lb, ub;
-  streamer_read_real_value (ib, );
-  streamer_read_real_value (ib, );
+
+  // Stream in NAN bits.
   struct bitpack_d bp = streamer_read_bitpack (ib);
   bool pos_nan = (bool) bp_unpack_value (, 1);
   bool neg_nan = (bool) bp_unpack_value (, 1);
   nan_state nan (pos_nan, neg_nan);
-  r.set (type, lb, ub, nan);
+
+  if (kind == VR_NAN)
+   r.set_nan (type, nan);
+  else
+   {
+ REAL_VALUE_TYPE lb, ub;
+ streamer_read_real_value (ib, );
+ streamer_read_real_value (ib, );
+ r.set (type, lb, ub, nan);
+   }
   return;
 }
   gcc_unreachable ();
diff --git a/gcc/data-streamer-out.cc b/gcc/data-streamer-out.cc
index afc9862062b..93dedfcb895 100644
--- a/gcc/data-streamer-out.cc
+++ b/gcc/data-streamer-out.cc
@@ -410,7 +410,7 @@ streamer_write_vrange (struct output_block *ob, const 
vrange )
   gcc_checking_assert (!v.undefined_p ());
 
   // Write the common fields to all vranges.
-  value_range_kind kind = v.varying_p () ? VR_VARYING : VR_RANGE;
+  value_range_kind kind = v.m_kind;
   streamer_write_enum (ob->main_stream, value_range_kind, VR_LAST, kind);
   stream_write_tree (ob, v.type (), true);
 
@@ -429,15 +429,22 @@ streamer_write_vrange (struct output_block *ob, const 
vrange )
   if (is_a  (v))
 {
   const frange  = as_a  (v);
-  REAL_VALUE_TYPE lb = r.lower_bound ();
-  REAL_VALUE_TYPE ub = r.upper_bound ();
-  streamer_write_real_value (ob, );
-  streamer_write_real_value (ob, );
+
+  // Stream out NAN bits.
   bitpack_d bp = bitpack_create (ob->main_stream);
   nan_state nan = r.get_nan_state ();
   bp_pack_value (, nan.pos_p (), 1);
   bp_pack_value (, nan.neg_p (), 1);
   streamer_write_bitpack ();
+
+  // Stream out bounds.
+  if (kind != VR_NAN)
+   {
+ REAL_VALUE_TYPE lb = r.lower_bound ();
+ REAL_VALUE_TYPE ub = r.upper_bound ();
+ streamer_write_real_value (ob, );
+ streamer_write_real_value (ob, );
+   }
   return;
 }
   gcc_unreachable ();
diff --git a/gcc/value-range.h b/gcc/value-range.h
index 39023e7b5eb..2b4ebabe7c8 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -76,6 +76,7 @@ class GTY((user)) vrange
 {
   template  friend bool is_a (vrange &);
   friend class Value_Range;
+  friend void streamer_write_vrange (struct output_block *, const vrange &);
 public:
   virtual void accept (const class vrange_visitor ) const = 0;
   virtual void set (tree, tree, value_range_kind = VR_RANGE);
-- 
2.40.1



[COMMITTED] Disallow setting of NANs in frange setter unless setting trees.

2023-05-24 Thread Aldy Hernandez via Gcc-patches
frange::set() is confusing in that we can set a NAN by specifying a
bound of +-NAN, even though we tecnically disallow NANs in the setter
because the kind can never be VR_NAN.  This is a wart for
get_tree_range(), which builds a range out of a tree from the source,
to work correctly.  It's ugly, and it showed its limitation while
implementing LTO streaming of ranges.

This patch disallows passing NAN bounds in frange::set() and fixes
get_tree_range.

gcc/ChangeLog:

* value-query.cc (range_query::get_tree_range): Set NAN directly
if necessary.
* value-range.cc (frange::set): Assert that bounds are not NAN.
---
 gcc/value-query.cc | 13 ++---
 gcc/value-range.cc |  9 +
 2 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index 43297f17c39..a84f164d77b 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -189,9 +189,16 @@ range_query::get_tree_range (vrange , tree expr, gimple 
*stmt)
   {
frange  = as_a  (r);
REAL_VALUE_TYPE *rv = TREE_REAL_CST_PTR (expr);
-   f.set (TREE_TYPE (expr), *rv, *rv);
-   if (!real_isnan (rv))
- f.clear_nan ();
+   if (real_isnan (rv))
+ {
+   bool sign = real_isneg (rv);
+   f.set_nan (TREE_TYPE (expr), sign);
+ }
+   else
+ {
+   nan_state nan (false);
+   f.set (TREE_TYPE (expr), *rv, *rv, nan);
+ }
return true;
   }
 
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 2f37ff3e58e..707b1f15fd4 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -359,14 +359,7 @@ frange::set (tree type,
   gcc_unreachable ();
 }
 
-  // Handle NANs.
-  if (real_isnan () || real_isnan ())
-{
-  gcc_checking_assert (real_identical (, ));
-  bool sign = real_isneg ();
-  set_nan (type, sign);
-  return;
-}
+  gcc_checking_assert (!real_isnan () && !real_isnan ());
 
   m_kind = kind;
   m_type = type;
-- 
2.40.1



[COMMITTED] Hash known NANs correctly for franges.

2023-05-24 Thread Aldy Hernandez via Gcc-patches
We're ICEing when trying to hash a known NAN.  This is unnoticeable
because the only user would be IPA, and even so, it currently doesn't
handle floats.  However, handling floats is a flip of a switch, so
it's best to handle them already.

gcc/ChangeLog:

* value-range.cc (add_vrange): Handle known NANs.
---
 gcc/value-range.cc | 14 +++---
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 874a1843ebf..2f37ff3e58e 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -269,14 +269,14 @@ add_vrange (const vrange , inchash::hash ,
   if (is_a  (v))
 {
   const frange  = as_a  (v);
-  if (r.varying_p ())
-   hstate.add_int (VR_VARYING);
+  if (r.known_isnan ())
+   hstate.add_int (VR_NAN);
   else
-   hstate.add_int (VR_RANGE);
-
-  hstate.add_real_value (r.lower_bound ());
-  hstate.add_real_value (r.upper_bound ());
-
+   {
+ hstate.add_int (r.varying_p () ? VR_VARYING : VR_RANGE);
+ hstate.add_real_value (r.lower_bound ());
+ hstate.add_real_value (r.upper_bound ());
+   }
   nan_state nan = r.get_nan_state ();
   hstate.add_int (nan.pos_p ());
   hstate.add_int (nan.neg_p ());
-- 
2.40.1



[COMMITTED] Add an frange::set_nan() variant that takes a nan_state.

2023-05-24 Thread Aldy Hernandez via Gcc-patches
Generalize frange::set_nan() to take a nan_state and make current
set_nan() methods syntactic sugar.

This is in preparation for better streaming of NANs for LTO/IPA.

gcc/ChangeLog:

* value-range.h (frange::set_nan): New.
---
 gcc/value-range.h | 32 +---
 1 file changed, 17 insertions(+), 15 deletions(-)

diff --git a/gcc/value-range.h b/gcc/value-range.h
index b8cc2a0e76a..39023e7b5eb 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -327,6 +327,7 @@ public:
const nan_state &, value_range_kind = VR_RANGE);
   void set_nan (tree type);
   void set_nan (tree type, bool sign);
+  void set_nan (tree type, const nan_state &);
   virtual void set_varying (tree type) override;
   virtual void set_undefined () override;
   virtual bool union_ (const vrange &) override;
@@ -1219,17 +1220,18 @@ frange_val_is_max (const REAL_VALUE_TYPE , const_tree 
type)
   return real_identical (, );
 }
 
-// Build a signless NAN of type TYPE.
+// Build a NAN with a state of NAN.
 
 inline void
-frange::set_nan (tree type)
+frange::set_nan (tree type, const nan_state )
 {
+  gcc_checking_assert (nan.pos_p () || nan.neg_p ());
   if (HONOR_NANS (type))
 {
   m_kind = VR_NAN;
   m_type = type;
-  m_pos_nan = true;
-  m_neg_nan = true;
+  m_neg_nan = nan.neg_p ();
+  m_pos_nan = nan.pos_p ();
   if (flag_checking)
verify_range ();
 }
@@ -1237,22 +1239,22 @@ frange::set_nan (tree type)
 set_undefined ();
 }
 
+// Build a signless NAN of type TYPE.
+
+inline void
+frange::set_nan (tree type)
+{
+  nan_state nan (true);
+  set_nan (type, nan);
+}
+
 // Build a NAN of type TYPE with SIGN.
 
 inline void
 frange::set_nan (tree type, bool sign)
 {
-  if (HONOR_NANS (type))
-{
-  m_kind = VR_NAN;
-  m_type = type;
-  m_neg_nan = sign;
-  m_pos_nan = !sign;
-  if (flag_checking)
-   verify_range ();
-}
-  else
-set_undefined ();
+  nan_state nan (/*pos=*/!sign, /*neg=*/sign);
+  set_nan (type, nan);
 }
 
 // Return TRUE if range is known to be finite.
-- 
2.40.1



[COMMITTED] Remove deprecated vrange::kind().

2023-05-24 Thread Aldy Hernandez via Gcc-patches
gcc/ChangeLog:

* value-range.h (vrange::kind): Remove.
---
 gcc/value-range.h | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/gcc/value-range.h b/gcc/value-range.h
index 936eb175062..b8cc2a0e76a 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -100,9 +100,6 @@ public:
   bool operator== (const vrange &) const;
   bool operator!= (const vrange ) const { return !(*this == r); }
   void dump (FILE *) const;
-
-  enum value_range_kind kind () const; // DEPRECATED
-
 protected:
   vrange (enum value_range_discriminator d) : m_discriminator (d) { }
   ENUM_BITFIELD(value_range_kind) m_kind : 8;
-- 
2.40.1



Re: [COMMITTED] Remove buggy special case in irange::invert [PR109934].

2023-05-23 Thread Aldy Hernandez via Gcc-patches
BTW, we should probably backport this to god knows how many branches.

Aldy

On Tue, May 23, 2023 at 2:58 PM Aldy Hernandez  wrote:
>
> [Andrew, do you remotely remember what if anything this did?  It came
> from a wholesale merge from our long forgotten branch, so there's no
> history on the specifics of it.  Not important, I'm just curious.  It
> was probably me high on something.]
>
> This patch removes a buggy special case in irange::invert which seems
> to have been broken for a while, and probably never triggered because
> the legacy code was handled elsewhere, and the non-legacy code was
> using an int_range_max of int_range<255> which made it extremely
> likely for num_ranges == 255.  However, with auto-resizing ranges,
> int_range_max will start off at 3 and can hit this bogus code in the
> unswitching code.
>
> PR tree-optimization/109934
>
> gcc/ChangeLog:
>
> * value-range.cc (irange::invert): Remove buggy special case.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.dg/tree-ssa/pr109934.c: New test.
> ---
>  gcc/testsuite/gcc.dg/tree-ssa/pr109934.c | 22 ++
>  gcc/value-range.cc   |  8 
>  2 files changed, 22 insertions(+), 8 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr109934.c
>
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr109934.c 
> b/gcc/testsuite/gcc.dg/tree-ssa/pr109934.c
> new file mode 100644
> index 000..08bd5ce95c6
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr109934.c
> @@ -0,0 +1,22 @@
> +// { dg-do run }
> +// { dg-options "-O3" }
> +
> +int printf(const char *, ...);
> +short a;
> +long b = 3, c;
> +int d(int e) {
> +  switch (e)
> +  case 111:
> +  case 222:
> +  case 44:
> +return 0;
> +  return e;
> +}
> +int main() {
> +  for (; a >= 0; --a)
> +if (d(c + 23) - 23)
> +  b = 0;
> +
> +  if (b != 3)
> +__builtin_abort ();
> +}
> diff --git a/gcc/value-range.cc b/gcc/value-range.cc
> index 45b1e655967..874a1843ebf 100644
> --- a/gcc/value-range.cc
> +++ b/gcc/value-range.cc
> @@ -1650,14 +1650,6 @@ irange::invert ()
>wide_int type_min = wi::min_value (prec, sign);
>wide_int type_max = wi::max_value (prec, sign);
>m_nonzero_mask = wi::minus_one (prec);
> -  if (m_num_ranges == m_max_ranges
> -  && lower_bound () != type_min
> -  && upper_bound () != type_max)
> -{
> -  m_base[1] = type_max;
> -  m_num_ranges = 1;
> -  return;
> -}
>
>// At this point, we need one extra sub-range to represent the
>// inverse.
> --
> 2.40.1
>



[COMMITTED] Remove buggy special case in irange::invert [PR109934].

2023-05-23 Thread Aldy Hernandez via Gcc-patches
[Andrew, do you remotely remember what if anything this did?  It came
from a wholesale merge from our long forgotten branch, so there's no
history on the specifics of it.  Not important, I'm just curious.  It
was probably me high on something.]

This patch removes a buggy special case in irange::invert which seems
to have been broken for a while, and probably never triggered because
the legacy code was handled elsewhere, and the non-legacy code was
using an int_range_max of int_range<255> which made it extremely
likely for num_ranges == 255.  However, with auto-resizing ranges,
int_range_max will start off at 3 and can hit this bogus code in the
unswitching code.

PR tree-optimization/109934

gcc/ChangeLog:

* value-range.cc (irange::invert): Remove buggy special case.

gcc/testsuite/ChangeLog:

* gcc.dg/tree-ssa/pr109934.c: New test.
---
 gcc/testsuite/gcc.dg/tree-ssa/pr109934.c | 22 ++
 gcc/value-range.cc   |  8 
 2 files changed, 22 insertions(+), 8 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr109934.c

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr109934.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr109934.c
new file mode 100644
index 000..08bd5ce95c6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr109934.c
@@ -0,0 +1,22 @@
+// { dg-do run }
+// { dg-options "-O3" }
+
+int printf(const char *, ...);
+short a;
+long b = 3, c;
+int d(int e) {
+  switch (e)
+  case 111:
+  case 222:
+  case 44:
+return 0;
+  return e;
+}
+int main() {
+  for (; a >= 0; --a)
+if (d(c + 23) - 23)
+  b = 0;
+
+  if (b != 3)
+__builtin_abort ();
+}
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 45b1e655967..874a1843ebf 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -1650,14 +1650,6 @@ irange::invert ()
   wide_int type_min = wi::min_value (prec, sign);
   wide_int type_max = wi::max_value (prec, sign);
   m_nonzero_mask = wi::minus_one (prec);
-  if (m_num_ranges == m_max_ranges
-  && lower_bound () != type_min
-  && upper_bound () != type_max)
-{
-  m_base[1] = type_max;
-  m_num_ranges = 1;
-  return;
-}
 
   // At this point, we need one extra sub-range to represent the
   // inverse.
-- 
2.40.1



[COMMITTED] Use delete[] in int_range destructor [PR109920]

2023-05-23 Thread Aldy Hernandez via Gcc-patches
gcc/ChangeLog:

PR tree-optimization/109920
* value-range.h (RESIZABLE>::~int_range): Use delete[].
---
 gcc/value-range.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gcc/value-range.h b/gcc/value-range.h
index 171e6426c6e..936eb175062 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -490,7 +490,7 @@ inline
 int_range::~int_range ()
 {
   if (RESIZABLE && m_base != m_ranges)
-delete m_base;
+delete[] m_base;
 }
 
 // This is an "infinite" precision irange for use in temporary
-- 
2.40.1



[PATCH] Convert remaining uses of value_range in ipa-*.cc to Value_Range.

2023-05-22 Thread Aldy Hernandez via Gcc-patches
Minor cleanups to get rid of value_range in IPA.  There's only one left,
but it's in the switch code which is integer specific.

OK?

gcc/ChangeLog:

* ipa-cp.cc (decide_whether_version_node): Adjust comment.
* ipa-fnsummary.cc (evaluate_conditions_for_known_args): Adjust
for Value_Range.
(set_switch_stmt_execution_predicate): Same.
* ipa-prop.cc (ipa_compute_jump_functions_for_edge): Same.
---
 gcc/ipa-cp.cc|  3 +--
 gcc/ipa-fnsummary.cc | 22 ++
 gcc/ipa-prop.cc  |  9 +++--
 3 files changed, 18 insertions(+), 16 deletions(-)

diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
index 03273666ea2..2e64415096e 100644
--- a/gcc/ipa-cp.cc
+++ b/gcc/ipa-cp.cc
@@ -6287,8 +6287,7 @@ decide_whether_version_node (struct cgraph_node *node)
{
  /* If some values generated for self-recursive calls with
 arithmetic jump functions fall outside of the known
-value_range for the parameter, we can skip them.  VR interface
-supports this only for integers now.  */
+range for the parameter, we can skip them.  */
  if (TREE_CODE (val->value) == INTEGER_CST
  && !plats->m_value_range.bottom_p ()
  && !ipa_range_contains_p (plats->m_value_range.m_vr,
diff --git a/gcc/ipa-fnsummary.cc b/gcc/ipa-fnsummary.cc
index 0474af8991e..1ce8501fe85 100644
--- a/gcc/ipa-fnsummary.cc
+++ b/gcc/ipa-fnsummary.cc
@@ -488,19 +488,20 @@ evaluate_conditions_for_known_args (struct cgraph_node 
*node,
  if (vr.varying_p () || vr.undefined_p ())
break;
 
- value_range res;
+ Value_Range res (op->type);
  if (!op->val[0])
{
+ Value_Range varying (op->type);
+ varying.set_varying (op->type);
  range_op_handler handler (op->code, op->type);
  if (!handler
  || !res.supports_type_p (op->type)
- || !handler.fold_range (res, op->type, vr,
- value_range (op->type)))
+ || !handler.fold_range (res, op->type, vr, varying))
res.set_varying (op->type);
}
  else if (!op->val[1])
{
- value_range op0;
+ Value_Range op0 (op->type);
  range_op_handler handler (op->code, op->type);
 
  ipa_range_set_and_normalize (op0, op->val[0]);
@@ -518,14 +519,14 @@ evaluate_conditions_for_known_args (struct cgraph_node 
*node,
}
  if (!vr.varying_p () && !vr.undefined_p ())
{
- value_range res;
- value_range val_vr;
+ int_range<2> res;
+ Value_Range val_vr (TREE_TYPE (c->val));
  range_op_handler handler (c->code, boolean_type_node);
 
  ipa_range_set_and_normalize (val_vr, c->val);
 
  if (!handler
- || !res.supports_type_p (boolean_type_node)
+ || !val_vr.supports_type_p (TREE_TYPE (c->val))
  || !handler.fold_range (res, boolean_type_node, vr, 
val_vr))
res.set_varying (boolean_type_node);
 
@@ -1687,12 +1688,17 @@ set_switch_stmt_execution_predicate (struct 
ipa_func_body_info *fbi,
   int bound_limit = opt_for_fn (fbi->node->decl,
param_ipa_max_switch_predicate_bounds);
   int bound_count = 0;
-  value_range vr;
+  // This can safely be an integer range, as switches can only hold
+  // integers.
+  int_range<2> vr;
 
   get_range_query (cfun)->range_of_expr (vr, op);
   if (vr.undefined_p ())
 vr.set_varying (TREE_TYPE (op));
   tree vr_min, vr_max;
+  // ?? This entire function could use a rewrite to use the irange
+  // API, instead of trying to recreate its intersection/union logic.
+  // Any use of get_legacy_range() is a serious code smell.
   value_range_kind vr_type = get_legacy_range (vr, vr_min, vr_max);
   wide_int vr_wmin = wi::to_wide (vr_min);
   wide_int vr_wmax = wi::to_wide (vr_max);
diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
index 6383bc11e0a..5f9e6dbbff2 100644
--- a/gcc/ipa-prop.cc
+++ b/gcc/ipa-prop.cc
@@ -2348,7 +2348,6 @@ ipa_compute_jump_functions_for_edge (struct 
ipa_func_body_info *fbi,
   gcall *call = cs->call_stmt;
   int n, arg_num = gimple_call_num_args (call);
   bool useful_context = false;
-  value_range vr;
 
   if (arg_num == 0 || args->jump_functions)
 return;
@@ -2379,6 +2378,7 @@ ipa_compute_jump_functions_for_edge (struct 
ipa_func_body_info *fbi,
useful_context = true;
}
 
+  Value_Range vr (TREE_TYPE (arg));
   if (POINTER_TYPE_P (TREE_TYPE (arg)))
{
  bool 

[PATCH] Implement ipa_vr hashing.

2023-05-22 Thread Aldy Hernandez via Gcc-patches
Implement hashing for ipa_vr.  When all is said and done, all these
patches incurr a 7.64% slowdown for ipa-cp, with is entirely covered by
the similar 7% increase in this area last week.  So we get type agnostic
ranges with "infinite" range precision close to free.

There is no change in overall compilation.

OK?

gcc/ChangeLog:

* ipa-prop.cc (struct ipa_vr_ggc_hash_traits): Adjust for use with
ipa_vr instead of value_range.
(gt_pch_nx): Same.
(gt_ggc_mx): Same.
(ipa_get_value_range): Same.
* value-range.cc (gt_pch_nx): Move to ipa-prop.cc and adjust for
ipa_vr.
(gt_ggc_mx): Same.
---
 gcc/ipa-prop.cc| 76 +++---
 gcc/value-range.cc | 15 -
 2 files changed, 45 insertions(+), 46 deletions(-)

diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
index c46a89f1b49..6383bc11e0a 100644
--- a/gcc/ipa-prop.cc
+++ b/gcc/ipa-prop.cc
@@ -109,53 +109,53 @@ struct ipa_bit_ggc_hash_traits : public ggc_cache_remove 

 /* Hash table for avoid repeated allocations of equal ipa_bits.  */
 static GTY ((cache)) hash_table *ipa_bits_hash_table;
 
-/* Traits for a hash table for reusing value_ranges used for IPA.  Note that
-   the equiv bitmap is not hashed and is expected to be NULL.  */
+/* Traits for a hash table for reusing ranges.  */
 
-struct ipa_vr_ggc_hash_traits : public ggc_cache_remove 
+struct ipa_vr_ggc_hash_traits : public ggc_cache_remove 
 {
-  typedef value_range *value_type;
-  typedef value_range *compare_type;
+  typedef ipa_vr *value_type;
+  typedef const vrange *compare_type;
   static hashval_t
-  hash (const value_range *p)
+  hash (const ipa_vr *p)
 {
-  tree min, max;
-  value_range_kind kind = get_legacy_range (*p, min, max);
-  inchash::hash hstate (kind);
-  inchash::add_expr (min, hstate);
-  inchash::add_expr (max, hstate);
+  // This never get called, except in the verification code, as
+  // ipa_get_value_range() calculates the hash itself.  This
+  // function is mostly here for completness' sake.
+  Value_Range vr;
+  p->get_vrange (vr);
+  inchash::hash hstate;
+  add_vrange (vr, hstate);
   return hstate.end ();
 }
   static bool
-  equal (const value_range *a, const value_range *b)
+  equal (const ipa_vr *a, const vrange *b)
 {
-  return (types_compatible_p (a->type (), b->type ())
- && *a == *b);
+  return a->equal_p (*b);
 }
   static const bool empty_zero_p = true;
   static void
-  mark_empty (value_range *)
+  mark_empty (ipa_vr *)
 {
   p = NULL;
 }
   static bool
-  is_empty (const value_range *p)
+  is_empty (const ipa_vr *p)
 {
   return p == NULL;
 }
   static bool
-  is_deleted (const value_range *p)
+  is_deleted (const ipa_vr *p)
 {
-  return p == reinterpret_cast (1);
+  return p == reinterpret_cast (1);
 }
   static void
-  mark_deleted (value_range *)
+  mark_deleted (ipa_vr *)
 {
-  p = reinterpret_cast (1);
+  p = reinterpret_cast (1);
 }
 };
 
-/* Hash table for avoid repeated allocations of equal value_ranges.  */
+/* Hash table for avoid repeated allocations of equal ranges.  */
 static GTY ((cache)) hash_table *ipa_vr_hash_table;
 
 /* Holders of ipa cgraph hooks: */
@@ -265,6 +265,22 @@ ipa_vr::dump (FILE *out) const
 fprintf (out, "NO RANGE");
 }
 
+// ?? These stubs are because we use an ipa_vr in a hash_traits and
+// hash-traits.h defines an extern of gt_ggc_mx (T &) instead of
+// picking up the gt_ggc_mx (T *) version.
+void
+gt_pch_nx (ipa_vr *)
+{
+  return gt_pch_nx ((ipa_vr *) x);
+}
+
+void
+gt_ggc_mx (ipa_vr *)
+{
+  return gt_ggc_mx ((ipa_vr *) x);
+}
+
+
 /* Return true if DECL_FUNCTION_SPECIFIC_OPTIMIZATION of the decl associated
with NODE should prevent us from analyzing it for the purposes of IPA-CP.  
*/
 
@@ -2284,27 +2300,25 @@ ipa_set_jfunc_bits (ipa_jump_func *jf, const widest_int 
,
   jf->bits = ipa_get_ipa_bits_for_value (value, mask);
 }
 
-/* Return a pointer to a value_range just like *TMP, but either find it in
-   ipa_vr_hash_table or allocate it in GC memory.  TMP->equiv must be NULL.  */
+/* Return a pointer to an ipa_vr just like TMP, but either find it in
+   ipa_vr_hash_table or allocate it in GC memory.  */
 
 static ipa_vr *
 ipa_get_value_range (const vrange )
 {
-  /* FIXME: Add hashing support.
-  value_range **slot = ipa_vr_hash_table->find_slot (tmp, INSERT);
+  inchash::hash hstate;
+  inchash::add_vrange (tmp, hstate);
+  hashval_t hash = hstate.end ();
+  ipa_vr **slot = ipa_vr_hash_table->find_slot_with_hash (, hash, INSERT);
   if (*slot)
 return *slot;
 
-  value_range *vr = new (ggc_alloc ()) value_range;
-  *vr = *tmp;
-  *slot = vr;
-  */
   ipa_vr *vr = new (ggc_alloc ()) ipa_vr (tmp);
-
+  *slot = vr;
   return vr;
 }
 
-/* Assign to JF a pointer to a value_range just like TMP but either fetch a
+/* Assign to JF a pointer to a range just like TMP 

[PATCH] Convert ipa_jump_func to use ipa_vr instead of a value_range.

2023-05-22 Thread Aldy Hernandez via Gcc-patches
This patch converts the ipa_jump_func code to use the type agnostic
ipa_vr suitable for GC instead of value_range which is integer specific.

I've disabled the range cacheing to simplify the patch for review, but
it is handled in the next patch in the series.

OK?

gcc/ChangeLog:

* ipa-cp.cc (ipa_vr_operation_and_type_effects): New.
* ipa-prop.cc (ipa_get_value_range): Adjust for ipa_vr.
(ipa_set_jfunc_vr): Take a range.
(ipa_compute_jump_functions_for_edge): Pass range to
ipa_set_jfunc_vr.
(ipa_write_jump_function): Call streamer write helper.
(ipa_read_jump_function): Call streamer read helper.
* ipa-prop.h (class ipa_vr): Change m_vr to an ipa_vr.
---
 gcc/ipa-cp.cc   | 15 +++
 gcc/ipa-prop.cc | 70 ++---
 gcc/ipa-prop.h  |  5 +++-
 3 files changed, 44 insertions(+), 46 deletions(-)

diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
index bdbc2184b5f..03273666ea2 100644
--- a/gcc/ipa-cp.cc
+++ b/gcc/ipa-cp.cc
@@ -1928,6 +1928,21 @@ ipa_vr_operation_and_type_effects (vrange _vr,
  && !dst_vr.undefined_p ());
 }
 
+/* Same as above, but the SRC_VR argument is an IPA_VR which must
+   first be extracted onto a vrange.  */
+
+static bool
+ipa_vr_operation_and_type_effects (vrange _vr,
+  const ipa_vr _vr,
+  enum tree_code operation,
+  tree dst_type, tree src_type)
+{
+  Value_Range tmp;
+  src_vr.get_vrange (tmp);
+  return ipa_vr_operation_and_type_effects (dst_vr, tmp, operation,
+   dst_type, src_type);
+}
+
 /* Determine range of JFUNC given that INFO describes the caller node or
the one it is inlined to, CS is the call graph edge corresponding to JFUNC
and PARM_TYPE of the parameter.  */
diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
index bbfe0f8aa45..c46a89f1b49 100644
--- a/gcc/ipa-prop.cc
+++ b/gcc/ipa-prop.cc
@@ -2287,9 +2287,10 @@ ipa_set_jfunc_bits (ipa_jump_func *jf, const widest_int 
,
 /* Return a pointer to a value_range just like *TMP, but either find it in
ipa_vr_hash_table or allocate it in GC memory.  TMP->equiv must be NULL.  */
 
-static value_range *
-ipa_get_value_range (value_range *tmp)
+static ipa_vr *
+ipa_get_value_range (const vrange )
 {
+  /* FIXME: Add hashing support.
   value_range **slot = ipa_vr_hash_table->find_slot (tmp, INSERT);
   if (*slot)
 return *slot;
@@ -2297,40 +2298,27 @@ ipa_get_value_range (value_range *tmp)
   value_range *vr = new (ggc_alloc ()) value_range;
   *vr = *tmp;
   *slot = vr;
+  */
+  ipa_vr *vr = new (ggc_alloc ()) ipa_vr (tmp);
 
   return vr;
 }
 
-/* Return a pointer to a value range consisting of TYPE, MIN, MAX and an empty
-   equiv set. Use hash table in order to avoid creating multiple same copies of
-   value_ranges.  */
-
-static value_range *
-ipa_get_value_range (enum value_range_kind kind, tree min, tree max)
-{
-  value_range tmp (TREE_TYPE (min),
-  wi::to_wide (min), wi::to_wide (max), kind);
-  return ipa_get_value_range ();
-}
-
-/* Assign to JF a pointer to a value_range structure with TYPE, MIN and MAX and
-   a NULL equiv bitmap.  Use hash table in order to avoid creating multiple
-   same value_range structures.  */
+/* Assign to JF a pointer to a value_range just like TMP but either fetch a
+   copy from ipa_vr_hash_table or allocate a new on in GC memory.  */
 
 static void
-ipa_set_jfunc_vr (ipa_jump_func *jf, enum value_range_kind type,
- tree min, tree max)
+ipa_set_jfunc_vr (ipa_jump_func *jf, const vrange )
 {
-  jf->m_vr = ipa_get_value_range (type, min, max);
+  jf->m_vr = ipa_get_value_range (tmp);
 }
 
-/* Assign to JF a pointer to a value_range just like TMP but either fetch a
-   copy from ipa_vr_hash_table or allocate a new on in GC memory.  */
-
 static void
-ipa_set_jfunc_vr (ipa_jump_func *jf, value_range *tmp)
+ipa_set_jfunc_vr (ipa_jump_func *jf, const ipa_vr )
 {
-  jf->m_vr = ipa_get_value_range (tmp);
+  Value_Range tmp;
+  vr.get_vrange (tmp);
+  ipa_set_jfunc_vr (jf, tmp);
 }
 
 /* Compute jump function for all arguments of callsite CS and insert the
@@ -2392,8 +2380,8 @@ ipa_compute_jump_functions_for_edge (struct 
ipa_func_body_info *fbi,
 
  if (addr_nonzero)
{
- tree z = build_int_cst (TREE_TYPE (arg), 0);
- ipa_set_jfunc_vr (jfunc, VR_ANTI_RANGE, z, z);
+ vr.set_nonzero (TREE_TYPE (arg));
+ ipa_set_jfunc_vr (jfunc, vr);
}
  else
gcc_assert (!jfunc->m_vr);
@@ -2412,7 +2400,7 @@ ipa_compute_jump_functions_for_edge (struct 
ipa_func_body_info *fbi,
  value_range resvr = vr;
  range_cast (resvr, param_type);
  if (!resvr.undefined_p () && !resvr.varying_p ())
-   ipa_set_jfunc_vr (jfunc, );
+   ipa_set_jfunc_vr (jfunc, resvr);
  

Re: [PATCH] Convert ipcp_vr_lattice to type agnostic framework.

2023-05-22 Thread Aldy Hernandez via Gcc-patches
I've adjusted the patch with some minor cleanups that came up when I
implemented the rest of the IPA revamp.

Rested.  OK?

On Wed, May 17, 2023 at 4:31 PM Aldy Hernandez  wrote:
>
> This converts the lattice to store ranges in Value_Range instead of
> value_range (*) to make it type agnostic, and adjust all users
> accordingly.
>
> I think it is a good example on converting from static ranges to more
> general, type agnostic ones.
>
> I've been careful to make sure Value_Range never ends up on GC, since
> it contains an int_range_max and can expand on-demand onto the heap.
> Longer term storage for ranges should be done with vrange_storage, as
> per the previous patch ("Provide an API for ipa_vr").
>
> (*) I do know the Value_Range naming versus value_range is quite
> annoying, but it was a judgement call last release for the eventual
> migration to having "value_range" be a type agnostic range object.  We
> will ultimately rename Value_Range to value_range.
>
> OK for trunk?
>
> gcc/ChangeLog:
>
> * ipa-cp.cc (ipcp_vr_lattice::init): Take type argument.
> (ipcp_vr_lattice::print): Call dump method.
> (ipcp_vr_lattice::meet_with): Adjust for m_vr being a
> Value_Range.
> (ipcp_vr_lattice::meet_with_1): Make argument a reference.
> (ipcp_vr_lattice::set_to_bottom): Add type argument.
> (set_all_contains_variable): Same.
> (initialize_node_lattices): Pass type when appropriate.
> (ipa_vr_operation_and_type_effects): Make type agnostic.
> (ipa_value_range_from_jfunc): Same.
> (propagate_vr_across_jump_function): Same.
> (propagate_constants_across_call): Same.
> * ipa-fnsummary.cc (evaluate_conditions_for_known_args): Same.
> (evaluate_properties_for_edge): Same.
> * ipa-prop.cc (ipcp_update_vr): Same.
> * ipa-prop.h (ipa_value_range_from_jfunc): Same.
> (ipa_range_set_and_normalize): Same.
> ---
>  gcc/ipa-cp.cc| 159 +++
>  gcc/ipa-fnsummary.cc |  16 ++---
>  gcc/ipa-prop.cc  |   2 +-
>  gcc/ipa-prop.h   |  19 ++
>  4 files changed, 101 insertions(+), 95 deletions(-)
>
> diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
> index d4b9d4ac27e..bd5b1da17b2 100644
> --- a/gcc/ipa-cp.cc
> +++ b/gcc/ipa-cp.cc
> @@ -343,20 +343,29 @@ private:
>  class ipcp_vr_lattice
>  {
>  public:
> -  value_range m_vr;
> +  Value_Range m_vr;
>
>inline bool bottom_p () const;
>inline bool top_p () const;
> -  inline bool set_to_bottom ();
> -  bool meet_with (const value_range *p_vr);
> +  inline bool set_to_bottom (tree type);
> +  bool meet_with (const vrange _vr);
>bool meet_with (const ipcp_vr_lattice );
> -  void init () { gcc_assert (m_vr.undefined_p ()); }
> +  void init (tree type);
>void print (FILE * f);
>
>  private:
> -  bool meet_with_1 (const value_range *other_vr);
> +  bool meet_with_1 (const vrange _vr);
>  };
>
> +inline void
> +ipcp_vr_lattice::init (tree type)
> +{
> +  if (type)
> +m_vr.set_type (type);
> +
> +  // Otherwise m_vr will default to unsupported_range.
> +}
> +
>  /* Structure containing lattices for a parameter itself and for pieces of
> aggregates that are passed in the parameter or by a reference in a 
> parameter
> plus some other useful flags.  */
> @@ -585,7 +594,7 @@ ipcp_bits_lattice::print (FILE *f)
>  void
>  ipcp_vr_lattice::print (FILE * f)
>  {
> -  dump_value_range (f, _vr);
> +  m_vr.dump (f);
>  }
>
>  /* Print all ipcp_lattices of all functions to F.  */
> @@ -1016,14 +1025,14 @@ set_agg_lats_contain_variable (class 
> ipcp_param_lattices *plats)
>  bool
>  ipcp_vr_lattice::meet_with (const ipcp_vr_lattice )
>  {
> -  return meet_with_1 (_vr);
> +  return meet_with_1 (other.m_vr);
>  }
>
>  /* Meet the current value of the lattice with value range described by VR
> lattice.  */
>
>  bool
> -ipcp_vr_lattice::meet_with (const value_range *p_vr)
> +ipcp_vr_lattice::meet_with (const vrange _vr)
>  {
>return meet_with_1 (p_vr);
>  }
> @@ -1032,23 +1041,23 @@ ipcp_vr_lattice::meet_with (const value_range *p_vr)
> OTHER_VR lattice.  Return TRUE if anything changed.  */
>
>  bool
> -ipcp_vr_lattice::meet_with_1 (const value_range *other_vr)
> +ipcp_vr_lattice::meet_with_1 (const vrange _vr)
>  {
>if (bottom_p ())
>  return false;
>
> -  if (other_vr->varying_p ())
> -return set_to_bottom ();
> +  if (other_vr.varying_p ())
> +return set_to_bottom (other_vr.type ());
>
>bool res;
>if (flag_checking)
>  {
> -  value_range save (m_vr);
> -  res = m_vr.union_ (*other_vr);
> +  Value_Range save (m_vr);
> +  res = m_vr.union_ (other_vr);
>gcc_assert (res == (m_vr != save));
>  }
>else
> -res = m_vr.union_ (*other_vr);
> +res = m_vr.union_ (other_vr);
>return res;
>  }
>
> @@ -1073,16 +1082,11 @@ ipcp_vr_lattice::bottom_p () const
> previously was in a different state.  */
>
>  bool
> 

Re: [PATCH] Provide an API for ipa_vr.

2023-05-22 Thread Aldy Hernandez via Gcc-patches
I've adjusted the patch with some minor cleanups that came up when I
implemented the rest of the IPA revamp.

Retested.   OK?

On Wed, May 17, 2023 at 4:16 PM Aldy Hernandez  wrote:
>
> This patch encapsulates the ipa_vr internals into an API.  It also
> makes it type agnostic, in preparation for upcoming changes to IPA.
>
> Interestingly, there's a 0.44% improvement to IPA-cp, which I'm sure
> we'll soak up with future changes in this area :).
>
> BTW, there's a note here:
> +  // vrange_storage is typeless, but we need to know what type of
> +  // range that is being streamed out (irange, frange, etc).  AFAICT,
> +  // there's no way to get at the underlying type by the time we
> +  // stream out in write_ipcp_transformation_info.
> +  tree m_type;
>
> Could someone more IPA savvy double check this is indeed the case?
>
> OK for trunk?
>
> gcc/ChangeLog:
>
> * ipa-cp.cc (ipa_value_range_from_jfunc): Use new ipa_vr API.
> (ipcp_store_vr_results): Same.
> * ipa-prop.cc (ipa_vr::ipa_vr): New.
> (ipa_vr::get_vrange): New.
> (ipa_vr::set_unknown): New.
> (ipa_vr::streamer_read): New.
> (ipa_vr::streamer_write): New.
> (write_ipcp_transformation_info): Use new ipa_vr API.
> (read_ipcp_transformation_info): Same.
> (ipa_vr::nonzero_p): Delete.
> (ipcp_update_vr): Use new ipa_vr API.
> * ipa-prop.h (class ipa_vr): Provide an API and hide internals.
> * ipa-sra.cc (zap_useless_ipcp_results): Use new ipa_vr API.
> * gcc.dg/ipa/pr78121.c: Adjust for vrange::dump use.
> * gcc.dg/ipa/vrp1.c: Same.
> * gcc.dg/ipa/vrp2.c: Same.
> * gcc.dg/ipa/vrp3.c: Same.
> * gcc.dg/ipa/vrp4.c: Same.
> * gcc.dg/ipa/vrp5.c: Same.
> * gcc.dg/ipa/vrp6.c: Same.
> * gcc.dg/ipa/vrp7.c: Same.
> * gcc.dg/ipa/vrp8.c: Same.
> ---
>  gcc/ipa-cp.cc  |  22 ++---
>  gcc/ipa-prop.cc| 129 -
>  gcc/ipa-prop.h |  25 --
>  gcc/ipa-sra.cc |   4 +-
>  gcc/testsuite/gcc.dg/ipa/pr78121.c |   2 +-
>  gcc/testsuite/gcc.dg/ipa/vrp1.c|   4 +-
>  gcc/testsuite/gcc.dg/ipa/vrp2.c|   4 +-
>  gcc/testsuite/gcc.dg/ipa/vrp3.c|   2 +-
>  gcc/testsuite/gcc.dg/ipa/vrp4.c|   2 +-
>  gcc/testsuite/gcc.dg/ipa/vrp5.c|   2 +-
>  gcc/testsuite/gcc.dg/ipa/vrp6.c|   2 +-
>  gcc/testsuite/gcc.dg/ipa/vrp7.c|   2 +-
>  gcc/testsuite/gcc.dg/ipa/vrp8.c|   2 +-
>  13 files changed, 109 insertions(+), 93 deletions(-)
>
> diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
> index 8cd0fa2cae7..d4b9d4ac27e 100644
> --- a/gcc/ipa-cp.cc
> +++ b/gcc/ipa-cp.cc
> @@ -1947,13 +1947,11 @@ ipa_value_range_from_jfunc (ipa_node_params *info, 
> cgraph_edge *cs,
>
>idx = ipa_get_jf_pass_through_formal_id (jfunc);
>
> -  if (!(*sum->m_vr)[idx].known)
> +  if (!(*sum->m_vr)[idx].known_p ())
> return vr;
>tree vr_type = ipa_get_type (info, idx);
> -  value_range srcvr (vr_type,
> -(*sum->m_vr)[idx].min,
> -(*sum->m_vr)[idx].max,
> -(*sum->m_vr)[idx].type);
> +  value_range srcvr;
> +  (*sum->m_vr)[idx].get_vrange (srcvr, vr_type);
>
>enum tree_code operation = ipa_get_jf_pass_through_operation (jfunc);
>
> @@ -6621,25 +6619,19 @@ ipcp_store_vr_results (void)
>for (unsigned i = 0; i < count; i++)
> {
>   ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
> - ipa_vr vr;
>
>   if (!plats->m_value_range.bottom_p ()
>   && !plats->m_value_range.top_p ()
>   && dbg_cnt (ipa_cp_vr))
> {
> - tree min, max;
> - vr.known = true;
> - vr.type = get_legacy_range (plats->m_value_range.m_vr, min, 
> max);
> - vr.min = wi::to_wide (min);
> - vr.max = wi::to_wide (max);
> + ipa_vr vr (plats->m_value_range.m_vr);
> + ts->m_vr->quick_push (vr);
> }
>   else
> {
> - vr.known = false;
> - vr.type = VR_VARYING;
> - vr.min = vr.max = wi::zero (INT_TYPE_SIZE);
> + ipa_vr vr;
> + ts->m_vr->quick_push (vr);
> }
> - ts->m_vr->quick_push (vr);
> }
>  }
>  }
> diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
> index d7d70e5ec68..4ace410de49 100644
> --- a/gcc/ipa-prop.cc
> +++ b/gcc/ipa-prop.cc
> @@ -56,6 +56,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "symtab-clones.h"
>  #include "attr-fnspec.h"
>  #include "gimple-range.h"
> +#include "value-range-storage.h"
>
>  /* Function summary where the parameter infos are actually stored. */
>  ipa_node_params_t *ipa_node_params_sum = NULL;
> @@ -177,6 +178,66 @@ struct ipa_cst_ref_desc
>  static object_allocator ipa_refdesc_pool
>("IPA-PROP 

[COMMITTED] Implement some miscellaneous zero accessors for Value_Range.

2023-05-22 Thread Aldy Hernandez via Gcc-patches
This adds some missing accessors to the type agnostic Value_Range
class.  They'll be used in the upcoming IPA work.

gcc/ChangeLog:

* value-range.h (class Value_Range): Implement set_zero,
set_nonzero, and nonzero_p.
---
 gcc/value-range.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/gcc/value-range.h b/gcc/value-range.h
index af81d6080da..171e6426c6e 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -542,6 +542,9 @@ public:
   bool contains_p (tree cst) const { return m_vrange->contains_p (cst); }
   bool singleton_p (tree *result = NULL) const
 { return m_vrange->singleton_p (result); }
+  void set_zero (tree type) { return m_vrange->set_zero (type); }
+  void set_nonzero (tree type) { return m_vrange->set_nonzero (type); }
+  bool nonzero_p () const { return m_vrange->nonzero_p (); }
   bool zero_p () const { return m_vrange->zero_p (); }
   wide_int lower_bound () const; // For irange/prange comparability.
   wide_int upper_bound () const; // For irange/prange comparability.
-- 
2.40.1



Re: [PATCH] Convert ipcp_vr_lattice to type agnostic framework.

2023-05-17 Thread Aldy Hernandez via Gcc-patches




On 5/17/23 16:30, Aldy Hernandez wrote:

This converts the lattice to store ranges in Value_Range instead of
value_range (*) to make it type agnostic, and adjust all users
accordingly.

I think it is a good example on converting from static ranges to more
general, type agnostic ones.

I've been careful to make sure Value_Range never ends up on GC, since
it contains an int_range_max and can expand on-demand onto the heap.
Longer term storage for ranges should be done with vrange_storage, as
per the previous patch ("Provide an API for ipa_vr").

(*) I do know the Value_Range naming versus value_range is quite
annoying, but it was a judgement call last release for the eventual
migration to having "value_range" be a type agnostic range object.  We
will ultimately rename Value_Range to value_range.


I forgot to mention.  This doesn't make IPA be type agnostic per se, 
just the range usage throughout.  The IPA code is still guarded by stuff 
like:


  if (!param_type
  || (!INTEGRAL_TYPE_P (param_type)
  && !POINTER_TYPE_P (param_type)))
return dest_lat->set_to_bottom (param_type);

It is up to the maintainers to adjust their passes, as I'm liable to 
break everything in the process ;-).


The above should probably become:

   if (!param_type || !Value_Range::supports_type_p (param_type))
...

This is the canonical way of querying whether a type is supported by 
Value_Range, the ranger temporary that can handle each supported type, 
and thus the ranger.  This is documented here:


// To query what types ranger and the entire ecosystem can support,
// use Value_Range::supports_type_p(tree type).  This is a static
// method available independently of any vrange object.
//
// To query what a given vrange variant can support, use:
//irange::supports_p ()
//frange::supports_p ()
//etc

However, with the changes I have posted so far, ranges throughout have a 
much finer granularity and are no longer limited to the 2-sub-ranges in 
a value_range.  If you look at IPA dumps now, you'll see the ranges are 
much more refined and are streamed for LTO accordingly.  This is an 
improvement in and of itself.


Aldy



[PATCH] Convert ipcp_vr_lattice to type agnostic framework.

2023-05-17 Thread Aldy Hernandez via Gcc-patches
This converts the lattice to store ranges in Value_Range instead of
value_range (*) to make it type agnostic, and adjust all users
accordingly.

I think it is a good example on converting from static ranges to more
general, type agnostic ones.

I've been careful to make sure Value_Range never ends up on GC, since
it contains an int_range_max and can expand on-demand onto the heap.
Longer term storage for ranges should be done with vrange_storage, as
per the previous patch ("Provide an API for ipa_vr").

(*) I do know the Value_Range naming versus value_range is quite
annoying, but it was a judgement call last release for the eventual
migration to having "value_range" be a type agnostic range object.  We
will ultimately rename Value_Range to value_range.

OK for trunk?

gcc/ChangeLog:

* ipa-cp.cc (ipcp_vr_lattice::init): Take type argument.
(ipcp_vr_lattice::print): Call dump method.
(ipcp_vr_lattice::meet_with): Adjust for m_vr being a
Value_Range.
(ipcp_vr_lattice::meet_with_1): Make argument a reference.
(ipcp_vr_lattice::set_to_bottom): Add type argument.
(set_all_contains_variable): Same.
(initialize_node_lattices): Pass type when appropriate.
(ipa_vr_operation_and_type_effects): Make type agnostic.
(ipa_value_range_from_jfunc): Same.
(propagate_vr_across_jump_function): Same.
(propagate_constants_across_call): Same.
* ipa-fnsummary.cc (evaluate_conditions_for_known_args): Same.
(evaluate_properties_for_edge): Same.
* ipa-prop.cc (ipcp_update_vr): Same.
* ipa-prop.h (ipa_value_range_from_jfunc): Same.
(ipa_range_set_and_normalize): Same.
---
 gcc/ipa-cp.cc| 159 +++
 gcc/ipa-fnsummary.cc |  16 ++---
 gcc/ipa-prop.cc  |   2 +-
 gcc/ipa-prop.h   |  19 ++
 4 files changed, 101 insertions(+), 95 deletions(-)

diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
index d4b9d4ac27e..bd5b1da17b2 100644
--- a/gcc/ipa-cp.cc
+++ b/gcc/ipa-cp.cc
@@ -343,20 +343,29 @@ private:
 class ipcp_vr_lattice
 {
 public:
-  value_range m_vr;
+  Value_Range m_vr;
 
   inline bool bottom_p () const;
   inline bool top_p () const;
-  inline bool set_to_bottom ();
-  bool meet_with (const value_range *p_vr);
+  inline bool set_to_bottom (tree type);
+  bool meet_with (const vrange _vr);
   bool meet_with (const ipcp_vr_lattice );
-  void init () { gcc_assert (m_vr.undefined_p ()); }
+  void init (tree type);
   void print (FILE * f);
 
 private:
-  bool meet_with_1 (const value_range *other_vr);
+  bool meet_with_1 (const vrange _vr);
 };
 
+inline void
+ipcp_vr_lattice::init (tree type)
+{
+  if (type)
+m_vr.set_type (type);
+
+  // Otherwise m_vr will default to unsupported_range.
+}
+
 /* Structure containing lattices for a parameter itself and for pieces of
aggregates that are passed in the parameter or by a reference in a parameter
plus some other useful flags.  */
@@ -585,7 +594,7 @@ ipcp_bits_lattice::print (FILE *f)
 void
 ipcp_vr_lattice::print (FILE * f)
 {
-  dump_value_range (f, _vr);
+  m_vr.dump (f);
 }
 
 /* Print all ipcp_lattices of all functions to F.  */
@@ -1016,14 +1025,14 @@ set_agg_lats_contain_variable (class 
ipcp_param_lattices *plats)
 bool
 ipcp_vr_lattice::meet_with (const ipcp_vr_lattice )
 {
-  return meet_with_1 (_vr);
+  return meet_with_1 (other.m_vr);
 }
 
 /* Meet the current value of the lattice with value range described by VR
lattice.  */
 
 bool
-ipcp_vr_lattice::meet_with (const value_range *p_vr)
+ipcp_vr_lattice::meet_with (const vrange _vr)
 {
   return meet_with_1 (p_vr);
 }
@@ -1032,23 +1041,23 @@ ipcp_vr_lattice::meet_with (const value_range *p_vr)
OTHER_VR lattice.  Return TRUE if anything changed.  */
 
 bool
-ipcp_vr_lattice::meet_with_1 (const value_range *other_vr)
+ipcp_vr_lattice::meet_with_1 (const vrange _vr)
 {
   if (bottom_p ())
 return false;
 
-  if (other_vr->varying_p ())
-return set_to_bottom ();
+  if (other_vr.varying_p ())
+return set_to_bottom (other_vr.type ());
 
   bool res;
   if (flag_checking)
 {
-  value_range save (m_vr);
-  res = m_vr.union_ (*other_vr);
+  Value_Range save (m_vr);
+  res = m_vr.union_ (other_vr);
   gcc_assert (res == (m_vr != save));
 }
   else
-res = m_vr.union_ (*other_vr);
+res = m_vr.union_ (other_vr);
   return res;
 }
 
@@ -1073,16 +1082,11 @@ ipcp_vr_lattice::bottom_p () const
previously was in a different state.  */
 
 bool
-ipcp_vr_lattice::set_to_bottom ()
+ipcp_vr_lattice::set_to_bottom (tree type)
 {
   if (m_vr.varying_p ())
 return false;
-  /* ?? We create all sorts of VARYING ranges for floats, structures,
- and other types which we cannot handle as ranges.  We should
- probably avoid handling them throughout the pass, but it's easier
- to create a sensible VARYING here and let the lattice
- propagate.  */
-  m_vr.set_varying 

[PATCH] Provide an API for ipa_vr.

2023-05-17 Thread Aldy Hernandez via Gcc-patches
This patch encapsulates the ipa_vr internals into an API.  It also
makes it type agnostic, in preparation for upcoming changes to IPA.

Interestingly, there's a 0.44% improvement to IPA-cp, which I'm sure
we'll soak up with future changes in this area :).

BTW, there's a note here:
+  // vrange_storage is typeless, but we need to know what type of
+  // range that is being streamed out (irange, frange, etc).  AFAICT,
+  // there's no way to get at the underlying type by the time we
+  // stream out in write_ipcp_transformation_info.
+  tree m_type;

Could someone more IPA savvy double check this is indeed the case?

OK for trunk?

gcc/ChangeLog:

* ipa-cp.cc (ipa_value_range_from_jfunc): Use new ipa_vr API.
(ipcp_store_vr_results): Same.
* ipa-prop.cc (ipa_vr::ipa_vr): New.
(ipa_vr::get_vrange): New.
(ipa_vr::set_unknown): New.
(ipa_vr::streamer_read): New.
(ipa_vr::streamer_write): New.
(write_ipcp_transformation_info): Use new ipa_vr API.
(read_ipcp_transformation_info): Same.
(ipa_vr::nonzero_p): Delete.
(ipcp_update_vr): Use new ipa_vr API.
* ipa-prop.h (class ipa_vr): Provide an API and hide internals.
* ipa-sra.cc (zap_useless_ipcp_results): Use new ipa_vr API.
* gcc.dg/ipa/pr78121.c: Adjust for vrange::dump use.
* gcc.dg/ipa/vrp1.c: Same.
* gcc.dg/ipa/vrp2.c: Same.
* gcc.dg/ipa/vrp3.c: Same.
* gcc.dg/ipa/vrp4.c: Same.
* gcc.dg/ipa/vrp5.c: Same.
* gcc.dg/ipa/vrp6.c: Same.
* gcc.dg/ipa/vrp7.c: Same.
* gcc.dg/ipa/vrp8.c: Same.
---
 gcc/ipa-cp.cc  |  22 ++---
 gcc/ipa-prop.cc| 129 -
 gcc/ipa-prop.h |  25 --
 gcc/ipa-sra.cc |   4 +-
 gcc/testsuite/gcc.dg/ipa/pr78121.c |   2 +-
 gcc/testsuite/gcc.dg/ipa/vrp1.c|   4 +-
 gcc/testsuite/gcc.dg/ipa/vrp2.c|   4 +-
 gcc/testsuite/gcc.dg/ipa/vrp3.c|   2 +-
 gcc/testsuite/gcc.dg/ipa/vrp4.c|   2 +-
 gcc/testsuite/gcc.dg/ipa/vrp5.c|   2 +-
 gcc/testsuite/gcc.dg/ipa/vrp6.c|   2 +-
 gcc/testsuite/gcc.dg/ipa/vrp7.c|   2 +-
 gcc/testsuite/gcc.dg/ipa/vrp8.c|   2 +-
 13 files changed, 109 insertions(+), 93 deletions(-)

diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
index 8cd0fa2cae7..d4b9d4ac27e 100644
--- a/gcc/ipa-cp.cc
+++ b/gcc/ipa-cp.cc
@@ -1947,13 +1947,11 @@ ipa_value_range_from_jfunc (ipa_node_params *info, 
cgraph_edge *cs,
 
   idx = ipa_get_jf_pass_through_formal_id (jfunc);
 
-  if (!(*sum->m_vr)[idx].known)
+  if (!(*sum->m_vr)[idx].known_p ())
return vr;
   tree vr_type = ipa_get_type (info, idx);
-  value_range srcvr (vr_type,
-(*sum->m_vr)[idx].min,
-(*sum->m_vr)[idx].max,
-(*sum->m_vr)[idx].type);
+  value_range srcvr;
+  (*sum->m_vr)[idx].get_vrange (srcvr, vr_type);
 
   enum tree_code operation = ipa_get_jf_pass_through_operation (jfunc);
 
@@ -6621,25 +6619,19 @@ ipcp_store_vr_results (void)
   for (unsigned i = 0; i < count; i++)
{
  ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
- ipa_vr vr;
 
  if (!plats->m_value_range.bottom_p ()
  && !plats->m_value_range.top_p ()
  && dbg_cnt (ipa_cp_vr))
{
- tree min, max;
- vr.known = true;
- vr.type = get_legacy_range (plats->m_value_range.m_vr, min, max);
- vr.min = wi::to_wide (min);
- vr.max = wi::to_wide (max);
+ ipa_vr vr (plats->m_value_range.m_vr);
+ ts->m_vr->quick_push (vr);
}
  else
{
- vr.known = false;
- vr.type = VR_VARYING;
- vr.min = vr.max = wi::zero (INT_TYPE_SIZE);
+ ipa_vr vr;
+ ts->m_vr->quick_push (vr);
}
- ts->m_vr->quick_push (vr);
}
 }
 }
diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
index d7d70e5ec68..4ace410de49 100644
--- a/gcc/ipa-prop.cc
+++ b/gcc/ipa-prop.cc
@@ -56,6 +56,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "symtab-clones.h"
 #include "attr-fnspec.h"
 #include "gimple-range.h"
+#include "value-range-storage.h"
 
 /* Function summary where the parameter infos are actually stored. */
 ipa_node_params_t *ipa_node_params_sum = NULL;
@@ -177,6 +178,66 @@ struct ipa_cst_ref_desc
 static object_allocator ipa_refdesc_pool
   ("IPA-PROP ref descriptions");
 
+ipa_vr::ipa_vr ()
+  : m_storage (NULL),
+m_type (NULL)
+{
+}
+
+ipa_vr::ipa_vr (const vrange )
+  : m_storage (ggc_alloc_vrange_storage (r)),
+m_type (r.type ())
+{
+}
+
+void
+ipa_vr::get_vrange (vrange , tree type) const
+{
+  m_storage->get_vrange (r, type);
+}
+
+void
+ipa_vr::set_unknown ()
+{
+  if (m_storage)
+ggc_free (m_storage);
+
+  m_storage = NULL;
+}
+
+void

[COMMITTED] Add Value_Range::operator=.

2023-05-17 Thread Aldy Hernandez via Gcc-patches
gcc/ChangeLog:

* value-range.h (Value_Range::operator=): New.
---
 gcc/value-range.h | 25 +
 1 file changed, 25 insertions(+)

diff --git a/gcc/value-range.h b/gcc/value-range.h
index ab982d18402..af81d6080da 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -523,6 +523,7 @@ public:
   Value_Range (const Value_Range &);
   void set_type (tree type);
   vrange& operator= (const vrange &);
+  Value_Range& operator= (const Value_Range &);
   bool operator== (const Value_Range ) const;
   bool operator!= (const Value_Range ) const;
   operator vrange &();
@@ -642,6 +643,30 @@ Value_Range::operator= (const vrange )
   return *m_vrange;
 }
 
+inline Value_Range &
+Value_Range::operator= (const Value_Range )
+{
+  if (r.m_vrange == _irange)
+{
+  m_irange = r.m_irange;
+  m_vrange = _irange;
+}
+  else if (r.m_vrange == _frange)
+{
+  m_frange = r.m_frange;
+  m_vrange = _frange;
+}
+  else if (r.m_vrange == _unsupported)
+{
+  m_unsupported = r.m_unsupported;
+  m_vrange = _unsupported;
+}
+  else
+gcc_unreachable ();
+
+  return *this;
+}
+
 inline bool
 Value_Range::operator== (const Value_Range ) const
 {
-- 
2.40.0



[COMMITTED] Provide support for copying unsupported ranges.

2023-05-17 Thread Aldy Hernandez via Gcc-patches
The unsupported_range class is provided for completness sake.  It is a
way to set VARYING/UNDEFINED ranges for unsupported ranges (currently
anything not float, integer, or pointer).  You can't do anything with
them, except set_varying, and set_undefined.  We will trap on any
other operation.

This patch provides a way to copy them, just in case they creep in.
This could happen in IPA under certain circumstances.

gcc/ChangeLog:

* value-range.cc (vrange::operator=): Add a stub to copy
unsupported ranges.
* value-range.h (is_a ): New.
(Value_Range::operator=): Support copying unsupported ranges.
---
 gcc/value-range.cc |  5 -
 gcc/value-range.h  | 12 
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 93c44a68365..45b1e655967 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -203,7 +203,10 @@ vrange::operator= (const vrange )
   else if (is_a  (src))
 as_a  (*this) = as_a  (src);
   else
-gcc_unreachable ();
+{
+  gcc_checking_assert (is_a  (src));
+  m_kind = src.m_kind;
+}
   return *this;
 }
 
diff --git a/gcc/value-range.h b/gcc/value-range.h
index 0da2a42764a..ab982d18402 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -460,6 +460,13 @@ is_a  (vrange )
   return v.m_discriminator == VR_FRANGE;
 }
 
+template <>
+inline bool
+is_a  (vrange )
+{
+  return v.m_discriminator == VR_UNKNOWN;
+}
+
 // For resizable ranges, resize the range up to HARD_MAX_RANGES if the
 // NEEDED pairs is greater than the current capacity of the range.
 
@@ -624,6 +631,11 @@ Value_Range::operator= (const vrange )
   m_frange = as_a  (r);
   m_vrange = _frange;
 }
+  else if (is_a  (r))
+{
+  m_unsupported = as_a  (r);
+  m_vrange = _unsupported;
+}
   else
 gcc_unreachable ();
 
-- 
2.40.0



Re: [PATCH] Add support for vrange streaming.

2023-05-17 Thread Aldy Hernandez via Gcc-patches
I'm pushing this in preparation for further changes in this area later today.

Aldy

On Thu, Apr 27, 2023 at 1:36 PM Aldy Hernandez  wrote:
>
> Thanks. I will put it aside until I start posting the IPA patches.
>
> Aldy
>
> On Thu, Apr 27, 2023, 13:02 Richard Biener  wrote:
>>
>> On Tue, Apr 18, 2023 at 2:48 PM Aldy Hernandez  wrote:
>> >
>> >
>> >
>> > On 4/18/23 11:06, Aldy Hernandez wrote:
>> > > I think it's time for the ranger folk to start owning range streaming
>> > > instead of passes (IPA, etc) doing their own thing.  I have plans for
>> > > overhauling the IPA code later this cycle to support generic ranges,
>> > > and I'd like to start cleaning up the streaming and hashing interface.
>> > >
>> > > This patch adds generic streaming support for vrange.
>> > >
>> > > I'd appreciate another set of eyes.
>> > >
>> > > Thoughts?
>> >
>> > We recently added support for querying and storing an frange's NAN
>> > without the need to be friends with the class.
>> >
>> > Adjusted patch in testing...
>>
>> I think this is reasonable once you find use for it.
>>
>> Thanks,
>> Richard.
>>
>> > Aldy
>>



Re: [PATCH] Add auto-resizing capability to irange's [PR109695]

2023-05-16 Thread Aldy Hernandez via Gcc-patches



On 5/15/23 20:14, Aldy Hernandez wrote:

On 5/15/23 17:07, Aldy Hernandez wrote:



On 5/15/23 12:42, Jakub Jelinek wrote:

On Mon, May 15, 2023 at 12:35:23PM +0200, Aldy Hernandez wrote:

gcc/ChangeLog:

PR tree-optimization/109695
* value-range.cc (irange::operator=): Resize range.
(irange::union_): Same.
(irange::intersect): Same.
(irange::invert): Same.
(int_range_max): Default to 3 sub-ranges and resize as needed.
* value-range.h (irange::maybe_resize): New.
(~int_range): New.
(int_range::int_range): Adjust for resizing.
(int_range::operator=): Same.


LGTM.

One question is if we shouldn't do it for GCC13/GCC12 as well, perhaps
changing it to some larger number than 3 when the members aren't 
wide_ints

in there but just trees.  Sure, in 13/12 the problem is 10x less severe
than in current trunk, but still we have some cases where we run out of
stack because of it on some hosts.


Sure, but that would require messing around with the gt_* GTY 
functions, and making sure we're allocating the trees from a sensible 
place, etc etc.  I'm less confident in my ability to mess with GTY 
stuff this late in the game.


Hmmm, maybe backporting this isn't too bad.  The only time we'd have a 
chunk on the heap is for int_range_max, which will never live in GC 
space.  So I don't think we need to worry about GC at all.


Although, legacy mode in GCC13 does get in a the way a bit.  Sigh.


I've adapted the patch to GCC13 and tested it on x86-64 Linux.  Please 
look over the new[] I do for trees to make sure I did things right.


int_range_max on GCC13 is currently 4112 bytes.  Here are the numbers 
for various defaults:


< 2> =  64 bytes, 3.02% for VRP.
< 3> =  80 bytes, 2.67% for VRP.
< 8> = 160 bytes, 2.46% for VRP.
<16> = 288 bytes, 2.40% for VRP.

Note that we don't have any runway on GCC13, so this would be a net loss 
in performance for VRP.  Threading shows about half as much of a drop 
than VRP.  Overall compilation is within 0.2%, so not noticeable.


I'm surprised 2 sub-ranges doesn't incur a  bigger penalty, but 3 seems 
to be the happy medium.  Anything more than that, and there's no difference.


The patch defaults to 3 sub-ranges.  I must say, 80 bytes looks mighty 
nice.  It's up to you what to do with the patch.  I'm chicken shit at 
heart and hate touching release compilers :).


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

Backport the following from trunk.

	Note that the patch has been adapted to trees.

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


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


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

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

For example:

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

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

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

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

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

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

Re: [PATCH] Add auto-resizing capability to irange's [PR109695]

2023-05-15 Thread Aldy Hernandez via Gcc-patches

On 5/15/23 17:07, Aldy Hernandez wrote:



On 5/15/23 12:42, Jakub Jelinek wrote:

On Mon, May 15, 2023 at 12:35:23PM +0200, Aldy Hernandez wrote:

gcc/ChangeLog:

PR tree-optimization/109695
* value-range.cc (irange::operator=): Resize range.
(irange::union_): Same.
(irange::intersect): Same.
(irange::invert): Same.
(int_range_max): Default to 3 sub-ranges and resize as needed.
* value-range.h (irange::maybe_resize): New.
(~int_range): New.
(int_range::int_range): Adjust for resizing.
(int_range::operator=): Same.


LGTM.

One question is if we shouldn't do it for GCC13/GCC12 as well, perhaps
changing it to some larger number than 3 when the members aren't 
wide_ints

in there but just trees.  Sure, in 13/12 the problem is 10x less severe
than in current trunk, but still we have some cases where we run out of
stack because of it on some hosts.


Sure, but that would require messing around with the gt_* GTY functions, 
and making sure we're allocating the trees from a sensible place, etc 
etc.  I'm less confident in my ability to mess with GTY stuff this late 
in the game.


Hmmm, maybe backporting this isn't too bad.  The only time we'd have a 
chunk on the heap is for int_range_max, which will never live in GC 
space.  So I don't think we need to worry about GC at all.


Although, legacy mode in GCC13 does get in a the way a bit.  Sigh.

And unrealted, but speaking of GC... we should remove all GTY markers 
from vrange.  It should never live in GC.  That's why we have 
vrange_storage for, and that is what we put in the tree_ssa_name.


 /* Value range information.  */
  union ssa_name_info_type {
/* Range and aliasing info for pointers.  */
struct GTY ((tag ("0"))) ptr_info_def *ptr_info;
/* Range info for everything else.  */
struct GTY ((tag ("1"))) vrange_storage * range_info;
  } GTY ((desc ("%1.typed.type ?" \
"!POINTER_TYPE_P (TREE_TYPE ((tree)&%1)) : 2"))) info;

That should have been the only use of range GC stuff, but alas another 
one crept in... IPA:


struct GTY (()) ipa_jump_func
{
...
  /* Information about value range, containing valid data only when 
vr_known is

 true.  The pointed to structure is shared betweed different jump
 functions.  Use ipa_set_jfunc_vr to set this field.  */
  value_range *m_vr;
...
};

This means that we can't nuke int_range and default to an always 
resizable range just yet, because we'll end up with the value_range in 
GC memory, and resizable part in the heap.


That m_vr pointer should be a pointer to vrange_storage.  Meh...I'm 
bumping against my IPA work yet again.  I think it's time to start 
dusting off those patches.


Aldy



Re: [COMMITTED] Remove deprecated range_fold_{unary, binary}_expr uses from ipa-*.

2023-05-15 Thread Aldy Hernandez via Gcc-patches




On 5/5/23 17:10, Martin Jambor wrote:

Hello,

On Wed, Apr 26 2023, Aldy Hernandez via Gcc-patches wrote:

gcc/ChangeLog:

* ipa-cp.cc (ipa_vr_operation_and_type_effects): Convert to ranger API.
(ipa_value_range_from_jfunc): Same.
(propagate_vr_across_jump_function): Same.
* ipa-fnsummary.cc (evaluate_conditions_for_known_args): Same.
* ipa-prop.cc (ipa_compute_jump_functions_for_edge): Same.
* vr-values.cc (bounds_of_var_in_loop): Same.


thanks for taking care of the value range uses in IPA.


---
  gcc/ipa-cp.cc| 28 +--
  gcc/ipa-fnsummary.cc | 45 
  gcc/ipa-prop.cc  |  5 ++---
  gcc/vr-values.cc |  6 --
  4 files changed, 57 insertions(+), 27 deletions(-)

diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
index 65c49558b58..673c40b 100644
--- a/gcc/ipa-cp.cc
+++ b/gcc/ipa-cp.cc
@@ -128,6 +128,7 @@ along with GCC; see the file COPYING3.  If not see
  #include "attribs.h"
  #include "dbgcnt.h"
  #include "symtab-clones.h"
+#include "gimple-range.h"
  
  template  class ipcp_value;
  
@@ -1900,10 +1901,15 @@ ipa_vr_operation_and_type_effects (value_range *dst_vr,

   enum tree_code operation,
   tree dst_type, tree src_type)
  {
-  range_fold_unary_expr (dst_vr, operation, dst_type, src_vr, src_type);
-  if (dst_vr->varying_p () || dst_vr->undefined_p ())
+  if (!irange::supports_p (dst_type) || !irange::supports_p (src_type))
  return false;
-  return true;
+
+  range_op_handler handler (operation, dst_type);


Would it be possible to document the range_op_handler class somewhat?


+  return (handler
+ && handler.fold_range (*dst_vr, dst_type,
+*src_vr, value_range (dst_type))
+ && !dst_vr->varying_p ()
+ && !dst_vr->undefined_p ());


It looks important but the class is not documented at all.  Although the
use of fold_range is probably hopefully mostly clear from its uses in
this patch, the meaning of the return value of this method and what
other methods do is less obvious.

For example, I am curious why (not in this patch, but in the code as it
is now in the repo), uses of fold_range seem to be always preceeded with
a check for supports_type_p, even though the type is then also fed into
fold_range itself.  Does the return value of fold_range mean something
slightly different from "could not deduce anything?"


Oh, I see what you mean.

Take for instance this bit in ipa-cp:

  if (!irange::supports_p (dst_type) || !irange::supports_p (src_type))
return false;

  range_op_handler handler (operation, dst_type);
  return (handler
  && handler.fold_range (*dst_vr, dst_type,
 *src_vr, value_range (dst_type))
  && !dst_vr->varying_p ()
  && !dst_vr->undefined_p ());

range_op_handler::fold_range() takes a type agnostic vrange (from which 
irange inherits).  If you pass it an irange, but the type is say a 
float, you'll get an ICE downstream.


Ranger itself is type agnostic and takes a vrange almost everywhere. 
It's up to the user to make sure the the range type and the type of the 
operation matches.


Eventually we should convert all those value_range arguments in IPA to 
vrange and have it work in a type agnostic manner.  I have patches for 
this, but I still have to flush out all this preliminary stuff :).


Aldy



Re: [PATCH] Add auto-resizing capability to irange's [PR109695]

2023-05-15 Thread Aldy Hernandez via Gcc-patches
On Mon, May 15, 2023 at 5:03 PM Aldy Hernandez  wrote:
>
>
>
> On 5/15/23 13:08, Richard Biener wrote:
> > On Mon, May 15, 2023 at 12:35 PM Aldy Hernandez  wrote:
> >>
> >> 
> >> We can now have int_range for automatically
> >> resizable ranges.  int_range_max is now int_range<3, true>
> >> for a 69X reduction in size from current trunk, and 6.9X reduction from
> >> GCC12.  This incurs a 5% performance penalty for VRP that is more than
> >> covered by our > 13% improvements recently.
> >> 
> >>
> >> int_range_max is the temporary range object we use in the ranger for
> >> integers.  With the conversion to wide_int, this structure bloated up
> >> significantly because wide_ints are huge (80 bytes a piece) and are
> >> about 10 times as big as a plain tree.  Since the temporary object
> >> requires 255 sub-ranges, that's 255 * 80 * 2, plus the control word.
> >> This means the structure grew from 4112 bytes to 40912 bytes.
> >>
> >> This patch adds the ability to resize ranges as needed, defaulting to
> >> no resizing, while int_range_max now defaults to 3 sub-ranges (instead
> >> of 255) and grows to 255 when the range being calculated does not fit.
> >>
> >> For example:
> >>
> >> int_range<1> foo;   // 1 sub-range with no resizing.
> >> int_range<5> foo;   // 5 sub-ranges with no resizing.
> >> int_range<5, true> foo; // 5 sub-ranges with resizing.
> >>
> >> I ran some tests and found that 3 sub-ranges cover 99% of cases, so
> >> I've set the int_range_max default to that:
> >>
> >>  typedef int_range<3, /*RESIZABLE=*/true> int_range_max;
> >>
> >> We don't bother growing incrementally, since the default covers most
> >> cases and we have a 255 hard-limit.  This hard limit could be reduced
> >> to 128, since my tests never saw a range needing more than 124, but we
> >> could do that as a follow-up if needed.
> >>
> >> With 3-subranges, int_range_max is now 592 bytes versus 40912 for
> >> trunk, and versus 4112 bytes for GCC12!  The penalty is 5.04% for VRP
> >> and 3.02% for threading, with no noticeable change in overall
> >> compilation (0.27%).  This is more than covered by our 13.26%
> >> improvements for the legacy removal + wide_int conversion.
> >
> > Thanks for doing this.
> >
> >> I think this approach is a good alternative, while providing us with
> >> flexibility going forward.  For example, we could try defaulting to a
> >> 8 sub-ranges for a noticeable improvement in VRP.  We could also use
> >> large sub-ranges for switch analysis to avoid resizing.
> >>
> >> Another approach I tried was always resizing.  With this, we could
> >> drop the whole int_range nonsense, and have irange just hold a
> >> resizable range.  This simplified things, but incurred a 7% penalty on
> >> ipa_cp.  This was hard to pinpoint, and I'm not entirely convinced
> >> this wasn't some artifact of valgrind.  However, until we're sure,
> >> let's avoid massive changes, especially since IPA changes are coming
> >> up.
> >>
> >> For the curious, a particular hot spot for IPA in this area was:
> >>
> >> ipcp_vr_lattice::meet_with_1 (const value_range *other_vr)
> >> {
> >> ...
> >> ...
> >>value_range save (m_vr);
> >>m_vr.union_ (*other_vr);
> >>return m_vr != save;
> >> }
> >>
> >> The problem isn't the resizing (since we do that at most once) but the
> >> fact that for some functions with lots of callers we end up a huge
> >> range that gets copied and compared for every meet operation.  Maybe
> >> the IPA algorithm could be adjusted somehow??.
> >
> > Well, the above just wants to know whether the union_ operation changed
> > the range.  I suppose that would be an interesting (and easy to compute?)
> > secondary output of union_ and it seems it already computes that (but
> > maybe not correctly?).  So I suggest to change the above to
>
> union_ returns a value specifically for that, which Andrew uses for
> cache optimization.  For that matter, your suggestion was my first
> approach, but I quickly found out we were being overly pessimistic in
> some cases, and I was too lazy to figure out why.
>
> >
> >bool res;
> >if (flag_checking)
> > {
> >value_range save (m_vr);
> >res = m_vr.union_ (*other_vr);
> >gcc_assert (res == (m_vr != save));
> > }
> >   else
> >  res = m_vr.union (*other_vr);
> >   return res;
>
> With your suggested sanity check I chased the problem to a minor
> inconsistency when unioning nonzero masks.  The issue wasn't a bug, just
> a pessimization.  I'm attaching a patch that corrects the oversight
> (well, not oversight, everything was more expensive with trees)... It
> yields a 6.89% improvement to the ipa-cp pass!!!  Thanks.
>
> I'll push it if it passes tests.

Tests passed.  Pushed patch.

I've also pushed the original patch in this email.  We can address
anything else as a follow-up.

Thanks for everyone's feedback.
Aldy



Re: [PATCH] Add auto-resizing capability to irange's [PR109695]

2023-05-15 Thread Aldy Hernandez via Gcc-patches




On 5/15/23 12:42, Jakub Jelinek wrote:

On Mon, May 15, 2023 at 12:35:23PM +0200, Aldy Hernandez wrote:

gcc/ChangeLog:

PR tree-optimization/109695
* value-range.cc (irange::operator=): Resize range.
(irange::union_): Same.
(irange::intersect): Same.
(irange::invert): Same.
(int_range_max): Default to 3 sub-ranges and resize as needed.
* value-range.h (irange::maybe_resize): New.
(~int_range): New.
(int_range::int_range): Adjust for resizing.
(int_range::operator=): Same.


LGTM.

One question is if we shouldn't do it for GCC13/GCC12 as well, perhaps
changing it to some larger number than 3 when the members aren't wide_ints
in there but just trees.  Sure, in 13/12 the problem is 10x less severe
than in current trunk, but still we have some cases where we run out of
stack because of it on some hosts.


Sure, but that would require messing around with the gt_* GTY functions, 
and making sure we're allocating the trees from a sensible place, etc 
etc.  I'm less confident in my ability to mess with GTY stuff this late 
in the game.


Thoughts?
Aldy



Re: [PATCH] Add auto-resizing capability to irange's [PR109695]

2023-05-15 Thread Aldy Hernandez via Gcc-patches



On 5/15/23 13:08, Richard Biener wrote:

On Mon, May 15, 2023 at 12:35 PM Aldy Hernandez  wrote:



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


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

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

For example:

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

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

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

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

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


Thanks for doing this.


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

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

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

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

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


Well, the above just wants to know whether the union_ operation changed
the range.  I suppose that would be an interesting (and easy to compute?)
secondary output of union_ and it seems it already computes that (but
maybe not correctly?).  So I suggest to change the above to


union_ returns a value specifically for that, which Andrew uses for 
cache optimization.  For that matter, your suggestion was my first 
approach, but I quickly found out we were being overly pessimistic in 
some cases, and I was too lazy to figure out why.




   bool res;
   if (flag_checking)
{
   value_range save (m_vr);
   res = m_vr.union_ (*other_vr);
   gcc_assert (res == (m_vr != save));
}
  else
 res = m_vr.union (*other_vr);
  return res;


With your suggested sanity check I chased the problem to a minor 
inconsistency when unioning nonzero masks.  The issue wasn't a bug, just 
a pessimization.  I'm attaching a patch that corrects the oversight 
(well, not oversight, everything was more expensive with trees)... It 
yields a 6.89% improvement to the ipa-cp pass!!!  Thanks.


I'll push it if it passes tests.

BTW, without the annoying IPA-cp performance regression, this paves the 
way for nuking int_range in favor of just irange, and have everything 
resize as needed.  I'll wait for Andrew to chime in when he returns from 
PTO, since we may want to leave int_range around since it does 
provide flexibility (at the expensive of fugly looking declarations).


AldyFrom 6a7354d3494665d46f8cbfc71c58f784c02142ff Mon Sep 17 00:00:00 2001
From: Aldy Hernandez 
Date: Mon, 15 May 2023 15:10:11 +0200
Subject: [PATCH] Only return changed=true in union_nonzero when appropriate.

irange::union_ was being overly pessimistic in its return value.  It
was returning false when the nonzero mask was possibly the same.

The reason for this is because the 

Re: [PATCH] Add auto-resizing capability to irange's [PR109695]

2023-05-15 Thread Aldy Hernandez via Gcc-patches




On 5/15/23 16:24, Bernhard Reutner-Fischer wrote:

On Mon, 15 May 2023 12:35:23 +0200
Aldy Hernandez via Gcc-patches  wrote:


+// For resizable ranges, resize the range up to HARD_MAX_RANGES if the
+// NEEDED pairs is greater than the current capacity of the range.
+
+inline void
+irange::maybe_resize (int needed)
+{
+  if (!m_resizable || m_max_ranges == HARD_MAX_RANGES)
+return;
+
+  if (needed > m_max_ranges)
+{
+  m_max_ranges = HARD_MAX_RANGES;
+  wide_int *newmem = new wide_int[m_max_ranges * 2];
+  memcpy (newmem, m_base, sizeof (wide_int) * num_pairs () * 2);
+  m_base = newmem;


Please excuse my ignorance, but where's the old m_base freed? I think
the assignment above does not call the destructor, or does it?


The old m_base is never freed because it points to m_ranges, a static 
array in int_range:


template
class GTY((user)) int_range : public irange
{
...
...
private:
  wide_int m_ranges[N*2];
};

Aldy



[PATCH] Add auto-resizing capability to irange's [PR109695]

2023-05-15 Thread Aldy Hernandez via Gcc-patches

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


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

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

For example:

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

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

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

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

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

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

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

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

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

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

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

I'll hold off a day or two, as I'd appreciate feedback here.

gcc/ChangeLog:

PR tree-optimization/109695
* value-range.cc (irange::operator=): Resize range.
(irange::union_): Same.
(irange::intersect): Same.
(irange::invert): Same.
(int_range_max): Default to 3 sub-ranges and resize as needed.
* value-range.h (irange::maybe_resize): New.
(~int_range): New.
(int_range::int_range): Adjust for resizing.
(int_range::operator=): Same.
---
 gcc/value-range.cc | 14 +++
 gcc/value-range.h  | 98 --
 2 files changed, 82 insertions(+), 30 deletions(-)

diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index def9299dc0e..cea4ff59254 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -901,6 +901,9 @@ frange::set_nonnegative (tree type)
 irange &
 irange::operator= (const irange )
 {
+  int needed = src.num_pairs ();
+  maybe_resize (needed);
+
   unsigned x;
   unsigned lim = src.m_num_ranges;
   if (lim > m_max_ranges)
@@ -1340,6 +1343,7 @@ irange::union_ (const vrange )
   // Now it simply needs to be copied, and if there are too many
   // ranges, merge some.  We wont do any analysis as to what the
   // "best" merges are, simply combine the final ranges into one.
+  maybe_resize (i / 2);
   if (i > m_max_ranges * 2)
 {
   res[m_max_ranges * 2 - 1] = res[i - 1];
@@ -1439,6 +1443,11 @@ irange::intersect (const vrange )
   if (r.irange_contains_p (*this))
 return intersect_nonzero_bits (r);
 
+  // ?? We could probably come up with something smarter than the
+  // worst case scenario here.
+  int needed = num_pairs () + r.num_pairs ();
+  maybe_resize (needed);
+

Re: [COMMITTED] Remove deprecated range_fold_{unary, binary}_expr uses from ipa-*.

2023-05-11 Thread Aldy Hernandez via Gcc-patches




On 5/5/23 17:10, Martin Jambor wrote:

Hello,

On Wed, Apr 26 2023, Aldy Hernandez via Gcc-patches wrote:

gcc/ChangeLog:

* ipa-cp.cc (ipa_vr_operation_and_type_effects): Convert to ranger API.
(ipa_value_range_from_jfunc): Same.
(propagate_vr_across_jump_function): Same.
* ipa-fnsummary.cc (evaluate_conditions_for_known_args): Same.
* ipa-prop.cc (ipa_compute_jump_functions_for_edge): Same.
* vr-values.cc (bounds_of_var_in_loop): Same.


thanks for taking care of the value range uses in IPA.


---
  gcc/ipa-cp.cc| 28 +--
  gcc/ipa-fnsummary.cc | 45 
  gcc/ipa-prop.cc  |  5 ++---
  gcc/vr-values.cc |  6 --
  4 files changed, 57 insertions(+), 27 deletions(-)

diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
index 65c49558b58..673c40b 100644
--- a/gcc/ipa-cp.cc
+++ b/gcc/ipa-cp.cc
@@ -128,6 +128,7 @@ along with GCC; see the file COPYING3.  If not see
  #include "attribs.h"
  #include "dbgcnt.h"
  #include "symtab-clones.h"
+#include "gimple-range.h"
  
  template  class ipcp_value;
  
@@ -1900,10 +1901,15 @@ ipa_vr_operation_and_type_effects (value_range *dst_vr,

   enum tree_code operation,
   tree dst_type, tree src_type)
  {
-  range_fold_unary_expr (dst_vr, operation, dst_type, src_vr, src_type);
-  if (dst_vr->varying_p () || dst_vr->undefined_p ())
+  if (!irange::supports_p (dst_type) || !irange::supports_p (src_type))
  return false;
-  return true;
+
+  range_op_handler handler (operation, dst_type);


Would it be possible to document the range_op_handler class somewhat?


Sorry for the late response, but you're totally right.  We're in dire 
need of documentation here.  I had planned to work on comments and 
actual documentation much later this cycle, but I may need to bump that 
up in priority.





+  return (handler
+ && handler.fold_range (*dst_vr, dst_type,
+*src_vr, value_range (dst_type))
+ && !dst_vr->varying_p ()
+ && !dst_vr->undefined_p ());


It looks important but the class is not documented at all.  Although the
use of fold_range is probably hopefully mostly clear from its uses in
this patch, the meaning of the return value of this method and what
other methods do is less obvious.

For example, I am curious why (not in this patch, but in the code as it
is now in the repo), uses of fold_range seem to be always preceeded with
a check for supports_type_p, even though the type is then also fed into
fold_range itself.  Does the return value of fold_range mean something
slightly different from "could not deduce anything?"


Returning false from fold_range() is a shortcut for I don't know 
anything, which will be treated as VARYING upstream.


The other methods also need documentation.  The most important ones are 
documented in range-op.h:


// This class is implemented for each kind of operator supported by
// the range generator.  It serves various purposes.

particularly op1_range, and op2_range which can be confusing.  But yes, 
we need to revisit this, as those comments are pretty out of date.


Aldy



Re: [PATCH] Remove type from vrange_storage::equal_p.

2023-05-05 Thread Aldy Hernandez via Gcc-patches

On 5/3/23 13:41, Aldy Hernandez wrote:

[Andrew, since you suggested this, is this what you had in mind?].


Pushed.  You can comment when you're back from vacation :).

Aldy


The equal_p method in vrange_storage is only used to compare ranges
that are the same type.  No sense passing the type if it can be
determined from the range being compared.

gcc/ChangeLog:

* gimple-range-cache.cc (sbr_sparse_bitmap::set_bb_range): Do not
pass type to vrange_storage::equal_p.
* value-range-storage.cc (vrange_storage::equal_p): Remove type.
(irange_storage::equal_p): Same.
(frange_storage::equal_p): Same.
* value-range-storage.h (class frange_storage): Same.
---
  gcc/gimple-range-cache.cc  |  2 +-
  gcc/value-range-storage.cc | 28 +++-
  gcc/value-range-storage.h  |  6 +++---
  3 files changed, 15 insertions(+), 21 deletions(-)

diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index 92622fc5000..07c69ef858a 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -320,7 +320,7 @@ sbr_sparse_bitmap::set_bb_range (const_basic_block bb, const 
vrange )
  
// Loop thru the values to see if R is already present.

for (int x = 0; x < SBR_NUM; x++)
-if (!m_range[x] || m_range[x]->equal_p (r, m_type))
+if (!m_range[x] || m_range[x]->equal_p (r))
{
if (!m_range[x])
  m_range[x] = m_range_allocator->clone (r);
diff --git a/gcc/value-range-storage.cc b/gcc/value-range-storage.cc
index 7d2de5e8384..1e06a7acc8d 100644
--- a/gcc/value-range-storage.cc
+++ b/gcc/value-range-storage.cc
@@ -206,20 +206,22 @@ vrange_storage::fits_p (const vrange ) const
return false;
  }
  
-// Return TRUE if the range in storage is equal to R.

+// Return TRUE if the range in storage is equal to R.  It is the
+// caller's responsibility to verify that the type of the range in
+// storage matches that of R.
  
  bool

-vrange_storage::equal_p (const vrange , tree type) const
+vrange_storage::equal_p (const vrange ) const
  {
if (is_a  (r))
  {
const irange_storage *s = static_cast  (this);
-  return s->equal_p (as_a  (r), type);
+  return s->equal_p (as_a  (r));
  }
if (is_a  (r))
  {
const frange_storage *s = static_cast  (this);
-  return s->equal_p (as_a  (r), type);
+  return s->equal_p (as_a  (r));
  }
gcc_unreachable ();
  }
@@ -375,21 +377,17 @@ irange_storage::get_irange (irange , tree type) const
  }
  
  bool

-irange_storage::equal_p (const irange , tree type) const
+irange_storage::equal_p (const irange ) const
  {
if (m_kind == VR_UNDEFINED || r.undefined_p ())
  return m_kind == r.m_kind;
if (m_kind == VR_VARYING || r.varying_p ())
-return m_kind == r.m_kind && types_compatible_p (r.type (), type);
-
-  tree rtype = r.type ();
-  if (!types_compatible_p (rtype, type))
-return false;
+return m_kind == r.m_kind;
  
// ?? We could make this faster by doing the comparison in place,

// without going through get_irange.
int_range_max tmp;
-  get_irange (tmp, rtype);
+  get_irange (tmp, r.type ());
return tmp == r;
  }
  
@@ -526,17 +524,13 @@ frange_storage::get_frange (frange , tree type) const

  }
  
  bool

-frange_storage::equal_p (const frange , tree type) const
+frange_storage::equal_p (const frange ) const
  {
if (r.undefined_p ())
  return m_kind == VR_UNDEFINED;
  
-  tree rtype = type;

-  if (!types_compatible_p (rtype, type))
-return false;
-
frange tmp;
-  get_frange (tmp, rtype);
+  get_frange (tmp, r.type ());
return tmp == r;
  }
  
diff --git a/gcc/value-range-storage.h b/gcc/value-range-storage.h

index 4ec0da73059..f25489f32c1 100644
--- a/gcc/value-range-storage.h
+++ b/gcc/value-range-storage.h
@@ -54,7 +54,7 @@ public:
void get_vrange (vrange , tree type) const;
void set_vrange (const vrange );
bool fits_p (const vrange ) const;
-  bool equal_p (const vrange , tree type) const;
+  bool equal_p (const vrange ) const;
  protected:
// Stack initialization disallowed.
vrange_storage () { }
@@ -68,7 +68,7 @@ public:
static irange_storage *alloc (vrange_internal_alloc &, const irange &);
void set_irange (const irange );
void get_irange (irange , tree type) const;
-  bool equal_p (const irange , tree type) const;
+  bool equal_p (const irange ) const;
bool fits_p (const irange ) const;
void dump () const;
  private:
@@ -111,7 +111,7 @@ class frange_storage : public vrange_storage
static frange_storage *alloc (vrange_internal_alloc &, const frange );
void set_frange (const frange );
void get_frange (frange , tree type) const;
-  bool equal_p (const frange , tree type) const;
+  bool equal_p (const frange ) const;
bool fits_p (const frange &) const;
   private:
frange_storage (const frange ) { set_frange (r); }




Re: [PATCH] gimple-range-op: Improve handling of sin/cos ranges

2023-05-05 Thread Aldy Hernandez via Gcc-patches




On 5/5/23 22:53, Jakub Jelinek wrote:

Hi!

Similarly to the earlier sqrt patch, this patch attempts to improve
sin/cos ranges.  As the functions are periodic, for the reverse range
there is not much we can do (but I've discovered I forgot to take
into account the boundary ulps for the discovery of impossible result
ranges).  For fold_range, we can do something only if the range is
narrow enough (narrower than 2*pi).  The patch computes the value of
the functions (taking ulps into account) and also computes the derivative
to find out if the function is growing or declining on the boundaries and
from that it figures out if the result range should be
[min (fn (lb), fn (ub)), max (fn (lb), fn (ub))] or if it needs to be
extended to 1 (actually using +Inf) and/or -1 (actually using -Inf) because
there must be a local minimum and/or maximum in the range.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?


It's getting to the point where I think my reviews are getting less 
useful for you.  The mathematical bits are beyond my area of expertise 
and I'm just limiting myself to commenting on general style in range-op, 
etc.


I have no problem with you going ahead with this patch, but it may be 
beneficial to get someone else's opinion on the math bits.  Up to you. 
I don't want to impede your progress here.


Thanks for your work in this area.

Aldy



2023-05-05  Jakub Jelinek  

* real.h (dconst_pi): Define.
(dconst_e_ptr): Formatting fix.
(dconst_pi_ptr): Declare.
* real.cc (dconst_pi_ptr): New function.
* gimple-range-op.cc (cfn_sincos::fold_range): Intersect the generic
boundaries range with range computed from sin/cos of the particular
bounds if the argument range is shorter than 2*pi.
(cfn_sincos::op1_range): Take bulps into account when determining
which result ranges are always invalid or behave like known NAN.

* gcc.dg/tree-ssa/range-sincos-2.c: New test.

--- gcc/real.h.jj   2023-04-19 09:33:59.434350121 +0200
+++ gcc/real.h  2023-05-05 16:36:35.606611170 +0200
@@ -480,9 +480,13 @@ extern REAL_VALUE_TYPE dconstninf;
  #define dconst_sixth() (*dconst_sixth_ptr ())
  #define dconst_ninth() (*dconst_ninth_ptr ())
  #define dconst_sqrt2() (*dconst_sqrt2_ptr ())
+#define dconst_pi() (*dconst_pi_ptr ())
  
  /* Function to return the real value special constant 'e'.  */

-extern const REAL_VALUE_TYPE * dconst_e_ptr (void);
+extern const REAL_VALUE_TYPE *dconst_e_ptr (void);
+
+/* Function to return the real value special constant 'pi'.  */
+extern const REAL_VALUE_TYPE *dconst_pi_ptr (void);
  
  /* Returns a cached REAL_VALUE_TYPE corresponding to 1/n, for various n.  */

  extern const REAL_VALUE_TYPE *dconst_third_ptr (void);
--- gcc/real.cc.jj  2023-04-20 09:36:09.066376175 +0200
+++ gcc/real.cc 2023-05-05 16:39:25.244201299 +0200
@@ -2475,6 +2475,26 @@ dconst_e_ptr (void)
return 
  }
  
+/* Returns the special REAL_VALUE_TYPE corresponding to 'pi'.  */

+
+const REAL_VALUE_TYPE *
+dconst_pi_ptr (void)
+{
+  static REAL_VALUE_TYPE value;
+
+  /* Initialize mathematical constants for constant folding builtins.
+ These constants need to be given to at least 160 bits precision.  */
+  if (value.cl == rvc_zero)
+{
+  auto_mpfr m (SIGNIFICAND_BITS);
+  mpfr_set_si (m, -1, MPFR_RNDN);
+  mpfr_acos (m, m, MPFR_RNDN);
+  real_from_mpfr (, m, NULL_TREE, MPFR_RNDN);
+
+}
+  return 
+}
+
  /* Returns a cached REAL_VALUE_TYPE corresponding to 1/n, for various n.  */
  
  #define CACHED_FRACTION(NAME, N)	\

--- gcc/gimple-range-op.cc.jj   2023-05-05 16:02:48.174419009 +0200
+++ gcc/gimple-range-op.cc  2023-05-05 19:44:27.292304968 +0200
@@ -633,6 +633,98 @@ public:
}
  if (!lh.maybe_isnan () && !lh.maybe_isinf ())
r.clear_nan ();
+
+unsigned ulps
+  = targetm.libm_function_max_error (m_cfn, TYPE_MODE (type), false);
+if (ulps == ~0U)
+  return true;
+REAL_VALUE_TYPE lb = lh.lower_bound ();
+REAL_VALUE_TYPE ub = lh.upper_bound ();
+REAL_VALUE_TYPE diff;
+real_arithmetic (, MINUS_EXPR, , );
+if (!real_isfinite ())
+  return true;
+REAL_VALUE_TYPE pi = dconst_pi ();
+REAL_VALUE_TYPE pix2;
+real_arithmetic (, PLUS_EXPR, , );
+// We can only try to narrow the range further if ub-lb < 2*pi.
+if (!real_less (, ))
+  return true;
+REAL_VALUE_TYPE lb_lo, lb_hi, ub_lo, ub_hi;
+REAL_VALUE_TYPE lb_deriv_lo, lb_deriv_hi, ub_deriv_lo, ub_deriv_hi;
+if (!frange_mpfr_arg1 (_lo, _hi,
+  m_cfn == CFN_SIN ? mpfr_sin : mpfr_cos, lb,
+  type, ulps)
+   || !frange_mpfr_arg1 (_lo, _hi,
+ m_cfn == CFN_SIN ? mpfr_sin : mpfr_cos, ub,
+ type, ulps)
+   || !frange_mpfr_arg1 (_deriv_lo, _deriv_hi,
+ m_cfn == CFN_SIN ? mpfr_cos : mpfr_sin, lb,
+

Re: [PATCH] gimple-range-op: Improve handling of sqrt ranges

2023-05-05 Thread Aldy Hernandez via Gcc-patches
On Fri, May 5, 2023 at 11:14 AM Jakub Jelinek  wrote:
>
> On Fri, May 05, 2023 at 11:06:31AM +0200, Aldy Hernandez wrote:
> > > +/* Compute FUNC (ARG) where FUNC is a mpfr function.  If RES_LOW is 
> > > non-NULL,
> > > +   set it to low bound of possible range if the function is expected to 
> > > have
> > > +   ULPS precision and similarly if RES_HIGH is non-NULL, set it to high 
> > > bound.
> > > +   If the function returns false, the results weren't set.  */
> > > +
> > > +static bool
> > > +frange_mpfr_arg1 (REAL_VALUE_TYPE *res_low, REAL_VALUE_TYPE *res_high,
> > > + int (*func) (mpfr_ptr, mpfr_srcptr, mpfr_rnd_t),
> > > + const REAL_VALUE_TYPE , tree type, unsigned ulps)
> > > +{
> >
> > Since you're returning a range of sorts [low, high], would it be cleaner to
> > return an frange, or is always calculating low/high too expensive?  I notice
> > you avoid it when passing NULL.
>
> The point was that the caller can tell which bound it needs, low, high or
> both and we don't waste time calculating ones we don't need (especially with
> larger values of ulps).  E.g. for the sqrt case we only need one of them,
> but when I thought about the sin/cos case, I'll probably need both and
> calling the function twice would mean repeating the even more expensive mpfr
> call.
>
> > Would you mind adding a typedef for the (*func) callback above?  I always
> > find C callbacks a pain to read.
>
> I can, what I used comes from elsewhere (builtins.cc/fold-const-call.cc
> which use it like that).

It would be my preference to have a typedef in
builtins.cc/fold-const-call.cc as well, as we could clean everything
up.  But I defer to you as a global maintainer, whether we want to do
that or not.  If not, then don't bother with just cleaning up
gimple-range-op.cc.

LGTM.

Aldy



Re: [PATCH] gimple-range-op: Improve handling of sqrt ranges

2023-05-05 Thread Aldy Hernandez via Gcc-patches




On 5/5/23 10:00, Jakub Jelinek wrote:

Hi!

The previous patch just added basic intrinsic ranges for sqrt
([-0.0, +Inf] +-NAN being the general result range of the function
and [-0.0, +Inf] the general operand range if result isn't NAN etc.),
the following patch intersects those ranges with particular range
computed from argument or result's exact range with the expected
error in ulps taken into account and adds a function (frange_arithmetic
variant) which can be used by other functions as well as helper.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2023-05-05  Jakub Jelinek  

* value-range.h (frange_arithmetic): Declare.
* range-op-float.cc (frange_arithmetic): No longer static.
* gimple-range-op.cc (frange_mpfr_arg1): New function.
(cfn_sqrt::fold_range): Intersect the generic boundaries range
with range computed from sqrt of the particular bounds.
(cfn_sqrt::op1_range): Intersect the generic boundaries range
with range computed from squared particular bounds.

* gcc.dg/tree-ssa/range-sqrt-2.c: New test.

--- gcc/value-range.h.jj2023-05-04 13:34:45.140336099 +0200
+++ gcc/value-range.h   2023-05-04 16:28:18.286108178 +0200
@@ -1294,5 +1294,8 @@ frange::nan_signbit_p (bool ) co
  
  void frange_nextafter (enum machine_mode, REAL_VALUE_TYPE &,

   const REAL_VALUE_TYPE &);
+void frange_arithmetic (enum tree_code, tree, REAL_VALUE_TYPE &,
+   const REAL_VALUE_TYPE &, const REAL_VALUE_TYPE &,
+   const REAL_VALUE_TYPE &);
  
  #endif // GCC_VALUE_RANGE_H

--- gcc/range-op-float.cc.jj2023-05-04 13:34:45.139336114 +0200
+++ gcc/range-op-float.cc   2023-05-04 16:28:18.285108192 +0200
@@ -305,7 +305,7 @@ frange_nextafter (enum machine_mode mode
  // SF/DFmode (when storing into memory from the 387 stack).  Maybe
  // this is ok as well though it is just occasionally more precise. ??
  
-static void

+void
  frange_arithmetic (enum tree_code code, tree type,
   REAL_VALUE_TYPE ,
   const REAL_VALUE_TYPE ,
--- gcc/gimple-range-op.cc.jj   2023-05-04 13:34:45.139336114 +0200
+++ gcc/gimple-range-op.cc  2023-05-04 19:58:44.842606865 +0200
@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3.
  #include "value-query.h"
  #include "gimple-range.h"
  #include "attr-fnspec.h"
+#include "realmpfr.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
@@ -403,6 +404,66 @@ public:
}
  } op_cfn_copysign;
  
+/* Compute FUNC (ARG) where FUNC is a mpfr function.  If RES_LOW is non-NULL,

+   set it to low bound of possible range if the function is expected to have
+   ULPS precision and similarly if RES_HIGH is non-NULL, set it to high bound.
+   If the function returns false, the results weren't set.  */
+
+static bool
+frange_mpfr_arg1 (REAL_VALUE_TYPE *res_low, REAL_VALUE_TYPE *res_high,
+ int (*func) (mpfr_ptr, mpfr_srcptr, mpfr_rnd_t),
+ const REAL_VALUE_TYPE , tree type, unsigned ulps)
+{


Since you're returning a range of sorts [low, high], would it be cleaner 
to return an frange, or is always calculating low/high too expensive?  I 
notice you avoid it when passing NULL.


Would you mind adding a typedef for the (*func) callback above?  I 
always find C callbacks a pain to read.


Thanks.
Aldy


+  if (ulps == ~0U || !real_isfinite ())
+return false;
+  machine_mode mode = TYPE_MODE (type);
+  const real_format *format = REAL_MODE_FORMAT (mode);
+  auto_mpfr m (format->p);
+  mpfr_from_real (m, , MPFR_RNDN);
+  mpfr_clear_flags ();
+  bool inexact = func (m, m, MPFR_RNDN);
+  if (!mpfr_number_p (m) || mpfr_overflow_p () || mpfr_underflow_p ())
+return false;
+
+  REAL_VALUE_TYPE value, result;
+  real_from_mpfr (, m, format, MPFR_RNDN);
+  if (!real_isfinite ())
+return false;
+  if ((value.cl == rvc_zero) != (mpfr_zero_p (m) != 0))
+inexact = true;
+
+  real_convert (, format, );
+  if (!real_isfinite ())
+return false;
+  bool round_low = false;
+  bool round_high = false;
+  if (!ulps && flag_rounding_math)
+++ulps;
+  if (inexact || !real_identical (, ))
+{
+  if (MODE_COMPOSITE_P (mode))
+   round_low = round_high = true;
+  else
+   {
+ round_low = !real_less (, );
+ round_high = !real_less (, );
+   }
+}
+  if (res_low)
+{
+  *res_low = result;
+  for (unsigned int i = 0; i < ulps + round_low; ++i)
+   frange_nextafter (mode, *res_low, dconstninf);
+}
+  if (res_high)
+{
+  *res_high = result;
+  for (unsigned int i = 0; i < ulps + round_high; ++i)
+   frange_nextafter (mode, *res_high, dconstinf);
+}
+  return true;
+}
+
  class cfn_sqrt : public range_operator_float
  {
  public:
@@ -434,6 +495,20 @@ public:
}
  if (!lh.maybe_isnan () && 

[COMMITTED] Allow varying ranges of unknown types in irange::verify_range [PR109711]

2023-05-03 Thread Aldy Hernandez via Gcc-patches
The old legacy code allowed building ranges of unknown types so passes
like IPA could build and propagate VARYING.  For now it's easiest to
allow the old behavior, it's not like you can do anything with these
ranges except build them and copy them.

Eventually we should convert all users of set_varying() to use
supported types.  I will address this in my upcoming IPA work.

PR tree-optimization/109711

gcc/ChangeLog:

* value-range.cc (irange::verify_range): Allow types of
error_mark_node.
---
 gcc/testsuite/gcc.dg/tree-ssa/pr109711-1.c | 16 +++
 gcc/testsuite/gcc.dg/tree-ssa/pr109711-2.c | 24 ++
 gcc/value-range.cc |  7 +++
 3 files changed, 47 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr109711-1.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr109711-2.c

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr109711-1.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr109711-1.c
new file mode 100644
index 000..81777505002
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr109711-1.c
@@ -0,0 +1,16 @@
+// { dg-do compile }
+// { dg-options "-O2" }
+
+void lspf2lpc();
+
+void interpolate_lpc(int subframe_num) {
+  float weight = 0.25 * subframe_num + 1;
+  if (weight)
+lspf2lpc();
+}
+
+void qcelp_decode_frame() {
+  int i;
+  for (;; i++)
+interpolate_lpc(i);
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr109711-2.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr109711-2.c
new file mode 100644
index 000..f80bb1afec8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr109711-2.c
@@ -0,0 +1,24 @@
+// { dg-do compile }
+// { dg-options "-O2" }
+
+void lspf2lpc();
+
+int interpolate_lpc_q_0;
+
+void
+interpolate_lpc(int subframe_num) {
+  float weight;
+  if (interpolate_lpc_q_0)
+weight = subframe_num;
+  else
+weight = 1.0;
+  if (weight != 1.0)
+lspf2lpc();
+}
+
+void
+qcelp_decode_frame() {
+  int i;
+  for (;; i++)
+interpolate_lpc(i);
+}
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 655ffc2d6d4..def9299dc0e 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -1057,6 +1057,13 @@ irange::verify_range ()
   return;
 }
   gcc_checking_assert (m_num_ranges <= m_max_ranges);
+
+  // Legacy allowed these to represent VARYING for unknown types.
+  // Leave this in for now, until all users are converted.  Eventually
+  // we should abort in set_varying.
+  if (m_kind == VR_VARYING && m_type == error_mark_node)
+return;
+
   unsigned prec = TYPE_PRECISION (m_type);
   if (m_kind == VR_VARYING)
 {
-- 
2.40.0



[PATCH] Remove type from vrange_storage::equal_p.

2023-05-03 Thread Aldy Hernandez via Gcc-patches
[Andrew, since you suggested this, is this what you had in mind?].

The equal_p method in vrange_storage is only used to compare ranges
that are the same type.  No sense passing the type if it can be
determined from the range being compared.

gcc/ChangeLog:

* gimple-range-cache.cc (sbr_sparse_bitmap::set_bb_range): Do not
pass type to vrange_storage::equal_p.
* value-range-storage.cc (vrange_storage::equal_p): Remove type.
(irange_storage::equal_p): Same.
(frange_storage::equal_p): Same.
* value-range-storage.h (class frange_storage): Same.
---
 gcc/gimple-range-cache.cc  |  2 +-
 gcc/value-range-storage.cc | 28 +++-
 gcc/value-range-storage.h  |  6 +++---
 3 files changed, 15 insertions(+), 21 deletions(-)

diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index 92622fc5000..07c69ef858a 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -320,7 +320,7 @@ sbr_sparse_bitmap::set_bb_range (const_basic_block bb, 
const vrange )
 
   // Loop thru the values to see if R is already present.
   for (int x = 0; x < SBR_NUM; x++)
-if (!m_range[x] || m_range[x]->equal_p (r, m_type))
+if (!m_range[x] || m_range[x]->equal_p (r))
   {
if (!m_range[x])
  m_range[x] = m_range_allocator->clone (r);
diff --git a/gcc/value-range-storage.cc b/gcc/value-range-storage.cc
index 7d2de5e8384..1e06a7acc8d 100644
--- a/gcc/value-range-storage.cc
+++ b/gcc/value-range-storage.cc
@@ -206,20 +206,22 @@ vrange_storage::fits_p (const vrange ) const
   return false;
 }
 
-// Return TRUE if the range in storage is equal to R.
+// Return TRUE if the range in storage is equal to R.  It is the
+// caller's responsibility to verify that the type of the range in
+// storage matches that of R.
 
 bool
-vrange_storage::equal_p (const vrange , tree type) const
+vrange_storage::equal_p (const vrange ) const
 {
   if (is_a  (r))
 {
   const irange_storage *s = static_cast  (this);
-  return s->equal_p (as_a  (r), type);
+  return s->equal_p (as_a  (r));
 }
   if (is_a  (r))
 {
   const frange_storage *s = static_cast  (this);
-  return s->equal_p (as_a  (r), type);
+  return s->equal_p (as_a  (r));
 }
   gcc_unreachable ();
 }
@@ -375,21 +377,17 @@ irange_storage::get_irange (irange , tree type) const
 }
 
 bool
-irange_storage::equal_p (const irange , tree type) const
+irange_storage::equal_p (const irange ) const
 {
   if (m_kind == VR_UNDEFINED || r.undefined_p ())
 return m_kind == r.m_kind;
   if (m_kind == VR_VARYING || r.varying_p ())
-return m_kind == r.m_kind && types_compatible_p (r.type (), type);
-
-  tree rtype = r.type ();
-  if (!types_compatible_p (rtype, type))
-return false;
+return m_kind == r.m_kind;
 
   // ?? We could make this faster by doing the comparison in place,
   // without going through get_irange.
   int_range_max tmp;
-  get_irange (tmp, rtype);
+  get_irange (tmp, r.type ());
   return tmp == r;
 }
 
@@ -526,17 +524,13 @@ frange_storage::get_frange (frange , tree type) const
 }
 
 bool
-frange_storage::equal_p (const frange , tree type) const
+frange_storage::equal_p (const frange ) const
 {
   if (r.undefined_p ())
 return m_kind == VR_UNDEFINED;
 
-  tree rtype = type;
-  if (!types_compatible_p (rtype, type))
-return false;
-
   frange tmp;
-  get_frange (tmp, rtype);
+  get_frange (tmp, r.type ());
   return tmp == r;
 }
 
diff --git a/gcc/value-range-storage.h b/gcc/value-range-storage.h
index 4ec0da73059..f25489f32c1 100644
--- a/gcc/value-range-storage.h
+++ b/gcc/value-range-storage.h
@@ -54,7 +54,7 @@ public:
   void get_vrange (vrange , tree type) const;
   void set_vrange (const vrange );
   bool fits_p (const vrange ) const;
-  bool equal_p (const vrange , tree type) const;
+  bool equal_p (const vrange ) const;
 protected:
   // Stack initialization disallowed.
   vrange_storage () { }
@@ -68,7 +68,7 @@ public:
   static irange_storage *alloc (vrange_internal_alloc &, const irange &);
   void set_irange (const irange );
   void get_irange (irange , tree type) const;
-  bool equal_p (const irange , tree type) const;
+  bool equal_p (const irange ) const;
   bool fits_p (const irange ) const;
   void dump () const;
 private:
@@ -111,7 +111,7 @@ class frange_storage : public vrange_storage
   static frange_storage *alloc (vrange_internal_alloc &, const frange );
   void set_frange (const frange );
   void get_frange (frange , tree type) const;
-  bool equal_p (const frange , tree type) const;
+  bool equal_p (const frange ) const;
   bool fits_p (const frange &) const;
  private:
   frange_storage (const frange ) { set_frange (r); }
-- 
2.40.0



Re: [PATCH (pushed)] clang warning: warning: private field 'm_gc' is not used [-Wunused-private-field]

2023-05-03 Thread Aldy Hernandez via Gcc-patches
Thanks.

On Wed, May 3, 2023, 11:17 Martin Liška  wrote:

> Pushed to master as obvious.
>
> Martin
>
> PR tree-optimization/109693
>
> gcc/ChangeLog:
>
> * value-range-storage.cc (vrange_allocator::vrange_allocator):
> Remove unused field.
> * value-range-storage.h: Likewise.
> ---
>  gcc/value-range-storage.cc | 1 -
>  gcc/value-range-storage.h  | 1 -
>  2 files changed, 2 deletions(-)
>
> diff --git a/gcc/value-range-storage.cc b/gcc/value-range-storage.cc
> index 7d2de5e8384..14bec500dbc 100644
> --- a/gcc/value-range-storage.cc
> +++ b/gcc/value-range-storage.cc
> @@ -80,7 +80,6 @@ public:
>  };
>
>  vrange_allocator::vrange_allocator (bool gc)
> -  : m_gc (gc)
>  {
>if (gc)
>  m_alloc = new vrange_ggc_alloc;
> diff --git a/gcc/value-range-storage.h b/gcc/value-range-storage.h
> index 4ec0da73059..a90b64b2bf0 100644
> --- a/gcc/value-range-storage.h
> +++ b/gcc/value-range-storage.h
> @@ -38,7 +38,6 @@ public:
>  private:
>DISABLE_COPY_AND_ASSIGN (vrange_allocator);
>class vrange_internal_alloc *m_alloc;
> -  bool m_gc;
>  };
>
>  // Efficient memory storage for a vrange.
> --
> 2.40.1
>
>


[COMMITTED] Remove unused friends in int_range<>.

2023-05-01 Thread Aldy Hernandez via Gcc-patches
gcc/ChangeLog:

* value-range.h (class int_range): Remove gt_ggc_mx and gt_pch_nx
friends.
---
 gcc/value-range.h | 5 -
 1 file changed, 5 deletions(-)

diff --git a/gcc/value-range.h b/gcc/value-range.h
index 5cff50e6d03..ab8d7d3c5dc 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -216,11 +216,6 @@ public:
 protected:
   int_range (tree, tree, value_range_kind = VR_RANGE);
 private:
-  template  friend void gt_ggc_mx (int_range *);
-  template  friend void gt_pch_nx (int_range *);
-  template  friend void gt_pch_nx (int_range *,
-  gt_pointer_operator, void *);
-
   wide_int m_ranges[N*2];
 };
 
-- 
2.40.0



[COMMITTED] Conversion to irange wide_int API.

2023-05-01 Thread Aldy Hernandez via Gcc-patches
This converts the irange API to use wide_ints exclusively, along with
its users.

This patch will slow down VRP, as there will be more useless
wide_int to tree conversions.  However, this slowdown is only
temporary, as a follow-up patch will convert the internal
representation of iranges to wide_ints for a net overall gain
in performance.

gcc/ChangeLog:

* fold-const.cc (expr_not_equal_to): Convert to irange wide_int API.
* gimple-fold.cc (size_must_be_zero_p): Same.
* gimple-loop-versioning.cc
(loop_versioning::prune_loop_conditions): Same.
* gimple-range-edge.cc (gcond_edge_range): Same.
(gimple_outgoing_range::calc_switch_ranges): Same.
* gimple-range-fold.cc (adjust_imagpart_expr): Same.
(adjust_realpart_expr): Same.
(fold_using_range::range_of_address): Same.
(fold_using_range::relation_fold_and_or): Same.
* gimple-range-gori.cc (gori_compute::gori_compute): Same.
(range_is_either_true_or_false): Same.
* gimple-range-op.cc (cfn_toupper_tolower::get_letter_range): Same.
(cfn_clz::fold_range): Same.
(cfn_ctz::fold_range): Same.
* gimple-range-tests.cc (class test_expr_eval): Same.
* gimple-ssa-warn-alloca.cc (alloca_call_type): Same.
* ipa-cp.cc (ipa_value_range_from_jfunc): Same.
(propagate_vr_across_jump_function): Same.
(decide_whether_version_node): Same.
* ipa-fnsummary.cc (evaluate_conditions_for_known_args): Same.
* ipa-prop.cc (ipa_get_value_range): Same.
* range-op.cc (get_shift_range): Same.
(value_range_from_overflowed_bounds): Same.
(value_range_with_overflow): Same.
(create_possibly_reversed_range): Same.
(equal_op1_op2_relation): Same.
(not_equal_op1_op2_relation): Same.
(lt_op1_op2_relation): Same.
(le_op1_op2_relation): Same.
(gt_op1_op2_relation): Same.
(ge_op1_op2_relation): Same.
(operator_mult::op1_range): Same.
(operator_exact_divide::op1_range): Same.
(operator_lshift::op1_range): Same.
(operator_rshift::op1_range): Same.
(operator_cast::op1_range): Same.
(operator_logical_and::fold_range): Same.
(set_nonzero_range_from_mask): Same.
(operator_bitwise_or::op1_range): Same.
(operator_bitwise_xor::op1_range): Same.
(operator_addr_expr::fold_range): Same.
(pointer_plus_operator::wi_fold): Same.
(pointer_or_operator::op1_range): Same.
(INT): Same.
(UINT): Same.
(INT16): Same.
(UINT16): Same.
(SCHAR): Same.
(UCHAR): Same.
(range_op_cast_tests): Same.
(range_op_lshift_tests): Same.
(range_op_rshift_tests): Same.
(range_op_bitwise_and_tests): Same.
(range_relational_tests): Same.
* range.cc (range_zero): Same.
(range_nonzero): Same.
* range.h (range_true): Same.
(range_false): Same.
(range_true_and_false): Same.
* tree-data-ref.cc (split_constant_offset_1): Same.
* tree-ssa-loop-ch.cc (entry_loop_condition_is_static): Same.
* tree-ssa-loop-unswitch.cc (struct unswitch_predicate): Same.
(find_unswitching_predicates_for_bb): Same.
* tree-ssa-phiopt.cc (value_replacement): Same.
* tree-ssa-threadbackward.cc
(back_threader::find_taken_edge_cond): Same.
* tree-ssanames.cc (ssa_name_has_boolean_range): Same.
* tree-vrp.cc (find_case_label_range): Same.
* value-query.cc (range_query::get_tree_range): Same.
* value-range.cc (irange::set_nonnegative): Same.
(frange::contains_p): Same.
(frange::singleton_p): Same.
(frange::internal_singleton_p): Same.
(irange::irange_set): Same.
(irange::irange_set_1bit_anti_range): Same.
(irange::irange_set_anti_range): Same.
(irange::set): Same.
(irange::operator==): Same.
(irange::singleton_p): Same.
(irange::contains_p): Same.
(irange::set_range_from_nonzero_bits): Same.
(DEFINE_INT_RANGE_INSTANCE): Same.
(INT): Same.
(UINT): Same.
(SCHAR): Same.
(UINT128): Same.
(UCHAR): Same.
(range): New.
(tree_range): New.
(range_int): New.
(range_uint): New.
(range_uint128): New.
(range_uchar): New.
(range_char): New.
(build_range3): Convert to irange wide_int API.
(range_tests_irange3): Same.
(range_tests_int_range_max): Same.
(range_tests_strict_enum): Same.
(range_tests_misc): Same.
(range_tests_nonzero_bits): Same.
(range_tests_nan): Same.
(range_tests_signed_zeros): Same.
* value-range.h (Value_Range::Value_Range): Same.
(irange::set): Same.
(irange::nonzero_p): Same.
(irange::contains_p): Same.
(range_includes_zero_p): 

[COMMITTED] Inline irange::set_nonzero.

2023-05-01 Thread Aldy Hernandez via Gcc-patches
irange::set_nonzero is used everywhere and benefits immensely from
inlining.

gcc/ChangeLog:

* value-range.h (irange::set_nonzero): Inline.
---
 gcc/value-range.h | 20 ++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/gcc/value-range.h b/gcc/value-range.h
index 9a834c91b17..5cff50e6d03 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -886,8 +886,24 @@ irange::upper_bound () const
 inline void
 irange::set_nonzero (tree type)
 {
-  wide_int zero = wi::zero (TYPE_PRECISION (type));
-  set (type, zero, zero, VR_ANTI_RANGE);
+  unsigned prec = TYPE_PRECISION (type);
+
+  if (TYPE_UNSIGNED (type))
+{
+  m_type = type;
+  m_kind = VR_RANGE;
+  m_base[0] = wi::one (prec);
+  m_base[1] = m_nonzero_mask = wi::minus_one (prec);
+  m_num_ranges = 1;
+
+  if (flag_checking)
+   verify_range ();
+}
+  else
+{
+  wide_int zero = wi::zero (prec);
+  set (type, zero, zero, VR_ANTI_RANGE);
+}
 }
 
 // Set value range VR to a ZERO range of type TYPE.
-- 
2.40.0



[COMMITTED] Rewrite bounds_of_var_in_loop() to use ranges.

2023-05-01 Thread Aldy Hernandez via Gcc-patches
Little by little, bounds_of_var_in_loop() has grown into an
unmaintainable mess.  This patch rewrites the code to use the relevant
APIs as well as refactor it to make it more readable.

gcc/ChangeLog:

* gimple-range-fold.cc (tree_lower_bound): Delete.
(tree_upper_bound): Delete.
(vrp_val_max): Delete.
(vrp_val_min): Delete.
(fold_using_range::range_of_ssa_name_with_loop_info): Call
range_of_var_in_loop.
* vr-values.cc (valid_value_p): Delete.
(fix_overflow): Delete.
(get_scev_info): New.
(bounds_of_var_in_loop): Refactor into...
(induction_variable_may_overflow_p): ...this,
(range_from_loop_direction): ...and this,
(range_of_var_in_loop): ...and this.
* vr-values.h (bounds_of_var_in_loop): Delete.
(range_of_var_in_loop): New.
---
 gcc/gimple-range-fold.cc |  80 +--
 gcc/vr-values.cc | 282 ---
 gcc/vr-values.h  |   4 +-
 3 files changed, 117 insertions(+), 249 deletions(-)

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index 1b76e6e02a3..96cbd799488 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -944,60 +944,6 @@ fold_using_range::range_of_cond_expr  (vrange , gassign 
*s, fur_source )
   return true;
 }
 
-// Return the lower bound of R as a tree.
-
-static inline tree
-tree_lower_bound (const vrange , tree type)
-{
-  if (is_a  (r))
-return wide_int_to_tree (type, as_a  (r).lower_bound ());
-  // ?? Handle floats when they contain endpoints.
-  return NULL;
-}
-
-// Return the upper bound of R as a tree.
-
-static inline tree
-tree_upper_bound (const vrange , tree type)
-{
-  if (is_a  (r))
-return wide_int_to_tree (type, as_a  (r).upper_bound ());
-  // ?? Handle floats when they contain endpoints.
-  return NULL;
-}
-
-// Return the maximum value for TYPE.
-
-static inline tree
-vrp_val_max (const_tree type)
-{
-  if (INTEGRAL_TYPE_P (type)
-  || POINTER_TYPE_P (type))
-return wide_int_to_tree (const_cast  (type), irange_val_max (type));
-  if (frange::supports_p (type))
-{
-  REAL_VALUE_TYPE r = frange_val_max (type);
-  return build_real (const_cast  (type), r);
-}
-  return NULL_TREE;
-}
-
-// Return the minimum value for TYPE.
-
-static inline tree
-vrp_val_min (const_tree type)
-{
-  if (INTEGRAL_TYPE_P (type)
-  || POINTER_TYPE_P (type))
-return wide_int_to_tree (const_cast  (type), irange_val_min (type));
-  if (frange::supports_p (type))
-{
-  REAL_VALUE_TYPE r = frange_val_min (type);
-  return build_real (const_cast  (type), r);
-}
-  return NULL_TREE;
-}
-
 // If SCEV has any information about phi node NAME, return it as a range in R.
 
 void
@@ -1006,30 +952,8 @@ fold_using_range::range_of_ssa_name_with_loop_info 
(vrange , tree name,
fur_source )
 {
   gcc_checking_assert (TREE_CODE (name) == SSA_NAME);
-  tree min, max, type = TREE_TYPE (name);
-  if (bounds_of_var_in_loop (, , src.query (), l, phi, name))
-{
-  if (!is_gimple_constant (min))
-   {
- if (src.query ()->range_of_expr (r, min, phi) && !r.undefined_p ())
-   min = tree_lower_bound (r, type);
- else
-   min = vrp_val_min (type);
-   }
-  if (!is_gimple_constant (max))
-   {
- if (src.query ()->range_of_expr (r, max, phi) && !r.undefined_p ())
-   max = tree_upper_bound (r, type);
- else
-   max = vrp_val_max (type);
-   }
-  if (min && max)
-   {
- r.set (min, max);
- return;
-   }
-}
-  r.set_varying (type);
+  if (!range_of_var_in_loop (r, name, l, phi, src.query ()))
+r.set_varying (TREE_TYPE (name));
 }
 
 // ---
diff --git a/gcc/vr-values.cc b/gcc/vr-values.cc
index 31df6b85ce6..86c1bf8ebc6 100644
--- a/gcc/vr-values.cc
+++ b/gcc/vr-values.cc
@@ -52,23 +52,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "range-op.h"
 #include "gimple-range.h"
 
-/* Returns true if EXPR is a valid value (as expected by compare_values) --
-   a gimple invariant, or SSA_NAME +- CST.  */
-
-static bool
-valid_value_p (tree expr)
-{
-  if (TREE_CODE (expr) == SSA_NAME)
-return true;
-
-  if (TREE_CODE (expr) == PLUS_EXPR
-  || TREE_CODE (expr) == MINUS_EXPR)
-return (TREE_CODE (TREE_OPERAND (expr, 0)) == SSA_NAME
-   && TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST);
-
-  return is_gimple_min_invariant (expr);
-}
-
 /* Return true if op is in a boolean [0, 1] value-range.  */
 
 bool
@@ -184,178 +167,139 @@ check_for_binary_op_overflow (range_query *query,
   return true;
 }
 
-static inline void
-fix_overflow (tree *min, tree *max)
+/* Set INIT, STEP, and DIRECTION the the corresponding values of NAME
+   within LOOP, and return TRUE.  Otherwise return FALSE, and set R to
+   the 

[COMMITTED] Convert get_legacy_range in bounds_of_var_in_loop to irange API.

2023-05-01 Thread Aldy Hernandez via Gcc-patches
gcc/ChangeLog:

* vr-values.cc (bounds_of_var_in_loop): Convert to irange API.
---
 gcc/vr-values.cc | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/gcc/vr-values.cc b/gcc/vr-values.cc
index 7f623102ac6..3d28198f9f5 100644
--- a/gcc/vr-values.cc
+++ b/gcc/vr-values.cc
@@ -331,13 +331,16 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query 
*query,
  || initvr.undefined_p ())
return false;
 
- tree initvr_min, initvr_max;
+ tree initvr_type = initvr.type ();
+ tree initvr_min = wide_int_to_tree (initvr_type,
+ initvr.lower_bound ());
+ tree initvr_max = wide_int_to_tree (initvr_type,
+ initvr.upper_bound ());
  tree maxvr_type = maxvr.type ();
  tree maxvr_min = wide_int_to_tree (maxvr_type,
 maxvr.lower_bound ());
  tree maxvr_max = wide_int_to_tree (maxvr_type,
 maxvr.upper_bound ());
- get_legacy_range (initvr, initvr_min, initvr_max);
 
  /* Check if init + nit * step overflows.  Though we checked
 scev {init, step}_loop doesn't wrap, it is not enough
-- 
2.40.0



[COMMITTED] Convert internal representation of irange to wide_ints.

2023-05-01 Thread Aldy Hernandez via Gcc-patches
gcc/ChangeLog:

* range-op.cc (update_known_bitmask): Adjust for irange containing
wide_ints internally.
* tree-ssanames.cc (set_nonzero_bits): Same.
* tree-ssanames.h (set_nonzero_bits): Same.
* value-range-storage.cc (irange_storage::set_irange): Same.
(irange_storage::get_irange): Same.
* value-range.cc (irange::operator=): Same.
(irange::irange_set): Same.
(irange::irange_set_1bit_anti_range): Same.
(irange::irange_set_anti_range): Same.
(irange::set): Same.
(irange::verify_range): Same.
(irange::contains_p): Same.
(irange::irange_single_pair_union): Same.
(irange::union_): Same.
(irange::irange_contains_p): Same.
(irange::intersect): Same.
(irange::invert): Same.
(irange::set_range_from_nonzero_bits): Same.
(irange::set_nonzero_bits): Same.
(mask_to_wi): Same.
(irange::intersect_nonzero_bits): Same.
(irange::union_nonzero_bits): Same.
(gt_ggc_mx): Same.
(gt_pch_nx): Same.
(tree_range): Same.
(range_tests_strict_enum): Same.
(range_tests_misc): Same.
(range_tests_nonzero_bits): Same.
* value-range.h (irange::type): Same.
(irange::varying_compatible_p): Same.
(irange::irange): Same.
(int_range::int_range): Same.
(irange::set_undefined): Same.
(irange::set_varying): Same.
(irange::lower_bound): Same.
(irange::upper_bound): Same.
---
 gcc/range-op.cc|   3 +-
 gcc/tree-ssanames.cc   |   2 +-
 gcc/tree-ssanames.h|   2 +-
 gcc/value-range-storage.cc |  22 +--
 gcc/value-range.cc | 267 -
 gcc/value-range.h  |  70 --
 6 files changed, 153 insertions(+), 213 deletions(-)

diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index fc0eef998e4..3ab2c665901 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -89,7 +89,8 @@ update_known_bitmask (irange , tree_code code,
   bit_value_binop (code, sign, prec, , ,
   lh_sign, lh_prec, lh_value, lh_mask,
   rh_sign, rh_prec, rh_value, rh_mask);
-  r.set_nonzero_bits (value | mask);
+  wide_int tmp = wide_int::from (value | mask, prec, sign);
+  r.set_nonzero_bits (tmp);
 }
 
 // Return the upper limit for a type.
diff --git a/gcc/tree-ssanames.cc b/gcc/tree-ssanames.cc
index a510dfa031a..5fdb6a37e9f 100644
--- a/gcc/tree-ssanames.cc
+++ b/gcc/tree-ssanames.cc
@@ -456,7 +456,7 @@ set_ptr_nonnull (tree name)
 /* Update the non-zero bits bitmask of NAME.  */
 
 void
-set_nonzero_bits (tree name, const wide_int_ref )
+set_nonzero_bits (tree name, const wide_int )
 {
   gcc_assert (!POINTER_TYPE_P (TREE_TYPE (name)));
 
diff --git a/gcc/tree-ssanames.h b/gcc/tree-ssanames.h
index b09e71bf779..f3fa609208a 100644
--- a/gcc/tree-ssanames.h
+++ b/gcc/tree-ssanames.h
@@ -58,7 +58,7 @@ struct GTY(()) ptr_info_def
 
 /* Sets the value range to SSA.  */
 extern bool set_range_info (tree, const vrange &);
-extern void set_nonzero_bits (tree, const wide_int_ref &);
+extern void set_nonzero_bits (tree, const wide_int &);
 extern wide_int get_nonzero_bits (const_tree);
 extern bool ssa_name_has_boolean_range (tree);
 extern void init_ssanames (struct function *, int);
diff --git a/gcc/value-range-storage.cc b/gcc/value-range-storage.cc
index 98a6d99af78..7d2de5e8384 100644
--- a/gcc/value-range-storage.cc
+++ b/gcc/value-range-storage.cc
@@ -300,10 +300,7 @@ irange_storage::set_irange (const irange )
   write_wide_int (val, len, r.lower_bound (i));
   write_wide_int (val, len, r.upper_bound (i));
 }
-  if (r.m_nonzero_mask)
-write_wide_int (val, len, wi::to_wide (r.m_nonzero_mask));
-  else
-write_wide_int (val, len, wi::minus_one (m_precision));
+  write_wide_int (val, len, r.m_nonzero_mask);
 
   if (flag_checking)
 {
@@ -341,17 +338,16 @@ irange_storage::get_irange (irange , tree type) const
   gcc_checking_assert (TYPE_PRECISION (type) == m_precision);
   const HOST_WIDE_INT *val = _val[0];
   const unsigned char *len = lengths_address ();
-  wide_int w;
 
   // Handle the common case where R can fit the new range.
   if (r.m_max_ranges >= m_num_ranges)
 {
   r.m_kind = VR_RANGE;
   r.m_num_ranges = m_num_ranges;
+  r.m_type = type;
   for (unsigned i = 0; i < m_num_ranges * 2; ++i)
{
- read_wide_int (w, val, *len, m_precision);
- r.m_base[i] = wide_int_to_tree (type, w);
+ read_wide_int (r.m_base[i], val, *len, m_precision);
  val += *len++;
}
 }
@@ -370,15 +366,9 @@ irange_storage::get_irange (irange , tree type) const
  r.union_ (tmp);
}
 }
-  read_wide_int (w, val, *len, m_precision);
-  if (w == -1)
-r.m_nonzero_mask = NULL;
-  else
-{
-  r.m_nonzero_mask = wide_int_to_tree (type, w);
-  if (r.m_kind == VR_VARYING)
-   r.m_kind = VR_RANGE;
-  

[COMMITTED] Merge irange::union/intersect into irange_union/intersect.

2023-05-01 Thread Aldy Hernandez via Gcc-patches
gcc/ChangeLog:

* value-range.cc (irange::irange_union): Rename to...
(irange::union_): ...this.
(irange::irange_intersect): Rename to...
(irange::intersect): ...this.
* value-range.h (irange::union_): Delete.
(irange::intersect): Delete.
---
 gcc/value-range.cc | 11 +++
 gcc/value-range.h  | 14 --
 2 files changed, 7 insertions(+), 18 deletions(-)

diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index a0e49df28f3..69b214ecc06 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -1246,11 +1246,13 @@ irange::irange_single_pair_union (const irange )
   return true;
 }
 
-// union_ for multi-ranges.
+// Return TRUE if anything changes.
 
 bool
-irange::irange_union (const irange )
+irange::union_ (const vrange )
 {
+  const irange  = as_a  (v);
+
   if (r.undefined_p ())
 return false;
 
@@ -1415,11 +1417,12 @@ irange::irange_contains_p (const irange ) const
 }
 
 
-// Intersect for multi-ranges.  Return TRUE if anything changes.
+// Return TRUE if anything changes.
 
 bool
-irange::irange_intersect (const irange )
+irange::intersect (const vrange )
 {
+  const irange  = as_a  (v);
   gcc_checking_assert (undefined_p () || r.undefined_p ()
   || range_compatible_p (type (), r.type ()));
 
diff --git a/gcc/value-range.h b/gcc/value-range.h
index 10c44c5c062..6d108154dc1 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -170,8 +170,6 @@ protected:
   irange (tree *, unsigned);
 
// In-place operators.
-  bool irange_union (const irange &);
-  bool irange_intersect (const irange &);
   void irange_set (tree, tree);
   void irange_set_anti_range (tree, tree);
   bool irange_contains_p (const irange &) const;
@@ -903,18 +901,6 @@ irange::upper_bound () const
   return upper_bound (pairs - 1);
 }
 
-inline bool
-irange::union_ (const vrange )
-{
-  return irange_union (as_a  (r));
-}
-
-inline bool
-irange::intersect (const vrange )
-{
-  return irange_intersect (as_a  (r));
-}
-
 // Set value range VR to a nonzero range of type TYPE.
 
 inline void
-- 
2.40.0



[COMMITTED] Replace vrp_val* with wide_ints.

2023-05-01 Thread Aldy Hernandez via Gcc-patches
This patch removes all uses of vrp_val_{min,max} in favor for a
irange_val_* which are wide_int based.  This will leave only one use
of vrp_val_* which returns trees in range_of_ssa_name_with_loop_info()
because it needs to work with non-integers (floats, etc).  In a
follow-up patch, this function will also be cleaned up such that
vrp_val_* can be deleted.

The functions min_limit and max_limit in range-op.cc are now useless
as they're basically irange_val*.  I didn't rename them yet to avoid
churn.  I'll do it in a later patch.

gcc/ChangeLog:

* gimple-range-fold.cc (adjust_pointer_diff_expr): Rewrite with
irange_val*.
(vrp_val_max): New.
(vrp_val_min): New.
* gimple-range-op.cc (cfn_strlen::fold_range): Use irange_val_*.
* range-op.cc (max_limit): Same.
(min_limit): Same.
(plus_minus_ranges): Same.
(operator_rshift::op1_range): Same.
(operator_cast::inside_domain_p): Same.
* value-range.cc (vrp_val_is_max): Delete.
(vrp_val_is_min): Delete.
(range_tests_misc): Use irange_val_*.
* value-range.h (vrp_val_is_min): Delete.
(vrp_val_is_max): Delete.
(vrp_val_max): Delete.
(irange_val_min): New.
(vrp_val_min): Delete.
(irange_val_max): New.
* vr-values.cc (check_for_binary_op_overflow): Use irange_val_*.
---
 gcc/gimple-range-fold.cc | 40 +
 gcc/gimple-range-op.cc   |  8 +++
 gcc/range-op.cc  | 19 +++-
 gcc/value-range.cc   | 37 +--
 gcc/value-range.h| 41 +++---
 gcc/vr-values.cc | 48 ++--
 6 files changed, 78 insertions(+), 115 deletions(-)

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index 62875a35038..1b76e6e02a3 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -360,10 +360,10 @@ adjust_pointer_diff_expr (irange , const gimple 
*diff_stmt)
   && vrp_operand_equal_p (op1, gimple_call_arg (call, 0))
   && integer_zerop (gimple_call_arg (call, 1)))
 {
-  tree max = vrp_val_max (ptrdiff_type_node);
-  unsigned prec = TYPE_PRECISION (TREE_TYPE (max));
-  wide_int wmaxm1 = wi::to_wide (max, prec) - 1;
-  res.intersect (int_range<2> (TREE_TYPE (max), wi::zero (prec), wmaxm1));
+  wide_int maxm1 = irange_val_max (ptrdiff_type_node) - 1;
+  res.intersect (int_range<2> (ptrdiff_type_node,
+  wi::zero (TYPE_PRECISION 
(ptrdiff_type_node)),
+  maxm1));
 }
 }
 
@@ -966,6 +966,38 @@ tree_upper_bound (const vrange , tree type)
   return NULL;
 }
 
+// Return the maximum value for TYPE.
+
+static inline tree
+vrp_val_max (const_tree type)
+{
+  if (INTEGRAL_TYPE_P (type)
+  || POINTER_TYPE_P (type))
+return wide_int_to_tree (const_cast  (type), irange_val_max (type));
+  if (frange::supports_p (type))
+{
+  REAL_VALUE_TYPE r = frange_val_max (type);
+  return build_real (const_cast  (type), r);
+}
+  return NULL_TREE;
+}
+
+// Return the minimum value for TYPE.
+
+static inline tree
+vrp_val_min (const_tree type)
+{
+  if (INTEGRAL_TYPE_P (type)
+  || POINTER_TYPE_P (type))
+return wide_int_to_tree (const_cast  (type), irange_val_min (type));
+  if (frange::supports_p (type))
+{
+  REAL_VALUE_TYPE r = frange_val_min (type);
+  return build_real (const_cast  (type), r);
+}
+  return NULL_TREE;
+}
+
 // If SCEV has any information about phi node NAME, return it as a range in R.
 
 void
diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index 29c7c776a2c..3aef8357d8d 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -900,15 +900,13 @@ public:
   virtual bool fold_range (irange , tree type, const irange &,
   const irange &, relation_trio) const
   {
-tree max = vrp_val_max (ptrdiff_type_node);
-wide_int wmax
-  = wi::to_wide (max, TYPE_PRECISION (TREE_TYPE (max)));
+wide_int max = irange_val_max (ptrdiff_type_node);
 // 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.
-r.set (type, wi::zero (TYPE_PRECISION (type)), wmax - 2);
+r.set (type, wi::zero (TYPE_PRECISION (type)), max - 2);
 return true;
   }
 } op_cfn_strlen;
@@ -936,7 +934,7 @@ public:
   wi::shwi (m_is_pos ? 0 : 1, TYPE_PRECISION (type)),
   size
   ? wi::shwi (size - m_is_pos, TYPE_PRECISION (type))
-  : wi::to_wide (vrp_val_max (type)));
+  : irange_val_max (type));
 return true;
   }
 private:
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 224a561c170..fc0eef998e4 100644
--- a/gcc/range-op.cc
+++ 

[COMMITTED] Cleanup irange::set.

2023-05-01 Thread Aldy Hernandez via Gcc-patches
Now that anti-ranges are no more and iranges contain wide_ints instead
of trees, various cleanups are possible.  This is one of a handful of
patches improving the performance of irange::set() which is not on a
hot path, but quite sensitive because it is so pervasive.

gcc/ChangeLog:

* gimple-range-op.cc (cfn_ffs::fold_range): Use the correct
precision.
* gimple-ssa-warn-alloca.cc (alloca_call_type): Use <2> for
invalid_range, as it is an inverse range.
* tree-vrp.cc (find_case_label_range): Avoid trees.
* value-range.cc (irange::irange_set): Delete.
(irange::irange_set_1bit_anti_range): Delete.
(irange::irange_set_anti_range): Delete.
(irange::set): Cleanup.
* value-range.h (class irange): Remove irange_set,
irange_set_anti_range, irange_set_1bit_anti_range.
(irange::set_undefined): Remove set to m_type.
---
 gcc/gimple-range-op.cc|   4 +-
 gcc/gimple-ssa-warn-alloca.cc |   2 +-
 gcc/tree-vrp.cc   |   8 +-
 gcc/value-range.cc| 175 ++
 gcc/value-range.h |   5 -
 5 files changed, 59 insertions(+), 135 deletions(-)

diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index 3aef8357d8d..5d1f921ba40 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -654,7 +654,9 @@ public:
   range_cast (tmp, unsigned_type_for (tmp.type ()));
 wide_int max = tmp.upper_bound ();
 maxi = wi::floor_log2 (max) + 1;
-r.set (type, wi::shwi (mini, prec), wi::shwi (maxi, prec));
+r.set (type,
+  wi::shwi (mini, TYPE_PRECISION (type)),
+  wi::shwi (maxi, TYPE_PRECISION (type)));
 return true;
   }
 } op_cfn_ffs;
diff --git a/gcc/gimple-ssa-warn-alloca.cc b/gcc/gimple-ssa-warn-alloca.cc
index c129aca16e2..2d8ab93a81d 100644
--- a/gcc/gimple-ssa-warn-alloca.cc
+++ b/gcc/gimple-ssa-warn-alloca.cc
@@ -222,7 +222,7 @@ alloca_call_type (gimple *stmt, bool is_vla)
   && !r.varying_p ())
 {
   // The invalid bits are anything outside of [0, MAX_SIZE].
-  int_range<1> invalid_range (size_type_node,
+  int_range<2> invalid_range (size_type_node,
  wi::shwi (0, TYPE_PRECISION (size_type_node)),
  wi::shwi (max_size, TYPE_PRECISION 
(size_type_node)),
  VR_ANTI_RANGE);
diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc
index d28637b1918..0761b6896fe 100644
--- a/gcc/tree-vrp.cc
+++ b/gcc/tree-vrp.cc
@@ -827,6 +827,8 @@ find_case_label_range (gswitch *switch_stmt, const irange 
*range_of_op)
   size_t i, j;
   tree op = gimple_switch_index (switch_stmt);
   tree type = TREE_TYPE (op);
+  unsigned prec = TYPE_PRECISION (type);
+  signop sign = TYPE_SIGN (type);
   tree tmin = wide_int_to_tree (type, range_of_op->lower_bound ());
   tree tmax = wide_int_to_tree (type, range_of_op->upper_bound ());
   find_case_label_range (switch_stmt, tmin, tmax, , );
@@ -837,9 +839,11 @@ find_case_label_range (gswitch *switch_stmt, const irange 
*range_of_op)
   tree label = gimple_switch_label (switch_stmt, i);
   tree case_high
= CASE_HIGH (label) ? CASE_HIGH (label) : CASE_LOW (label);
+  wide_int wlow = wi::to_wide (CASE_LOW (label));
+  wide_int whigh = wi::to_wide (case_high);
   int_range_max label_range (type,
-wi::to_wide (CASE_LOW (label)),
-wi::to_wide (case_high));
+wide_int::from (wlow, prec, sign),
+wide_int::from (whigh, prec, sign));
   if (!types_compatible_p (label_range.type (), range_of_op->type ()))
range_cast (label_range, range_of_op->type ());
   label_range.intersect (*range_of_op);
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 2dc6b98bc63..655ffc2d6d4 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -961,98 +961,6 @@ get_legacy_range (const irange , tree , tree )
   return VR_RANGE;
 }
 
-void
-irange::irange_set (tree type, const wide_int , const wide_int )
-{
-  m_type = type;
-  m_base[0] = min;
-  m_base[1] = max;
-  m_num_ranges = 1;
-  m_kind = VR_RANGE;
-  m_nonzero_mask = wi::minus_one (TYPE_PRECISION (type));
-  normalize_kind ();
-
-  if (flag_checking)
-verify_range ();
-}
-
-void
-irange::irange_set_1bit_anti_range (tree type,
-   const wide_int , const wide_int )
-{
-  unsigned prec = TYPE_PRECISION (type);
-  signop sign = TYPE_SIGN (type);
-  gcc_checking_assert (prec == 1);
-
-  if (min == max)
-{
-  wide_int tmp;
-  // Since these are 1-bit quantities, they can only be [MIN,MIN]
-  // or [MAX,MAX].
-  if (min == wi::min_value (prec, sign))
-   tmp = wi::max_value (prec, sign);
-  else
-   tmp = wi::min_value (prec, sign);
-  set (type, tmp, tmp);
-}
-  else
-{
-  // The only alternative is [MIN,MAX], 

[COMMITTED] vrange_storage overhaul

2023-05-01 Thread Aldy Hernandez via Gcc-patches
[tl;dr: This is a rewrite of value-range-storage.* such that global
ranges and the internal ranger cache can use the same efficient
storage mechanism.  It is optimized such that when wide_ints are
dropped into irange, the copying back and forth from storage will be
very fast, while being able to hold any number of sub-ranges
dynamically allocated at run-time.  This replaces the global storage
mechanism which was limited to 6-subranges.]

Previously we had a vrange allocator for use in the ranger cache.  It
worked with trees and could be used in place (fast), but it was not
memory efficient.  With the upcoming switch to wide_ints for irange,
we can't afford to allocate ranges that can be used in place, because
an irange will be significantly larger, as it will hold full
wide_ints.  We need a trailing_wide_int mechanism similar to what we
use for global ranges, but fast enough to use in the ranger's cache.

The global ranges had another allocation mechanism that was
trailing_wide_int based.  It was memory efficient but slow given the
constant conversions from trees to wide_ints.

This patch gets us the best of both worlds by providing a storage
mechanism with a custom trailing wide int interface, while at the same
time being fast enough to use in the ranger cache.

We use a custom trailing wide_int mechanism but more flexible than
trailing_wide_int, since the latter has compile-time fixed-sized
wide_ints.  The original TWI structure has the current length of each
wide_int in a static portion preceeding the variable length:

template 
struct GTY((user)) trailing_wide_ints
{
...
...
  /* The current length of each number.
 that will, in turn, turn off TBAA on gimple, trees and RTL.  */
  struct {unsigned char len;} m_len[N];

  /* The variable-length part of the structure, which always contains
 at least one HWI.  Element I starts at index I * M_MAX_LEN.  */
  HOST_WIDE_INT m_val[1];
};

We need both m_len[] and m_val[] to be variable-length at run-time.
In the previous incarnation of the storage mechanism the limitation of
m_len[] being static meant that we were limited to whatever [N] could
use up the unused bits in the TWI control world.  In practice this
meant we were limited to 6 sub-ranges.  This worked fine for global
ranges, but is a no go for our internal cache, where we must represent
things exactly (ranges for switches, etc).

The new implementation removes this restriction by making both m_len[]
and m_val[] variable length.  Also, rolling our own allows future
optimization be using some of the leftover bits in the control world.

Also, in preparation for the wide_int conversion, vrange_storage is
now optimized to blast the bits directly into the ultimate irange
instead of going through the irange API.  So ultimately copying back
and forth between the ranger cache and the storage mechanism is just a
matter of copying a few bits for the control word, and copying an
array of HOST_WIDE_INTs.  These changes were heavily profiled, and
yielded a good chunk of the overall speedup for the wide_int
conversion.

Finally, vrange_storage is now a first class structure with GTY
markers and all, thus alleviating the void * hack in struct
tree_ssa_name and friends.  This removes a few warts in the API and
looks cleaner overall.

gcc/ChangeLog:

* gimple-fold.cc (maybe_fold_comparisons_from_match_pd): Adjust
for vrange_storage.
* gimple-range-cache.cc (sbr_vector::sbr_vector): Same.
(sbr_vector::grow): Same.
(sbr_vector::set_bb_range): Same.
(sbr_vector::get_bb_range): Same.
(sbr_sparse_bitmap::sbr_sparse_bitmap): Same.
(sbr_sparse_bitmap::set_bb_range): Same.
(sbr_sparse_bitmap::get_bb_range): Same.
(block_range_cache::block_range_cache): Same.
(ssa_global_cache::ssa_global_cache): Same.
(ssa_global_cache::get_global_range): Same.
(ssa_global_cache::set_global_range): Same.
* gimple-range-cache.h: Same.
* gimple-range-edge.cc
(gimple_outgoing_range::gimple_outgoing_range): Same.
(gimple_outgoing_range::switch_edge_range): Same.
(gimple_outgoing_range::calc_switch_ranges): Same.
* gimple-range-edge.h: Same.
* gimple-range-infer.cc
(infer_range_manager::infer_range_manager): Same.
(infer_range_manager::get_nonzero): Same.
(infer_range_manager::maybe_adjust_range): Same.
(infer_range_manager::add_range): Same.
* gimple-range-infer.h: Rename obstack_vrange_allocator to
vrange_allocator.
* tree-core.h (struct irange_storage_slot): Remove.
(struct tree_ssa_name): Remove irange_info and frange_info.  Make
range_info a pointer to vrange_storage.
* tree-ssanames.cc (range_info_fits_p): Adjust for vrange_storage.
(range_info_alloc): Same.
(range_info_free): Same.
(range_info_get_range): Same.
(range_info_set_range): Same.

[COMMITTED] Various cleanups in vr-values.cc towards ranger API.

2023-05-01 Thread Aldy Hernandez via Gcc-patches
gcc/ChangeLog:

* vr-values.cc (check_for_binary_op_overflow): Tidy up by using
ranger API.
(compare_ranges): Delete.
(compare_range_with_value): Delete.
(bounds_of_var_in_loop): Tidy up by using ranger API.
(simplify_using_ranges::fold_cond_with_ops): Cleanup and rename
from vrp_evaluate_conditional_warnv_with_ops_using_ranges.
(simplify_using_ranges::legacy_fold_cond_overflow): Remove
strict_overflow_p and only_ranges.
(simplify_using_ranges::legacy_fold_cond): Adjust call to
legacy_fold_cond_overflow.
(simplify_using_ranges::simplify_abs_using_ranges): Adjust for
rename.
(range_fits_type_p): Rename value_range to irange.
* vr-values.h (range_fits_type_p): Adjust prototype.
---
 gcc/vr-values.cc | 531 ---
 gcc/vr-values.h  |   8 +-
 2 files changed, 87 insertions(+), 452 deletions(-)

diff --git a/gcc/vr-values.cc b/gcc/vr-values.cc
index 2ee234c4d88..7f623102ac6 100644
--- a/gcc/vr-values.cc
+++ b/gcc/vr-values.cc
@@ -104,43 +104,34 @@ check_for_binary_op_overflow (range_query *query,
  tree op0, tree op1, bool *ovf, gimple *s = NULL)
 {
   value_range vr0, vr1;
-  if (TREE_CODE (op0) == SSA_NAME)
-{
-  if (!query->range_of_expr (vr0, op0, s))
-   vr0.set_varying (TREE_TYPE (op0));
-}
-  else if (TREE_CODE (op0) == INTEGER_CST)
-vr0.set (op0, op0);
-  else
+  if (!query->range_of_expr (vr0, op0, s))
 vr0.set_varying (TREE_TYPE (op0));
-
-  if (TREE_CODE (op1) == SSA_NAME)
-{
-  if (!query->range_of_expr (vr1, op1, s))
-   vr1.set_varying (TREE_TYPE (op1));
-}
-  else if (TREE_CODE (op1) == INTEGER_CST)
-vr1.set (op1, op1);
-  else
+  if (!query->range_of_expr (vr1, op1, s))
 vr1.set_varying (TREE_TYPE (op1));
 
   tree vr0min, vr0max, vr1min, vr1max;
-  value_range_kind kind0 = get_legacy_range (vr0, vr0min, vr0max);
-  value_range_kind kind1 = get_legacy_range (vr1, vr1min, vr1max);
-  if (kind0 != VR_RANGE
-  || TREE_OVERFLOW (vr0min)
-  || TREE_OVERFLOW (vr0max))
+  if (vr0.undefined_p () || vr0.varying_p ())
 {
   vr0min = vrp_val_min (TREE_TYPE (op0));
   vr0max = vrp_val_max (TREE_TYPE (op0));
 }
-  if (kind1 != VR_RANGE
-  || TREE_OVERFLOW (vr1min)
-  || TREE_OVERFLOW (vr1max))
+  else
+{
+  tree type = vr0.type ();
+  vr0min = wide_int_to_tree (type, vr0.lower_bound ());
+  vr0max = wide_int_to_tree (type, vr0.upper_bound ());
+}
+  if (vr1.undefined_p () || vr1.varying_p ())
 {
   vr1min = vrp_val_min (TREE_TYPE (op1));
   vr1max = vrp_val_max (TREE_TYPE (op1));
 }
+  else
+{
+  tree type = vr1.type ();
+  vr1min = wide_int_to_tree (type, vr1.lower_bound ());
+  vr1max = wide_int_to_tree (type, vr1.upper_bound ());
+}
   *ovf = arith_overflowed_p (subcode, type, vr0min,
 subcode == MINUS_EXPR ? vr1max : vr1min);
   if (arith_overflowed_p (subcode, type, vr0max,
@@ -208,269 +199,6 @@ check_for_binary_op_overflow (range_query *query,
   return true;
 }
 
-/* Given two numeric value ranges VR0, VR1 and a comparison code COMP:
-
-   - Return BOOLEAN_TRUE_NODE if VR0 COMP VR1 always returns true for
- all the values in the ranges.
-
-   - Return BOOLEAN_FALSE_NODE if the comparison always returns false.
-
-   - Return NULL_TREE if it is not always possible to determine the
- value of the comparison.
-
-   Also set *STRICT_OVERFLOW_P to indicate whether comparision evaluation
-   assumed signed overflow is undefined.  */
-
-
-static tree
-compare_ranges (enum tree_code comp, const value_range *vr0,
-   const value_range *vr1, bool *strict_overflow_p)
-{
-  /* VARYING or UNDEFINED ranges cannot be compared.  */
-  if (vr0->varying_p ()
-  || vr0->undefined_p ()
-  || vr1->varying_p ()
-  || vr1->undefined_p ())
-return NULL_TREE;
-
-  /* Anti-ranges need to be handled separately.  */
-  tree vr0min, vr0max, vr1min, vr1max;
-  value_range_kind kind0 = get_legacy_range (*vr0, vr0min, vr0max);
-  value_range_kind kind1 = get_legacy_range (*vr1, vr1min, vr1max);
-  if (kind0 == VR_ANTI_RANGE || kind1 == VR_ANTI_RANGE)
-{
-  /* If both are anti-ranges, then we cannot compute any
-comparison.  */
-  if (kind0 == VR_ANTI_RANGE && kind1 == VR_ANTI_RANGE)
-   return NULL_TREE;
-
-  /* These comparisons are never statically computable.  */
-  if (comp == GT_EXPR
- || comp == GE_EXPR
- || comp == LT_EXPR
- || comp == LE_EXPR)
-   return NULL_TREE;
-
-  /* Equality can be computed only between a range and an
-anti-range.  ~[VAL1, VAL2] == [VAL1, VAL2] is always false.  */
-  if (kind0 == VR_RANGE)
-   {
- /* To simplify processing, make VR0 the anti-range.  */
- kind0 = kind1;
- vr0min = vr1min;
- vr0max = vr1max;
-   

[COMMITTED] Remove irange::{min,max,kind}.

2023-05-01 Thread Aldy Hernandez via Gcc-patches
gcc/ChangeLog:

* tree-ssa-loop-niter.cc (refine_value_range_using_guard): Remove
kind() call.
(determine_value_range): Same.
(record_nonwrapping_iv): Same.
(infer_loop_bounds_from_signedness): Same.
(scev_var_range_cant_overflow): Same.
* tree-vrp.cc (operand_less_p): Delete.
* tree-vrp.h (operand_less_p): Delete.
* value-range.cc (get_legacy_range): Remove uses of deprecated API.
(irange::value_inside_range): Delete.
* value-range.h (vrange::kind): Delete.
(irange::num_pairs): Remove check of m_kind.
(irange::min): Delete.
(irange::max): Delete.
---
 gcc/tree-ssa-loop-niter.cc | 26 +---
 gcc/tree-vrp.cc| 24 ---
 gcc/tree-vrp.h |  1 -
 gcc/value-range.cc | 49 --
 gcc/value-range.h  | 37 +---
 5 files changed, 19 insertions(+), 118 deletions(-)

diff --git a/gcc/tree-ssa-loop-niter.cc b/gcc/tree-ssa-loop-niter.cc
index 33233979ba0..c0ed6573409 100644
--- a/gcc/tree-ssa-loop-niter.cc
+++ b/gcc/tree-ssa-loop-niter.cc
@@ -223,7 +223,8 @@ refine_value_range_using_guard (tree type, tree var,
   else if (TREE_CODE (varc1) == SSA_NAME
   && INTEGRAL_TYPE_P (type)
   && get_range_query (cfun)->range_of_expr (r, varc1)
-  && r.kind () == VR_RANGE)
+  && !r.undefined_p ()
+  && !r.varying_p ())
 {
   gcc_assert (wi::le_p (r.lower_bound (), r.upper_bound (), sgn));
   wi::to_mpz (r.lower_bound (), minc1, sgn);
@@ -368,7 +369,10 @@ determine_value_range (class loop *loop, tree type, tree 
var, mpz_t off,
   /* Either for VAR itself...  */
   Value_Range var_range (TREE_TYPE (var));
   get_range_query (cfun)->range_of_expr (var_range, var);
-  rtype = var_range.kind ();
+  if (var_range.varying_p () || var_range.undefined_p ())
+   rtype = VR_VARYING;
+  else
+   rtype = VR_RANGE;
   if (!var_range.undefined_p ())
{
  minv = var_range.lower_bound ();
@@ -384,7 +388,8 @@ determine_value_range (class loop *loop, tree type, tree 
var, mpz_t off,
  if (PHI_ARG_DEF_FROM_EDGE (phi, e) == var
  && get_range_query (cfun)->range_of_expr (phi_range,
gimple_phi_result (phi))
- && phi_range.kind () == VR_RANGE)
+ && !phi_range.varying_p ()
+ && !phi_range.undefined_p ())
{
  if (rtype != VR_RANGE)
{
@@ -404,7 +409,10 @@ determine_value_range (class loop *loop, tree type, tree 
var, mpz_t off,
{
  Value_Range vr (TREE_TYPE (var));
  get_range_query (cfun)->range_of_expr (vr, var);
- rtype = vr.kind ();
+ if (vr.varying_p () || vr.undefined_p ())
+   rtype = VR_VARYING;
+ else
+   rtype = VR_RANGE;
  if (!vr.undefined_p ())
{
  minv = vr.lower_bound ();
@@ -4045,7 +4053,8 @@ record_nonwrapping_iv (class loop *loop, tree base, tree 
step, gimple *stmt,
   if (TREE_CODE (orig_base) == SSA_NAME
  && TREE_CODE (high) == INTEGER_CST
  && INTEGRAL_TYPE_P (TREE_TYPE (orig_base))
- && (base_range.kind () == VR_RANGE
+ && ((!base_range.varying_p ()
+  && !base_range.undefined_p ())
  || get_cst_init_from_scev (orig_base, , false))
  && wi::gts_p (wi::to_wide (high), max))
base = wide_int_to_tree (unsigned_type, max);
@@ -4067,7 +4076,8 @@ record_nonwrapping_iv (class loop *loop, tree base, tree 
step, gimple *stmt,
   if (TREE_CODE (orig_base) == SSA_NAME
  && TREE_CODE (low) == INTEGER_CST
  && INTEGRAL_TYPE_P (TREE_TYPE (orig_base))
- && (base_range.kind () == VR_RANGE
+ && ((!base_range.varying_p ()
+  && !base_range.undefined_p ())
  || get_cst_init_from_scev (orig_base, , true))
  && wi::gts_p (min, wi::to_wide (low)))
base = wide_int_to_tree (unsigned_type, min);
@@ -4335,7 +4345,7 @@ infer_loop_bounds_from_signedness (class loop *loop, 
gimple *stmt)
   high = upper_bound_in_type (type, type);
   Value_Range r (TREE_TYPE (def));
   get_range_query (cfun)->range_of_expr (r, def);
-  if (r.kind () == VR_RANGE)
+  if (!r.varying_p () && !r.undefined_p ())
 {
   low = wide_int_to_tree (type, r.lower_bound ());
   high = wide_int_to_tree (type, r.upper_bound ());
@@ -5385,7 +5395,7 @@ scev_var_range_cant_overflow (tree var, tree step, class 
loop *loop)
 
   Value_Range r (TREE_TYPE (var));
   get_range_query (cfun)->range_of_expr (r, var);
-  if (r.kind () != VR_RANGE)
+  if (r.varying_p () || r.undefined_p ())
 return false;
 
   /* VAR is a scev whose evolution 

[COMMITTED] Remove irange::tree_{lower,upper}_bound.

2023-05-01 Thread Aldy Hernandez via Gcc-patches
gcc/ChangeLog:

* value-range.cc (irange::irange_set_anti_range): Remove uses of
tree_lower_bound and tree_upper_bound.
(irange::verify_range): Same.
(irange::operator==): Same.
(irange::singleton_p): Same.
* value-range.h (irange::tree_lower_bound): Delete.
(irange::tree_upper_bound): Delete.
(irange::lower_bound): Delete.
(irange::upper_bound): Delete.
(irange::zero_p): Remove uses of tree_lower_bound and
tree_upper_bound.
---
 gcc/value-range.cc | 36 ++--
 gcc/value-range.h  | 39 ---
 2 files changed, 22 insertions(+), 53 deletions(-)

diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index ee43efa1ab5..a0e49df28f3 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -1010,7 +1010,7 @@ irange::irange_set_anti_range (tree min, tree max)
 {
   wide_int lim1 = wi::sub (w_min, 1, sign, );
   gcc_checking_assert (ovf != wi::OVF_OVERFLOW);
-  m_base[0] = type_range.tree_lower_bound (0);
+  m_base[0] = wide_int_to_tree (type, type_range.lower_bound (0));
   m_base[1] = wide_int_to_tree (type, lim1);
   m_num_ranges = 1;
 }
@@ -1025,7 +1025,8 @@ irange::irange_set_anti_range (tree min, tree max)
   wide_int lim2 = wi::add (w_max, 1, sign, );
   gcc_checking_assert (ovf != wi::OVF_OVERFLOW);
   m_base[m_num_ranges * 2] = wide_int_to_tree (type, lim2);
-  m_base[m_num_ranges * 2 + 1] = type_range.tree_upper_bound (0);
+  m_base[m_num_ranges * 2 + 1]
+   = wide_int_to_tree (type, type_range.upper_bound (0));
   ++m_num_ranges;
 }
 
@@ -1104,9 +1105,9 @@ irange::verify_range ()
   gcc_checking_assert (!varying_compatible_p ());
   for (unsigned i = 0; i < m_num_ranges; ++i)
 {
-  tree lb = tree_lower_bound (i);
-  tree ub = tree_upper_bound (i);
-  int c = compare_values (lb, ub);
+  wide_int lb = lower_bound (i);
+  wide_int ub = upper_bound (i);
+  int c = wi::cmp (lb, ub, TYPE_SIGN (type ()));
   gcc_checking_assert (c == 0 || c == -1);
 }
 }
@@ -1120,20 +1121,20 @@ irange::operator== (const irange ) const
   if (m_num_ranges == 0)
 return true;
 
+  signop sign1 = TYPE_SIGN (type ());
+  signop sign2 = TYPE_SIGN (other.type ());
+
   for (unsigned i = 0; i < m_num_ranges; ++i)
 {
-  tree lb = tree_lower_bound (i);
-  tree ub = tree_upper_bound (i);
-  tree lb_other = other.tree_lower_bound (i);
-  tree ub_other = other.tree_upper_bound (i);
-  if (!operand_equal_p (lb, lb_other, 0)
- || !operand_equal_p (ub, ub_other, 0))
+  widest_int lb = widest_int::from (lower_bound (i), sign1);
+  widest_int ub = widest_int::from (upper_bound (i), sign1);
+  widest_int lb_other = widest_int::from (other.lower_bound (i), sign2);
+  widest_int ub_other = widest_int::from (other.upper_bound (i), sign2);
+  if (lb != lb_other || ub != ub_other)
return false;
 }
-  widest_int nz1 = widest_int::from (get_nonzero_bits (),
-TYPE_SIGN (type ()));
-  widest_int nz2 = widest_int::from (other.get_nonzero_bits (),
-TYPE_SIGN (other.type ()));
+  widest_int nz1 = widest_int::from (get_nonzero_bits (), sign1);
+  widest_int nz2 = widest_int::from (other.get_nonzero_bits (), sign2);
   return nz1 == nz2;
 }
 
@@ -1144,11 +1145,10 @@ irange::operator== (const irange ) const
 bool
 irange::singleton_p (tree *result) const
 {
-  if (num_pairs () == 1 && (wi::to_wide (tree_lower_bound ())
-   == wi::to_wide (tree_upper_bound (
+  if (num_pairs () == 1 && lower_bound () == upper_bound ())
 {
   if (result)
-   *result = tree_lower_bound ();
+   *result = wide_int_to_tree (type (), lower_bound ());
   return true;
 }
   return false;
diff --git a/gcc/value-range.h b/gcc/value-range.h
index 68f380a2dbb..10c44c5c062 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -168,10 +168,6 @@ public:
 
 protected:
   irange (tree *, unsigned);
-  // potential promotion to public?
-  tree tree_lower_bound (unsigned = 0) const;
-  tree tree_upper_bound (unsigned) const;
-  tree tree_upper_bound () const;
 
// In-place operators.
   bool irange_union (const irange &);
@@ -654,33 +650,6 @@ irange::type () const
   return TREE_TYPE (m_base[0]);
 }
 
-// Return the lower bound of a sub-range expressed as a tree.  PAIR is
-// the sub-range in question.
-
-inline tree
-irange::tree_lower_bound (unsigned pair) const
-{
-  return m_base[pair * 2];
-}
-
-// Return the upper bound of a sub-range expressed as a tree.  PAIR is
-// the sub-range in question.
-
-inline tree
-irange::tree_upper_bound (unsigned pair) const
-{
-  return m_base[pair * 2 + 1];
-}
-
-// Return the highest bound of a range expressed as a tree.
-
-inline tree
-irange::tree_upper_bound () const
-{
-  gcc_checking_assert (m_num_ranges);

Re: [PATCH] gimple-range-op: Handle sqrt (basic bounds only)

2023-04-27 Thread Aldy Hernandez via Gcc-patches
Ok

On Thu, Apr 27, 2023, 15:30 Jakub Jelinek  wrote:

> Hi!
>
> The following patch adds sqrt support (but similarly to sincos, only
> dumb basic ranges only).
>
> Ok for trunk if it passes bootstrap/regtest?
>
> Will improve this incrementally and sin/cos as well.
>
> 2023-04-27  Jakub Jelinek  
>
> * gimple-range-op.cc (class cfn_sqrt): New type.
> (op_cfn_sqrt): New variable.
> (gimple_range_op_handler::maybe_builtin_call): Handle
> CASE_CFN_SQRT{,_FN}.
>
> * gcc.dg/tree-ssa/range-sqrt.c: New test.
>
> --- gcc/gimple-range-op.cc.jj   2023-04-27 11:57:09.865879982 +0200
> +++ gcc/gimple-range-op.cc  2023-04-27 15:15:05.089787859 +0200
> @@ -400,6 +400,83 @@ public:
>}
>  } op_cfn_copysign;
>
> +class cfn_sqrt : public range_operator_float
> +{
> +public:
> +  using range_operator_float::fold_range;
> +  using range_operator_float::op1_range;
> +  virtual bool fold_range (frange , tree type,
> +  const frange , const frange &,
> +  relation_trio) const final override
> +  {
> +if (lh.undefined_p ())
> +  return false;
> +if (lh.known_isnan () || real_less (_bound (), ))
> +  {
> +   r.set_nan (type);
> +   return true;
> +  }
> +unsigned bulps
> +  = targetm.libm_function_max_error (CFN_SQRT, TYPE_MODE (type),
> true);
> +if (bulps == ~0U)
> +  r.set_varying (type);
> +else if (bulps == 0)
> +  r.set (type, dconstm0, dconstinf);
> +else
> +  {
> +   REAL_VALUE_TYPE boundmin = dconstm0;
> +   while (bulps--)
> + frange_nextafter (TYPE_MODE (type), boundmin, dconstninf);
> +   r.set (type, boundmin, dconstinf);
> +  }
> +if (!lh.maybe_isnan () && !real_less (_bound (), ))
> +  r.clear_nan ();
> +return true;
> +  }
> +  virtual bool op1_range (frange , tree type,
> + const frange , const frange &,
> + relation_trio) const final override
> +  {
> +if (lhs.undefined_p ())
> +  return false;
> +
> +// A known NAN means the input is [-INF,-0.) U +-NAN.
> +if (lhs.known_isnan ())
> +  {
> +  known_nan:
> +   REAL_VALUE_TYPE ub = dconstm0;
> +   frange_nextafter (TYPE_MODE (type), ub, dconstninf);
> +   r.set (type, dconstninf, ub);
> +   // No r.flush_denormals_to_zero (); here - it is a reverse op.
> +   return true;
> +  }
> +
> +// Results outside of [-0.0, +Inf] are impossible.
> +const REAL_VALUE_TYPE  = lhs.upper_bound ();
> +if (real_less (, ))
> +  {
> +   if (!lhs.maybe_isnan ())
> + r.set_undefined ();
> +   else
> + // If lhs could be NAN and finite result is impossible,
> + // the range is like lhs.known_isnan () above.
> + goto known_nan;
> +   return true;
> +  }
> +
> +if (!lhs.maybe_isnan ())
> +  {
> +   // If NAN is not valid result, the input cannot include either
> +   // a NAN nor values smaller than -0.
> +   r.set (type, dconstm0, dconstinf, nan_state (false, false));
> +   return true;
> +  }
> +
> +r.set_varying (type);
> +return true;
> +  }
> +} op_cfn_sqrt;
> +
>  class cfn_sincos : public range_operator_float
>  {
>  public:
> @@ -961,6 +1038,13 @@ gimple_range_op_handler::maybe_builtin_c
>m_valid = true;
>break;
>
> +CASE_CFN_SQRT:
> +CASE_CFN_SQRT_FN:
> +  m_op1 = gimple_call_arg (call, 0);
> +  m_float = _cfn_sqrt;
> +  m_valid = true;
> +  break;
> +
>  CASE_CFN_SIN:
>  CASE_CFN_SIN_FN:
>m_op1 = gimple_call_arg (call, 0);
> --- gcc/testsuite/gcc.dg/tree-ssa/range-sqrt.c.jj   2023-04-27
> 15:10:09.285102144 +0200
> +++ gcc/testsuite/gcc.dg/tree-ssa/range-sqrt.c  2023-04-27
> 15:12:01.478465821 +0200
> @@ -0,0 +1,41 @@
> +// { dg-do compile }
> +// { dg-options "-O2 -fdump-tree-evrp -fno-thread-jumps" }
> +
> +#include 
> +
> +void use (double);
> +void link_error ();
> +
> +void
> +foo (double x)
> +{
> +  if (__builtin_isnan (x))
> +__builtin_unreachable ();
> +  x = sqrt (x);
> +  if (x < -0.0)
> +link_error ();
> +  use (x);
> +}
> +
> +void
> +bar (double x)
> +{
> +  if (!__builtin_isnan (sqrt (x)))
> +{
> +  if (__builtin_isnan (x))
> +   link_error ();
> +  if (x < -0.0)
> +   link_error ();
> +}
> +}
> +
> +void
> +stool (double x)
> +{
> +  double res1 = sqrt (x);
> +  double res2 = __builtin_sqrt (x);
> +  if (res1 < -0.0 || res2 < -0.0)
> +link_error ();
> +}
> +
> +// { dg-final { scan-tree-dump-not "link_error" "evrp" { target { {
> *-*-linux* } && { glibc } } } } }
>
> Jakub
>
>


  1   2   3   4   5   6   7   8   9   10   >