[Bug libgcc/78759] New: __gcc_qadd could have been "more commutative" when a+c is infinity, but a+c+aa+cc is not

timshen at gcc dot gnu.org gcc-bugzilla@gcc.gnu.org
Fri Dec 9 22:20:00 GMT 2016


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

            Bug ID: 78759
           Summary: __gcc_qadd could have been "more commutative" when a+c
                    is infinity, but a+c+aa+cc is not
           Product: gcc
           Version: 7.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libgcc
          Assignee: unassigned at gcc dot gnu.org
          Reporter: timshen at gcc dot gnu.org
  Target Milestone: ---

#include <cstdio>
#include <cstdint>
#include <cstring>
#include <cfenv>

int main() {
  static_assert(sizeof(long double) == 16, "");
  uint64_t raw_input[4] = { 0x7c90000000000000ull, 0, 0x7fefffffffffffffull,
0xf950000000000000ull, };
  long double input[2];
  memcpy(&input[0], &raw_input[0], sizeof(input));

  long double result = input[0] + input[1];

  uint64_t output[2];
  memcpy(output, &result, sizeof(result));
  printf("%lx %lx\n", output[0], output[1]);

  return 0;
}


The code above prints:
  7ff0000000000000
  0

Which stands for inifinity. However, if the addends are exchanged:
  -  uint64_t raw_input[4] = { 0x7c90000000000000ull, 0, 0x7fefffffffffffffull,
0xf950000000000000ull, };
  +  uint64_t raw_input[4] = { 0x7fefffffffffffffull, 0xf950000000000000ull,
0x7c90000000000000ull, 0, };
the result is finite:
  7fefffffffffffff
  7c8fffffffffffff

Proof of concept fix:

diff --git a/libgcc/config/rs6000/ibm-ldouble.c
b/libgcc/config/rs6000/ibm-ldouble.c
index 3116cf4..d7b5a92 100644
--- a/libgcc/config/rs6000/ibm-ldouble.c
+++ b/libgcc/config/rs6000/ibm-ldouble.c
@@ -118,7 +118,10 @@ __gcc_qadd (double a, double aa, double c, double cc)
     {
       if (fabs (z) != inf())
        return z;
-      z = cc + aa + c + a;
+      if (fabs(a) > fabs(c))
+        z = cc + aa + c + a;
+      else
+        z = cc + aa + a + c;
       if (nonfinite (z))
        return z;
       xh = z;  /* Will always be DBL_MAX.  */


More information about the Gcc-bugs mailing list