reg-stack.c (compare_for_stack_reg): Add bool argument.
authorUros Bizjak <ubizjak@gmail.com>
Tue, 17 Oct 2017 16:35:11 +0000 (18:35 +0200)
committerUros Bizjak <uros@gcc.gnu.org>
Tue, 17 Oct 2017 16:35:11 +0000 (18:35 +0200)
* reg-stack.c (compare_for_stack_reg): Add bool argument.
Detect FTST instruction and handle its register pops.  Only pop
second operand if can_pop_second_op is true.
(subst_stack_regs_pat) <case COMPARE>: Detect FCOMI instruction to
set can_pop_second_op to false in the compare_for_stack_reg call.

* config/i386/i386.md (*cmpi<FPCMP:unord><MODEF:mode>): Only call
output_fp_compare for stack register operands.
* config/i386/i386.c (output_fp_compare): Do not output SSE compare
instructions here.  Do not emit stack register pops here.  Assert
that FCOMPP pops next to top stack register.  Rewrite function.

From-SVN: r253821

gcc/ChangeLog
gcc/config/i386/i386.c
gcc/config/i386/i386.md
gcc/reg-stack.c

index 14f0d01613c1db1963f594077dd65ffa84cc7f5e..3c7fac739df76d169f3ee27b7677db2fd3fe3637 100644 (file)
@@ -1,3 +1,17 @@
+2017-10-17  Uros Bizjak  <ubizjak@gmail.com>
+
+       * reg-stack.c (compare_for_stack_reg): Add bool argument.
+       Detect FTST instruction and handle its register pops.  Only pop
+       second operand if can_pop_second_op is true.
+       (subst_stack_regs_pat) <case COMPARE>: Detect FCOMI instruction to
+       set can_pop_second_op to false in the compare_for_stack_reg call.
+
+       * config/i386/i386.md (*cmpi<FPCMP:unord><MODEF:mode>): Only call
+       output_fp_compare for stack register operands.
+       * config/i386/i386.c (output_fp_compare): Do not output SSE compare
+       instructions here.  Do not emit stack register pops here.  Assert
+       that FCOMPP pops next to top stack register.  Rewrite function.
+
 2017-10-17  Nathan Sidwell  <nathan@acm.org>
 
        PR middle-end/82577
index 26b22d6d7aac88c3be856c233bc66c86e4e547f1..2024cfea8ff96ae574ce381a558d5e64086bab8c 100644 (file)
@@ -18879,120 +18879,65 @@ output_387_ffreep (rtx *operands ATTRIBUTE_UNUSED, int opno)
    should be used.  UNORDERED_P is true when fucom should be used.  */
 
 const char *
-output_fp_compare (rtx_insn *insn, rtx *operands, bool eflags_p, bool unordered_p)
+output_fp_compare (rtx_insn *insn, rtx *operands,
+                  bool eflags_p, bool unordered_p)
 {
-  int stack_top_dies;
-  rtx cmp_op0, cmp_op1;
-  int is_sse = SSE_REG_P (operands[0]) || SSE_REG_P (operands[1]);
+  rtx *xops = eflags_p ? &operands[0] : &operands[1];
+  bool stack_top_dies;
 
-  if (eflags_p)
-    {
-      cmp_op0 = operands[0];
-      cmp_op1 = operands[1];
-    }
-  else
-    {
-      cmp_op0 = operands[1];
-      cmp_op1 = operands[2];
-    }
+  static char buf[40];
+  const char *p, *r;
+  gcc_assert (STACK_TOP_P (xops[0]));
 
-  if (is_sse)
-    {
-      if (GET_MODE (operands[0]) == SFmode)
-       if (unordered_p)
-         return "%vucomiss\t{%1, %0|%0, %1}";
-       else
-         return "%vcomiss\t{%1, %0|%0, %1}";
-      else
-       if (unordered_p)
-         return "%vucomisd\t{%1, %0|%0, %1}";
-       else
-         return "%vcomisd\t{%1, %0|%0, %1}";
-    }
+  stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG);
 
-  gcc_assert (STACK_TOP_P (cmp_op0));
+  if (eflags_p)
+    {
+      p = unordered_p ? "fucomi" : "fcomi";
+      strcpy (buf, p);
 
-  stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
+      r = "p\t{%y1, %0|%0, %y1}";
+      strcat (buf, r + !stack_top_dies);
 
-  if (cmp_op1 == CONST0_RTX (GET_MODE (cmp_op1)))
-    {
-      if (stack_top_dies)
-       {
-         output_asm_insn ("ftst\n\tfnstsw\t%0", operands);
-         return output_387_ffreep (operands, 1);
-       }
-      else
-       return "ftst\n\tfnstsw\t%0";
+      return buf;
     }
 
-  if (STACK_REG_P (cmp_op1)
+  if (STACK_REG_P (xops[1])
       && stack_top_dies
-      && find_regno_note (insn, REG_DEAD, REGNO (cmp_op1))
-      && REGNO (cmp_op1) != FIRST_STACK_REG)
+      && find_regno_note (insn, REG_DEAD, FIRST_STACK_REG + 1))
     {
-      /* If both the top of the 387 stack dies, and the other operand
-        is also a stack register that dies, then this must be a
-        `fcompp' float compare */
+      gcc_assert (REGNO (xops[1]) == FIRST_STACK_REG + 1);
 
-      if (eflags_p)
-       {
-         /* There is no double popping fcomi variant.  Fortunately,
-            eflags is immune from the fstp's cc clobbering.  */
-         if (unordered_p)
-           output_asm_insn ("fucomip\t{%y1, %0|%0, %y1}", operands);
-         else
-           output_asm_insn ("fcomip\t{%y1, %0|%0, %y1}", operands);
-         return output_387_ffreep (operands, 0);
-       }
-      else
-       {
-         if (unordered_p)
-           return "fucompp\n\tfnstsw\t%0";
-         else
-           return "fcompp\n\tfnstsw\t%0";
-       }
+      /* If both the top of the 387 stack die, and the other operand
+        is also a stack register that dies, then this must be a
+        `fcompp' float compare.  */
+      p = unordered_p ? "fucompp" : "fcompp";
+      strcpy (buf, p);
+    }
+  else if (const0_operand (xops[1], VOIDmode))
+    {
+      gcc_assert (!unordered_p);
+      strcpy (buf, "ftst");
     }
   else
     {
-      /* Encoded here as eflags_p | intmode | unordered_p | stack_top_dies.  */
-
-      static const char * const alt[16] =
-      {
-       "fcom%Z2\t%y2\n\tfnstsw\t%0",
-       "fcomp%Z2\t%y2\n\tfnstsw\t%0",
-       "fucom%Z2\t%y2\n\tfnstsw\t%0",
-       "fucomp%Z2\t%y2\n\tfnstsw\t%0",
-
-       "ficom%Z2\t%y2\n\tfnstsw\t%0",
-       "ficomp%Z2\t%y2\n\tfnstsw\t%0",
-       NULL,
-       NULL,
-
-       "fcomi\t{%y1, %0|%0, %y1}",
-       "fcomip\t{%y1, %0|%0, %y1}",
-       "fucomi\t{%y1, %0|%0, %y1}",
-       "fucomip\t{%y1, %0|%0, %y1}",
-
-       NULL,
-       NULL,
-       NULL,
-       NULL
-      };
-
-      int mask;
-      const char *ret;
-
-      mask  = eflags_p << 3;
-      mask |= (GET_MODE_CLASS (GET_MODE (cmp_op1)) == MODE_INT) << 2;
-      mask |= unordered_p << 1;
-      mask |= stack_top_dies;
+      if (GET_MODE_CLASS (GET_MODE (xops[1])) == MODE_INT)
+       {
+         gcc_assert (!unordered_p);
+         p = "ficom";
+       }
+      else
+       p = unordered_p ? "fucom" : "fcom";
 
-      gcc_assert (mask < 16);
-      ret = alt[mask];
-      gcc_assert (ret);
+      strcpy (buf, p);
 
-      return ret;
+      r = "p%Z2\t%y2";
+      strcat (buf, r + !stack_top_dies);
     }
+
+  output_asm_insn (buf, operands);
+  return "fnstsw\t%0";
 }
 
 void
index 8262cf1c3f03e2c026965cc73930686e5b2394a5..512bd64c3c30a12c505b5f06c0ec121863e0f66b 100644 (file)
    (set_attr "mode" "SI")])
 
 ;; Pentium Pro can do steps 1 through 3 in one go.
-;; comi*, ucomi*, fcomi*, ficomi*, fucomi*
-;; (these i387 instructions set flags directly)
+;; (these instructions set flags directly)
 
 (define_mode_iterator FPCMP [CCFP CCFPU])
 (define_mode_attr unord [(CCFP "") (CCFPU "u")])
          (match_operand:MODEF 1 "register_ssemem_operand" "f,vm")))]
   "(SSE_FLOAT_MODE_P (<MODEF:MODE>mode) && TARGET_SSE_MATH)
    || (TARGET_80387 && TARGET_CMOVE)"
-  "* return output_fp_compare (insn, operands, true,
-                              <FPCMP:MODE>mode == CCFPUmode);"
+  "@
+   * return output_fp_compare (insn, operands, true, \
+                              <FPCMP:MODE>mode == CCFPUmode);
+   %v<FPCMP:unord>comi<MODEF:ssemodesuffix>\t{%1, %0|%0, %1}"
   [(set_attr "type" "fcmp,ssecomi")
    (set_attr "prefix" "orig,maybe_vex")
    (set_attr "mode" "<MODEF:MODE>")
index f2381067f5e3885b342d0a6e6c661054ee511fc3..86021ab0b90de016ac0f5a312bed129bcf7ff793 100644 (file)
@@ -262,7 +262,7 @@ static bool move_for_stack_reg (rtx_insn *, stack_ptr, rtx);
 static bool move_nan_for_stack_reg (rtx_insn *, stack_ptr, rtx);
 static int swap_rtx_condition_1 (rtx);
 static int swap_rtx_condition (rtx_insn *);
-static void compare_for_stack_reg (rtx_insn *, stack_ptr, rtx);
+static void compare_for_stack_reg (rtx_insn *, stack_ptr, rtx, bool);
 static bool subst_stack_regs_pat (rtx_insn *, stack_ptr, rtx);
 static void subst_asm_stack_regs (rtx_insn *, stack_ptr);
 static bool subst_stack_regs (rtx_insn *, stack_ptr);
@@ -1325,7 +1325,8 @@ swap_rtx_condition (rtx_insn *insn)
    set up.  */
 
 static void
-compare_for_stack_reg (rtx_insn *insn, stack_ptr regstack, rtx pat_src)
+compare_for_stack_reg (rtx_insn *insn, stack_ptr regstack,
+                      rtx pat_src, bool can_pop_second_op)
 {
   rtx *src1, *src2;
   rtx src1_note, src2_note;
@@ -1366,8 +1367,18 @@ compare_for_stack_reg (rtx_insn *insn, stack_ptr regstack, rtx pat_src)
 
   if (src1_note)
     {
-      pop_stack (regstack, REGNO (XEXP (src1_note, 0)));
-      replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG);
+      if (*src2 == CONST0_RTX (GET_MODE (*src2)))
+       {
+         /* This is `ftst' insn that can't pop register.  */
+         remove_regno_note (insn, REG_DEAD, REGNO (XEXP (src1_note, 0)));
+         emit_pop_insn (insn, regstack, XEXP (src1_note, 0),
+                        EMIT_AFTER);
+       }
+      else
+       {
+         pop_stack (regstack, REGNO (XEXP (src1_note, 0)));
+         replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG);
+       }
     }
 
   /* If the second operand dies, handle that.  But if the operands are
@@ -1384,7 +1395,7 @@ compare_for_stack_reg (rtx_insn *insn, stack_ptr regstack, rtx pat_src)
         at top (FIRST_STACK_REG) now.  */
 
       if (get_hard_regnum (regstack, XEXP (src2_note, 0)) == FIRST_STACK_REG
-         && src1_note)
+         && src1_note && can_pop_second_op)
        {
          pop_stack (regstack, REGNO (XEXP (src2_note, 0)));
          replace_reg (&XEXP (src2_note, 0), FIRST_STACK_REG + 1);
@@ -1550,7 +1561,9 @@ subst_stack_regs_pat (rtx_insn *insn, stack_ptr regstack, rtx pat)
        switch (GET_CODE (pat_src))
          {
          case COMPARE:
-           compare_for_stack_reg (insn, regstack, pat_src);
+           /* `fcomi' insn can't pop two regs.  */
+           compare_for_stack_reg (insn, regstack, pat_src,
+                                  REGNO (*dest) != FLAGS_REG);
            break;
 
          case CALL:
@@ -1970,7 +1983,7 @@ subst_stack_regs_pat (rtx_insn *insn, stack_ptr regstack, rtx pat)
                pat_src = XVECEXP (pat_src, 0, 0);
                gcc_assert (GET_CODE (pat_src) == COMPARE);
 
-               compare_for_stack_reg (insn, regstack, pat_src);
+               compare_for_stack_reg (insn, regstack, pat_src, true);
                break;
 
              default: