diff options
author | Richard Henderson <rth@redhat.com> | 2011-01-17 09:53:55 -0800 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 2011-01-17 09:53:55 -0800 |
commit | e963cb1a8a5b1660897be19d0aca20cbdcac413f (patch) | |
tree | 3007be2eaad792204f0b8c032a8f8aee8531c6ef /gcc | |
parent | af530bb412465cf6fc55fd9a31ab69b2b2c0a64a (diff) | |
download | gcc-e963cb1a8a5b1660897be19d0aca20cbdcac413f.zip gcc-e963cb1a8a5b1660897be19d0aca20cbdcac413f.tar.gz gcc-e963cb1a8a5b1660897be19d0aca20cbdcac413f.tar.bz2 |
rx: Cleanup conditional branches.
Use match_operator, not code_iterators. Use a new helper function,
rx_split_cbranch. Get the modes right on the comparisons. Distinguish
fp comparisons with CC_Fmode.
From-SVN: r168919
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 29 | ||||
-rw-r--r-- | gcc/config/rx/predicates.md | 17 | ||||
-rw-r--r-- | gcc/config/rx/rx-protos.h | 3 | ||||
-rw-r--r-- | gcc/config/rx/rx.c | 353 | ||||
-rw-r--r-- | gcc/config/rx/rx.md | 381 |
5 files changed, 465 insertions, 318 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0d539f6..6636b51 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,34 @@ 2011-01-17 Richard Henderson <rth@redhat.com> + * config/rx/predicates.md (label_ref_operand): New. + (rx_z_comparison_operator): New. + (rx_zs_comparison_operator): New. + (rx_fp_comparison_operator): New. + * config/rx/rx.c (rx_print_operand) [B]: Examine comparison modes. + Validate that the flags are set properly for the comparison. + (rx_gen_cond_branch_template): Remove. + (rx_cc_modes_compatible): Remove. + (mode_from_flags): New. + (flags_from_code): Rename from flags_needed_for_conditional. + (rx_cc_modes_compatible): Re-write in terms of flags_from_mode. + (rx_select_cc_mode): Likewise. + (rx_split_fp_compare): New. + (rx_split_cbranch): New. + * config/rx/rx.md (most_cond, zs_cond): Remove iterators. + (*cbranchsi4): Use match_operator and rx_split_cbranch. + (*cbranchsf4): Similarly. + (*cbranchsi4_tst): Rename from *tstbranchsi4_<code>. Use + match_operator and rx_split_cbranch. + (*cbranchsi4_tst_ext): Combine *tstbranchsi4m_eq and + tstbranchsi4m_ne. Use match_operator and rx_split_cbranch. + (*cmpsi): Rename from cmpsi. + (*tstsi): Rename from tstsi. + (*cmpsf): Rename from cmpsf; use CC_Fmode. + (*conditional_branch): Rename from conditional_branch. + (*reveresed_conditional_branch): Remove. + (b<code>): Remove expander. + * config/rx/rx-protos.h: Update. + * config/rx/rx.c (rx_compare_redundant): Remove. * config/rx/rx.md (cmpsi): Don't use it. * config/rx/rx-protos.h: Update. diff --git a/gcc/config/rx/predicates.md b/gcc/config/rx/predicates.md index e1b3f0c..0ab4df3 100644 --- a/gcc/config/rx/predicates.md +++ b/gcc/config/rx/predicates.md @@ -293,3 +293,20 @@ element = XVECEXP (op, 0, count - 1); return GET_CODE (element) == RETURN; }) + +(define_predicate "label_ref_operand" + (match_code "label_ref") +) + +(define_predicate "rx_z_comparison_operator" + (match_code "eq,ne") +) + +(define_predicate "rx_zs_comparison_operator" + (match_code "eq,ne,lt,ge") +) + +;; GT, LE, UNLE, UNGT omitted due to operand swap required. +(define_predicate "rx_fp_comparison_operator" + (match_code "eq,ne,lt,ge,ordered,unordered,uneq,unlt,unge,ltgt") +) diff --git a/gcc/config/rx/rx-protos.h b/gcc/config/rx/rx-protos.h index 02e12ed..f0c2105 100644 --- a/gcc/config/rx/rx-protos.h +++ b/gcc/config/rx/rx-protos.h @@ -34,12 +34,13 @@ extern void rx_emit_stack_popm (rtx *, bool); extern void rx_emit_stack_pushm (rtx *); extern void rx_expand_epilogue (bool); extern bool rx_expand_insv (rtx *); -extern const char * rx_gen_cond_branch_template (rtx, bool); extern char * rx_gen_move_template (rtx *, bool); extern bool rx_is_legitimate_constant (rtx); extern bool rx_is_mode_dependent_addr (rtx); extern bool rx_is_restricted_memory_address (rtx, Mmode); extern void rx_notice_update_cc (rtx body, rtx insn); +extern void rx_split_cbranch (Mmode, Rcode, rtx, rtx, rtx); +extern bool rx_split_fp_compare (Rcode, Rcode *, Rcode *); extern Mmode rx_select_cc_mode (Rcode, rtx, rtx); #endif diff --git a/gcc/config/rx/rx.c b/gcc/config/rx/rx.c index 9a163fe..a2ff95e 100644 --- a/gcc/config/rx/rx.c +++ b/gcc/config/rx/rx.c @@ -53,6 +53,15 @@ static void rx_print_operand (FILE *, rtx, int); +#define CC_FLAG_S (1 << 0) +#define CC_FLAG_Z (1 << 1) +#define CC_FLAG_O (1 << 2) +#define CC_FLAG_C (1 << 3) +#define CC_FLAG_FP (1 << 4) /* fake, to differentiate CC_Fmode */ + +static unsigned int flags_from_mode (enum machine_mode mode); +static unsigned int flags_from_code (enum rtx_code code); + enum rx_cpu_types rx_cpu_type = RX600; /* Return true if OP is a reference to an object in a small data area. */ @@ -395,21 +404,84 @@ rx_print_operand (FILE * file, rtx op, int letter) break; case 'B': - switch (GET_CODE (op)) - { - case LT: fprintf (file, "lt"); break; - case GE: fprintf (file, "ge"); break; - case GT: fprintf (file, "gt"); break; - case LE: fprintf (file, "le"); break; - case GEU: fprintf (file, "geu"); break; - case LTU: fprintf (file, "ltu"); break; - case GTU: fprintf (file, "gtu"); break; - case LEU: fprintf (file, "leu"); break; - case EQ: fprintf (file, "eq"); break; - case NE: fprintf (file, "ne"); break; - default: debug_rtx (op); gcc_unreachable (); - } - break; + { + enum rtx_code code = GET_CODE (op); + enum machine_mode mode = GET_MODE (XEXP (op, 0)); + const char *ret; + + if (mode == CC_Fmode) + { + /* C flag is undefined, and O flag carries unordered. None of the + branch combinations that include O use it helpfully. */ + switch (code) + { + case ORDERED: + ret = "no"; + break; + case UNORDERED: + ret = "o"; + break; + case LT: + ret = "n"; + break; + case GE: + ret = "pz"; + break; + case EQ: + ret = "eq"; + break; + case NE: + ret = "ne"; + break; + default: + gcc_unreachable (); + } + } + else + { + switch (code) + { + case LT: + ret = "n"; + break; + case GE: + ret = "pz"; + break; + case GT: + ret = "gt"; + break; + case LE: + ret = "le"; + break; + case GEU: + ret = "geu"; + break; + case LTU: + ret = "ltu"; + break; + case GTU: + ret = "gtu"; + break; + case LEU: + ret = "leu"; + break; + case EQ: + ret = "eq"; + break; + case NE: + ret = "ne"; + break; + default: + gcc_unreachable (); + } + /* ??? Removable when all of cbranch, cstore, cmove are updated. */ + if (GET_MODE_CLASS (mode) == MODE_CC) + gcc_checking_assert ((flags_from_code (code) + & ~flags_from_mode (mode)) == 0); + } + fputs (ret, file); + break; + } case 'C': gcc_assert (CONST_INT_P (op)); @@ -700,51 +772,6 @@ rx_gen_move_template (rtx * operands, bool is_movu) extension, src_template, dst_template); return out_template; } - -/* Returns an assembler template for a conditional branch instruction. */ - -const char * -rx_gen_cond_branch_template (rtx condition, bool reversed) -{ - enum rtx_code code = GET_CODE (condition); - - if (reversed) - { - if (rx_float_compare_mode) - code = reverse_condition_maybe_unordered (code); - else - code = reverse_condition (code); - } - - /* We do not worry about encoding the branch length here as GAS knows - how to choose the smallest version, and how to expand a branch that - is to a destination that is out of range. */ - - switch (code) - { - case UNEQ: return "bo\t1f\n\tbeq\t%0\n1:"; - case LTGT: return "bo\t1f\n\tbne\t%0\n1:"; - case UNLT: return "bo\t1f\n\tbn\t%0\n1:"; - case UNGE: return "bo\t1f\n\tbpz\t%0\n1:"; - case UNLE: return "bo\t1f\n\tbgt\t1f\n\tbra\t%0\n1:"; - case UNGT: return "bo\t1f\n\tble\t1f\n\tbra\t%0\n1:"; - case UNORDERED: return "bo\t%0"; - case ORDERED: return "bno\t%0"; - - case LT: return rx_float_compare_mode ? "bn\t%0" : "blt\t%0"; - case GE: return rx_float_compare_mode ? "bpz\t%0" : "bge\t%0"; - case GT: return "bgt\t%0"; - case LE: return "ble\t%0"; - case GEU: return "bgeu\t%0"; - case LTU: return "bltu\t%0"; - case GTU: return "bgtu\t%0"; - case LEU: return "bleu\t%0"; - case EQ: return "beq\t%0"; - case NE: return "bne\t%0"; - default: - gcc_unreachable (); - } -} /* Return VALUE rounded up to the next ALIGNMENT boundary. */ @@ -2543,69 +2570,100 @@ rx_trampoline_init (rtx tramp, tree fndecl, rtx chain) } } - -static enum machine_mode -rx_cc_modes_compatible (enum machine_mode m1, enum machine_mode m2) +static int +rx_memory_move_cost (enum machine_mode mode, reg_class_t regclass, bool in) { - if (m1 == CCmode) - return m2; - if (m2 == CCmode) - return m1; - if (m1 == m2) - return m1; - if (m1 == CC_ZSmode) - return m1; - if (m2 == CC_ZSmode) - return m2; - return VOIDmode; + return 2 + memory_move_secondary_cost (mode, regclass, in); } -#define CC_FLAG_S (1 << 0) -#define CC_FLAG_Z (1 << 1) -#define CC_FLAG_O (1 << 2) -#define CC_FLAG_C (1 << 3) +/* Convert a CC_MODE to the set of flags that it represents. */ static unsigned int -flags_needed_for_conditional (rtx conditional) +flags_from_mode (enum machine_mode mode) { - switch (GET_CODE (conditional)) + switch (mode) { - case LE: - case GT: return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_O; - - case LEU: - case GTU: return CC_FLAG_Z | CC_FLAG_C; - - case LT: - case GE: return CC_FLAG_S | CC_FLAG_O; - - case LTU: - case GEU: return CC_FLAG_C; + case CC_ZSmode: + return CC_FLAG_S | CC_FLAG_Z; + case CC_ZSOmode: + return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_O; + case CC_ZSCmode: + return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_C; + case CCmode: + return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_O | CC_FLAG_C; + case CC_Fmode: + return CC_FLAG_FP; + default: + gcc_unreachable (); + } +} - case EQ: - case NE: return CC_FLAG_Z; +/* Convert a set of flags to a CC_MODE that can implement it. */ - default: gcc_unreachable (); +static enum machine_mode +mode_from_flags (unsigned int f) +{ + if (f & CC_FLAG_FP) + return CC_Fmode; + if (f & CC_FLAG_O) + { + if (f & CC_FLAG_C) + return CCmode; + else + return CC_ZSOmode; } + else if (f & CC_FLAG_C) + return CC_ZSCmode; + else + return CC_ZSmode; } +/* Convert an RTX_CODE to the set of flags needed to implement it. + This assumes an integer comparison. */ + static unsigned int -flags_from_mode (enum machine_mode mode) +flags_from_code (enum rtx_code code) { - switch (mode) + switch (code) { - case CCmode: return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_O | CC_FLAG_C; - case CC_ZSmode: return CC_FLAG_S | CC_FLAG_Z; - case CC_ZSOmode: return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_O; - case CC_ZSCmode: return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_C; - default: gcc_unreachable (); + case LT: + case GE: + return CC_FLAG_S; + case GT: + case LE: + return CC_FLAG_S | CC_FLAG_O | CC_FLAG_Z; + case GEU: + case LTU: + return CC_FLAG_C; + case GTU: + case LEU: + return CC_FLAG_C | CC_FLAG_Z; + case EQ: + case NE: + return CC_FLAG_Z; + default: + gcc_unreachable (); } } -static int -rx_memory_move_cost (enum machine_mode mode, reg_class_t regclass, bool in) +/* Return a CC_MODE of which both M1 and M2 are subsets. */ + +static enum machine_mode +rx_cc_modes_compatible (enum machine_mode m1, enum machine_mode m2) { - return 2 + memory_move_secondary_cost (mode, regclass, in); + unsigned f; + + /* Early out for identical modes. */ + if (m1 == m2) + return m1; + + /* There's no valid combination for FP vs non-FP. */ + f = flags_from_mode (m1) | flags_from_mode (m2); + if (f & CC_FLAG_FP) + return VOIDmode; + + /* Otherwise, see what mode can implement all the flags. */ + return mode_from_flags (f); } /* Return the minimal CC mode needed to implement (CMP_CODE X Y). */ @@ -2616,24 +2674,89 @@ rx_select_cc_mode (enum rtx_code cmp_code, rtx x, rtx y ATTRIBUTE_UNUSED) if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) return CC_Fmode; - switch (cmp_code) + return mode_from_flags (flags_from_code (cmp_code)); +} + +/* Split the floating-point comparison IN into individual comparisons + O1 and O2. O2 may be UNKNOWN if there is no second comparison. + Return true iff the comparison operands must be swapped. */ + +bool +rx_split_fp_compare (enum rtx_code in, enum rtx_code *o1, enum rtx_code *o2) +{ + enum rtx_code cmp1 = in, cmp2 = UNKNOWN; + bool swap = false; + + switch (in) { - case EQ: - case NE: + case ORDERED: + case UNORDERED: case LT: case GE: - return CC_ZSmode; + case EQ: + case NE: + break; + case GT: case LE: - return CC_ZSOmode; - case GEU: - case LTU: - case GTU: - case LEU: - return CC_ZSCmode; + cmp1 = swap_condition (cmp1); + swap = true; + break; + + case UNEQ: + cmp1 = UNORDERED; + cmp2 = EQ; + break; + case UNLT: + cmp1 = UNORDERED; + cmp2 = LT; + break; + case UNGE: + cmp1 = UNORDERED; + cmp2 = GE; + break; + case UNLE: + cmp1 = UNORDERED; + cmp2 = GT; + swap = true; + break; + case UNGT: + cmp1 = UNORDERED; + cmp2 = LE; + swap = true; + break; + case LTGT: + cmp1 = ORDERED; + cmp2 = NE; + break; + default: - return CCmode; + gcc_unreachable (); } + + *o1 = cmp1; + *o2 = cmp2; + return swap; +} + +/* Split the conditional branch. Emit (COMPARE C1 C2) into CC_REG with + CC_MODE, and use that in branches based on that compare. */ + +void +rx_split_cbranch (enum machine_mode cc_mode, enum rtx_code cmp1, + rtx c1, rtx c2, rtx label) +{ + rtx flags, x; + + flags = gen_rtx_REG (cc_mode, CC_REG); + x = gen_rtx_COMPARE (cc_mode, c1, c2); + x = gen_rtx_SET (VOIDmode, flags, x); + emit_insn (x); + + x = gen_rtx_fmt_ee (cmp1, VOIDmode, flags, const0_rtx); + x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, label, pc_rtx); + x = gen_rtx_SET (VOIDmode, pc_rtx, x); + emit_jump_insn (x); } diff --git a/gcc/config/rx/rx.md b/gcc/config/rx/rx.md index 545c2fb..c2161a2 100644 --- a/gcc/config/rx/rx.md +++ b/gcc/config/rx/rx.md @@ -19,14 +19,6 @@ ;; <http://www.gnu.org/licenses/>. -;; This code iterator allows all branch instructions to -;; be generated from a single define_expand template. -(define_code_iterator most_cond [eq ne gt ge lt le gtu geu ltu leu - unordered ordered ]) - -;; Likewise, but only the ones that use Z or S. -(define_code_iterator zs_cond [eq ne gtu geu ltu leu ]) - ;; This code iterator is used for sign- and zero- extensions. (define_mode_iterator small_int_modes [(HI "") (QI "")]) @@ -150,6 +142,8 @@ (define_insn_reservation "throughput_18_latency_18" 1 (eq_attr "timings" "1818") "throughput*18") +;; ---------------------------------------------------------------------------- + ;; Comparisons ;; Note - we do not specify the two instructions necessary to perform @@ -160,245 +154,228 @@ (define_expand "cbranchsi4" [(set (pc) - (if_then_else (match_operator 0 "comparison_operator" - [(match_operand:SI 1 "register_operand") - (match_operand:SI 2 "rx_source_operand")]) - (label_ref (match_operand 3 "")) - (pc))) - ] - "" + (if_then_else + (match_operator 0 "comparison_operator" + [(match_operand:SI 1 "register_operand") + (match_operand:SI 2 "rx_source_operand")]) + (label_ref (match_operand 3 "")) + (pc)))] "" ) -(define_insn_and_split "*cbranchsi4_<code>" +(define_insn_and_split "*cbranchsi4" [(set (pc) - (if_then_else (most_cond (match_operand:SI 0 "register_operand" "r") - (match_operand:SI 1 "rx_source_operand" "riQ")) - (label_ref (match_operand 2 "" "")) - (pc))) - ] + (if_then_else + (match_operator 3 "comparison_operator" + [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "rx_source_operand" "riQ")]) + (match_operand 2 "label_ref_operand" "") + (pc)))] "" "#" "reload_completed" [(const_int 0)] - " - /* We contstruct the split by hand as otherwise the JUMP_LABEL - attribute is not set correctly on the jump insn. */ - emit_insn (gen_cmpsi (operands[0], operands[1])); - - emit_jump_insn (gen_conditional_branch (operands[2], - gen_rtx_fmt_ee (<most_cond:CODE>, CCmode, - gen_rtx_REG (CCmode, CC_REG), const0_rtx))); - " -) +{ + rx_split_cbranch (CCmode, GET_CODE (operands[3]), + operands[0], operands[1], operands[2]); + DONE; +}) -;; ----------------------------------------------------------------------------- -;; These two are the canonical TST/branch insns. However, GCC -;; generates a wide variety of tst-like patterns, we catch those -;; below. -(define_insn_and_split "*tstbranchsi4_<code>" - [(set (pc) - (if_then_else (zs_cond (and:SI (match_operand:SI 0 "register_operand" "r") - (match_operand:SI 1 "rx_source_operand" "riQ")) - (const_int 0)) - (label_ref (match_operand 2 "" "")) - (pc))) - ] - "" - "#" +(define_insn "*cmpsi" + [(set (reg:CC CC_REG) + (compare:CC (match_operand:SI 0 "register_operand" "r,r,r,r,r,r,r") + (match_operand:SI 1 "rx_source_operand" "r,Uint04,Int08,Sint16,Sint24,i,Q")))] "reload_completed" - [(const_int 0)] - " - emit_insn (gen_tstsi (operands[0], operands[1])); - - emit_jump_insn (gen_conditional_branch (operands[2], - gen_rtx_fmt_ee (<zs_cond:CODE>, CCmode, - gen_rtx_REG (CCmode, CC_REG), const0_rtx))); - " + "cmp\t%Q1, %0" + [(set_attr "timings" "11,11,11,11,11,11,33") + (set_attr "length" "2,2,3,4,5,6,5")] ) -;; Inverse of above -(define_insn_and_split "*tstbranchsi4r_<code>" +;; Canonical method for representing TST. +(define_insn_and_split "*cbranchsi4_tst" [(set (pc) - (if_then_else (zs_cond (and:SI (match_operand:SI 0 "register_operand" "r") - (match_operand:SI 1 "rx_source_operand" "riQ")) - (const_int 0)) - (pc) - (label_ref (match_operand 2 "" "")))) - ] + (if_then_else + (match_operator 3 "rx_zs_comparison_operator" + [(and:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "rx_source_operand" "riQ")) + (const_int 0)]) + (match_operand 2 "label_ref_operand" "") + (pc)))] "" "#" "reload_completed" [(const_int 0)] - " - emit_insn (gen_tstsi (operands[0], operands[1])); - - emit_jump_insn (gen_conditional_branch (operands[2], - gen_rtx_fmt_ee (reverse_condition (<zs_cond:CODE>), CCmode, - gen_rtx_REG (CCmode, CC_REG), const0_rtx))); - " -) +{ + rx_split_cbranch (CC_ZSmode, GET_CODE (operands[3]), + XEXP (operands[3], 0), XEXP (operands[3], 1), + operands[2]); + DONE; +}) ;; Various other ways that GCC codes "var & const" - -(define_insn_and_split "*tstbranchsi4m_eq" - [(set (pc) - (if_then_else (eq (zero_extract:SI (match_operand:SI 0 "register_operand" "r") - (match_operand 1 "rx_constshift_operand" "i") - (match_operand 2 "rx_constshift_operand" "i")) - (const_int 0)) - (label_ref (match_operand 3 "" "")) - (pc))) - ] - "" - "#" - "" - [(set (pc) - (if_then_else (eq (and:SI (match_dup 0) - (match_dup 4)) - (const_int 0)) - (label_ref (match_dup 3)) - (pc))) - ] - "operands[4] = GEN_INT (((1 << INTVAL (operands[1]))-1) << INTVAL (operands[2]));" -) - -(define_insn_and_split "*tstbranchsi4m_ne" +(define_insn_and_split "*cbranchsi4_tst_ext" [(set (pc) - (if_then_else (ne (zero_extract:SI (match_operand:SI 0 "register_operand" "r") - (match_operand 1 "rx_constshift_operand" "i") - (match_operand 2 "rx_constshift_operand" "i")) - (const_int 0)) - (label_ref (match_operand 3 "" "")) - (pc))) - ] + (if_then_else + (match_operator 4 "rx_z_comparison_operator" + [(zero_extract:SI + (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "rx_constshift_operand" "") + (match_operand:SI 2 "rx_constshift_operand" "")) + (const_int 0)]) + (match_operand 3 "label_ref_operand" "") + (pc)))] "" "#" - "" - [(set (pc) - (if_then_else (ne (and:SI (match_dup 0) - (match_dup 4)) - (const_int 0)) - (label_ref (match_dup 3)) - (pc))) - ] - "operands[4] = GEN_INT (((1 << INTVAL (operands[1]))-1) << INTVAL (operands[2]));" + "reload_completed" + [(const_int 0)] +{ + HOST_WIDE_INT mask; + rtx x; + + mask = 1; + mask <<= INTVAL (operands[1]); + mask -= 1; + mask <<= INTVAL (operands[2]); + x = gen_rtx_AND (SImode, operands[0], gen_int_mode (mask, SImode)); + + rx_split_cbranch (CC_ZSmode, GET_CODE (operands[4]), + x, const0_rtx, operands[3]); + DONE; +}) + +(define_insn "*tstsi" + [(set (reg:CC_ZS CC_REG) + (compare:CC_ZS + (and:SI (match_operand:SI 0 "register_operand" "r,r,r") + (match_operand:SI 1 "rx_source_operand" "r,i,Q")) + (const_int 0)))] + "reload_completed" + "tst\t%Q1, %0" + [(set_attr "timings" "11,11,33") + (set_attr "length" "3,7,6")] ) -;; ----------------------------------------------------------------------------- - (define_expand "cbranchsf4" [(set (pc) - (if_then_else (match_operator 0 "comparison_operator" - [(match_operand:SF 1 "register_operand") - (match_operand:SF 2 "rx_source_operand")]) - (label_ref (match_operand 3 "")) - (pc))) - ] + (if_then_else + (match_operator 0 "comparison_operator" + [(match_operand:SF 1 "register_operand") + (match_operand:SF 2 "register_operand")]) + (label_ref (match_operand 3 "")) + (pc)))] "ALLOW_RX_FPU_INSNS" - "" -) - -(define_insn_and_split "*cbranchsf4_<code>" +{ + enum rtx_code cmp1, cmp2; + + /* If the comparison needs swapping of operands, do that now. + Do not split the comparison in two yet. */ + if (rx_split_fp_compare (GET_CODE (operands[0]), &cmp1, &cmp2)) + { + rtx op1, op2; + + if (cmp2 != UNKNOWN) + { + gcc_assert (cmp1 == UNORDERED); + if (cmp2 == GT) + cmp1 = UNGT; + else if (cmp2 == LE) + cmp1 = UNLE; + else + gcc_unreachable (); + } + + op1 = operands[2]; + op2 = operands[1]; + operands[0] = gen_rtx_fmt_ee (cmp1, VOIDmode, op1, op2); + operands[1] = op1; + operands[2] = op2; + } +}) + +(define_insn_and_split "*cbranchsf4" [(set (pc) - (if_then_else (most_cond (match_operand:SF 0 "register_operand" "r") - (match_operand:SF 1 "rx_source_operand" "rFiQ")) - (label_ref (match_operand 2 "" "")) - (pc))) - ] + (if_then_else + (match_operator 3 "rx_fp_comparison_operator" + [(match_operand:SF 0 "register_operand" "r") + (match_operand:SF 1 "rx_source_operand" "rFiQ")]) + (match_operand 2 "label_ref_operand" "") + (pc)))] "ALLOW_RX_FPU_INSNS" "#" "&& reload_completed" [(const_int 0)] - " - /* We contstruct the split by hand as otherwise the JUMP_LABEL - attribute is not set correctly on the jump insn. */ - emit_insn (gen_cmpsf (operands[0], operands[1])); - - emit_jump_insn (gen_conditional_branch (operands[2], - gen_rtx_fmt_ee (<most_cond:CODE>, CCmode, - gen_rtx_REG (CCmode, CC_REG), const0_rtx))); - " -) - -(define_insn "tstsi" - [(set (reg:CC_ZS CC_REG) - (compare:CC_ZS (and:SI (match_operand:SI 0 "register_operand" "r,r,r") - (match_operand:SI 1 "rx_source_operand" "r,i,Q")) - (const_int 0)))] - "" - { - rx_float_compare_mode = false; - return "tst\t%Q1, %0"; - } - [(set_attr "timings" "11,11,33") - (set_attr "length" "3,7,6")] -) - -(define_insn "cmpsi" - [(set (reg:CC CC_REG) - (compare:CC (match_operand:SI 0 "register_operand" "r,r,r,r,r,r,r") - (match_operand:SI 1 "rx_source_operand" "r,Uint04,Int08,Sint16,Sint24,i,Q")))] - "" - "cmp\t%Q1, %0" - [(set_attr "timings" "11,11,11,11,11,11,33") - (set_attr "length" "2,2,3,4,5,6,5")] -) - -;; ??? g++.dg/eh/080514-1.C to see this happen. -(define_insn "cmpsf" - [(set (reg:CC_ZSO CC_REG) - (compare:CC_ZSO (match_operand:SF 0 "register_operand" "r,r,r") - (match_operand:SF 1 "rx_source_operand" "r,iF,Q")))] - "ALLOW_RX_FPU_INSNS" - { - rx_float_compare_mode = true; - return "fcmp\t%1, %0"; - } +{ + enum rtx_code cmp0, cmp1, cmp2; + rtx flags, lab1, lab2, over, x; + bool swap; + + cmp0 = GET_CODE (operands[3]); + swap = rx_split_fp_compare (cmp0, &cmp1, &cmp2); + gcc_assert (!swap); + + flags = gen_rtx_REG (CC_Fmode, CC_REG); + x = gen_rtx_COMPARE (CC_Fmode, operands[0], operands[1]); + x = gen_rtx_SET (VOIDmode, flags, x); + emit_insn (x); + + over = NULL; + lab1 = lab2 = operands[2]; + + /* The one case of LTGT needs to be split into cmp1 && cmp2. */ + if (cmp0 == LTGT) + { + over = gen_label_rtx (); + lab1 = gen_rtx_LABEL_REF (VOIDmode, over); + cmp1 = reverse_condition_maybe_unordered (cmp1); + } + + /* Otherwise we split into cmp1 || cmp2. */ + x = gen_rtx_fmt_ee (cmp1, VOIDmode, flags, const0_rtx); + x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, lab1, pc_rtx); + x = gen_rtx_SET (VOIDmode, pc_rtx, x); + emit_jump_insn (x); + + if (cmp2 != UNKNOWN) + { + x = gen_rtx_fmt_ee (cmp2, VOIDmode, flags, const0_rtx); + x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, lab2, pc_rtx); + x = gen_rtx_SET (VOIDmode, pc_rtx, x); + emit_jump_insn (x); + } + + if (over) + emit_label (over); + DONE; +}) + +(define_insn "*cmpsf" + [(set (reg:CC_F CC_REG) + (compare:CC_F + (match_operand:SF 0 "register_operand" "r,r,r") + (match_operand:SF 1 "rx_source_operand" "r,iF,Q")))] + "ALLOW_RX_FPU_INSNS && reload_completed" + "fcmp\t%1, %0" [(set_attr "timings" "11,11,33") (set_attr "length" "3,7,5")] ) ;; Flow Control Instructions: -(define_expand "b<code>" - [(set (pc) - (if_then_else (most_cond (reg:CC CC_REG) (const_int 0)) - (label_ref (match_operand 0)) - (pc)))] - "" - "" -) - -(define_insn "conditional_branch" +(define_insn "*conditional_branch" [(set (pc) - (if_then_else (match_operator 1 "comparison_operator" - [(reg:CC CC_REG) (const_int 0)]) - (label_ref (match_operand 0 "" "")) - (pc)))] + (if_then_else + (match_operator 1 "comparison_operator" + [(reg CC_REG) (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] "" - { - return rx_gen_cond_branch_template (operands[1], false); - } + "b%B1\t%0" [(set_attr "length" "8") ;; This length is wrong, but it is ;; too hard to compute statically. (set_attr "timings" "33")] ;; The timing assumes that the branch is taken. ) -(define_insn "*reveresed_conditional_branch" - [(set (pc) - (if_then_else (match_operator 1 "comparison_operator" - [(reg:CC CC_REG) (const_int 0)]) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" - { - return rx_gen_cond_branch_template (operands[1], true); - } - [(set_attr "length" "8") ;; This length is wrong, but it is - ;; too hard to compute statically. - (set_attr "timings" "33")] ;; The timing assumes that the branch is taken. -) +;; ---------------------------------------------------------------------------- (define_insn "jump" [(set (pc) |