Re: [RFC PATCH] range-op-float: Fix up op1_op2_relation of comparisons
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
Re: [RFC PATCH] range-op-float: Fix up op1_op2_relation of comparisons
On 12 April 2023 16:21:24 CEST, Jakub Jelinek via Gcc-patches 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 , tree type, > const frange , const frange , > relation_trio = TRIO_VARYING) const final override; >- relation_kind op1_op2_relation (const irange , const frange &, >-const frange &) const final override >+ relation_kind op1_op2_relation (const irange , const frange , >+const frange ) 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 , tree type, > const irange , const frange , >@@ -952,9 +959,17 @@ public: > bool fold_range (irange , tree type, > const frange , const frange , > relation_trio rel = TRIO_VARYING) const final override; >- relation_kind op1_op2_relation (const irange , const frange &, >-const frange &) const final override >+ relation_kind op1_op2_relation (const irange , const frange , >+const frange ) 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,
Re: [RFC PATCH] range-op-float: Fix up op1_op2_relation of comparisons
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 * 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.jj2023-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 , tree type, const frange , const frange , relation_trio = TRIO_VARYING) const final override; - relation_kind op1_op2_relation (const irange , const frange &, - const frange &) const final override + relation_kind op1_op2_relation (const irange , const frange , + const frange ) 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 , tree type,
Re: [RFC PATCH] range-op-float: Fix up op1_op2_relation of comparisons
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 * 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.jj2023-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 , tree type, const frange , const frange , relation_trio = TRIO_VARYING) const final override; - relation_kind op1_op2_relation (const irange , const frange &, - const frange &) const final override + relation_kind op1_op2_relation (const irange , const frange , + const frange ) 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 , tree type, const irange , const frange , @@ -952,9 +960,18 @@ public: bool fold_range (irange , tree type, const frange , const frange , relation_trio rel = TRIO_VARYING) const final override; - relation_kind op1_op2_relation (const irange , const frange &, - const frange &) const final override + relation_kind op1_op2_relation (const irange , const frange , + const frange ) 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 , tree type, @@ -1063,10 +1080,18 @@ public: bool fold_range (irange , tree type, const frange , const frange , relation_trio = TRIO_VARYING) const final override; - relation_kind op1_op2_relation (const irange , const frange &, - const frange &) const final override + relation_kind op1_op2_relation (const irange , const frange , + const frange ) 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 , tree type, const irange , const frange , @@ -1184,10 +1209,18 @@ public: bool fold_range (irange , tree type, const frange , const frange , relation_trio = TRIO_VARYING) const final override; - relation_kind op1_op2_relation (const irange , const frange &, - const frange &) const final override + relation_kind op1_op2_relation (const irange , const frange , + const frange ) 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 , tree type, const irange , const frange , @@
Re: [RFC PATCH] range-op-float: Fix up op1_op2_relation of comparisons
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 commit 3715234f2cba21f2b9ec6c609b6f058d1d8af500 Author: Andrew MacLeod Date: Tue Apr 11 12:25:49 2023 -0400 Add op1 and op2 ranges to op1_op2_relation. * gimple-range-fold.cc (fold_using_range::relation_fold_and_or): Provide VARYING for op1 and op2 when calling op1_op2_relation. (fur_source::register_outgoing_edges): Ditto. * gimple-range-gori.cc (gori_compute::compute_operand1_range): Pass op1 and op2 ranges to op1_op2_relation. (gori_compute::compute_operand2_range): Ditto. * range-op-float.cc (*::op1_op2_relation): Adjust params. * range-op.cc (*::op1_op2_relation): Adjust params. * range-op.h (*::op1_op2_relation): Adjust params. diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc index e81f6b3699e..3170b1e71a1 100644 --- a/gcc/gimple-range-fold.cc +++ b/gcc/gimple-range-fold.cc @@ -1051,9 +1051,11 @@ fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s, return; int_range<2> bool_one (boolean_true_node, boolean_true_node); + Value_Range op (TREE_TYPE (ssa1)); + op.set_varying (TREE_TYPE (ssa1)); - relation_kind relation1 = handler1.op1_op2_relation (bool_one); - relation_kind relation2 = handler2.op1_op2_relation (bool_one); + relation_kind relation1 = handler1.op1_op2_relation (bool_one, op, op); + relation_kind relation2 = handler2.op1_op2_relation (bool_one, op, op); if (relation1 == VREL_VARYING || relation2 == VREL_VARYING) return; @@ -1125,15 +1127,17 @@ fur_source::register_outgoing_edges (gcond *s, irange _range, edge e0, edge tree ssa2 = gimple_range_ssa_p (handler.operand2 ()); if (ssa1 && ssa2) { + Value_Range op (TREE_TYPE (ssa1)); + op.set_varying (TREE_TYPE (ssa1)); if (e0) { - relation_kind relation = handler.op1_op2_relation (e0_range); + relation_kind relation = handler.op1_op2_relation (e0_range, op, op); if (relation != VREL_VARYING) register_relation (e0, relation, ssa1, ssa2); } if (e1) { - relation_kind relation = handler.op1_op2_relation (e1_range); + relation_kind relation = handler.op1_op2_relation (e1_range, op, op); if (relation != VREL_VARYING) register_relation (e1, relation, ssa1, ssa2); } @@ -1160,17 +1164,19 @@ fur_source::register_outgoing_edges (gcond *s, irange _range, edge e0, edge Value_Range r (TREE_TYPE (name)); if (ssa1 && ssa2) { + Value_Range op (TREE_TYPE (ssa1)); + op.set_varying (TREE_TYPE (ssa1)); if (e0 && gori ()->outgoing_edge_range_p (r, e0, name, *m_query) && r.singleton_p ()) { - relation_kind relation = handler.op1_op2_relation (r); + relation_kind
Re: [RFC PATCH] range-op-float: Fix up op1_op2_relation of comparisons
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 * 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.jj2023-04-01 09:32:02.635423345 +0200 +++ gcc/range-op-float.cc 2023-04-03 10:42:54.0 +0200 @@ -831,7 +831,10 @@ public: relation_trio = TRIO_VARYING) const final override; relation_kind op1_op2_relation (const irange ) 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 , tree type, const irange , const frange , @@ -947,6 +950,10 @@ public: relation_trio rel = TRIO_VARYING) const final override; relation_kind op1_op2_relation (const irange ) 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 , tree type, @@ -1057,7 +1064,10 @@ public: relation_trio = TRIO_VARYING) const final override; relation_kind op1_op2_relation (const irange ) 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 , tree type, const irange , const frange , @@ -1177,7 +1187,10 @@ public: relation_trio = TRIO_VARYING) const final override; relation_kind op1_op2_relation (const irange ) 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 , tree type, const irange , const frange , @@ -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 , tree type, const frange , const frange , @@ -1599,6 +1613,13 @@ public: return true; } } + relation_kind op1_op2_relation (const irange ) 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 , tree type, const irange , const frange , @@ -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 , tree type, const frange , const frange , @@ -1710,6 +1732,13 @@ public: return true;
[RFC PATCH] range-op-float: Fix up op1_op2_relation of comparisons
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 * 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.jj2023-04-01 09:32:02.635423345 +0200 +++ gcc/range-op-float.cc 2023-04-03 10:42:54.0 +0200 @@ -831,7 +831,10 @@ public: relation_trio = TRIO_VARYING) const final override; relation_kind op1_op2_relation (const irange ) 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 , tree type, const irange , const frange , @@ -947,6 +950,10 @@ public: relation_trio rel = TRIO_VARYING) const final override; relation_kind op1_op2_relation (const irange ) 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 , tree type, @@ -1057,7 +1064,10 @@ public: relation_trio = TRIO_VARYING) const final override; relation_kind op1_op2_relation (const irange ) 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 , tree type, const irange , const frange , @@ -1177,7 +1187,10 @@ public: relation_trio = TRIO_VARYING) const final override; relation_kind op1_op2_relation (const irange ) 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 , tree type, const irange , const frange , @@ -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 , tree type, const frange , const frange , @@ -1599,6 +1613,13 @@ public: return true; } } + relation_kind op1_op2_relation (const irange ) 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 , tree type, const irange , const frange , @@ -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 , tree type, const frange , const frange , @@ -1710,6 +1732,13 @@ public: return true; } } + relation_kind op1_op2_relation (const irange ) const final override + { +relation_kind ret = le_op1_op2_relation (lhs); +if (ret == VREL_LE) +