From 7c82106ff9548634c85fa7cd7f1cc3a906fd6efa Mon Sep 17 00:00:00 2001 From: Uros Bizjak Date: Wed, 8 Dec 2004 07:50:58 +0100 Subject: [PATCH] i386-protos.h (ix86_split_fp_branch): New rtx argument. * config/i386/i386-protos.h (ix86_split_fp_branch): New rtx argument. * config/i386/i386.c (output_fp_compare): Fix is_sse condition. Use EFLAGS_P only when fcomi insn should be used. Fix handling of eflags_p variable. Change alt table accordingly. For non-fcomi compare insn always use trailing fnstsw insn. Fix intmode calculation for ficom insn. (ix86_split_fp_branch): Add "rtx pushed" as new parameter. Call ix86_free_from_memory when "pushed" is specified. (ix86_expand_branch): Change call to ix86_split_fp_branch. * config/i386/i386.md (*cmpfp_0_sf, *cmpfp_0_df, *cmpfp_0_xf): Change eflags_p parameter in call to output_fp_compare. (*cmpfp_2_sf, *cmpfp_2_df, *cmpfp_2_xf): Remove. (*cmpfp_2_sf_1, *cmpfp_2_df_1, *cmpfp_2_xf_1): Rename to *cmpfp_2_sf, *cmpfp_2_df, *cmpfp_2_xf. Change eflags_p parameter in call to output_fp_compare. (*cmpfp_2_u): Remove. (*cmpfp_2_u_1): Rename to *cmpfp_2_u. Change eflags_p parameter in call to output_fp_compare. (*ficom_1): Remove insn definition and corresponding define_split. (*cmpfp_si): New insn definition. (*fp_jcc_8): New insn definition. Add new splitters for "memory_operand" and "register_operand". (define_split): Add new parameter in call to ix86_split_fp_branch. config/i386/predicates.md (float_operator): New predicate. From-SVN: r91856 --- gcc/ChangeLog | 31 ++++++ gcc/config/i386/i386-protos.h | 3 +- gcc/config/i386/i386.c | 71 +++++------- gcc/config/i386/i386.md | 197 +++++++++++++++++----------------- gcc/config/i386/predicates.md | 4 + 5 files changed, 163 insertions(+), 143 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9c032694b1e..7b526cc1fa4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,34 @@ +2004-12-07 Uros Bizjak + + * config/i386/i386-protos.h (ix86_split_fp_branch): New rtx + argument. + + * config/i386/i386.c (output_fp_compare): Fix is_sse condition. + Use EFLAGS_P only when fcomi insn should be used. Fix handling + of eflags_p variable. Change alt table accordingly. For non-fcomi + compare insn always use trailing fnstsw insn. Fix intmode + calculation for ficom insn. + (ix86_split_fp_branch): Add "rtx pushed" as new parameter. Call + ix86_free_from_memory when "pushed" is specified. + (ix86_expand_branch): Change call to ix86_split_fp_branch. + + * config/i386/i386.md (*cmpfp_0_sf, *cmpfp_0_df, *cmpfp_0_xf): + Change eflags_p parameter in call to output_fp_compare. + (*cmpfp_2_sf, *cmpfp_2_df, *cmpfp_2_xf): Remove. + (*cmpfp_2_sf_1, *cmpfp_2_df_1, *cmpfp_2_xf_1): Rename to + *cmpfp_2_sf, *cmpfp_2_df, *cmpfp_2_xf. Change eflags_p + parameter in call to output_fp_compare. + (*cmpfp_2_u): Remove. + (*cmpfp_2_u_1): Rename to *cmpfp_2_u. Change eflags_p parameter + in call to output_fp_compare. + (*ficom_1): Remove insn definition and corresponding define_split. + (*cmpfp_si): New insn definition. + (*fp_jcc_8): New insn definition. Add new splitters for + "memory_operand" and "register_operand". + (define_split): Add new parameter in call to ix86_split_fp_branch. + + config/i386/predicates.md (float_operator): New predicate. + 2004-12-08 Kazu Hirata * c-common.c (verify_tree): Don't check code length if we know diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index d0ff2e16621..c79acd033ca 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -165,7 +165,8 @@ extern rtx ix86_va_arg (tree, tree); extern rtx ix86_force_to_memory (enum machine_mode, rtx); extern void ix86_free_from_memory (enum machine_mode); -extern void ix86_split_fp_branch (enum rtx_code code, rtx, rtx, rtx, rtx, rtx); +extern void ix86_split_fp_branch (enum rtx_code code, rtx, rtx, + rtx, rtx, rtx, rtx); extern int ix86_hard_regno_mode_ok (int, enum machine_mode); extern int ix86_register_move_cost (enum machine_mode, enum reg_class, enum reg_class); diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 1a63fe08873..2bd53bc862f 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -7208,26 +7208,25 @@ output_fix_trunc (rtx insn, rtx *operands) } /* Output code for INSN to compare OPERANDS. EFLAGS_P is 1 when fcomi - should be used and 2 when fnstsw should be used. UNORDERED_P is true - when fucom should be used. */ + should be used. UNORDERED_P is true when fucom should be used. */ const char * output_fp_compare (rtx insn, rtx *operands, int eflags_p, int unordered_p) { int stack_top_dies; rtx cmp_op0, cmp_op1; - int is_sse = SSE_REG_P (operands[0]) | SSE_REG_P (operands[1]); + int is_sse = SSE_REG_P (operands[0]) || SSE_REG_P (operands[1]); - if (eflags_p == 2) - { - cmp_op0 = operands[1]; - cmp_op1 = operands[2]; - } - else + if (eflags_p) { cmp_op0 = operands[0]; cmp_op1 = operands[1]; } + else + { + cmp_op0 = operands[1]; + cmp_op1 = operands[2]; + } if (is_sse) { @@ -7268,7 +7267,7 @@ output_fp_compare (rtx insn, rtx *operands, int eflags_p, int unordered_p) is also a stack register that dies, then this must be a `fcompp' float compare */ - if (eflags_p == 1) + if (eflags_p) { /* There is no double popping fcomi variant. Fortunately, eflags is immune from the fstp's cc clobbering. */ @@ -7280,35 +7279,25 @@ output_fp_compare (rtx insn, rtx *operands, int eflags_p, int unordered_p) } else { - if (eflags_p == 2) - { - if (unordered_p) - return "fucompp\n\tfnstsw\t%0"; - else - return "fcompp\n\tfnstsw\t%0"; - } + if (unordered_p) + return "fucompp\n\tfnstsw\t%0"; else - { - if (unordered_p) - return "fucompp"; - else - return "fcompp"; - } + return "fcompp\n\tfnstsw\t%0"; } } else { /* Encoded here as eflags_p | intmode | unordered_p | stack_top_dies. */ - static const char * const alt[24] = + static const char * const alt[16] = { - "fcom%z1\t%y1", - "fcomp%z1\t%y1", - "fucom%z1\t%y1", - "fucomp%z1\t%y1", + "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%z1\t%y1", - "ficomp%z1\t%y1", + "ficom%z2\t%y2\n\tfnstsw\t%0", + "ficomp%z2\t%y2\n\tfnstsw\t%0", NULL, NULL, @@ -7320,16 +7309,6 @@ output_fp_compare (rtx insn, rtx *operands, int eflags_p, int unordered_p) NULL, NULL, NULL, - NULL, - - "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 }; @@ -7337,11 +7316,11 @@ output_fp_compare (rtx insn, rtx *operands, int eflags_p, int unordered_p) const char *ret; mask = eflags_p << 3; - mask |= (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT) << 2; + mask |= (GET_MODE_CLASS (GET_MODE (cmp_op1)) == MODE_INT) << 2; mask |= unordered_p << 1; mask |= stack_top_dies; - if (mask >= 24) + if (mask >= 16) abort (); ret = alt[mask]; if (ret == NULL) @@ -8458,7 +8437,7 @@ ix86_expand_branch (enum rtx_code code, rtx label) { ix86_split_fp_branch (code, ix86_compare_op0, ix86_compare_op1, gen_rtx_LABEL_REF (VOIDmode, label), - pc_rtx, NULL_RTX); + pc_rtx, NULL_RTX, NULL_RTX); } else { @@ -8606,7 +8585,7 @@ ix86_expand_branch (enum rtx_code code, rtx label) /* Split branch based on floating point condition. */ void ix86_split_fp_branch (enum rtx_code code, rtx op1, rtx op2, - rtx target1, rtx target2, rtx tmp) + rtx target1, rtx target2, rtx tmp, rtx pushed) { rtx second, bypass; rtx label = NULL_RTX; @@ -8625,6 +8604,10 @@ ix86_split_fp_branch (enum rtx_code code, rtx op1, rtx op2, condition = ix86_expand_fp_compare (code, op1, op2, tmp, &second, &bypass); + /* Remove pushed operand from stack. */ + if (pushed) + ix86_free_from_memory (GET_MODE (pushed)); + if (split_branch_probability >= 0) { /* Distribute the probabilities across the jumps. diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 84617c5f7eb..84b97e86805 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -797,6 +797,9 @@ ;; CCFPmode compare with exceptions ;; CCFPUmode compare with no exceptions +;; We may not use "#" to split and emit these, since the REG_DEAD notes +;; used to manage the reg stack popping would not be preserved. + (define_insn "*cmpfp_0_sf" [(set (match_operand:HI 0 "register_operand" "=a") (unspec:HI @@ -805,7 +808,7 @@ (match_operand:SF 2 "const0_operand" "X"))] UNSPEC_FNSTSW))] "TARGET_80387" - "* return output_fp_compare (insn, operands, 2, 0);" + "* return output_fp_compare (insn, operands, 0, 0);" [(set_attr "type" "multi") (set_attr "mode" "SF")]) @@ -817,7 +820,7 @@ (match_operand:DF 2 "const0_operand" "X"))] UNSPEC_FNSTSW))] "TARGET_80387" - "* return output_fp_compare (insn, operands, 2, 0);" + "* return output_fp_compare (insn, operands, 0, 0);" [(set_attr "type" "multi") (set_attr "mode" "DF")]) @@ -829,24 +832,11 @@ (match_operand:XF 2 "const0_operand" "X"))] UNSPEC_FNSTSW))] "TARGET_80387" - "* return output_fp_compare (insn, operands, 2, 0);" + "* return output_fp_compare (insn, operands, 0, 0);" [(set_attr "type" "multi") (set_attr "mode" "XF")]) -;; We may not use "#" to split and emit these, since the REG_DEAD notes -;; used to manage the reg stack popping would not be preserved. - -(define_insn "*cmpfp_2_sf" - [(set (reg:CCFP FPSR_REG) - (compare:CCFP - (match_operand:SF 0 "register_operand" "f") - (match_operand:SF 1 "nonimmediate_operand" "fm")))] - "TARGET_80387" - "* return output_fp_compare (insn, operands, 0, 0);" - [(set_attr "type" "fcmp") - (set_attr "mode" "SF")]) - -(define_insn "*cmpfp_2_sf_1" +(define_insn "*cmpfp_sf" [(set (match_operand:HI 0 "register_operand" "=a") (unspec:HI [(compare:CCFP @@ -854,21 +844,11 @@ (match_operand:SF 2 "nonimmediate_operand" "fm"))] UNSPEC_FNSTSW))] "TARGET_80387" - "* return output_fp_compare (insn, operands, 2, 0);" + "* return output_fp_compare (insn, operands, 0, 0);" [(set_attr "type" "fcmp") (set_attr "mode" "SF")]) -(define_insn "*cmpfp_2_df" - [(set (reg:CCFP FPSR_REG) - (compare:CCFP - (match_operand:DF 0 "register_operand" "f") - (match_operand:DF 1 "nonimmediate_operand" "fm")))] - "TARGET_80387" - "* return output_fp_compare (insn, operands, 0, 0);" - [(set_attr "type" "fcmp") - (set_attr "mode" "DF")]) - -(define_insn "*cmpfp_2_df_1" +(define_insn "*cmpfp_df" [(set (match_operand:HI 0 "register_operand" "=a") (unspec:HI [(compare:CCFP @@ -876,21 +856,11 @@ (match_operand:DF 2 "nonimmediate_operand" "fm"))] UNSPEC_FNSTSW))] "TARGET_80387" - "* return output_fp_compare (insn, operands, 2, 0);" + "* return output_fp_compare (insn, operands, 0, 0);" [(set_attr "type" "multi") (set_attr "mode" "DF")]) -(define_insn "*cmpfp_2_xf" - [(set (reg:CCFP FPSR_REG) - (compare:CCFP - (match_operand:XF 0 "register_operand" "f") - (match_operand:XF 1 "register_operand" "f")))] - "TARGET_80387" - "* return output_fp_compare (insn, operands, 0, 0);" - [(set_attr "type" "fcmp") - (set_attr "mode" "XF")]) - -(define_insn "*cmpfp_2_xf_1" +(define_insn "*cmpfp_xf" [(set (match_operand:HI 0 "register_operand" "=a") (unspec:HI [(compare:CCFP @@ -898,29 +868,11 @@ (match_operand:XF 2 "register_operand" "f"))] UNSPEC_FNSTSW))] "TARGET_80387" - "* return output_fp_compare (insn, operands, 2, 0);" + "* return output_fp_compare (insn, operands, 0, 0);" [(set_attr "type" "multi") (set_attr "mode" "XF")]) -(define_insn "*cmpfp_2u" - [(set (reg:CCFPU FPSR_REG) - (compare:CCFPU - (match_operand 0 "register_operand" "f") - (match_operand 1 "register_operand" "f")))] - "TARGET_80387 - && FLOAT_MODE_P (GET_MODE (operands[0])) - && GET_MODE (operands[0]) == GET_MODE (operands[1])" - "* return output_fp_compare (insn, operands, 0, 1);" - [(set_attr "type" "fcmp") - (set (attr "mode") - (cond [(match_operand:SF 1 "" "") - (const_string "SF") - (match_operand:DF 1 "" "") - (const_string "DF") - ] - (const_string "XF")))]) - -(define_insn "*cmpfp_2u_1" +(define_insn "*cmpfp_u" [(set (match_operand:HI 0 "register_operand" "=a") (unspec:HI [(compare:CCFPU @@ -930,7 +882,7 @@ "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1])) && GET_MODE (operands[1]) == GET_MODE (operands[2])" - "* return output_fp_compare (insn, operands, 2, 1);" + "* return output_fp_compare (insn, operands, 0, 1);" [(set_attr "type" "multi") (set (attr "mode") (cond [(match_operand:SF 1 "" "") @@ -940,40 +892,21 @@ ] (const_string "XF")))]) -;; Patterns to match the SImode-in-memory ficom instructions. -;; -;; %%% Play games with accepting gp registers, as otherwise we have to -;; force them to memory during rtl generation, which is no good. We -;; can get rid of this once we teach reload to do memory input reloads -;; via pushes. - -(define_insn "*ficom_1" - [(set (reg:CCFP FPSR_REG) - (compare:CCFP - (match_operand 0 "register_operand" "f,f") - (float (match_operand:SI 1 "nonimmediate_operand" "m,?r"))))] - "0 && TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[0])) - && GET_MODE (XEXP (SET_SRC (PATTERN (insn)), 1)) == GET_MODE (operands[0])" - "#") - -;; Split the not-really-implemented gp register case into a -;; push-op-pop sequence. -;; -;; %%% This is most efficient, but am I gonna get in trouble -;; for separating cc0_setter and cc0_user? - -(define_split - [(set (reg:CCFP FPSR_REG) - (compare:CCFP - (match_operand:SF 0 "register_operand" "") - (float (match_operand:SI 1 "register_operand" ""))))] - "0 && TARGET_80387 && reload_completed" - [(set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_dup 1)) - (set (reg:CCFP FPSR_REG) (compare:CCFP (match_dup 0) (match_dup 2))) - (parallel [(set (match_dup 1) (mem:SI (reg:SI SP_REG))) - (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 4)))])] - "operands[2] = gen_rtx_MEM (Pmode, stack_pointer_rtx); - operands[2] = gen_rtx_FLOAT (GET_MODE (operands[0]), operands[2]);") +(define_insn "*cmpfp_si" + [(set (match_operand:HI 0 "register_operand" "=a") + (unspec:HI + [(compare:CCFP + (match_operand 1 "register_operand" "f") + (match_operator 3 "float_operator" + [(match_operand:SI 2 "memory_operand" "m")]))] + UNSPEC_FNSTSW))] + "TARGET_80387 && TARGET_USE_FIOP + && FLOAT_MODE_P (GET_MODE (operands[1])) + && (GET_MODE (operands [3]) == GET_MODE (operands[1]))" + "* return output_fp_compare (insn, operands, 0, 0);" + [(set_attr "type" "multi") + (set_attr "fp_int_src" "true") + (set_attr "mode" "SI")]) ;; FP compares, step 2 ;; Move the fpsw to ax. @@ -13298,6 +13231,30 @@ && ix86_fp_jump_nontrivial_p (GET_CODE (operands[0]))" "#") +;; The order of operands in *fp_jcc_8 is forced by combine in +;; simplify_comparison () function. Float operator is treated as RTX_OBJ +;; with a precedence over other operators and is always put in the first +;; place. Swap condition and operands to match ficom instruction. + +(define_insn "*fp_jcc_8" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operator 1 "float_operator" + [(match_operand:SI 2 "nonimmediate_operand" "m,?r")]) + (match_operand 3 "register_operand" "f,f")]) + (label_ref (match_operand 4 "" "")) + (pc))) + (clobber (reg:CCFP FPSR_REG)) + (clobber (reg:CCFP FLAGS_REG)) + (clobber (match_scratch:HI 5 "=a,a"))] + "TARGET_80387 && TARGET_USE_FIOP + && FLOAT_MODE_P (GET_MODE (operands[3])) + && GET_MODE (operands[1]) == GET_MODE (operands[3]) + && !ix86_use_fcomi_compare (swap_condition (GET_CODE (operands[0]))) + && ix86_fp_compare_mode (swap_condition (GET_CODE (operands[0]))) == CCFPmode + && ix86_fp_jump_nontrivial_p (swap_condition (GET_CODE (operands[0])))" + "#") + (define_split [(set (pc) (if_then_else (match_operator 0 "comparison_operator" @@ -13311,7 +13268,7 @@ [(const_int 0)] { ix86_split_fp_branch (GET_CODE (operands[0]), operands[1], operands[2], - operands[3], operands[4], NULL_RTX); + operands[3], operands[4], NULL_RTX, NULL_RTX); DONE; }) @@ -13329,7 +13286,51 @@ [(const_int 0)] { ix86_split_fp_branch (GET_CODE (operands[0]), operands[1], operands[2], - operands[3], operands[4], operands[5]); + operands[3], operands[4], operands[5], NULL_RTX); + DONE; +}) + +(define_split + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operator 1 "float_operator" + [(match_operand:SI 2 "memory_operand" "")]) + (match_operand 3 "register_operand" "")]) + (match_operand 4 "" "") + (match_operand 5 "" ""))) + (clobber (reg:CCFP FPSR_REG)) + (clobber (reg:CCFP FLAGS_REG)) + (clobber (match_scratch:HI 6 "=a"))] + "reload_completed" + [(const_int 0)] +{ + operands[7] = gen_rtx_FLOAT (GET_MODE (operands[1]), operands[2]); + ix86_split_fp_branch (swap_condition (GET_CODE (operands[0])), + operands[3], operands[7], + operands[4], operands[5], operands[6], NULL_RTX); + DONE; +}) + +;; %%% Kill this when reload knows how to do it. +(define_split + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operator 1 "float_operator" + [(match_operand:SI 2 "register_operand" "")]) + (match_operand 3 "register_operand" "")]) + (match_operand 4 "" "") + (match_operand 5 "" ""))) + (clobber (reg:CCFP FPSR_REG)) + (clobber (reg:CCFP FLAGS_REG)) + (clobber (match_scratch:HI 6 "=a"))] + "reload_completed" + [(const_int 0)] +{ + operands[7] = ix86_force_to_memory (GET_MODE (operands[2]), operands[2]); + operands[7] = gen_rtx_FLOAT (GET_MODE (operands[1]), operands[7]); + ix86_split_fp_branch (swap_condition (GET_CODE (operands[0])), + operands[3], operands[7], + operands[4], operands[5], operands[6], operands[2]); DONE; }) diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md index ec747aef20e..9154aea8c62 100644 --- a/gcc/config/i386/predicates.md +++ b/gcc/config/i386/predicates.md @@ -795,6 +795,10 @@ (define_predicate "div_operator" (match_code "div")) +;; Return true if this is a float extend operation. +(define_predicate "float_operator" + (match_code "float")) + ;; Return true for ARITHMETIC_P. (define_predicate "arith_or_logical_operator" (match_code "PLUS,MULT,AND,IOR,XOR,SMIN,SMAX,UMIN,UMAX,COMPARE,MINUS,DIV,