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 4:16 PM, Jerry D wrote:
> On 5/24/26 3:23 PM, Thomas Koenig wrote:
>> Jerry,
>>
>> a quick question: We have GFC_UINTEGER_8, would it make sense to use
>> that?  That could get you out of the C type quagmire.
>>
>> Best regards
>>
>>      Thomas
>>
> 
> This is a good idea. I think I will try this in a later patch as a cleanup. 
> There may be other places where ought to be used.
> 
> Cheers,
> 
> Jerry
> 
> 

I revised the patch to use GFC_UINTEGER_8 in all places. It regression tests 
clean.  This should be good to go. See attached.

Thanks for the feedback.

Jerry
0001-Fortran-PR93727-Fix-EX-format-kind-8-output-on-ILP32.patch (text/x-patch, 5.2 KB)
From 0fa89b926ed0e2227fddb7b250fcf16e61dfe072 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.

Fix kind=8 by using GFC_UINTEGER_8, which is guaranteed 64 bits on all
targets.  Update kind=10 and kind=16 to use GFC_UINTEGER_8 throughout
for consistency with libgfortran conventions.

	PR fortran/93727

libgfortran/ChangeLog:

	* io/write_float.def (get_float_hex_string): Fix kind=8 frac_part
	from unsigned long to GFC_UINTEGER_8 to correct truncated hex
	output and IEEE_INVALID_FLAG on ILP32 targets.  Update kind=10
	and kind=16 to use GFC_UINTEGER_8 for consistency.

Assisted by: Claude Sonnet 4.6
---
 libgfortran/io/write_float.def | 34 ++++++++++++++++++++--------------
 1 file changed, 20 insertions(+), 14 deletions(-)

diff --git a/libgfortran/io/write_float.def b/libgfortran/io/write_float.def
index 608106af7c7..da31c8af51c 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;
+	GFC_UINTEGER_8 frac_part;
 
 	val = *(const GFC_REAL_8 *) source;
 	is_negative = signbit (val);
@@ -172,11 +172,13 @@ 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 = (GFC_UINTEGER_8) 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,
+			     (GFC_UINTEGER_8) 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,
+			     (GFC_UINTEGER_8) frac_part, expon);
       }
       break;
 #ifdef HAVE_GFC_REAL_10
@@ -186,7 +188,7 @@ get_float_hex_string (const void *source, int kind, char *buffer,
 	GFC_REAL_10 mant;
 	int expon;
 	int int_part;
-	unsigned long long frac_part;
+	GFC_UINTEGER_8 frac_part;
 
 	val = *(const GFC_REAL_10 *) source;
 	is_negative = signbit (val);
@@ -230,11 +232,13 @@ get_float_hex_string (const void *source, int kind, char *buffer,
 	int_part = (int) mant;
 	/* 64 is the nearest integer divisible by 4 that is >= 64 (mantissa bits
 	   for kind=10).  (64-4)/4 = 15 hex digits for the fractional part.  */
-	frac_part = (unsigned long long) scalbnl (mant - (GFC_REAL_10) int_part, 64 - 4);
+	frac_part = (GFC_UINTEGER_8) scalbnl (mant - (GFC_REAL_10) int_part, 64 - 4);
 	if (is_negative)
-	  result = snprintf (buffer, 28, "-0X%X.%15.15llXP%+d", int_part, frac_part, expon);
+	  result = snprintf (buffer, 28, "-0X%X.%15.15llXP%+d", int_part,
+			     (GFC_UINTEGER_8) frac_part, expon);
 	else
-	  result = snprintf (buffer, 28, "0X%X.%15.15llXP%+d", int_part, frac_part, expon);
+	  result = snprintf (buffer, 28, "0X%X.%15.15llXP%+d", int_part,
+			     (GFC_UINTEGER_8) frac_part, expon);
       }
       break;
 #endif
@@ -245,7 +249,7 @@ get_float_hex_string (const void *source, int kind, char *buffer,
 	GFC_REAL_16 mant;
 	int expon;
 	int int_part;
-	unsigned long long frac_hi, frac_lo;
+	GFC_UINTEGER_8 frac_hi, frac_lo;
 	GFC_REAL_16 frac_val, frac_lo_val;
 
 	val = *(const GFC_REAL_16 *) source;
@@ -291,17 +295,19 @@ get_float_hex_string (const void *source, int kind, char *buffer,
 	/* 116 is the nearest integer divisible by 4 that is >= 113 (mantissa
 	   bits for kind=16).  (116-4)/4 = 28 hex digits for the fractional
 	   part, split into two 56-bit halves (14 hex digits each) to fit in
-	   unsigned long long.  */
+	   GFC_UINTEGER_8.  */
 	frac_val = mant - (GFC_REAL_16) int_part;
-	frac_hi = (unsigned long long) GFC_REAL_16_SCALBN (frac_val, 56);
+	frac_hi = (GFC_UINTEGER_8) GFC_REAL_16_SCALBN (frac_val, 56);
 	frac_lo_val = frac_val - GFC_REAL_16_SCALBN ((GFC_REAL_16) frac_hi, -56);
-	frac_lo = (unsigned long long) GFC_REAL_16_SCALBN (frac_lo_val, 112);
+	frac_lo = (GFC_UINTEGER_8) GFC_REAL_16_SCALBN (frac_lo_val, 112);
 	if (is_negative)
 	  result = snprintf (buffer, 42, "-0X%X.%14.14llX%14.14llXP%+d",
-			     int_part, frac_hi, frac_lo, expon);
+			     int_part, (GFC_UINTEGER_8) frac_hi,
+			     (GFC_UINTEGER_8) frac_lo, expon);
 	else
 	  result = snprintf (buffer, 42, "0X%X.%14.14llX%14.14llXP%+d",
-			     int_part, frac_hi, frac_lo, expon);
+			     int_part, (GFC_UINTEGER_8) frac_hi,
+			     (GFC_UINTEGER_8) frac_lo, expon);
       }
       break;
 #endif /* HAVE_GFC_REAL_16  */
-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.