diff options
author | Jakub Jelinek <jakub@redhat.com> | 2017-01-26 09:46:36 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2017-01-26 09:46:36 +0100 |
commit | 1a27fab1aded9fe71ecac0108f7dcf4ebf17637e (patch) | |
tree | e62c3830860aef695c7137e2e8a1f5a8a998734e /gcc/reg-stack.c | |
parent | e6d55103c3cf917a0305628619784808e1abf096 (diff) | |
download | gcc-1a27fab1aded9fe71ecac0108f7dcf4ebf17637e.zip gcc-1a27fab1aded9fe71ecac0108f7dcf4ebf17637e.tar.gz gcc-1a27fab1aded9fe71ecac0108f7dcf4ebf17637e.tar.bz2 |
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
Diffstat (limited to 'gcc/reg-stack.c')
-rw-r--r-- | gcc/reg-stack.c | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c index 063ef54..7bf007c 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 |