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