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

            Bug ID: 89175
           Summary: gcc's conversion code from double to unsigned int
                    handles overflows incorrectly on x86-64
           Product: gcc
           Version: 8.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: david.monni...@univ-grenoble-alpes.fr
  Target Milestone: ---

$ gcc-8 --version
gcc-8 (Ubuntu 8.2.0-1ubuntu2~18.04) 8.2.0

Compile the following:

unsigned conversion(double x) {
  return (unsigned) x;
}

The compiled code performs incorrectly if the rounded value of x lies in the
range of the 'signed long long' but not in the range of 'unsigned int': it
should signal a floating-point "invalid operation" exception (as per C99 F.4)
but it does not.

Explanation:

The generated code performs the conversion using
    cvttsd2siq  %xmm0, %rax
which raises "invalid operation"if the result does not fit into a 64-bit signed
number.

It suggest that, unless -ffast-math or similar option is set, the result of
this conversion should be checked for being in the correct range for unsigned,
and if not, the exception should be flagged.


The following code demonstrates the issue: it should display invalid=1 but does
not (it does display invalid=1 if compiled under CompCert, which performs a
range check).

#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <fenv.h>

int main() {
  double x = 1E10;
  uint32_t u=x;
  printf("x=%lf u=%" PRIu32 " %" PRIx32 " equal=%d invalid=%x\n", x, u, u,
u==x, fetestexcept(FE_INVALID | FE_OVERFLOW));
  double y= 0;
  y = y / y;
  printf("invalid2=%x\n", fetestexcept(FE_INVALID | FE_OVERFLOW));
  return 0;
}

Reply via email to