https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126641

Aldy Hernandez <aldyh at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |jakub at gcc dot gnu.org

--- Comment #9 from Aldy Hernandez <aldyh at gcc dot gnu.org> ---
I am not an FP expert, not do I play one on TV.

I debugged this with heavy help from Claude.  Yeah, don’t shoot me.

Here is a testcase that I believe shows the problem.

FWIW, we should probably keep that assert.

diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index baf8a6dc098..ca443201d7b 100644
--- a/gcc/range-op-float.cc
+++ b/gcc/range-op-float.cc
@@ -3277,6 +3277,19 @@ range_op_float_tests ()
   REAL_VALUE_TYPE five;
   real_from_string (&five, "5.0");
   ASSERT_FALSE (r.contains_p (five));
+
+  // float_widen_lhs_range widens each sub-range bound by
+  // half an ulp, so a bound at the smallest denormal lands just below it. 
When
+  // frange_fusible_p then calls real_nextafter on that sub-denormal bound,
+  // real_nextafter's np2 reaches SIGNIFICAND_BITS and set_significand_bit
stores
+  // one past sig[]
+  r0 = frange_float ("-1.0", "-0x1p-149");
+  r1 = frange_float ("0x1p-149", "1.0");
+  r0.union_ (r1);
+  r0.clear_nan ();
+  ASSERT_EQ (r0.num_pairs (), 2);
+  r = float_widen_lhs_range (float_type_node, r0);
+  ASSERT_EQ (r.num_pairs (), 2);
 }

 } // namespace selftest
diff --git a/gcc/real.cc b/gcc/real.cc
index 29cb6a1edd2..6a76d26ad65 100644
--- a/gcc/real.cc
+++ b/gcc/real.cc
@@ -399,6 +399,7 @@ cmp_significand_0 (const REAL_VALUE_TYPE *a)
 static inline void
 set_significand_bit (REAL_VALUE_TYPE *r, unsigned int n)
 {
+  gcc_assert (n < SIGNIFICAND_BITS);
   r->sig[n / HOST_BITS_PER_LONG]
     |= (unsigned long)1 << (n % HOST_BITS_PER_LONG);
 }

Reply via email to