rx: Cleanup conditional branches.
authorRichard Henderson <rth@redhat.com>
Mon, 17 Jan 2011 17:53:55 +0000 (09:53 -0800)
committerRichard Henderson <rth@gcc.gnu.org>
Mon, 17 Jan 2011 17:53:55 +0000 (09:53 -0800)
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

gcc/ChangeLog
gcc/config/rx/predicates.md
gcc/config/rx/rx-protos.h
gcc/config/rx/rx.c
gcc/config/rx/rx.md

index 0d539f6ff8713e1636a97b55a4440a1a280cd024..6636b512b49b8b9aec1cb0835760d5e138b82226 100644 (file)
@@ -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.
index e1b3f0c9f913ac0f82f4d8d36c5739cd766582e5..0ab4df3aac9768a440cfff9d9ff44da5f918a235 100644 (file)
   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")
+)
index 02e12ed486734ea8181902398bdf530fc4d0a4e6..f0c2105ad1c812a815ca1ada1fc6ae80eb85f4d8 100644 (file)
@@ -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
 
index 9a163fe49f62ed0f1df189656872434821831f64..a2ff95ecdc93909590efecd9ce06ffac08e0633d 100644 (file)
 \f
 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;
 \f
 /* 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 ();
-    }
-}
 \f
 /* Return VALUE rounded up to the next ALIGNMENT boundary.  */
 
@@ -2543,69 +2570,100 @@ rx_trampoline_init (rtx tramp, tree fndecl, rtx chain)
     }
 }
 \f
-
-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);
 }
 
 \f
index 545c2fb21e88218bcf2e4531f3a9988b05fe350f..c2161a251412198e92caea0fdbd67e4281578a26 100644 (file)
 ;; <http://www.gnu.org/licenses/>.
 \f
 
-;; 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 "")])
 
 (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
 
 (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)