[RFC] range-op-float: Fix up op1_op2_relation of comparisons
Checks
Commit Message
Hi!
This patch was what I've tried first before the currently committed
PR109386 fix. Still, I think it is the right thing until we have proper
full set of VREL_* relations for NANs (though it would be really nice
if op1_op2_relation could be passed either type of the comparison
operands, or even better ranges of the two operands, such that
we could choose if inversion of say VREL_LT is VREL_GE (if !MODE_HONOR_NANS
(TYPE_MODE (type))) or rhs1/rhs2 ranges are guaranteed not to include
NANs (!known_isnan && !maybe_isnan for both), or VREL_UNGE, etc.
Anyway, the current state is that for the LE/LT/GE/GT comparisons
we pretend the inverse is like for integral comparisons, which is
true only if NANs can't appear in operands, while for UNLE/UNLT/UNGE/UNGT
we don't override op1_op2_relation (so it always yields VREL_VARYING).
Though, this patch regresses the
FAIL: gcc.dg/tree-ssa/vrp-float-6.c scan-tree-dump-times evrp "Folding predicate x_.* <= y_.* to 1" 1
test, so am not sure what to do with it. The test has explicit
!isnan tests around it, so e.g. having the ranges passed to op1_op2_relation
would also fix it.
2023-04-11 Jakub Jelinek <jakub@redhat.com>
* range-op-float.cc (foperator_lt::op1_op2_relation): Return
VREL_VARYING instead of VREL_GE.
(foperator_le::op1_op2_relation): Return VREL_VARYING instead of
VREL_GT.
(foperator_gt::op1_op2_relation): Return VREL_VARYING instead of
VREL_LE.
(foperator_ge::op1_op2_relation): Return VREL_VARYING instead of
VREL_LT.
(foperator_unordered_lt::op1_op2_relation,
foperator_unordered_le::op1_op2_relation,
foperator_unordered_gt::op1_op2_relation,
foperator_unordered_ge::op1_op2_relation): New.
Jakub
Comments
On 4/11/23 10:21, Jakub Jelinek wrote:
> Hi!
>
> This patch was what I've tried first before the currently committed
> PR109386 fix. Still, I think it is the right thing until we have proper
> full set of VREL_* relations for NANs (though it would be really nice
> if op1_op2_relation could be passed either type of the comparison
> operands, or even better ranges of the two operands, such that
> we could choose if inversion of say VREL_LT is VREL_GE (if !MODE_HONOR_NANS
> (TYPE_MODE (type))) or rhs1/rhs2 ranges are guaranteed not to include
> NANs (!known_isnan && !maybe_isnan for both), or VREL_UNGE, etc.
> Anyway, the current state is that for the LE/LT/GE/GT comparisons
> we pretend the inverse is like for integral comparisons, which is
> true only if NANs can't appear in operands, while for UNLE/UNLT/UNGE/UNGT
> we don't override op1_op2_relation (so it always yields VREL_VARYING).
>
> Though, this patch regresses the
> FAIL: gcc.dg/tree-ssa/vrp-float-6.c scan-tree-dump-times evrp "Folding predicate x_.* <= y_.* to 1" 1
> test, so am not sure what to do with it. The test has explicit
> !isnan tests around it, so e.g. having the ranges passed to op1_op2_relation
> would also fix it.
I'll defer to Andrew on this, as he's the master of the relation oracle :).
Aldy
>
> 2023-04-11 Jakub Jelinek <jakub@redhat.com>
>
> * range-op-float.cc (foperator_lt::op1_op2_relation): Return
> VREL_VARYING instead of VREL_GE.
> (foperator_le::op1_op2_relation): Return VREL_VARYING instead of
> VREL_GT.
> (foperator_gt::op1_op2_relation): Return VREL_VARYING instead of
> VREL_LE.
> (foperator_ge::op1_op2_relation): Return VREL_VARYING instead of
> VREL_LT.
> (foperator_unordered_lt::op1_op2_relation,
> foperator_unordered_le::op1_op2_relation,
> foperator_unordered_gt::op1_op2_relation,
> foperator_unordered_ge::op1_op2_relation): New.
>
> --- gcc/range-op-float.cc.jj 2023-04-01 09:32:02.635423345 +0200
> +++ gcc/range-op-float.cc 2023-04-03 10:42:54.000000000 +0200
> @@ -831,7 +831,10 @@ public:
> relation_trio = TRIO_VARYING) const final override;
> relation_kind op1_op2_relation (const irange &lhs) const final override
> {
> - return lt_op1_op2_relation (lhs);
> + relation_kind ret = lt_op1_op2_relation (lhs);
> + if (ret == VREL_GE)
> + ret = VREL_VARYING; // Inverse of VREL_LT is VREL_UNGE.
> + return ret;
> }
> bool op1_range (frange &r, tree type,
> const irange &lhs, const frange &op2,
> @@ -947,6 +950,10 @@ public:
> relation_trio rel = TRIO_VARYING) const final override;
> relation_kind op1_op2_relation (const irange &lhs) const final override
> {
> + relation_kind ret = le_op1_op2_relation (lhs);
> + if (ret == VREL_GT)
> + ret = VREL_VARYING; // Inverse of VREL_LE is VREL_UNGT.
> + return ret;
> return le_op1_op2_relation (lhs);
> }
> bool op1_range (frange &r, tree type,
> @@ -1057,7 +1064,10 @@ public:
> relation_trio = TRIO_VARYING) const final override;
> relation_kind op1_op2_relation (const irange &lhs) const final override
> {
> - return gt_op1_op2_relation (lhs);
> + relation_kind ret = gt_op1_op2_relation (lhs);
> + if (ret == VREL_LE)
> + ret = VREL_VARYING; // Inverse of VREL_GT is VREL_UNLE.
> + return ret;
> }
> bool op1_range (frange &r, tree type,
> const irange &lhs, const frange &op2,
> @@ -1177,7 +1187,10 @@ public:
> relation_trio = TRIO_VARYING) const final override;
> relation_kind op1_op2_relation (const irange &lhs) const final override
> {
> - return ge_op1_op2_relation (lhs);
> + relation_kind ret = ge_op1_op2_relation (lhs);
> + if (ret == VREL_LT)
> + ret = VREL_VARYING; // Inverse of VREL_GE is VREL_UNLT.
> + return ret;
> }
> bool op1_range (frange &r, tree type,
> const irange &lhs, const frange &op2,
> @@ -1571,6 +1584,7 @@ class foperator_unordered_lt : public ra
> using range_operator_float::fold_range;
> using range_operator_float::op1_range;
> using range_operator_float::op2_range;
> + using range_operator_float::op1_op2_relation;
> public:
> bool fold_range (irange &r, tree type,
> const frange &op1, const frange &op2,
> @@ -1599,6 +1613,13 @@ public:
> return true;
> }
> }
> + relation_kind op1_op2_relation (const irange &lhs) const final override
> + {
> + relation_kind ret = lt_op1_op2_relation (lhs);
> + if (ret == VREL_LT)
> + ret = VREL_VARYING; // Should have been VREL_UNLT.
> + return ret;
> + }
> bool op1_range (frange &r, tree type,
> const irange &lhs,
> const frange &op2,
> @@ -1682,6 +1703,7 @@ class foperator_unordered_le : public ra
> using range_operator_float::fold_range;
> using range_operator_float::op1_range;
> using range_operator_float::op2_range;
> + using range_operator_float::op1_op2_relation;
> public:
> bool fold_range (irange &r, tree type,
> const frange &op1, const frange &op2,
> @@ -1710,6 +1732,13 @@ public:
> return true;
> }
> }
> + relation_kind op1_op2_relation (const irange &lhs) const final override
> + {
> + relation_kind ret = le_op1_op2_relation (lhs);
> + if (ret == VREL_LE)
> + ret = VREL_VARYING; // Should have been VREL_UNLE.
> + return ret;
> + }
> bool op1_range (frange &r, tree type,
> const irange &lhs, const frange &op2,
> relation_trio = TRIO_VARYING) const final override;
> @@ -1789,6 +1818,7 @@ class foperator_unordered_gt : public ra
> using range_operator_float::fold_range;
> using range_operator_float::op1_range;
> using range_operator_float::op2_range;
> + using range_operator_float::op1_op2_relation;
> public:
> bool fold_range (irange &r, tree type,
> const frange &op1, const frange &op2,
> @@ -1817,6 +1847,13 @@ public:
> return true;
> }
> }
> + relation_kind op1_op2_relation (const irange &lhs) const final override
> + {
> + relation_kind ret = gt_op1_op2_relation (lhs);
> + if (ret == VREL_GT)
> + ret = VREL_VARYING; // Should have been VREL_UNGT.
> + return ret;
> + }
> bool op1_range (frange &r, tree type,
> const irange &lhs, const frange &op2,
> relation_trio = TRIO_VARYING) const final override;
> @@ -1900,6 +1937,7 @@ class foperator_unordered_ge : public ra
> using range_operator_float::fold_range;
> using range_operator_float::op1_range;
> using range_operator_float::op2_range;
> + using range_operator_float::op1_op2_relation;
> public:
> bool fold_range (irange &r, tree type,
> const frange &op1, const frange &op2,
> @@ -1928,6 +1966,13 @@ public:
> return true;
> }
> }
> + relation_kind op1_op2_relation (const irange &lhs) const final override
> + {
> + relation_kind ret = ge_op1_op2_relation (lhs);
> + if (ret == VREL_GE)
> + ret = VREL_VARYING; // Should have been VREL_UNGE.
> + return ret;
> + }
> bool op1_range (frange &r, tree type,
> const irange &lhs, const frange &op2,
> relation_trio = TRIO_VARYING) const final override;
>
> Jakub
>
On 4/11/23 04:21, Jakub Jelinek wrote:
> Hi!
>
> This patch was what I've tried first before the currently committed
> PR109386 fix. Still, I think it is the right thing until we have proper
> full set of VREL_* relations for NANs (though it would be really nice
> if op1_op2_relation could be passed either type of the comparison
> operands, or even better ranges of the two operands, such that
> we could choose if inversion of say VREL_LT is VREL_GE (if !MODE_HONOR_NANS
> (TYPE_MODE (type))) or rhs1/rhs2 ranges are guaranteed not to include
> NANs (!known_isnan && !maybe_isnan for both), or VREL_UNGE, etc.
> Anyway, the current state is that for the LE/LT/GE/GT comparisons
> we pretend the inverse is like for integral comparisons, which is
> true only if NANs can't appear in operands, while for UNLE/UNLT/UNGE/UNGT
> we don't override op1_op2_relation (so it always yields VREL_VARYING).
>
> Though, this patch regresses the
> FAIL: gcc.dg/tree-ssa/vrp-float-6.c scan-tree-dump-times evrp "Folding predicate x_.* <= y_.* to 1" 1
> test, so am not sure what to do with it. The test has explicit
> !isnan tests around it, so e.g. having the ranges passed to op1_op2_relation
> would also fix it.
I see no reason op1_op2_relation can't have ranges provided to it for
op1 and op2. There was no need originally. There are times when we
don't have a range handy and we want the simple answer, but if the
ranges are available, we could utilize them.
Attached is a patch which added op1 and op2 ranges to the routine. GORI
will utilize and pass on real ranges (which I think is the core part you
want), but the consumers in fold_using_range at this point will simply
pass in varying. There are 2 consumers in fold_using_range.. one is a
combiner for logicals, and the other is for export outgoing relations
that are not on the branch condition. The combiner could use real
ranges, but until I fix dispatch up it is very awkward to get them. The
export one simply doesn't have them without going to an calculating
them.. which would probably be expensive..
Regardless, you can at least try your enhancement using real ranges and
see if this works for you.
This bootstraps and has no regressions, and is fine by me if you want to
use it.,
Andrew
On Tue, Apr 11, 2023 at 04:58:19PM -0400, Andrew MacLeod wrote:
> This bootstraps and has no regressions, and is fine by me if you want to use
> it.
Thanks, looks nice.
My incremental patch on top of that would then be below.
Though,
FAIL: gcc.dg/tree-ssa/vrp-float-6.c scan-tree-dump-times evrp "Folding predicate x_.* <= y_.* to 1" 1
still FAILs with those 2 patches together.
Shall we just xfail it for now and find some solution for GCC 14?
2023-04-12 Jakub Jelinek <jakub@redhat.com>
* range-op-float.cc (foperator_lt::op1_op2_relation): Return
VREL_VARYING instead of VREL_GE if HONOR_NANS and op1 or op2 could be
NANs.
(foperator_le::op1_op2_relation): Similarly return VREL_VARYING
instead of VREL_GT.
(foperator_gt::op1_op2_relation): Similarly return VREL_VARYING
instead of VREL_LE.
(foperator_ge::op1_op2_relation): Similarly return VREL_VARYING
instead of VREL_LT.
(foperator_unordered_lt::op1_op2_relation,
foperator_unordered_le::op1_op2_relation,
foperator_unordered_gt::op1_op2_relation,
foperator_unordered_ge::op1_op2_relation): New.
--- gcc/range-op-float.cc.jj 2023-04-12 12:17:44.784962757 +0200
+++ gcc/range-op-float.cc 2023-04-12 12:26:11.740657502 +0200
@@ -835,10 +835,18 @@ public:
bool fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
relation_trio = TRIO_VARYING) const final override;
- relation_kind op1_op2_relation (const irange &lhs, const frange &,
- const frange &) const final override
+ relation_kind op1_op2_relation (const irange &lhs, const frange &op1,
+ const frange &op2) const final override
{
- return lt_op1_op2_relation (lhs);
+ relation_kind ret = lt_op1_op2_relation (lhs);
+ if (ret == VREL_GE
+ && HONOR_NANS (op1.type ())
+ && (op1.known_isnan ()
+ || op1.maybe_isnan ()
+ || op2.known_isnan ()
+ || op2.maybe_isnan ()))
+ ret = VREL_VARYING; // Inverse of VREL_LT is VREL_UNGE with NAN ops.
+ return ret;
}
bool op1_range (frange &r, tree type,
const irange &lhs, const frange &op2,
@@ -952,9 +960,18 @@ public:
bool fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
relation_trio rel = TRIO_VARYING) const final override;
- relation_kind op1_op2_relation (const irange &lhs, const frange &,
- const frange &) const final override
+ relation_kind op1_op2_relation (const irange &lhs, const frange &op1,
+ const frange &op2) const final override
{
+ relation_kind ret = le_op1_op2_relation (lhs);
+ if (ret == VREL_GT
+ && HONOR_NANS (op1.type ())
+ && (op1.known_isnan ()
+ || op1.maybe_isnan ()
+ || op2.known_isnan ()
+ || op2.maybe_isnan ()))
+ ret = VREL_VARYING; // Inverse of VREL_LE is VREL_UNGT with NAN ops.
+ return ret;
return le_op1_op2_relation (lhs);
}
bool op1_range (frange &r, tree type,
@@ -1063,10 +1080,18 @@ public:
bool fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
relation_trio = TRIO_VARYING) const final override;
- relation_kind op1_op2_relation (const irange &lhs, const frange &,
- const frange &) const final override
+ relation_kind op1_op2_relation (const irange &lhs, const frange &op1,
+ const frange &op2) const final override
{
- return gt_op1_op2_relation (lhs);
+ relation_kind ret = gt_op1_op2_relation (lhs);
+ if (ret == VREL_LE
+ && HONOR_NANS (op1.type ())
+ && (op1.known_isnan ()
+ || op1.maybe_isnan ()
+ || op2.known_isnan ()
+ || op2.maybe_isnan ()))
+ ret = VREL_VARYING; // Inverse of VREL_GT is VREL_UNLE with NAN ops.
+ return ret;
}
bool op1_range (frange &r, tree type,
const irange &lhs, const frange &op2,
@@ -1184,10 +1209,18 @@ public:
bool fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
relation_trio = TRIO_VARYING) const final override;
- relation_kind op1_op2_relation (const irange &lhs, const frange &,
- const frange &) const final override
+ relation_kind op1_op2_relation (const irange &lhs, const frange &op1,
+ const frange &op2) const final override
{
- return ge_op1_op2_relation (lhs);
+ relation_kind ret = ge_op1_op2_relation (lhs);
+ if (ret == VREL_LT
+ && HONOR_NANS (op1.type ())
+ && (op1.known_isnan ()
+ || op1.maybe_isnan ()
+ || op2.known_isnan ()
+ || op2.maybe_isnan ()))
+ ret = VREL_VARYING; // Inverse of VREL_GE is VREL_UNLT with NAN ops.
+ return ret;
}
bool op1_range (frange &r, tree type,
const irange &lhs, const frange &op2,
@@ -1581,6 +1614,7 @@ class foperator_unordered_lt : public ra
using range_operator_float::fold_range;
using range_operator_float::op1_range;
using range_operator_float::op2_range;
+ using range_operator_float::op1_op2_relation;
public:
bool fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
@@ -1609,6 +1643,19 @@ public:
return true;
}
}
+ relation_kind op1_op2_relation (const irange &lhs, const frange &op1,
+ const frange &op2) const final override
+ {
+ relation_kind ret = lt_op1_op2_relation (lhs);
+ if (ret == VREL_LT
+ && HONOR_NANS (op1.type ())
+ && (op1.known_isnan ()
+ || op1.maybe_isnan ()
+ || op2.known_isnan ()
+ || op2.maybe_isnan ()))
+ ret = VREL_VARYING; // Should have been VREL_UNLT with NAN ops.
+ return ret;
+ }
bool op1_range (frange &r, tree type,
const irange &lhs,
const frange &op2,
@@ -1692,6 +1739,7 @@ class foperator_unordered_le : public ra
using range_operator_float::fold_range;
using range_operator_float::op1_range;
using range_operator_float::op2_range;
+ using range_operator_float::op1_op2_relation;
public:
bool fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
@@ -1720,6 +1768,19 @@ public:
return true;
}
}
+ relation_kind op1_op2_relation (const irange &lhs, const frange &op1,
+ const frange &op2) const final override
+ {
+ relation_kind ret = le_op1_op2_relation (lhs);
+ if (ret == VREL_LE
+ && HONOR_NANS (op1.type ())
+ && (op1.known_isnan ()
+ || op1.maybe_isnan ()
+ || op2.known_isnan ()
+ || op2.maybe_isnan ()))
+ ret = VREL_VARYING; // Should have been VREL_UNLE with NAN ops.
+ return ret;
+ }
bool op1_range (frange &r, tree type,
const irange &lhs, const frange &op2,
relation_trio = TRIO_VARYING) const final override;
@@ -1799,6 +1860,7 @@ class foperator_unordered_gt : public ra
using range_operator_float::fold_range;
using range_operator_float::op1_range;
using range_operator_float::op2_range;
+ using range_operator_float::op1_op2_relation;
public:
bool fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
@@ -1827,6 +1889,19 @@ public:
return true;
}
}
+ relation_kind op1_op2_relation (const irange &lhs, const frange &op1,
+ const frange &op2) const final override
+ {
+ relation_kind ret = gt_op1_op2_relation (lhs);
+ if (ret == VREL_GT
+ && HONOR_NANS (op1.type ())
+ && (op1.known_isnan ()
+ || op1.maybe_isnan ()
+ || op2.known_isnan ()
+ || op2.maybe_isnan ()))
+ ret = VREL_VARYING; // Should have been VREL_UNGT with NAN ops.
+ return ret;
+ }
bool op1_range (frange &r, tree type,
const irange &lhs, const frange &op2,
relation_trio = TRIO_VARYING) const final override;
@@ -1910,6 +1985,7 @@ class foperator_unordered_ge : public ra
using range_operator_float::fold_range;
using range_operator_float::op1_range;
using range_operator_float::op2_range;
+ using range_operator_float::op1_op2_relation;
public:
bool fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
@@ -1938,6 +2014,19 @@ public:
return true;
}
}
+ relation_kind op1_op2_relation (const irange &lhs, const frange &op1,
+ const frange &op2) const final override
+ {
+ relation_kind ret = ge_op1_op2_relation (lhs);
+ if (ret == VREL_GE
+ && HONOR_NANS (op1.type ())
+ && (op1.known_isnan ()
+ || op1.maybe_isnan ()
+ || op2.known_isnan ()
+ || op2.maybe_isnan ()))
+ ret = VREL_VARYING; // Should have been VREL_UNGE with NAN ops.
+ return ret;
+ }
bool op1_range (frange &r, tree type,
const irange &lhs, const frange &op2,
relation_trio = TRIO_VARYING) const final override;
Jakub
On Wed, Apr 12, 2023 at 12:33:39PM +0200, Jakub Jelinek via Gcc-patches wrote:
> On Tue, Apr 11, 2023 at 04:58:19PM -0400, Andrew MacLeod wrote:
> > This bootstraps and has no regressions, and is fine by me if you want to use
> > it.
>
> Thanks, looks nice.
> My incremental patch on top of that would then be below.
>
> Though,
> FAIL: gcc.dg/tree-ssa/vrp-float-6.c scan-tree-dump-times evrp "Folding predicate x_.* <= y_.* to 1" 1
> still FAILs with those 2 patches together.
> Shall we just xfail it for now and find some solution for GCC 14?
Except that testing of this patch on top of your patch has shown
+FAIL: gfortran.dg/maxlocval_4.f90 -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions (internal compiler error: in type, at value-range.h:1157)
+FAIL: gfortran.dg/maxlocval_4.f90 -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions (test for excess errors)
+UNRESOLVED: gfortran.dg/maxlocval_4.f90 -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions compilation failed to produce executable
+FAIL: gfortran.dg/maxlocval_4.f90 -O3 -g (internal compiler error: in type, at value-range.h:1157)
+FAIL: gfortran.dg/maxlocval_4.f90 -O3 -g (test for excess errors)
+UNRESOLVED: gfortran.dg/maxlocval_4.f90 -O3 -g compilation failed to produce executable
+FAIL: gfortran.dg/minlocval_1.f90 -Os (internal compiler error: in type, at value-range.h:1157)
+FAIL: gfortran.dg/minlocval_1.f90 -Os (test for excess errors)
+UNRESOLVED: gfortran.dg/minlocval_1.f90 -Os compilation failed to produce executable
+FAIL: gfortran.dg/minlocval_4.f90 -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions (internal compiler error: in type, at value-range.h:1157)
+FAIL: gfortran.dg/minlocval_4.f90 -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions (test for excess errors)
+UNRESOLVED: gfortran.dg/minlocval_4.f90 -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions compilation failed to produce executable
+FAIL: gfortran.dg/minlocval_4.f90 -O3 -g (internal compiler error: in type, at value-range.h:1157)
+FAIL: gfortran.dg/minlocval_4.f90 -O3 -g (test for excess errors)
+UNRESOLVED: gfortran.dg/minlocval_4.f90 -O3 -g compilation failed to produce executable
+FAIL: gfortran.dg/pr104466.f90 -O (internal compiler error: in type, at value-range.h:1157)
+FAIL: gfortran.dg/pr104466.f90 -O (test for excess errors)
+FAIL: gfortran.dg/pr79315.f90 -O (internal compiler error: in type, at value-range.h:1157)
+FAIL: gfortran.dg/pr79315.f90 -O (test for excess errors)
+FAIL: gfortran.dg/pr81175.f -O (internal compiler error: in type, at value-range.h:1157)
+FAIL: gfortran.dg/pr81175.f -O (test for excess errors)
+FAIL: gfortran.dg/graphite/id-11.f -O (internal compiler error: in type, at value-range.h:1157)
+FAIL: gfortran.dg/graphite/id-11.f -O (test for excess errors)
regressions, missed the fact that frange::type ICEs on undefined_p values.
Seems the HONOR_NANS case was there just as a bad attempt to speed the test
up, we can just test known_isnan || maybe_isnan on both operands and that is
it.
With this version all those tests pass again:
2023-04-12 Jakub Jelinek <jakub@redhat.com>
* range-op-float.cc (foperator_lt::op1_op2_relation): Return
VREL_VARYING instead of VREL_GE if op1 or op2 could be NANs.
(foperator_le::op1_op2_relation): Similarly return VREL_VARYING
instead of VREL_GT.
(foperator_gt::op1_op2_relation): Similarly return VREL_VARYING
instead of VREL_LE.
(foperator_ge::op1_op2_relation): Similarly return VREL_VARYING
instead of VREL_LT.
(foperator_unordered_lt::op1_op2_relation,
foperator_unordered_le::op1_op2_relation,
foperator_unordered_gt::op1_op2_relation,
foperator_unordered_ge::op1_op2_relation): New.
--- gcc/range-op-float.cc.jj 2023-04-12 12:17:44.784962757 +0200
+++ gcc/range-op-float.cc 2023-04-12 16:07:54.948759355 +0200
@@ -835,10 +835,17 @@ public:
bool fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
relation_trio = TRIO_VARYING) const final override;
- relation_kind op1_op2_relation (const irange &lhs, const frange &,
- const frange &) const final override
+ relation_kind op1_op2_relation (const irange &lhs, const frange &op1,
+ const frange &op2) const final override
{
- return lt_op1_op2_relation (lhs);
+ relation_kind ret = lt_op1_op2_relation (lhs);
+ if (ret == VREL_GE
+ && (op1.known_isnan ()
+ || op1.maybe_isnan ()
+ || op2.known_isnan ()
+ || op2.maybe_isnan ()))
+ ret = VREL_VARYING; // Inverse of VREL_LT is VREL_UNGE with NAN ops.
+ return ret;
}
bool op1_range (frange &r, tree type,
const irange &lhs, const frange &op2,
@@ -952,9 +959,17 @@ public:
bool fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
relation_trio rel = TRIO_VARYING) const final override;
- relation_kind op1_op2_relation (const irange &lhs, const frange &,
- const frange &) const final override
+ relation_kind op1_op2_relation (const irange &lhs, const frange &op1,
+ const frange &op2) const final override
{
+ relation_kind ret = le_op1_op2_relation (lhs);
+ if (ret == VREL_GT
+ && (op1.known_isnan ()
+ || op1.maybe_isnan ()
+ || op2.known_isnan ()
+ || op2.maybe_isnan ()))
+ ret = VREL_VARYING; // Inverse of VREL_LE is VREL_UNGT with NAN ops.
+ return ret;
return le_op1_op2_relation (lhs);
}
bool op1_range (frange &r, tree type,
@@ -1063,10 +1078,17 @@ public:
bool fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
relation_trio = TRIO_VARYING) const final override;
- relation_kind op1_op2_relation (const irange &lhs, const frange &,
- const frange &) const final override
+ relation_kind op1_op2_relation (const irange &lhs, const frange &op1,
+ const frange &op2) const final override
{
- return gt_op1_op2_relation (lhs);
+ relation_kind ret = gt_op1_op2_relation (lhs);
+ if (ret == VREL_LE
+ && (op1.known_isnan ()
+ || op1.maybe_isnan ()
+ || op2.known_isnan ()
+ || op2.maybe_isnan ()))
+ ret = VREL_VARYING; // Inverse of VREL_GT is VREL_UNLE with NAN ops.
+ return ret;
}
bool op1_range (frange &r, tree type,
const irange &lhs, const frange &op2,
@@ -1184,10 +1206,17 @@ public:
bool fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
relation_trio = TRIO_VARYING) const final override;
- relation_kind op1_op2_relation (const irange &lhs, const frange &,
- const frange &) const final override
+ relation_kind op1_op2_relation (const irange &lhs, const frange &op1,
+ const frange &op2) const final override
{
- return ge_op1_op2_relation (lhs);
+ relation_kind ret = ge_op1_op2_relation (lhs);
+ if (ret == VREL_LT
+ && (op1.known_isnan ()
+ || op1.maybe_isnan ()
+ || op2.known_isnan ()
+ || op2.maybe_isnan ()))
+ ret = VREL_VARYING; // Inverse of VREL_GE is VREL_UNLT with NAN ops.
+ return ret;
}
bool op1_range (frange &r, tree type,
const irange &lhs, const frange &op2,
@@ -1581,6 +1610,7 @@ class foperator_unordered_lt : public ra
using range_operator_float::fold_range;
using range_operator_float::op1_range;
using range_operator_float::op2_range;
+ using range_operator_float::op1_op2_relation;
public:
bool fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
@@ -1609,6 +1639,18 @@ public:
return true;
}
}
+ relation_kind op1_op2_relation (const irange &lhs, const frange &op1,
+ const frange &op2) const final override
+ {
+ relation_kind ret = lt_op1_op2_relation (lhs);
+ if (ret == VREL_LT
+ && (op1.known_isnan ()
+ || op1.maybe_isnan ()
+ || op2.known_isnan ()
+ || op2.maybe_isnan ()))
+ ret = VREL_VARYING; // Should have been VREL_UNLT with NAN ops.
+ return ret;
+ }
bool op1_range (frange &r, tree type,
const irange &lhs,
const frange &op2,
@@ -1692,6 +1734,7 @@ class foperator_unordered_le : public ra
using range_operator_float::fold_range;
using range_operator_float::op1_range;
using range_operator_float::op2_range;
+ using range_operator_float::op1_op2_relation;
public:
bool fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
@@ -1720,6 +1763,18 @@ public:
return true;
}
}
+ relation_kind op1_op2_relation (const irange &lhs, const frange &op1,
+ const frange &op2) const final override
+ {
+ relation_kind ret = le_op1_op2_relation (lhs);
+ if (ret == VREL_LE
+ && (op1.known_isnan ()
+ || op1.maybe_isnan ()
+ || op2.known_isnan ()
+ || op2.maybe_isnan ()))
+ ret = VREL_VARYING; // Should have been VREL_UNLE with NAN ops.
+ return ret;
+ }
bool op1_range (frange &r, tree type,
const irange &lhs, const frange &op2,
relation_trio = TRIO_VARYING) const final override;
@@ -1799,6 +1854,7 @@ class foperator_unordered_gt : public ra
using range_operator_float::fold_range;
using range_operator_float::op1_range;
using range_operator_float::op2_range;
+ using range_operator_float::op1_op2_relation;
public:
bool fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
@@ -1827,6 +1883,18 @@ public:
return true;
}
}
+ relation_kind op1_op2_relation (const irange &lhs, const frange &op1,
+ const frange &op2) const final override
+ {
+ relation_kind ret = gt_op1_op2_relation (lhs);
+ if (ret == VREL_GT
+ && (op1.known_isnan ()
+ || op1.maybe_isnan ()
+ || op2.known_isnan ()
+ || op2.maybe_isnan ()))
+ ret = VREL_VARYING; // Should have been VREL_UNGT with NAN ops.
+ return ret;
+ }
bool op1_range (frange &r, tree type,
const irange &lhs, const frange &op2,
relation_trio = TRIO_VARYING) const final override;
@@ -1910,6 +1978,7 @@ class foperator_unordered_ge : public ra
using range_operator_float::fold_range;
using range_operator_float::op1_range;
using range_operator_float::op2_range;
+ using range_operator_float::op1_op2_relation;
public:
bool fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
@@ -1938,6 +2007,18 @@ public:
return true;
}
}
+ relation_kind op1_op2_relation (const irange &lhs, const frange &op1,
+ const frange &op2) const final override
+ {
+ relation_kind ret = ge_op1_op2_relation (lhs);
+ if (ret == VREL_GE
+ && (op1.known_isnan ()
+ || op1.maybe_isnan ()
+ || op2.known_isnan ()
+ || op2.maybe_isnan ()))
+ ret = VREL_VARYING; // Should have been VREL_UNGE with NAN ops.
+ return ret;
+ }
bool op1_range (frange &r, tree type,
const irange &lhs, const frange &op2,
relation_trio = TRIO_VARYING) const final override;
Jakub
On 12 April 2023 16:21:24 CEST, Jakub Jelinek via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>--- gcc/range-op-float.cc.jj 2023-04-12 12:17:44.784962757 +0200
>+++ gcc/range-op-float.cc 2023-04-12 16:07:54.948759355 +0200
>@@ -835,10 +835,17 @@ public:
> bool fold_range (irange &r, tree type,
> const frange &op1, const frange &op2,
> relation_trio = TRIO_VARYING) const final override;
>- relation_kind op1_op2_relation (const irange &lhs, const frange &,
>- const frange &) const final override
>+ relation_kind op1_op2_relation (const irange &lhs, const frange &op1,
>+ const frange &op2) const final override
> {
>- return lt_op1_op2_relation (lhs);
>+ relation_kind ret = lt_op1_op2_relation (lhs);
>+ if (ret == VREL_GE
>+ && (op1.known_isnan ()
>+ || op1.maybe_isnan ()
>+ || op2.known_isnan ()
>+ || op2.maybe_isnan ()))
>+ ret = VREL_VARYING; // Inverse of VREL_LT is VREL_UNGE with NAN ops.
>+ return ret;
> }
> bool op1_range (frange &r, tree type,
> const irange &lhs, const frange &op2,
>@@ -952,9 +959,17 @@ public:
> bool fold_range (irange &r, tree type,
> const frange &op1, const frange &op2,
> relation_trio rel = TRIO_VARYING) const final override;
>- relation_kind op1_op2_relation (const irange &lhs, const frange &,
>- const frange &) const final override
>+ relation_kind op1_op2_relation (const irange &lhs, const frange &op1,
>+ const frange &op2) const final override
> {
>+ relation_kind ret = le_op1_op2_relation (lhs);
>+ if (ret == VREL_GT
>+ && (op1.known_isnan ()
>+ || op1.maybe_isnan ()
>+ || op2.known_isnan ()
>+ || op2.maybe_isnan ()))
>+ ret = VREL_VARYING; // Inverse of VREL_LE is VREL_UNGT with NAN ops.
>+ return ret;
> return le_op1_op2_relation (lhs);
I think you forgot to delete the above return.
thanks,
On Wed, Apr 12, 2023 at 06:35:29PM +0200, Bernhard Reutner-Fischer wrote:
> >+ relation_kind ret = le_op1_op2_relation (lhs);
> >+ if (ret == VREL_GT
> >+ && (op1.known_isnan ()
> >+ || op1.maybe_isnan ()
> >+ || op2.known_isnan ()
> >+ || op2.maybe_isnan ()))
> >+ ret = VREL_VARYING; // Inverse of VREL_LE is VREL_UNGT with NAN ops.
> >+ return ret;
> > return le_op1_op2_relation (lhs);
>
> I think you forgot to delete the above return.
Thanks, adjusted in my copy.
Jakub
@@ -831,7 +831,10 @@ public:
relation_trio = TRIO_VARYING) const final override;
relation_kind op1_op2_relation (const irange &lhs) const final override
{
- return lt_op1_op2_relation (lhs);
+ relation_kind ret = lt_op1_op2_relation (lhs);
+ if (ret == VREL_GE)
+ ret = VREL_VARYING; // Inverse of VREL_LT is VREL_UNGE.
+ return ret;
}
bool op1_range (frange &r, tree type,
const irange &lhs, const frange &op2,
@@ -947,6 +950,10 @@ public:
relation_trio rel = TRIO_VARYING) const final override;
relation_kind op1_op2_relation (const irange &lhs) const final override
{
+ relation_kind ret = le_op1_op2_relation (lhs);
+ if (ret == VREL_GT)
+ ret = VREL_VARYING; // Inverse of VREL_LE is VREL_UNGT.
+ return ret;
return le_op1_op2_relation (lhs);
}
bool op1_range (frange &r, tree type,
@@ -1057,7 +1064,10 @@ public:
relation_trio = TRIO_VARYING) const final override;
relation_kind op1_op2_relation (const irange &lhs) const final override
{
- return gt_op1_op2_relation (lhs);
+ relation_kind ret = gt_op1_op2_relation (lhs);
+ if (ret == VREL_LE)
+ ret = VREL_VARYING; // Inverse of VREL_GT is VREL_UNLE.
+ return ret;
}
bool op1_range (frange &r, tree type,
const irange &lhs, const frange &op2,
@@ -1177,7 +1187,10 @@ public:
relation_trio = TRIO_VARYING) const final override;
relation_kind op1_op2_relation (const irange &lhs) const final override
{
- return ge_op1_op2_relation (lhs);
+ relation_kind ret = ge_op1_op2_relation (lhs);
+ if (ret == VREL_LT)
+ ret = VREL_VARYING; // Inverse of VREL_GE is VREL_UNLT.
+ return ret;
}
bool op1_range (frange &r, tree type,
const irange &lhs, const frange &op2,
@@ -1571,6 +1584,7 @@ class foperator_unordered_lt : public ra
using range_operator_float::fold_range;
using range_operator_float::op1_range;
using range_operator_float::op2_range;
+ using range_operator_float::op1_op2_relation;
public:
bool fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
@@ -1599,6 +1613,13 @@ public:
return true;
}
}
+ relation_kind op1_op2_relation (const irange &lhs) const final override
+ {
+ relation_kind ret = lt_op1_op2_relation (lhs);
+ if (ret == VREL_LT)
+ ret = VREL_VARYING; // Should have been VREL_UNLT.
+ return ret;
+ }
bool op1_range (frange &r, tree type,
const irange &lhs,
const frange &op2,
@@ -1682,6 +1703,7 @@ class foperator_unordered_le : public ra
using range_operator_float::fold_range;
using range_operator_float::op1_range;
using range_operator_float::op2_range;
+ using range_operator_float::op1_op2_relation;
public:
bool fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
@@ -1710,6 +1732,13 @@ public:
return true;
}
}
+ relation_kind op1_op2_relation (const irange &lhs) const final override
+ {
+ relation_kind ret = le_op1_op2_relation (lhs);
+ if (ret == VREL_LE)
+ ret = VREL_VARYING; // Should have been VREL_UNLE.
+ return ret;
+ }
bool op1_range (frange &r, tree type,
const irange &lhs, const frange &op2,
relation_trio = TRIO_VARYING) const final override;
@@ -1789,6 +1818,7 @@ class foperator_unordered_gt : public ra
using range_operator_float::fold_range;
using range_operator_float::op1_range;
using range_operator_float::op2_range;
+ using range_operator_float::op1_op2_relation;
public:
bool fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
@@ -1817,6 +1847,13 @@ public:
return true;
}
}
+ relation_kind op1_op2_relation (const irange &lhs) const final override
+ {
+ relation_kind ret = gt_op1_op2_relation (lhs);
+ if (ret == VREL_GT)
+ ret = VREL_VARYING; // Should have been VREL_UNGT.
+ return ret;
+ }
bool op1_range (frange &r, tree type,
const irange &lhs, const frange &op2,
relation_trio = TRIO_VARYING) const final override;
@@ -1900,6 +1937,7 @@ class foperator_unordered_ge : public ra
using range_operator_float::fold_range;
using range_operator_float::op1_range;
using range_operator_float::op2_range;
+ using range_operator_float::op1_op2_relation;
public:
bool fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
@@ -1928,6 +1966,13 @@ public:
return true;
}
}
+ relation_kind op1_op2_relation (const irange &lhs) const final override
+ {
+ relation_kind ret = ge_op1_op2_relation (lhs);
+ if (ret == VREL_GE)
+ ret = VREL_VARYING; // Should have been VREL_UNGE.
+ return ret;
+ }
bool op1_range (frange &r, tree type,
const irange &lhs, const frange &op2,
relation_trio = TRIO_VARYING) const final override;