diff mbox

gfortran -- Map REAL128 to REAL kind type with widest precision

Message ID 20170207184635.GA64694@troutmask.apl.washington.edu
State New
Headers show

Commit Message

Steve Kargl Feb. 7, 2017, 6:46 p.m. UTC
All,

The attach patch maps REAL128 from iso_fortran_env to 
the REAL kind type with widest precision.  Prior to
this patch, REAL128 is mapped to the first REAL kind
type with a matching storage size of 128 bits.  On
x86_64-*-freebsd both REAL(10) and REAL(16) occupy 
16 bytes, but REAL(10) is mapped to REAL128.  This 
may surprise users that assume REAL128 is mapped to
an IEEE754-2008 128-bit floating point entity with
113 bits of precision.  OK to commit?

2017-02-07  Steven G. Kargl  <kargl@gcc.gnu.org>

	* trans-types.c	(gfc_get_int_kind_from_width_isofortranen):  Choose
	REAL type with the widest precision if two (or more) have the same
	storage size.

Comments

Mikael Morin Feb. 7, 2017, 8:07 p.m. UTC | #1
Le 07/02/2017 à 19:46, Steve Kargl a écrit :
> All,
>
> The attach patch maps REAL128 from iso_fortran_env to
> the REAL kind type with widest precision.  Prior to
> this patch, REAL128 is mapped to the first REAL kind
> type with a matching storage size of 128 bits.  On
> x86_64-*-freebsd both REAL(10) and REAL(16) occupy
> 16 bytes, but REAL(10) is mapped to REAL128.  This
> may surprise users that assume REAL128 is mapped to
> an IEEE754-2008 128-bit floating point entity with
> 113 bits of precision.  OK to commit?
>
Yes, thanks.

Mikael
FX Coudert Feb. 8, 2017, 9:25 a.m. UTC | #2
Hi Steve,

I see Mikael has okayed the patch, but I did not have any time to comment prior. I wanted to note that:

 - the choice was deliberate, as the standard allows us to choose which real kind REAL128 corresponds to when there are several matching choices. The idea behind the current choice was to avoid forcing the use of slower soft-float arithmetic when a hardware type existed. I don’t have a strong opinion myself on the issue.

 - This is a breakage of the ABI, so we want to write it in the release notes, and in the doc about ISO_FORTRAN_ENV.

 - Is this appropriate for stage 4?

FX
Steve Kargl Feb. 8, 2017, 4:55 p.m. UTC | #3
On Wed, Feb 08, 2017 at 10:25:22AM +0100, FX wrote:
> Hi Steve,
> 
> I see Mikael has okayed the patch, but I did not have any
> time to comment prior. I wanted to note that:
> 
>  - the choice was deliberate, as the standard allows us to
> choose which real kind REAL128 corresponds to when there are
> several matching choices. The idea behind the current choice
> was to avoid forcing the use of slower soft-float arithmetic
> when a hardware type existed. I don’t have a strong opinion
> myself on the issue.

Yes, I considered that REAL128 would now be a software implementation.
However, as an individual who works on FreeBSD, I found it rather
unpleasing for i686-*-freebsd to map REAL128 to REAL(16) and 
x86_64-*-freebsd to map it to REAL(10).  I also considered that
some (many?, most?) users who don't look under the hood may 
expect REAL128 to map to a IEEE754 128-bit floating point entity
where it has 113 bits of precision.

>  - This is a breakage of the ABI, so we want to write it in the
> release notes, and in the doc about ISO_FORTRAN_ENV.

The 6.3 manual has 

REAL32, REAL64, REAL128:  Kind type parameters to specify a REAL
type with a storage size of 32, 64, and 128 bits.  It is negative
if a target platform does not support the particular kind.
(Fortran 2008 or later.) 

My patch does not change the above.

I'll also note that with my patch REAL128 does not change with
-m96bit-long-double, -mlong-double-64, or -mlong-double-80.  So,
the ABI is now stable.  On my x86_64-*-freebsd system, gfortran6
does not include my unpatched and gfc7 is patches.

% cat a.f90
program foo
   use iso_fortran_env
   REAL(REAL128) x
   print '(3(I0,1X))', kind(x), digits(x), precision(x)
end program foo

% gfortran6 -static -o z a.f90 && ./z
10 64 18
% gfortran6 -static -o z a.f90 -m96bit-long-double && ./z
16 113 33
% gfc7 -static -o z a.f90 && ./z
16 113 33
% gfc7 -static -o z a.f90 -m96bit-long-double && ./z
16 113 33

>  - Is this appropriate for stage 4?

I think it is appropriate as we already broke libgfortran
for 7.0.  I'll revert the patch as I can always maintain a
local patches.
Mikael Morin Feb. 8, 2017, 7:23 p.m. UTC | #4
Le 08/02/2017 à 10:25, FX a écrit :
> Hi Steve,
>
> I see Mikael has okayed the patch, but I did not have any time to comment prior. I wanted to note that:
>
>  - the choice was deliberate, as the standard allows us to choose which real kind REAL128 corresponds to when there are several matching choices. The idea behind the current choice was to avoid forcing the use of slower soft-float arithmetic when a hardware type existed. I don’t have a strong opinion myself on the issue.
Hello, I didn’t have this in mind when I OKed the patch.
Still, I think the rule above goes against the principle of least surprise.
Actually I don’t really see the use case for these constants.
When would a user say; give me a real that big, including padding bits?

>
>  - Is this appropriate for stage 4?
>
Now  that you remind of it, if we take the rules to the letter, no.
My opinion is that it should be accepted, in stage 4 or later.
But I don’t have a strong opinion about it either.

Mikael
Janne Blomqvist Feb. 9, 2017, 10:10 a.m. UTC | #5
On Wed, Feb 8, 2017 at 9:23 PM, Mikael Morin <morin-mikael@orange.fr> wrote:
> Le 08/02/2017 à 10:25, FX a écrit :
>>
>> Hi Steve,
>>
>> I see Mikael has okayed the patch, but I did not have any time to comment
>> prior. I wanted to note that:
>>
>>  - the choice was deliberate, as the standard allows us to choose which
>> real kind REAL128 corresponds to when there are several matching choices.
>> The idea behind the current choice was to avoid forcing the use of slower
>> soft-float arithmetic when a hardware type existed. I don’t have a strong
>> opinion myself on the issue.
>
> Hello, I didn’t have this in mind when I OKed the patch.
> Still, I think the rule above goes against the principle of least surprise.
> Actually I don’t really see the use case for these constants.
> When would a user say; give me a real that big, including padding bits?

IMO, the current behavior is confusing and unportable, users shouldn't
need to know target ABI details to understand why the compiler chooses
the kind it does. FWIW wikipedia gets it wrong too, see
https://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format
.

So I think Steve's patch is a clear improvement.

That being said, I think even with Steve's patch, it's not guaranteed
to give you IEEE 754-2008 binary128. E.g. on IBM POWER targets,
depending on the ABI you may get an IBM extended double (double-double
or __ibm128) format. Although if IEEE binary128 is also available,
with Steve's patch you should get that one has it has more precision
that __ibm128.

>
>>
>>  - Is this appropriate for stage 4?
>>
> Now  that you remind of it, if we take the rules to the letter, no.
> My opinion is that it should be accepted, in stage 4 or later.
> But I don’t have a strong opinion about it either.

I think it's Ok, the patch is quite small and unlikely to cause
regressions. In particular since the ABI has already been bumped, now
is a good time to piggyback other ABI changing stuff.

Steve, please don't revert, but add a note to gcc-7/changes.html and
the GFortran wiki.
diff mbox

Patch

Index: gcc/fortran/trans-types.c
===================================================================
--- gcc/fortran/trans-types.c	(revision 245068)
+++ gcc/fortran/trans-types.c	(working copy)
@@ -234,27 +234,42 @@  gfc_get_int_kind_from_width_isofortranen
   return -1;
 }
 
-/* Get the kind number corresponding to a real of given storage size,
-   following the required return values for ISO_FORTRAN_ENV REAL* constants:
-   -2 is returned if we support a kind of larger size, -1 otherwise.  */
+
+/* Get the kind number corresponding to a real of a given storage size.
+   If two real's have the same storage size, then choose the real with
+   the largest precision.  If a kind type is unavailable and a real
+   exists with wider storage, then return -2; otherwise, return -1.  */
+
 int
 gfc_get_real_kind_from_width_isofortranenv (int size)
 {
-  int i;
+  int digits, i, kind;
 
   size /= 8;
 
+  kind = -1;
+  digits = 0;
+
   /* Look for a kind with matching storage size.  */
   for (i = 0; gfc_real_kinds[i].kind != 0; i++)
     if (int_size_in_bytes (gfc_get_real_type (gfc_real_kinds[i].kind)) == size)
-      return gfc_real_kinds[i].kind;
+      {
+	if (gfc_real_kinds[i].digits > digits)
+	  {
+	    digits = gfc_real_kinds[i].digits;
+	    kind = gfc_real_kinds[i].kind;
+	  }
+      }
+
+  if (kind != -1)
+    return kind;
 
   /* Look for a kind with larger storage size.  */
   for (i = 0; gfc_real_kinds[i].kind != 0; i++)
     if (int_size_in_bytes (gfc_get_real_type (gfc_real_kinds[i].kind)) > size)
-      return -2;
+      kind = -2;
 
-  return -1;
+  return kind;
 }