https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67718
Bug ID: 67718 Summary: [aarch64] long double incorrect code for copysign Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: middle-end Assignee: unassigned at gcc dot gnu.org Reporter: thanm at google dot com Target Milestone: --- Created attachment 36392 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=36392&action=edit reduced test case (C++) Compiling the attached example with g++ at -O2 or -O1 results in incorrect code (-O0 looks ok). This is with gcc trunk aarch64-linux-android target; problem is also present in 4.9. Source being compiled looks like: /// begin union IEEEl2bits { long double e; struct { unsigned long manl :64; unsigned long manh :48; unsigned int exp :15; unsigned int sign :1; } bits; }; long double copysignl(long double x, long double y) { union IEEEl2bits ux, uy; ux.e = x; uy.e = y; ux.bits.sign = uy.bits.sign; return (ux.e); } /// end Here is -O2 assembly: ushr d1, d1, 63 fmov x0, d0 fmov x1, v0.d[1] fmov d0, x0 fmov x2, d1 bfi x1, x2, 63, 1 fmov v0.d[1], x1 ret Note that the first instruction is sourcing d1 (incorrect) -- this needs to read q0 in order for correct semantics. I am not a gcc expert, but I'm guessing that the problem is happening in the reload phase. Prior to reload the RTL looks ok: (insn 10 9 7 2 (set (reg:DI 81 [ D.3189 ]) (lshiftrt:DI (subreg:DI (reg:TI 33 v1 [ y ]) 8) (const_int 63 [0x3f]))) bionic/libm/upstream-freebsd/lib/msun/src/s_copysignl.c:40 512 {*aarch64_lshr_sisd_or_int_di3} (expr_list:REG_DEAD (reg:TI 33 v1 [ y ]) (nil))) and then after reload this gets turned into (insn 10 9 7 2 (set (reg:DI 33 v1 [orig:81 D.3189 ] [81]) (lshiftrt:DI (reg:DI 33 v1 [ y+8 ]) (const_int 63 [0x3f]))) bionic/libm/upstream-freebsd/lib/msun/src/s_copysignl.c:40 512 {*aarch64_lshr_sisd_or_int_di3} (nil)) which doesn't look right -- we seem to have lost the "TI", which I take to be the bug.