[Patch v2 Fortran] Fix c_float128 and c_float128_complex on targets with 128-bit long double.
Tobias Burnus
tobias@codesourcery.com
Tue Aug 10 08:29:08 GMT 2021
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<sandra@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<sandra@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
More information about the Fortran
mailing list