public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Aldy Hernandez <aldyh@redhat.com>
To: GCC patches <gcc-patches@gcc.gnu.org>,
	"MacLeod, Andrew" <amacleod@redhat.com>
Cc: Jeff Law <jeffreyalaw@gmail.com>,
	Richard Biener <richard.guenther@gmail.com>,
	 Jakub Jelinek <jakub@redhat.com>,
	Roger Sayle <roger@nextmovesoftware.com>
Subject: Re: [RFA] Implement basic range operators to enable floating point VRP.
Date: Tue, 2 Aug 2022 14:57:10 +0200	[thread overview]
Message-ID: <CAGm3qMXzZGVBWwjcWdxd_3um57FOcEiLUWPBQ--qX+MLiUbvTw@mail.gmail.com> (raw)
In-Reply-To: <CAGm3qMV3TPrztsD1qMop1SGbnsXHajVUTcqkxHYHJZptCKT93w@mail.gmail.com>

Alright, I know everyon'es pretty busy and I am blocking myself here,
so I hereby approve my own patch, since I am the maintainer ;-).

After all, I'd like to have 5-6 days to field any possible fallout
before I disappear off to a tropical island to drink mojitos and beer.
Ok, not really-- just changing diapers, but without a laptop.

Feedback still welcome; I'll just address it as a follow-up.

Pushed.
Aldy

On Sun, Jul 31, 2022 at 8:11 PM Aldy Hernandez <aldyh@redhat.com> wrote:
>
> PING
>
> Andrew, anyone, would you mind giving this a once over?  I realize
> reviewing ranger's range-op code is not on anyone's list of
> priorities, but I could use a sanity check.
>
> The patch is sufficiently self-contained to easily catch anything
> caused by it, and I'd like to commit earlier in the week to have
> enough time to field any possible fallout before I take a few days off
> next week.
>
> Updated patch attached.
>
> Thanks.
> Aldy
>
> On Mon, Jul 25, 2022 at 8:50 PM Aldy Hernandez <aldyh@redhat.com> wrote:
> >
> > Without further ado, here is the implementation for floating point
> > range operators, plus the switch to enable all ranger clients to
> > handle floats.
> >
> > These are bare bone implementations good enough for relation operators
> > to work, while keeping the NAN bits up to date in the frange.  There
> > is also minimal support for keeping track of +-INF when it is obvious.
> >
> > I have included some basic tests to help get a feel of what is
> > ultimately handled.
> >
> > Since range-ops is the domain specific core of ranger, I think its
> > best if a global maintainer or an FP expert could review this.
> >
> > OK for trunk?
> >
> > Tested on x86-64 Linux.
> >
> > p.s. I haven't done extensive testing in DOM, but with this we're mighty
> > close for the forward threader there to be replaceable with the backward
> > threader, thus removing the last use of the forward threader.
> >
> > gcc/ChangeLog:
> >
> >         * range-op-float.cc (finite_operands_p): New.
> >         (frelop_early_resolve): New.
> >         (default_frelop_fold_range): New.
> >         (class foperator_equal): New.
> >         (class foperator_not_equal): New.
> >         (class foperator_lt): New.
> >         (class foperator_le): New.
> >         (class foperator_gt): New.
> >         (class foperator_ge): New.
> >         (class foperator_unordered): New.
> >         (class foperator_ordered): New.
> >         (class foperator_relop_unknown): New.
> >         (floating_op_table::floating_op_table): Add above classes to
> >         floating op table.
> >         * value-range.h (frange::supports_p): Enable.
> >
> > gcc/testsuite/ChangeLog:
> >
> >         * g++.dg/opt/pr94589-2.C: Add notes.
> >         * gcc.dg/tree-ssa/vrp-float-1.c: New test.
> >         * gcc.dg/tree-ssa/vrp-float-11.c: New test.
> >         * gcc.dg/tree-ssa/vrp-float-3.c: New test.
> >         * gcc.dg/tree-ssa/vrp-float-4.c: New test.
> >         * gcc.dg/tree-ssa/vrp-float-6.c: New test.
> >         * gcc.dg/tree-ssa/vrp-float-7.c: New test.
> >         * gcc.dg/tree-ssa/vrp-float-8.c: New test.
> > ---
> >  gcc/range-op-float.cc                        | 564 +++++++++++++++++++
> >  gcc/testsuite/g++.dg/opt/pr94589-2.C         |  25 +
> >  gcc/testsuite/gcc.dg/tree-ssa/vrp-float-1.c  |  19 +
> >  gcc/testsuite/gcc.dg/tree-ssa/vrp-float-11.c |  26 +
> >  gcc/testsuite/gcc.dg/tree-ssa/vrp-float-3.c  |  18 +
> >  gcc/testsuite/gcc.dg/tree-ssa/vrp-float-4.c  |  16 +
> >  gcc/testsuite/gcc.dg/tree-ssa/vrp-float-6.c  |  20 +
> >  gcc/testsuite/gcc.dg/tree-ssa/vrp-float-7.c  |  14 +
> >  gcc/testsuite/gcc.dg/tree-ssa/vrp-float-8.c  |  26 +
> >  gcc/value-range.h                            |   3 +-
> >  10 files changed, 729 insertions(+), 2 deletions(-)
> >  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-float-1.c
> >  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-float-11.c
> >  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-float-3.c
> >  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-float-4.c
> >  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-float-6.c
> >  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-float-7.c
> >  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-float-8.c
> >
> > diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
> > index 8e9d83e3827..d94ff6f915a 100644
> > --- a/gcc/range-op-float.cc
> > +++ b/gcc/range-op-float.cc
> > @@ -150,6 +150,50 @@ range_operator_float::op1_op2_relation (const irange &lhs ATTRIBUTE_UNUSED) cons
> >    return VREL_VARYING;
> >  }
> >
> > +// Return TRUE if OP1 and OP2 are known to be free of NANs.
> > +
> > +static inline bool
> > +finite_operands_p (const frange &op1, const frange &op2)
> > +{
> > +  return (flag_finite_math_only
> > +         || (op1.get_nan ().no_p ()
> > +             && op2.get_nan ().no_p ()));
> > +}
> > +
> > +// Floating version of relop_early_resolve that takes into account NAN
> > +// and -ffinite-math-only.
> > +
> > +inline bool
> > +frelop_early_resolve (irange &r, tree type,
> > +                     const frange &op1, const frange &op2,
> > +                     relation_kind rel, relation_kind my_rel)
> > +{
> > +  // 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 (finite_operands_p (op1, op2)
> > +         && relop_early_resolve (r, type, op1, op2, rel, my_rel));
> > +}
> > +
> > +// Default implementation of fold_range for relational operators.
> > +// This amounts to passing on any known relations from the oracle, iff
> > +// we know the operands are not NAN or -ffinite-math-only holds.
> > +
> > +static inline bool
> > +default_frelop_fold_range (irange &r, tree type,
> > +                         const frange &op1, const frange &op2,
> > +                         relation_kind rel, relation_kind my_rel)
> > +{
> > +  if (frelop_early_resolve (r, type, op1, op2, rel, my_rel))
> > +    return true;
> > +
> > +  r.set_varying (type);
> > +  return true;
> > +}
> > +
> >  class foperator_identity : public range_operator_float
> >  {
> >    using range_operator_float::fold_range;
> > @@ -172,6 +216,509 @@ class foperator_identity : public range_operator_float
> >  public:
> >  } fop_identity;
> >
> > +class foperator_equal : public range_operator_float
> > +{
> > +  using range_operator_float::fold_range;
> > +  using range_operator_float::op1_range;
> > +  using range_operator_float::op2_range;
> > +
> > +  bool fold_range (irange &r, tree type,
> > +                  const frange &op1, const frange &op2,
> > +                  relation_kind rel) const final override
> > +  {
> > +    return default_frelop_fold_range (r, type, op1, op2, rel, VREL_EQ);
> > +  }
> > +  relation_kind op1_op2_relation (const irange &lhs) const final override
> > +  {
> > +    return equal_op1_op2_relation (lhs);
> > +  }
> > +  bool op1_range (frange &r, tree type,
> > +                 const irange &lhs, const frange &op2,
> > +                 relation_kind rel) const final override;
> > +  bool op2_range (frange &r, tree type,
> > +                 const irange &lhs, const frange &op1,
> > +                 relation_kind rel) const final override
> > +  {
> > +    return op1_range (r, type, lhs, op1, rel);
> > +  }
> > +} fop_equal;
> > +
> > +bool
> > +foperator_equal::op1_range (frange &r, tree type,
> > +                           const irange &lhs,
> > +                           const frange &op2 ATTRIBUTE_UNUSED,
> > +                           relation_kind rel) const
> > +{
> > +  switch (get_bool_state (r, lhs, type))
> > +    {
> > +    case BRS_TRUE:
> > +      r.set_varying (type);
> > +      // The TRUE side of op1 == op2 implies op1 is !NAN.
> > +      r.set_nan (fp_prop::NO);
> > +      break;
> > +
> > +    case BRS_FALSE:
> > +      r.set_varying (type);
> > +      // The FALSE side of op1 ORDERED op1 implies op1 is a NAN.
> > +      if (rel == VREL_EQ)
> > +       r.set_nan (fp_prop::YES);
> > +      break;
> > +
> > +    default:
> > +      break;
> > +    }
> > +  return true;
> > +}
> > +
> > +class foperator_not_equal : public range_operator_float
> > +{
> > +  using range_operator_float::fold_range;
> > +  using range_operator_float::op1_range;
> > +
> > +  bool fold_range (irange &r, tree type,
> > +                  const frange &op1, const frange &op2,
> > +                  relation_kind rel) const final override
> > +  {
> > +    return default_frelop_fold_range (r, type, op1, op2, rel, VREL_NE);
> > +  }
> > +  relation_kind op1_op2_relation (const irange &lhs) const final override
> > +  {
> > +    return not_equal_op1_op2_relation (lhs);
> > +  }
> > +  bool op1_range (frange &r, tree type,
> > +                 const irange &lhs, const frange &op2,
> > +                 relation_kind rel) const final override;
> > +} fop_not_equal;
> > +
> > +bool
> > +foperator_not_equal::op1_range (frange &r, tree type,
> > +                               const irange &lhs,
> > +                               const frange &op2 ATTRIBUTE_UNUSED,
> > +                               relation_kind) const
> > +{
> > +  switch (get_bool_state (r, lhs, type))
> > +    {
> > +    case BRS_TRUE:
> > +      r.set_varying (type);
> > +      break;
> > +
> > +    case BRS_FALSE:
> > +      r.set_varying (type);
> > +      // The FALSE side of op1 != op2 implies op1 is !NAN.
> > +      r.set_nan (fp_prop::NO);
> > +      break;
> > +
> > +    default:
> > +      break;
> > +    }
> > +  return true;
> > +}
> > +
> > +class foperator_lt : public range_operator_float
> > +{
> > +  using range_operator_float::fold_range;
> > +  using range_operator_float::op1_range;
> > +  using range_operator_float::op2_range;
> > +
> > +  bool fold_range (irange &r, tree type,
> > +                  const frange &op1, const frange &op2,
> > +                  relation_kind rel) const final override
> > +  {
> > +    return default_frelop_fold_range (r, type, op1, op2, rel, VREL_LT);
> > +  }
> > +  relation_kind op1_op2_relation (const irange &lhs) const final override
> > +  {
> > +    return lt_op1_op2_relation (lhs);
> > +  }
> > +  bool op1_range (frange &r, tree type,
> > +                 const irange &lhs, const frange &op2,
> > +                 relation_kind rel) const final override;
> > +  bool op2_range (frange &r, tree type,
> > +                 const irange &lhs, const frange &op1,
> > +                 relation_kind rel) const final override;
> > +} fop_lt;
> > +
> > +bool
> > +foperator_lt::op1_range (frange &r,
> > +                        tree type,
> > +                        const irange &lhs,
> > +                        const frange &op2 ATTRIBUTE_UNUSED,
> > +                        relation_kind) const
> > +{
> > +  switch (get_bool_state (r, lhs, type))
> > +    {
> > +    case BRS_TRUE:
> > +      r.set_varying (type);
> > +      // The TRUE side of op1 < op2 implies op1 is !NAN and !INF.
> > +      r.set_nan (fp_prop::NO);
> > +      r.set_inf (fp_prop::NO);
> > +      break;
> > +
> > +    case BRS_FALSE:
> > +      r.set_varying (type);
> > +      break;
> > +
> > +    default:
> > +      break;
> > +    }
> > +  return true;
> > +}
> > +
> > +bool
> > +foperator_lt::op2_range (frange &r,
> > +                        tree type,
> > +                        const irange &lhs,
> > +                        const frange &op1 ATTRIBUTE_UNUSED,
> > +                        relation_kind) const
> > +{
> > +  switch (get_bool_state (r, lhs, type))
> > +    {
> > +    case BRS_TRUE:
> > +      r.set_varying (type);
> > +      // The TRUE side of op1 < op2 implies op2 is !NAN and !NINF.
> > +      r.set_nan (fp_prop::NO);
> > +      r.set_ninf (fp_prop::NO);
> > +      break;
> > +
> > +    case BRS_FALSE:
> > +      r.set_varying (type);
> > +      break;
> > +
> > +    default:
> > +      break;
> > +    }
> > +  return true;
> > +}
> > +
> > +class foperator_le : public range_operator_float
> > +{
> > +  using range_operator_float::fold_range;
> > +  using range_operator_float::op1_range;
> > +  using range_operator_float::op2_range;
> > +
> > +  bool fold_range (irange &r, tree type,
> > +                  const frange &op1, const frange &op2,
> > +                  relation_kind rel) const final override
> > +  {
> > +    return default_frelop_fold_range (r, type, op1, op2, rel, VREL_LE);
> > +  }
> > +  relation_kind op1_op2_relation (const irange &lhs) const final override
> > +  {
> > +    return le_op1_op2_relation (lhs);
> > +  }
> > +  bool op1_range (frange &r, tree type,
> > +                 const irange &lhs, const frange &op2,
> > +                 relation_kind rel) const final override;
> > +  bool op2_range (frange &r, tree type,
> > +                 const irange &lhs, const frange &op1,
> > +                 relation_kind rel) const final override
> > +  {
> > +    return op1_range (r, type, lhs, op1, rel);
> > +  }
> > +} fop_le;
> > +
> > +bool
> > +foperator_le::op1_range (frange &r,
> > +                        tree type,
> > +                        const irange &lhs,
> > +                        const frange &op2 ATTRIBUTE_UNUSED,
> > +                        relation_kind) const
> > +{
> > +  switch (get_bool_state (r, lhs, type))
> > +    {
> > +    case BRS_TRUE:
> > +      r.set_varying (type);
> > +      // The TRUE side of op1 <= op2 implies op1 is !NAN.
> > +      r.set_nan (fp_prop::NO);
> > +      break;
> > +
> > +    case BRS_FALSE:
> > +      r.set_varying (type);
> > +      break;
> > +
> > +    default:
> > +      break;
> > +    }
> > +  return true;
> > +}
> > +
> > +class foperator_gt : public range_operator_float
> > +{
> > +  using range_operator_float::fold_range;
> > +  using range_operator_float::op1_range;
> > +  using range_operator_float::op2_range;
> > +
> > +  bool fold_range (irange &r, tree type,
> > +                  const frange &op1, const frange &op2,
> > +                  relation_kind rel) const final override
> > +  {
> > +    return default_frelop_fold_range (r, type, op1, op2, rel, VREL_GT);
> > +  }
> > +  relation_kind op1_op2_relation (const irange &lhs) const final override
> > +  {
> > +    return gt_op1_op2_relation (lhs);
> > +  }
> > +  bool op1_range (frange &r, tree type,
> > +                 const irange &lhs, const frange &op2,
> > +                 relation_kind rel) const final override;
> > +  bool op2_range (frange &r, tree type,
> > +                 const irange &lhs, const frange &op1,
> > +                 relation_kind rel) const final override;
> > +} fop_gt;
> > +
> > +bool
> > +foperator_gt::op1_range (frange &r,
> > +                        tree type,
> > +                        const irange &lhs,
> > +                        const frange &op2 ATTRIBUTE_UNUSED,
> > +                        relation_kind) const
> > +{
> > +  switch (get_bool_state (r, lhs, type))
> > +    {
> > +    case BRS_TRUE:
> > +      r.set_varying (type);
> > +      // The TRUE side of op1 > op2 implies op1 is !NAN and !NINF.
> > +      r.set_nan (fp_prop::NO);
> > +      r.set_ninf (fp_prop::NO);
> > +      break;
> > +
> > +    case BRS_FALSE:
> > +      r.set_varying (type);
> > +      break;
> > +
> > +    default:
> > +      break;
> > +    }
> > +  return true;
> > +}
> > +
> > +bool
> > +foperator_gt::op2_range (frange &r,
> > +                        tree type,
> > +                        const irange &lhs,
> > +                        const frange &op1 ATTRIBUTE_UNUSED,
> > +                        relation_kind) const
> > +{
> > +  switch (get_bool_state (r, lhs, type))
> > +    {
> > +    case BRS_TRUE:
> > +      r.set_varying (type);
> > +      // The TRUE side of op1 > op2 implies op2 is !NAN and !INF.
> > +      r.set_nan (fp_prop::NO);
> > +      r.set_inf (fp_prop::NO);
> > +      break;
> > +
> > +    case BRS_FALSE:
> > +      r.set_varying (type);
> > +      break;
> > +
> > +    default:
> > +      break;
> > +    }
> > +  return true;
> > +}
> > +
> > +class foperator_ge : public range_operator_float
> > +{
> > +  using range_operator_float::fold_range;
> > +  using range_operator_float::op1_range;
> > +  using range_operator_float::op2_range;
> > +
> > +  bool fold_range (irange &r, tree type,
> > +                  const frange &op1, const frange &op2,
> > +                  relation_kind rel) const final override
> > +  {
> > +    return default_frelop_fold_range (r, type, op1, op2, rel, VREL_GE);
> > +  }
> > +  relation_kind op1_op2_relation (const irange &lhs) const final override
> > +  {
> > +    return ge_op1_op2_relation (lhs);
> > +  }
> > +  bool op1_range (frange &r, tree type,
> > +                 const irange &lhs, const frange &op2,
> > +                 relation_kind rel) const final override;
> > +  bool op2_range (frange &r, tree type,
> > +                 const irange &lhs, const frange &op1,
> > +                 relation_kind rel) const final override
> > +  {
> > +    return op1_range (r, type, lhs, op1, rel);
> > +  }
> > +} fop_ge;
> > +
> > +bool
> > +foperator_ge::op1_range (frange &r,
> > +                        tree type,
> > +                        const irange &lhs,
> > +                        const frange &op2 ATTRIBUTE_UNUSED,
> > +                        relation_kind) const
> > +{
> > +  switch (get_bool_state (r, lhs, type))
> > +    {
> > +    case BRS_TRUE:
> > +      r.set_varying (type);
> > +      // The TRUE side of op1 >= op2 implies op1 is !NAN.
> > +      r.set_nan (fp_prop::NO);
> > +      break;
> > +
> > +    case BRS_FALSE:
> > +      r.set_varying (type);
> > +      break;
> > +
> > +    default:
> > +      break;
> > +    }
> > +  return true;
> > +}
> > +
> > +// UNORDERED_EXPR comparison.
> > +
> > +class foperator_unordered : public range_operator_float
> > +{
> > +  using range_operator_float::fold_range;
> > +  using range_operator_float::op1_range;
> > +  using range_operator_float::op2_range;
> > +
> > +public:
> > +  bool fold_range (irange &r, tree type,
> > +                  const frange &op1, const frange &op2,
> > +                  relation_kind rel) const final override;
> > +  bool op1_range (frange &r, tree type,
> > +                 const irange &lhs, const frange &op2,
> > +                 relation_kind rel) const final override;
> > +  bool op2_range (frange &r, tree type,
> > +                 const irange &lhs, const frange &op1,
> > +                 relation_kind rel) const final override
> > +  {
> > +    return op1_range (r, type, lhs, op1, rel);
> > +  }
> > +} fop_unordered;
> > +
> > +bool
> > +foperator_unordered::fold_range (irange &r, tree type,
> > +                                const frange &op1, const frange &op2,
> > +                                relation_kind) const
> > +{
> > +  // UNORDERED is TRUE if either operand is a NAN.
> > +  if (op1.get_nan ().yes_p () || op2.get_nan ().yes_p ())
> > +    r = range_true (type);
> > +  // UNORDERED is FALSE if neither operand is a NAN.
> > +  else if (op1.get_nan ().no_p () && op2.get_nan ().no_p ())
> > +    r = range_false (type);
> > +  else
> > +    r = range_true_and_false (type);
> > +  return true;
> > +}
> > +
> > +bool
> > +foperator_unordered::op1_range (frange &r, tree type,
> > +                               const irange &lhs,
> > +                               const frange &op2 ATTRIBUTE_UNUSED,
> > +                               relation_kind) const
> > +{
> > +  switch (get_bool_state (r, lhs, type))
> > +    {
> > +    case BRS_TRUE:
> > +      r.set_varying (type);
> > +      // Since at least one operand must be NAN, if one of them is
> > +      // not, the other must be.
> > +      if (op2.get_nan ().no_p ())
> > +       r.set_nan (fp_prop::YES);
> > +      break;
> > +
> > +    case BRS_FALSE:
> > +      r.set_varying (type);
> > +      // A false UNORDERED means both operands are !NAN.
> > +      r.set_nan (fp_prop::NO);
> > +      break;
> > +
> > +    default:
> > +      break;
> > +    }
> > +  return true;
> > +}
> > +
> > +// ORDERED_EXPR comparison.
> > +
> > +class foperator_ordered : public range_operator_float
> > +{
> > +  using range_operator_float::fold_range;
> > +  using range_operator_float::op1_range;
> > +  using range_operator_float::op2_range;
> > +
> > +public:
> > +  bool fold_range (irange &r, tree type,
> > +                  const frange &op1, const frange &op2,
> > +                  relation_kind rel) const final override;
> > +  bool op1_range (frange &r, tree type,
> > +                 const irange &lhs, const frange &op2,
> > +                 relation_kind rel) const final override;
> > +  bool op2_range (frange &r, tree type,
> > +                 const irange &lhs, const frange &op1,
> > +                 relation_kind rel) const final override
> > +  {
> > +    return op1_range (r, type, lhs, op1, rel);
> > +  }
> > +} fop_ordered;
> > +
> > +bool
> > +foperator_ordered::fold_range (irange &r, tree type,
> > +                              const frange &op1, const frange &op2,
> > +                              relation_kind) const
> > +{
> > +  // ORDERED is TRUE if neither operand is a NAN.
> > +  if (op1.get_nan ().no_p () && op2.get_nan ().no_p ())
> > +    r = range_true (type);
> > +  // ORDERED is FALSE if either operand is a NAN.
> > +  else if (op1.get_nan ().yes_p () || op2.get_nan ().yes_p ())
> > +    r = range_false (type);
> > +  else
> > +    r = range_true_and_false (type);
> > +  return true;
> > +}
> > +
> > +bool
> > +foperator_ordered::op1_range (frange &r, tree type,
> > +                             const irange &lhs,
> > +                             const frange &op2 ATTRIBUTE_UNUSED,
> > +                             relation_kind rel) const
> > +{
> > +  switch (get_bool_state (r, lhs, type))
> > +    {
> > +    case BRS_TRUE:
> > +      r.set_varying (type);
> > +      // The TRUE side of op1 UNORDERED op2 implies op1 is !NAN.
> > +      r.set_nan (fp_prop::NO);
> > +      break;
> > +
> > +    case BRS_FALSE:
> > +      r.set_varying (type);
> > +      // The FALSE side of op1 UNORDERED op1 implies op1 is !NAN.
> > +      if (rel == VREL_EQ)
> > +       r.set_nan (fp_prop::NO);
> > +      break;
> > +
> > +    default:
> > +      break;
> > +    }
> > +  return true;
> > +}
> > +
> > +// Placeholder for unimplemented relational operators.
> > +
> > +class foperator_relop_unknown : public range_operator_float
> > +{
> > +  using range_operator_float::fold_range;
> > +
> > +public:
> > +  bool fold_range (irange &r, tree type,
> > +                  const frange &, const frange &,
> > +                  relation_kind) const final override
> > +  {
> > +    r.set_varying (type);
> > +    return true;
> > +  }
> > +} fop_relop_unknown;
> > +
> >
> >  // Instantiate a range_op_table for floating point operations.
> >  static floating_op_table global_floating_table;
> > @@ -185,6 +732,23 @@ floating_op_table::floating_op_table ()
> >    set (PAREN_EXPR, fop_identity);
> >    set (OBJ_TYPE_REF, fop_identity);
> >    set (REAL_CST, fop_identity);
> > +
> > +  // All the relational operators are expected to work, because the
> > +  // calculation of ranges on outgoing edges expect the handlers to be
> > +  // present.
> > +  set (EQ_EXPR, fop_equal);
> > +  set (NE_EXPR, fop_not_equal);
> > +  set (LT_EXPR, fop_lt);
> > +  set (LE_EXPR, fop_le);
> > +  set (GT_EXPR, fop_gt);
> > +  set (GE_EXPR, fop_ge);
> > +  set (UNLE_EXPR, fop_relop_unknown);
> > +  set (UNLT_EXPR, fop_relop_unknown);
> > +  set (UNGE_EXPR, fop_relop_unknown);
> > +  set (UNGT_EXPR, fop_relop_unknown);
> > +  set (UNEQ_EXPR, fop_relop_unknown);
> > +  set (ORDERED_EXPR, fop_ordered);
> > +  set (UNORDERED_EXPR, fop_unordered);
> >  }
> >
> >  // Return a pointer to the range_operator_float instance, if there is
> > diff --git a/gcc/testsuite/g++.dg/opt/pr94589-2.C b/gcc/testsuite/g++.dg/opt/pr94589-2.C
> > index e9ef84b1912..1caa725061e 100644
> > --- a/gcc/testsuite/g++.dg/opt/pr94589-2.C
> > +++ b/gcc/testsuite/g++.dg/opt/pr94589-2.C
> > @@ -4,6 +4,31 @@
> >  // { dg-final { scan-tree-dump-times "\[ij]_\[0-9]+\\(D\\) (?:<|<=|==|!=|>|>=) \[ij]_\[0-9]+\\(D\\)" 12 "optimized" } }
> >  // { dg-final { scan-tree-dump-times "i_\[0-9]+\\(D\\) (?:<|<=|==|!=|>|>=) 5\\.0" 12 "optimized" } }
> >
> > +/* This is failing on f5() because the spaceship operator is no longer
> > +   folded.  What happens is that evrp folds away the final condition
> > +   here as always true.
> > +
> > +  <bb 2> :
> > +  if (i_2(D) != j_4(D))
> > +    goto <bb 3>; [INV]
> > +  else
> > +    goto <bb 6>; [INV]
> > +
> > +  <bb 3> :
> > +  if (i_2(D) >= j_4(D))
> > +    goto <bb 4>; [INV]
> > +  else
> > +    goto <bb 6>; [INV]
> > +
> > +  <bb 4> :
> > +  if (i_2(D) > j_4(D))   <<== ALWAYS TRUE
> > +    goto <bb 6>; [INV]
> > +  else
> > +    goto <bb 5>; [INV]
> > +
> > +  This causes phiopt to no longer be able to fold the total sequence
> > +  into i_2 >= j_4.  */
> > +
> >  #include <compare>
> >
> >  #define A __attribute__((noipa))
> > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-1.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-1.c
> > new file mode 100644
> > index 00000000000..88faf72ac42
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-1.c
> > @@ -0,0 +1,19 @@
> > +// { dg-do compile }
> > +// { dg-options "-O2 -fdisable-tree-ethread -fdisable-tree-fre1 -fdump-tree-evrp" }
> > +
> > +void bar ();
> > +void george ();
> > +
> > +float
> > +foo (float x, float y)
> > +{
> > +  if (x == x)
> > +    {
> > +      if (x > y)
> > +        bar();
> > +      if (x == x)
> > +        george();
> > +    }
> > +}
> > +
> > +// { dg-final { scan-tree-dump-times "Folding predicate x_*to 1" "evrp" 1 } }
> > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-11.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-11.c
> > new file mode 100644
> > index 00000000000..2f4dc8757a3
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-11.c
> > @@ -0,0 +1,26 @@
> > +// { dg-do compile }
> > +// { dg-options "-O2 -fno-thread-jumps -fdump-tree-evrp" }
> > +
> > +extern void link_error ();
> > +
> > +void fast_sqrt (float);
> > +
> > +float test (float x)
> > +{
> > +  float y = x*x;
> > +  if (y >= 0.f)
> > +    {
> > +      if (__builtin_isnan (y))
> > +       link_error ();
> > +      else
> > +       fast_sqrt (y);
> > +
> > +      if (!__builtin_isnan (y))
> > +       fast_sqrt (y);
> > +      else
> > +       link_error ();
> > +    }
> > +}
> > +
> > +// { dg-final { scan-tree-dump-times "fast_sqrt" 2 "evrp" } }
> > +// { dg-final { scan-tree-dump-not "link_error" "evrp" } }
> > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-3.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-3.c
> > new file mode 100644
> > index 00000000000..c659abb6cc0
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-3.c
> > @@ -0,0 +1,18 @@
> > +// { dg-do compile }
> > +// { dg-options "-O2 -fdisable-tree-ethread -fdump-tree-evrp" }
> > +
> > +void link_error ();
> > +
> > +void
> > +foo (double x, double y)
> > +{
> > +  if (x == y)
> > +    {
> > +      if (__builtin_isnan (x))
> > +        link_error ();
> > +      if (__builtin_isnan (y))
> > +        link_error ();
> > +    }
> > +}
> > +
> > +// { dg-final { scan-tree-dump-not "link_error" "evrp" } }
> > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-4.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-4.c
> > new file mode 100644
> > index 00000000000..86436742e0a
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-4.c
> > @@ -0,0 +1,16 @@
> > +// { dg-do compile }
> > +// { dg-options "-O2 -fdisable-tree-ethread -fdump-tree-evrp" }
> > +
> > +void link_error ();
> > +
> > +void
> > +foo (double x, double y)
> > +{
> > +  if (x > y)
> > +    {
> > +      if (__builtin_isnan (x) || __builtin_isnan (y))
> > +        link_error ();
> > +    }
> > +}
> > +
> > +// { dg-final { scan-tree-dump-not "link_error" "evrp" } }
> > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-6.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-6.c
> > new file mode 100644
> > index 00000000000..145d1861804
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-6.c
> > @@ -0,0 +1,20 @@
> > +// { dg-do compile }
> > +// { dg-options "-O2 -fdisable-tree-ethread -fdump-tree-evrp" }
> > +
> > +void bar ();
> > +
> > +void
> > +foo (double x, double y)
> > +{
> > +      if (x > y)
> > +       ;
> > +      else if (!__builtin_isnan (x) && !__builtin_isnan (y))
> > +       {
> > +         // If x and y are not NAN, the x <= y relationship holds, and the
> > +         // following conditional can be folded away.
> > +         if (x <= y)
> > +           bar ();
> > +       }
> > +}
> > +
> > +// { dg-final { scan-tree-dump-times "Folding predicate x_.* <= y_.* to 1" 1 "evrp" } }
> > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-7.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-7.c
> > new file mode 100644
> > index 00000000000..92af87091a8
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-7.c
> > @@ -0,0 +1,14 @@
> > +// { dg-do compile }
> > +// { dg-options "-O2 -fno-tree-forwprop -fno-tree-ccp -fno-tree-fre -fdump-tree-evrp" }
> > +
> > +extern void link_error ();
> > +
> > +void
> > +foo ()
> > +{
> > +  float z = 0.0;
> > +  if (__builtin_isnan (z))
> > +    link_error ();
> > +}
> > +
> > +// { dg-final { scan-tree-dump-not "link_error" "evrp" } }
> > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-8.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-8.c
> > new file mode 100644
> > index 00000000000..9170150d453
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-8.c
> > @@ -0,0 +1,26 @@
> > +// { dg-do compile }
> > +// { dg-options "-O2 -fno-thread-jumps -fdump-tree-evrp" }
> > +
> > +extern void link_error ();
> > +
> > +void fast_sqrt (float);
> > +
> > +float test (float x)
> > +{
> > +    float y = x*x;
> > +    if (y >= 0.f)
> > +      {
> > +        if (__builtin_isnan (y))
> > +         link_error ();
> > +        else
> > +          fast_sqrt (y);
> > +
> > +       if (!__builtin_isnan (y))
> > +         fast_sqrt (y);
> > +       else
> > +         link_error ();
> > +      }
> > +}
> > +
> > +// { dg-final { scan-tree-dump-times "fast_sqrt" 2 "evrp" } }
> > +// { dg-final { scan-tree-dump-not "link_error" "evrp" } }
> > diff --git a/gcc/value-range.h b/gcc/value-range.h
> > index e43fbe30f27..478f165e02b 100644
> > --- a/gcc/value-range.h
> > +++ b/gcc/value-range.h
> > @@ -338,8 +338,7 @@ public:
> >    frange (const frange &);
> >    static bool supports_p (tree type)
> >    {
> > -    // Disabled until floating point range-ops come live.
> > -    return 0 && SCALAR_FLOAT_TYPE_P (type);
> > +    return SCALAR_FLOAT_TYPE_P (type);
> >    }
> >    virtual tree type () const override;
> >    virtual void set (tree, tree, value_range_kind = VR_RANGE) override;
> > --
> > 2.36.1
> >


      reply	other threads:[~2022-08-02 12:57 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-07-25 18:49 Aldy Hernandez
2022-07-25 18:53 ` Aldy Hernandez
2022-07-31 18:11 ` Aldy Hernandez
2022-08-02 12:57   ` Aldy Hernandez [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAGm3qMXzZGVBWwjcWdxd_3um57FOcEiLUWPBQ--qX+MLiUbvTw@mail.gmail.com \
    --to=aldyh@redhat.com \
    --cc=amacleod@redhat.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jakub@redhat.com \
    --cc=jeffreyalaw@gmail.com \
    --cc=richard.guenther@gmail.com \
    --cc=roger@nextmovesoftware.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).