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. */