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

            Bug ID: 107174
           Summary: [ARM] Wrong opcodes *.f64.s32 (signed) in conversion
                    [unsigned ->double] with -O2
           Product: gcc
           Version: 8.3.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: rozne at pabich dot waw.pl
  Target Milestone: ---

When building for 32-bit ARMhf with optimization -O2 and higher sometimes wrong
conversion opcodes are generated - *.f64.s32 (signed conversion) instead of
*.f64.u32 (unsigned). These are very rare cases, and are higly sensitive to
code arrangement.

The bug seems to be present at least since GCC 8.3. GCC 8.4 and 12 are
affected.

GCC 7.5 is not affected (and very old 4.4 also).

It is not present on x86 architecture, seems to be ARM specific.

Example cross-compiled on Ubuntu 18.04.6 (x86_64):
  arm-linux-gnueabihf-gcc-8 -Wall -Wextra -O2 -static

GCC 8.4 version:
  arm-linux-gnueabihf-gcc-8 (Ubuntu/Linaro 8.4.0-1ubuntu1~18.04) 8.4.0


Code:

#include <stdio.h>

__attribute__((noinline)) double deltaToDouble(int a, int b) {
  if (a < b) {
    unsigned int delta = b - a;
    return -((double)delta);
  } else {
    unsigned int delta = a - b;
    return (double)delta;
  }
}

int main() {
  return (deltaToDouble( 2000000000, -1000000000) !=  3000000000.0 ||
          deltaToDouble(-1000000000,  2000000000) != -3000000000.0);
}


Disassembly:

<deltaToDouble>:
  cmp     r0, r1
  itete   lt
  sublt   r0, r1, r0
  subge   r0, r0, r1
  vmovlt  s15, r0
  vmovge  s15, r0
  itte    lt
  vcvtlt.f64.s32  d0, s15
  vneglt.f64      d0, d0
  vcvtge.f64.s32  d0, s15
  bx      lr


It is easy to see that opcodes are for signed int32 conversion (vcvtlt.f64.s32,
vcvtge.f64.s32). Code generated by older GCC 7.5 is same except correct opcodes
for unsigned int32 (vcvtlt.f64.u32, vcvtge.f64.u32) were used.

Reply via email to