On Mon, Mar 13, 2023 at 09:41:47AM +0100, Aldy Hernandez wrote:
> On 3/13/23 09:06, Jakub Jelinek wrote:
> > On Mon, Mar 13, 2023 at 08:59:15AM +0100, Aldy Hernandez wrote:
> > > > Yes, sure - I just noticed that we're forced to use high-level API for
> > > > something that's quite low-level and should be internal (a range
> > > > "breaking" internal consistency checks).
> > > 
> > > Yeah, let's fix the API.  No sense hacking around things if what we need 
> > > is
> > > to tweak the design.
> > > 
> > > I don't like hacking around things.  It always comes back to bite me ;-).
> > 
> > Sure.  The current state is that I think the actual bugs are fixed except
> > for the !MODE_HAS_INFINITIES case which people rarely use, so fixing up the
> > API can wait even to next release.
> > 
> > For !MODE_HAS_INFINITIES, I wonder if the best fix wouldn't be to change
> > set and a few other spots, so that if the boundaries are
> > real_min_representable/real_max_representable, we widen them to -inf and inf
> > and change frange_val_min/max to also be dconstninf/dconstinf for
> > !MODE_HAS_INFINITIES, because the min/max for that case (probably) really 
> > work as
> > infinities.  Whenever we actually round that value to mode, it will become
> > real_min_representable/real_max_representable again.
> > But that can also wait a week.
> 
> That sounds very reasonable.  It would remove special casing and would make
> the code easier to read.  For that matter, that was what I had in the
> original implementation.

I think we don't want to remove the special casing for -ffinite-math-only
on types which do support infinities.
Thinking further on it, perhaps for !MODE_HAS_INFINITIES a better fix would
be to do something like the patch below.
Consider say having a range of VAX float type:
#define M0 -FLT_MAX
#define M1 nextafterf (F0, FLT_MAX)
#define M2 nextafterf (M1, FLT_MAX)
[M2, M2] - [M0, M1]
Or perhaps if one or both of the operands are in such a case a min and max,
perform real_arithmetic recurse on the argument replaced with
dconstninf/dconstinf and then depending on inf pick the mininum or maximum
of the two results (and carefully think about what to do if both operands
are min/max).

2023-03-20  Jakub Jelinek  <ja...@redhat.com>

        * range-op-float.cc (frange_arithmetic): For !MODE_HAS_INFINITIES
        types, pretend operands with minimum or maximum values are actually
        infinities.

--- gcc/range-op-float.cc.jj    2023-03-10 12:40:19.673108938 +0100
+++ gcc/range-op-float.cc       2023-03-20 16:58:36.604981486 +0100
@@ -313,8 +313,26 @@ frange_arithmetic (enum tree_code code,
   REAL_VALUE_TYPE value;
   enum machine_mode mode = TYPE_MODE (type);
   bool mode_composite = MODE_COMPOSITE_P (mode);
+  const REAL_VALUE_TYPE *pop1 = &op1;
+  const REAL_VALUE_TYPE *pop2 = &op2;
 
-  bool inexact = real_arithmetic (&value, code, &op1, &op2);
+  if (!MODE_HAS_INFINITIES (mode))
+    {
+      // If mode doesn't have infinities, the minimum and maximum
+      // values are saturating.  Pretend for real_arithmetic such
+      // values are actual infinities.  real_convert will then
+      // canonicalize the result not to be an infinity.
+      if (frange_val_is_min (op1, type))
+       pop1 = &dconstninf;
+      else if (frange_val_is_max (op1, type))
+       pop1 = &dconstinf;
+      if (frange_val_is_min (op2, type))
+       pop2 = &dconstninf;
+      else if (frange_val_is_max (op2, type))
+       pop2 = &dconstinf;
+    }
+
+  bool inexact = real_arithmetic (&value, code, pop1, pop2);
   real_convert (&result, mode, &value);
 
   // Be extra careful if there may be discrepancies between the


        Jakub

Reply via email to