diff mbox

[mn10300] use the post-reload compare elimination pass

Message ID 4CF43D32.9050001@redhat.com
State New
Headers show

Commit Message

Richard Henderson Nov. 29, 2010, 11:54 p.m. UTC
This is the backend patch that makes use of the -fcompare-elim pass.

This only attempts to handle PLUS, MINUS, AND, OR, XOR in how they
set the flags.  Further work along these lines could handle shifts,
but its clear that PLUS is the most complicated case.

Note that BTST is handled via the pre-reload combine pass and
another cbranch variant.  At least the register form was easy
enough to handle that way.  I didn't try to handle the memory form.

Comments?


r~
From 1bab3418de4dd6c3480ae254512d1dd30d62df16 Mon Sep 17 00:00:00 2001
From: Richard Henderson <rth@twiddle.net>
Date: Mon, 29 Nov 2010 15:28:26 -0800
Subject: [PATCH 3/3] mn10300: Use the compare-elim pass.

In addition to enabling the pass, add the sorts of patterns
to match combined operate-and-compare.
---
 gcc/config/mn10300/mn10300-modes.def |    1 +
 gcc/config/mn10300/mn10300-protos.h  |    6 +-
 gcc/config/mn10300/mn10300.c         |  303 +++++++++++----
 gcc/config/mn10300/mn10300.h         |    2 +-
 gcc/config/mn10300/mn10300.md        |  687 ++++++++++------------------------
 gcc/config/mn10300/predicates.md     |   28 ++
 6 files changed, 457 insertions(+), 570 deletions(-)

Comments

Jeff Law Nov. 30, 2010, 4:59 p.m. UTC | #1
On 11/29/10 16:54, Richard Henderson wrote:
> This is the backend patch that makes use of the -fcompare-elim pass.
>
> This only attempts to handle PLUS, MINUS, AND, OR, XOR in how they
> set the flags.  Further work along these lines could handle shifts,
> but its clear that PLUS is the most complicated case.
>
> Note that BTST is handled via the pre-reload combine pass and
> another cbranch variant.  At least the register form was easy
> enough to handle that way.  I didn't try to handle the memory form.
>
> Comments?
My backend-fu is a bit rusty.  For a comparison operator, we don't use 
modes, right?  It appears that the old cbranchsi4_post_reload had CCmode 
when it generated the comparison:

-  emit_jump_insn (gen_integer_conditional_branch
-                      (gen_rtx_fmt_ee (GET_CODE (operands[3]),
-                       CCmode,
-                        gen_rtx_REG (CCmode, CC_REG),
-                                  const0_rtx),
-                       operands[2]));

The new code in split_cbranch uses VOIDmode:

+  x = gen_rtx_fmt_ee (GET_CODE (cmp_op), VOIDmode, flags, const0_rtx);

I simply don't recall what (if any) rules/guidelines we had for include 
a mode on the comparison rtx.


You need to update the comment before the cmpsi pattern.  I think the 
first hunk of the comment shoudl probably remain unchanged, the second 
part however, needs updating.

Is there some reason why you took out the ZERO_EXTRACT cost from 
mn10300_rtx_costs?

You eliminated the negsi2 expander, was that on purpose?  Presumably 
it's handled generically these days? (if not, it should)?


Overall it looks pretty reasonable.  In a lot of ways the resulting md 
file looks cleaner to me.

I guess the ultimate test is whether or not it actually works :-)

jeff
Richard Henderson Nov. 30, 2010, 9:29 p.m. UTC | #2
On 11/30/2010 08:59 AM, Jeff Law wrote:
> My backend-fu is a bit rusty.  For a comparison operator, we don't use modes, right?

Only for setcc insns.

> It appears that the old cbranchsi4_post_reload had CCmode when it generated the comparison:
> 
> -  emit_jump_insn (gen_integer_conditional_branch
> -                      (gen_rtx_fmt_ee (GET_CODE (operands[3]),
> -                       CCmode,
> -                        gen_rtx_REG (CCmode, CC_REG),
> -                                  const0_rtx),
> -                       operands[2]));
> 
> The new code in split_cbranch uses VOIDmode:

Yep.  We had been adding the CCmode where it wasn't desired.

> You need to update the comment before the cmpsi pattern.  I think the
> first hunk of the comment shoudl probably remain unchanged, the
> second part however, needs updating.

Yeah, looking at it closer, I think a better way to handle this is *not*
to use matching constraints at all, but simply to do an rtx_equal_p test
inside the output template.

> Is there some reason why you took out the ZERO_EXTRACT cost from mn10300_rtx_costs?

btst is no longer represented with a ZERO_EXTRACT, so that code is dead.

> You eliminated the negsi2 expander, was that on purpose? Presumably
> it's handled generically these days? (if not, it should)?

Yes, generic code will generate "op0 = 0 - op1".


r~
Jeff Law Dec. 1, 2010, 3:21 p.m. UTC | #3
On 11/30/10 14:29, Richard Henderson wrote:
>
>> You need to update the comment before the cmpsi pattern.  I think the
>> first hunk of the comment shoudl probably remain unchanged, the
>> second part however, needs updating.
> Yeah, looking at it closer, I think a better way to handle this is *not*
> to use matching constraints at all, but simply to do an rtx_equal_p test
> inside the output template.
Agreed.  No clue why that was originally done with a constraint.

Jeff
Nick Clifton Dec. 4, 2010, 10:05 a.m. UTC | #4
Hi Richard.

> This is the backend patch that makes use of the -fcompare-elim pass.

Wow - fantastic - thanks very much for doing this.

Cheers
   Nick
diff mbox

Patch

diff --git a/gcc/config/mn10300/mn10300-modes.def b/gcc/config/mn10300/mn10300-modes.def
index 8bcffcd..a7a5aa4 100644
--- a/gcc/config/mn10300/mn10300-modes.def
+++ b/gcc/config/mn10300/mn10300-modes.def
@@ -19,4 +19,5 @@ 
    the Free Software Foundation, , Inc., 51 Franklin Street - Fifth
    Floor, Boston, MA 02110-1301, USA.  */
 
+CC_MODE (CCNZ);
 CC_MODE (CC_FLOAT);
diff --git a/gcc/config/mn10300/mn10300-protos.h b/gcc/config/mn10300/mn10300-protos.h
index ebf915e..1e286e3 100644
--- a/gcc/config/mn10300/mn10300-protos.h
+++ b/gcc/config/mn10300/mn10300-protos.h
@@ -33,21 +33,23 @@  extern bool  mn10300_hard_regno_mode_ok (unsigned int, Mmode);
 extern bool  mn10300_legitimate_constant_p (rtx);
 extern bool  mn10300_modes_tieable (Mmode, Mmode);
 extern Cstar mn10300_output_cmp (rtx, rtx);
+extern Cstar mn10300_output_add (rtx[3], bool);
 extern void  mn10300_print_operand (FILE *, rtx, int);
 extern void  mn10300_print_operand_address (FILE *, rtx);
 extern void  mn10300_print_reg_list (FILE *, int);
 extern Rclas mn10300_secondary_reload_class (Rclas, Mmode, rtx);
-extern Mmode mn10300_select_cc_mode (rtx);
+extern Mmode mn10300_select_cc_mode (enum rtx_code, rtx, rtx);
 extern int   mn10300_store_multiple_operation (rtx, Mmode);
 extern int   mn10300_symbolic_operand (rtx, Mmode);
 extern bool  mn10300_wide_const_load_uses_clr (rtx operands[2]);
+extern bool  mn10300_set_or_clobber_flags_parallel (rtx, Mmode);
+extern void  mn10300_split_cbranch (Mmode, rtx, rtx);
 #endif /* RTX_CODE */
 
 extern int   mn10300_can_use_return_insn (void);
 extern void  mn10300_expand_prologue (void);
 extern void  mn10300_expand_epilogue (void);
 extern int   mn10300_initial_offset (int, int);
-extern int   mn10300_mask_ok_for_mem_btst (int, int);
 
 #undef Mmode
 #undef Cstar
diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index 71ecff2..4d7abe4 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -131,7 +131,11 @@  mn10300_option_override (void)
       flag_schedule_insns = 0;
       flag_schedule_insns_after_reload = 0;
     }
-  
+
+  /* Enable comparison elimination, unless explicitly disabled.  */
+  if (optimize && !global_options_set.x_flag_compare_elim_after_reload)
+    flag_compare_elim_after_reload = 1;
+
   if (mn10300_tune_string)
     {
       if (strcasecmp (mn10300_tune_string, "mn10300") == 0)
@@ -164,64 +168,15 @@  mn10300_file_start (void)
 void
 mn10300_print_operand (FILE *file, rtx x, int code)
 {
+  enum rtx_code cmp;
+  enum machine_mode mode;
+
   switch (code)
     {
       case 'b':
-      case 'B':
-	if (GET_MODE (XEXP (x, 0)) == CC_FLOATmode)
-	  {
-	    switch (code == 'b' ? GET_CODE (x)
-		    : reverse_condition_maybe_unordered (GET_CODE (x)))
-	      {
-	      case NE:
-		fprintf (file, "ne");
-		break;
-	      case EQ:
-		fprintf (file, "eq");
-		break;
-	      case GE:
-		fprintf (file, "ge");
-		break;
-	      case GT:
-		fprintf (file, "gt");
-		break;
-	      case LE:
-		fprintf (file, "le");
-		break;
-	      case LT:
-		fprintf (file, "lt");
-		break;
-	      case ORDERED:
-		fprintf (file, "lge");
-		break;
-	      case UNORDERED:
-		fprintf (file, "uo");
-		break;
-	      case LTGT:
-		fprintf (file, "lg");
-		break;
-	      case UNEQ:
-		fprintf (file, "ue");
-		break;
-	      case UNGE:
-		fprintf (file, "uge");
-		break;
-	      case UNGT:
-		fprintf (file, "ug");
-		break;
-	      case UNLE:
-		fprintf (file, "ule");
-		break;
-	      case UNLT:
-		fprintf (file, "ul");
-		break;
-	      default:
-		gcc_unreachable ();
-	      }
-	    break;
-	  }
-	/* These are normal and reversed branches.  */
-	switch (code == 'b' ? GET_CODE (x) : reverse_condition (GET_CODE (x)))
+        cmp = GET_CODE (x);
+	mode = GET_MODE (XEXP (x, 0));
+	switch (cmp)
 	  {
 	  case NE:
 	    fprintf (file, "ne");
@@ -230,33 +185,72 @@  mn10300_print_operand (FILE *file, rtx x, int code)
 	    fprintf (file, "eq");
 	    break;
 	  case GE:
-	    fprintf (file, "ge");
+	    fprintf (file, mode == CCNZmode ? "nc" : "ge");
 	    break;
 	  case GT:
+	    gcc_checking_assert (mode == CCmode || mode == CC_FLOATmode);
 	    fprintf (file, "gt");
 	    break;
 	  case LE:
+	    gcc_checking_assert (mode == CCmode || mode == CC_FLOATmode);
 	    fprintf (file, "le");
 	    break;
 	  case LT:
-	    fprintf (file, "lt");
+	    fprintf (file, mode == CCNZmode ? "ns" : "lt");
 	    break;
 	  case GEU:
+	    gcc_checking_assert (mode == CCmode);
 	    fprintf (file, "cc");
 	    break;
 	  case GTU:
+	    gcc_checking_assert (mode == CCmode);
 	    fprintf (file, "hi");
 	    break;
 	  case LEU:
+	    gcc_checking_assert (mode == CCmode);
 	    fprintf (file, "ls");
 	    break;
 	  case LTU:
+	    gcc_checking_assert (mode == CCmode);
 	    fprintf (file, "cs");
 	    break;
+	  case ORDERED:
+	    gcc_checking_assert (mode == CC_FLOATmode);
+	    fprintf (file, "lge");
+	    break;
+	  case UNORDERED:
+	    gcc_checking_assert (mode == CC_FLOATmode);
+	    fprintf (file, "uo");
+	    break;
+	  case LTGT:
+	    gcc_checking_assert (mode == CC_FLOATmode);
+	    fprintf (file, "lg");
+	    break;
+	  case UNEQ:
+	    gcc_checking_assert (mode == CC_FLOATmode);
+	    fprintf (file, "ue");
+	    break;
+	  case UNGE:
+	    gcc_checking_assert (mode == CC_FLOATmode);
+	    fprintf (file, "uge");
+	    break;
+	  case UNGT:
+	    gcc_checking_assert (mode == CC_FLOATmode);
+	    fprintf (file, "ug");
+	    break;
+	  case UNLE:
+	    gcc_checking_assert (mode == CC_FLOATmode);
+	    fprintf (file, "ule");
+	    break;
+	  case UNLT:
+	    gcc_checking_assert (mode == CC_FLOATmode);
+	    fprintf (file, "ul");
+	    break;
 	  default:
 	    gcc_unreachable ();
 	  }
 	break;
+
       case 'C':
 	/* This is used for the operand to a call instruction;
 	   if it's a REG, enclose it in parens, else output
@@ -1767,25 +1761,85 @@  mn10300_output_cmp (rtx operand, rtx insn)
   return "cmp 0,%0";
 }
 
-/* Similarly, but when using a zero_extract pattern for a btst where
-   the source operand might end up in memory.  */
-int
-mn10300_mask_ok_for_mem_btst (int len, int bit)
+/* Output an addition instruction.  */
+
+const char *
+mn10300_output_add (rtx operands[3], bool need_flags)
 {
-  unsigned int mask = 0;
+  rtx dest, src1, src2;
+  unsigned int dest_regnum, src1_regnum, src2_regnum;
+  enum reg_class src1_class, src2_class, dest_class;
+
+  dest = operands[0];
+  src1 = operands[1];
+  src2 = operands[2];
+
+  dest_regnum = true_regnum (dest);
+  src1_regnum = true_regnum (src1);
+
+  dest_class = REGNO_REG_CLASS (dest_regnum);
+  src1_class = REGNO_REG_CLASS (src1_regnum);
 
-  while (len > 0)
+  if (GET_CODE (src2) == CONST_INT)
     {
-      mask |= (1 << bit);
-      bit++;
-      len--;
+      gcc_assert (dest_regnum == src1_regnum);
+
+      if (src2 == const1_rtx && !need_flags)
+	return "inc %0";
+      if (INTVAL (src2) == 4 && !need_flags && dest_class != DATA_REGS)
+        return "inc4 %0";
+
+      gcc_assert (!need_flags || dest_class != SP_REGS);
+      return "add %2,%0";
+    }
+
+  src2_regnum = true_regnum (src2);
+  src2_class = REGNO_REG_CLASS (src2_regnum);
+      
+  if (dest_regnum == src1_regnum)
+    return "add %2,%0";
+  if (dest_regnum == src2_regnum)
+    return "add %1,%0";
+
+  /* Catch cases where no extended register was used.  */
+  if (src1_class != EXTENDED_REGS
+      && src2_class != EXTENDED_REGS
+      && dest_class != EXTENDED_REGS)
+    {
+      /* We have to copy one of the sources into the destination, then
+         add the other source to the destination.
+
+         Carefully select which source to copy to the destination; a
+         naive implementation will waste a byte when the source classes
+         are different and the destination is an address register.
+         Selecting the lowest cost register copy will optimize this
+         sequence.  */
+      if (src1_class == dest_class)
+        return "mov %1,%0\n\tadd %2,%0";
+      else
+	return "mov %2,%0\n\tadd %1,%0";
     }
 
-  /* MASK must bit into an 8bit value.  */
-  return (((mask & 0xff) == mask)
-	  || ((mask & 0xff00) == mask)
-	  || ((mask & 0xff0000) == mask)
-	  || ((mask & 0xff000000) == mask));
+  /* At least one register is an extended register.  */
+
+  /* The three operand add instruction on the am33 is a win iff the
+     output register is an extended register, or if both source
+     registers are extended registers.  */
+  if (dest_class == EXTENDED_REGS || src1_class == src2_class)
+    return "add %2,%1,%0";
+
+  /* It is better to copy one of the sources to the destination, then
+     perform a 2 address add.  The destination in this case must be
+     an address or data register and one of the sources must be an
+     extended register and the remaining source must not be an extended
+     register.
+
+     The best code for this case is to copy the extended reg to the
+     destination, then emit a two address add.  */
+  if (src1_class == EXTENDED_REGS)
+    return "mov %1,%0\n\tadd %2,%0";
+  else
+    return "mov %2,%0\n\tadd %1,%0";
 }
 
 /* Return 1 if X contains a symbolic expression.  We know these
@@ -2164,12 +2218,6 @@  mn10300_rtx_costs (rtx x, int code, int outer_code, int *total,
       *total = 8;
       return true;
 
-    case ZERO_EXTRACT:
-      /* This is cheap, we can use btst.  */
-      if (outer_code == COMPARE)
-	*total = 0;
-      return false;
-
    /* ??? This probably needs more work.  */
     case MOD:
     case DIV:
@@ -2389,9 +2437,33 @@  mn10300_modes_tieable (enum machine_mode mode1, enum machine_mode mode2)
 }
 
 enum machine_mode
-mn10300_select_cc_mode (rtx x)
+mn10300_select_cc_mode (enum rtx_code code, rtx x, rtx y ATTRIBUTE_UNUSED)
 {
-  return (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) ? CC_FLOATmode : CCmode;
+  if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
+    return CC_FLOATmode;
+
+  /* When combining with PLUS or MINUS, we always generate all of the flags.
+     Using CCmode allows LT,GE to avoid the longer "bn[cs]" insns.  */
+  switch (GET_CODE (x))
+    {
+    case PLUS:
+    case MINUS:
+      return CCmode;
+    default:
+      break;
+    }
+
+  switch (code)
+    {
+    case EQ:	/* Z */
+    case NE:	/* ~Z */
+    case LT:	/* N */
+    case GE:	/* ~N */
+      return CCNZmode;
+      break;
+    default:
+      return CCmode;
+    }
 }
 
 static inline bool
@@ -2510,6 +2582,77 @@  mn10300_conditional_register_usage (void)
     fixed_regs[PIC_OFFSET_TABLE_REGNUM] =
     call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
 }
+
+
+/* A helper function for splitting cbranch patterns after reload.  */
+
+void
+mn10300_split_cbranch (enum machine_mode cmp_mode, rtx cmp_op, rtx label_ref)
+{
+  rtx flags, x;
+
+  flags = gen_rtx_REG (cmp_mode, CC_REG);
+  x = gen_rtx_COMPARE (cmp_mode, XEXP (cmp_op, 0), XEXP (cmp_op, 1));
+  x = gen_rtx_SET (VOIDmode, flags, x);
+  emit_insn (x);
+
+  x = gen_rtx_fmt_ee (GET_CODE (cmp_op), VOIDmode, flags, const0_rtx);
+  x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, label_ref, pc_rtx);
+  x = gen_rtx_SET (VOIDmode, pc_rtx, x);
+  emit_jump_insn (x);
+}
+
+/* A helper function for matching parallels that either set
+   or clobber the flags.  */
+
+bool
+mn10300_set_or_clobber_flags_parallel (rtx par, enum machine_mode cc_mode)
+{
+  rtx op1, flags;
+
+  if (XVECLEN (par, 0) != 2)
+    return false;
+
+  op1 = XVECEXP (par, 0, 1);
+  if (GET_CODE (op1) == CLOBBER)
+    flags = XEXP (op1, 0);
+  else if (GET_CODE (op1) == SET)
+    {
+      enum machine_mode flags_mode;
+      rtx cmp;
+
+      cmp = SET_SRC (op1);
+      if (GET_CODE (cmp) != COMPARE)
+	return false;
+      if (!rtx_equal_p (XEXP (cmp, 0), SET_SRC (XVECEXP (par, 0, 0))))
+	return false;
+      if (XEXP (cmp, 1) != const0_rtx)
+	return false;
+
+      flags = SET_DEST (op1);
+      flags_mode = GET_MODE (flags);
+
+      if (GET_MODE (cmp) != flags_mode)
+	return false;
+
+      /* Ensure that the mode of FLAGS is compatible with CC_MODE.  */
+      switch (flags_mode)
+	{
+	case CCmode:
+	  /* CCmode sets all flags.  */
+	  break;
+        case CCNZmode:
+	  /* CCNZmode only sets N and Z.  */
+	  if (cc_mode != CCNZmode)
+	    return false;
+	  break;
+	default:
+	  return false;
+	}
+    }
+
+  return REG_P (flags) && REGNO (flags) == CC_REG;
+}
 
 /* Initialize the GCC target structure.  */
 
diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h
index 6db0ed0..1cba413 100644
--- a/gcc/config/mn10300/mn10300.h
+++ b/gcc/config/mn10300/mn10300.h
@@ -579,7 +579,7 @@  struct cum_arg
 /* Non-global SYMBOL_REFs have SYMBOL_REF_FLAG enabled.  */
 #define MN10300_GLOBAL_P(X) (! SYMBOL_REF_FLAG (X))
 
-#define SELECT_CC_MODE(OP, X, Y)  mn10300_select_cc_mode (X)
+#define SELECT_CC_MODE(OP, X, Y)  mn10300_select_cc_mode (OP, X, Y)
 #define REVERSIBLE_CC_MODE(MODE)  0
 
 #define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2) \
diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index 3fad021..c39563c 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -1061,138 +1061,52 @@ 
   [(parallel [(set (match_operand:SI          0 "register_operand")
 		   (plus:SI (match_operand:SI 1 "register_operand")
 			    (match_operand:SI 2 "nonmemory_operand")))
-	      (clobber (reg:CC CC_REG))
-	     ])
-  ]
+	      (clobber (reg:CC CC_REG))])]
   ""
   "")
 
 (define_insn "*am33_addsi3"
-  [(set (match_operand:SI          0 "register_operand" "=dx,a,x,a,dax,!*y,!dax")
-	(plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,dax")
-		 (match_operand:SI 2 "nonmemory_operand" "J,J,L,L,daxi,i,dax")))
-   (clobber (reg:CC CC_REG))
-  ]
+  [(set (match_operand:SI          0 "register_operand"  "=dax,!*y,!dax")
+	(plus:SI (match_operand:SI 1 "register_operand"  "%  0,  0, dax")
+		 (match_operand:SI 2 "nonmemory_operand" "daxi,  i, dax")))
+   (clobber (reg:CC CC_REG))]
   "TARGET_AM33"
-  "*
-{
-  switch (which_alternative)
-    {
-    case 0:
-    case 1:
-      return \"inc %0\";
-    case 2:
-    case 3:
-      return \"inc4 %0\";
-    case 4:
-    case 5:
-      return \"add %2,%0\";
-    case 6:
-      {
-	enum reg_class src1_class, src2_class, dst_class;
-
-	src1_class = REGNO_REG_CLASS (true_regnum (operands[1]));
-	src2_class = REGNO_REG_CLASS (true_regnum (operands[2]));
-	dst_class = REGNO_REG_CLASS (true_regnum (operands[0]));
-
-	/* I'm not sure if this can happen or not.  Might as well be prepared
-	  and generate the best possible code if it does happen.  */
-	if (true_regnum (operands[0]) == true_regnum (operands[1]))
-	  return \"add %2,%0\";
-	if (true_regnum (operands[0]) == true_regnum (operands[2]))
-	  return \"add %1,%0\";
-
-	/* Catch cases where no extended register was used.  These should be
-	   handled just like the mn10300.  */
-	if (src1_class != EXTENDED_REGS
-	    && src2_class != EXTENDED_REGS
-	    && dst_class != EXTENDED_REGS)
-	  {
-	    /* We have to copy one of the sources into the destination, then
-	       add the other source to the destination.
-
-	       Carefully select which source to copy to the destination; a
-	       naive implementation will waste a byte when the source classes
-	       are different and the destination is an address register.
-	       Selecting the lowest cost register copy will optimize this
-	       sequence.  */
-	    if (REGNO_REG_CLASS (true_regnum (operands[1]))
-		== REGNO_REG_CLASS (true_regnum (operands[0])))
-	      return \"mov %1,%0\;add %2,%0\";
-	    return \"mov %2,%0\;add %1,%0\";
-	  }
-
-	/* At least one register is an extended register.  */
-
-	/* The three operand add instruction on the am33 is a win iff the
-	   output register is an extended register, or if both source
-	   registers are extended registers.  */
-	if (dst_class == EXTENDED_REGS
-	    || src1_class == src2_class)
-	  return \"add %2,%1,%0\";
-
-      /* It is better to copy one of the sources to the destination, then
-	 perform a 2 address add.  The destination in this case must be
-	 an address or data register and one of the sources must be an
-	 extended register and the remaining source must not be an extended
-	 register.
-
-	 The best code for this case is to copy the extended reg to the
-	 destination, then emit a two address add.  */
-      if (src1_class == EXTENDED_REGS)
-	return \"mov %1,%0\;add %2,%0\";
-      return \"mov %2,%0\;add %1,%0\";
-      }
-    default:
-      gcc_unreachable ();
-    }
-  }"
-  [(set_attr "timings" "11,11,11,11,11,11,22")]
+  { return mn10300_output_add (operands, false); }
+  [(set_attr "timings" "11,11,22")]
 )
 
 (define_insn "*mn10300_addsi3"
-  [(set (match_operand:SI          0 "register_operand" "=dx,a,a,dax,!*y,!dax")
-	(plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,dax")
-		 (match_operand:SI 2 "nonmemory_operand" "J,J,L,daxi,i,dax")))
-   (clobber (reg:CC CC_REG))
-  ]
+  [(set (match_operand:SI          0 "register_operand"  "=da,!*y,!da")
+	(plus:SI (match_operand:SI 1 "register_operand"  "% 0,  0, da")
+		 (match_operand:SI 2 "nonmemory_operand" "dai,  i, da")))
+   (clobber (reg:CC CC_REG))]
   ""
-  "*
-{
-  switch (which_alternative)
-    {
-    case 0:
-    case 1:
-      return \"inc %0\";
-    case 2:
-      return \"inc4 %0\";
-    case 3:
-    case 4:
-      return \"add %2,%0\";
-    case 5:
-      /* I'm not sure if this can happen or not.  Might as well be prepared
-	 and generate the best possible code if it does happen.  */
-      if (true_regnum (operands[0]) == true_regnum (operands[1]))
-	return \"add %2,%0\";
-      if (true_regnum (operands[0]) == true_regnum (operands[2]))
-	return \"add %1,%0\";
-
-      /* We have to copy one of the sources into the destination, then add
-	 the other source to the destination.
-
-	 Carefully select which source to copy to the destination; a naive
-	 implementation will waste a byte when the source classes are different
-	 and the destination is an address register.  Selecting the lowest
-	 cost register copy will optimize this sequence.  */
-      if (REGNO_REG_CLASS (true_regnum (operands[1]))
-	  == REGNO_REG_CLASS (true_regnum (operands[0])))
-	return \"mov %1,%0\;add %2,%0\";
-      return \"mov %2,%0\;add %1,%0\";
-    default:
-      gcc_unreachable ();
-    }
-}"
-  [(set_attr "timings" "11,11,11,11,11,22")]
+  { return mn10300_output_add (operands, false); }
+  [(set_attr "timings" "11,11,22")]
+)
+
+;; Note that ADD IMM,SP does not set the flags, so omit that here.
+;; Also note that one form of CCmode_set_parallel uses a clobber,
+;; but that form is shadowed by the patterns above.
+
+(define_insn "*am33_addsi3_flags"
+  [(match_parallel 3 "CCmode_set_parallel"
+     [(set (match_operand:SI          0 "register_operand" "= dax,!dax")
+	   (plus:SI (match_operand:SI 1 "register_operand" "%   0, dax")
+		    (match_operand:SI 2 "nonmemory_operand" "daxi, dax")))])]
+  "TARGET_AM33"
+  { return mn10300_output_add (operands, true); }
+  [(set_attr "timings" "11,22")]
+)
+
+(define_insn "*mn10300_addsi3_flags"
+  [(match_parallel 3 "CCmode_set_parallel"
+     [(set (match_operand:SI          0 "register_operand"  "=da,!da")
+	   (plus:SI (match_operand:SI 1 "register_operand"  "% 0, da")
+		    (match_operand:SI 2 "nonmemory_operand" "dai, da")))])]
+  ""
+  { return mn10300_output_add (operands, true); }
+  [(set_attr "timings" "11,22")]
 )
 
 ;; ----------------------------------------------------------------------
@@ -1203,71 +1117,53 @@ 
   [(parallel [(set (match_operand:SI           0 "register_operand")
 		   (minus:SI (match_operand:SI 1 "register_operand")
 			     (match_operand:SI 2 "nonmemory_operand")))
-	      (clobber (reg:CC CC_REG))
-	     ])
-  ]
+	      (clobber (reg:CC CC_REG))])]
   ""
-  "")
+  ""
+)
 
 (define_insn "*am33_subsi3"
-  [(set (match_operand:SI           0 "register_operand" "=dax,!dax")
-	(minus:SI (match_operand:SI 1 "register_operand" "0,dax")
-		  (match_operand:SI 2 "nonmemory_operand" "daxi,dax")))
-   (clobber (reg:CC CC_REG))
-  ]
+  [(match_parallel 3 "CCmode_set_parallel"
+     [(set (match_operand:SI           0 "register_operand"  "=dax,!dax")
+	   (minus:SI (match_operand:SI 1 "register_operand"  "   0, dax")
+		     (match_operand:SI 2 "nonmemory_operand" "daxi, dax")))])]
   "TARGET_AM33"
-  "*
-  {
-    if (true_regnum (operands[0]) == true_regnum (operands[1]))
-      return \"sub %2,%0\";
-    else
-      {
-        enum reg_class src1_class, src2_class, dst_class;
-
-        src1_class = REGNO_REG_CLASS (true_regnum (operands[1]));
-        src2_class = REGNO_REG_CLASS (true_regnum (operands[2]));
-        dst_class = REGNO_REG_CLASS (true_regnum (operands[0]));
-
-        /* If no extended registers are used, then the best way to handle
-	   this is to copy the first source operand into the destination
-	   and emit a two address subtraction.  */
-        if (src1_class != EXTENDED_REGS
-	    && src2_class != EXTENDED_REGS
-	    && dst_class != EXTENDED_REGS
-	    && true_regnum (operands[0]) != true_regnum (operands[2]))
-	  return \"mov %1,%0\;sub %2,%0\";
-        return \"sub %2,%1,%0\";
-      }
-  }"
+{
+  if (true_regnum (operands[0]) == true_regnum (operands[1]))
+    return "sub %2,%0";
+  else
+    {
+      enum reg_class src1_class, src2_class, dst_class;
+
+      src1_class = REGNO_REG_CLASS (true_regnum (operands[1]));
+      src2_class = REGNO_REG_CLASS (true_regnum (operands[2]));
+      dst_class = REGNO_REG_CLASS (true_regnum (operands[0]));
+
+      /* If no extended registers are used, then the best way to handle
+	 this is to copy the first source operand into the destination
+	 and emit a two address subtraction.  */
+      if (src1_class != EXTENDED_REGS
+	  && src2_class != EXTENDED_REGS
+	  && dst_class != EXTENDED_REGS
+	  && true_regnum (operands[0]) != true_regnum (operands[2]))
+	return "mov %1,%0\;sub %2,%0";
+      return "sub %2,%1,%0";
+    }
+}
   [(set_attr "timings" "11,22")]
 )
-
-(define_insn "*mn10300_subsi3"
-  [(set (match_operand:SI           0 "register_operand" "=dax")
-	(minus:SI (match_operand:SI 1 "register_operand" "0")
-		  (match_operand:SI 2 "nonmemory_operand" "daxi")))
-   (clobber (reg:CC CC_REG))
-  ]
+ 
+(define_insn "*subsi3"
+  [(match_parallel 3 "CCmode_set_parallel"
+     [(set (match_operand:SI           0 "register_operand"  "=dax")
+	   (minus:SI (match_operand:SI 1 "register_operand"  "0")
+		     (match_operand:SI 2 "nonmemory_operand" "daxi")))])]
   ""
   "sub %2,%0"
   [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
 				       (const_int 11) (const_int 22)))]
 )
 
-(define_expand "negsi2"
-  [(set (match_operand:SI         0 "register_operand")
-        (neg:SI (match_operand:SI 1 "register_operand")))]
-  ""
-  "
-{
-  rtx target = gen_reg_rtx (SImode);
-
-  emit_move_insn (target, const0_rtx);
-  emit_insn (gen_subsi3 (target, target, operands[1]));
-  emit_move_insn (operands[0], target);
-  DONE;
-}")
-
 ;; ----------------------------------------------------------------------
 ;; MULTIPLY INSTRUCTIONS
 ;; ----------------------------------------------------------------------
@@ -1422,80 +1318,62 @@ 
   [(parallel [(set (match_operand:SI         0 "register_operand")
 		   (and:SI (match_operand:SI 1 "register_operand")
 			   (match_operand:SI 2 "nonmemory_operand")))
-	      (clobber (reg:CC CC_REG))
-	     ])
-  ]
+	      (clobber (reg:CC CC_REG))])]
   ""
   "")
 
-(define_insn "*am33_andsi3"
-  [(set (match_operand:SI         0 "register_operand" "=dx,dx,!dax")
-	(and:SI (match_operand:SI 1 "register_operand" "%0,0,dax")
-		(match_operand:SI 2 "nonmemory_operand" "N,dxi,dax")))
-   (clobber (reg:CC CC_REG))
-  ]
-  "TARGET_AM33"
-  {
-    if (CONST_INT_P (operands[2]))
-      switch (INTVAL (operands[2]))
-        {
-        case 0xff:       return "extbu %0";
-        case 0xffff:     return "exthu %0";
-        case 0x7fffffff: return "add  %0, %0; lsr 1, %0";
-        case 0x3fffffff: return "asl2 %0; lsr 2, %0";
-        case 0x1fffffff: return "add  %0, %0; asl2 %0; lsr 3, %0";
-        case 0x0fffffff: return "asl2 %0; asl2 %0; lsr 4, %0";
-        case 0xfffffffe: return "lsr 1, %0; add  %0, %0";
-        case 0xfffffffc: return "lsr 2, %0; asl2 %0";
-        case 0xfffffff8: return "lsr 3, %0; add  %0, %0; asl2 %0";
-        case 0xfffffff0: return "lsr 4, %0; asl2 %0; asl2 %0";
-        }
-      
-    if (REG_P (operands[2]) && REG_P (operands[1])
-        && true_regnum (operands[0]) != true_regnum (operands[1])
-        && true_regnum (operands[0]) != true_regnum (operands[2])
-        && REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
-        && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
-        && REGNO_REG_CLASS (true_regnum (operands[2])) == DATA_REGS)
-      return "mov %1, %0; and %2, %0";
-    if (REG_P (operands[2]) && REG_P (operands[1])
-        && true_regnum (operands[0]) != true_regnum (operands[1])
-        && true_regnum (operands[0]) != true_regnum (operands[2]))
-      return "and %1, %2, %0";
-    if (REG_P (operands[2]) && REG_P (operands[0])
-        && true_regnum (operands[2]) == true_regnum (operands[0]))
-      return "and %1, %0";
+(define_insn "*andsi3"
+  [(set (match_operand:SI         0 "register_operand"  "=dx")
+	(and:SI (match_operand:SI 1 "register_operand"  "%0")
+		(match_operand:SI 2 "nonmemory_operand" "dxi")))
+   (clobber (reg:CC CC_REG))]
+  ""
+{
+  if (CONST_INT_P (operands[2]))
+    switch (INTVAL (operands[2]))
+      {
+      case 0xff:       return "extbu %0";
+      case 0xffff:     return "exthu %0";
+      case 0x7fffffff: return "add  %0, %0; lsr 1, %0";
+      case 0x3fffffff: return "asl2 %0; lsr 2, %0";
+      case 0x1fffffff: return "add  %0, %0; asl2 %0; lsr 3, %0";
+      case 0x0fffffff: return "asl2 %0; asl2 %0; lsr 4, %0";
+      case 0xfffffffe: return "lsr 1, %0; add  %0, %0";
+      case 0xfffffffc: return "lsr 2, %0; asl2 %0";
+      case 0xfffffff8: return "lsr 3, %0; add  %0, %0; asl2 %0";
+      case 0xfffffff0: return "lsr 4, %0; asl2 %0; asl2 %0";
+      }
 
-    return "and %2, %0";
-  }
+  return "and %2, %0";
+}
   [(set_attr "timings" "33")]
 )
 
-(define_insn "*mn10300_andsi3"
-  [(set (match_operand:SI         0 "register_operand" "=dx,dx")
-	(and:SI (match_operand:SI 1 "register_operand" "%0,0")
-		(match_operand:SI 2 "nonmemory_operand" "N,dxi")))
-   (clobber (reg:CC CC_REG))
-  ]
+;; The EXT instructions do not set the flags.
+(define_insn "*andsi3_flags"
+  [(set (match_operand:SI         0 "register_operand"  "=dx")
+	(and:SI (match_operand:SI 1 "register_operand"  "%0")
+		(match_operand:SI 2 "nonmemory_operand" "dxi")))
+   (set (reg:CCNZ CC_REG)
+	(compare:CCNZ (and:SI (match_dup 1) (match_dup 2))
+		      (const_int 0)))]
   ""
-  {
-    if (CONST_INT_P (operands[2]))
-      switch (INTVAL (operands[2]))
-        {
-        case 0xff:       return "extbu %0";
-        case 0xffff:     return "exthu %0";
-        case 0x7fffffff: return "add  %0, %0; lsr 1, %0";
-        case 0x3fffffff: return "asl2 %0; lsr 2, %0";
-        case 0x1fffffff: return "add  %0, %0; asl2 %0; lsr 3, %0";
-        case 0x0fffffff: return "asl2 %0; asl2 %0; lsr 4, %0";
-        case 0xfffffffe: return "lsr 1, %0; add  %0, %0";
-        case 0xfffffffc: return "lsr 2, %0; asl2 %0";
-        case 0xfffffff8: return "lsr 3, %0; add  %0, %0; asl2 %0";
-        case 0xfffffff0: return "lsr 4, %0; asl2 %0; asl2 %0";
-	}
+{
+  if (CONST_INT_P (operands[2]))
+    switch (INTVAL (operands[2]))
+      {
+      case 0x7fffffff: return "add  %0, %0; lsr 1, %0";
+      case 0x3fffffff: return "asl2 %0; lsr 2, %0";
+      case 0x1fffffff: return "add  %0, %0; asl2 %0; lsr 3, %0";
+      case 0x0fffffff: return "asl2 %0; asl2 %0; lsr 4, %0";
+      case 0xfffffffe: return "lsr 1, %0; add  %0, %0";
+      case 0xfffffffc: return "lsr 2, %0; asl2 %0";
+      case 0xfffffff8: return "lsr 3, %0; add  %0, %0; asl2 %0";
+      case 0xfffffff0: return "lsr 4, %0; asl2 %0; asl2 %0";
+      }
 
-    return "and %2, %0";
-  }
+  return "and %2, %0";
+}
   [(set_attr "timings" "33")]
 )
 
@@ -1507,46 +1385,15 @@ 
   [(parallel [(set (match_operand:SI         0 "register_operand")
 		   (ior:SI (match_operand:SI 1 "register_operand")
 			   (match_operand:SI 2 "nonmemory_operand")))
-	      (clobber (reg:CC CC_REG))
-	     ])
-  ]
+	      (clobber (reg:CC CC_REG))])]
   ""
   "")
 
-(define_insn "*am33_iorsi3"
-  [(set (match_operand:SI 0 "register_operand" "=dx,!dax")
-	(ior:SI (match_operand:SI 1 "register_operand" "%0,dax")
-		(match_operand:SI 2 "nonmemory_operand" "dxi,dax")))
-   (clobber (reg:CC CC_REG))
-  ]
-  "TARGET_AM33"
-  "*
-  {
-    if (REG_P (operands[2]) && REG_P (operands[1])
-        && true_regnum (operands[0]) != true_regnum (operands[1])
-        && true_regnum (operands[0]) != true_regnum (operands[2])
-        && REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
-        && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
-        && REGNO_REG_CLASS (true_regnum (operands[2])) == DATA_REGS)
-      return \"mov %1,%0\;or %2,%0\";
-    if (REG_P (operands[2]) && REG_P (operands[1])
-        && true_regnum (operands[0]) != true_regnum (operands[1])
-        && true_regnum (operands[0]) != true_regnum (operands[2]))
-      return \"or %1,%2,%0\";
-    if (REG_P (operands[2]) && REG_P (operands[0])
-        && true_regnum (operands[2]) == true_regnum (operands[0]))
-      return \"or %1,%0\";
-    return \"or %2,%0\";
-  }"
-  [(set_attr "timings" "22")]
-)
-
-(define_insn "*mn10300_iorsi3"
-  [(set (match_operand:SI         0 "register_operand" "=dx")
-	(ior:SI (match_operand:SI 1 "register_operand" "%0")
-		(match_operand:SI 2 "nonmemory_operand" "dxi")))
-   (clobber (reg:CC CC_REG))
-  ]
+(define_insn "*iorsi3"
+  [(match_parallel 3 "CCNZmode_set_parallel"
+     [(set (match_operand:SI         0 "register_operand"  "=dx")
+	   (ior:SI (match_operand:SI 1 "register_operand"  "%0")
+		   (match_operand:SI 2 "nonmemory_operand" "dxi")))])]
   ""
   "or %2,%0"
   [(set_attr "timings" "33")]
@@ -1566,40 +1413,11 @@ 
   ""
   "")
 
-(define_insn "*am33_xorsi3"
-  [(set (match_operand:SI         0 "register_operand" "=dx,!dax")
-	(xor:SI (match_operand:SI 1 "register_operand" "%0,dax")
-		(match_operand:SI 2 "nonmemory_operand" "dxi,dax")))
-   (clobber (reg:CC CC_REG))
-  ]
-  "TARGET_AM33"
-  "*
-  {
-    if (REG_P (operands[2]) && REG_P (operands[1])
-        && true_regnum (operands[0]) != true_regnum (operands[1])
-        && true_regnum (operands[0]) != true_regnum (operands[2])
-        && REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
-        && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
-        && REGNO_REG_CLASS (true_regnum (operands[2])) == DATA_REGS)
-      return \"mov %1,%0\;xor %2,%0\";
-    if (REG_P (operands[2]) && REG_P (operands[1])
-        && true_regnum (operands[0]) != true_regnum (operands[1])
-        && true_regnum (operands[0]) != true_regnum (operands[2]))
-      return \"xor %1,%2,%0\";
-    if (REG_P (operands[2]) && REG_P (operands[0])
-        && true_regnum (operands[2]) == true_regnum (operands[0]))
-      return \"xor %1,%0\";
-    return \"xor %2,%0\";
-  }"
-  [(set_attr "timings" "22")]
-)
-
-(define_insn "*mn10300_xorsi3"
-  [(set (match_operand:SI         0 "register_operand" "=dx")
-	(xor:SI (match_operand:SI 1 "register_operand" "%0")
-		(match_operand:SI 2 "nonmemory_operand" "dxi")))
-   (clobber (reg:CC CC_REG))
-  ]
+(define_insn "*xorsi3"
+  [(match_parallel 3 "CCNZmode_set_parallel"
+     [(set (match_operand:SI         0 "register_operand" "=dx")
+	   (xor:SI (match_operand:SI 1 "register_operand" "%0")
+		   (match_operand:SI 2 "nonmemory_operand" "dxi")))])]
   ""
   "xor %2,%0"
   [(set_attr "timings" "11")]
@@ -1612,26 +1430,22 @@ 
 (define_expand "one_cmplsi2"
   [(parallel [(set (match_operand:SI         0 "register_operand")
 		   (not:SI (match_operand:SI 1 "register_operand")))
-	      (clobber (reg:CC CC_REG))
-	     ])
-  ]
+	      (clobber (reg:CC CC_REG))])]
   ""
   "")
 
 (define_insn "*am33_cmplsi2"
-  [(set (match_operand:SI         0 "register_operand" "=dx,!dax")
-	(not:SI (match_operand:SI 1 "register_operand" "0,0")))
-   (clobber (reg:CC CC_REG))
-  ]
+  [(match_parallel 2 "CCNZmode_set_parallel"
+     [(set (match_operand:SI         0 "register_operand" "=dx,!a")
+	   (not:SI (match_operand:SI 1 "register_operand" "0,0")))])]
   "TARGET_AM33"
   "not %0"
 )
 
 (define_insn "*mn10300_cmplsi2"
-  [(set (match_operand:SI         0 "register_operand" "=dx")
-	(not:SI (match_operand:SI 1 "register_operand" "0")))
-   (clobber (reg:CC CC_REG))
-  ]
+  [(match_parallel 2 "CCNZmode_set_parallel"
+     [(set (match_operand:SI         0 "register_operand" "=dx")
+	   (not:SI (match_operand:SI 1 "register_operand" "0")))])]
   ""
   "not %0"
 )
@@ -1796,118 +1610,6 @@ 
   ]
 )
 
-(define_insn "*test_int_bitfield"
-  [(set (reg:CC CC_REG)
-     (compare (zero_extract:SI (match_operand:SI 0 "register_operand" "dx")
-			       (match_operand 1 "const_int_operand" "")
-			       (match_operand 2 "const_int_operand" ""))
-	      (const_int 0)))]
-  ""
-  "*
-{
-  int len = INTVAL (operands[1]);
-  int bit = INTVAL (operands[2]);
-  int mask = 0;
-  rtx xoperands[2];
-
-  while (len > 0)
-    {
-      mask |= (1 << bit);
-      bit++;
-      len--;
-    }
-
-  xoperands[0] = operands[0];
-  xoperands[1] = GEN_INT (trunc_int_for_mode (mask, SImode));
-  output_asm_insn (\"btst %1,%0\", xoperands);
-  return \"\";
-}"
-)
-
-(define_insn "*test_byte_bitfield"
-  [(set (reg:CC CC_REG)
-     (compare (zero_extract:SI (match_operand:QI 0 "nonimmediate_operand" "R,dx")
-			       (match_operand 1 "const_int_operand" "")
-			       (match_operand 2 "const_int_operand" ""))
-	      (const_int 0)))]
-  "mn10300_mask_ok_for_mem_btst (INTVAL (operands[1]), INTVAL (operands[2]))"
-  "*
-{
-  int len = INTVAL (operands[1]);
-  int bit = INTVAL (operands[2]);
-  int mask = 0;
-  rtx xoperands[2];
-
-  while (len > 0)
-    {
-      mask |= (1 << bit);
-      bit++;
-      len--;
-    }
-
-  /* If the source operand is not a reg (i.e. it is memory), then extract the
-     bits from mask that we actually want to test.  Note that the mask will
-     never cross a byte boundary.  */
-  if (!REG_P (operands[0]))
-    {
-      if (mask & 0xff)
-	mask = mask & 0xff;
-      else if (mask & 0xff00)
-	mask = (mask >> 8) & 0xff;
-      else if (mask & 0xff0000)
-	mask = (mask >> 16) & 0xff;
-      else if (mask & 0xff000000)
-	mask = (mask >> 24) & 0xff;
-    }
-
-  xoperands[0] = operands[0];
-  xoperands[1] = GEN_INT (trunc_int_for_mode (mask, SImode));
-  if (REG_P (operands[0]))
-    output_asm_insn (\"btst %1,%0\", xoperands);
-  else
-    output_asm_insn (\"btst %U1,%A0\", xoperands);
-  return \"\";
-}"
-  [(set_attr_alternative "timings"
-			 [(if_then_else (eq_attr "cpu" "am34")
-			 		(const_int 11) (const_int 22))
-			  (if_then_else (eq_attr "cpu" "am34")
-			  		(const_int 44) (const_int 55))
-			 ])
-  ]
-)
-
-(define_insn "*bit_test"
-  [(set (reg:CC CC_REG)
-	(compare (and:SI (match_operand:SI 0 "register_operand" "dx")
-			 (match_operand:SI 1 "const_int_operand" ""))
-		 (const_int 0)))
-  ]
-  ""
-  "btst %1,%0"
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-				       (const_int 11) (const_int 22)))]
-)
-
-(define_insn "*subreg_bit_test"
-  [(set (reg:CC CC_REG)
-     (compare (and:SI
-	       (subreg:SI (match_operand:QI 0 "nonimmediate_operand" "R,dx") 0)
-	       (match_operand:SI 1 "const_8bit_operand" ""))
-	      (const_int 0)))]
-  ""
-  "@
-  btst %U1,%A0
-  btst %1,%0"
-  [(set_attr_alternative "timings"
-			 [(if_then_else (eq_attr "cpu" "am34")
-					(const_int 44) (const_int 55))
-			  (if_then_else (eq_attr "cpu" "am34")
-					(const_int 11) (const_int 22))
-			 ])
-  ]
-)
-
 
 ;; ----------------------------------------------------------------------
 ;; COMPARE AND BRANCH INSTRUCTIONS
@@ -1921,37 +1623,28 @@ 
 	      (match_operator                    0 "ordered_comparison_operator"
 			      [(match_operand:SI 1 "register_operand")
 			       (match_operand:SI 2 "nonmemory_operand")])
-              (label_ref (match_operand          3 ""))
+              (label_ref (match_operand 3 ""))
               (pc)))]
   ""
   ""
 )
 
-(define_insn_and_split "*cbranchsi4_post_reload"
+(define_insn_and_split "*cbranchsi4_cmp"
   [(set (pc)
 	(if_then_else (match_operator           3 "ordered_comparison_operator"
                        [(match_operand:SI       0 "register_operand"  "dax")
 		        (match_operand:SI       1 "nonmemory_operand" "daxi")])
-		      (label_ref (match_operand 2 "" ""))
+		      (match_operand            2 "label_ref_operand" "")
 		      (pc)))
    ]
   ""
   "#"
   "reload_completed"
   [(const_int 0)]
-  "
-  /* We construct 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_integer_conditional_branch
-                      (gen_rtx_fmt_ee (GET_CODE (operands[3]),
-				       CCmode,
-		 		       gen_rtx_REG (CCmode, CC_REG),
-				  	            const0_rtx),
-				       operands[2]));
-  "
-)
+{
+  mn10300_split_cbranch (CCmode, operands[3], operands[2]);
+  DONE;
+})
 
 ;; Ordinarily, the cmp instruction will set the Z bit of cc0 to 1 if
 ;; its operands hold equal values, but the operands of a cmp
@@ -1969,18 +1662,18 @@ 
 ;; possibly satisfied, so just mark the alternative with a `!', so
 ;; that it is not considered by reload.
 
-(define_insn "cmpsi"
-  [(set (reg:CC CC_REG)
-	(compare (match_operand:SI 0 "register_operand" "!*d*a*x,dax,dax")
-		 (match_operand:SI 1 "nonmemory_operand" "*0,I,daxi")))]
-  ""
-  {
-    if (which_alternative == 0)
-      return \"btst 0,d0\";
-    if (which_alternative == 1)
-      return mn10300_output_cmp (operands[0], insn);
-    return \"cmp %1,%0\";
-  }
+(define_insn "*cmpsi"
+  [(set (reg CC_REG)
+	(compare (match_operand:SI 0 "register_operand"  "dax,dax,dax")
+		 (match_operand:SI 1 "nonmemory_operand" "  0,  I,daxi")))]
+  "reload_completed"
+{
+  if (which_alternative == 0)
+    return "btst 0,d0";
+  if (which_alternative == 1)
+    return mn10300_output_cmp (operands[0], insn);
+  return "cmp %1,%0";
+}
   [(set_attr_alternative "timings"
 			 [(const_int 11)
 			  (if_then_else (eq_attr "cpu" "am34")
@@ -1990,71 +1683,91 @@ 
   ]
 )
 
-(define_insn "integer_conditional_branch"
+(define_insn "*integer_conditional_branch"
   [(set (pc)
 	(if_then_else (match_operator 0 "comparison_operator"
-				      [(reg:CC CC_REG) (const_int 0)])
+			[(match_operand 2 "int_mode_flags" "")
+			 (const_int 0)])
 		      (label_ref (match_operand 1 "" ""))
 		      (pc)))]
-  ""
+  "reload_completed"
   "b%b0 %1"
 )
 
+(define_insn_and_split "*cbranchsi4_btst"
+  [(set (pc)
+	(if_then_else
+	  (match_operator 3 "CCNZ_comparison_operator"
+	    [(and:SI (match_operand:SI 0 "register_operand" "dx")
+		     (match_operand:SI 1 "const_int_operand" ""))
+	     (const_int 0)])
+	  (match_operand 2 "label_ref_operand" "")
+	  (pc)))]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  mn10300_split_cbranch (CCNZmode, operands[3], operands[2]);
+  DONE;
+})
+
+(define_insn "*btstsi"
+  [(set (reg:CCNZ CC_REG)
+	(compare:CCNZ
+	  (and:SI (match_operand:SI 0 "register_operand" "dx")
+		  (match_operand:SI 1 "const_int_operand" ""))
+	  (const_int 0)))]
+  "reload_completed"
+  "btst %1,%0"
+)
+
 (define_expand "cbranchsf4"
   [(set (pc)
       (if_then_else
             (match_operator                    0 "ordered_comparison_operator"
 			    [(match_operand:SF 1 "register_operand")
 			     (match_operand:SF 2 "nonmemory_operand")])
-	    (label_ref (match_operand          3 ""))
+	    (label_ref (match_operand 3 ""))
 	    (pc)))]
   "TARGET_AM33_2"
   ""
 )
 
-(define_insn_and_split "*cbranchsf4_post_reload"
+(define_insn_and_split "*cbranchsf4_cmp"
   [(set (pc)
 	(if_then_else (match_operator            3 "ordered_comparison_operator"
 			[(match_operand:SF       0 "register_operand"  "f")
 			 (match_operand:SF       1 "nonmemory_operand" "fF")])
-		      (label_ref (match_operand  2 "" ""))
+		      (match_operand             2 "label_ref_operand" "")
 		      (pc)))
    ]
   "TARGET_AM33_2"
   "#"
   "&& reload_completed"
   [(const_int 0)]
-  "
-  /* We construct the split by hand as otherwise the JUMP_LABEL
-     attribute is not set correctly on the jump insn.  */
-  emit_insn (gen_am33_cmpsf (operands[0], operands[1]));
-  
-  emit_jump_insn (gen_float_conditional_branch
-                     (gen_rtx_fmt_ee (GET_CODE (operands[3]),
-				      CC_FLOATmode,
- 		 	       	      gen_rtx_REG (CC_FLOATmode, CC_REG),
-				      const0_rtx),
-				      operands[2]));
-  "
-)
+{
+  mn10300_split_cbranch (CC_FLOATmode, operands[3], operands[2]);
+  DONE;
+})
 
-(define_insn "am33_cmpsf"
+(define_insn "*am33_cmpsf"
   [(set (reg:CC_FLOAT CC_REG)
 	(compare:CC_FLOAT (match_operand:SF 0 "register_operand"  "f")
 			  (match_operand:SF 1 "nonmemory_operand" "fF")))]
-  "TARGET_AM33_2"
+  "TARGET_AM33_2 && reload_completed"
   "fcmp %1, %0"
   [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
 				       (const_int 17) (const_int 25)))]
 )
 
-(define_insn "float_conditional_branch"
+(define_insn "*float_conditional_branch"
   [(set (pc)
 	(if_then_else (match_operator 0 "comparison_operator"
 				      [(reg:CC_FLOAT CC_REG) (const_int 0)])
 		      (label_ref (match_operand 1 "" ""))
 		      (pc)))]
-  "TARGET_AM33_2"
+  "TARGET_AM33_2 && reload_completed"
   "fb%b0 %1"
   [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
 				       (const_int 44) (const_int 33)))]
diff --git a/gcc/config/mn10300/predicates.md b/gcc/config/mn10300/predicates.md
index 0f76a49..d3f7df8 100644
--- a/gcc/config/mn10300/predicates.md
+++ b/gcc/config/mn10300/predicates.md
@@ -54,3 +54,31 @@ 
   return XEXP (op, 0) == stack_pointer_rtx
       || XEXP (op, 1) == stack_pointer_rtx;
 })
+
+(define_predicate "label_ref_operand"
+  (match_code "label_ref"))
+
+(define_special_predicate "int_mode_flags"
+  (match_code "reg")
+{
+  if (REGNO (op) != CC_REG)
+    return false;
+  if (GET_MODE (op) == CC_FLOATmode)
+    return false;
+  return GET_MODE_CLASS (GET_MODE (op)) == MODE_CC;
+})
+
+(define_predicate "CCmode_set_parallel"
+  (match_code "parallel")
+{
+  return mn10300_set_or_clobber_flags_parallel (op, CCmode);
+})
+
+(define_predicate "CCNZmode_set_parallel"
+  (match_code "parallel")
+{
+  return mn10300_set_or_clobber_flags_parallel (op, CCNZmode);
+})
+
+(define_predicate "CCNZ_comparison_operator"
+  (match_code "eq,ne,lt,ge"))