]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[PATCH] libgcc: PR target/116363 Fix SFtype to UDWtype conversion
authorJan Dubiec <jdx@o2.pl>
Thu, 10 Jul 2025 13:41:08 +0000 (07:41 -0600)
committerJeff Law <jlaw@ventanamicro.com>
Thu, 10 Jul 2025 13:41:08 +0000 (07:41 -0600)
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.

PR target/116363

libgcc/ChangeLog:

* libgcc2.c (__fixunssfDI): Fix SFtype to UDWtype conversion for targets
without LIBGCC2_HAS_DF_MODE defined

libgcc/libgcc2.c

index faefff3730ca1e45c79390271b3687bfda7e26b3..df99c78eb2043854ecf0424aab44ef0f4943cf24 100644 (file)
@@ -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