This patch fixes SFtype to UDWtype (aka float to unsigned long long)
conversion on targets without DFmode like e.g. H8/300H. It solely relies
on SFtype->UWtype and UWtype->UDWtype conversions/casts. The existing code
in line 2218 (counter = a) assigns/casts a float which is *always* not lesser
than Wtype_MAXp1_F to an UWtype int which of course does not have enough
capacity.

2025-02-22  Jan Dubiec  <j...@o2.pl>

        PR target/116363

libgcc/ChangeLog:

        * libgcc2.c (__fixunssfDI): Fix SFtype to UDWtype conversion for targets
        without LIBGCC2_HAS_DF_MODE defined
 libgcc/libgcc2.c | 41 +++++++++++++----------------------------
 1 file changed, 13 insertions(+), 28 deletions(-)

diff --git a/libgcc/libgcc2.c b/libgcc/libgcc2.c
index 92cb79dc8f8..b1e24927f47 100644
--- a/libgcc/libgcc2.c
+++ b/libgcc/libgcc2.c
@@ -2187,36 +2187,21 @@ __fixunssfDI (SFtype a)
   if (a < 1)
     return 0;
   if (a < Wtype_MAXp1_F)
-    return (UWtype)a;
+    return (UWtype) a;
   if (a < Wtype_MAXp1_F * Wtype_MAXp1_F)
     {
-      /* Since we know that there are fewer significant bits in the SFmode
-        quantity than in a word, we know that we can convert out all the
-        significant bits in one step, and thus avoid losing bits.  */
-
-      /* ??? This following loop essentially performs frexpf.  If we could
-        use the real libm function, or poke at the actual bits of the fp
-        format, it would be significantly faster.  */
-
-      UWtype shift = 0, counter;
-      SFtype msb;
-
-      a /= Wtype_MAXp1_F;
-      for (counter = W_TYPE_SIZE / 2; counter != 0; counter >>= 1)
-       {
-         SFtype counterf = (UWtype)1 << counter;
-         if (a >= counterf)
-           {
-             shift |= counter;
-             a /= counterf;
-           }
-       }
-
-      /* Rescale into the range of one word, extract the bits of that
-        one word, and shift the result into position.  */
-      a *= Wtype_MAXp1_F;
-      counter = a;
-      return (DWtype)counter << shift;
+      /* We assume that SFtype -> UWtype and UWtype -> UDWtype casts work
+         properly. Obviously, we *cannot* assume that SFtype -> UDWtype
+         works as expected.  */
+      SFtype a_hi, a_lo;
+
+      a_hi = a / Wtype_MAXp1_F;
+      a_lo = a - a_hi * Wtype_MAXp1_F;
+
+      /* A lot of parentheses. This is to make it very clear what is
+         the sequence of operations.  */
+      return ((UDWtype) ((UWtype) a_hi)) << W_TYPE_SIZE
+            | (UDWtype) ((UWtype) a_lo);
     }
   return -1;
 #else

Reply via email to