Re: [PATCH, fortran] PR93727 Implement new EX format specifier
Jerry D <[email protected]>
| Newsgroups | gmane.comp.gcc.patches,gmane.comp.gcc.fortran |
|---|---|
| Message-ID | <[email protected]> |
On 5/24/26 12:38 AM, H.J. Lu wrote: > Note: The following floating-point exceptions are signalling: > IEEE_INVALID_FLAG IEEE_UNDERFLOW_FLAG IEEE_DENORMAL > STOP 3 > FAIL: gfortran.dg/EXformat_1.F90 -O0 execution test I fed the above and the CI report I received to Claude and it arrived at the attached patch rather quickly. Can you try this and confirm whether it fixes it or not? Regards, Jerry --------------- From 837ca2b4c3d1069ddb938a5a7c259d34a85479fc Mon Sep 17 00:00:00 2001 From: Jerry DeLisle <[email protected]> Date: Sun, 24 May 2026 11:51:49 -0700 Subject: [PATCH] Fortran: [PR93727] Fix EX format kind=8 output on ILP32 targets On 32-bit targets such as ARM where unsigned long is 32 bits, the kind=8 case in get_float_hex_string used unsigned long for frac_part. The kind=8 mantissa requires 52 bits (13 hex digits), so the cast silently truncated the upper bits, producing wrong hex output. In addition, converting a ~4.5e15 double value to a 32-bit unsigned long is out of range, which raised IEEE_INVALID_FLAG on ARM hardware. The kind=10 case already used unsigned long long for the same reason. Fix kind=8 to match: change the type, the cast, and the two %lX format specifiers to %llX. PR fortran/93727 libgfortran/ChangeLog: * io/write_float.def (get_float_hex_string): Change frac_part for kind=8 from unsigned long to unsigned long long and update format specifiers from %13.13lX to %13.13llX to fix truncated hex output and IEEE_INVALID_FLAG on ILP32 targets. Assisted by: Claude Sonnet 4.6
0001-Fortran-PR93727-Fix-EX-format-kind-8-output-on-ILP32.patch
(text/x-patch, 2.5 KB)
From 837ca2b4c3d1069ddb938a5a7c259d34a85479fc Mon Sep 17 00:00:00 2001 From: Jerry DeLisle <[email protected]> Date: Sun, 24 May 2026 11:51:49 -0700 Subject: [PATCH] Fortran: [PR93727] Fix EX format kind=8 output on ILP32 targets On 32-bit targets such as ARM where unsigned long is 32 bits, the kind=8 case in get_float_hex_string used unsigned long for frac_part. The kind=8 mantissa requires 52 bits (13 hex digits), so the cast silently truncated the upper bits, producing wrong hex output. In addition, converting a ~4.5e15 double value to a 32-bit unsigned long is out of range, which raised IEEE_INVALID_FLAG on ARM hardware. The kind=10 case already used unsigned long long for the same reason. Fix kind=8 to match: change the type, the cast, and the two %lX format specifiers to %llX. PR fortran/93727 libgfortran/ChangeLog: * io/write_float.def (get_float_hex_string): Change frac_part for kind=8 from unsigned long to unsigned long long and update format specifiers from %13.13lX to %13.13llX to fix truncated hex output and IEEE_INVALID_FLAG on ILP32 targets. Assisted by: Claude Sonnet 4.6 --- libgfortran/io/write_float.def | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libgfortran/io/write_float.def b/libgfortran/io/write_float.def index 608106af7c7..66fd7cfe69a 100644 --- a/libgfortran/io/write_float.def +++ b/libgfortran/io/write_float.def @@ -128,7 +128,7 @@ get_float_hex_string (const void *source, int kind, char *buffer, double mant; int expon; int int_part; - unsigned long frac_part; + unsigned long long frac_part; val = *(const GFC_REAL_8 *) source; is_negative = signbit (val); @@ -172,11 +172,11 @@ get_float_hex_string (const void *source, int kind, char *buffer, int_part = (int) mant; /* 56 is the nearest integer divisible by 4 that is >= 53 (mantissa bits for kind=8). (56-4)/4 = 13 hex digits for the fractional part. */ - frac_part = (unsigned long) scalbn (mant - (double) int_part, 56 - 4); + frac_part = (unsigned long long) scalbn (mant - (double) int_part, 56 - 4); if (is_negative) - result = snprintf (buffer, 25, "-0X%X.%13.13lXP%+d", int_part, frac_part, expon); + result = snprintf (buffer, 25, "-0X%X.%13.13llXP%+d", int_part, frac_part, expon); else - result = snprintf (buffer, 25, "0X%X.%13.13lXP%+d", int_part, frac_part, expon); + result = snprintf (buffer, 25, "0X%X.%13.13llXP%+d", int_part, frac_part, expon); } break; #ifdef HAVE_GFC_REAL_10 -- 2.54.0