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

            Bug ID: 81012
           Summary: ARM: Spill instead of register copy / dead store on
                    int-to-double conversion
           Product: gcc
           Version: 8.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: gergo.barany at inria dot fr
  Target Milestone: ---

Created attachment 41496
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=41496&action=edit
Input C file for triggering the issue

Input file (also in attachment):

double fn2(int p1, int p2) {
  double a = p1;
  if (744073425321881 * p2 + 5)
    a = 2;
  return a;
}

Generated code on ARMv7 for VFPv3:

$ gcc tst.c -Wall -Wextra -O3 -fomit-frame-pointer -S -o -
[...]
fn2:
        @ args = 0, pretend = 0, frame = 8
        @ frame_needed = 0, uses_anonymous_args = 0
        @ link register save eliminated.
        movw    r3, #42171
        movt    r3, 2
        push    {r4, r5}
        movw    r2, #65433
        sub     sp, sp, #8
        asr     r5, r1, #31
        movt    r2, 6195
        mvn     r4, #4
        mul     r3, r3, r1
        str     r0, [sp, #4]           // SPILL
        mla     r0, r2, r5, r3
        mvn     r5, #0
        umull   r2, r3, r1, r2
        add     r3, r0, r3
        cmp     r3, r5
        cmpeq   r2, r4
        vldreq.32       s15, [sp, #4]   @ int
        vmovne.f64      d0, #2.0e+0
        vcvteq.f64.s32  d0, s15
        add     sp, sp, #8
        @ sp needed
        pop     {r4, r5}
        bx      lr
        .size   fn2, .-fn2
        .ident  "GCC: (GNU) 8.0.0 20170606 (experimental)"

Note the store I marked "SPILL". It is a store of the integer register r0 which
is reloaded on the line marked "@ int" into a floating-point register for
subsequent int-to-double conversion. The spill frees r0 for other use, but it
would be better to just replace the spill/reload sequence with

        vmov s15, r0

since the register is available.

Also, if the large constant 744073425321881 in the if condition is changed to
something smaller like 1881 (that fits into a mov's immediate field), GCC
generates this code:

fn2:
        @ args = 0, pretend = 0, frame = 8
        @ frame_needed = 0, uses_anonymous_args = 0
        @ link register save eliminated.
        movw    r3, #1881
        sub     sp, sp, #8
        mul     r1, r3, r1
        str     r0, [sp, #4]                // DEAD STORE
        cmn     r1, #5
        vmovne.f64      d0, #2.0e+0
        vmoveq  s15, r0 @ int
        vcvteq.f64.s32  d0, s15
        add     sp, sp, #8
        @ sp needed
        bx      lr

This does perform a conditional move from r0 to s15, but it also generates a
dead store to the stack.

Clang and CompCert both just do a copy and don't touch the stack for this
value.

$ gcc -v
[...]
Target: armv7a-eabihf
Configured with: --target=armv7a-eabihf --with-arch=armv7-a
--with-fpu=vfpv3-d16 --with-float-abi=hard --with-float=hard
Thread model: single
gcc version 8.0.0 20170510 (experimental) (GCC)

Not sure if this is related to
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80861 which also the stack for a
float-to-char conversion. But that's the other direction, and if I understand
correctly, there the problem is related to the final sign extension.

Reply via email to