Hi Sandra, hi all,

Let's start reverse – by trying to answer:

On 09.08.21 23:42, Sandra Loosemore wrote:
...
    if (mode_precision != LONG_DOUBLE_TYPE_SIZE && mode_precision == 128)
      {
+      /* FIXME: why are we assuming that this type has IEEE
+      representation?  That's implied by associating it with the
+      C type __float128.  */
        info->c_float128 = 1;

First, a lot of code implicitly assumes x86(-64) with the i387
80bit long double and __float128 being the true 128bit floating type.

In terms of the code, there are builtins for float, double, and
long double but for kind(16) > long double, no builtin exists but
a library call has to be done. Likewise, there is the assumption
that in this case, the functions end in 'q', i.e. 'sinq' besides
the known sinf, sin, and sinl.

Thus, in terms of the FE, info->c_float128 implies 'q' suffix and
library calls for functions where for other types a built-in exists.

Thus, by itself, it is unrelated to __float128.

However, as libquadmath uses __float128, the C decl dependency
appears, unless some other library provides 'sinq' etc. for the
non-__float128 128bit type.

 * * *

In terms of Fortran, REAL types do not need to follow IEEE
(there are IEEE intrinsic modules to handle IEEE); thus, REAL(16)
does not need to be an IEEE type – albeit most users implicitly
expect it.

Likewise, kind numbers have no meaning, but there is plenty of
code which expects that kind=4 = 32bit and kind=8 = 64bit,
especially when used in older code as '<type>*<kind>' (e.g. 'real*8')
but also quite some code using the newer syntax '<type>(<kind>)' or
'<type>(kind=<kind>') (e.g. 'real(8)' or 'real(kind=8)').

For real, kind=10 (i387's 80bit type) is a specialty of gfortran
(most? all?) other compilers do not support it; kind=16 is more widely
supported, albeit some simply map it to 'long double'.

There is no reason why the different PowerPC TF modes couldn't be
mapped to, e.g., the kinds 17, 18, 19, 20 – except that the Fortran FE,
libgfortran current assumes that only 4, 8, 10 and 16 exist and if
10 exists, 16 is the 'q'/libquadmath version. – Additionally, those
17-20 kinds will also confuse users and using '16' has to be mapped
somehow to one of the TF modes in a way that it still works with
interface kind checks and .mod module files and PowerPC's -m flags.

 * * *

Back to:

On 8/5/21 2:09 PM, Michael Meissner wrote:

All PowerPC systems that I'm aware of that use 128-bit floating point
use the
IBM format.  It is anticipated that one or more Linux distributions
in the
future may move to IEEE 128-bit format, but right now, I'm not aware
that any
have moved.

OK.  I now think it's correct that the Fortran front end doesn't
support c_float128 and c_float128_complex on this target, but that the
code that initializes those constants is still buggy. The reason why
it shouldn't support them is that all 3 128-bit floating-point modes
on PowerPC would map onto kind=16,

Side note: in rs6000-modes.h, there is:
  #define FLOAT_PRECISION_IFmode  128
  #define FLOAT_PRECISION_TFmode  127
  #define FLOAT_PRECISION_KFmode  126
with IFmode (IBM 128-bit floating point), TFmode (long double mode), KFmode 
(explicit __float128).

As written above, there is nothing in Fortran (the language) which
prevents those to be mapped to, e.g., kind=14, 15, 16. Thus, I do not
see the conclusion that all of them would be kind=16 – neither from the code
(which filters out all but TFmode for kind=16) nor from the language.
(On the other hand, support for multiple 128bit FP is also not in the FE - nor
the support for real kind != 4,8,10,16.)

Actually, kind=11 (= ia64's long double alias RFmode) is also supported,
but I am not sure it really works as it not well tested; it is accessible
via the REAL_KINDS array, which enables access to all kind numbers or
via selected_real_kinds() or ...


and we can only support one of them unless we make some exception to
the formula for mapping precision -> kind.  And the mode the Fortran
front end already prefers is the one that corresponds to long double
or TFmode.
I concur.
So the reason why the current code is wrong is that
gfc_float128_type_node only gets set if there is a type with 128-bit
precision that is not long double, so c_float128 wouldn't be supported
on a target where __float128 is equivalent to long double.  Moreover,
on targets where it does define gfc_float128_type_node, it's not doing
anything to ensure that it's actually the same IEEE representation as
__float128.  Both problems can be fixed by just using
float128_type_node to get the type corresponding to __float128.  If
that's not a mode the Fortran front end knows about,
get_real_kind_from_node will detect that.
That sounds right.
I suspect there are some similar lurking bugs in other uses of
gfc_float128_type_node in the Fortran front end, but that's out of
scope for my current project focusing on interoperability features.
I'll file an issue about it, though.

Besides the general issue ('q' + libquadmath, calling library
functions), I think the current code should be fine and IEEE is not
really needed. – Actually, the co-processor i387 also does not proper
IEEE rounding (contrary to SSE) and it is still used with 'kind=10' or
'long double'. – Still, there might be issues, especially thinking about
IA-64's kind=11 + when we want to support all PowerPC 128-bit modes.

 * * *

commit 073dd403d11553c199610b038285b203c130cee5
Author: Sandra Loosemore<san...@codesourcery.com>
Date:   Tue Aug 3 16:21:16 2021 -0700

     Fix c_float128 and c_float128_complex definitions.

     gfc_float128_type_node is only non-NULL on targets that support a
     128-bit type that is not long double.  Use float128_type_node instead
     when computing the value of the kind constants c_float128 and
     c_float128_complex from the ISO_C_BINDING intrinsic module; this also
     ensures it actually corresponds to __float128 (the IEEE encoding) and
     not some other 128-bit floating-point type.

     2021-08-09  Sandra Loosemore<san...@codesourcery.com>

     gcc/fortran/
      * iso-c-binding.def (c_float128, c_float128_complex): Check
      float128_type_node instead of gfc_float128_type_node.
      * trans-types.c (gfc_init_kinds, gfc_build_real_type):
      Update comments re supported 128-bit floating-point types.

diff --git a/gcc/fortran/iso-c-binding.def b/gcc/fortran/iso-c-binding.def
index 8bf69ef..e65c750 100644
--- a/gcc/fortran/iso-c-binding.def
+++ b/gcc/fortran/iso-c-binding.def
@@ -114,9 +114,14 @@ NAMED_REALCST (ISOCBINDING_DOUBLE, "c_double", \
                 get_real_kind_from_node (double_type_node), GFC_STD_F2003)
  NAMED_REALCST (ISOCBINDING_LONG_DOUBLE, "c_long_double", \
                 get_real_kind_from_node (long_double_type_node), GFC_STD_F2003)
+
+/* GNU Extension.  Note that the equivalence here is specifically to
+   the IEEE 128-bit type __float128; if that does not map onto a type
+   otherwise supported by the Fortran front end, get_real_kind_from_node
+   will reject it as unsupported.  */
  NAMED_REALCST (ISOCBINDING_FLOAT128, "c_float128", \
-            gfc_float128_type_node == NULL_TREE \
-               ? -4 : get_real_kind_from_node (gfc_float128_type_node), \
+             (float128_type_node == NULL_TREE \
+              ? -4 : get_real_kind_from_node (float128_type_node)), \
             GFC_STD_GNU)
  NAMED_CMPXCST (ISOCBINDING_FLOAT_COMPLEX, "c_float_complex", \
                 get_real_kind_from_node (float_type_node), GFC_STD_F2003)
@@ -124,9 +129,11 @@ NAMED_CMPXCST (ISOCBINDING_DOUBLE_COMPLEX, 
"c_double_complex", \
                 get_real_kind_from_node (double_type_node), GFC_STD_F2003)
  NAMED_CMPXCST (ISOCBINDING_LONG_DOUBLE_COMPLEX, "c_long_double_complex", \
                 get_real_kind_from_node (long_double_type_node), GFC_STD_F2003)
+
+/* GNU Extension.  Similar issues to c_float128 above.  */
  NAMED_CMPXCST (ISOCBINDING_FLOAT128_COMPLEX, "c_float128_complex", \
-            gfc_float128_type_node == NULL_TREE \
-               ? -4 : get_real_kind_from_node (gfc_float128_type_node), \
+             (float128_type_node == NULL_TREE \
+              ? -4 : get_real_kind_from_node (float128_type_node)), \
             GFC_STD_GNU)

  NAMED_LOGCST (ISOCBINDING_BOOL, "c_bool", \
diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c
index 50fda43..8250219 100644
--- a/gcc/fortran/trans-types.c
+++ b/gcc/fortran/trans-types.c
@@ -446,7 +446,7 @@ gfc_init_kinds (void)
        if (!targetm.scalar_mode_supported_p (mode))
      continue;

-      /* Only let float, double, long double and __float128 go through.
+      /* Only let float, double, long double and TFmode go through.
       Runtime support for others is not provided, so they would be
       useless.  */
        if (!targetm.libgcc_floating_mode_supported_p (mode))
All changes above are fine. But:
@@ -471,7 +471,15 @@ gfc_init_kinds (void)
       We round up so as to handle IA-64 __floatreg (RFmode), which is an
       82 bit type.  Not to be confused with __float80 (XFmode), which is
       an 80 bit type also supported by IA-64.  So XFmode should come out
-      to be kind=10, and RFmode should come out to be kind=11.  Egads.  */
+      to be kind=10, and RFmode should come out to be kind=11.  Egads.
+
+      One consequence of this mapping is that all 3 128-bit
+      floating-point modes on PowerPC would have kind 16 in spite of
+      having incompatible representations.  But we have filtered out
+      IFmode (the explicit IBM format) and KFmode (the explicit IEEE
+      format) already in the code just above, leaving only whichever
+      representation has been designated for TFmode as kind=16.
+      */

First, I am not sure about the last bit as both TFmode and
TYPE_MODE (long_double_type_node) can reach this code – and I am not
sure whether they are always the same.

And additionally, the comment above for IA-64 talks about
actual results – while you talk about something hypothetical
(if IFmode/KFmode reached that code, it would map to kind=16).

I think a comment like the following is clearer – describing a pitfall
and a to-do item:

"TODO: The kind calculation has to be modified to support all three
128-bit floating-point modes on PowerPC as IFmode, KFmode, and TFmode
as the following line would all map to kind=16. However, currently only
float, double, long double, and TFmode reach this code."

        kind = (GET_MODE_PRECISION (mode) + 7) / 8;

@@ -851,6 +859,9 @@ gfc_build_real_type (gfc_real_info *info)
      info->c_long_double = 1;
    if (mode_precision != LONG_DOUBLE_TYPE_SIZE && mode_precision == 128)
      {
+      /* FIXME: why are we assuming that this type has IEEE
+      representation?  That's implied by associating it with the
+      C type __float128.  */
        info->c_float128 = 1;
        gfc_real16_is_float128 = true;
      }
I think the question has been answered above.

Given the dependency on intrinsics:
libc/libm provide float/double/long double functions and
lib<somthing> (like libquadmath) has to provide the suffix 'q' version;
As both ligfortran and libquadmath use __float128, we effectively do
depend on having a data type which is compatible with C's __float128.

As the "why" has been answered, can you turn this into a note about
issues with this or a to-do item?

 * * *

To conclude: I like the code changes (LGTM); the
'__float128' -> 'TFmode' comment change also matches the code.

However, I think both longer comments need to be updated.

 * * *

And I concur that some overhaul of the kind handling is needed
for PowerPC's 128-bit floats – but the main issue there is less the
FE but how to handle it on the library side as libm-like math
functions are needed by almost every Fortran code – and,
additionally, libgfortran has to be updated as well as it provides
somes REAL functions, which also need to support additional kinds.

Tobias

-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 
München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas 
Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht 
München, HRB 106955

Reply via email to