* [PATCH] [frange] Relax floating point relational folding.
@ 2023-08-23 15:22 Aldy Hernandez
2023-08-28 7:01 ` Jakub Jelinek
0 siblings, 1 reply; 3+ messages in thread
From: Aldy Hernandez @ 2023-08-23 15:22 UTC (permalink / raw)
To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez
[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 &op1, const frange &op2)
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)" has a
+// relation of VREL_LT, but behaves as VREL_UNLT unless we can prove
+// neither operand can be NAN.
+//
+// ?? It is unclear whether providing unordered VREL relations would
+// simplify things, as we'd have to add more entries to various
+// tables, tweak all the op1_op2_relation() entries, etc.
static inline bool
frelop_early_resolve (irange &r, tree type,
const frange &op1, const frange &op2,
- relation_trio rel, relation_kind my_rel)
+ relation_trio trio, relation_kind my_rel)
{
+ relation_kind rel = trio.op1_op2 ();
+
+ if (maybe_isnan (op1, op2))
+ {
+ // There's not much we can do for VREL_EQ if NAN is a
+ // possibility. It is up to the caller to deal with these
+ // special cases.
+ if (rel == VREL_EQ)
+ return empty_range_varying (r, type, op1, op2);
+ }
+ // If known relation is a complete subset of this relation, always
+ // return true. However, avoid doing this when NAN is a possibility
+ // as we'll incorrectly fold conditions:
+ //
+ // if (x_3 >= y_5)
+ // ;
+ // else
+ // ;; With NANs the relation here is basically VREL_UNLT, so we
+ // ;; can't fold the following:
+ // if (x_3 < y_5)
+ else if (relation_union (rel, my_rel) == my_rel)
+ {
+ r = range_true (type);
+ return true;
+ }
+
+ // If known relation has no subset of this relation, always false.
+ if (relation_intersect (rel, my_rel) == VREL_UNDEFINED)
+ {
+ r = range_false (type);
+ return true;
+ }
+
// If either operand is undefined, return VARYING.
if (empty_range_varying (r, type, op1, op2))
return true;
- // We can fold relations from the oracle when we know both operands
- // are free of NANs, or when -ffinite-math-only.
- return (!maybe_isnan (op1, op2)
- && relop_early_resolve (r, type, op1, op2, rel, my_rel));
+ return false;
}
// Set VALUE to its next real value, or INF if the operation overflows.
@@ -738,9 +791,17 @@ operator_equal::op1_op2_relation (const irange &lhs, const frange &,
bool
operator_not_equal::fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
- relation_trio rel) const
+ relation_trio trio) const
{
- if (frelop_early_resolve (r, type, op1, op2, rel, VREL_NE))
+ relation_kind rel = trio.op1_op2 ();
+
+ // VREL_NE & NE_EXPR is always true, even with NANs.
+ if (rel == VREL_NE)
+ {
+ r = range_true (type);
+ return true;
+ }
+ if (frelop_early_resolve (r, type, op1, op2, trio, VREL_NE))
return true;
// x != NAN is always TRUE.
@@ -862,9 +923,17 @@ operator_not_equal::op1_op2_relation (const irange &lhs, const frange &,
bool
operator_lt::fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
- relation_trio rel) const
+ relation_trio trio) const
{
- if (frelop_early_resolve (r, type, op1, op2, rel, VREL_LT))
+ relation_kind rel = trio.op1_op2 ();
+
+ // VREL_EQ & LT_EXPR is impossible, even with NANs.
+ if (rel == VREL_EQ)
+ {
+ r = range_false (type);
+ return true;
+ }
+ if (frelop_early_resolve (r, type, op1, op2, trio, VREL_LT))
return true;
if (op1.known_isnan ()
@@ -1083,9 +1152,17 @@ operator_le::op1_op2_relation (const irange &lhs, const frange &,
bool
operator_gt::fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
- relation_trio rel) const
+ relation_trio trio) const
{
- if (frelop_early_resolve (r, type, op1, op2, rel, VREL_GT))
+ relation_kind rel = trio.op1_op2 ();
+
+ // VREL_EQ & GT_EXPR is impossible, even with NANs.
+ if (rel == VREL_EQ)
+ {
+ r = range_false (type);
+ return true;
+ }
+ if (frelop_early_resolve (r, type, op1, op2, trio, VREL_GT))
return true;
if (op1.known_isnan ()
@@ -1587,9 +1664,12 @@ class foperator_unordered_lt : public range_operator
public:
bool fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
- relation_trio rel = TRIO_VARYING) const final override
+ relation_trio trio = TRIO_VARYING) const final override
{
- if (op1.known_isnan () || op2.known_isnan ())
+ relation_kind rel = trio.op1_op2 ();
+
+ if (op1.known_isnan () || op2.known_isnan ()
+ || rel == VREL_LT)
{
r = range_true (type);
return true;
@@ -1601,7 +1681,7 @@ public:
if (op2.maybe_isnan ())
op2_no_nan.clear_nan ();
if (!range_op_handler (LT_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.
@@ -1699,9 +1779,12 @@ class foperator_unordered_le : public range_operator
public:
bool fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
- relation_trio rel = TRIO_VARYING) const final override
+ relation_trio trio = TRIO_VARYING) const final override
{
- if (op1.known_isnan () || op2.known_isnan ())
+ relation_kind rel = trio.op1_op2 ();
+
+ if (op1.known_isnan () || op2.known_isnan ()
+ || rel == VREL_LE)
{
r = range_true (type);
return true;
@@ -1713,7 +1796,7 @@ public:
if (op2.maybe_isnan ())
op2_no_nan.clear_nan ();
if (!range_op_handler (LE_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.
@@ -1807,9 +1890,12 @@ class foperator_unordered_gt : public range_operator
public:
bool fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
- relation_trio rel = TRIO_VARYING) const final override
+ relation_trio trio = TRIO_VARYING) const final override
{
- if (op1.known_isnan () || op2.known_isnan ())
+ relation_kind rel = trio.op1_op2 ();
+
+ if (op1.known_isnan () || op2.known_isnan ()
+ || rel == VREL_GT)
{
r = range_true (type);
return true;
@@ -1821,7 +1907,7 @@ public:
if (op2.maybe_isnan ())
op2_no_nan.clear_nan ();
if (!range_op_handler (GT_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.
@@ -1919,9 +2005,12 @@ class foperator_unordered_ge : public range_operator
public:
bool fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
- relation_trio rel = TRIO_VARYING) const final override
+ relation_trio trio = TRIO_VARYING) const final override
{
- if (op1.known_isnan () || op2.known_isnan ())
+ relation_kind rel = trio.op1_op2 ();
+
+ if (op1.known_isnan () || op2.known_isnan ()
+ || rel == VREL_GE)
{
r = range_true (type);
return true;
@@ -1933,7 +2022,7 @@ public:
if (op2.maybe_isnan ())
op2_no_nan.clear_nan ();
if (!range_op_handler (GE_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.
@@ -2030,9 +2119,12 @@ class foperator_unordered_equal : public range_operator
public:
bool fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
- relation_trio rel = TRIO_VARYING) const final override
+ relation_trio trio = TRIO_VARYING) const final override
{
- if (op1.known_isnan () || op2.known_isnan ())
+ relation_kind rel = trio.op1_op2 ();
+
+ if (op1.known_isnan () || op2.known_isnan ()
+ || rel == VREL_EQ)
{
r = range_true (type);
return true;
@@ -2044,7 +2136,7 @@ public:
if (op2.maybe_isnan ())
op2_no_nan.clear_nan ();
if (!range_op_handler (EQ_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.
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-12.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-12.c
new file mode 100644
index 00000000000..0c9426dfef5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-12.c
@@ -0,0 +1,23 @@
+// { dg-do compile }
+// { dg-options "-O2 -fdisable-tree-fre1 -fdump-tree-evrp" }
+
+void link_error ();
+void func ();
+
+void foo1 (float x, float y)
+{
+ if (x != y)
+ if (x == y)
+ link_error();
+}
+
+void foo2 (float a, float b)
+{
+ if (a != b)
+ // This conditional should be folded away.
+ if (a != b)
+ func ();
+}
+
+// { dg-final { scan-tree-dump-not "link_error" "evrp" } }
+// { dg-final { scan-tree-dump-times "if \\(a_2\\(D\\) != b_3\\(D\\)" 1 "evrp" } }
--
2.41.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] [frange] Relax floating point relational folding.
2023-08-23 15:22 [PATCH] [frange] Relax floating point relational folding Aldy Hernandez
@ 2023-08-28 7:01 ` Jakub Jelinek
2023-09-19 19:17 ` Aldy Hernandez
0 siblings, 1 reply; 3+ messages in thread
From: Jakub Jelinek @ 2023-08-28 7:01 UTC (permalink / raw)
To: Aldy Hernandez; +Cc: GCC patches, Andrew MacLeod
On Wed, Aug 23, 2023 at 05:22:00PM +0200, Aldy Hernandez via Gcc-patches wrote:
> 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).
My strong preference would be to have the full set of operations,
i.e. VREL_LTGT, VREL_{,UN}ORDERED, VREL_UN{LT,LE,GT,GE,EQ}, then everything
will fall out of this cleanly, not just some common special cases, but
also unions of them, intersections etc.
The only important question is if you want to differentiate VREL_*
for floating point comparisions with possible NANs vs. other comparisons
in the callers, then one needs effectively e.g. 2 sets of rr_* tables
in value-relation.cc and what exactly say VREL_EQ inverts to etc. is then
dependent on the context (this is what we do at the tree level normally,
e.g. fold-const.cc (invert_tree_comparison) has honor_nans argument),
or whether it would be a completely new set of value relations, so
even for EQ/NE etc. one would use VRELF_ or something similar.
Jakub
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] [frange] Relax floating point relational folding.
2023-08-28 7:01 ` Jakub Jelinek
@ 2023-09-19 19:17 ` Aldy Hernandez
0 siblings, 0 replies; 3+ messages in thread
From: Aldy Hernandez @ 2023-09-19 19:17 UTC (permalink / raw)
To: Jakub Jelinek; +Cc: GCC patches, Andrew MacLeod
[-- Attachment #1: Type: text/plain, Size: 2455 bytes --]
Hi Jakub.
I wasn't ignoring you, just quietly thinking, making sure we weren't
missing anything. In the process I cleaned everything, which
hopefully makes it easier to see why we don't need relationals (the
key is to look at frelop_early_resolve() and the op1/op2_range entries
which clear the NAN bits).
I am committing the patch below, and as I say in it:
I don't mean this patch as a hard-no against implementing the
unordered relations Jakub preferred, but seeing that it's looking
cleaner and trivially simple without the added burden of more enums,
I'd like to flesh it out completely and then discuss if we still think
new codes are needed. At least now we have tests :).
Please let me know if you have any test cases you think we may be
missing. FYI, I'm still not done with the unordered folders.
Tested on x86-64 Linux. Committed.
Aldy
On Mon, Aug 28, 2023 at 3:01 AM Jakub Jelinek <jakub@redhat.com> wrote:
>
> On Wed, Aug 23, 2023 at 05:22:00PM +0200, Aldy Hernandez via Gcc-patches wrote:
> > 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).
>
> My strong preference would be to have the full set of operations,
> i.e. VREL_LTGT, VREL_{,UN}ORDERED, VREL_UN{LT,LE,GT,GE,EQ}, then everything
> will fall out of this cleanly, not just some common special cases, but
> also unions of them, intersections etc.
> The only important question is if you want to differentiate VREL_*
> for floating point comparisions with possible NANs vs. other comparisons
> in the callers, then one needs effectively e.g. 2 sets of rr_* tables
> in value-relation.cc and what exactly say VREL_EQ inverts to etc. is then
> dependent on the context (this is what we do at the tree level normally,
> e.g. fold-const.cc (invert_tree_comparison) has honor_nans argument),
> or whether it would be a completely new set of value relations, so
> even for EQ/NE etc. one would use VRELF_ or something similar.
>
> Jakub
>
[-- Attachment #2: 0001-frange-Clean-up-floating-point-relational-folding.patch --]
[-- Type: text/x-patch, Size: 10138 bytes --]
From 220a58d9abbb1f403e8f79cd42ad01b7c9b10ae9 Mon Sep 17 00:00:00 2001
From: Aldy Hernandez <aldyh@redhat.com>
Date: Mon, 18 Sep 2023 21:41:08 -0400
Subject: [PATCH] [frange] Clean up floating point relational folding.
The following patch removes all the special casing from the floating
point relational folding code. Now all the code relating to folding
of relationals is in frelop_early_resolve() and in
operator_not_equal::fold_range() which requires a small tweak.
I have written new relational tests, and moved them to
gcc.dg/tree-ssa/vrp-float-relations-* for easy reference. In the
tests it's easy to see the type of things we need to handle:
(a)
if (x != y)
if (x == y)
link_error ();
(b)
if (a != b)
if (a != b) // Foldable as true.
(c)
/* We can thread BB2->BB4->BB5 even though we have no knowledge
of the NANness of either x_1 or a_5. */
__BB(4):
x_1 = __PHI (__BB2: a_5(D), __BB3: b_4(D));
if (x_1 __UNEQ a_5(D))
(d)
/* Even though x_1 and a_4 are equivalent on the BB2->BB4 path,
we cannot fold the conditional because of possible NANs: */
__BB(4):
# x_1 = __PHI (__BB2: a_4(D), __BB3: 8.0e+0(3));
if (x_1 == a_4(D))
(e)
if (cond)
x = a;
else
x = 8.0;
/* We can fold this as false on the path coming out of cond==1,
regardless of NANs on either "x" or "a". */
if (x < a)
stuff ();
[etc, etc]
We can implement everything without either special casing,
get_identity_relation(), or adding new unordered relationals.
The basic idea is that if we accurately reflect NANs in op[12]_range,
this information gets propagated to the relevant edges, and there's no
need for unordered relations (VREL_UN*), because the information is in
the range itself. This information is then used in
frelop_early_resolve() to fold certain combinations.
I don't mean this patch as a hard-no against implementing the
unordered relations Jakub preferred, but seeing that it's looking
cleaner and trivially simple without the added burden of more enums,
I'd like to flesh it out completely and then discuss if we still think
new codes are needed.
More testcases or corner cases are highly welcome.
In follow-up patches I will finish up unordered relation folding, and
come up with suitable tests.
gcc/ChangeLog:
* range-op-float.cc (frelop_early_resolve): Clean-up and remove
special casing.
(operator_not_equal::fold_range): Handle VREL_EQ.
(operator_lt::fold_range): Remove special casing for VREL_EQ.
(operator_gt::fold_range): Same.
(foperator_unordered_equal::fold_range): Same.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/vrp-float-12.c: Moved to...
* gcc.dg/tree-ssa/vrp-float-relations-1.c: ...here.
* gcc.dg/tree-ssa/vrp-float-relations-2.c: New test.
* gcc.dg/tree-ssa/vrp-float-relations-3.c: New test.
* gcc.dg/tree-ssa/vrp-float-relations-4.c: New test.
---
gcc/range-op-float.cc | 51 ++++---------------
...vrp-float-12.c => vrp-float-relations-1.c} | 0
.../gcc.dg/tree-ssa/vrp-float-relations-2.c | 21 ++++++++
.../gcc.dg/tree-ssa/vrp-float-relations-3.c | 27 ++++++++++
.../gcc.dg/tree-ssa/vrp-float-relations-4.c | 38 ++++++++++++++
5 files changed, 95 insertions(+), 42 deletions(-)
rename gcc/testsuite/gcc.dg/tree-ssa/{vrp-float-12.c => vrp-float-relations-1.c} (100%)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-float-relations-2.c
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-float-relations-3.c
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-float-relations-4.c
diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index 5eb1d9c06e3..399deee5d8a 100644
--- a/gcc/range-op-float.cc
+++ b/gcc/range-op-float.cc
@@ -281,18 +281,6 @@ maybe_isnan (const frange &op1, const frange &op2)
// 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)" has a
-// relation of VREL_LT, but behaves as VREL_UNLT unless we can prove
-// neither operand can be NAN.
-//
-// ?? It is unclear whether providing unordered VREL relations would
-// simplify things, as we'd have to add more entries to various
-// tables, tweak all the op1_op2_relation() entries, etc.
static inline bool
frelop_early_resolve (irange &r, tree type,
@@ -301,14 +289,6 @@ frelop_early_resolve (irange &r, tree type,
{
relation_kind rel = trio.op1_op2 ();
- if (maybe_isnan (op1, op2))
- {
- // There's not much we can do for VREL_EQ if NAN is a
- // possibility. It is up to the caller to deal with these
- // special cases.
- if (rel == VREL_EQ)
- return empty_range_varying (r, type, op1, op2);
- }
// If known relation is a complete subset of this relation, always
// return true. However, avoid doing this when NAN is a possibility
// as we'll incorrectly fold conditions:
@@ -319,7 +299,7 @@ frelop_early_resolve (irange &r, tree type,
// ;; With NANs the relation here is basically VREL_UNLT, so we
// ;; can't fold the following:
// if (x_3 < y_5)
- else if (relation_union (rel, my_rel) == my_rel)
+ if (!maybe_isnan (op1, op2) && relation_union (rel, my_rel) == my_rel)
{
r = range_true (type);
return true;
@@ -801,7 +781,13 @@ operator_not_equal::fold_range (irange &r, tree type,
r = range_true (type);
return true;
}
- if (frelop_early_resolve (r, type, op1, op2, trio, VREL_NE))
+ if (rel == VREL_EQ && maybe_isnan (op1, op2))
+ {
+ // Avoid frelop_early_resolve() below as it could fold to FALSE
+ // without regards to NANs. This would be incorrect if trying
+ // to fold x_5 != x_5 without prior knowledge of NANs.
+ }
+ else if (frelop_early_resolve (r, type, op1, op2, trio, VREL_NE))
return true;
// x != NAN is always TRUE.
@@ -933,14 +919,6 @@ operator_lt::fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
relation_trio trio) const
{
- relation_kind rel = trio.op1_op2 ();
-
- // VREL_EQ & LT_EXPR is impossible, even with NANs.
- if (rel == VREL_EQ)
- {
- r = range_false (type);
- return true;
- }
if (frelop_early_resolve (r, type, op1, op2, trio, VREL_LT))
return true;
@@ -1162,14 +1140,6 @@ operator_gt::fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
relation_trio trio) const
{
- relation_kind rel = trio.op1_op2 ();
-
- // VREL_EQ & GT_EXPR is impossible, even with NANs.
- if (rel == VREL_EQ)
- {
- r = range_false (type);
- return true;
- }
if (frelop_early_resolve (r, type, op1, op2, trio, VREL_GT))
return true;
@@ -2129,10 +2099,7 @@ public:
const frange &op1, const frange &op2,
relation_trio trio = TRIO_VARYING) const final override
{
- relation_kind rel = trio.op1_op2 ();
-
- if (op1.known_isnan () || op2.known_isnan ()
- || rel == VREL_EQ)
+ if (op1.known_isnan () || op2.known_isnan ())
{
r = range_true (type);
return true;
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-12.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-relations-1.c
similarity index 100%
rename from gcc/testsuite/gcc.dg/tree-ssa/vrp-float-12.c
rename to gcc/testsuite/gcc.dg/tree-ssa/vrp-float-relations-1.c
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-relations-2.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-relations-2.c
new file mode 100644
index 00000000000..76c91302167
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-relations-2.c
@@ -0,0 +1,21 @@
+// { dg-do compile }
+// { dg-options "-O2 -fdump-tree-threadfull1-details" }
+
+void stuff();
+
+void foo (float a, int cond)
+{
+ float x;
+
+ if (cond)
+ x = a;
+ else
+ x = 8.0;
+
+ /* We should be able to fold this as false on the path coming out of
+ cond == TRUE conditional. */
+ if (x < a)
+ stuff();
+}
+
+// { dg-final { scan-tree-dump "Registering jump thread: \\(2, 4\\)" "threadfull1" } }
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-relations-3.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-relations-3.c
new file mode 100644
index 00000000000..b7389f5ce26
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-relations-3.c
@@ -0,0 +1,27 @@
+// { dg-do compile }
+// { dg-options "-O2 -fdump-tree-all-stats" }
+
+void stuff();
+
+void foo (float a, int cond)
+{
+ float x;
+
+ if (cond)
+ x = a;
+ else
+ x = 8.0;
+
+ /* Even though on the BB2->BB4 path, x_1 and a_4 are equivalent, we cannot
+ fold x_1 == a_4 because of possible NANs:
+
+ <bb 4>
+ # x_1 = PHI <a_4(D)(2), 8.0e+0(3)>
+ if (x_1 == a_4(D))
+ */
+ if (x == a)
+ stuff();
+}
+
+// { dg-final { scan-tree-dump-not "Jumps threaded" "threadfull1" } }
+// { dg-final { scan-tree-dump-not "Jumps threaded" "threadfull2" } }
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-relations-4.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-relations-4.c
new file mode 100644
index 00000000000..f38b305f4af
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-relations-4.c
@@ -0,0 +1,38 @@
+// { dg-do compile }
+// { dg-options "-O2 -fgimple -fdump-tree-threadfull1-details" }
+
+void stuff();
+
+void __GIMPLE (ssa,startwith("threadfull1"))
+foo (float a, float b, int cond)
+{
+ float x;
+
+ __BB(2):
+ if (cond_3(D) != 0)
+ goto __BB4;
+ else
+ goto __BB3;
+
+ __BB(3):
+ goto __BB4;
+
+ /* We should be able to thread BB2->BB4->BB5 even though we have no knowledge
+ of the NANness of either x_1 or a_5. */
+ __BB(4):
+ x_1 = __PHI (__BB2: a_5(D), __BB3: b_4(D));
+ if (x_1 __UNEQ a_5(D))
+ goto __BB5;
+ else
+ goto __BB6;
+
+ __BB(5):
+ stuff ();
+ goto __BB6;
+
+ __BB(6):
+ return;
+
+}
+
+// { dg-final { scan-tree-dump "Registering jump thread: \\(2, 4\\)" "threadfull1" } }
--
2.41.0
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2023-09-19 19:17 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-23 15:22 [PATCH] [frange] Relax floating point relational folding Aldy Hernandez
2023-08-28 7:01 ` Jakub Jelinek
2023-09-19 19:17 ` Aldy Hernandez
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).