From 7061821d4aa300b600f689cadb994d7658600414 Mon Sep 17 00:00:00 2001 From: Uros Bizjak Date: Tue, 17 Oct 2017 18:35:11 +0200 Subject: reg-stack.c (compare_for_stack_reg): Add bool argument. * 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) : Detect FCOMI instruction to set can_pop_second_op to false in the compare_for_stack_reg call. * config/i386/i386.md (*cmpi): 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 | 14 +++++ gcc/config/i386/i386.c | 139 +++++++++++++++--------------------------------- gcc/config/i386/i386.md | 9 ++-- gcc/reg-stack.c | 27 +++++++--- 4 files changed, 81 insertions(+), 108 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 14f0d01..3c7fac7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2017-10-17 Uros Bizjak + + * 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) : Detect FCOMI instruction to + set can_pop_second_op to false in the compare_for_stack_reg call. + + * config/i386/i386.md (*cmpi): 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 PR middle-end/82577 diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 26b22d6..2024cfe 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -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 diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 8262cf1..512bd64 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -1685,8 +1685,7 @@ (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")]) @@ -1698,8 +1697,10 @@ (match_operand:MODEF 1 "register_ssemem_operand" "f,vm")))] "(SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH) || (TARGET_80387 && TARGET_CMOVE)" - "* return output_fp_compare (insn, operands, true, - mode == CCFPUmode);" + "@ + * return output_fp_compare (insn, operands, true, \ + mode == CCFPUmode); + %vcomi\t{%1, %0|%0, %1}" [(set_attr "type" "fcmp,ssecomi") (set_attr "prefix" "orig,maybe_vex") (set_attr "mode" "") diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c index f238106..86021ab 100644 --- a/gcc/reg-stack.c +++ b/gcc/reg-stack.c @@ -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: -- cgit v1.1