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.