]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/config/mn10300/mn10300.md
Update copyright years.
[thirdparty/gcc.git] / gcc / config / mn10300 / mn10300.md
index 3a266960ffea78de12a4c234ff7a9510ab7e0bcb..939f20d5a58322ab22ca19c894d12d2435878e09 100644 (file)
@@ -1,7 +1,5 @@
 ;; GCC machine description for Matsushita MN10300
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-;; 2005, 2006, 2007, 2008, 2009, 2010
-;; Free Software Foundation, Inc.
+;; Copyright (C) 1996-2024 Free Software Foundation, Inc.
 ;; Contributed by Jeff Law (law@cygnus.com).
 
 ;; This file is part of GCC.
 ;; See file "rtl.def" for documentation on define_insn, match_*, et. al.
 
 (define_constants [
-  (PIC_REG 6)
-  (SP_REG  9)
-  (CC_REG 51)
+  (PIC_REG   6)
+  (SP_REG    9)
+  (MDR_REG  50)
+  (CC_REG   51)
 
-  (UNSPEC_INT_LABEL    0)
   (UNSPEC_PIC          1)
   (UNSPEC_GOT          2)
   (UNSPEC_GOTOFF       3)
   (UNSPEC_PLT          4)
   (UNSPEC_GOTSYM_OFF   5)
+
+  (UNSPEC_EXT          6)
+  (UNSPEC_BSCH         7)
+
+  ;; This is used to encode LIW patterns.
+  (UNSPEC_LIW          8)
+  ;; This is for the low overhead loop instructions.
+  (UNSPEC_SETLB         9)
 ])
 
 (include "predicates.md")
 (define_attr "cpu" "mn10300,am33,am33_2,am34"
   (const (symbol_ref "(enum attr_cpu) mn10300_tune_cpu")))
 
+;; Used to control the "enabled" attribute on a per-instruction basis.
+(define_attr "isa" "base,am33,am33_2,am34"
+  (const_string "base"))
+
+(define_attr "enabled" ""
+  (cond [(eq_attr "isa" "base")
+         (const_int 1)
+
+         (and (eq_attr "isa" "am33")
+             (match_test "TARGET_AM33"))
+         (const_int 1)
+
+         (and (eq_attr "isa" "am33_2")
+             (match_test "TARGET_AM33_2"))
+         (const_int 1)
+        
+         (and (eq_attr "isa" "am34")
+             (match_test "TARGET_AM34"))
+         (const_int 1)
+       ]
+       (const_int 0))
+)
+
+(define_mode_iterator INT [QI HI SI])
+
 \f
+;; Bundling of smaller insns into a long instruction word (LIW)
+(define_automaton "liw_bundling")
+(automata_option "ndfa")
+
+(define_cpu_unit "liw_op1_u,liw_op2_u" "liw_bundling")
+
+(define_attr "liw" "op1,op2,both,either"
+  (const_string "both"))
+;; Note: this list must match the one defined for liw_op_names[].
+(define_attr "liw_op" "add,cmp,sub,mov,and,or,xor,asr,lsr,asl,none,max"
+  (const_string "none"))
+
+(define_insn_reservation "liw_op1" 1
+  (and (ior (eq_attr "cpu" "am33")
+            (eq_attr "cpu" "am33_2")
+           (eq_attr "cpu" "am34"))
+       (eq_attr "liw" "op1"))
+  "liw_op1_u");
+(define_insn_reservation "liw_op2" 1
+  (and (ior (eq_attr "cpu" "am33")
+            (eq_attr "cpu" "am33_2")
+           (eq_attr "cpu" "am34"))
+       (eq_attr "liw" "op2"))
+  "liw_op2_u");
+(define_insn_reservation "liw_both" 1
+  (and (ior (eq_attr "cpu" "am33")
+            (eq_attr "cpu" "am33_2")
+           (eq_attr "cpu" "am34"))
+       (eq_attr "liw" "both"))
+  "liw_op1_u + liw_op2_u");
+(define_insn_reservation "liw_either" 1
+  (and (ior (eq_attr "cpu" "am33")
+            (eq_attr "cpu" "am33_2")
+           (eq_attr "cpu" "am34"))
+       (eq_attr "liw" "either"))
+  "liw_op1_u | liw_op2_u");
+\f
+;; ----------------------------------------------------------------------
 ;; Pipeline description.
+;; ----------------------------------------------------------------------
 
 ;; The AM33 only has a single pipeline.  It has five stages (fetch,
 ;; decode, execute, memory access, writeback) each of which normally
   (eq_attr "timings" "4040") "throughput*40")
 (define_insn_reservation "throughput_41_latency_42" 42
   (eq_attr "timings" "4142") "throughput*41,nothing")
+(define_insn_reservation "throughput_42_latency_43" 44
+  (eq_attr "timings" "4243") "throughput*42,nothing")
 (define_insn_reservation "throughput_43_latency_44" 44
   (eq_attr "timings" "4344") "throughput*43,nothing")
 (define_insn_reservation "throughput_45_latency_46" 46
   [(set (match_operand:QI 0 "nonimmediate_operand")
        (match_operand:QI 1 "general_operand"))]
   ""
-  "
 {
   /* One of the ops has to be in a register.  */
   if (!register_operand (operand0, QImode)
       && !register_operand (operand1, QImode))
-    operands[1] = copy_to_mode_reg (QImode, operand1);
-}")
-
-(define_insn "*am33_movqi"
-  [(set (match_operand:QI 0 "nonimmediate_operand"
-                         ;; 0       1      2      3     4       5
-                         "=d*x*a*f, d*x*a, d*x*a, m,   *f,      d*x*a")
-       (match_operand:QI 1 "general_operand"
-                          "0,       d*xai, m,     d*xa, d*xa*f, *f"))]
-  "TARGET_AM33
-   && (register_operand (operands[0], QImode)
-       || register_operand (operands[1], QImode))"
-  "*
-  {
-    switch (which_alternative)
-      {
-      case 0:
-        return \"nop\";
-      case 1:
-        gcc_assert (! CONST_DOUBLE_P (operands[1]));
-
-        if (REGNO_REG_CLASS (true_regnum (operands[0])) == EXTENDED_REGS
-           && CONST_INT_P (operands[1]))
-         {
-           HOST_WIDE_INT val = INTVAL (operands[1]);
-
-           if (((val & 0x80) && ! (val & 0xffffff00))
-               || ((val & 0x800000) && ! (val & 0xff000000)))
-             return \"movu %1,%0\";
-         }
-        return \"mov %1,%0\";
-      case 2:
-      case 3:
-        return \"movbu %1,%0\";
-      case 4:
-      case 5:
-        return \"fmov %1,%0\";
-      default:
-        gcc_unreachable ();
-      }
-  }"
-  [(set_attr_alternative "timings"
-                        [(const_int 11)
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 11) (const_int 22))
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 13) (const_int 24))
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 13) (const_int 24))
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 47) (const_int 25))
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 47) (const_int 25))
-                        ])
-  ]
-)
+    operands[1] = force_reg (QImode, operand1);
+})
 
-(define_insn "*mn10300_movqi"
-  [(set (match_operand:QI 0 "nonimmediate_operand" "=d*a,d,d,!*a,d*a,d,m")
-       (match_operand:QI 1 "general_operand"       "0,  I,i,i,  da, m,d"))]
-  "register_operand (operands[0], QImode)
-   || register_operand (operands[1], QImode)"
-  "*
+(define_insn "*movqi_internal"
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=*r,D*r,D*r,D,m,*z,d")
+       (match_operand:QI 1 "general_operand"      "  0,D*r,  i,m,D,d,*z"))]
+  "(register_operand (operands[0], QImode)
+    || register_operand (operands[1], QImode))"
 {
   switch (which_alternative)
     {
     case 0:
-      return \"nop\";
+      return "";
     case 1:
     case 2:
-    case 3:
-    case 4:
-      gcc_assert (! CONST_DOUBLE_P (operands[1]));
-      return \"mov %1,%0\";
     case 5:
     case 6:
-      return \"movbu %1,%0\";
+      return "mov %1,%0";
+    case 3:
+    case 4:
+      return "movbu %1,%0";
     default:
       gcc_unreachable ();
     }
-}"
+}
   [(set_attr_alternative "timings"
-                        [(const_int 11)
-                         (const_int 11)
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 11) (const_int 22))
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 11) (const_int 22))
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 11) (const_int 22))
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 13) (const_int 24))
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 13) (const_int 24))
-                        ])
-  ]
+        [(const_int 11)
+         (const_int 11)
+         (const_int 11)
+         (if_then_else (eq_attr "cpu" "am34")
+                       (const_int 13) (const_int 24))
+         (if_then_else (eq_attr "cpu" "am34")
+                       (const_int 11) (const_int 22))
+         (const_int 11)
+         (const_int 11)
+        ])]
 )
 
 ;; movhi
   [(set (match_operand:HI 0 "nonimmediate_operand")
        (match_operand:HI 1 "general_operand"))]
   ""
-  "
 {
   /* One of the ops has to be in a register.  */
   if (!register_operand (operand1, HImode)
       && !register_operand (operand0, HImode))
-    operands[1] = copy_to_mode_reg (HImode, operand1);
-}")
-
-(define_insn "*am33_movhi"
-  [(set (match_operand:HI 0 "nonimmediate_operand"
-                         ;; 0       1       2      3     4         5
-                         "=d*x*a*f, d*x*a,  d*x*a, m,    *f,       d*x*a")
-       (match_operand:HI 1 "general_operand"
-                         "0,        d*x*ai, m,     d*x*a, d*x*a*f, *f"))]
-  "TARGET_AM33
-   && (register_operand (operands[0], HImode)
-       || register_operand (operands[1], HImode))"
-  "*
-{
-  switch (which_alternative)
-    {
-    case 0:
-      return \"nop\";
-    case 1:
-      gcc_assert (! CONST_DOUBLE_P (operands[1]));
-
-      if (REGNO_REG_CLASS (true_regnum (operands[0])) == EXTENDED_REGS
-         && CONST_INT_P (operands[1]))
-       {
-         HOST_WIDE_INT val = INTVAL (operands[1]);
-
-         if (((val & 0x80) && ! (val & 0xffffff00))
-             || ((val & 0x800000) && ! (val & 0xff000000)))
-           return \"movu %1,%0\";
-       }
-      return \"mov %1,%0\";
-    case 2:
-    case 3:
-      return \"movhu %1,%0\";
-    case 4:
-    case 5:
-      return \"fmov %1,%0\";
-    default:
-      gcc_unreachable ();
-    }
-}"
-  [(set_attr_alternative "timings"
-                        [(const_int 11)
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 11) (const_int 22))
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 13) (const_int 24))
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 13) (const_int 24))
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 47) (const_int 25))
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 47) (const_int 25))
-                        ])
-  ]
-)
+    operands[1] = force_reg (HImode, operand1);
+})
 
-(define_insn "*mn10300_movhi"
-  [(set (match_operand:HI 0 "nonimmediate_operand" "=d*a,d,d,!*a,d*a,d,m")
-       (match_operand:HI 1 "general_operand"       "0,  I,i,i,  da, m,d"))]
-  "register_operand (operands[0], HImode)
-   || register_operand (operands[1], HImode)"
-  "*
+(define_insn "*movhi_internal"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=*r,D*r,D*r,D,m,*z,d")
+       (match_operand:HI 1 "general_operand"      "  0,  i,D*r,m,D,d,*z"))]
+  "(register_operand (operands[0], HImode)
+    || register_operand (operands[1], HImode))"
 {
   switch (which_alternative)
     {
     case 0:
-      return \"nop\";
+      return "";
     case 1:
+      /* Note that "MOV imm8,An" is already zero-extending, and is 2 bytes.
+        We have "MOV imm16,Dn" at 3 bytes.  The only win for the 4 byte
+        movu is for an 8-bit unsigned move into Rn.  */
+      if (TARGET_AM33
+         && CONST_INT_P (operands[1])
+         && IN_RANGE (INTVAL (operands[1]), 0x80, 0xff)
+         && REGNO_EXTENDED_P (REGNO (operands[0]), 1))
+       return "movu %1,%0";
+      /* FALLTHRU */
+    case 5:
+    case 6:
     case 2:
+      return "mov %1,%0";
     case 3:
     case 4:
-      gcc_assert (! CONST_DOUBLE_P (operands[1]));
-      return \"mov %1,%0\";
-    case 5:
-    case 6:
-      return \"movhu %1,%0\";
+      return "movhu %1,%0";
     default:
       gcc_unreachable ();
     }
-}"
+}
   [(set_attr_alternative "timings"
-                        [(const_int 11)
-                         (const_int 11)
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 11) (const_int 22))
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 11) (const_int 22))
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 11) (const_int 22))
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 13) (const_int 24))
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 13) (const_int 24))
-                        ])
-  ]
+        [(const_int 11)
+         (const_int 11)
+         (if_then_else (eq_attr "cpu" "am34")
+                       (const_int 11) (const_int 22))
+         (if_then_else (eq_attr "cpu" "am34")
+                       (const_int 13) (const_int 24))
+         (if_then_else (eq_attr "cpu" "am34")
+                       (const_int 11) (const_int 22))
+         (if_then_else (eq_attr "cpu" "am34")
+                       (const_int 11) (const_int 22))
+         (if_then_else (eq_attr "cpu" "am34")
+                       (const_int 11) (const_int 22))
+        ])]
 )
 
 ;; movsi and helpers
 ;; We use this to handle addition of two values when one operand is the
 ;; stack pointer and the other is a memory reference of some kind.  Reload
 ;; does not handle them correctly without this expander.
-(define_expand "reload_insi"
-  [(set (match_operand:SI     0 "register_operand" "=a")
+(define_expand "reload_plus_sp_const"
+  [(set (match_operand:SI     0 "register_operand" "=r")
        (match_operand:SI     1 "impossible_plus_operand" ""))
-   (clobber (match_operand:SI 2 "register_operand" "=&r"))]
+   (clobber (match_operand:SI 2 "register_operand" "=&A"))]
   ""
-  "
 {
-  gcc_assert (REGNO (operands[0]) != REGNO (operands[2]));
+  rtx dest, scratch, other;
+
+  dest = operands[0];
+  scratch = operands[2];
 
-  if (XEXP (operands[1], 0) == stack_pointer_rtx)
+  other = XEXP (operands[1], 1);
+  if (other == stack_pointer_rtx)
+    other = XEXP (operands[1], 0);
+
+  if (true_regnum (other) == true_regnum (dest))
     {
-      if (GET_CODE (XEXP (operands[1], 1)) == SUBREG
-         && (GET_MODE_SIZE (GET_MODE (XEXP (operands[1], 1)))
-             > GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (operands[1], 1))))))
-       emit_move_insn (operands[2],
-                       gen_rtx_ZERO_EXTEND
-                       (GET_MODE (XEXP (operands[1], 1)),
-                        SUBREG_REG (XEXP (operands[1], 1))));
-      else
-       emit_move_insn (operands[2], XEXP (operands[1], 1));
-      emit_move_insn (operands[0], XEXP (operands[1], 0));
+      gcc_assert (true_regnum (scratch) != true_regnum (dest));
+      emit_move_insn (scratch, stack_pointer_rtx);
+      emit_insn (gen_addsi3 (dest, dest, scratch));
+    }
+  else if (TARGET_AM33 || REGNO_REG_CLASS (true_regnum (dest)) == ADDRESS_REGS)
+    {
+      emit_move_insn (dest, stack_pointer_rtx);
+      if (other == stack_pointer_rtx)
+        emit_insn (gen_addsi3 (dest, dest, dest));
+      else if (other != const0_rtx)
+        emit_insn (gen_addsi3 (dest, dest, other));
     }
   else
     {
-      if (GET_CODE (XEXP (operands[1], 0)) == SUBREG
-         && (GET_MODE_SIZE (GET_MODE (XEXP (operands[1], 0)))
-             > GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (operands[1], 0))))))
-       emit_move_insn (operands[2],
-                       gen_rtx_ZERO_EXTEND
-                       (GET_MODE (XEXP (operands[1], 0)),
-                        SUBREG_REG (XEXP (operands[1], 0))));
+      emit_move_insn (scratch, stack_pointer_rtx);
+      if (other == stack_pointer_rtx)
+       {
+         emit_move_insn (dest, scratch);
+          emit_insn (gen_addsi3 (dest, dest, dest));
+       }
+      else if (other != const0_rtx)
+       {
+         emit_move_insn (dest, other);
+          emit_insn (gen_addsi3 (dest, dest, scratch));
+       }
       else
-       emit_move_insn (operands[2], XEXP (operands[1], 0));
-      emit_move_insn (operands[0], XEXP (operands[1], 1));
+       emit_move_insn (dest, scratch);
     }
-  emit_insn (gen_addsi3 (operands[0], operands[0], operands[2]));
   DONE;
-}")
-
-(define_insn "pop_pic_reg"
-  [(set (reg:SI PIC_REG)
-       (mem:SI (post_inc:SI (reg:SI SP_REG))))]
-  "reload_completed"
-  "movm (sp),[a2]"
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-                                      (const_int 44) (const_int 33)))]
-)
+})
 
 (define_expand "movsi"
   [(set (match_operand:SI 0 "nonimmediate_operand")
        (match_operand:SI 1 "general_operand"))]
   ""
-  "
 {
   /* One of the ops has to be in a register.  */
   if (!register_operand (operand1, SImode)
       && !register_operand (operand0, SImode))
-    operands[1] = copy_to_mode_reg (SImode, operand1);
+    operands[1] = force_reg (SImode, operand1);
   if (flag_pic)
     {
       rtx temp;
                                      0, OPTAB_LIB_WIDEN);
        }
     }
-}")
+})
 
 (define_insn "*movsi_internal"
   [(set (match_operand:SI 0 "nonimmediate_operand"
-                         "=dax, dax,  m,   dax, axR, !*y")
+                         "=r,r,r,r,m,r, A,*y,*y,*z,*d")
        (match_operand:SI 1 "general_operand"
-                         "0,    Idax, dax, im,  !*y, axR"))
-  ]
+                         " 0,O,i,r,r,m,*y, A, i,*d,*z"))]
   "register_operand (operands[0], SImode)
    || register_operand (operands[1], SImode)"
-  "*
-  {
-    if (which_alternative == 0)
-      return \"nop\";
-
-    gcc_assert (! CONST_DOUBLE_P (operands[1]));
-
-    if (REGNO_REG_CLASS (true_regnum (operands[0])) == EXTENDED_REGS
-        && CONST_INT_P (operands[1]))
-      {
-        HOST_WIDE_INT val = INTVAL (operands[1]);
-
-        if (((val & 0x80) && ! (val & 0xffffff00))
-            || ((val & 0x800000) && ! (val & 0xff000000)))
-          return \"movu %1, %0\";
-      }
-
-    return \"mov %1, %0\";
-  }"
-  [(set_attr_alternative "timings"
-                        [(const_int 11)
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 13) (const_int 24))
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 13) (const_int 24))
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 13) (const_int 24))
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 13) (const_int 24))
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 13) (const_int 24))
-                        ])
-  ]
+{
+  switch (which_alternative)
+    {
+    case 0:
+      return "";
+    case 1: /* imm-reg.  */
+    case 2: 
+      /* See movhi for a discussion of sizes for 8-bit movu.  Note that the
+        24-bit movu is 6 bytes, which is the same size as the full 32-bit
+        mov form for An and Dn.  So again movu is only a win for Rn.  */
+      if (TARGET_AM33
+         && CONST_INT_P (operands[1])
+         && REGNO_EXTENDED_P (REGNO (operands[0]), 1))
+       {
+         HOST_WIDE_INT val = INTVAL (operands[1]);
+         if (IN_RANGE (val, 0x80, 0xff)
+             || IN_RANGE (val, 0x800000, 0xffffff))
+           return "movu %1,%0";
+       }
+      /* FALLTHRU */
+    case 3:  /* reg-reg */
+    case 4:  /* reg-mem */
+    case 5:  /* mem-reg */
+    case 6:  /* sp-reg */
+    case 7:  /* reg-sp */
+    case 8:  /* imm-sp */
+    case 9:  /* reg-mdr */
+    case 10:  /* mdr-reg */
+      return "mov %1,%0";
+    default:
+      gcc_unreachable ();
+    }
+}
+  [(set_attr "isa" "*,*,*,*,*,*,*,*,am33,*,*")
+   (set_attr "liw" "*,either,*,either,*,*,*,*,*,*,*")
+   (set_attr "liw_op" "mov")
+   (set_attr_alternative "timings"
+        [(const_int 11)
+         (const_int 22)
+         (const_int 22)
+         (const_int 11)
+         (if_then_else (eq_attr "cpu" "am34")
+                       (const_int 11) (const_int 22))
+         (if_then_else (eq_attr "cpu" "am34")
+                       (const_int 13) (const_int 24))
+         (if_then_else (eq_attr "cpu" "am34")
+                       (const_int 11) (const_int 22))
+         (if_then_else (eq_attr "cpu" "am34")
+                       (const_int 13) (const_int 24))
+         (const_int 11)
+         (const_int 11)
+         (const_int 11)
+        ])]
 )
 
 (define_expand "movsf"
   [(set (match_operand:SF 0 "nonimmediate_operand")
        (match_operand:SF 1 "general_operand"))]
-  ""
-  "
+  "TARGET_AM33_2"
 {
   /* One of the ops has to be in a register.  */
   if (!register_operand (operand1, SFmode)
       && !register_operand (operand0, SFmode))
-    operands[1] = copy_to_mode_reg (SFmode, operand1);
-}")
+    operands[1] = force_reg (SFmode, operand1);
+})
 
 (define_insn "*movsf_internal"
-  [(set (match_operand:SF 0 "nonimmediate_operand"
-                         ;; 0    1    2       3     4     5
-                         "=fdxa, dxa, f,      dxaQ, daxm, dax")
-       (match_operand:SF 1 "general_operand"
-                         " 0,    G,   fdxaQF, f,    dax,  daxFm"))
-  ]
-  "register_operand (operands[0], SFmode)
-   || register_operand (operands[1], SFmode)"
-  "*
-  {
-    switch (which_alternative)
-      {
-      case 0:
-        return \"nop\";
-      /* case 1: below.  */
-      case 2:
-      case 3:
-        return \"fmov %1, %0\";
-      case 1:
-      case 4:
-      case 5:
-        if (REGNO_REG_CLASS (true_regnum (operands[0])) == EXTENDED_REGS
-           && CONST_INT_P (operands[1]))
-         {
-           HOST_WIDE_INT val = INTVAL (operands[1]);
-
-           if (((val & 0x80) && ! (val & 0xffffff00))
-               || ((val & 0x800000) && ! (val & 0xff000000)))
-             return \"movu %1, %0\";
-         }
-        return \"mov %1, %0\";
-      default:
-        gcc_unreachable ();
-      }
-  }"
-  [(set_attr_alternative "timings"
-                        [(const_int 11)
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 13) (const_int 24))
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 47) (const_int 25))
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 47) (const_int 25))
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 13) (const_int 24))
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 13) (const_int 24))
-                        ])
-  ]
-)
-
-(define_expand "movdi"
-  [(set (match_operand:DI 0 "nonimmediate_operand")
-       (match_operand:DI 1 "general_operand"))]
-  ""
-  "
-{
-  /* One of the ops has to be in a register.  */
-  if (!register_operand (operand1, DImode)
-      && !register_operand (operand0, DImode))
-    operands[1] = copy_to_mode_reg (DImode, operand1);
-}")
-
-
-(define_insn "*movdi_internal"                   ;;   0 1  2  3 4   5   6  7 8  9
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=dx,ax,dx,a,dxm,dxm,a, a,dx,a")
-       (match_operand:DI 1 "general_operand"        "0,0, I, I,dx, a,  dx,a,im,im"))]
-  "register_operand (operands[0], DImode)
-   || register_operand (operands[1], DImode)"
-  "*
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=rf,r,f,r,f,r,f,r,m,f,Q,z,d")
+       (match_operand:SF 1 "general_operand"      "  0,F,F,r,f,f,r,m,r,Q,f,d,z"))]
+  "TARGET_AM33_2
+   && (register_operand (operands[0], SFmode)
+       || register_operand (operands[1], SFmode))"
 {
-  long val[2];
-  REAL_VALUE_TYPE rv;
-
   switch (which_alternative)
     {
-      case 0:
-      case 1:
-       return \"nop\";
-
-      case 2:
-       return \"mov 0, %L0\;mov 0, %H0\";
-
-      case 3:
-       if (rtx_equal_p (operands[0], operands[1]))
-         return \"sub %L1,%L0\;mov %L0,%H0\";
-       else
-         return \"mov %1,%L0\;mov %L0,%H0\";
-      case 4:
-      case 5:
-      case 6:
-      case 7:
-      case 8:
-      case 9:
-       if (CONST_INT_P (operands[1]))
-         {
-           rtx low, high;
-           split_double (operands[1], &low, &high);
-           val[0] = INTVAL (low);
-           val[1] = INTVAL (high);
-         }
-       if (CONST_DOUBLE_P (operands[1]))
-         {
-           if (GET_MODE (operands[1]) == DFmode)
-             {
-               REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
-               REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
-             }
-           else if (GET_MODE (operands[1]) == VOIDmode
-                    || GET_MODE (operands[1]) == DImode)
-             {
-               val[0] = CONST_DOUBLE_LOW (operands[1]);
-               val[1] = CONST_DOUBLE_HIGH (operands[1]);
-             }
-         }
-
-       if (MEM_P (operands[1])
-           && reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0)))
-         {
-           rtx temp = operands[0];
-
-           while (GET_CODE (temp) == SUBREG)
-             temp = SUBREG_REG (temp);
-
-           gcc_assert (REG_P (temp));
-
-           if (reg_overlap_mentioned_p (gen_rtx_REG (SImode, REGNO (temp)),
-                                        XEXP (operands[1], 0)))
-             return \"mov %H1,%H0\;mov %L1,%L0\";
-           else
-             return \"mov %L1,%L0\;mov %H1,%H0\";
-
-         }
-       else if (MEM_P (operands[1])
-                && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))
-                && REGNO_REG_CLASS (REGNO (operands[0])) == ADDRESS_REGS)
-         {
-           rtx xoperands[2];
-
-           xoperands[0] = operands[0];
-           xoperands[1] = XEXP (operands[1], 0);
-
-           output_asm_insn (\"mov %1,%L0\;mov (4,%L0),%H0\;mov (%L0),%L0\",
-                            xoperands);
-           return \"\";
-         }
-       else
-         {
-           if ((CONST_INT_P (operands[1])
-                || CONST_DOUBLE_P (operands[1]))
-               && val[0] == 0)
-             {
-               if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
-                 output_asm_insn (\"mov 0, %L0\", operands);
-               else
-                 output_asm_insn (\"mov %L1,%L0\", operands);
-             }
-           else if ((CONST_INT_P (operands[1])
-                     || CONST_DOUBLE_P (operands[1]))
-                    && (REGNO_REG_CLASS (true_regnum (operands[0]))
-                        == EXTENDED_REGS)
-                    && (((val[0] & 0x80) && ! (val[0] & 0xffffff00))
-                        || ((val[0] & 0x800000) && ! (val[0] & 0xff000000))))
-             output_asm_insn (\"movu %L1,%L0\", operands);
-           else
-             output_asm_insn (\"mov %L1,%L0\", operands);
-
-           if ((CONST_INT_P (operands[1])
-                || CONST_DOUBLE_P (operands[1]))
-               && val[1] == 0)
-             {
-               if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
-                 output_asm_insn (\"mov 0, %H0\", operands);
-               else
-                 output_asm_insn (\"mov %H1,%H0\", operands);
-             }
-           else if ((CONST_INT_P (operands[1])
-                     || CONST_DOUBLE_P (operands[1]))
-                    && val[0] == val[1])
-             output_asm_insn (\"mov %L0,%H0\", operands);
-           else if ((CONST_INT_P (operands[1])
-                     || CONST_DOUBLE_P (operands[1]))
-                    && (REGNO_REG_CLASS (true_regnum (operands[0]))
-                        == EXTENDED_REGS)
-                    && (((val[1] & 0x80) && ! (val[1] & 0xffffff00))
-                        || ((val[1] & 0x800000) && ! (val[1] & 0xff000000))))
-             output_asm_insn (\"movu %H1,%H0\", operands);
-           else
-             output_asm_insn (\"mov %H1,%H0\", operands);
-           return \"\";
-         }
+    case 0:
+      return "";
+    case 1:
+    case 3:
+    case 7:
+    case 8:
+    case 11:
+    case 12:
+      return "mov %1,%0";
+    case 2:
+    case 4:
+    case 5:
+    case 6:
+    case 9:
+    case 10:
+      return "fmov %1,%0";
     default:
       gcc_unreachable ();
     }
-  }"
-  ;; The timing of "37" is an approximation of the worst case sceanario.
+}
   [(set_attr_alternative "timings"
-                        [(const_int 11)
-                         (const_int 11)
-                         (const_int 22)
-                         (const_int 22)
-                         (const_int 37)
-                         (const_int 37)
-                         (const_int 37)
-                         (const_int 37)
-                         (const_int 37)
-                         (const_int 37)
-                        ])
-  ]
+                [(const_int 11)
+                 (const_int 22)
+                 (if_then_else (eq_attr "cpu" "am34")
+                               (const_int 47) (const_int 25))
+                 (const_int 11)
+                 (if_then_else (eq_attr "cpu" "am34")
+                               (const_int 13) (const_int 14))
+                 (if_then_else (eq_attr "cpu" "am34")
+                               (const_int 13) (const_int 12))
+                 (if_then_else (eq_attr "cpu" "am34")
+                               (const_int 13) (const_int 14))
+                 (if_then_else (eq_attr "cpu" "am34")
+                               (const_int 13) (const_int 24))
+                 (if_then_else (eq_attr "cpu" "am34")
+                               (const_int 13) (const_int 24))
+                 (if_then_else (eq_attr "cpu" "am34")
+                               (const_int 13) (const_int 24))
+                 (if_then_else (eq_attr "cpu" "am34")
+                               (const_int 13) (const_int 24))
+                 (const_int 22)
+                 (const_int 22)
+                ])]
+)
+
+;; If the flags register is not live, generate CLR instead of MOV 0.
+;; For MN103, this is only legal for DATA_REGS; for AM33 this is legal
+;; but not a win for ADDRESS_REGS.
+(define_peephole2
+  [(set (match_operand:INT 0 "register_operand" "") (const_int 0))]
+  "peep2_regno_dead_p (0, CC_REG)
+   && (REGNO_DATA_P (REGNO (operands[0]), 1)
+       || REGNO_EXTENDED_P (REGNO (operands[0]), 1))"
+  [(parallel [(set (match_dup 0) (const_int 0))
+             (clobber (reg:CC CC_REG))])]
+)
+
+(define_insn "*mov<mode>_clr"
+  [(set (match_operand:INT 0 "register_operand" "=D")
+       (const_int 0))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "clr %0"
 )
+\f
+;; ----------------------------------------------------------------------
+;; ADD INSTRUCTIONS
+;; ----------------------------------------------------------------------
 
-(define_expand "movdf"
-  [(set (match_operand:DF 0 "nonimmediate_operand")
-       (match_operand:DF 1 "general_operand"))]
+(define_insn "addsi3"
+  [(set (match_operand:SI          0 "register_operand"  "=r,r,r,!*y,!r")
+       (plus:SI (match_operand:SI 1 "register_operand"  "%0,0,0,  0, r")
+                (match_operand:SI 2 "nonmemory_operand"  "r,O,i,  i, r")))
+   (clobber (reg:CC CC_REG))]
   ""
-  "
-{
-  /* One of the ops has to be in a register.  */
-  if (!register_operand (operand1, DFmode)
-      && !register_operand (operand0, DFmode))
-    operands[1] = copy_to_mode_reg (DFmode, operand1);
-}")
-
-(define_insn "*am33_2_movdf"
-  [(set (match_operand:DF 0 "nonimmediate_operand"
-                         ;; 0   1   2    3    4 5 6   7   8  9 10 11
-                         "=fdax,dax,fdxa,f,   f,Q,dxm,dxm,a, a,dx,a")
-       (match_operand:DF 1 "general_operand"
-                         " 0,   G,  f,   dxaF,Q,f,dx, a,  dx,a,Fm,Fm"))]
-  "TARGET_AM33_2
-   && (register_operand (operands[0], DFmode)
-       || register_operand (operands[1], DFmode))"
-  "*
-  {
-    long val[2];
-    REAL_VALUE_TYPE rv;
-
-    switch (which_alternative)
-      {
-      case 0:
-       return \"nop\";
-
-      case 1:
-       return \"mov 0, %L0\; mov 0, %H0\";
-
-      case 2:
-      case 3:
-        return \"fmov %L1, %L0\; fmov %H1, %H0\";
-
-      case 4:
-       if (MEM_P (operands[1])
-           && CONST_INT_P (XEXP (operands[1], 0))
-           && (INTVAL (XEXP (operands[1], 0)) & 7) == 0)
-         return \"fmov %D1, %D0\";
-       else
-          return \"fmov %L1, %L0\; fmov %H1, %H0\";
-
-      case 5:
-       if (MEM_P (operands[0])
-           && CONST_INT_P (XEXP (operands[0], 0))
-           && (INTVAL (XEXP (operands[0], 0)) & 7) == 0)
-         return \"fmov %D1, %D0\";
-       else
-          return \"fmov %L1, %L0\; fmov %H1, %H0\";
-
-      case 6:
-      case 7:
-      case 8:
-      case 9:
-      case 10:
-      case 11:
-       if (CONST_INT_P (operands[1]))
-         {
-           rtx low, high;
-           split_double (operands[1], &low, &high);
-           val[0] = INTVAL (low);
-           val[1] = INTVAL (high);
-         }
-       if (CONST_DOUBLE_P (operands[1]))
-         {
-           if (GET_MODE (operands[1]) == DFmode)
-             {
-               REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
-               REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
-             }
-           else if (GET_MODE (operands[1]) == VOIDmode
-                    || GET_MODE (operands[1]) == DImode)
-             {
-               val[0] = CONST_DOUBLE_LOW (operands[1]);
-               val[1] = CONST_DOUBLE_HIGH (operands[1]);
-             }
-         }
-
-       if (MEM_P (operands[1])
-           && reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0)))
-         {
-           rtx temp = operands[0];
-
-           while (GET_CODE (temp) == SUBREG)
-             temp = SUBREG_REG (temp);
-
-           gcc_assert (REG_P (temp));
-
-           if (reg_overlap_mentioned_p (gen_rtx_REG (SImode, REGNO (temp)),
-                                        XEXP (operands[1], 0)))
-             return \"mov %H1, %H0\; mov %L1, %L0\";
-           else
-             return \"mov %L1, %L0\; mov %H1, %H0\";
-
-         }
-       else if (MEM_P (operands[1])
-                && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))
-                && REGNO_REG_CLASS (REGNO (operands[0])) == ADDRESS_REGS)
-         {
-           rtx xoperands[2];
-
-           xoperands[0] = operands[0];
-           xoperands[1] = XEXP (operands[1], 0);
-
-           output_asm_insn (\"mov %1, %L0\; mov (4, %L0), %H0\; mov (%L0), %L0\",
-                            xoperands);
-           return \"\";
-         }
-       else
-         {
-           if ((CONST_INT_P (operands[1])
-                || CONST_DOUBLE_P (operands[1]))
-               && val[0] == 0)
-             {
-               if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
-                 output_asm_insn (\"mov 0, %L0\", operands);
-               else
-                 output_asm_insn (\"mov %L1,%L0\", operands);
-             }
-           else if ((CONST_INT_P (operands[1])
-                     || CONST_DOUBLE_P (operands[1]))
-                    && (REGNO_REG_CLASS (true_regnum (operands[0]))
-                        == EXTENDED_REGS)
-                    && (((val[0] & 0x80) && ! (val[0] & 0xffffff00))
-                        || ((val[0] & 0x800000) && ! (val[0] & 0xff000000))))
-             output_asm_insn (\"movu %L1, %L0\", operands);
-           else
-             output_asm_insn (\"mov %L1, %L0\", operands);
-
-           if ((CONST_INT_P (operands[1])
-                || CONST_DOUBLE_P (operands[1]))
-               && val[1] == 0)
-             {
-               if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
-                 output_asm_insn (\"mov 0, %H0\", operands);
-               else
-                 output_asm_insn (\"mov %H1, %H0\", operands);
-             }
-           else if ((CONST_INT_P (operands[1])
-                     || CONST_DOUBLE_P (operands[1]))
-                    && val[0] == val[1])
-             output_asm_insn (\"mov %L0,%H0\", operands);
-           else if ((CONST_INT_P (operands[1])
-                     || CONST_DOUBLE_P (operands[1]))
-                    && (REGNO_REG_CLASS (true_regnum (operands[0]))
-                        == EXTENDED_REGS)
-                    && (((val[1] & 0x80) && ! (val[1] & 0xffffff00))
-                        || ((val[1] & 0x800000) && ! (val[1] & 0xff000000))))
-             output_asm_insn (\"movu %H1, %H0\", operands);
-           else
-             output_asm_insn (\"mov %H1, %H0\", operands);
-           return \"\";
-         }
-    default:
-      gcc_unreachable ();
-    }
-  }"
-  ;; The timing of "37" is an approximation of the worst case sceanario.
-  [(set_attr_alternative "timings"
-                        [(const_int 11)
-                         (const_int 22)
-                         (const_int 22)
-                         (const_int 22)
-                         (const_int 22)
-                         (const_int 37)
-                         (const_int 37)
-                         (const_int 37)
-                         (const_int 37)
-                         (const_int 37)
-                         (const_int 37)
-                         (const_int 37)
-                        ])
-  ]
+  { return mn10300_output_add (operands, false); }
+  [(set_attr "timings" "11,11,11,11,22")
+   (set_attr "liw" "either,either,*,*,*")
+   (set_attr "liw_op" "add")]
 )
 
-(define_insn "*mn10300_movdf"
-  [(set (match_operand:DF 0 "nonimmediate_operand"
-                         ;;0    1    2    3    4   5  6   7
-                         "=dxa, dax, dxm, dxm, a,  a, dx, a")
-       (match_operand:DF 1 "general_operand"
-                         " 0,   G,   dx,  a,   dx, a, Fm, Fm"))]
-  "register_operand (operands[0], DFmode)
-   || register_operand (operands[1], DFmode)"
-  "*
-  {
-    long val[2];
-    REAL_VALUE_TYPE rv;
-
-    switch (which_alternative)
-      {
-      case 0:
-       return \"nop\";
-
-      case 1:
-       return \"mov 0, %L0\; mov 0, %H0\";
-
-      case 2:
-      case 3:
-      case 4:
-      case 5:
-      case 6:
-      case 7:
-       if (CONST_INT_P (operands[1]))
-         {
-           rtx low, high;
-           split_double (operands[1], &low, &high);
-           val[0] = INTVAL (low);
-           val[1] = INTVAL (high);
-         }
-        if (CONST_DOUBLE_P (operands[1]))
-         {
-           if (GET_MODE (operands[1]) == DFmode)
-             {
-               REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
-               REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
-             }
-           else if (GET_MODE (operands[1]) == VOIDmode
-                    || GET_MODE (operands[1]) == DImode)
-             {
-               val[0] = CONST_DOUBLE_LOW (operands[1]);
-               val[1] = CONST_DOUBLE_HIGH (operands[1]);
-             }
-         }
-
-       if (MEM_P (operands[1])
-           && reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0)))
-         {
-           rtx temp = operands[0];
-
-           while (GET_CODE (temp) == SUBREG)
-             temp = SUBREG_REG (temp);
-
-           gcc_assert (REG_P (temp));
-
-           if (reg_overlap_mentioned_p (gen_rtx_REG (SImode, REGNO (temp)),
-                                        XEXP (operands[1], 0)))
-             return \"mov %H1, %H0\; mov %L1, %L0\";
-           else
-             return \"mov %L1, %L0\; mov %H1, %H0\";
-         }
-       else if (MEM_P (operands[1])
-                && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))
-                && REGNO_REG_CLASS (REGNO (operands[0])) == ADDRESS_REGS)
-         {
-           rtx xoperands[2];
-
-           xoperands[0] = operands[0];
-           xoperands[1] = XEXP (operands[1], 0);
-
-           output_asm_insn (\"mov %1, %L0\; mov (4, %L0), %H0\; mov (%L0), %L0\",
-                            xoperands);
-           return \"\";
-         }
-       else
-         {
-           if ((CONST_INT_P (operands[1])
-                || CONST_DOUBLE_P (operands[1]))
-               && val[0] == 0)
-             {
-               if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
-                 output_asm_insn (\"mov 0, %L0\", operands);
-               else
-                 output_asm_insn (\"mov %L1, %L0\", operands);
-             }
-           else if ((CONST_INT_P (operands[1])
-                     || CONST_DOUBLE_P (operands[1]))
-                    && (REGNO_REG_CLASS (true_regnum (operands[0]))
-                        == EXTENDED_REGS)
-                    && (((val[0] & 0x80) && ! (val[0] & 0xffffff00))
-                        || ((val[0] & 0x800000) && ! (val[0] & 0xff000000))))
-             output_asm_insn (\"movu %L1, %L0\", operands);
-           else
-             output_asm_insn (\"mov %L1, %L0\", operands);
-
-           if ((CONST_INT_P (operands[1])
-                || CONST_DOUBLE_P (operands[1]))
-               && val[1] == 0)
-             {
-               if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
-                 output_asm_insn (\"mov 0, %H0\", operands);
-               else
-                 output_asm_insn (\"mov %H1, %H0\", operands);
-             }
-           else if ((CONST_INT_P (operands[1])
-                     || CONST_DOUBLE_P (operands[1]))
-                    && val[0] == val[1])
-             output_asm_insn (\"mov %L0, %H0\", operands);
-           else if ((CONST_INT_P (operands[1])
-                     || CONST_DOUBLE_P (operands[1]))
-                    && (REGNO_REG_CLASS (true_regnum (operands[0]))
-                        == EXTENDED_REGS)
-                    && (((val[1] & 0x80) && ! (val[1] & 0xffffff00))
-                        || ((val[1] & 0x800000) && ! (val[1] & 0xff000000))))
-             output_asm_insn (\"movu %H1, %H0\", operands);
-           else
-             output_asm_insn (\"mov %H1, %H0\", operands);
-           return \"\";
-         }
-    default:
-      gcc_unreachable ();
-    }
-  }"
-  ;; Timings of "37" is approximation of the worst case sceanario.
-  [(set_attr_alternative "timings"
-                        [(const_int 11)
-                         (const_int 22)
-                         (const_int 37)
-                         (const_int 37)
-                         (const_int 37)
-                         (const_int 37)
-                         (const_int 37)
-                         (const_int 37)
-                        ])
-  ]
+;; Note that ADD IMM,SP does not set the flags, so omit that here.
+(define_insn "*addsi3_flags"
+  [(set (reg CC_REG)
+       (compare (plus:SI (match_operand:SI 1 "register_operand"  "%0, r")
+                         (match_operand:SI 2 "nonmemory_operand" "ri, r"))
+                (const_int 0)))
+   (set (match_operand:SI          0 "register_operand"  "=r,!r")
+       (plus:SI (match_dup 1) (match_dup 2)))]
+  "reload_completed && mn10300_match_ccmode (insn, CCZNCmode)"
+  { return mn10300_output_add (operands, true); }
+  [(set_attr "timings" "11,22")]
 )
-\f
-;; ----------------------------------------------------------------------
-;; ADD INSTRUCTIONS
-;; ----------------------------------------------------------------------
 
-(define_expand "addsi3"
-  [(parallel [(set (match_operand:SI          0 "register_operand")
+;; A helper to expand the above, with the CC_MODE filled in.
+(define_expand "addsi3_flags"
+  [(parallel [(set (reg:CCZNC CC_REG)
+                  (compare:CCZNC (plus:SI (match_dup 1) (match_dup 2))
+                                 (const_int 0)))
+             (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))
-            ])
-  ]
+                           (match_operand:SI 2 "nonmemory_operand")))])]
   ""
-  "")
+)
 
-(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))
-  ]
-  "TARGET_AM33"
-  "*
+(define_insn "addc_internal"
+  [(set (match_operand:SI 0 "register_operand"            "=D,r,r")
+       (plus:SI
+         (plus:SI
+           (ltu:SI (reg:CC CC_REG) (const_int 0))
+           (match_operand:SI 1 "register_operand"        "%0,0,r"))
+         (match_operand:SI 2 "reg_or_am33_const_operand" " D,i,r")))
+    (clobber (reg:CC CC_REG))]
+  "reload_completed"
+  "@
+   addc %2,%0
+   addc %2,%0
+   addc %2,%1,%0"
+  [(set_attr "isa" "*,am33,am33")]
+)
+
+(define_expand "adddi3"
+  [(set (match_operand:DI 0 "register_operand" "")
+       (plus:DI (match_operand:DI 1 "register_operand" "")
+                (match_operand:DI 2 "nonmemory_operand" "")))]
+  ""
 {
-  switch (which_alternative)
+  rtx op0l, op0h, op1l, op1h, op2l, op2h;
+
+  op0l = gen_lowpart (SImode, operands[0]);
+  op1l = gen_lowpart (SImode, operands[1]);
+  op2l = gen_lowpart (SImode, operands[2]);
+  op0h = gen_highpart (SImode, operands[0]);
+  op1h = gen_highpart (SImode, operands[1]);
+  op2h = gen_highpart_mode (SImode, DImode, operands[2]);
+
+  if (!reg_or_am33_const_operand (op2h, SImode))
+    op2h = force_reg (SImode, op2h);
+
+  emit_insn (gen_adddi3_internal (op0l, op0h, op1l, op2l, op1h, op2h));
+  DONE;
+})
+
+;; Note that reload only supports one commutative operand.  Thus we cannot
+;; auto-swap both the high and low outputs with their matching constraints.
+;; For MN103, we're strapped for registers but thankfully the alternatives
+;; are few.  For AM33, it becomes much easier to not represent the early
+;; clobber and 6 permutations of immediate and three-operand adds, but
+;; instead allocate a scratch register and do the expansion by hand.
+
+(define_insn_and_split "adddi3_internal"
+  [(set (match_operand:SI          0 "register_operand"   "=r, r, r")
+       (plus:SI (match_operand:SI 2 "register_operand"   "%0, 0, r")
+                (match_operand:SI 3 "nonmemory_operand"  "ri,ri,ri")))
+   (set (match_operand:SI          1 "register_operand"   "=D, D, r")
+       (plus:SI
+         (plus:SI
+           (ltu:SI (plus:SI (match_dup 2) (match_dup 3)) (match_dup 2))
+           (match_operand:SI      4 "register_operand"   " 1, D, r"))
+         (match_operand:SI 5 "reg_or_am33_const_operand" " D, 1,ri")))
+   (clobber (match_scratch:SI      6                      "=X, X,&r"))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  rtx op0l = operands[0];
+  rtx op0h = operands[1];
+  rtx op1l = operands[2];
+  rtx op2l = operands[3];
+  rtx op1h = operands[4];
+  rtx op2h = operands[5];
+  rtx scratch = operands[6];
+  rtx x;
+
+  if (reg_overlap_mentioned_p (op0l, op1h))
     {
-    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 ();
+      emit_move_insn (scratch, op0l);
+      op1h = scratch;
+      if (reg_overlap_mentioned_p (op0l, op2h))
+       op2h = scratch;
+    }
+  else if (reg_overlap_mentioned_p (op0l, op2h))
+    {
+      emit_move_insn (scratch, op0l);
+      op2h = scratch;
     }
-  }"
-  [(set_attr "timings" "11,11,11,11,11,11,22")]
+
+  if (rtx_equal_p (op0l, op1l))
+    ;
+  else if (rtx_equal_p (op0l, op2l))
+    x = op1l, op1l = op2l, op2l = x;
+  else
+    {
+      gcc_assert (TARGET_AM33);
+      if (!REG_P (op2l))
+       {
+         emit_move_insn (op0l, op2l);
+         op2l = op1l;
+         op1l = op0l;
+       }
+    }
+  emit_insn (gen_addsi3_flags (op0l, op1l, op2l));
+
+  if (rtx_equal_p (op0h, op1h))
+    ;
+  else if (rtx_equal_p (op0h, op2h))
+    x = op1h, op1h = op2h, op2h = x;
+  else
+    {
+      gcc_assert (TARGET_AM33);
+      if (!REG_P (op2h))
+       {
+         emit_move_insn (op0h, op2h);
+         op2h = op1h;
+         op1h = op0h;
+       }
+    }
+  emit_insn (gen_addc_internal (op0h, op1h, op2h));
+  DONE;
+}
+  [(set_attr "isa" "*,*,am33")]
 )
 
-(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))
-  ]
+;; The following pattern is generated by combine when it proves that one
+;; of the inputs to the low-part of the double-word add is zero, and thus
+;; no carry is generated into the high-part.
+
+(define_insn_and_split "*adddi3_degenerate"
+  [(set (match_operand:SI          0 "register_operand"  "=&r,&r")
+       (match_operand:SI          2 "nonmemory_operand" "  0, 0"))
+   (set (match_operand:SI          1 "register_operand"  "=r , r")
+       (plus:SI (match_operand:SI 3 "register_operand"  "%1 , r")
+                (match_operand:SI 4 "nonmemory_operand" "ri, r")))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
   ""
-  "*
+  [(const_int 0)]
 {
-  switch (which_alternative)
+  rtx scratch = NULL_RTX;
+  if (!rtx_equal_p (operands[0], operands[2]))
     {
-    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 ();
+      if (reg_overlap_mentioned_p (operands[0], operands[3])
+         || reg_overlap_mentioned_p (operands[0], operands[4]))
+       {
+         scratch = gen_reg_rtx (SImode);
+         emit_move_insn (scratch, operands[2]);
+       }
+      else
+       emit_move_insn (operands[0], operands[2]);
     }
-}"
-  [(set_attr "timings" "11,11,11,11,11,22")]
-)
+  emit_insn (gen_addsi3 (operands[1], operands[3], operands[4]));
+  if (scratch)
+    emit_move_insn (operands[0], scratch);
+  DONE;
+})
 
 ;; ----------------------------------------------------------------------
 ;; SUBTRACT INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
-(define_expand "subsi3"
-  [(parallel [(set (match_operand:SI           0 "register_operand")
+(define_insn "subsi3"
+  [(set (match_operand:SI           0 "register_operand"  "=r,r,r,r")
+       (minus:SI (match_operand:SI 1 "register_operand"   "0,0,0,r")
+                 (match_operand:SI 2 "nonmemory_operand"  "r,O,i,r")))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "@
+   sub %2,%0
+   sub %2,%0
+   sub %2,%0
+   sub %2,%1,%0"
+  [(set_attr "isa" "*,*,*,am33")
+   (set_attr "liw" "either,either,*,*")
+   (set_attr "liw_op" "sub")
+   (set_attr "timings" "11,11,11,22")]
+)
+
+(define_insn "*subsi3_flags"
+  [(set (reg CC_REG)
+       (compare (minus:SI (match_operand:SI 1 "register_operand"  "0, r")
+                          (match_operand:SI 2 "nonmemory_operand" "ri,r"))
+                (const_int 0)))
+   (set (match_operand:SI           0 "register_operand"  "=r, r")
+       (minus:SI (match_dup 1) (match_dup 2)))]
+  "reload_completed && mn10300_match_ccmode (insn, CCZNCmode)"
+  "@
+   sub %2,%0
+   sub %2,%1,%0"
+  [(set_attr "isa" "*,am33")
+   (set_attr "timings" "11,22")]
+)
+
+;; A helper to expand the above, with the CC_MODE filled in.
+(define_expand "subsi3_flags"
+  [(parallel [(set (reg:CCZNC CC_REG)
+                  (compare:CCZNC (minus:SI (match_dup 1) (match_dup 2))
+                                 (const_int 0)))
+             (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))
-            ])
-  ]
+                            (match_operand:SI 2 "nonmemory_operand")))])]
   ""
-  "")
-
-(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))
-  ]
-  "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\";
-      }
-  }"
-  [(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))
-  ]
-  ""
-  "sub %2,%0"
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-                                      (const_int 11) (const_int 22)))]
+(define_insn "subc_internal"
+  [(set (match_operand:SI 0 "register_operand"                      "=D,r,r")
+       (minus:SI
+         (minus:SI (match_operand:SI 1 "register_operand"          " 0,0,r")
+                   (match_operand:SI 2 "reg_or_am33_const_operand" " D,i,r"))
+         (geu:SI (reg:CC CC_REG) (const_int 0))))
+   (clobber (reg:CC CC_REG))]
+  "reload_completed"
+  "@
+   subc %2,%0
+   subc %2,%0
+   subc %2,%1,%0"
+  [(set_attr "isa" "*,am33,am33")]
 )
 
-(define_expand "negsi2"
-  [(set (match_operand:SI         0 "register_operand")
-        (neg:SI (match_operand:SI 1 "register_operand")))]
+(define_expand "subdi3"
+  [(set (match_operand:DI 0 "register_operand" "")
+        (minus:DI (match_operand:DI 1 "register_operand" "")
+                  (match_operand:DI 2 "nonmemory_operand" "")))]
   ""
-  "
 {
-  rtx target = gen_reg_rtx (SImode);
+  rtx op0l, op0h, op1l, op1h, op2l, op2h;
 
-  emit_move_insn (target, const0_rtx);
-  emit_insn (gen_subsi3 (target, target, operands[1]));
-  emit_move_insn (operands[0], target);
-  DONE;
-}")
+  op0l = gen_lowpart (SImode, operands[0]);
+  op1l = gen_lowpart (SImode, operands[1]);
+  op2l = gen_lowpart (SImode, operands[2]);
+  op0h = gen_highpart (SImode, operands[0]);
+  op1h = gen_highpart (SImode, operands[1]);
+  op2h = gen_highpart_mode (SImode, DImode, operands[2]);
 
-;; ----------------------------------------------------------------------
-;; MULTIPLY INSTRUCTIONS
-;; ----------------------------------------------------------------------
-
-(define_insn "mulsidi3"
-  [(set (match_operand:DI 0 "register_operand" "=dax")
-        (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "dax"))
-                 (sign_extend:DI (match_operand:SI 2 "register_operand" "dax"))))
-   (clobber (reg:CC CC_REG))
-  ]
-  "TARGET_AM33"
-  "mul %1,%2,%H0,%L0"
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-                                      (const_int 24) (const_int 23)))]
-)
+  if (!reg_or_am33_const_operand (op2h, SImode))
+    op2h = force_reg (SImode, op2h);
 
-(define_insn "umulsidi3"
-  [(set (match_operand:DI                          0 "register_operand" "=dax")
-        (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "dax"))
-                 (zero_extend:DI (match_operand:SI 2 "register_operand" "dax"))))
-   (clobber (reg:CC CC_REG))
-  ]
-  "TARGET_AM33"
-  "mulu %1,%2,%H0,%L0"
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-                                      (const_int 24) (const_int 23)))]
-)
+  emit_insn (gen_subdi3_internal (op0l, op0h, op1l, op1h, op2l, op2h));
+  DONE;
+})
 
-(define_expand "mulsi3"
-  [(parallel [(set (match_operand:SI          0 "register_operand")
-                  (mult:SI (match_operand:SI 1 "register_operand")
-                           (match_operand:SI 2 "register_operand")))
-             (clobber (reg:CC CC_REG))
-            ])
-  ]
+;; As with adddi3, the use of the scratch register helps reduce the 
+;; number of permutations for AM33.
+;; ??? The early clobber on op0 avoids a reload bug wherein both output
+;; registers are set the same.  Consider negate, where both op2 and op3
+;; are 0, are csed to the same input register, and reload fails to undo
+;; the cse when satisfying the matching constraints.
+
+(define_insn_and_split "subdi3_internal"
+  [(set (match_operand:SI     0 "register_operand"         "=&r, r")
+       (minus:SI
+         (match_operand:SI   2 "register_operand"         "  0, r")
+         (match_operand:SI   4 "nonmemory_operand"        " ri,ri")))
+   (set (match_operand:SI     1 "register_operand"         "=D , r")
+       (minus:SI
+         (minus:SI
+           (match_operand:SI 3 "register_operand"         "  1, r")
+           (match_operand:SI 5 "reg_or_am33_const_operand" " D,ri"))
+         (ltu:SI (match_dup 2) (match_dup 4))))
+   (clobber (match_scratch:SI 6                            "=X ,&r"))
+   (clobber (reg:CC CC_REG))]
   ""
-  "")
-
-(define_insn "*am33_mulsi3"
-  [(set (match_operand:SI          0 "register_operand" "=dx,!dax")
-       (mult:SI (match_operand:SI 1 "register_operand" "%0,0")
-                (match_operand:SI 2 "nonmemory_operand" "dx,daxi")))
-   (clobber (reg:CC CC_REG))
-  ]
-  "TARGET_AM33"
-  "*
+  "#"
+  "reload_completed"
+  [(const_int 0)]
 {
-  if (TARGET_MULT_BUG)
-    return \"nop\;nop\;mul %2,%0\";
-  else
-    return \"mul %2,%0\";
-}"
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34") (const_int 24) (const_int 23)))]
-)
+  rtx op0l = operands[0];
+  rtx op0h = operands[1];
+  rtx op1l = operands[2];
+  rtx op1h = operands[3];
+  rtx op2l = operands[4];
+  rtx op2h = operands[5];
+  rtx scratch = operands[6];
+
+  if (reg_overlap_mentioned_p (op0l, op1h))
+    {
+      emit_move_insn (scratch, op0l);
+      op1h = scratch;
+      if (reg_overlap_mentioned_p (op0l, op2h))
+       op2h = scratch;
+    }
+  else if (reg_overlap_mentioned_p (op0l, op2h))
+    {
+      emit_move_insn (scratch, op0l);
+      op2h = scratch;
+    }
 
-(define_insn "*mn10300_mulsi3"
-  [(set (match_operand:SI          0 "register_operand" "=dx")
-       (mult:SI (match_operand:SI 1 "register_operand" "%0")
-                (match_operand:SI 2 "register_operand" "dx")))
-   (clobber (reg:CC CC_REG))
-  ]
-  ""
-  "*
-{
-  if (TARGET_MULT_BUG)
-    return \"nop\;nop\;mul %2,%0\";
-  else
-    return \"mul %2,%0\";
-}"
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-                                      (const_int 24) (const_int 23)))]
-)
+  if (!rtx_equal_p (op0l, op1l))
+    {
+      gcc_assert (TARGET_AM33);
+      if (!REG_P (op2l))
+       {
+         emit_move_insn (op0l, op1l);
+         op1l = op0l;
+       }
+    }
+  emit_insn (gen_subsi3_flags (op0l, op1l, op2l));
 
-(define_expand "udivmodsi4"
-  [(parallel [(set (match_operand:SI          0 "register_operand")
-                  (udiv:SI (match_operand:SI 1 "general_operand")
-                           (match_operand:SI 2 "general_operand")))
-             (set (match_operand:SI          3 "register_operand")
-                  (umod:SI (match_dup 1) (match_dup 2)))
-             (clobber (reg:CC CC_REG))
-            ])
-  ]
-  ""
-  "{
-    if (!register_operand (operands[1], SImode))
-      operands[1] = copy_to_mode_reg (SImode, operands[1]);
-    if (!register_operand (operands[2], SImode))
-      operands[2] = copy_to_mode_reg (SImode, operands[2]);
-   }"
+  if (!rtx_equal_p (op0h, op1h))
+    {
+      gcc_assert (TARGET_AM33);
+      if (!REG_P (op2h))
+       {
+         emit_move_insn (op0h, op1h);
+         op1h = op0h;
+       }
+    }
+  emit_insn (gen_subc_internal (op0h, op1h, op2h));
+  DONE;
+}
+  [(set_attr "isa" "*,am33")]
 )
 
-(define_insn "*udivmodsi4"
-  [(set (match_operand:SI          0 "register_operand" "=dx")
-       (udiv:SI (match_operand:SI 1 "register_operand" "0")
-                (match_operand:SI 2 "register_operand" "dx")))
-   (set (match_operand:SI          3 "register_operand" "=&d")
-       (umod:SI (match_dup 1) (match_dup 2)))
-   (clobber (reg:CC CC_REG))
-  ]
+;; The following pattern is generated by combine when it proves that one
+;; of the inputs to the low-part of the double-word sub is zero, and thus
+;; no carry is generated into the high-part.
+
+(define_insn_and_split "*subdi3_degenerate"
+  [(set (match_operand:SI          0 "register_operand"   "=&r,&r")
+       (match_operand:SI          2 "nonmemory_operand"  "  0, 0"))
+   (set (match_operand:SI          1 "register_operand"   "=r , r")
+       (minus:SI (match_operand:SI 3 "register_operand"  "  1, r")
+                 (match_operand:SI 4 "nonmemory_operand" " ri, r")))
+   (clobber (reg:CC CC_REG))]
   ""
-  "*
+  "#"
+  ""
+  [(const_int 0)]
 {
-  output_asm_insn (\"sub %3,%3\;mov %3,mdr\", operands);
-
-  if (find_reg_note (insn, REG_UNUSED, operands[3]))
-    return \"divu %2,%0\";
-  else
-    return \"divu %2,%0\;mov mdr,%3\";
-}"
-  ;; Timings:  AM33   AM34
-  ;;  SUB       1/1    1/1
-  ;;  MOV       1/1    1/1
-  ;;  DIVU     38/39  42/43
-  ;;  MOV       1/1    1/1
-  ;;  --------------------
-  ;;  total    41/42  45/46  (worst case sceanario)
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-                                      (const_int 4546) (const_int 4142)))]
-)
+  rtx scratch = NULL_RTX;
+  if (!rtx_equal_p (operands[0], operands[2]))
+    {
+      gcc_assert (!reg_overlap_mentioned_p (operands[0], operands[1]));
+      if (reg_overlap_mentioned_p (operands[0], operands[3])
+         || reg_overlap_mentioned_p (operands[0], operands[4]))
+       {
+         scratch = gen_reg_rtx (SImode);
+         emit_move_insn (scratch, operands[2]);
+       }
+      else
+       emit_move_insn (operands[0], operands[2]);
+    }
+  emit_insn (gen_subsi3 (operands[1], operands[3], operands[4]));
+  if (scratch)
+    emit_move_insn (operands[0], scratch);
+  DONE;
+})
 
-(define_insn "divmodsi4"
-  [(set (match_operand:SI          0 "register_operand" "=dx")
-       (div:SI (match_operand:SI  1 "register_operand"  "0")
-                (match_operand:SI 2 "register_operand"  "dx")))
-   (set (match_operand:SI          3 "register_operand" "=d")
-       (mod:SI (match_dup 1) (match_dup 2)))
-   (clobber (reg:CC CC_REG))
-  ]
+(define_insn_and_split "negsi2"
+  [(set (match_operand:SI         0 "register_operand"  "=D,&r")
+       (neg:SI (match_operand:SI 1 "register_operand"  " 0, r")))
+   (clobber (reg:CC CC_REG))]
   ""
-  "*
+  "#"
+  "&& reload_completed"
+  [(const_int 0)]
 {
-  if (find_reg_note (insn, REG_UNUSED, operands[3]))
-    return \"ext %0\;div %2,%0\";
+  /* Recall that twos-compliment is ones-compliment plus one.  When
+     allocated in DATA_REGS this is 2+1 bytes; otherwise (for am33)
+     this is 3+3 bytes.
+
+     For AM33, it would have been possible to load zero and use the
+     three-address subtract to have a total size of 3+4*N bytes for
+     multiple negations, plus increased throughput.  Not attempted here.  */
+     
+  if (true_regnum (operands[0]) == true_regnum (operands[1]))
+    {
+      emit_insn (gen_one_cmplsi2 (operands[0], operands[0]));
+      emit_insn (gen_addsi3 (operands[0], operands[0], const1_rtx));
+    }
   else
-    return \"ext %0\;div %2,%0\;mov mdr,%3\";
-}"
-  ;; Timings:  AM33   AM34
-  ;;  EXT       1/1    1/1
-  ;;  DIV      38/39  42/43
-  ;;  --------------------
-  ;;  total    39/40  43/44  (worst case sceanario)
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-                                      (const_int 4344) (const_int 3940)))]
-)
+    {
+      emit_move_insn (operands[0], const0_rtx);
+      emit_insn (gen_subsi3 (operands[0], operands[0], operands[1]));
+    }
+  DONE;
+})
 
-\f
 ;; ----------------------------------------------------------------------
-;; AND INSTRUCTIONS
+;; MULTIPLY INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
-(define_expand "andsi3"
-  [(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))
-            ])
-  ]
-  ""
-  "")
-
-(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";
-
-    return "and %2, %0";
-  }
-  [(set_attr "timings" "33")]
-)
+;; ??? Note that AM33 has a third multiply variant that puts the high part
+;; into the MDRQ register, however this variant also constrains the inputs
+;; to be in DATA_REGS and thus isn't as helpful as it might be considering
+;; the existence of the 4-operand multiply.  Nor is there a set of divide
+;; insns that use MDRQ.  Given that there is an IMM->MDRQ insn, this would
+;; have been very handy for starting udivmodsi4...
 
-(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))
-  ]
+(define_expand "mulsidi3"
+  [(set (match_operand:DI 0 "register_operand" "")
+        (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" ""))
+                 (sign_extend:DI (match_operand:SI 2 "register_operand" ""))))]
   ""
-  {
-    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";
-       }
+{
+  emit_insn (gen_mulsidi3_internal (gen_lowpart (SImode, operands[0]),
+                                   gen_highpart (SImode, operands[0]),
+                                   operands[1], operands[2]));
+  DONE;
+})
 
-    return "and %2, %0";
-  }
-  [(set_attr "timings" "33")]
+(define_insn "mulsidi3_internal"
+  [(set (match_operand:SI          0 "register_operand" "=D,r")
+       (mult:SI (match_operand:SI 2 "register_operand" "%0,r")
+                (match_operand:SI 3 "register_operand" " D,r")))
+   (set (match_operand:SI          1 "register_operand" "=z,r")
+       (truncate:SI
+         (ashiftrt:DI
+           (mult:DI (sign_extend:DI (match_dup 2))
+                    (sign_extend:DI (match_dup 3)))
+           (const_int 32))))
+   (clobber (reg:CC CC_REG))]
+  ""
+{
+  if (which_alternative == 1)
+    return "mul %2,%3,%1,%0";
+  else if (TARGET_MULT_BUG)
+    return "nop\;nop\;mul %3,%0";
+  else
+    return "mul %3,%0";
+}
+  [(set_attr "isa" "*,am33")
+   (set (attr "timings")
+        (if_then_else (eq_attr "cpu" "am34") (const_int 24) (const_int 23)))]
 )
 
-;; ----------------------------------------------------------------------
-;; OR INSTRUCTIONS
-;; ----------------------------------------------------------------------
-
-(define_expand "iorsi3"
-  [(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))
-            ])
-  ]
+(define_expand "umulsidi3"
+  [(set (match_operand:DI 0 "register_operand" "")
+        (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" ""))
+                 (zero_extend:DI (match_operand:SI 2 "register_operand" ""))))
+   (clobber (reg:CC CC_REG))]
   ""
-  "")
+{
+  emit_insn (gen_umulsidi3_internal (gen_lowpart (SImode, operands[0]),
+                                    gen_highpart (SImode, operands[0]),
+                                    operands[1], operands[2]));
+  DONE;
+})
 
-(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 "umulsidi3_internal"
+  [(set (match_operand:SI          0 "register_operand" "=D,r")
+       (mult:SI (match_operand:SI 2 "register_operand" "%0,r")
+                (match_operand:SI 3 "register_operand" " D,r")))
+   (set (match_operand:SI          1 "register_operand" "=z,r")
+       (truncate:SI
+         (lshiftrt:DI
+           (mult:DI (zero_extend:DI (match_dup 2))
+                    (zero_extend:DI (match_dup 3)))
+           (const_int 32))))
+   (clobber (reg:CC CC_REG))]
   ""
-  "or %2,%0"
-  [(set_attr "timings" "33")]
+{
+  if (which_alternative == 1)
+    return "mulu %2,%3,%1,%0";
+  else if (TARGET_MULT_BUG)
+    return "nop\;nop\;mulu %3,%0";
+  else
+    return "mulu %3,%0";
+}
+  [(set_attr "isa" "*,am33")
+   (set (attr "timings")
+        (if_then_else (eq_attr "cpu" "am34") (const_int 24) (const_int 23)))]
 )
 
-;; ----------------------------------------------------------------------
-;; XOR INSTRUCTIONS
-;; ----------------------------------------------------------------------
-
-(define_expand "xorsi3"
-  [(parallel [(set (match_operand:SI         0 "register_operand")
-                  (xor:SI (match_operand:SI 1 "register_operand")
-                          (match_operand:SI 2 "nonmemory_operand")))
-             (clobber (reg:CC CC_REG))
-            ])
-  ]
-  ""
-  "")
-
-(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_expand "mulsi3"
+  [(parallel [(set (match_operand:SI          0 "register_operand")
+                  (mult:SI (match_operand:SI 1 "register_operand")
+                           (match_operand:SI 2 "reg_or_am33_const_operand")))
+             (clobber (match_scratch:SI      3))
+             (clobber (reg:CC CC_REG))])]
   ""
-  "xor %2,%0"
-  [(set_attr "timings" "11")]
 )
 
-;; ----------------------------------------------------------------------
-;; NOT INSTRUCTIONS
-;; ----------------------------------------------------------------------
-
-(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))
-            ])
-  ]
+(define_insn "*mulsi3"
+  [(set (match_operand:SI          0 "register_operand"          "=D, r,r")
+       (mult:SI (match_operand:SI 2 "register_operand"          "%0, 0,r")
+                (match_operand:SI 3 "reg_or_am33_const_operand" " D,ri,r")))
+   (clobber (match_scratch:SI      1                             "=z, z,r"))
+   (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))
-  ]
-  "TARGET_AM33"
-  "not %0"
+{
+  if (which_alternative == 2)
+    return "mul %2,%3,%1,%0";
+  else if (TARGET_MULT_BUG)
+    return "nop\;nop\;mul %3,%0";
+  else
+    return "mul %3,%0";
+}
+  [(set_attr "isa" "*,am33,am33")
+   (set (attr "timings")
+       (if_then_else (eq_attr "cpu" "am34") (const_int 24) (const_int 23)))]
 )
 
-(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))
-  ]
+(define_expand "udivmodsi4"
+  [(parallel [(set (match_operand:SI          0 "register_operand")
+                  (udiv:SI (match_operand:SI 1 "register_operand")
+                           (match_operand:SI 2 "register_operand")))
+             (set (match_operand:SI          3 "register_operand")
+                  (umod:SI (match_dup 1) (match_dup 2)))
+             (use (const_int 0))
+             (clobber (reg:CC CC_REG))])]
   ""
-  "not %0"
 )
-\f
-;; -----------------------------------------------------------------
-;; BIT FIELDS
-;; -----------------------------------------------------------------
 
+;; Note the trick to get reload to put the zero into the MDR register,
+;; rather than exposing the load early and letting CSE or someone try
+;; to share the zeros between division insns.  Which tends to result
+;; in sequences like 0->r0->d0->mdr.
 
-;; These set/clear memory in byte sized chunks.
-;;
-;; They are no smaller/faster than loading the value into a register
-;; and storing the register, but they don't need a scratch register
-;; which may allow for better code generation.
-(define_insn "*byte_clear"
-  [(set (match_operand:QI 0 "nonimmediate_operand" "=R,d") (const_int 0))
-   (clobber (reg:CC CC_REG))
-   ]
-  "(! MEM_P (operands[0])) || (! MEM_VOLATILE_P (operands[0])
-                               && GET_CODE (XEXP (operands[0], 0)) != PLUS)"
-  "@
-  bclr 255,%A0
-  clr %0"
-  [(set_attr_alternative "timings"
-                        [(if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 66) (const_int 77))
-                         (const_int 11)
-                        ])
-  ]
-)
-
-(define_insn "*byte_set"
-  [(set (match_operand:QI 0 "nonimmediate_operand" "=R,d") (const_int -1))
-   (clobber (reg:CC CC_REG))
-  ]
-  "(! MEM_P (operands[0])) || (! MEM_VOLATILE_P (operands[0])
-                               && GET_CODE (XEXP (operands[0], 0)) != PLUS)"
-  "@
-  bset 255,%A0
-  mov -1,%0"
-  [(set_attr_alternative "timings"
-                        [(if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 66) (const_int 77))
-                         (const_int 11)
-                        ])
-  ]
+(define_insn "*udivmodsi4"
+  [(set (match_operand:SI          0 "register_operand" "=D")
+       (udiv:SI (match_operand:SI 2 "register_operand" " 0")
+                (match_operand:SI 3 "register_operand" " D")))
+   (set (match_operand:SI          1 "register_operand" "=z")
+       (umod:SI (match_dup 2) (match_dup 3)))
+   (use (match_operand:SI          4 "nonmemory_operand" " 1"))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "divu %3,%0"
+  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+                                      (const_int 3839) (const_int 4243)))]
 )
 
-(define_insn "*bit_clear1"
-  [(set (match_operand:QI 0 "nonimmediate_operand" "+R,d")
-       (subreg:QI
-         (and:SI (subreg:SI (match_dup 0) 0)
-                 (match_operand:SI 1 "const_int_operand" "i,i")) 0))
-   (clobber (reg:CC CC_REG))
-  ]
+(define_expand "divmodsi4"
+  [(parallel [(set (match_operand:SI          0 "register_operand" "")
+                  (div:SI (match_operand:SI  1 "register_operand" "")
+                          (match_operand:SI  2 "register_operand" "")))
+             (set (match_operand:SI          3 "register_operand" "")
+                  (mod:SI (match_dup 1) (match_dup 2)))
+             (use (match_dup 4))
+             (clobber (reg:CC CC_REG))])]
   ""
-  "@
-  bclr %N1,%A0
-  and %1,%0"
-  [(set_attr_alternative "timings"
-                        [(if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 66) (const_int 77))
-                         (const_int 11)
-                        ])
-  ]
-)
+{
+  operands[4] = gen_reg_rtx (SImode);
+  emit_insn (gen_ext_internal (operands[4], operands[1]));
+})
 
-(define_insn "*bit_clear2"
-  [(set (match_operand:QI 0 "memory_operand" "=R,T")
-       (and:QI
-        (match_dup 0)
-        (not:QI (match_operand:QI 1 "nonmemory_operand" "i,d"))))
-   (clobber (reg:CC CC_REG))
-  ]
+;; ??? Ideally we'd represent this via shift, but it seems like adding a
+;; special-case pattern for (ashiftrt x 31) is just as likely to result
+;; in poor register allocation choices.
+(define_insn "ext_internal"
+  [(set (match_operand:SI 0 "register_operand" "=z")
+       (unspec:SI [(match_operand:SI 1 "register_operand" "D")] UNSPEC_EXT))]
   ""
-  "@
-  bclr %U1,%A0
-  bclr %1,%0"
-  [(set_attr_alternative "timings"
-                        [(if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 66) (const_int 77))
-                         (const_int 66)
-                        ])
-  ]
+  "ext %1"
 )
 
-(define_insn "*bit_set"
-  [(set (match_operand:QI 0 "nonimmediate_operand" "+R,d")
-       (subreg:QI
-         (ior:SI (subreg:SI (match_dup 0) 0)
-                 (match_operand:SI 1 "const_int_operand" "i,i")) 0))
-   (clobber (reg:CC CC_REG))
-  ]
+(define_insn "*divmodsi4"
+  [(set (match_operand:SI          0 "register_operand" "=D")
+       (div:SI (match_operand:SI  2 "register_operand" " 0")
+               (match_operand:SI  3 "register_operand" " D")))
+   (set (match_operand:SI          1 "register_operand" "=z")
+       (mod:SI (match_dup 2) (match_dup 3)))
+   (use (match_operand:SI          4 "register_operand" " 1"))
+   (clobber (reg:CC CC_REG))]
   ""
-  "@
-  bset %U1,%A0
-  or %1,%0"
-  [(set_attr_alternative "timings"
-                        [(if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 66) (const_int 77))
-                         (const_int 11)
-                        ])
-  ]
+  "div %3,%0";
+  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+                                      (const_int 3839) (const_int 4243)))]
 )
 
-(define_expand "iorqi3"
-  [(parallel [(set (match_operand:QI         0 "nonimmediate_operand")
-                  (ior:QI (match_operand:QI 1 "nonimmediate_operand")
-                          (match_operand:QI 2 "nonmemory_operand")))
-             (clobber (reg:CC CC_REG))
-            ])
-  ]
+\f
+;; ----------------------------------------------------------------------
+;; AND INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+(define_insn "andsi3"
+  [(set (match_operand:SI         0 "register_operand"  "=D,D,r")
+       (and:SI (match_operand:SI 1 "register_operand"  "%0,0,r")
+               (match_operand:SI 2 "nonmemory_operand" " i,D,r")))
+   (clobber (reg:CC CC_REG))]
   ""
-  "")
-
-(define_insn "*am33_iorqi3"
-  [(set (match_operand:QI         0 "nonimmediate_operand" "=R,T,r")
-       (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0")
-               ;; This constraint should really be nonmemory_operand,
-               ;; but making it general_operand, along with the
-               ;; condition that not both input operands are MEMs,
-               ;; helps combine do a better job.
-               (match_operand:QI 2 "general_operand" "i,d,ir")))
-   (clobber (reg:CC CC_REG))
-  ]
-  "TARGET_AM33 && 
-   ((! MEM_P (operands[2])) || (! MEM_P (operands[1])))"
   "@
-  bset %U2,%A0
-  bset %2,%0
-  or %2,%0"
-  [(set_attr_alternative "timings"
-                        [(if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 66) (const_int 77))
-                         (const_int 66)
-                         (const_int 11)
-                        ])
-  ]
-)
-
-(define_insn "*mn10300_iorqi3"
-  [(set (match_operand:QI         0 "nonimmediate_operand" "=R,T,d")
-       (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0")
-               ;; This constraint should really be nonmemory_operand,
-               ;; but making it general_operand, along with the
-               ;; condition that not both input operands are MEMs,
-               ;; helps combine do a better job.
-               (match_operand:QI 2 "general_operand" "i,d,id")))
-   (clobber (reg:CC CC_REG))
-  ]
-  "(! MEM_P (operands[2])) || (! MEM_P (operands[1]))"
+   and %2,%0
+   and %2,%0
+   and %2,%1,%0"
+  [(set_attr "isa" "*,*,am33")
+   (set_attr "liw" "*,op1,*")
+   (set_attr "liw_op" "and")
+   (set_attr "timings" "22,11,11")]
+)
+
+(define_insn "*andsi3_flags"
+  [(set (reg CC_REG)
+       (compare (and:SI (match_operand:SI 1 "register_operand"  "%0,0,r")
+                        (match_operand:SI 2 "nonmemory_operand" " i,D,r"))
+                (const_int 0)))
+   (set (match_operand:SI         0 "register_operand"  "=D,D,r")
+       (and:SI (match_dup 1) (match_dup 2)))]
+  "reload_completed && mn10300_match_ccmode (insn, CCZNmode)"
   "@
-  bset %U2,%A0
-  bset %2,%0
-  or %2,%0"
-  [(set_attr_alternative "timings"
-                        [(if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 66) (const_int 77))
-                         (const_int 66)
-                         (const_int 11)
-                        ])
-  ]
+   and %2,%0
+   and %2,%0
+   and %2,%1,%0"
+  [(set_attr "isa" "*,*,am33")
+   (set_attr "timings" "22,11,11")]
 )
 
-(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];
+;; Make sure we generate extensions instead of ANDs.
 
-  while (len > 0)
-    {
-      mask |= (1 << bit);
-      bit++;
-      len--;
-    }
+(define_split
+  [(parallel [(set (match_operand:SI 0 "register_operand" "")
+                  (and:SI (match_operand:SI 1 "register_operand" "")
+                          (const_int 255)))
+             (clobber (reg:CC CC_REG))])]
+  ""
+  [(set (match_dup 0) (zero_extend:SI (match_dup 1)))]
+  { operands[1] = gen_lowpart (QImode, operands[1]); }
+)
 
-  xoperands[0] = operands[0];
-  xoperands[1] = GEN_INT (trunc_int_for_mode (mask, SImode));
-  output_asm_insn (\"btst %1,%0\", xoperands);
-  return \"\";
-}"
+(define_split
+  [(parallel [(set (match_operand:SI 0 "register_operand" "")
+                  (and:SI (match_operand:SI 1 "register_operand" "")
+                          (const_int 65535)))
+             (clobber (reg:CC CC_REG))])]
+  ""
+  [(set (match_dup 0) (zero_extend:SI (match_dup 1)))]
+  { operands[1] = gen_lowpart (HImode, operands[1]); }
 )
 
-(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];
+;; Split AND by an appropriate constant into two shifts.  Recall that 
+;; operations with a full 32-bit immediate require an extra cycle, so
+;; this is a size optimization with no speed penalty.  This only applies
+;; do DATA_REGS; the shift insns that AM33 adds are too large for a win.
 
-  while (len > 0)
+(define_split
+  [(parallel [(set (match_operand:SI 0 "register_operand" "")
+                  (and:SI (match_dup 0)
+                          (match_operand:SI 1 "const_int_operand" "")))
+             (clobber (reg:CC CC_REG))])]
+  "reload_completed
+   && REGNO_DATA_P (true_regnum (operands[0]), 1)
+   && mn10300_split_and_operand_count (operands[1]) != 0"
+  [(const_int 0)]
+{
+  int count = mn10300_split_and_operand_count (operands[1]);
+  if (count > 0)
     {
-      mask |= (1 << bit);
-      bit++;
-      len--;
+      emit_insn (gen_lshrsi3 (operands[0], operands[0], GEN_INT (count)));
+      emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (count)));
     }
-
-  /* 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]))
+  else
     {
-      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;
+      emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (-count)));
+      emit_insn (gen_lshrsi3 (operands[0], operands[0], GEN_INT (-count)));
     }
+  DONE;
+})
 
-  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))
-                        ])
-  ]
-)
+;; ----------------------------------------------------------------------
+;; OR INSTRUCTIONS
+;; ----------------------------------------------------------------------
 
-(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)))
-  ]
+(define_insn "iorsi3"
+  [(set (match_operand:SI         0 "register_operand"  "=D,D,r")
+       (ior:SI (match_operand:SI 1 "register_operand"  "%0,0,r")
+               (match_operand:SI 2 "nonmemory_operand" " i,D,r")))
+   (clobber (reg:CC CC_REG))]
   ""
-  "btst %1,%0"
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-                                      (const_int 11) (const_int 22)))]
+  "@
+   or %2,%0
+   or %2,%0
+   or %2,%1,%0"
+  [(set_attr "isa" "*,*,am33")
+   (set_attr "liw" "*,op1,*")
+   (set_attr "liw_op" "or")
+   (set_attr "timings" "22,11,11")]
+)
+
+(define_insn "*iorsi3_flags"
+  [(set (reg CC_REG)
+       (compare (ior:SI (match_operand:SI 1 "register_operand"  "%0,0,r")
+                        (match_operand:SI 2 "nonmemory_operand" " i,D,r"))
+                (const_int 0)))
+   (set (match_operand:SI         0 "register_operand"  "=D,D,r")
+       (ior:SI (match_dup 1) (match_dup 2)))]
+  "reload_completed && mn10300_match_ccmode (insn, CCZNmode)"
+  "@
+   or %2,%0
+   or %2,%0
+   or %2,%1,%0"
+  [(set_attr "isa" "*,*,am33")
+   (set_attr "timings" "22,11,11")]
 )
 
-(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)))]
+;; ----------------------------------------------------------------------
+;; XOR INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+(define_insn "xorsi3"
+  [(set (match_operand:SI         0 "register_operand"  "=D,D,r")
+       (xor:SI (match_operand:SI 1 "register_operand"  "%0,0,r")
+               (match_operand:SI 2 "nonmemory_operand" " i,D,r")))
+   (clobber (reg:CC CC_REG))]
   ""
   "@
-  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))
-                        ])
-  ]
+   xor %2,%0
+   xor %2,%0
+   xor %2,%1,%0"
+  [(set_attr "isa" "*,*,am33")
+   (set_attr "liw" "*,op1,*")
+   (set_attr "liw_op" "xor")
+   (set_attr "timings" "22,11,11")]
+)
+
+(define_insn "*xorsi3_flags"
+  [(set (reg CC_REG)
+       (compare (xor:SI (match_operand:SI 1 "register_operand"  "%0,0,r")
+                        (match_operand:SI 2 "nonmemory_operand" " i,D,r"))
+                (const_int 0)))
+   (set (match_operand:SI         0 "register_operand"  "=D,D,r")
+       (xor:SI (match_dup 1) (match_dup 2)))]
+  "reload_completed && mn10300_match_ccmode (insn, CCZNmode)"
+  "@
+   xor %2,%0
+   xor %2,%0
+   xor %2,%1,%0"
+  [(set_attr "isa" "*,*,am33")
+   (set_attr "timings" "22,11,11")]
+)
+
+;; ----------------------------------------------------------------------
+;; NOT INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+(define_insn "one_cmplsi2"
+  [(set (match_operand:SI         0 "register_operand" "=D")
+       (not:SI (match_operand:SI 1 "register_operand" " 0")))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "not %0"
 )
 
+(define_insn "*one_cmplsi2_flags"
+  [(set (reg CC_REG)
+       (compare (not:SI (match_operand:SI 1 "register_operand" "0"))
+                (const_int 0)))
+   (set (match_operand:SI         0 "register_operand" "=D")
+       (not:SI (match_dup 1)))]
+  "reload_completed && mn10300_match_ccmode (insn, CCZNmode)"
+  "not %0"
+)
 \f
 ;; ----------------------------------------------------------------------
 ;; COMPARE AND BRANCH INSTRUCTIONS
              (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 "" ""))
-                     (pc)))
-   ]
+                       [(match_operand:SI       0 "register_operand"  "r")
+                       (match_operand:SI       1 "nonmemory_operand" "ri")])
+                     (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]));
-  "
-)
-
-;; 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
-;; instruction must be distinct registers.  In the case where we'd
-;; like to compare a register to itself, we can achieve this effect
-;; with a btst 0,d0 instead.  (This will not alter the contents of d0
-;; but will have the proper effect on cc0.  Using d0 is arbitrary; any
-;; data register would work.)
-
-;; Even though the first alternative would be preferable if it can
-;; possibly match, reload must not be given the opportunity to attempt
-;; to use it.  It assumes that such matches can only occur when one of
-;; the operands is used for input and the other for output.  Since
-;; this is not the case, it abort()s.  Indeed, such a reload cannot be
-;; possibly satisfied, so just mark the alternative with a `!', so
-;; that it is not considered by reload.
+{
+  mn10300_split_cbranch (CCmode, operands[3], operands[2]);
+  DONE;
+})
 
 (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\";
-  }
+  [(set (reg CC_REG)
+       (compare (match_operand:SI 0 "register_operand"  "r,r,r")
+                (match_operand:SI 1 "nonmemory_operand" "r,O,i")))]
+  "reload_completed"
+{
+  /* The operands of CMP must be distinct registers.  In the case where
+     we've failed to optimize the comparison of a register to itself, we
+     must use another method to set the Z flag.  We can achieve this 
+     effect with a BTST 0,D0.  This will not alter the contents of D0;
+     the use of d0 is arbitrary; any data register would work.  */
+  if (rtx_equal_p (operands[0], operands[1]))
+    return "btst 0,d0";
+  else
+    return "cmp %1,%0";
+}
   [(set_attr_alternative "timings"
-                        [(const_int 11)
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 11) (const_int 22))
-                         (const_int 22)
-                        ])
-  ]
+     [(if_then_else (eq_attr "cpu" "am34") (const_int 11) (const_int 22))
+      (if_then_else (eq_attr "cpu" "am34") (const_int 11) (const_int 22))
+      (if_then_else (eq_attr "cpu" "am34") (const_int 11) (const_int 22))])
+   (set_attr "liw" "either,either,*")
+   (set_attr "liw_op" "cmp")]
 )
 
-(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 "CCZN_comparison_operator"
+           [(and:SI (match_operand:SI 0 "register_operand" "D")
+                    (match_operand:SI 1 "immediate_operand" "i"))
+            (const_int 0)])
+         (match_operand 2 "label_ref_operand" "")
+         (pc)))]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  mn10300_split_cbranch (CCZNmode, operands[3], operands[2]);
+  DONE;
+})
+
+(define_insn "*btstsi"
+  [(set (reg:CCZN CC_REG)
+       (compare:CCZN
+         (and:SI (match_operand:SI 0 "register_operand" "D")
+                 (match_operand:SI 1 "immediate_operand" "i"))
+         (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]));
-  "
-)
-
-(define_insn "am33_cmpsf"
+{
+  mn10300_split_cbranch (CC_FLOATmode, operands[3], operands[2]);
+  DONE;
+})
+
+(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)))]
 (define_expand "builtin_setjmp_receiver"
   [(match_operand 0 "" "")]
   "flag_pic"
-  "
 {
-  if (flag_pic)
-    emit_insn (gen_GOTaddr2picreg ());
-
+  emit_insn (gen_load_pic ());
   DONE;
-}")
+})
 
 (define_expand "casesi"
   [(match_operand:SI 0 "register_operand")
    (match_operand:SI 2 "immediate_operand")
    (match_operand 3 "" "") (match_operand 4 "")]
   ""
-  "
 {
   rtx table = gen_reg_rtx (SImode);
   rtx index = gen_reg_rtx (SImode);
 
   emit_jump_insn (gen_tablejump (addr, operands[3]));
   DONE;
-}")
+})
 
 (define_insn "tablejump"
   [(set (pc) (match_operand:SI 0 "register_operand" "a"))
               (match_operand 1 "")
               (match_operand 2 "")])]
   ""
-  "
 {
   int i;
 
       emit_move_insn (SET_DEST (set), SET_SRC (set));
     }
   DONE;
-}")
+})
 
 (define_insn "nop"
   [(const_int 0)]
 ;; EXTEND INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
-(define_expand "zero_extendqisi2"
-  [(set (match_operand:SI 0 "register_operand")
-       (zero_extend:SI
-        (match_operand:QI 1 "nonimmediate_operand")))]
-  ""
-  "")
-
-(define_insn "*zero_extendqisi2_am33"
-  [(set (match_operand:SI 0 "register_operand" "=dx,dx,dx,!dax,!dax,!dax")
-       (zero_extend:SI
-        (match_operand:QI 1 "nonimmediate_operand" "0,dax,m,0,dax,m")))]
-  "TARGET_AM33"
-  "@
-  extbu %0
-  mov %1,%0\;extbu %0
-  movbu %1,%0
-  extbu %0
-  mov %1,%0\;extbu %0
-  movbu %1,%0"
-  [(set_attr_alternative "timings"
-                        [(const_int 11)
-                         (const_int 22)
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 13) (const_int 24))
-                         (const_int 11)
-                         (const_int 22)
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 13) (const_int 24))
-                        ])
-  ]
-)
-
-(define_insn "*zero_extendqisi2_mn10300"
-  [(set (match_operand:SI 0 "register_operand" "=dx,dx,dx")
-       (zero_extend:SI
-        (match_operand:QI 1 "nonimmediate_operand" "0,d,m")))]
-  ""
-  "@
-  extbu %0
-  mov %1,%0\;extbu %0
-  movbu %1,%0"
-  [(set_attr_alternative "timings"
-                        [(const_int 11)
-                         (const_int 22)
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 13) (const_int 24))
-                        ])
-  ]
-)
-
-(define_expand "zero_extendhisi2"
-  [(set (match_operand:SI 0 "register_operand")
+(define_insn "zero_extendqisi2"
+  [(set (match_operand:SI 0 "register_operand"      "=D,D,r")
        (zero_extend:SI
-        (match_operand:HI 1 "nonimmediate_operand")))]
+        (match_operand:QI 1 "nonimmediate_operand" " 0,m,r")))]
   ""
-  "")
-
-(define_insn "*zero_extendhisi2_am33"
-  [(set (match_operand:SI 0 "register_operand" "=dx,dx,dx,!dax,!dax,!dax")
-       (zero_extend:SI
-        (match_operand:HI 1 "nonimmediate_operand" "0,dax,m,0,dax,m")))]
-  "TARGET_AM33"
   "@
-  exthu %0
-  mov %1,%0\;exthu %0
-  movhu %1,%0
-  exthu %0
-  mov %1,%0\;exthu %0
-  movhu %1,%0"
-  [(set_attr_alternative "timings"
-                        [(const_int 11)
-                         (const_int 22)
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 13) (const_int 24))
-                         (const_int 11)
-                         (const_int 22)
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 13) (const_int 24))
-                        ])
-  ]
-)
-
-(define_insn "*zero_extendhisi2_mn10300"
-  [(set (match_operand:SI 0 "register_operand" "=dx,dx,dx")
+   extbu %0
+   movbu %1,%0
+   extbu %1,%0"
+  [(set_attr "isa" "*,*,am33")
+   (set_attr_alternative "timings"
+                [(const_int 11)
+                 (if_then_else (eq_attr "cpu" "am34")
+                               (const_int 13) (const_int 24))
+                 (const_int 11)
+                ])]
+)
+
+(define_insn "zero_extendhisi2"
+  [(set (match_operand:SI 0 "register_operand"      "=D,D,r")
        (zero_extend:SI
-        (match_operand:HI 1 "nonimmediate_operand" "0,dx,m")))]
-  ""
-  "@
-  exthu %0
-  mov %1,%0\;exthu %0
-  movhu %1,%0"
-  [(set_attr_alternative "timings"
-                        [(const_int 11)
-                         (const_int 22)
-                         (if_then_else (eq_attr "cpu" "am34")
-                                       (const_int 13) (const_int 24))
-                        ])
-  ]
-)
-
-;;- sign extension instructions
-
-(define_expand "extendqisi2"
-  [(set (match_operand:SI 0 "register_operand")
-       (sign_extend:SI
-        (match_operand:QI 1 "register_operand")))]
-  ""
-  "")
-
-(define_insn "*extendqisi2_am33"
-  [(set (match_operand:SI 0 "register_operand" "=dx,dx,!dax,!dax")
-       (sign_extend:SI
-        (match_operand:QI 1 "register_operand" "0,dx,0,dax")))]
-  "TARGET_AM33"
-  "@
-  extb %0
-  mov %1,%0\;extb %0
-  extb %0
-  mov %1,%0\;extb %0"
-  [(set_attr "timings" "11,22,11,22")]
-)
-
-(define_insn "*extendqisi2_mn10300"
-  [(set (match_operand:SI 0 "register_operand" "=dx,dx")
-       (sign_extend:SI
-        (match_operand:QI 1 "register_operand" "0,dx")))]
+        (match_operand:HI 1 "nonimmediate_operand" " 0,m,r")))]
   ""
   "@
-  extb %0
-  mov %1,%0\;extb %0"
-  [(set_attr "timings" "11,22")]
-)
-
-(define_expand "extendhisi2"
-  [(set (match_operand:SI 0 "register_operand")
+   exthu %0
+   movhu %1,%0
+   exthu %1,%0"
+  [(set_attr "isa" "*,*,am33")
+   (set_attr_alternative "timings"
+                [(const_int 11)
+                 (if_then_else (eq_attr "cpu" "am34")
+                               (const_int 13) (const_int 24))
+                 (const_int 11)])]
+)
+
+(define_insn "extendqisi2"
+  [(set (match_operand:SI 0 "register_operand" "=D,r")
        (sign_extend:SI
-        (match_operand:HI 1 "register_operand")))]
+        (match_operand:QI 1 "register_operand" "0,r")))]
   ""
-  "")
-
-(define_insn "*extendhisi2_am33"
-  [(set (match_operand:SI 0 "register_operand" "=dx,dx,!dax,!dax")
-       (sign_extend:SI
-        (match_operand:HI 1 "register_operand" "0,dax,0,dax")))]
-  "TARGET_AM33"
   "@
-  exth %0
-  mov %1,%0\;exth %0
-  exth %0
-  mov %1,%0\;exth %0"
-  [(set_attr "timings" "11,22,11,22")]
+   extb %0
+   extb %1,%0"
+  [(set_attr "isa" "*,am33")]
 )
 
-(define_insn "*extendhisi2_mn10300"
-  [(set (match_operand:SI 0 "register_operand" "=dx,dx")
+(define_insn "extendhisi2"
+  [(set (match_operand:SI 0 "register_operand" "=D,r")
        (sign_extend:SI
-        (match_operand:HI 1 "register_operand" "0,dx")))]
+        (match_operand:HI 1 "register_operand" "0,r")))]
   ""
   "@
-  exth %0
-  mov %1,%0\;exth %0"
-  [(set_attr "timings" "11,22")]
+   exth %0
+   exth %1,%0"
+  [(set_attr "isa" "*,am33")]
 )
 \f
 ;; ----------------------------------------------------------------------
 ;; SHIFTS
 ;; ----------------------------------------------------------------------
 
-(define_expand "ashlsi3"
-  [(parallel [(set (match_operand:SI 0 "register_operand")
-                  (ashift:SI
-                   (match_operand:SI 1 "register_operand")
-                   (match_operand:QI 2 "nonmemory_operand")))
-             (clobber (reg:CC CC_REG))
-            ])
-  ]
-  ""
-  "")
-
-(define_insn "*am33_ashlsi3"
-  [(set (match_operand:SI 0 "register_operand" "=dax,dx,!dax")
+(define_insn "ashlsi3"
+  [(set (match_operand:SI  0 "register_operand"   "=r,D,d,d,D,D,D,r")
        (ashift:SI
-        (match_operand:SI 1 "register_operand" "0,0,dax")
-        (match_operand:QI 2 "nonmemory_operand" "J,dxi,dax")))
-   (clobber (reg:CC CC_REG))
-  ]
-  "TARGET_AM33"
-  "*
-  {
-    if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) == 1)
-      return \"add %0,%0\";
-
-    if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) == 2)
-      return \"asl2 %0\";
-
-    if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) == 3
-        && REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS)
-      return \"asl2 %0\;add %0,%0\";
-
-    if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) == 4
-        && REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS)
-      return \"asl2 %0\;asl2 %0\";
-
-    if (true_regnum (operands[1]) == true_regnum (operands[0]))
-      return \"asl %S2,%0\";
-
-    if (REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
-        && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
-        && true_regnum (operands[0]) != true_regnum (operands[2]))
-      return \"mov %1,%0\;asl %S2,%0\";
-    return \"asl %2,%1,%0\";
-  }"
-  [(set_attr "timings" "22")]
+         (match_operand:SI 1 "register_operand"  " 0,0,0,0,0,0,0,r")
+         (match_operand:QI 2 "nonmemory_operand" " J,K,M,L,D,O,i,r")))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "@
+   add %0,%0
+   asl2 %0
+   asl2 %0\;add %0,%0
+   asl2 %0\;asl2 %0
+   asl %S2,%0
+   asl %S2,%0
+   asl %S2,%0
+   asl %2,%1,%0"
+  [(set_attr "isa" "*,*,*,*,*,*,*,am33")
+   (set_attr "liw" "op2,op2,op2,op2,op2,op2,*,*")
+   (set_attr "liw_op" "asl")
+   (set_attr "timings" "11,11,22,22,11,11,11,11")]
+)
+
+(define_insn "lshrsi3"
+  [(set (match_operand:SI  0 "register_operand"  "=D,D,D,r")
+       (lshiftrt:SI
+         (match_operand:SI 1 "register_operand"  "0,0,0,r")
+         (match_operand:QI 2 "nonmemory_operand" "D,O,i,r")))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "@
+   lsr %S2,%0
+   lsr %S2,%0
+   lsr %S2,%0
+   lsr %2,%1,%0"
+  [(set_attr "isa" "*,*,*,am33")
+   (set_attr "liw" "op2,op2,*,*")
+   (set_attr "liw_op" "lsr")]
 )
 
-(define_insn "*mn10300_ashlsi3"
-  [(set (match_operand:SI 0 "register_operand" "=dax,dx,dx,dx,dx")
-       (ashift:SI
-        (match_operand:SI 1 "register_operand" "0,0,0,0,0")
-        (match_operand:QI 2 "nonmemory_operand" "J,K,M,L,dxi")))
-   (clobber (reg:CC CC_REG))
-  ]
+(define_insn "ashrsi3"
+  [(set (match_operand:SI  0 "register_operand"  "=D,D,D,r")
+       (ashiftrt:SI
+         (match_operand:SI 1 "register_operand"  "0,0,0,r")
+         (match_operand:QI 2 "nonmemory_operand" "D,O,i,r")))
+   (clobber (reg:CC CC_REG))]
   ""
   "@
-  add %0,%0
-  asl2 %0
-  asl2 %0\;add %0,%0
-  asl2 %0\;asl2 %0
-  asl %S2,%0"
-  [(set_attr "timings" "11,11,22,22,11")]
+   asr %S2,%0
+   asr %S2,%0
+   asr %S2,%0
+   asr %2,%1,%0"
+  [(set_attr "isa" "*,*,*,am33")
+   (set_attr "liw" "op2,op2,*,*")
+   (set_attr "liw_op" "asr")]
 )
 
-(define_expand "lshrsi3"
-  [(parallel [(set (match_operand:SI 0 "register_operand")
-                  (lshiftrt:SI
-                   (match_operand:SI 1 "register_operand")
-                   (match_operand:QI 2 "nonmemory_operand")))
-             (clobber (reg:CC CC_REG))
-            ])
-  ]
-  ""
-  "")
+;; ----------------------------------------------------------------------
+;; MISCELLANEOUS
+;; ----------------------------------------------------------------------
 
-(define_insn "*am33_lshrsi3"
-  [(set (match_operand:SI 0 "register_operand" "=dx,!dax")
-       (lshiftrt:SI
-        (match_operand:SI 1 "register_operand" "0,dax")
-        (match_operand:QI 2 "nonmemory_operand" "dxi,dax")))
-   (clobber (reg:CC CC_REG))
-  ]
+;; Note the use of the (const_int 0) when generating the insn that matches
+;; the bsch pattern.  This ensures that the destination register is
+;; initialised with 0 which will make the BSCH instruction set searching
+;; at bit 31.
+;;
+;; The XOR in the instruction sequence below is there because the BSCH
+;; instruction returns the bit number of the highest set bit and we want
+;; the number of zero bits above that bit.  The AM33 does not have a
+;; reverse subtraction instruction, but we can use a simple xor instead
+;; since we know that the top 27 bits are clear.
+(define_expand "clzsi2"
+  [(parallel [(set (match_operand:SI 0 "register_operand")
+                  (unspec:SI [(match_operand:SI 1 "register_operand")
+                              (const_int 0)] UNSPEC_BSCH))
+             (clobber (reg:CC CC_REG))])
+   (parallel [(set (match_dup 0)
+                  (xor:SI (match_dup 0)
+                          (const_int 31)))
+             (clobber (reg:CC CC_REG))])]
   "TARGET_AM33"
-  "*
-  {
-    if (true_regnum (operands[1]) == true_regnum (operands[0]))
-      return \"lsr %S2,%0\";
-
-    if (REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
-        && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
-        && true_regnum (operands[0]) != true_regnum (operands[2]))
-      return \"mov %1,%0\;lsr %S2,%0\";
-    return \"lsr %2,%1,%0\";
-  }"
-  [(set_attr "timings" "22")]
-)
-
-(define_insn "*mn10300_lshrsi3"
-  [(set (match_operand:SI 0 "register_operand" "=dx")
-       (lshiftrt:SI
-        (match_operand:SI 1 "register_operand" "0")
-        (match_operand:QI 2 "nonmemory_operand" "dxi")))
-   (clobber (reg:CC CC_REG))
-  ]
-  ""
-  "lsr %S2,%0"
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-                                      (const_int 11) (const_int 22)))]
 )
 
-(define_expand "ashrsi3"
-  [(parallel [(set (match_operand:SI 0 "register_operand")
-                  (ashiftrt:SI
-                   (match_operand:SI 1 "register_operand")
-                   (match_operand:QI 2 "nonmemory_operand")))
-             (clobber (reg:CC CC_REG))
-            ])
-  ]
-  ""
-  "")
-
-(define_insn "*am33_ashrisi3"
-  [(set (match_operand:SI 0 "register_operand" "=dx,!dax")
-       (ashiftrt:SI
-        (match_operand:SI 1 "register_operand" "0,dax")
-        (match_operand:QI 2 "nonmemory_operand" "dxi,dax")))
-   (clobber (reg:CC CC_REG))
-  ]
+(define_insn "*bsch"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (unspec:SI [(match_operand:SI 1 "register_operand" "r")
+                   (match_operand:SI 2 "nonmemory_operand" "0")]
+                  UNSPEC_BSCH))
+   (clobber (reg:CC CC_REG))]
   "TARGET_AM33"
-  "*
-  {
-    if (true_regnum (operands[1]) == true_regnum (operands[0]))
-      return \"asr %S2,%0\";
-
-    if (REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
-        && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
-        && true_regnum (operands[0]) != true_regnum (operands[2]))
-      return \"mov %1,%0\;asr %S2,%0\";
-    return \"asr %2,%1,%0\";
-  }"
-  [(set_attr "timings" "22")]
-)
-
-(define_insn "*mn10300_ashrsi3"
-  [(set (match_operand:SI 0 "register_operand" "=dx")
-       (ashiftrt:SI
-        (match_operand:SI 1 "register_operand" "0")
-        (match_operand:QI 2 "nonmemory_operand" "dxi")))
-   (clobber (reg:CC CC_REG))
-  ]
-  ""
-  "asr %S2,%0"
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-                                      (const_int 11) (const_int 22)))]
+  "bsch %1, %0"
 )
 
 ;; ----------------------------------------------------------------------
 )
 
 (define_insn "fmasf4"
-  [(set (match_operand:SF         0 "register_operand" "=A")
+  [(set (match_operand:SF         0 "register_operand" "=c")
        (fma:SF (match_operand:SF 1 "register_operand" "f")
                (match_operand:SF 2 "register_operand" "f")
                (match_operand:SF 3 "register_operand" "f")))
 )
 
 (define_insn "fmssf4"
-  [(set (match_operand:SF                 0 "register_operand" "=A")
+  [(set (match_operand:SF                 0 "register_operand" "=c")
        (fma:SF (match_operand:SF         1 "register_operand" "f")
                (match_operand:SF         2 "register_operand" "f")
                (neg:SF (match_operand:SF 3 "register_operand" "f"))))
 )
 
 (define_insn "fnmasf4"
-  [(set (match_operand:SF                 0 "register_operand" "=A")
+  [(set (match_operand:SF                 0 "register_operand" "=c")
        (fma:SF (neg:SF (match_operand:SF 1 "register_operand" "f"))
                (match_operand:SF         2 "register_operand" "f")
                (match_operand:SF         3 "register_operand" "f")))
 )
 
 (define_insn "fnmssf4"
-  [(set (match_operand:SF                 0 "register_operand" "=A")
+  [(set (match_operand:SF                 0 "register_operand" "=c")
        (fma:SF (neg:SF (match_operand:SF 1 "register_operand" "f"))
                (match_operand:SF         2 "register_operand" "f")
                (neg:SF (match_operand:SF 3 "register_operand" "f"))))
 (define_expand "prologue"
   [(const_int 0)]
   ""
-  "mn10300_expand_prologue (); DONE;")
+  { mn10300_expand_prologue (); DONE; }
+)
 
 (define_expand "epilogue"
   [(return)]
   ""
-  "
-  {
-    mn10300_expand_epilogue ();
-    DONE;
-  }")
-
-(define_insn "return_internal"
-  [(const_int 2)
-   (return)]
-  ""
-  "rets"
-  [(set_attr "timings" "66")]
+  { mn10300_expand_epilogue (); DONE; }
 )
 
-;; This insn restores the callee saved registers and does a return, it
-;; can also deallocate stack space.
-(define_insn "return_internal_regs"
-  [(const_int 0)
-   (match_operand:SI 0  "const_int_operand" "i")
-   (return)]
+(define_insn "return"
+  [(return)]
+  "mn10300_can_use_rets_insn ()"
+{
+  /* The RETF insn is 4 cycles faster than RETS, though 1 byte larger.  */
+  if (optimize_insn_for_speed_p () && mn10300_can_use_retf_insn ())
+    return "retf [],0";
+  else
+    return "rets";
+})
+
+(define_insn "return_ret"
+  [(return)
+   (use (match_operand:SI 0 "const_int_operand" ""))]
   ""
-  "*
-  {
-    fputs (\"\\tret \", asm_out_file);
-    mn10300_print_reg_list (asm_out_file, mn10300_get_live_callee_saved_regs ());
-    fprintf (asm_out_file, \",%d\\n\", (int) INTVAL (operands[0]));
-    return \"\";
-  }"
-  ;; Assumes that there will be no more than 8 regs to pop
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-                                      (const_int 1414) (const_int 1313)))]
-)
+{
+  /* The RETF insn is up to 3 cycles faster than RET.  */
+  fputs ((mn10300_can_use_retf_insn () ? "\tretf " : "\tret "), asm_out_file);
+  mn10300_print_reg_list (asm_out_file, mn10300_get_live_callee_saved_regs (NULL));
+  fprintf (asm_out_file, ",%d\n", (int) INTVAL (operands[0]));
+  return "";
+})
 
 ;; This instruction matches one generated by mn10300_gen_multiple_store()
 (define_insn "store_movm"
   [(match_parallel 0 "mn10300_store_multiple_operation"
     [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (match_operand 1 "" "")))])]
   ""
-  "*
-  {
-    fputs (\"\\tmovm \", asm_out_file);
-    mn10300_print_reg_list (asm_out_file,
-                            mn10300_store_multiple_operation (operands[0],
-                                                             VOIDmode));
-    fprintf (asm_out_file, \",(sp)\\n\");
-    return \"\";
-  }"
+{
+  fputs ("\tmovm ", asm_out_file);
+  mn10300_print_reg_list (asm_out_file,
+                          mn10300_store_multiple_regs (operands[0]));
+  fprintf (asm_out_file, ",(sp)\n");
+  return "";
+}
   ;; Assume that no more than 8 registers will be pushed.
   [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
                                       (const_int 99) (const_int 88)))]
 )
 
-(define_insn "return"
-  [(return)]
-  "mn10300_can_use_return_insn ()"
-  "*
+(define_expand "load_pic"
+  [(const_int 0)]
+  "flag_pic"
 {
-  rtx next = next_active_insn (insn);
-
-  if (next
-      && JUMP_P (next)
-      && GET_CODE (PATTERN (next)) == RETURN)
-    return \"\";
+  if (TARGET_AM33)
+    emit_insn (gen_am33_load_pic (pic_offset_table_rtx));
+  else if (mn10300_frame_size () == 0)
+    emit_insn (gen_mn10300_load_pic0 (pic_offset_table_rtx));
   else
-    return \"rets\";
-}"
-  [(set_attr "timings" "66")]
+    emit_insn (gen_mn10300_load_pic1 (pic_offset_table_rtx));
+  DONE;
+})
+
+(define_insn "am33_load_pic"
+  [(set (match_operand:SI 0 "register_operand" "=a")
+       (unspec:SI [(const_int 0)] UNSPEC_GOT))
+   (clobber (reg:CC CC_REG))]
+  "TARGET_AM33"
+{
+  operands[1] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);
+  return ".LPIC%=:\;mov pc,%0\;add %1-(.LPIC%=-.),%0";
+}
+  [(set_attr "timings" "33")]
 )
 
-;; Try to combine consecutive updates of the stack pointer (or any
-;; other register for that matter).
-(define_peephole
-  [(parallel [(set (match_operand:SI 0 "register_operand" "=dxay")
-                  (plus:SI (match_dup 0)
-                           (match_operand 1 "const_int_operand" "")))
-             (clobber (reg:CC CC_REG))
-            ])
-   (parallel [(set (match_dup 0)
-                  (plus:SI (match_dup 0)
-                           (match_operand 2 "const_int_operand" "")))
-             (clobber (reg:CC CC_REG))
-            ])
-  ]
+;; Load pic register with push/pop of stack.
+(define_insn "mn10300_load_pic0"
+  [(set (match_operand:SI 0 "register_operand" "=a")
+       (unspec:SI [(const_int 0)] UNSPEC_GOT))
+   (clobber (reg:SI MDR_REG))
+   (clobber (reg:CC CC_REG))]
   ""
-  "*
 {
-  operands[1] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[1]));
-  return \"add %1,%0\";
-}"
+  operands[1] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);
+  return ("add -4,sp\;"
+         "calls .LPIC%=\n"
+          ".LPIC%=:\;"
+         "movm (sp),[%0]\;"
+         "add %1-(.LPIC%=-.),%0");
+}
+  [(set_attr "timings" "88")]
 )
 
-(define_expand "int_label"
-  [(unspec [(match_operand:SI 0 "" "")] UNSPEC_INT_LABEL)]
-  "" "")
-
-(define_expand "GOTaddr2picreg"
-  [(match_dup 0)]
-  "" "
+;; Load pic register re-using existing stack space.
+(define_insn "mn10300_load_pic1"
+  [(set (match_operand:SI 0 "register_operand" "=a")
+       (unspec:SI [(const_int 0)] UNSPEC_GOT))
+   (clobber (mem:SI (reg:SI SP_REG)))
+   (clobber (reg:SI MDR_REG))
+   (clobber (reg:CC CC_REG))]
+  ""
 {
-  /* It would be nice to be able to have int_label keep track of the
-     counter and all, but if we add C code to it, we'll get an insn
-     back, and we just want the pattern.  */
-  operands[0] = gen_int_label (GEN_INT (mn10300_unspec_int_label_counter++));
-  if (TARGET_AM33)
-    emit_insn (gen_am33_loadPC (operands[0]));
-  else
-    emit_insn (gen_mn10300_loadPC (operands[0]));
-  emit_insn (gen_add_GOT_to_pic_reg (copy_rtx (operands[0])));
-  DONE;
+  operands[1] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);
+  return ("calls .LPIC%=\n"
+         ".LPIC%=:\;"
+          "mov (sp),%0\;"
+          "add %1-(.LPIC%=-.),%0");
 }
-")
+  [(set_attr "timings" "66")]
+)
 
-(define_insn "am33_loadPC"
-  [(parallel
-    [(set (reg:SI PIC_REG) (pc))
-     (use (match_operand 0 "" ""))])]
-  "TARGET_AM33"
-  "%0:\;mov pc,a2"
+;; The mode on operand 3 has been deliberately omitted because it
+;; can be either SI (for arithmetic operations) or QI (for shifts).
+(define_insn "liw"
+  [(set (match_operand:SI             0 "register_operand" "=r")
+       (unspec:SI [(match_dup 0)
+                    (match_operand    2 "liw_operand"       "rO")
+                    (match_operand:SI 4 "const_int_operand" "")]
+                   UNSPEC_LIW))
+   (set (match_operand:SI             1 "register_operand" "=r")
+        (unspec:SI [(match_dup 1)
+                    (match_operand    3 "liw_operand"       "rO")
+                    (match_operand:SI 5 "const_int_operand" "")]
+                   UNSPEC_LIW))]
+  "TARGET_ALLOW_LIW"
+  "%W4_%W5 %2, %0, %3, %1"
+  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+                                      (const_int 13) (const_int 12)))]
 )
 
-(define_insn_and_split "mn10300_loadPC"
-  [(parallel
-    [(set (reg:SI PIC_REG) (pc))
-     (use (match_operand 0 "" ""))])]
-  "! TARGET_AM33"
-  "#"
-  "&& reload_completed"
-  [(match_operand 0 "" "")]
-  {
-    rtx sp_reg = gen_rtx_REG (SImode, SP_REG);
-    int need_stack_space = (get_frame_size () == 0
-                           && crtl->outgoing_args_size == 0);
+;; The mode on operand 1 has been deliberately omitted because it
+;; can be either SI (for arithmetic operations) or QI (for shifts).
+(define_insn "cmp_liw"
+  [(set (reg:CC CC_REG)
+       (compare:CC (match_operand:SI 2 "register_operand" "r")
+                   (match_operand    3 "liw_operand"      "rO")))
+   (set (match_operand:SI             0 "register_operand" "=r")
+        (unspec:SI [(match_dup 0)
+                    (match_operand    1 "liw_operand"       "rO")
+                    (match_operand:SI 4 "const_int_operand" "")]
+                   UNSPEC_LIW))]
+  "TARGET_ALLOW_LIW"
+  "cmp_%W4 %3, %2, %1, %0"
+  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+                                      (const_int 13) (const_int 12)))]
+)
+
+(define_insn "liw_cmp"
+  [(set (match_operand:SI             0 "register_operand" "=r")
+        (unspec:SI [(match_dup 0)
+                    (match_operand    1 "liw_operand"      "rO")
+                    (match_operand:SI 4 "const_int_operand" "")]
+                   UNSPEC_LIW))
+   (set (reg:CC CC_REG)
+       (compare:CC (match_operand:SI 2 "register_operand" "r")
+                   (match_operand    3 "liw_operand"      "rO")))]
+  "TARGET_ALLOW_LIW"
+  "%W4_cmp %1, %0, %3, %2"
+  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+                                      (const_int 13) (const_int 12)))]
+)
 
-    if (need_stack_space)
-      emit_insn (gen_addsi3 (sp_reg, sp_reg, GEN_INT (-4)));
+;; Note - in theory the doloop patterns could be used here to express
+;; the SETLB and Lcc instructions.  In practice this does not work because
+;; the acceptable forms of the doloop patterns do not include UNSPECs
+;; and without them gcc's basic block reordering code can duplicate the
+;; doloop_end pattern, leading to bogus multiple decrements of the loop
+;; counter. 
 
-    emit_insn (gen_call_next_insn (operands[0]));
+(define_insn "setlb"
+  [(unspec [(const_int 0)] UNSPEC_SETLB)]
+  "TARGET_AM33 && TARGET_ALLOW_SETLB"
+  "setlb"
+)
 
-    if (need_stack_space)
-      emit_insn (gen_pop_pic_reg ());
-    else
-      emit_move_insn (pic_offset_table_rtx, gen_rtx_MEM (SImode, sp_reg));
-    DONE;
-  }
+(define_insn "Lcc"
+  [(set (pc)
+       (if_then_else (match_operator 0 "comparison_operator"
+                     [(reg:CC CC_REG) (const_int 0)])
+                     (label_ref (match_operand 1 "" ""))
+                     (pc)))
+   (unspec [(const_int 1)] UNSPEC_SETLB)]
+  "TARGET_AM33 && TARGET_ALLOW_SETLB"
+  "L%b0 # loop back to: %1"
 )
 
-(define_insn "call_next_insn"
-  [(parallel
-    [(set (mem:SI (reg:SI SP_REG)) (pc))
-     (use (match_operand 0 "" ""))])]
-  "reload_completed"
-  "calls %0\;%0:"
-  [(set_attr "timings" "44")]
-)
-
-(define_expand "add_GOT_to_pic_reg"
-  [(parallel [(set (reg:SI PIC_REG)
-                  (plus:SI
-                   (reg:SI PIC_REG)
-                   (const:SI
-                    (unspec:SI [(minus:SI
-                              (match_dup 1)
-                              (const (minus:SI
-                                      (const (match_operand:SI 0 "" ""))
-                                      (pc))))
-                             ] UNSPEC_PIC))))
-             (clobber (reg:CC CC_REG))
-             ])
-  ]
-  ""
-  "operands[1] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);"
-)
-
-(define_expand "add_GOT_to_any_reg"
-  [(parallel [(set (match_operand:SI 0 "" "")
-                  (plus:SI
-                   (match_operand:SI 1 "" "")
-                   (const
-                    (unspec [(minus:SI
-                              (match_dup 3)
-                              (const (minus:SI
-                                      (const (match_operand:SI 2 "" ""))
-                                      (pc))))
-                             ] UNSPEC_PIC))))
-             (clobber (reg:CC CC_REG))
-            ])
-  ]
-  ""
-  "operands[3] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);"
+(define_insn "FLcc"
+  [(set (pc)
+       (if_then_else (match_operator 0 "comparison_operator"
+                     [(reg:CC_FLOAT CC_REG) (const_int 0)])
+                     (label_ref (match_operand 1 "" ""))
+                     (pc)))
+   (unspec [(const_int 2)] UNSPEC_SETLB)]
+  "TARGET_AM33_2 && TARGET_ALLOW_SETLB"
+  "FL%b0 # loop back to: %1"
+  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34") (const_int 44) (const_int 11)))]
 )