diff mbox series

, Add optional IEEE/IBM long double multilib support

Message ID 20180104230555.GA4847@ibm-tiger.the-meissners.org
State New
Headers show
Series , Add optional IEEE/IBM long double multilib support | expand

Commit Message

Michael Meissner Jan. 4, 2018, 11:05 p.m. UTC
This patch is the beginning step to switching the PowerPC long double support
from IBM extended double to IEEE 128-bit floating point on PowerPC servers.  It
will be necessary to have this patch or a similar patch to allow the GLIBC team
to begin their modifications in GLIBC 2.28, so that by the time GCC 9 comes
out, we can decide to switch the default.  It is likely, the default will only
be switched on the 64-bit little endian PowerPC systems, when a distribution
goes through a major level, such that they can contemplate major changes.

If you do not use the configuration option --with-long-double-format=ieee or
--with-long-double-format=ibm, the system will not build multilibs, and just
build normal libraries with the default set to IBM extended double.  If you do
use either of the switches, and allow multilibs, it will build two sets of
multilibs, one for -mabi=ieeelongdouble and one for -mabi=ibmlongdouble.

Now, to build a compiler with multilibs, you need to do the following steps:

1) Install the IBM Advance Toolchain AT 11.0-2.

2) Clone the AT directory:
	# rsync -aH /opt/at11.0/ /opt/at11.0-ieee/

3) Go into the new directory and add a symlink from lib64 to ieee64.
Eventually once we have versions of the libraries compiled for
-mabi=ieeelongdouble, these libraries and objects would go into the ieee64
directory.  However, to do a build, you need the crt files in order to build
the shared libraries.

4) Configure the compiler with these options:
	--with-long-double-128			# should be default
	--with-cpu=power8			# or power9
	--with-long-double-format=ibm		# specify long double format
	--enable-multilib			# enable multilibs
	--with-system-libz			# do not build our own libz
	--with-advance-toolchain=at11.0-ieee	# use the special AT library
						# Use the AT library's includes
	--with-native-system-header-dir=/opt/at11.0-ieee/include
	--with-gnu-ld=/opt/at11.0-ieee/bin/ld	# specify as/ld locations
	--with-gnu-as=/opt/at11.0-ieee/bin/as
	--with-ld=/opt/at11.0-ieee/bin/ld
	--with-as=/opt/at11.0-ieee/bin/as

The libgcc changes were changes that show up when you build libgcc with the
default set to IEEE 128-bit.

There is a work around in rs6000-c.c to allow the AT 11.0-2 include files to be
used as is.  Otherwise, we need to modify /opt/at11.0/include/bits/floatn.h to
specify the correct IEEE 128-bit complex type in C++ (C++ does not support the
_Float128 keyword, and __float128 _Complex does not work, so we have to use the
mode attribute to declare the type).  When -mabi=ieeelongdouble is used, the
default Float128 types are TFmode for scalar and TCmode for complex.  With the
default -mabi=ibmlongdouble is used, the default Float128 types are KFmode and
KCmode.  It is hoped that in AT 11.0-3, we can fix floatn.h to declare the
appropriate type.

I have built bootstrap builds on a little endian power8 system without using
the --with-long-double-format switch and it runs the same as the unpatched
compiler.

I have also built bootstrap builds on a little endian power8 system with the
switches listed above, and the tests for the default long double format are the
same.  Obviously, we can't run multilib make checks until the necessary work
has been done in GLIBC.

I will do a big endian build shortly to make sure it builds normally.

What changes or additional tests do you feel I need to make before checking
this into the trunk?

[gcc]
2018-01-04  Michael Meissner  <meissner@linux.vnet.ibm.com>

	* configure.ac (--with-long-double-format): Add support for
	configuration option to change the default long double format in
	PowerPC Linux systems.
	* configure: Regenerate.
	* config.gcc (powerpc*-linux*-*): Add support for
	--with-long-double-format={ieee,ibm}.  If the format is explicit
	set, also set up IBM and IEEE multilibs.
	* config/rs6000/rs6000.h (FLOAT128_IEEE_P): Explicitly check for
	128-bit long doubles before checking TFmode or TCmode.
	(FLOAT128_IBM_P): Likewise.
	(TARGET_IEEEQUAD_MULTILIB): Set to 0 if not already defined.
	* config/rs6000/rs6000.c (rs6000_option_override_internal): If we
	have IBM/IEEE multilibs, don't give a warning if the user chagnes
	the long double format.
	(is_complex_IBM_long_double): Explicitly check for 128-bit long
	doubles before checking TCmode.
	* config/rs6000/rs6000-c.c (rs6000_cpu_cpp_builtins): If long
	double is IEEE, define __KC__ and __KF__ to allow floatn.h to be
	used without modification.
	* config/rs6000/linux64.h (MULTILIB_DEFAULTS_IEEE): Specify the
	-mabi={ieee,ibm}longdouble default for multilibs.
	(MULTILIB_DEFAULTS): Likewise.
	* config/rs6000/t-ldouble: New file, add IEEE/IBM long double
	multilibs.

[libgcc]
2018-01-04  Michael Meissner  <meissner@linux.vnet.ibm.com>

	* config/rs6000/quad-float128.h (IBM128_TYPE): Explicitly use
	__ibm128, instead of trying to use long double.
	(CVT_FLOAT128_TO_IBM128): Use TFtype instead of __float128 to
	accomidate -mabi=ieeelongdouble multilibs.
	(CVT_IBM128_TO_FLOAT128): Likewise.
	* config/rs6000/ibm-ldouble.c (IBM128_TYPE): New macro to define
	the appropriate IBM extended double type.
	(__gcc_qadd): Change all occurances of long double to IBM128_TYPE.
	(__gcc_qsub): Likewise.
	(__gcc_qmul): Likewise.
	(__gcc_qdiv): Likewise.
	(pack_ldouble): Likewise.
	(__gcc_qneg): Likewise.
	(__gcc_qeq): Likewise.
	(__gcc_qne): Likewise.
	(__gcc_qge): Likewise.
	(__gcc_qle): Likewise.
	(__gcc_stoq): Likewise.
	(__gcc_dtoq): Likewise.
	(__gcc_itoq): Likewise.
	(__gcc_utoq): Likewise.
	(__gcc_qunord): Likewise.
	* config/rs6000/_mulkc3.c (toplevel): Include soft-fp.h and
	quad-float128.h for the definitions.
	(COPYSIGN): Use the f128 version instead of the q version.
	(INFINITY): Likewise.
	(__mulkc3): Use TFmode/TCmode for float128 scalar/complex types.
	* config/rs6000/_divkc3.c (toplevel): Include soft-fp.h and
	quad-float128.h for the definitions.
	(COPYSIGN): Use the f128 version instead of the q version.
	(INFINITY): Likewise.
	(FABS): Likewise.
	(__divkc3): Use TFmode/TCmode for float128 scalar/complex types.
	* config/rs6000/extendkftf2-sw.c (__extendkftf2_sw): Likewise.
	* config/rs6000/trunctfkf2-sw.c (__trunctfkf2_sw): Likewise.

Comments

Joseph Myers Jan. 5, 2018, 5:28 p.m. UTC | #1
On Thu, 4 Jan 2018, Michael Meissner wrote:

> 	(CVT_FLOAT128_TO_IBM128): Use TFtype instead of __float128 to
> 	accomidate -mabi=ieeelongdouble multilibs.

Why is that correct in the -mabi=ibmlongdouble case?

As I understand it, TFtype is always of mode TFmode (it would certainly be 
confusing if it sometimes had a different mode), but TFmode's format 
depends on the selected ABI.  Where this code uses __float128, it requires 
something that is always of IEEE binary128 format.  In the 
-mabi=ieeelongdouble case, that's indeed TFtype, but not in the 
-mabi=ibmlongdouble case when TFmode has ibm128 format.

In C code, _Float128 and _Complex _Float128 should always be available 
when the binary128 format is supported, so I think the code needing that 
format can safely use those.

> 	(__mulkc3): Use TFmode/TCmode for float128 scalar/complex types.
> 	(__divkc3): Use TFmode/TCmode for float128 scalar/complex types.
> 	* config/rs6000/extendkftf2-sw.c (__extendkftf2_sw): Likewise.
> 	* config/rs6000/trunctfkf2-sw.c (__trunctfkf2_sw): Likewise.

And likewise here.

(My understanding is that each of the libgcc functions is meant to have a 
particular ABI that does not depend on the format of long double - so the 
"tf" and "tc" functions refer to ibm128 format, unconditionally, and the 
"kf" and "kc" ones to binary128 format, unconditionally.  I have not 
checked whether the libfuncs handling in init_float128_ibm and 
init_float128_ieee is sufficient to achieve this in all cases.  In 
particular, does complex arithmetic always use the correct one of "kc" and 
"tc" depending on the long double format?  What about __builtin_powil - 
does that properly use __powitf2 and __powikf2 as appropriate, or do you 
have the ABI of __powitf2 depending on the multilib?)
Jakub Jelinek Jan. 5, 2018, 5:33 p.m. UTC | #2
On Thu, Jan 04, 2018 at 06:05:55PM -0500, Michael Meissner wrote:
> This patch is the beginning step to switching the PowerPC long double support
> from IBM extended double to IEEE 128-bit floating point on PowerPC servers.  It
> will be necessary to have this patch or a similar patch to allow the GLIBC team
> to begin their modifications in GLIBC 2.28, so that by the time GCC 9 comes
> out, we can decide to switch the default.  It is likely, the default will only
> be switched on the 64-bit little endian PowerPC systems, when a distribution
> goes through a major level, such that they can contemplate major changes.

When you're mentioning multilibs, does that mean that we'll have two ABI
incompatible libgcc.so.* libraries, two ABI incompatible libstdc++.so.*
libraries etc.?  Just one or 2 libc.so.*/libm.so.*?

At least when doing the long double format double to doubledouble transition
(or on other targets to quad) last time we've managed to make it ABI
compatible.

	Jakub
Joseph Myers Jan. 5, 2018, 5:47 p.m. UTC | #3
On Fri, 5 Jan 2018, Jakub Jelinek wrote:

> On Thu, Jan 04, 2018 at 06:05:55PM -0500, Michael Meissner wrote:
> > This patch is the beginning step to switching the PowerPC long double support
> > from IBM extended double to IEEE 128-bit floating point on PowerPC servers.  It
> > will be necessary to have this patch or a similar patch to allow the GLIBC team
> > to begin their modifications in GLIBC 2.28, so that by the time GCC 9 comes
> > out, we can decide to switch the default.  It is likely, the default will only
> > be switched on the 64-bit little endian PowerPC systems, when a distribution
> > goes through a major level, such that they can contemplate major changes.
> 
> When you're mentioning multilibs, does that mean that we'll have two ABI
> incompatible libgcc.so.* libraries, two ABI incompatible libstdc++.so.*
> libraries etc.?  Just one or 2 libc.so.*/libm.so.*?

The existing GCC code tries to fix the libgcc function names so *tf* 
always means IBM long double and *kf* always means IEEE long double.  As 
noted in my reply to this patch, I suspect it might fail to handle 
__div?c3, __mul?c3 and __powi?c2 (at least) properly to avoid two 
different libgcc ABIs there.

I don't know the intent for libstdc++, libgfortran etc. - but it's been 
stated the intent is a single set of glibc libraries.  (Of course a 
distribution probably has other libraries influenced by the long double 
format in some way.)
Michael Meissner Jan. 5, 2018, 7:07 p.m. UTC | #4
On Fri, Jan 05, 2018 at 05:28:03PM +0000, Joseph Myers wrote:
> On Thu, 4 Jan 2018, Michael Meissner wrote:
> 
> > 	(CVT_FLOAT128_TO_IBM128): Use TFtype instead of __float128 to
> > 	accomidate -mabi=ieeelongdouble multilibs.
> 
> Why is that correct in the -mabi=ibmlongdouble case?

The PowerPC TFmode has always been 'special'.  It would mirror the 128-bit long
double format.  For the one port that actually used IEEE 128-bit floating
point, TFmode was IEEE.  For the the majority of ports TFmode is IBM extended
double.

So when I began this journey to add IEEE 128-bit support, I had to fit it into
this framework.

If long double is IBM extended double:
	TFmode is IBM extended double scalar
	TCmode is IBM extended double complex
	KFmode is IEEE scalar
	KCmode is IEEE complex
	IFmode is not used
	ICmode is not used

If long double is IEEE 128-bit (i.e. -mabi=ieeelongdouble):
	TFmode is IEEE scalar
	TCmode is IEEE complex
	KFmode is not used
	KCmode is not used
	IFmode is IBM extended double scalar
	ICmode is IBM extended double complex

We are just starting to look at the implications of switching the long double
type from IBM extended to IEEE.

While I would hope that eventualy GLIBC can do something with versioning so
that we avoid having to do multilibs, I suspect during initial development, we
will need multilibs just to get things right.  Then perhaps GLIBC can do
something like the original support for -mlong-double-64 and -mlong-double-128
went in.  However, since I don't work on GLIBC, I don't know how hard it is.  I
figured we would need multilibs as a crutch during initial development.

> As I understand it, TFtype is always of mode TFmode (it would certainly be 
> confusing if it sometimes had a different mode), but TFmode's format 
> depends on the selected ABI.  Where this code uses __float128, it requires 
> something that is always of IEEE binary128 format.  In the 
> -mabi=ieeelongdouble case, that's indeed TFtype, but not in the 
> -mabi=ibmlongdouble case when TFmode has ibm128 format.
> 
> In C code, _Float128 and _Complex _Float128 should always be available 
> when the binary128 format is supported, so I think the code needing that 
> format can safely use those.

Yes, in C code _Float128 _Comples works.  The trouble is compiling
libstdc++-v3.  In C++, we don't have _Float128, and __float128 _Complex does
not work for either x86 or PowerPC.  So on PowerPC the code from bits/floatn.h
is:


/* Defined to a complex binary128 type if __HAVE_FLOAT128 is 1.  */
#if __HAVE_FLOAT128
# if !__GNUC_PREREQ (7, 0) || defined __cplusplus
/* Add a typedef for older GCC compilers which don't natively support
   _Complex _Float128.  */
typedef _Complex float __cfloat128 __attribute__ ((__mode__ (__KC__)));
#  define __CFLOAT128 __cfloat128
# else
#  define __CFLOAT128 _Complex _Float128
# endif
#endif

Obviously, in a future release of GLIBC (via AT 11.0-3) we will fix that, but
it made the job of doing the initial port eaiser.

The problem is we need to get stuff into GCC so that GLIBC can start to add the
appropriate changes.


> > 	(__mulkc3): Use TFmode/TCmode for float128 scalar/complex types.
> > 	(__divkc3): Use TFmode/TCmode for float128 scalar/complex types.
> > 	* config/rs6000/extendkftf2-sw.c (__extendkftf2_sw): Likewise.
> > 	* config/rs6000/trunctfkf2-sw.c (__trunctfkf2_sw): Likewise.
> 
> And likewise here.
> 
> (My understanding is that each of the libgcc functions is meant to have a 
> particular ABI that does not depend on the format of long double - so the 
> "tf" and "tc" functions refer to ibm128 format, unconditionally, and the 
> "kf" and "kc" ones to binary128 format, unconditionally.  I have not 
> checked whether the libfuncs handling in init_float128_ibm and 
> init_float128_ieee is sufficient to achieve this in all cases.  In 
> particular, does complex arithmetic always use the correct one of "kc" and 
> "tc" depending on the long double format?  What about __builtin_powil - 
> does that properly use __powitf2 and __powikf2 as appropriate, or do you 
> have the ABI of __powitf2 depending on the multilib?)

Libgcc does not need to be multilibed.  It uses separate functions.  What does
currently need to be multilibed is libstdc++-v3 and possibly GLIBC.
Michael Meissner Jan. 5, 2018, 7:10 p.m. UTC | #5
On Fri, Jan 05, 2018 at 06:33:50PM +0100, Jakub Jelinek wrote:
> On Thu, Jan 04, 2018 at 06:05:55PM -0500, Michael Meissner wrote:
> > This patch is the beginning step to switching the PowerPC long double support
> > from IBM extended double to IEEE 128-bit floating point on PowerPC servers.  It
> > will be necessary to have this patch or a similar patch to allow the GLIBC team
> > to begin their modifications in GLIBC 2.28, so that by the time GCC 9 comes
> > out, we can decide to switch the default.  It is likely, the default will only
> > be switched on the 64-bit little endian PowerPC systems, when a distribution
> > goes through a major level, such that they can contemplate major changes.
> 
> When you're mentioning multilibs, does that mean that we'll have two ABI
> incompatible libgcc.so.* libraries, two ABI incompatible libstdc++.so.*
> libraries etc.?  Just one or 2 libc.so.*/libm.so.*?
> 
> At least when doing the long double format double to doubledouble transition
> (or on other targets to quad) last time we've managed to make it ABI
> compatible.

We are hoping that it eventually will not need multilibs.  But during the
initial development, it is likely that we will need to use multilibs.  That is
what the patch is for -- to allow building the compiler that supports
multilibs, but it is not on by default.

Part of the issue is GCC and GLIBC rev on different cycles and are done by
different people.  I have to guess what GLIBC will need, so that we have the
GLIBC solution by the time GCC 9 is ready.
Michael Meissner Jan. 5, 2018, 7:14 p.m. UTC | #6
On Fri, Jan 05, 2018 at 05:47:39PM +0000, Joseph Myers wrote:
> On Fri, 5 Jan 2018, Jakub Jelinek wrote:
> 
> > On Thu, Jan 04, 2018 at 06:05:55PM -0500, Michael Meissner wrote:
> > > This patch is the beginning step to switching the PowerPC long double support
> > > from IBM extended double to IEEE 128-bit floating point on PowerPC servers.  It
> > > will be necessary to have this patch or a similar patch to allow the GLIBC team
> > > to begin their modifications in GLIBC 2.28, so that by the time GCC 9 comes
> > > out, we can decide to switch the default.  It is likely, the default will only
> > > be switched on the 64-bit little endian PowerPC systems, when a distribution
> > > goes through a major level, such that they can contemplate major changes.
> > 
> > When you're mentioning multilibs, does that mean that we'll have two ABI
> > incompatible libgcc.so.* libraries, two ABI incompatible libstdc++.so.*
> > libraries etc.?  Just one or 2 libc.so.*/libm.so.*?
> 
> The existing GCC code tries to fix the libgcc function names so *tf* 
> always means IBM long double and *kf* always means IEEE long double.  As 
> noted in my reply to this patch, I suspect it might fail to handle 
> __div?c3, __mul?c3 and __powi?c2 (at least) properly to avoid two 
> different libgcc ABIs there.
> 
> I don't know the intent for libstdc++, libgfortran etc. - but it's been 
> stated the intent is a single set of glibc libraries.  (Of course a 
> distribution probably has other libraries influenced by the long double 
> format in some way.)

It would have been much simpler if we didn't already have a 128-bit floating
point type.  But we had the existing long double support.

In any case, even if you switch default long double format to IEEE, the kf/kc
functions in libgcc will be called, even though the type is now TFmode/TCmode.
It is unfortunate that the IBM extended double support did not define all of
the interfaces to be __gcc_q<xxx>, but there were some tf/tc functions defined
that are called, and I needed to pick unique names.
Jakub Jelinek Jan. 5, 2018, 7:22 p.m. UTC | #7
On Fri, Jan 05, 2018 at 02:07:51PM -0500, Michael Meissner wrote:
> Yes, in C code _Float128 _Comples works.  The trouble is compiling
> libstdc++-v3.  In C++, we don't have _Float128, and __float128 _Complex does
> not work for either x86 or PowerPC.  So on PowerPC the code from bits/floatn.h
> is:

Well, libstdc++-v3 should be certainly easier than glibc, at least assuming
that ICmode mangles differently from KCmode, because it should be just a
matter of compiling the subset of symbols refering to long double twice.

	Jakub
Michael Meissner Jan. 5, 2018, 7:25 p.m. UTC | #8
On Thu, Jan 04, 2018 at 06:05:55PM -0500, Michael Meissner wrote:
> This patch is the beginning step to switching the PowerPC long double support
> from IBM extended double to IEEE 128-bit floating point on PowerPC servers.  It
> will be necessary to have this patch or a similar patch to allow the GLIBC team
> to begin their modifications in GLIBC 2.28, so that by the time GCC 9 comes
> out, we can decide to switch the default.  It is likely, the default will only
> be switched on the 64-bit little endian PowerPC systems, when a distribution
> goes through a major level, such that they can contemplate major changes.

In doing some testing on a big endian system, it getting hairy to add support
to add optional multilibs for ieee/ibm.  On the BE system, the default cpu is
a power4, and so the IEEE emulator is not built unless you configure to make
power7, power8, or power9 the default cpu.  In addition, the BE system already
has multilibs for 64 vs. 32 bit.  While these things can be handled, it is not
currently planned to ultimately switch the long double format in BE.  So, this
patch replaces the previous patch, and it only allows you to switch the long
double format for powerpc64le-*-linux* systems.

Except for configure.ac and configure, all of the other changes are the same.

I have tested the patch on BE systems, and it builds normally providing you do
not use the --with-long-double-format option.

[gcc]
2018-01-05  Michael Meissner  <meissner@linux.vnet.ibm.com>

	* configure.ac (--with-long-double-format): Add support for
	configuration option to change the default long double format on
	little endian PowerPC Linux systems.
	* configure: Regenerate.
	* config.gcc (powerpc*-linux*-*): Add support for
	--with-long-double-format={ieee,ibm}.  If the format is explicit
	set, also set up IBM and IEEE multilibs.
	* config/rs6000/rs6000.h (FLOAT128_IEEE_P): Explicitly check for
	128-bit long doubles before checking TFmode or TCmode.
	(FLOAT128_IBM_P): Likewise.
	(TARGET_IEEEQUAD_MULTILIB): Set to 0 if not already defined.
	* config/rs6000/rs6000.c (rs6000_option_override_internal): If we
	have IBM/IEEE multilibs, don't give a warning if the user chagnes
	the long double format.
	(is_complex_IBM_long_double): Explicitly check for 128-bit long
	doubles before checking TCmode.
	* config/rs6000/rs6000-c.c (rs6000_cpu_cpp_builtins): If long
	double is IEEE, define __KC__ and __KF__ to allow floatn.h to be
	used without modification.
	* config/rs6000/linux64.h (MULTILIB_DEFAULTS_IEEE): Specify the
	-mabi={ieee,ibm}longdouble default for multilibs.
	(MULTILIB_DEFAULTS): Likewise.
	* config/rs6000/t-ldouble: New file, add IEEE/IBM long double
	multilibs.

[libgcc]
2018-01-05  Michael Meissner  <meissner@linux.vnet.ibm.com>

	* config/rs6000/quad-float128.h (IBM128_TYPE): Explicitly use
	__ibm128, instead of trying to use long double.
	(CVT_FLOAT128_TO_IBM128): Use TFtype instead of __float128 to
	accomidate -mabi=ieeelongdouble multilibs.
	(CVT_IBM128_TO_FLOAT128): Likewise.
	* config/rs6000/ibm-ldouble.c (IBM128_TYPE): New macro to define
	the appropriate IBM extended double type.
	(__gcc_qadd): Change all occurances of long double to IBM128_TYPE.
	(__gcc_qsub): Likewise.
	(__gcc_qmul): Likewise.
	(__gcc_qdiv): Likewise.
	(pack_ldouble): Likewise.
	(__gcc_qneg): Likewise.
	(__gcc_qeq): Likewise.
	(__gcc_qne): Likewise.
	(__gcc_qge): Likewise.
	(__gcc_qle): Likewise.
	(__gcc_stoq): Likewise.
	(__gcc_dtoq): Likewise.
	(__gcc_itoq): Likewise.
	(__gcc_utoq): Likewise.
	(__gcc_qunord): Likewise.
	* config/rs6000/_mulkc3.c (toplevel): Include soft-fp.h and
	quad-float128.h for the definitions.
	(COPYSIGN): Use the f128 version instead of the q version.
	(INFINITY): Likewise.
	(__mulkc3): Use TFmode/TCmode for float128 scalar/complex types.
	* config/rs6000/_divkc3.c (toplevel): Include soft-fp.h and
	quad-float128.h for the definitions.
	(COPYSIGN): Use the f128 version instead of the q version.
	(INFINITY): Likewise.
	(FABS): Likewise.
	(__divkc3): Use TFmode/TCmode for float128 scalar/complex types.
	* config/rs6000/extendkftf2-sw.c (__extendkftf2_sw): Likewise.
	* config/rs6000/trunctfkf2-sw.c (__trunctfkf2_sw): Likewise.
Michael Meissner Jan. 5, 2018, 7:26 p.m. UTC | #9
On Fri, Jan 05, 2018 at 08:22:57PM +0100, Jakub Jelinek wrote:
> On Fri, Jan 05, 2018 at 02:07:51PM -0500, Michael Meissner wrote:
> > Yes, in C code _Float128 _Comples works.  The trouble is compiling
> > libstdc++-v3.  In C++, we don't have _Float128, and __float128 _Complex does
> > not work for either x86 or PowerPC.  So on PowerPC the code from bits/floatn.h
> > is:
> 
> Well, libstdc++-v3 should be certainly easier than glibc, at least assuming
> that ICmode mangles differently from KCmode, because it should be just a
> matter of compiling the subset of symbols refering to long double twice.

Yep.  But as I said, I think we will need the crutch of having multilibs
initially.
Joseph Myers Jan. 5, 2018, 9:41 p.m. UTC | #10
On Fri, 5 Jan 2018, Michael Meissner wrote:

> On Fri, Jan 05, 2018 at 05:28:03PM +0000, Joseph Myers wrote:
> > On Thu, 4 Jan 2018, Michael Meissner wrote:
> > 
> > > 	(CVT_FLOAT128_TO_IBM128): Use TFtype instead of __float128 to
> > > 	accomidate -mabi=ieeelongdouble multilibs.
> > 
> > Why is that correct in the -mabi=ibmlongdouble case?
> 
> The PowerPC TFmode has always been 'special'.  It would mirror the 128-bit long
> double format.  For the one port that actually used IEEE 128-bit floating
> point, TFmode was IEEE.  For the the majority of ports TFmode is IBM extended
> double.

I don't think this answers my question.

CVT_FLOAT128_TO_IBM128 has an argument VALUE that is always of IEEE 
format.  You're doing "TFtype __value = (VALUE);".  In the case where 
TFmode is IBM long double, and so therefore is TFtype, this will do an 
unwanted conversion.  I'd expect it to result in __extendkftf2 recursively 
calling itself, in fact.  If it does not, what's wrong with my reasoning, 
and what exactly does that line do in the case where long double is 
ibm128?

> Yes, in C code _Float128 _Comples works.  The trouble is compiling
> libstdc++-v3.  In C++, we don't have _Float128, and __float128 _Complex does

My comments are about changes to code in libgcc, not about libstdc++-v3.

> > (My understanding is that each of the libgcc functions is meant to have a 
> > particular ABI that does not depend on the format of long double - so the 
> > "tf" and "tc" functions refer to ibm128 format, unconditionally, and the 
> > "kf" and "kc" ones to binary128 format, unconditionally.  I have not 
> > checked whether the libfuncs handling in init_float128_ibm and 
> > init_float128_ieee is sufficient to achieve this in all cases.  In 
> > particular, does complex arithmetic always use the correct one of "kc" and 
> > "tc" depending on the long double format?  What about __builtin_powil - 
> > does that properly use __powitf2 and __powikf2 as appropriate, or do you 
> > have the ABI of __powitf2 depending on the multilib?)
> 
> Libgcc does not need to be multilibed.  It uses separate functions.  What does
> currently need to be multilibed is libstdc++-v3 and possibly GLIBC.

I don't see how you ensure __mulkc3, for example, always uses IEEE format, 
given that you're making it use TFtype (= IBM long double in the default 
case).

I don't see how you ensure that, when IEEE long double is the default, 
__multc3 is still built to use IBM long double, which is the ABI for that 
function name.

Likewise for __divkc3, __divtc3, __powitf2, __powikf2.

For that matter, when building with IEEE long double as the default, how 
do you ensure that libgcc functions such as __fixtfti (built from generic 
libgcc2.c sources, in that case) are built with the proper ABI, meaning 
use of IFmode for the arguments or results corresponding to the "tf" in 
the name?
Segher Boessenkool Jan. 8, 2018, 4:17 p.m. UTC | #11
On Thu, Jan 04, 2018 at 06:05:55PM -0500, Michael Meissner wrote:
> This patch is the beginning step to switching the PowerPC long double support
> from IBM extended double to IEEE 128-bit floating point on PowerPC servers.  It
> will be necessary to have this patch or a similar patch to allow the GLIBC team
> to begin their modifications in GLIBC 2.28, so that by the time GCC 9 comes
> out, we can decide to switch the default.  It is likely, the default will only
> be switched on the 64-bit little endian PowerPC systems, when a distribution
> goes through a major level, such that they can contemplate major changes.

I would hope the default changes for BE systems at the same time (at
least those with VSX, but ideally *all*).

> If you do not use the configuration option --with-long-double-format=ieee or
> --with-long-double-format=ibm, the system will not build multilibs, and just
> build normal libraries with the default set to IBM extended double.  If you do
> use either of the switches, and allow multilibs, it will build two sets of
> multilibs, one for -mabi=ieeelongdouble and one for -mabi=ibmlongdouble.

Huh.  Why not always, then?  There already is an option to turn off
multilibs, for people who really really want that.


Segher
Michael Meissner Jan. 8, 2018, 5:28 p.m. UTC | #12
On Mon, Jan 08, 2018 at 10:17:06AM -0600, Segher Boessenkool wrote:
> On Thu, Jan 04, 2018 at 06:05:55PM -0500, Michael Meissner wrote:
> > This patch is the beginning step to switching the PowerPC long double support
> > from IBM extended double to IEEE 128-bit floating point on PowerPC servers.  It
> > will be necessary to have this patch or a similar patch to allow the GLIBC team
> > to begin their modifications in GLIBC 2.28, so that by the time GCC 9 comes
> > out, we can decide to switch the default.  It is likely, the default will only
> > be switched on the 64-bit little endian PowerPC systems, when a distribution
> > goes through a major level, such that they can contemplate major changes.
> 
> I would hope the default changes for BE systems at the same time (at
> least those with VSX, but ideally *all*).

Note, the change has to be on a system by system basis.  We will need to
support distributions that use the IBM extended double for the long double
format, and we will need to support distributions for the IEEE 128-bit format.
It all depends on what the host system uses.  While the work can be done, I
don't know of any BE distribution that will be using GCC 8 as their main
compiler.

> > If you do not use the configuration option --with-long-double-format=ieee or
> > --with-long-double-format=ibm, the system will not build multilibs, and just
> > build normal libraries with the default set to IBM extended double.  If you do
> > use either of the switches, and allow multilibs, it will build two sets of
> > multilibs, one for -mabi=ieeelongdouble and one for -mabi=ibmlongdouble.
> 
> Huh.  Why not always, then?  There already is an option to turn off
> multilibs, for people who really really want that.

I'm trying not to surprise people building compilers for a setup that does not
work.  In the GCC 9 timeframe, when there is GLIBC support for it, we can make
it default (assuming we keep the multilibs).

It is a chicken and egg problem.  Real users (as opposed to GCC and GLIBC
developers) would need GLIBC 2.28 in order to use the IEEE multilib.  But if we
don't provide the switch or multilib as an option, it makes the GLIBC work
harder.  I suspect that libstc++-v3 may be more of an issue than GLIBC, since
we have people starting to look at the GLIBC work, but we can't really do
anything about libstdc++-v3 until we have a GLIBC.
Joseph Myers Jan. 9, 2018, 9:14 p.m. UTC | #13
To answer some of my own questions about how this works (or doesn't work):

There are two different types in libgcc called TFtype, one in 
quad-float128.h and one in libgcc2.h.  The one in quad-float128.h is 
mapped to KFmode in the case where TFmode is IBM long double, so functions 
such as __mulkc3 do get the correct types.

As far as I can tell, functions such as __multf3, and libgcc2.c TFmode 
functions in general, get the version of TFtype from libgcc2.h (which is 
always of mode TFmode).  So I still don't see how you ensure all those 
functions do use IBM long double when IEEE long double is the default (but 
have not tested a build with IEEE long double as default).  (And __powikf2 
doesn't even exist, but is needed for __builtin_powil to work properly in 
the IEEE long double case.)

I have confirmed with testing that _Complex long double multiplication 
with -mabi=ieeelongdouble still uses __multc3, although it needs to use 
__mulkc3, and, likewise, _Complex long double division with 
-mabi=ieeelongdouble wrongly uses __divtc3 but should be using __divkc3.
Michael Meissner Jan. 12, 2018, 6:46 a.m. UTC | #14
This is my current multilib version support for migrating PowerPC servers from
using IBM extended double as the long double type to IEEE 128-bit floating
point.

I have built both little endian and big endian PowerPC toolchains without the
options, and it works with no regressions.  I have also built a PowerPC little
endian multlib toolchain (with IBM extended double as the default) and it
worked, once I remembered to add the --with-system-zlib option.

All of the other patches have been broken out of this patch and submitted (and
now comitteed -- thanks Segher), and this patch just adds the option multlib
support for PowerPC little endian.  I ran out of time to add the PowerPC big
endian multilib support (as it has to merge with 64/32-bit multilibs, and it
also can only be enabled if the compiler is compiled using --with-cpu with at
least power7).

Some changes from the last change based on comments I got:

1) The lib64 directory is the directory that holds the default libraries.  If
you configure the default to be IEEE 128-bit, then those libraries are put into
lib64.  As Bill Schmidt said in an internal meeting, that is required by the
ABI.  Other languages should work normally, assuming they don't use long
double.  If they do use long double and use other libraries than libc/libm,
they may need to use an -L -rpath optiosn to point to the old libraries.  I'm
sure as we get into modifying GLIBC 2.28, we will discover new things.

2) If you configure the compiler so that IBM long double is the default, the
IEEE libraries are in lib64/ieee128.  If you configure the compiler so that
IEEE is the default, the IBM extended double libraries are in lib64/ibm128.  I
assume if we do a big endian port, we would use lib/ieee128 and lib/ibm128.

3) Tulio says that he believes that the GLIBC libraries will be able to handle
the switch with a single library.  However, it is not clear to me that other
libraries like libstdc++, boost, etc. would be easy to add the necessary
support to change the interfaces based on the defines.  This is why I think we
need multilibs, at least for a transition period.

4) As before, you have to explicitly configure the long double format to enable
the multilibs.  Particularly with having to create a special version of the
Advance Toolchain with the crt/lib files in the alternate directory and use
--with-system-zlib, you really don't want to enable the multilibs by default.

Can I check this into the trunk?

As I post this, there are two previous patches that have not been ack'ed that
are not needed to enable the multilibs, but will be needed as we start doing
the transition.  The patches are:

1) The patch to set .gnu_attribute #4 if you use a long double value but don't
do any calls.

2) The patch to document the --with-long-double-format={ieee,ibm} option.

It would be useful if I could configure the compiler to look in lib64, if it
doesn't find the objects in lib64/ieee128 or lib64/ibm128.  But perhaps it is
safer if it doesn't, since some things may fall through the cracks.

Note, I will be on vacation for the next 4 days, and I will return on Tuesday
January 16th, 2018.  I will not have access to mail for most of the time.

2018-01-12  Michael Meissner  <meissner@linux.vnet.ibm.com>

	* config.gcc (powerpc*-linux*-*): Add support for 64-bit little
	endian Linux systems to optionally enable multilibs for selecting
	the long double type if the user configured an explicit type.
	* config/rs6000/rs6000.h (TARGET_IEEEQUAD_MULTILIB): Indicate we
	have no long double multilibs if not defined.
	* config/rs6000/rs6000.c (rs6000_option_override_internal): Do not
	warn if the user used -mabi={ieee,ibm}longdouble and we built
	multilibs for long double.
	* config/rs6000/linux64.h (MULTILIB_DEFAULTS_IEEE): Define as the
	appropriate multilib option.
	(MULTILIB_DEFAULTS): Add MULTILIB_DEFAULTS_IEEE to the default
	multilib options.
	* config/rs6000/t-ldouble-linux64le-ibm: New configuration files
	for building long double multilibs.
	* config/rs6000/t-ldouble-linux64le-ieee: Likewise.
Michael Meissner Jan. 12, 2018, 12:23 p.m. UTC | #15
Of course it would be helpful, if I included the patch:

2018-01-12  Michael Meissner  <meissner@linux.vnet.ibm.com>

	* config.gcc (powerpc*-linux*-*): Add support for 64-bit little
	endian Linux systems to optionally enable multilibs for selecting
	the long double type if the user configured an explicit type.
	* config/rs6000/rs6000.h (TARGET_IEEEQUAD_MULTILIB): Indicate we
	have no long double multilibs if not defined.
	* config/rs6000/rs6000.c (rs6000_option_override_internal): Do not
	warn if the user used -mabi={ieee,ibm}longdouble and we built
	multilibs for long double.
	* config/rs6000/linux64.h (MULTILIB_DEFAULTS_IEEE): Define as the
	appropriate multilib option.
	(MULTILIB_DEFAULTS): Add MULTILIB_DEFAULTS_IEEE to the default
	multilib options.
	* config/rs6000/t-ldouble-linux64le-ibm: New configuration files
	for building long double multilibs.
	* config/rs6000/t-ldouble-linux64le-ieee: Likewise.
Segher Boessenkool Jan. 12, 2018, 5:53 p.m. UTC | #16
On Fri, Jan 12, 2018 at 07:23:37AM -0500, Michael Meissner wrote:
> Of course it would be helpful, if I included the patch:

Yup :-)

> 2018-01-12  Michael Meissner  <meissner@linux.vnet.ibm.com>
> 
> 	* config.gcc (powerpc*-linux*-*): Add support for 64-bit little
> 	endian Linux systems to optionally enable multilibs for selecting
> 	the long double type if the user configured an explicit type.
> 	* config/rs6000/rs6000.h (TARGET_IEEEQUAD_MULTILIB): Indicate we
> 	have no long double multilibs if not defined.
> 	* config/rs6000/rs6000.c (rs6000_option_override_internal): Do not
> 	warn if the user used -mabi={ieee,ibm}longdouble and we built
> 	multilibs for long double.
> 	* config/rs6000/linux64.h (MULTILIB_DEFAULTS_IEEE): Define as the
> 	appropriate multilib option.
> 	(MULTILIB_DEFAULTS): Add MULTILIB_DEFAULTS_IEEE to the default
> 	multilib options.
> 	* config/rs6000/t-ldouble-linux64le-ibm: New configuration files
> 	for building long double multilibs.
> 	* config/rs6000/t-ldouble-linux64le-ieee: Likewise.


> +		case "${target}:${enable_multilib}:${with_long_double_format}" in
> +		    powerpc64le*:yes:ieee | powerpc64le*:yes:ibm)
> +			tm_defines="${tm_defines} TARGET_IEEEQUAD_MULTILIB=1"
> +			tmake_file="${tmake_file} rs6000/t-ldouble-linux64le-${with_long_double_format}"
> +			;;
> +		    *)
> +			:
> +			;;

You could just leave out those three lines default (or at least the :).

Looks fine I think.  Okay for trunk, thanks!


Segher
Segher Boessenkool Jan. 12, 2018, 5:58 p.m. UTC | #17
Hi!

On Fri, Jan 12, 2018 at 01:46:27AM -0500, Michael Meissner wrote:
> This is my current multilib version support for migrating PowerPC servers from
> using IBM extended double as the long double type to IEEE 128-bit floating
> point.
> 
> I have built both little endian and big endian PowerPC toolchains without the
> options, and it works with no regressions.  I have also built a PowerPC little
> endian multlib toolchain (with IBM extended double as the default) and it
> worked, once I remembered to add the --with-system-zlib option.
> 
> All of the other patches have been broken out of this patch and submitted (and
> now comitteed -- thanks Segher), and this patch just adds the option multlib
> support for PowerPC little endian.  I ran out of time to add the PowerPC big
> endian multilib support (as it has to merge with 64/32-bit multilibs, and it
> also can only be enabled if the compiler is compiled using --with-cpu with at
> least power7).

Right -- it will be much simpler if we can use ieee128 also without VSX.

> Some changes from the last change based on comments I got:
> 
> 1) The lib64 directory is the directory that holds the default libraries.  If
> you configure the default to be IEEE 128-bit, then those libraries are put into
> lib64.  As Bill Schmidt said in an internal meeting, that is required by the
> ABI.  Other languages should work normally, assuming they don't use long
> double.  If they do use long double and use other libraries than libc/libm,
> they may need to use an -L -rpath optiosn to point to the old libraries.  I'm
> sure as we get into modifying GLIBC 2.28, we will discover new things.

"Brace yourself, winter is coming".

> 2) If you configure the compiler so that IBM long double is the default, the
> IEEE libraries are in lib64/ieee128.  If you configure the compiler so that
> IEEE is the default, the IBM extended double libraries are in lib64/ibm128.  I
> assume if we do a big endian port, we would use lib/ieee128 and lib/ibm128.

For the 32-bit libs?  Yeah.

> 3) Tulio says that he believes that the GLIBC libraries will be able to handle
> the switch with a single library.  However, it is not clear to me that other
> libraries like libstdc++, boost, etc. would be easy to add the necessary
> support to change the interfaces based on the defines.  This is why I think we
> need multilibs, at least for a transition period.
> 
> 4) As before, you have to explicitly configure the long double format to enable
> the multilibs.  Particularly with having to create a special version of the
> Advance Toolchain with the crt/lib files in the alternate directory and use
> --with-system-zlib, you really don't want to enable the multilibs by default.
> 
> Can I check this into the trunk?
> 
> As I post this, there are two previous patches that have not been ack'ed that
> are not needed to enable the multilibs, but will be needed as we start doing
> the transition.  The patches are:
> 
> 1) The patch to set .gnu_attribute #4 if you use a long double value but don't
> do any calls.
> 
> 2) The patch to document the --with-long-double-format={ieee,ibm} option.
> 
> It would be useful if I could configure the compiler to look in lib64, if it
> doesn't find the objects in lib64/ieee128 or lib64/ibm128.  But perhaps it is
> safer if it doesn't, since some things may fall through the cracks.

I think it always does that?  If not, get back to me when you need this?

> Note, I will be on vacation for the next 4 days, and I will return on Tuesday
> January 16th, 2018.  I will not have access to mail for most of the time.

Enjoy your vacation!


Segher
diff mbox series

Patch

Index: gcc/configure.ac
===================================================================
--- gcc/configure.ac	(revision 256120)
+++ gcc/configure.ac	(working copy)
@@ -5885,6 +5885,30 @@  if test x$gcc_cv_target_ldbl128 = xyes; 
 	    [Define if TFmode long double should be the default])
 fi
 
+# Check if TFmode long double target should use the IBM extended double or IEEE
+# 128-bit floating point formats if long doubles are 128-bits long.  The long
+# double type can only be switched on powerpc64 bit Linux systems where VSX is
+# supported.  Other PowerPC systems do not build the IEEE 128-bit emulator in
+# liggcc.
+AC_ARG_WITH([long-double-format],
+  [AS_HELP_STRING([--with-long-double-format={ieee,ibm}]
+		  [Specify whether PowerPC long double uses IEEE or IBM format])],[
+case "$target:$with_cpu:$with_long_double_format" in
+  powerpc*-*-linux*:power[789]:ieee | powerpc*-*-linux*:power[1-9][0-9]+:ieee | \
+  powerpc*-*-linux*:power[789]:ibm | powerpc*-*-linux*:power[1-9][0-9]+:ibm | \
+  powerpc64le-*-linux*:*:ieee | powerpc64le-*-linux*:*:ibm)
+    ;;
+  powerpc*-*-linux*:power[789]:* | powerpc*-*-linux*:power[1-9][0-9]+:* | \
+  powerpc64le-*-linux*:*:*)
+    AC_MSG_ERROR([--with-long-double-format argument should be ibm or ieee])
+    ;;
+  *)
+    AC_MSG_ERROR([Configure option --with-long-double-format is only supported \
+for PowerPC VSX Linux systems])
+    ;;
+esac],
+  [])
+
 # Check if the target LIBC supports exporting the AT_PLATFORM and AT_HWCAP
 # values in the TCB.  Currently, only GLIBC 2.23 and later support this.
 gcc_cv_libc_provides_hwcap_in_tcb=no
Index: gcc/configure
===================================================================
--- gcc/configure	(revision 256120)
+++ gcc/configure	(working copy)
@@ -945,6 +945,7 @@  enable_linker_build_id
 enable_libssp
 enable_default_ssp
 with_long_double_128
+with_long_double_format
 with_gc
 with_system_zlib
 enable_maintainer_mode
@@ -1738,6 +1739,9 @@  Optional Packages:
   --with-glibc-version=M.N
                           assume GCC used with glibc version M.N or later
   --with-long-double-128  use 128-bit long double by default
+  --with-long-double-format={ieee,ibm}
+		  Specify whether PowerPC long double uses IEEE or IBM format
+
   --with-gc={page,zone}   this option is not supported anymore. It used to
                           choose the garbage collection mechanism to use with
                           the compiler
@@ -18442,7 +18446,7 @@  else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 18445 "configure"
+#line 18449 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -18548,7 +18552,7 @@  else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 18551 "configure"
+#line 18555 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -29185,6 +29189,32 @@  $as_echo "#define TARGET_DEFAULT_LONG_DO
 
 fi
 
+# Check if TFmode long double target should use the IBM extended double or IEEE
+# 128-bit floating point formats if long doubles are 128-bits long.  The long
+# double type can only be switched on powerpc64 bit Linux systems where VSX is
+# supported.  Other PowerPC systems do not build the IEEE 128-bit emulator in
+# liggcc.
+
+# Check whether --with-long-double-format was given.
+if test "${with_long_double_format+set}" = set; then :
+  withval=$with_long_double_format;
+case "$target:$with_cpu:$with_long_double_format" in
+  powerpc*-*-linux*:power789:ieee | powerpc*-*-linux*:power1-90-9+:ieee | \
+  powerpc*-*-linux*:power789:ibm | powerpc*-*-linux*:power1-90-9+:ibm | \
+  powerpc64le-*-linux*:*:ieee | powerpc64le-*-linux*:*:ibm)
+    ;;
+  powerpc*-*-linux*:power789:* | powerpc*-*-linux*:power1-90-9+:* | \
+  powerpc64le-*-linux*:*:*)
+    as_fn_error "--with-long-double-format argument should be ibm or ieee" "$LINENO" 5
+    ;;
+  *)
+    as_fn_error "Configure option --with-long-double-format is only supported \
+for PowerPC VSX Linux systems" "$LINENO" 5
+    ;;
+esac
+fi
+
+
 # Check if the target LIBC supports exporting the AT_PLATFORM and AT_HWCAP
 # values in the TCB.  Currently, only GLIBC 2.23 and later support this.
 gcc_cv_libc_provides_hwcap_in_tcb=no
Index: gcc/config.gcc
===================================================================
--- gcc/config.gcc	(revision 256120)
+++ gcc/config.gcc	(working copy)
@@ -4392,6 +4392,24 @@  case "${target}" in
 			exit 1
 		    fi
 		fi
+
+		# Set up the default long double format.  Only enable the
+		# IEEE/IBM multilibs if the user explicitly set the long double
+		# format and did not do --disable-multilib.
+		if test x$with_long_double_format = xieee; then
+		    tm_defines="${tm_defines} TARGET_IEEEQUAD_DEFAULT=1"
+		    if test x$enable_multilib = xyes; then
+			tm_defines="${tm_defines} TARGET_IEEEQUAD_MULTILIB=1"
+			tmake_file="${tmake_file} rs6000/t-ldouble"
+		    fi
+
+		elif test x$with_long_double_format = xibm; then
+		    tm_defines="${tm_defines} TARGET_IEEEQUAD_DEFAULT=0"
+		    if test x$enable_multilib = xyes; then
+			tm_defines="${tm_defines} TARGET_IEEEQUAD_MULTILIB=1"
+			tmake_file="${tmake_file} rs6000/t-ldouble"
+		    fi
+		fi
 		;;
 
 	s390*-*-*)
Index: gcc/config/rs6000/rs6000.h
===================================================================
--- gcc/config/rs6000/rs6000.h	(revision 256120)
+++ gcc/config/rs6000/rs6000.h	(working copy)
@@ -437,11 +437,13 @@  extern const char *host_detect_local_cpu
    Similarly IFmode is the IBM long double format even if the default is IEEE
    128-bit.  Don't allow IFmode if -msoft-float.  */
 #define FLOAT128_IEEE_P(MODE)						\
-  ((TARGET_IEEEQUAD && ((MODE) == TFmode || (MODE) == TCmode))		\
+  ((TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128				\
+    && ((MODE) == TFmode || (MODE) == TCmode))				\
    || ((MODE) == KFmode) || ((MODE) == KCmode))
 
 #define FLOAT128_IBM_P(MODE)						\
-  ((!TARGET_IEEEQUAD && ((MODE) == TFmode || (MODE) == TCmode))		\
+  ((!TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128				\
+    && ((MODE) == TFmode || (MODE) == TCmode))				\
    || (TARGET_HARD_FLOAT && ((MODE) == IFmode || (MODE) == ICmode)))
 
 /* Helper macros to say whether a 128-bit floating point type can go in a
@@ -562,6 +564,12 @@  extern int rs6000_vector_align[];
 #define TARGET_ALTIVEC_ABI rs6000_altivec_abi
 #define TARGET_LDBRX (TARGET_POPCNTD || rs6000_cpu == PROCESSOR_CELL)
 
+/* Define as 1 if we support multilibs for switching long double between IEEE
+   128-bit floating point and IBM extended double.  */
+#ifndef TARGET_IEEEQUAD_MULTILIB
+#define TARGET_IEEEQUAD_MULTILIB 0
+#endif
+
 /* ISA 2.01 allowed FCFID to be done in 32-bit, previously it was 64-bit only.
    Enable 32-bit fcfid's on any of the switches for newer ISA machines or
    XILINX.  */
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 256120)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -4600,11 +4600,15 @@  rs6000_option_override_internal (bool gl
      systems will also set long double to be IEEE 128-bit.  AIX and Darwin
      explicitly redefine TARGET_IEEEQUAD and TARGET_IEEEQUAD_DEFAULT to 0, so
      those systems will not pick up this default.  Warn if the user changes the
-     default unless -Wno-psabi.  */
+     default unless either the user used the -Wno-psabi option, or the compiler
+     was built to enable multilibs to switch between the two long double
+     types.  */
   if (!global_options_set.x_rs6000_ieeequad)
     rs6000_ieeequad = TARGET_IEEEQUAD_DEFAULT;
 
-  else if (rs6000_ieeequad != TARGET_IEEEQUAD_DEFAULT && TARGET_LONG_DOUBLE_128)
+  else if (!TARGET_IEEEQUAD_MULTILIB
+	   && rs6000_ieeequad != TARGET_IEEEQUAD_DEFAULT
+	   && TARGET_LONG_DOUBLE_128)
     {
       static bool warned_change_long_double;
       if (!warned_change_long_double)
@@ -11424,7 +11428,9 @@  rs6000_must_pass_in_stack (machine_mode 
 static inline bool
 is_complex_IBM_long_double (machine_mode mode)
 {
-  return mode == ICmode || (!TARGET_IEEEQUAD && mode == TCmode);
+  return mode == ICmode || (!TARGET_IEEEQUAD
+			    && TARGET_LONG_DOUBLE_128
+			    && mode == TCmode);
 }
 
 /* Whether ABI_V4 passes MODE args to a function in floating point
Index: gcc/config/rs6000/rs6000-c.c
===================================================================
--- gcc/config/rs6000/rs6000-c.c	(revision 256120)
+++ gcc/config/rs6000/rs6000-c.c	(working copy)
@@ -708,7 +708,18 @@  rs6000_cpu_cpp_builtins (cpp_reader *pfi
       builtin_define ("__LONGDOUBLE128");
 
       if (TARGET_IEEEQUAD)
-	builtin_define ("__LONG_DOUBLE_IEEE128__");
+	{
+	  /* Older versions of GLIBC used __attribute__((__KC__)) to create the
+	     IEEE 128-bit floating point complex type for C++ (which does not
+	     support _Float128 _Complex).  If the default for long double is
+	     IEEE 128-bit mode, the library would need to use
+	     __attribute__((__TC__)) instead.  Defining __KF__ and __KC__
+	     is a stop-gap to build with the older libraries, until we
+	     get an updated library.  */
+	  builtin_define ("__LONG_DOUBLE_IEEE128__");
+	  builtin_define ("__KF__=__TF__");
+	  builtin_define ("__KC__=__TC__");
+	}
       else
 	builtin_define ("__LONG_DOUBLE_IBM128__");
     }
Index: gcc/config/rs6000/linux64.h
===================================================================
--- gcc/config/rs6000/linux64.h	(revision 256120)
+++ gcc/config/rs6000/linux64.h	(working copy)
@@ -245,11 +245,23 @@  extern int dot_symbols;
 #define DYNAMIC_LINKER_PREFIX	""
 #endif
 
+#if TARGET_IEEEQUAD_MULTILIB
+#if TARGET_IEEEQUAD_DEFAULT
+#define MULTILIB_DEFAULTS_IEEE , "mabi=ieeelongdouble"
+
+#else	/* TARGET_IEEEQUAD_DEFAULT.  */
+#define MULTILIB_DEFAULTS_IEEE , "mabi=ibmlongdouble"
+#endif	/* TARGET_IEEEQUAD_DEFAULT.  */
+
+#else	/* TARGET_IEEEQUAD_MULTILIB.  */
+#define MULTILIB_DEFAULTS_IEEE
+#endif	/* TARGET_IEEEQUAD_MULTILIB.  */
+
 #undef	MULTILIB_DEFAULTS
 #if DEFAULT_ARCH64_P
-#define MULTILIB_DEFAULTS { "m64" }
+#define MULTILIB_DEFAULTS { "m64" MULTILIB_DEFAULTS_IEEE }
 #else
-#define MULTILIB_DEFAULTS { "m32" }
+#define MULTILIB_DEFAULTS { "m32" MULTILIB_DEFAULTS_IEEE }
 #endif
 
 /* Split stack is only supported for 64 bit, and requires glibc >= 2.18.  */
Index: gcc/config/rs6000/t-ldouble
===================================================================
--- gcc/config/rs6000/t-ldouble	(revision 0)
+++ gcc/config/rs6000/t-ldouble	(revision 0)
@@ -0,0 +1,24 @@ 
+# Copyright (C) 2017 Free Software Foundation, Inc.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# Enable building IEEE 128-bit floating point multilibs on a system that
+# defaults to IBM extended double floating point.
+MULTILIB_OPTIONS        += mabi=ibmlongdouble/mabi=ieeelongdouble
+MULTILIB_DIRNAMES       += ibm128 ieee128
+MULTILIB_OSDIRNAMES     += mabi.ibmlongdouble=../lib64 mabi.ieeelongdouble=../ieee64 ../lib64
+
Index: libgcc/config/rs6000/quad-float128.h
===================================================================
--- libgcc/config/rs6000/quad-float128.h	(revision 256120)
+++ libgcc/config/rs6000/quad-float128.h	(working copy)
@@ -51,12 +51,7 @@  typedef __complex float TCtype __attribu
 
 #include <quad.h>
 
-#ifdef __LONG_DOUBLE_IEEE128__
-#define IBM128_TYPE		__ibm128
-
-#else
-#define IBM128_TYPE		long double
-#endif
+#define IBM128_TYPE	__ibm128
 
 /* Add prototypes of the library functions created.  In case the appropriate
    int/long types are not declared in scope by the time quad.h is included,
@@ -185,7 +180,7 @@  union ibm128_union {
 #define CVT_FLOAT128_TO_IBM128(RESULT, VALUE)				\
 {									\
   double __high, __low;							\
-  __float128 __value = (VALUE);						\
+  TFtype __value = (VALUE);						\
   union ibm128_union u;							\
 									\
   __high = (double) __value;						\
@@ -196,7 +191,7 @@  union ibm128_union {
     {									\
       double __high_temp;						\
 									\
-      __low = (double) (__value - (__float128) __high);			\
+      __low = (double) (__value - (TFtype) __high);			\
       /* Renormalize low/high and move them into canonical IBM long	\
 	 double form.  */						\
       __high_temp = __high + __low;					\
@@ -220,13 +215,13 @@  union ibm128_union {
 									\
   /* Handle the special cases of NAN and infinity.  */			\
   if (__builtin_isnan (__high) || __builtin_isinf (__high))		\
-    RESULT = (__float128) __high;					\
+    RESULT = (TFtype) __high;						\
 									\
   /* If low is 0.0, there no need to do the add.  In addition,		\
      avoiding the add produces the correct sign if high is -0.0.  */	\
   else if (__low == 0.0)						\
-    RESULT = (__float128) __high;					\
+    RESULT = (TFtype) __high;						\
 									\
   else									\
-    RESULT = ((__float128) __high) + ((__float128) __low);		\
+    RESULT = ((TFtype) __high) + ((TFtype) __low);			\
 }
Index: libgcc/config/rs6000/ibm-ldouble.c
===================================================================
--- libgcc/config/rs6000/ibm-ldouble.c	(revision 256120)
+++ libgcc/config/rs6000/ibm-ldouble.c	(working copy)
@@ -56,6 +56,15 @@  see the files COPYING3 and COPYING.RUNTI
 
 #define nonfinite(a) unlikely (! isless (fabs (a), inf ()))
 
+/* If we have __float128/_Float128, use __ibm128 instead of long double.  On
+   other systems, use long double, because __ibm128 might not have been
+   created.  */
+#ifdef __FLOAT128__
+#define IBM128_TYPE __ibm128
+#else
+#define IBM128_TYPE long double
+#endif
+
 /* Define ALIASNAME as a strong alias for NAME.  */
 # define strong_alias(name, aliasname) _strong_alias(name, aliasname)
 # define _strong_alias(name, aliasname) \
@@ -65,10 +74,10 @@  see the files COPYING3 and COPYING.RUNTI
    but GCC currently generates poor code when a union is used to turn
    a long double into a pair of doubles.  */
 
-long double __gcc_qadd (double, double, double, double);
-long double __gcc_qsub (double, double, double, double);
-long double __gcc_qmul (double, double, double, double);
-long double __gcc_qdiv (double, double, double, double);
+IBM128_TYPE __gcc_qadd (double, double, double, double);
+IBM128_TYPE __gcc_qsub (double, double, double, double);
+IBM128_TYPE __gcc_qmul (double, double, double, double);
+IBM128_TYPE __gcc_qdiv (double, double, double, double);
 
 #if defined __ELF__ && defined SHARED \
     && (defined __powerpc64__ || !(defined __linux__ || defined __gnu_hurd__))
@@ -88,17 +97,17 @@  __asm__ (".symver __gcc_qadd,_xlqadd@GCC
 	 ".symver .__gcc_qdiv,._xlqdiv@GCC_3.4");
 #endif
 
-/* Combine two 'double' values into one 'long double' and return the result.  */
-static inline long double
+/* Combine two 'double' values into one 'IBM128_TYPE' and return the result.  */
+static inline IBM128_TYPE
 pack_ldouble (double dh, double dl)
 {
-#if defined (__LONG_DOUBLE_128__) \
+#if defined (__LONG_DOUBLE_128__) && defined (__LONG_DOUBLE_IBM128__)	\
     && !(defined (_SOFT_FLOAT) || defined (__NO_FPRS__))
   return __builtin_pack_longdouble (dh, dl);
 #else
   union
   {
-    long double ldval;
+    IBM128_TYPE ldval;
     double dval[2];
   } x;
   x.dval[0] = dh;
@@ -107,8 +116,8 @@  pack_ldouble (double dh, double dl)
 #endif
 }
 
-/* Add two 'long double' values and return the result.	*/
-long double
+/* Add two 'IBM128_TYPE' values and return the result.	*/
+IBM128_TYPE
 __gcc_qadd (double a, double aa, double c, double cc)
 {
   double xh, xl, z, q, zz;
@@ -147,7 +156,7 @@  __gcc_qadd (double a, double aa, double 
   return pack_ldouble (xh, xl);
 }
 
-long double
+IBM128_TYPE
 __gcc_qsub (double a, double b, double c, double d)
 {
   return __gcc_qadd (a, b, -c, -d);
@@ -157,7 +166,7 @@  __gcc_qsub (double a, double b, double c
 static double fmsub (double, double, double);
 #endif
 
-long double
+IBM128_TYPE
 __gcc_qmul (double a, double b, double c, double d)
 {
   double xh, xl, t, tau, u, v, w;
@@ -181,7 +190,7 @@  __gcc_qmul (double a, double b, double c
   tau += v + w;	    /* Add in other second-order terms.	 */
   u = t + tau;
 
-  /* Construct long double result.  */
+  /* Construct IBM128_TYPE result.  */
   if (nonfinite (u))
     return u;
   xh = u;
@@ -189,7 +198,7 @@  __gcc_qmul (double a, double b, double c
   return pack_ldouble (xh, xl);
 }
 
-long double
+IBM128_TYPE
 __gcc_qdiv (double a, double b, double c, double d)
 {
   double xh, xl, s, sigma, t, tau, u, v, w;
@@ -226,7 +235,7 @@  __gcc_qdiv (double a, double b, double c
   tau = ((v-sigma)+w)/c;   /* Correction to t.  */
   u = t + tau;
 
-  /* Construct long double result.  */
+  /* Construct IBM128_TYPE result.  */
   if (nonfinite (u))
     return u;
   xh = u;
@@ -236,32 +245,32 @@  __gcc_qdiv (double a, double b, double c
 
 #if defined (_SOFT_DOUBLE) && defined (__LONG_DOUBLE_128__)
 
-long double __gcc_qneg (double, double);
+IBM128_TYPE __gcc_qneg (double, double);
 int __gcc_qeq (double, double, double, double);
 int __gcc_qne (double, double, double, double);
 int __gcc_qge (double, double, double, double);
 int __gcc_qle (double, double, double, double);
-long double __gcc_stoq (float);
-long double __gcc_dtoq (double);
+IBM128_TYPE __gcc_stoq (float);
+IBM128_TYPE __gcc_dtoq (double);
 float __gcc_qtos (double, double);
 double __gcc_qtod (double, double);
 int __gcc_qtoi (double, double);
 unsigned int __gcc_qtou (double, double);
-long double __gcc_itoq (int);
-long double __gcc_utoq (unsigned int);
+IBM128_TYPE __gcc_itoq (int);
+IBM128_TYPE __gcc_utoq (unsigned int);
 
 extern int __eqdf2 (double, double);
 extern int __ledf2 (double, double);
 extern int __gedf2 (double, double);
 
-/* Negate 'long double' value and return the result.	*/
-long double
+/* Negate 'IBM128_TYPE' value and return the result.	*/
+IBM128_TYPE
 __gcc_qneg (double a, double aa)
 {
   return pack_ldouble (-a, -aa);
 }
 
-/* Compare two 'long double' values for equality.  */
+/* Compare two 'IBM128_TYPE' values for equality.  */
 int
 __gcc_qeq (double a, double aa, double c, double cc)
 {
@@ -272,7 +281,7 @@  __gcc_qeq (double a, double aa, double c
 
 strong_alias (__gcc_qeq, __gcc_qne);
 
-/* Compare two 'long double' values for less than or equal.  */
+/* Compare two 'IBM128_TYPE' values for less than or equal.  */
 int
 __gcc_qle (double a, double aa, double c, double cc)
 {
@@ -283,7 +292,7 @@  __gcc_qle (double a, double aa, double c
 
 strong_alias (__gcc_qle, __gcc_qlt);
 
-/* Compare two 'long double' values for greater than or equal.  */
+/* Compare two 'IBM128_TYPE' values for greater than or equal.  */
 int
 __gcc_qge (double a, double aa, double c, double cc)
 {
@@ -294,35 +303,35 @@  __gcc_qge (double a, double aa, double c
 
 strong_alias (__gcc_qge, __gcc_qgt);
 
-/* Convert single to long double.  */
-long double
+/* Convert single to IBM128_TYPE.  */
+IBM128_TYPE
 __gcc_stoq (float a)
 {
   return pack_ldouble ((double) a, 0.0);
 }
 
-/* Convert double to long double.  */
-long double
+/* Convert double to IBM128_TYPE.  */
+IBM128_TYPE
 __gcc_dtoq (double a)
 {
   return pack_ldouble (a, 0.0);
 }
 
-/* Convert long double to single.  */
+/* Convert IBM128_TYPE to single.  */
 float
 __gcc_qtos (double a, double aa __attribute__ ((__unused__)))
 {
   return (float) a;
 }
 
-/* Convert long double to double.  */
+/* Convert IBM128_TYPE to double.  */
 double
 __gcc_qtod (double a, double aa __attribute__ ((__unused__)))
 {
   return a;
 }
 
-/* Convert long double to int.  */
+/* Convert IBM128_TYPE to int.  */
 int
 __gcc_qtoi (double a, double aa)
 {
@@ -330,7 +339,7 @@  __gcc_qtoi (double a, double aa)
   return (int) z;
 }
 
-/* Convert long double to unsigned int.  */
+/* Convert IBM128_TYPE to unsigned int.  */
 unsigned int
 __gcc_qtou (double a, double aa)
 {
@@ -338,15 +347,15 @@  __gcc_qtou (double a, double aa)
   return (unsigned int) z;
 }
 
-/* Convert int to long double.  */
-long double
+/* Convert int to IBM128_TYPE.  */
+IBM128_TYPE
 __gcc_itoq (int a)
 {
   return __gcc_dtoq ((double) a);
 }
 
-/* Convert unsigned int to long double.  */
-long double
+/* Convert unsigned int to IBM128_TYPE.  */
+IBM128_TYPE
 __gcc_utoq (unsigned int a)
 {
   return __gcc_dtoq ((double) a);
@@ -361,7 +370,7 @@  int __gcc_qunord (double, double, double
 extern int __eqdf2 (double, double);
 extern int __unorddf2 (double, double);
 
-/* Compare two 'long double' values for unordered.  */
+/* Compare two 'IBM128_TYPE' values for unordered.  */
 int
 __gcc_qunord (double a, double aa, double c, double cc)
 {
@@ -389,7 +398,7 @@  fmsub (double a, double b, double c)
     FP_DECL_Q(V);
     FP_DECL_D(R);
     double r;
-    long double u, x, y, z;
+    IBM128_TYPE u, x, y, z;
 
     FP_INIT_ROUNDMODE;
     FP_UNPACK_RAW_D (A, a);
Index: libgcc/config/rs6000/_mulkc3.c
===================================================================
--- libgcc/config/rs6000/_mulkc3.c	(revision 256120)
+++ libgcc/config/rs6000/_mulkc3.c	(working copy)
@@ -23,11 +23,11 @@  see the files COPYING3 and COPYING.RUNTI
 
 /* This is a temporary specialization of code from libgcc/libgcc2.c.  */
 
-typedef float KFtype __attribute__ ((mode (KF)));
-typedef __complex float KCtype __attribute__ ((mode (KC)));
+#include "soft-fp.h"
+#include "quad-float128.h"
 
-#define COPYSIGN(x,y) __builtin_copysignq (x, y)
-#define INFINITY __builtin_infq ()
+#define COPYSIGN(x,y) __builtin_copysignf128 (x, y)
+#define INFINITY __builtin_inff128 ()
 #define isnan __builtin_isnan
 #define isinf __builtin_isinf
 
@@ -35,13 +35,11 @@  typedef __complex float KCtype __attribu
 #define __mulkc3 __mulkc3_sw
 #endif
 
-extern KCtype __mulkc3 (KFtype, KFtype, KFtype, KFtype);
-
-KCtype
-__mulkc3 (KFtype a, KFtype b, KFtype c, KFtype d)
+TCtype
+__mulkc3 (TFtype a, TFtype b, TFtype c, TFtype d)
 {
-  KFtype ac, bd, ad, bc, x, y;
-  KCtype res;
+  TFtype ac, bd, ad, bc, x, y;
+  TCtype res;
 
   ac = a * c;
   bd = b * d;
Index: libgcc/config/rs6000/_divkc3.c
===================================================================
--- libgcc/config/rs6000/_divkc3.c	(revision 256120)
+++ libgcc/config/rs6000/_divkc3.c	(working copy)
@@ -23,12 +23,12 @@  see the files COPYING3 and COPYING.RUNTI
 
 /* This is a temporary specialization of code from libgcc/libgcc2.c.  */
 
-typedef float KFtype __attribute__ ((mode (KF)));
-typedef __complex float KCtype __attribute__ ((mode (KC)));
+#include "soft-fp.h"
+#include "quad-float128.h"
 
-#define COPYSIGN(x,y) __builtin_copysignq (x, y)
-#define INFINITY __builtin_infq ()
-#define FABS __builtin_fabsq
+#define COPYSIGN(x,y) __builtin_copysignf128 (x, y)
+#define INFINITY __builtin_inff128 ()
+#define FABS __builtin_fabsf128
 #define isnan __builtin_isnan
 #define isinf __builtin_isinf
 #define isfinite __builtin_isfinite
@@ -37,13 +37,11 @@  typedef __complex float KCtype __attribu
 #define __divkc3 __divkc3_sw
 #endif
 
-extern KCtype __divkc3 (KFtype, KFtype, KFtype, KFtype);
-
-KCtype
-__divkc3 (KFtype a, KFtype b, KFtype c, KFtype d)
+TCtype
+__divkc3 (TFtype a, TFtype b, TFtype c, TFtype d)
 {
-  KFtype denom, ratio, x, y;
-  KCtype res;
+  TFtype denom, ratio, x, y;
+  TCtype res;
 
   /* ??? We can get better behavior from logarithmic scaling instead of
      the division.  But that would mean starting to link libgcc against
Index: libgcc/config/rs6000/extendkftf2-sw.c
===================================================================
--- libgcc/config/rs6000/extendkftf2-sw.c	(revision 256120)
+++ libgcc/config/rs6000/extendkftf2-sw.c	(working copy)
@@ -44,7 +44,7 @@ 
 #endif
 
 IBM128_TYPE
-__extendkftf2_sw (__float128 value)
+__extendkftf2_sw (TFtype value)
 {
   IBM128_TYPE ret;
 
Index: libgcc/config/rs6000/trunctfkf2-sw.c
===================================================================
--- libgcc/config/rs6000/trunctfkf2-sw.c	(revision 256120)
+++ libgcc/config/rs6000/trunctfkf2-sw.c	(working copy)
@@ -43,10 +43,10 @@ 
 #define __trunctfkf2_sw __trunctfkf2
 #endif
 
-__float128
+TFtype
 __trunctfkf2_sw (IBM128_TYPE value)
 {
-  __float128 ret;
+  TFtype ret;
 
   CVT_IBM128_TO_FLOAT128 (ret, value);
   return ret;