https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102475

            Bug ID: 102475
           Summary: incorrect definition of "normal" long doubles in
                    libgcc/config/rs6000/ibm-ldouble-format
           Product: gcc
           Version: 12.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: vincent-gcc at vinc17 dot net
  Target Milestone: ---

In libgcc/config/rs6000/ibm-ldouble-format as seen at
https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libgcc/config/rs6000/ibm-ldouble-format;hb=HEAD
I can read:

A long double can represent any value of the form
  s * 2^e * sum(k=0...105: f_k * 2^(-k))
where 's' is +1 or -1, 'e' is between 1022 and -968 inclusive, f_0 is
1, and f_k for k>0 is 0 or 1.  These are the 'normal' long doubles.

By "These are *the* 'normal' long doubles." I understand that the other long
double values are not 'normal' long doubles. This contradicts the following
definition in gcc/builtins.c:

        /* isnormal(x) -> isgreaterequal(fabs(x),DBL_MIN) &
           islessequal(fabs(x),DBL_MAX).  */

and the implementation. The following is a test I had posted to comp.std.c on
2021-07-30 (thread "isnormal and non-FP values: possible defect"):

Here's a test program for long double, which shows the issue on PowerPC. Here,
1 + 2^(-120) is exactly representable as a double-double number (the exact sum
of 1 and 2^(-120), which are both double-precision numbers). This is verified
by the output of x - 1, which gives 2^(-120) instead of 0.

------------------------------------------------------------------
#include <stdio.h>
#include <float.h>
#include <math.h>

int main (void)
{
  volatile long double x = 1 + 0x1.p-120L;
  int c;

  printf ("LDBL_MANT_DIG = %d\n", (int) LDBL_MANT_DIG);
  printf ("x - 1 = %La\n", x - 1);

  c = fpclassify (x);
  printf ("fpclassify(x) = %s\n",
          c == FP_NAN ? "FP_NAN" :
          c == FP_INFINITE ? "FP_INFINITE" :
          c == FP_ZERO ? "FP_ZERO" :
          c == FP_SUBNORMAL ? "FP_SUBNORMAL" :
          c == FP_NORMAL ? "FP_NORMAL" : "unknown");

  printf ("isfinite/isnormal/isnan/isinf(x) = %d/%d/%d/%d\n",
          isfinite (x), isnormal (x), isnan (x), isinf (x));

  return 0;
}
------------------------------------------------------------------

I get the following result:

LDBL_MANT_DIG = 106
x - 1 = 0x1p-120
fpclassify(x) = FP_NORMAL
isfinite/isnormal/isnan/isinf(x) = 1/1/0/0

So x is a number with more than the 106-bit precision of normal numbers, and
both fpclassify(x) and isnormal(x) regard it as a "normal number".

In the CFP group, it seems that it is currently agreed that "normal number"
should match the current gcc/builtins.c definition and implementation. Hence
the current definition in libgcc/config/rs6000/ibm-ldouble-format should be
regarded as incorrect.

Note: about another error in this file, see PR94073.

Reply via email to