Apologies in advance for the length of this reply.
Details seemed necessary to be sure we are on the same page
of understanding.

Aug 26, 2021 by Patrick McGehearty

The only IBM machines I have current access to are in the gcc fsf farm.

All studies were done on gcc135.fsffrance.org
Linux gcc135.osuosl.org 4.18.0-80.7.2.el7.ppc64le
/usr/bin/gcc version 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC)
/usr/lib64/libc.so.6 linked to libc-2.17.so
yum list glibc shows the version 2.17-307.el7.1 while
version 2.17-324.el7_9 is available.

I'm concerned that the old environment on gcc135.fsffrance.org
is not showing me a typical build environment for IBM linux users
with more modern environments. I am also concerned that I may
not be setting my environment completely to use current
components.

- - - -

I built gcc from current upstream gcc srcs, replacing KF references
in libgcc/config/rs6000/_divkc3.c with DF references
and installed it in $HOME/usr.

For the following test purposes, I added the following to my local environment:
PATH=$HOME/usr/bin:$PATH
export PATH
LD_LIBRARY_PATH=$HOME/usr/lib64:$HOME/usr/lib
export LD_LIBRARY_PATH

The only complex divide routines in $HOME/usr/lib64/libgcc_s.so.1 are:
__divdc3, __divsc3, __divtc3

Compiling a simple c=a/b (for long double complex a,b,c)
yields a call to __divtc3
Compiling with -mabi=ieeelongdouble
yields a call to __divkc3

When I link the version with the call to __divkc3 into an executable,
the executable contains __divkc3. I just can't tell where the linker
is finding it.

- - - -
Using this environment, I tried building upstream gcc with __LIBGCC_KF_MAX__
and other #defines in  libgcc/config/rs6000/_divkc3.c

#ifndef __LONG_DOUBLE_IEEE128__
#define RBIG   (__LIBGCC_KF_MAX__ / 2)
#define RMIN   (__LIBGCC_KF_MIN__)
#define RMIN2  (__LIBGCC_KF_EPSILON__)
#define RMINSCAL (1 / __LIBGCC_KF_EPSILON__)
#define RMAX2  (RBIG * RMIN2)
#else

The KF case got errors of the sort:
‘__LIBGCC_KF_MAX__’ undeclared
‘__LIBGCC_KF_EPSILON__’ undeclared
‘__LIBGCC_KF_MIN__’ undeclared

These values were supposed to be created by gcc/c-family/c-cppbuiltin.c.
They depend on KF being part of
FOR_EACH_MODE_IN_CLASS (mode_iter, MODE_FLOAT)
{
  const char *name = GET_MODE_NAME (mode);
...
}

Apparently KF is not one of the mode names when building in this
environment. I've spent some time trying to understand where/how
the MODE_FLOAT class is constructed, but I have not been able to
pinpoint what's going wrong.

- - - -
When I replace the various _KF_ values with _DF_ values,
the compiler builds to completion.

In other testing I have confirmed that the rs6000/_divkc3.c code
does expect to be generating code for IEEE mode.

- - - - - - - - - - - - - - - - - - - - - - - -

When I compile/run the new test program cdivchkld.c with the old
compiler and -lm in the default IBM 128bit mode, it aborts as expected.
When I attempt to use the -mabi=ieeelongdouble -lm, the compiler
aborts with an internal error. Clearly ieeelongdouble is not
supported on this old compiler.

When I compile/run cdivchkld.c with my new compiler with
_DF_ values in _divkc3.c, it runs to completion without aborting.
That is why I believed rs6000/_divkc3.c affected the behavior
of IBM 128bit mode.

When I compile/link cdivchkld.c with -mabi=ieeelongdouble -lm
I get cdivchkld.c:(.text+0x3c4): undefined reference to `__fmaxieee128'
caused by the reference in the code to LDBL_MAX_EXP.

- - - - -
I suspect that part of the KF issue is that the general environment on
gcc135.fsffrance.org is relatively old. That is, it includes some
include files or libraries from before the KF/TF option for handling
IBM vs IEEE format was added to gcc. My use of $HOME/usr for PATH and
LD_LIBRARY_PATH may be inadequate for bypassing the older environment.
I don't have access to a current (el8 or later) IBM environment.

- - - - - - - - - - - - - - - - - - - - - - - -

With moderate study, I find I still don't really understand how the
make files are building both _divtc3.c and _divkc3.c as appropriate
for machines with/without HW support for IEEE128. It will be some time
before I could get enough ahead on my primary assignments to learn
what I need to know to gain that understanding.

I am concerned that in some IBM environments, the build process will
fall back to using the code in libgcc/libgcc2.c for IBM 128bit float
complex divide. In that case, the current 1/__LIBGCC_TF_EPSILON__
value will generate an infinity result which would be
suboptimal. Changing __LIBGCC_TF_EPSILON__ to __LIBGCC_DF_EPSILON__
for all platforms avoids the overflow without changing the final
answers. It only has the effect of doing some scaling without possible
overflow/underflow when it is not necessary.

I propose for my next patch I change libgcc/libgcc2.c to use
__LIBGCC_DF_EPSILON__ instead of __LIBGCC_TF_EPSILON__
in addition to the most recent changes in rs6000/_divkc3.c.
That set of changes will allow the upstream gcc to build on
the IBM build farm on fsf as well as allowing the new test results
to pass.

I'm not sure how else to approach this issue for a short term solution.


- Patrick McGehearty (patrick.mcgehea...@oracle.com)




On 8/13/2021 12:12 PM, Joseph Myers wrote:
On Thu, 12 Aug 2021, Patrick McGehearty via Gcc-patches wrote:

If _divkc3.c is not intended to provide a version of complex divide
that handles IBM-128 format, then where should that option be handled?
That should be the function __divtc3.  (A single libgcc binary supports
multiple long double formats, so libgcc function names referring to
floating-point modes need to be understood as actually referring to a
particular *format*, which may or may not correspond to the named *mode*
depending on the compilation options used.  Thus, libgcc functions with
"tf" or "tc" in their names, on configurations such as
powerpc64le-linux-gnu that ever supported IBM long double, always refer to
IBM long double.  It's up to the back end to ensure that, when building
with TFmode = binary128, TCmode and KCmode division both get mapped to
__divkc3 while ICmode division gets mapped to __divtc3; when building with
TFmode = IBM long double, KCmode division should still be __divkc3, ICmode
division should still be __divtc3, and TCmode division should be __divtc3
in that case as well.)

Do I need add a special case for
#ifndef __LONG_DOUBLE_IEEE128__
in the complex divide code in libgcc/libgcc2.c?
That macro is architecture-specific so shouldn't be tested there.  Doing
things differently if __LIBGCC_TF_MANT_DIG__ == 106 would be reasonable
(if it fixes the observed problem!), however; there are a few places in
generic libgcc code that check for MANT_DIG == 106 to handle IBM long
double differently.

And, for completeness, does gcc support LDBL for non-IEEE on
any platform besides IBM?
I believe TFmode is IEEE binary128 everywhere except for those powerpc
configurations where it's IBM long double.


Reply via email to