I was trying last week to run my not-yet-committed TS29113 testsuite on
a powerpc64le-linux-gnu target and ran into some problems with the kind
constants c_float128 and c_float128_complex from the ISO_C_BINDING
module; per the gfortran manual they are supposed to represent the kind
of the gcc extension type __float128 and the corresponding complex type.
They were being set to -4 (e.g., not supported) instead of 16,
although this target does define __float128 and real(16) is accepted as
a supported type by the Fortran front end.
Anyway, the root of the problem is that the definition of these
constants only looked at gfc_float128_type_node, which only gets set if
TFmode is not the same type as long_double_type_node. I experimented
with setting gfc_float128_type_node = long_double_type_node but that
caused various Bad Things to happen elsewhere in code that expected them
to be distinct types, so I ended up with this minimally intrusive patch
that only tweaks the definitions of the c_float128 and
c_float128_complex constants.
I'm not sure this is completely correct, though. I see PowerPC
supports 2 different 128-bit encodings and it looks like TFmode/long
double is mapped onto the one selected by the ABI and/or command-line
options; that's the only one the Fortran front end knows about. All of
TFmode, IFmode, and KFmode would map onto kind 16 anyway (in spite of
having different TYPE_PRECISION values) so Fortran wouldn't be able to
distinguish them. The thing that confuses me is how/when the rs6000
backend defines __float128; it looks like the documentation in the GCC
manual doesn't agree with the code, and I'm not sure what the intended
behavior really is. Is it possible that __float128 could end up defined
but specifying a different type than TFmode, and if so is there a
target-independent way to identify that situation? Can the PowerPC
experts help straighten me out?
-Sandra
commit 158c2f6b1a4134bbdbe59034d38ce12faa8167a8
Author: Sandra Loosemore <san...@codesourcery.com>
Date: Tue Aug 3 16:21:16 2021 -0700
Fix c_float128 and c_float128_complex on targets with 128-bit long double.
gfc_float128_type_node is only non-NULL on targets where float128 is
supported and is a distinct type from long double. So, check
long_double_type_node as well when computing the value of the kind
constants c_float128 and c_float128_complex from the ISO_C_BINDING
intrinsic module.
2021-08-03 Sandra Loosemore <san...@codesourcery.com>
gcc/fortran/
* iso-c-binding.def (c_float128, c_float128_complex): Also
check long_double_type_node. Add comments to explain why.
diff --git a/gcc/fortran/iso-c-binding.def b/gcc/fortran/iso-c-binding.def
index 8bf69ef..a05e324 100644
--- a/gcc/fortran/iso-c-binding.def
+++ b/gcc/fortran/iso-c-binding.def
@@ -114,9 +114,25 @@ 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. gfc_float128_type_node is only non-null if the target
+ supports a 128-bit type distinct from the long double type. Otherwise
+ if long double has kind 16, that's also the float128 type and we can
+ use kind 16 for that too.
+
+ Specifically, on x86_64, long double is the 80-bit encoding with kind
+ 10; it has a storage size of 128 bits due to alignment requirements,
+ but if a true 128-bit float is supported it will have kind 16 and
+ gfc_float128_type_node will point to it. PowerPC has 3 different
+ 128-bit encodings that are distinguished by having different
+ TYPE_PRECISION values (not necessarily 128). They all map onto
+ Fortran kind 16, which corresponds to C long double. The default
+ encoding is determined by the ABI. */
NAMED_REALCST (ISOCBINDING_FLOAT128, "c_float128", \
- gfc_float128_type_node == NULL_TREE \
- ? -4 : get_real_kind_from_node (gfc_float128_type_node), \
+ (gfc_float128_type_node == NULL_TREE \
+ ? (get_real_kind_from_node (long_double_type_node) == 16 \
+ ? 16 : -4) \
+ : get_real_kind_from_node (gfc_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 +140,13 @@ 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), \
+ (gfc_float128_type_node == NULL_TREE \
+ ? (get_real_kind_from_node (long_double_type_node) == 16 \
+ ? 16 : -4) \
+ : get_real_kind_from_node (gfc_float128_type_node)), \
GFC_STD_GNU)
NAMED_LOGCST (ISOCBINDING_BOOL, "c_bool", \