aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Henderson <rth@redhat.com>2011-01-17 09:53:55 -0800
committerRichard Henderson <rth@gcc.gnu.org>2011-01-17 09:53:55 -0800
commite963cb1a8a5b1660897be19d0aca20cbdcac413f (patch)
tree3007be2eaad792204f0b8c032a8f8aee8531c6ef /gcc
parentaf530bb412465cf6fc55fd9a31ab69b2b2c0a64a (diff)
downloadgcc-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/ChangeLog29
-rw-r--r--gcc/config/rx/predicates.md17
-rw-r--r--gcc/config/rx/rx-protos.h3
-rw-r--r--gcc/config/rx/rx.c353
-rw-r--r--gcc/config/rx/rx.md381
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)