public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug target/107174] New: [ARM] Wrong opcodes *.f64.s32 (signed) in conversion [unsigned ->double] with -O2
@ 2022-10-06 18:49 rozne at pabich dot waw.pl
  2022-10-06 18:54 ` [Bug target/107174] " pinskia at gcc dot gnu.org
  2022-10-06 18:56 ` pinskia at gcc dot gnu.org
  0 siblings, 2 replies; 3+ messages in thread
From: rozne at pabich dot waw.pl @ 2022-10-06 18:49 UTC (permalink / raw)
  To: gcc-bugs

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.

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [Bug target/107174] [ARM] Wrong opcodes *.f64.s32 (signed) in conversion [unsigned ->double] with -O2
  2022-10-06 18:49 [Bug target/107174] New: [ARM] Wrong opcodes *.f64.s32 (signed) in conversion [unsigned ->double] with -O2 rozne at pabich dot waw.pl
@ 2022-10-06 18:54 ` pinskia at gcc dot gnu.org
  2022-10-06 18:56 ` pinskia at gcc dot gnu.org
  1 sibling, 0 replies; 3+ messages in thread
From: pinskia at gcc dot gnu.org @ 2022-10-06 18:54 UTC (permalink / raw)
  To: gcc-bugs

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

Andrew Pinski <pinskia at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
         Resolution|---                         |INVALID
             Status|UNCONFIRMED                 |RESOLVED

--- Comment #1 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
There is no bug here as signed integer overflow is undefined.
You should do the following if you want unsigned conversion.


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

Otherwise GCC will assume (a - b) and (b - a) will never be overflow (as it is
undefined) and you will get the signed coversions.

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [Bug target/107174] [ARM] Wrong opcodes *.f64.s32 (signed) in conversion [unsigned ->double] with -O2
  2022-10-06 18:49 [Bug target/107174] New: [ARM] Wrong opcodes *.f64.s32 (signed) in conversion [unsigned ->double] with -O2 rozne at pabich dot waw.pl
  2022-10-06 18:54 ` [Bug target/107174] " pinskia at gcc dot gnu.org
@ 2022-10-06 18:56 ` pinskia at gcc dot gnu.org
  1 sibling, 0 replies; 3+ messages in thread
From: pinskia at gcc dot gnu.org @ 2022-10-06 18:56 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #2 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
 -fsanitize=undefined catches this at runtime:
/app/example.cpp:10:28: runtime error: signed integer overflow: 2000000000 -
-1000000000 cannot be represented in type 'int'
/app/example.cpp:7:28: runtime error: signed integer overflow: 2000000000 -
-1000000000 cannot be represented in type 'int'

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2022-10-06 18:56 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-06 18:49 [Bug target/107174] New: [ARM] Wrong opcodes *.f64.s32 (signed) in conversion [unsigned ->double] with -O2 rozne at pabich dot waw.pl
2022-10-06 18:54 ` [Bug target/107174] " pinskia at gcc dot gnu.org
2022-10-06 18:56 ` pinskia at gcc dot gnu.org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).