The PLUS_EXPR was always meant to be a template for further
development, since most of the binary operators will share a similar
structure.  This patch abstracts out the common bits into the default
definition for range_operator_float::fold_range() and provides an
rv_fold() to be implemented by the individual entries wishing to use
the generic folder.  This is akin to what we do with fold_range() and
wi_fold() in the integer version of range-ops.

gcc/ChangeLog:

        * range-op-float.cc (range_operator_float::fold_range): Abstract
        out from foperator_plus.
        (range_operator_float::rv_fold): New.
        (foperator_plus::fold_range): Remove.
        (foperator_plus::rv_fold): New.
        (propagate_nans): Remove.
        * range-op.h (class range_operator_float): Add rv_fold.
---
 gcc/range-op-float.cc | 156 +++++++++++++++++++++---------------------
 gcc/range-op.h        |   7 ++
 2 files changed, 84 insertions(+), 79 deletions(-)

diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index 8282c912fc4..7075c25442a 100644
--- a/gcc/range-op-float.cc
+++ b/gcc/range-op-float.cc
@@ -49,13 +49,66 @@ along with GCC; see the file COPYING3.  If not see
 // Default definitions for floating point operators.
 
 bool
-range_operator_float::fold_range (frange &r ATTRIBUTE_UNUSED,
-                                 tree type ATTRIBUTE_UNUSED,
-                                 const frange &lh ATTRIBUTE_UNUSED,
-                                 const frange &rh ATTRIBUTE_UNUSED,
+range_operator_float::fold_range (frange &r, tree type,
+                                 const frange &op1, const frange &op2,
                                  relation_trio) const
 {
-  return false;
+  if (empty_range_varying (r, type, op1, op2))
+    return true;
+  if (op1.known_isnan () || op2.known_isnan ())
+    {
+      r.set_nan (op1.type ());
+      return true;
+    }
+
+  REAL_VALUE_TYPE lb, ub;
+  bool maybe_nan;
+  rv_fold (lb, ub, maybe_nan, type,
+          op1.lower_bound (), op1.upper_bound (),
+          op2.lower_bound (), op2.upper_bound ());
+
+  // Handle possible NANs by saturating to the appropriate INF if only
+  // one end is a NAN.  If both ends are a NAN, just return a NAN.
+  bool lb_nan = real_isnan (&lb);
+  bool ub_nan = real_isnan (&ub);
+  if (lb_nan && ub_nan)
+    {
+      r.set_nan (type);
+      return true;
+    }
+  if (lb_nan)
+    lb = dconstninf;
+  else if (ub_nan)
+    ub = dconstinf;
+
+  r.set (type, lb, ub);
+
+  if (lb_nan || ub_nan || maybe_nan)
+    // Keep the default NAN (with a varying sign) set by the setter.
+    ;
+  else if (!op1.maybe_isnan () && !op2.maybe_isnan ())
+    r.clear_nan ();
+
+  return true;
+}
+
+// For a given operation, fold two sets of ranges into [lb, ub].
+// MAYBE_NAN is set to TRUE if, in addition to any result in LB or
+// UB, the final range has the possiblity of a NAN.
+void
+range_operator_float::rv_fold (REAL_VALUE_TYPE &lb,
+                              REAL_VALUE_TYPE &ub,
+                              bool &maybe_nan,
+                              tree type ATTRIBUTE_UNUSED,
+                              const REAL_VALUE_TYPE &lh_lb ATTRIBUTE_UNUSED,
+                              const REAL_VALUE_TYPE &lh_ub ATTRIBUTE_UNUSED,
+                              const REAL_VALUE_TYPE &rh_lb ATTRIBUTE_UNUSED,
+                              const REAL_VALUE_TYPE &rh_ub ATTRIBUTE_UNUSED)
+  const
+{
+  lb = dconstninf;
+  ub = dconstinf;
+  maybe_nan = true;
 }
 
 bool
@@ -192,19 +245,6 @@ frelop_early_resolve (irange &r, tree type,
          && relop_early_resolve (r, type, op1, op2, rel, my_rel));
 }
 
-// If either operand is a NAN, set R to NAN and return TRUE.
-
-inline bool
-propagate_nans (frange &r, const frange &op1, const frange &op2)
-{
-  if (op1.known_isnan () || op2.known_isnan ())
-    {
-      r.set_nan (op1.type ());
-      return true;
-    }
-  return false;
-}
-
 // Set VALUE to its next real value, or INF if the operation overflows.
 
 inline void
@@ -1822,69 +1862,27 @@ foperator_unordered_equal::op1_range (frange &r, tree 
type,
 
 class foperator_plus : public range_operator_float
 {
-  using range_operator_float::fold_range;
-
-public:
-  bool fold_range (frange &r, tree type,
-                  const frange &lh,
-                  const frange &rh,
-                  relation_trio = TRIO_VARYING) const final override;
+  void rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, bool &maybe_nan,
+               tree type,
+               const REAL_VALUE_TYPE &lh_lb,
+               const REAL_VALUE_TYPE &lh_ub,
+               const REAL_VALUE_TYPE &rh_lb,
+               const REAL_VALUE_TYPE &rh_ub) const final override
+  {
+    frange_arithmetic (PLUS_EXPR, type, lb, lh_lb, rh_lb, dconstninf);
+    frange_arithmetic (PLUS_EXPR, type, ub, lh_ub, rh_ub, dconstinf);
+
+    // [-INF] + [+INF] = NAN
+    if (real_isinf (&lh_lb, true) && real_isinf (&rh_ub, false))
+      maybe_nan = true;
+    // [+INF] + [-INF] = NAN
+    else if (real_isinf (&lh_ub, false) && real_isinf (&rh_lb, true))
+      maybe_nan = true;
+    else
+      maybe_nan = false;
+  }
 } fop_plus;
 
-bool
-foperator_plus::fold_range (frange &r, tree type,
-                           const frange &op1, const frange &op2,
-                           relation_trio) const
-{
-  if (empty_range_varying (r, type, op1, op2))
-    return true;
-  if (propagate_nans (r, op1, op2))
-    return true;
-
-  REAL_VALUE_TYPE lb, ub;
-  frange_arithmetic (PLUS_EXPR, type, lb,
-                    op1.lower_bound (), op2.lower_bound (), dconstninf);
-  frange_arithmetic (PLUS_EXPR, type, ub,
-                    op1.upper_bound (), op2.upper_bound (), dconstinf);
-
-  // Handle possible NANs by saturating to the appropriate INF if only
-  // one end is a NAN.  If both ends are a NAN, just return a NAN.
-  bool lb_nan = real_isnan (&lb);
-  bool ub_nan = real_isnan (&ub);
-  if (lb_nan && ub_nan)
-    {
-      r.set_nan (type);
-      return true;
-    }
-  if (lb_nan)
-    lb = dconstninf;
-  else if (ub_nan)
-    ub = dconstinf;
-
-  r.set (type, lb, ub);
-
-  // Some combinations can yield a NAN even if no operands have the
-  // possibility of a NAN.
-  bool maybe_nan;
-  // [-INF] + [+INF] = NAN
-  if (real_isinf (&op1.lower_bound (), true)
-      && real_isinf (&op2.upper_bound (), false))
-    maybe_nan = true;
-  // [+INF] + [-INF] = NAN
-  else if (real_isinf (&op1.upper_bound (), false)
-          && real_isinf (&op2.lower_bound (), true))
-    maybe_nan = true;
-  else
-    maybe_nan = false;
-
-  if (lb_nan || ub_nan || maybe_nan)
-    // Keep the default NAN (with a varying sign) set by the setter.
-    ;
-  else if (!op1.maybe_isnan () && !op2.maybe_isnan ())
-    r.clear_nan ();
-
-  return true;
-}
 
 // Instantiate a range_op_table for floating point operations.
 static floating_op_table global_floating_table;
diff --git a/gcc/range-op.h b/gcc/range-op.h
index c7249890142..442a6e1d299 100644
--- a/gcc/range-op.h
+++ b/gcc/range-op.h
@@ -117,6 +117,13 @@ public:
                           const frange &lh,
                           const frange &rh,
                           relation_trio = TRIO_VARYING) const;
+  virtual void rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub,
+                       bool &maybe_nan,
+                       tree type,
+                       const REAL_VALUE_TYPE &lh_lb,
+                       const REAL_VALUE_TYPE &lh_ub,
+                       const REAL_VALUE_TYPE &rh_lb,
+                       const REAL_VALUE_TYPE &rh_ub) const;
   // Unary operations have the range of the LHS as op2.
   virtual bool fold_range (irange &r, tree type,
                           const frange &lh,
-- 
2.38.1

Reply via email to