re PR target/70465 (Poor code for x87 asm)
authorJakub Jelinek <jakub@redhat.com>
Thu, 26 Jan 2017 08:46:36 +0000 (09:46 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Thu, 26 Jan 2017 08:46:36 +0000 (09:46 +0100)
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
gcc/reg-stack.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/pr70465.c [new file with mode: 0644]

index 7bed16a7270bfd4632d4e6160d82f985eacdfa0b..9a82c9fb00a7231bec17d47434fe93f2c68fd042 100644 (file)
@@ -1,5 +1,9 @@
 2017-01-26  Jakub Jelinek  <jakub@redhat.com>
 
+       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.
 
index 063ef54205356fe242bb5602096479db18a639b9..7bf007cea45ef6b2336dd44d47386281626a1987 100644 (file)
@@ -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
index 46f8469777c91ebf8764ffaf71ae4fc5868b3a31..b2d3af0fc95b80373ab2f4ad7bb340e22b0d3a30 100644 (file)
@@ -1,5 +1,8 @@
 2017-01-26  Jakub Jelinek  <jakub@redhat.com>
 
+       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 (file)
index 0000000..2d45e1b
--- /dev/null
@@ -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;
+}