From 1a27fab1aded9fe71ecac0108f7dcf4ebf17637e Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 26 Jan 2017 09:46:36 +0100 Subject: [PATCH] re PR target/70465 (Poor code for x87 asm) PR target/70465 * reg-stack.c (emit_swap_insn): Instead of fld a; fld b; fxchg %st(1); emit fld b; fld a; if possible. * gcc.target/i386/pr70465.c: New test. From-SVN: r244921 --- gcc/ChangeLog | 4 ++ gcc/reg-stack.c | 71 +++++++++++++++++++++++++ gcc/testsuite/ChangeLog | 3 ++ gcc/testsuite/gcc.target/i386/pr70465.c | 12 +++++ 4 files changed, 90 insertions(+) create mode 100644 gcc/testsuite/gcc.target/i386/pr70465.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7bed16a7270..9a82c9fb00a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,9 @@ 2017-01-26 Jakub Jelinek + PR target/70465 + * reg-stack.c (emit_swap_insn): Instead of fld a; fld b; fxchg %st(1); + emit fld b; fld a; if possible. + * brig-builtins.def: Update copyright years. * config/arm/arm_acle_builtins.def: Update copyright years. diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c index 063ef542053..7bf007cea45 100644 --- a/gcc/reg-stack.c +++ b/gcc/reg-stack.c @@ -887,6 +887,77 @@ emit_swap_insn (rtx_insn *insn, stack_ptr regstack, rtx reg) && REG_P (i1src) && REGNO (i1src) == FIRST_STACK_REG && find_regno_note (i1, REG_DEAD, FIRST_STACK_REG) == NULL_RTX) return; + + /* Instead of + fld a + fld b + fxch %st(1) + just use + fld b + fld a + if possible. */ + + if (REG_P (i1dest) + && REGNO (i1dest) == FIRST_STACK_REG + && MEM_P (SET_SRC (i1set)) + && !side_effects_p (SET_SRC (i1set)) + && hard_regno == FIRST_STACK_REG + 1 + && i1 != BB_HEAD (current_block)) + { + /* i1 is the last insn that involves stack regs before insn, and + is known to be a load without other side-effects, i.e. fld b + in the above comment. */ + rtx_insn *i2 = NULL; + rtx i2set; + rtx_insn *tmp = PREV_INSN (i1); + rtx_insn *limit = PREV_INSN (BB_HEAD (current_block)); + /* Find the previous insn involving stack regs, but don't pass a + block boundary. */ + while (tmp != limit) + { + if (LABEL_P (tmp) + || CALL_P (tmp) + || NOTE_INSN_BASIC_BLOCK_P (tmp) + || (NONJUMP_INSN_P (tmp) + && stack_regs_mentioned (tmp))) + { + i2 = tmp; + break; + } + tmp = PREV_INSN (tmp); + } + if (i2 != NULL_RTX + && (i2set = single_set (i2)) != NULL_RTX) + { + rtx i2dest = *get_true_reg (&SET_DEST (i2set)); + /* If the last two insns before insn that involve + stack regs are loads, where the latter (i1) + pushes onto the register stack and thus + moves the value from the first load (i2) from + %st to %st(1), consider swapping them. */ + if (REG_P (i2dest) + && REGNO (i2dest) == FIRST_STACK_REG + && MEM_P (SET_SRC (i2set)) + /* Ensure i2 doesn't have other side-effects. */ + && !side_effects_p (SET_SRC (i2set)) + /* And that the two instructions can actually be + swapped, i.e. there shouldn't be any stores + in between i2 and i1 that might alias with + the i1 memory, and the memory address can't + use registers set in between i2 and i1. */ + && !modified_between_p (SET_SRC (i1set), i2, i1)) + { + /* Move i1 (fld b above) right before i2 (fld a + above. */ + remove_insn (i1); + SET_PREV_INSN (i1) = NULL_RTX; + SET_NEXT_INSN (i1) = NULL_RTX; + set_block_for_insn (i1, NULL); + emit_insn_before (i1, i2); + return; + } + } + } } /* Avoid emitting the swap if this is the first register stack insn diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 46f8469777c..b2d3af0fc95 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,8 @@ 2017-01-26 Jakub Jelinek + PR target/70465 + * gcc.target/i386/pr70465.c: New test. + * brig.dg/dg.exp: Update copyright years. * lib/brig-dg.exp: Update copyright years. * lib/brig.exp: Update copyright years. diff --git a/gcc/testsuite/gcc.target/i386/pr70465.c b/gcc/testsuite/gcc.target/i386/pr70465.c new file mode 100644 index 00000000000..2d45e1b5344 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr70465.c @@ -0,0 +1,12 @@ +/* PR target/70465 */ +/* { dg-do compile { target ia32 } } */ +/* { dg-options "-O2 -mfpmath=387 -fomit-frame-pointer" } */ +/* { dg-final { scan-assembler-not "fxch\t%st.1" } } */ + +double +atan2 (double y, double x) +{ + double res = 0.0; + asm ("fpatan" : "=t" (res) : "u" (y), "0" (x) : "st(1)"); + return res; +}