h8300.md (cpu): New attribute.
authorDoug Evans <dje@gnu.org>
Mon, 11 Jul 1994 22:53:08 +0000 (22:53 +0000)
committerDoug Evans <dje@gnu.org>
Mon, 11 Jul 1994 22:53:08 +0000 (22:53 +0000)
* h8300/h8300.md (cpu): New attribute.
(attribute length): Add h8/300h support.
(attribute cc): New value `cbit'.
(all anonymous insns): Give them names.
(move insns): Add h8/300h support.
(tstqi, tsthi): Use btst insn if able.
(arithmetic insns): Add h8/300h support.
(boolean insns): Likewise.
(negate insns): Likewise.
(branch insns): Likewise.
(call_value): Use call_insn_operand for operand 1.
(shift insns): Completely rewritten.  Add h8/300h support.
(zero/sign extension insns): Add h8/300h support.
(extv): Deleted.
(insv, extzv): Only use for h8/300.
(bitfield insns): Completely rewritten.
(fancyb*): New insns for speeding up bit accesses.

From-SVN: r7730

gcc/config/h8300/h8300.md

index 8355ac8..5c5c3ae 100644 (file)
@@ -1,5 +1,8 @@
-;;- Machine description for the Hitachi H8/300 for the GNU C compiler
-;;   Copyright (C) 1992, 1993 Free Software Foundation, Inc.
+;; GCC machine description for Hitachi H8/300
+;; Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+
+;;   Contributed by Steve Chamberlain (sac@cygnus.com),
+;;   Jim Wilson (wilson@cygnus.com), and Doug Evans (dje@cygnus.com).
 
 ;; This file is part of GNU CC.
 
 
 ;; See file "rtl.def" for documentation on define_insn, match_*, et. al.
 
+(define_attr "cpu" "h8300,h8300h"
+  (const (symbol_ref "cpu_type")))
+
+;; ??? If we can remove the operand type on all the insns, do it.
+;; ??? Otherwise, try to have the operand type on all the insns.
+
 (define_attr "type" "branch,return,call,arith,move,float,multi"
   (const_string "arith"))
 
 (define_attr "length" "" 
   (cond [(eq_attr "type" "branch")
         (if_then_else (and (ge (minus (pc) (match_dup 0))
-                               (const_int -128))
+                               (const_int -120))
                            (le (minus (pc) (match_dup 0))
-                               (const_int 128)))
+                               (const_int 120)))
                       (const_int 2)
-                      (const_int 6))
+                      (if_then_else (and (eq_attr "cpu" "h8300h")
+                                         (and (ge (minus (pc) (match_dup 0))
+                                                  (const_int -32000))
+                                              (le (minus (pc) (match_dup 0))
+                                                  (const_int 32000))))
+                                    (const_int 4)
+                                    (const_int 6)))
         (eq_attr "type" "move")        (const_int 4)
         (eq_attr "type" "return")      (const_int 2)
         (eq_attr "type" "float")       (const_int 12)
         (eq_attr "type" "call")        (const_int 4)]
        (const_int 200)))
 
-
-(define_attr "cc" "none,clobber,none_0hit,set,compare,whoops" 
+(define_attr "cc" "none,clobber,none_0hit,set,compare,whoops,cbit" 
   (const_string "whoops"))
-\f
+
 ;; ----------------------------------------------------------------------
-;; move instructions
+;; MOVE INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
-;; movhi
+;; movqi
 
-(define_insn ""
-  [(set (match_operand:HI 0 "push_operand" "=<")
-       (match_operand:HI 1 "register_operand" "ra"))]
+(define_insn "movqi_push"
+  [(set (match_operand:QI 0 "push_operand" "=<")
+       (match_operand:QI 1 "register_operand" "r"))]
   ""
-  "mov.w       %T1,%T0"
+  "*
+{
+  if (TARGET_H8300)
+    return \"push.w    %T1\";
+  else
+    return \"push.l    %S1\";
+}"
   [(set_attr "type" "move")
-   (set_attr "length" "2")
+   (set (attr "length") (if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4)))
    (set_attr "cc" "set")])
 
-(define_insn "movstricthi"
-  [(set (strict_low_part (match_operand:HI 0 "general_operand_dst" "=r,r,r,o,<"))
-       (match_operand:HI 1 "general_operand_src" "I,r,io,r,r"))]
+(define_insn "movqi_internal"
+  [(set (match_operand:QI 0 "general_operand_dst" "=r,r,r,o,<,r")
+       (match_operand:QI 1 "general_operand_src" "I,r>,io,r,r,c"))]
+  "register_operand (operands[0],QImode) || register_operand (operands[1], QImode)"
+  "@
+   sub.b       %X0,%X0
+   mov.b       %X1,%X0
+   mov.b       %X1,%X0
+   mov.b       %X1,%X0
+   mov.b       %X1,%X0
+   xor         %X0,%X0\;bst    #0,%X0"
+  [(set_attr "type" "move")
+   (set_attr_alternative "length"
+     [(const_int 2) (const_int 2)
+      (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))
+      (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))
+      (if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4))
+      (const_int 4)])
+   (set_attr "cc" "set,set,set,set,set,none")])
+
+(define_expand "movqi"
+  [(set (match_operand:QI 0 "general_operand_dst" "")
+       (match_operand:QI 1 "general_operand_src" ""))]
+  ""
+  "
+{
+  /* 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 "movstrictqi"
+  [(set (strict_low_part (match_operand:QI 0 "general_operand_dst" "=r,r,r,o,<"))
+                        (match_operand:QI 1 "general_operand_src" "I,r,io,r,r"))]
   ""
   "@
-   sub.w       %T0,%T0
-   mov.w       %T1,%T0
-   mov.w       %T1,%T0
-   mov.w       %T1,%T0
-   mov.w       %T1,%T0"
+   sub.b       %X0,%X0
+   mov.b       %X1,%X0
+   mov.b       %X1,%X0
+   mov.b       %X1,%X0
+   mov.b       %X1,%X0"
   [(set_attr "type" "move")
-   (set_attr "length" "2,2,4,4,2")
+   (set_attr_alternative "length"
+     [(const_int 2) (const_int 2)
+      (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))
+      (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))
+      (if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4))])
+   (set_attr "cc" "set")])
+   
+;; movhi
+
+(define_insn "movhi_push"
+  [(set (match_operand:HI 0 "push_operand" "=<")
+       (match_operand:HI 1 "register_operand" "ra"))]
+  ""
+  "*
+{
+  if (TARGET_H8300)
+    return \"push.w    %T1\";
+  else
+    return \"push.l    %S1\";
+}"
+  [(set_attr "type" "move")
+   (set (attr "length") (if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4)))
    (set_attr "cc" "set")])
 
-(define_insn ""
+(define_insn "movhi_internal"
   [(set (match_operand:HI 0 "general_operand_dst" "=ra,ra,ra,o,<")
-       (match_operand:HI 1 "general_operand_src" "I,ra,ion,ra,ra"))]
+       (match_operand:HI 1 "general_operand_src" "I,ra>,ion,ra,ra"))]
   ""
   "@
    sub.w       %T0,%T0
    mov.w       %T1,%T0
    mov.w       %T1,%T0"
   [(set_attr "type" "move")
-   (set_attr "length" "2,2,4,4,2")
+   (set_attr_alternative "length"
+     [(const_int 2) (const_int 2)
+      (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))
+      (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))
+      (if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4))])
    (set_attr "cc" "set")])
 
 (define_expand "movhi"
   ""
   "
 {
-  /* 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);
+  /* 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 ""
-  [(set (match_operand:HI 0 "register_operand" "=&ra")
-       (plus:HI (match_operand:HI 1 "general_operand_src" "g")
-                (match_operand:HI 2 "register_operand" "ra")))]
-  ""
-  "mov.w       %T1,%T0\;add.w  %T2,%T0"
-  [(set_attr "type" "arith")
-   (set_attr "length" "6")
-   (set_attr "cc" "set")])
-
-;; movqi
-
-(define_insn ""
-  [(set (match_operand:QI 0 "push_operand" "=<")
-       (match_operand:QI 1 "register_operand" "r"))]
-  ""
-  "mov.w       %T1,%T0"
-  [(set_attr "type" "move")
-   (set_attr "length" "2")
-   (set_attr "cc" "set")])
-
-(define_insn "movstrictqi"
-  [(set (strict_low_part (match_operand:QI 0 "general_operand_dst" "=r,r,r,o,<"))
-       (match_operand:QI 1 "general_operand_src" "I,r,io,r,r"))]
+(define_insn "movstricthi"
+  [(set (strict_low_part (match_operand:HI 0 "general_operand_dst" "=r,r,r,o,<"))
+                        (match_operand:HI 1 "general_operand_src" "I,r,io,r,r"))]
   ""
   "@
-   sub.b       %X0,%X0
-   mov.b       %X1,%X0
-   mov.b       %X1,%X0
-   mov.b       %X1,%X0
-   mov.b       %X1,%X0"
+   sub.w       %T0,%T0
+   mov.w       %T1,%T0
+   mov.w       %T1,%T0
+   mov.w       %T1,%T0
+   mov.w       %T1,%T0"
   [(set_attr "type" "move")
-   (set_attr "length" "2,2,4,4,2")
+   (set_attr_alternative "length"
+     [(const_int 2) (const_int 2)
+      (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))
+      (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))
+      (if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4))])
    (set_attr "cc" "set")])
 
-(define_insn ""
-  [(set (match_operand:QI 0 "general_operand_dst" "=r,r,r,o,<")
-       (match_operand:QI 1 "general_operand_src" "I,r,io,r,r"))]
-  ""
-  "@
-   sub.b       %X0,%X0
-   mov.b       %X1,%X0
-   mov.b       %X1,%X0
-   mov.b       %X1,%X0
-   mov.b       %X1,%X0"
-  [(set_attr "type" "move")
-   (set_attr "length" "2,2,4,4,2")
-   (set_attr "cc" "set")])
+;; movsi
 
-(define_expand "movqi"
-  [(set (match_operand:QI 0 "general_operand_dst" "")
-       (match_operand:QI 1 "general_operand_src" ""))]
+(define_expand "movsi"
+  [(set (match_operand:SI 0 "general_operand_dst" "")
+       (match_operand:SI 1 "general_operand_src" ""))]
   ""
   "
 {
-  /* 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);
+  if (TARGET_H8300)
+    {
+      if (do_movsi (operands))
+       DONE;
+    }
+  else /* TARGET_H8300H */
+    {
+      /* 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);
+       }
+    }
 }")
 
-;; movsi
-
-(define_insn ""
-  [(set (match_operand:SI 0 "general_operand_dst" "=l,l,l,o,<")
-       (match_operand:SI 1 "general_operand_src" "I,l,ion,l,l"))]
+(define_expand "movsf"
+  [(set (match_operand:SF 0 "general_operand_dst" "")
+       (match_operand:SF 1 "general_operand_src" ""))]
   ""
+  "
+{
+  if (TARGET_H8300)
+    {
+      if (do_movsi (operands))
+       DONE;
+    }
+  else /* TARGET_H8300H */
+    {
+      /* 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);
+       }
+    }
+}")
+
+(define_insn "movsi_h8300"
+  [(set (match_operand:SI 0 "general_operand_dst" "=r,r,r,o,<,r")
+       (match_operand:SI 1 "general_operand_src" "I,r,ion,r,r,>"))]
+  "TARGET_H8300
+   && (register_operand (operands[0], SImode)
+       || register_operand (operands[1], SImode))"
   "*
 {
   int rn = -1;
     case 0:
       return \"sub.w   %e0,%e0\;sub.w  %f0,%f0\";
     case 1:
-      return \"mov.w   %e1,%e0\;mov.w  %f1,%f0\";
+      if (REGNO(operands[0]) < REGNO(operands[1]))
+       return \"mov.w  %e1,%e0\;mov.w  %f1,%f0\";
+      else 
+       return \"mov.w  %f1,%f0\;mov.w  %e1,%e0\";
     case 2:
       /* Make sure we don't trample the register we index with.  */
     
-      if (GET_CODE (operands[1]) == MEM) 
+      if (GET_CODE(operands[1]) == MEM) 
        {
-         rtx inside = XEXP (operands[1], 0);
-         if (REG_P (inside))
-           rn = REGNO (inside);
+         rtx inside = XEXP (operands[1],0);
+         if  (REG_P (inside)) 
+           {
+             rn = REGNO(inside);
+           }
          else if (GET_CODE (inside) == PLUS) 
            {
-             rtx lhs = XEXP (inside, 0);
-             rtx rhs = XEXP (inside, 1);
-             if (REG_P (lhs))
-               rn = REGNO (lhs);
-             if (REG_P (rhs))
-               rn = REGNO (rhs);
+             rtx lhs = XEXP (inside,0);
+             rtx rhs = XEXP (inside,1);
+             if (REG_P (lhs)) rn = REGNO (lhs);
+             if (REG_P (rhs)) rn = REGNO (rhs);
            }
        }
-      if (rn == REGNO (operands[0]))
-       /* Move the second word first.  */
-       return \"mov.w  %f1,%f0\;mov.w  %e1,%e0\";
+      if (rn == REGNO (operands[0]))   
+       {
+         /* Move the second word first.  */
+         return \"mov.w        %f1,%f0\;mov.w  %e1,%e0\";
+       }
       else 
-       return \"mov.w  %e1,%e0\;mov.w  %f1,%f0\";
+       {
+         return \"mov.w        %e1,%e0\;mov.w  %f1,%f0\";
+       }
     
     case 3:
       return \"mov.w   %e1,%e0\;mov.w  %f1,%f0\";
     case 4:
       return \"mov.w   %f1,%T0\;mov.w  %e1,%T0\";
+    case 5:
+      return \"mov.w   %T1,%e0\;mov.w  %T1,%f0\";
     }
 }"
   [(set_attr "type" "move")
-   (set_attr "length" "4,4,8,8,4")
-   (set_attr "cc" "clobber")])
-
-(define_insn ""
-  [(set (match_operand:SI 0 "push_operand" "=<")
-       (match_operand:SI 1 "register_operand" "l"))]
-  ""
-  "mov.w      %f1,%T0\;mov.w   %e1,%T0"
-  [(set_attr "type" "move")
-   (set_attr "length" "4")
+   (set_attr "length" "4,4,8,8,4,4")
    (set_attr "cc" "clobber")])
 
-(define_expand "movsi"
-  [(set (match_operand:SI 0 "general_operand_dst" "")
-       (match_operand:SI 1 "general_operand_src" ""))]
-  ""                                   
-  "if (domovsi (operands)) DONE;")
-
-(define_insn ""
-  [(set (match_operand:SF 0 "general_operand_dst" "=l,l,l,o,<")
-       (match_operand:SF 1 "general_operand_src" "I,l,ion,l,l"))]
-  ""
+(define_insn "movsf_h8300"
+  [(set (match_operand:SF 0 "general_operand_dst" "=r,r,r,o,<,r")
+       (match_operand:SF 1 "general_operand_src" "I,r,ion,r,r,>"))]
+  "TARGET_H8300
+   && (register_operand (operands[0], SFmode)
+       || register_operand (operands[1], SFmode))"
   "*
 {
-  /* This is a copy of the movsi stuff.  */
+  /* Copy of the movsi stuff */
   int rn = -1;
   switch (which_alternative)
     {
     case 0:
       return \"sub.w   %e0,%e0\;sub.w  %f0,%f0\";
     case 1:
-      return \"mov.w   %e1,%e0\;mov.w  %f1,%f0\";
+      if (REGNO(operands[0]) < REGNO(operands[1]))
+       return \"mov.w  %e1,%e0\;mov.w  %f1,%f0\";
+      else 
+       return \"mov.w  %f1,%f0\;mov.w  %e1,%e0\";
     case 2:
       /* Make sure we don't trample the register we index with.  */
     
       if (GET_CODE (operands[1]) == MEM) 
        {
-         rtx inside = XEXP (operands[1], 0);
+         rtx inside = XEXP (operands[1],0);
          if (REG_P (inside))
-           rn = REGNO (inside);
+           {
+             rn = REGNO (inside);
+           }
          else if (GET_CODE (inside) == PLUS) 
            {
-             rtx lhs = XEXP (inside, 0);
-             rtx rhs = XEXP (inside, 1);
-             if (REG_P (lhs))
-               rn = REGNO (lhs);
-             if (REG_P (rhs))
-               rn = REGNO (rhs);
+             rtx lhs = XEXP (inside,0);
+             rtx rhs = XEXP (inside,1);
+             if (REG_P (lhs)) rn = REGNO (lhs);
+             if (REG_P (rhs)) rn = REGNO (rhs);
            }
        }
       if (rn == REGNO (operands[0]))
-       /* Move the second word first.  */
-       return \"mov.w  %f1,%f0\;mov.w  %e1,%e0\";
+       {
+         /* move the second word first */
+         return \"mov.w        %f1,%f0\;mov.w  %e1,%e0\";
+       }
       else 
-       return \"mov.w  %e1,%e0\;mov.w  %f1,%f0\";
+       {
+         return \"mov.w        %e1,%e0\;mov.w  %f1,%f0\";
+       }
     
     case 3:
       return \"mov.w   %e1,%e0\;mov.w  %f1,%f0\";
     case 4:
       return \"mov.w   %f1,%T0\;mov.w  %e1,%T0\";
-   }
+    case 5:
+      return \"mov.w   %T1,%e0\;mov.w  %T1,%f0\";
+
+    }
 }"
   [(set_attr "type" "move")
-   (set_attr "length" "4,4,8,8,4")
+   (set_attr "length" "4,4,8,8,4,4")
    (set_attr "cc" "clobber")])
 
-(define_insn ""
-  [(set (match_operand:SF 0 "push_operand" "=<")
-       (match_operand:SF 1 "register_operand" "l"))]
-  ""
-  "mov.w      %f1,%T0\;mov.w   %e1,%T0"
+(define_insn "movsi_h8300h"
+  [(set (match_operand:SI 0 "general_operand_dst" "=ra,ra,ra,o,<,ra")
+       (match_operand:SI 1 "general_operand_src" "I,ra,ion,ra,ra,>"))]
+  "TARGET_H8300H
+   && (register_operand (operands[0], SImode)
+       || register_operand (operands[1], SImode))"
+  "@
+   sub.l       %S0,%S0
+   mov.l       %S1,%S0
+   mov.l       %S1,%S0
+   mov.l       %S1,%S0
+   mov.l       %S1,%S0
+   mov.l       %S1,%S0"
   [(set_attr "type" "move")
-   (set_attr "length" "4")
-   (set_attr "cc" "clobber")])
-
-(define_expand "movsf"
-  [(set (match_operand:SF 0 "general_operand_dst" "")
-       (match_operand:SF 1 "general_operand_src" ""))]
-  ""                                   
-  "if (domovsi (operands)) DONE;")
+   (set_attr "length" "2,2,8,8,4,4")
+   (set_attr "cc" "set")])
 
-;; Block move
+(define_insn "movsf_h8300h"
+  [(set (match_operand:SF 0 "general_operand_dst" "=r,r,r,o,<")
+       (match_operand:SF 1 "general_operand_src" "I,r,ion,r,r"))]
+  "TARGET_H8300H
+   && (register_operand (operands[0], SFmode)
+       || register_operand (operands[1], SFmode))"
+  "@
+   sub.l       %S0,%S0
+   mov.l       %S1,%S0
+   mov.l       %S1,%S0
+   mov.l       %S1,%S0
+   mov.l       %S1,%S0"
+  [(set_attr "type" "move")
+   (set_attr "length" "2,2,8,8,4")
+   (set_attr "cc" "set")])
 
-(define_expand "movstrhi"
-  [(parallel [(set (mem:BLK (match_operand:BLK 0 "general_operand" ""))
-                  (mem:BLK (match_operand:BLK 1 "general_operand" "")))
-             (use (match_operand:HI 2 "general_operand" ""))
-             (use (match_operand:HI 3 "immediate_operand" ""))
-             (clobber (match_dup 3))
-             ])]
-  ""
-  "
-{
-  rtx src_ptr = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
-  rtx dst_ptr = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
-
-  enum machine_mode mode = INTVAL (operands[3]) >=2 ? HImode : QImode;
-  rtx tmpreg = gen_reg_rtx (mode);
-  rtx increment = mode == QImode  ? const1_rtx : const2_rtx;
-  rtx length = operands[2];
-  rtx label = gen_label_rtx ();
-  rtx end_src_ptr = gen_reg_rtx (Pmode);
-
-  emit_insn (gen_rtx (SET, VOIDmode, end_src_ptr,
-                     gen_rtx (PLUS, Pmode, src_ptr, length)));
-
-  emit_label (label);
-  emit_move_insn (tmpreg, gen_rtx (MEM, mode, src_ptr));
-  emit_move_insn (gen_rtx (MEM, mode, dst_ptr), tmpreg);
-  emit_insn (gen_rtx (SET, VOIDmode, src_ptr,
-                     gen_rtx (PLUS, Pmode, src_ptr, increment)));
-  emit_insn (gen_rtx (SET, VOIDmode, dst_ptr,
-                     gen_rtx (PLUS, Pmode, dst_ptr, increment)));
-
-  emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx,
-                     gen_rtx (COMPARE, HImode, src_ptr, end_src_ptr)));
-  emit_jump_insn (gen_bne (label));
-
-  DONE;        
-}
-")
-\f
 ;; ----------------------------------------------------------------------
-;; Test instructions
+;; TEST INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
 (define_insn "tstqi"
-  [(set (cc0)
-       (match_operand:QI 0 "register_operand" "ra"))]
+  [(set (cc0) (match_operand:QI 0 "register_operand" "ra"))]
   ""
-  "cmp.b       #0,%X0"
+  "*
+{
+  /* ??? I don't think this is right.  --Jim */
+  if (cc_prev_status.flags & CC_DONE_CBIT)
+    return \"btst      #0,%X0\";
+  else
+    return \"cmp.b     #0,%X0\";
+}"
   [(set_attr "type" "arith")
-   (set_attr "length" "2")
+   (set_attr "length" "4")
    (set_attr "cc" "set")])
 
 (define_insn "tsthi"
+  [(set (cc0) (match_operand:HI 0 "general_operand" "ra"))]
+  ""
+  "*
+{
+  /* ??? I don't think this is right.  --Jim */
+  if (cc_prev_status.flags & CC_DONE_CBIT)
+    return \"btst      #0,%0l\";
+  else
+    return \"mov.w     %T0,%T0\";
+}"
+  [(set_attr "type" "arith")
+   (set_attr "length" "4")
+   (set_attr "cc" "set")])
+
+(define_insn "tstsi"
+  [(set (cc0) (match_operand:SI 0 "general_operand" "ra"))]
+  "TARGET_H8300H"
+  "*
+{
+  /* ??? I don't think this is right.  --Jim */
+  if (cc_prev_status.flags & CC_DONE_CBIT)
+    return \"btst      #0,%0l\";
+  else
+    return \"mov.l     %S0,%S0\";
+}"
+  [(set_attr "type" "arith")
+   (set_attr "length" "4")
+   (set_attr "cc" "set")])
+
+(define_insn "cmpqi"
   [(set (cc0)
-       (match_operand:HI 0 "register_operand" "ra"))]
+       (compare:QI (match_operand:QI 0 "register_operand" "ra")
+                   (match_operand:QI 1 "nonmemory_operand" "rai")))]
   ""
-  "mov.w       %T0,%T0"
+  "cmp.b       %X1,%X0"
   [(set_attr "type" "arith")
    (set_attr "length" "2")
-   (set_attr "cc" "set")])
+   (set_attr "cc" "compare")])
+
+;; ??? 300h can have an immediate operand here.
 
 (define_insn "cmphi"
   [(set (cc0)
    (set_attr "length" "2")
    (set_attr "cc" "compare")])
 
-(define_insn "cmpqi"
+;; ??? 300h can have an immediate operand here.
+
+(define_insn "cmpsi"
   [(set (cc0)
-       (compare:QI (match_operand:QI 0 "register_operand" "ra")
-                   (match_operand:QI 1 "nonmemory_operand" "rai")))]
-  ""
-  "cmp.b       %X1,%X0"
+       (compare:SI (match_operand:SI 0 "register_operand" "ra")
+                   (match_operand:SI 1 "register_operand" "ra")))]
+  "TARGET_H8300H"
+  "cmp.l       %S1,%S0"
   [(set_attr "type" "arith")
    (set_attr "length" "2")
    (set_attr "cc" "compare")])
-\f
+
 ;; ----------------------------------------------------------------------
-;; Add instructions
+;; ADD INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
-(define_insn ""
+(define_insn "addqi3"
+  [(set (match_operand:QI 0 "register_operand" "=r")
+       (plus:QI (match_operand:QI 1 "register_operand" "%0")
+                (match_operand:QI 2 "nonmemory_operand" "ri")))]
+  ""
+  "add.b       %X2,%X0"
+  [(set_attr "type" "arith")
+   (set_attr "length" "2")
+   (set_attr "cc" "set")])
+
+;; ??? adds operates on the 32bit register.  We can use it because we don't
+;; use the e0-7 registers.
+;; ??? 4 can be handled in one insn on the 300h.
+
+(define_insn "addhi3_internal"
   [(set (match_operand:HI 0 "register_operand" "=ra,ra,ra,ra,r,ra")
        (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0,0")
                 (match_operand:HI 2 "nonmemory_operand" "K,M,L,N,n,ra")))]
   ""
   "@
-   adds        %T2,%T0
-   adds        #2,%T0\;adds    %C2,%T0
-   subs        %M2,%T0
-   subs        #2,%T0\;subs    %M2,%T0
+   adds        %T2,%A0
+   adds        #2,%A0\;adds    %C2,%A0
+   subs        %M2,%A0
+   subs        #2,%A0\;subs    %M2,%A0
    add.b       %s2,%s0\;addx   %t2,%t0 
    add.w       %T2,%T0"
-  [(set_attr "type" "multi,multi,multi,multi,multi,arith")
+  [(set_attr "type" "arith,multi,arith,multi,multi,arith")
    (set_attr "length" "2,4,2,4,4,2")
    (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,clobber,set")])
 
+;; ??? Why is this here?
 (define_expand "addhi3"
   [(set (match_operand:HI 0 "register_operand" "")
        (plus:HI (match_operand:HI 1 "register_operand" "")
                 (match_operand:HI 2 "nonmemory_operand" "")))]
   ""
-  "
-{
-  if (operands[0] != operands[1])
-    emit_move_insn (operands[0], operands[1]);
-}")
+  "")
 
-(define_insn "addqi3"
-  [(set (match_operand:QI 0 "register_operand" "=r")
-       (plus:QI (match_operand:QI 1 "register_operand" "%0")
-                (match_operand:QI 2 "nonmemory_operand" "ri")))]
+(define_expand "addsi3"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (plus:SI (match_operand:SI 1 "register_operand" "")
+                (match_operand:SI 2 "nonmemory_operand" "")))]
   ""
-  "add.b       %X2,%X0"
-  [(set_attr "type" "arith")
-   (set_attr "length" "2")
-   (set_attr "cc" "set")])
+  "")
 
-(define_insn ""
-  [(set (match_operand:SI 0 "register_operand" "=l,l")
-       (plus:SI (match_operand:SI 1 "register_operand" "%0,0")
-                (match_operand:SI 2 "nonmemory_operand" "l,n")))
-   (clobber (match_operand:HI 3 "register_operand" "=&l,l"))]
-  ""
+(define_insn "addsi_h8300"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,&r")
+       (plus:SI (match_operand:SI 1 "register_operand" "%0,0,r")
+                (match_operand:SI 2 "nonmemory_operand" "n,r,r")))]
+  "TARGET_H8300"
   "@
-     add       %w2,%w0\;addx   %x2,%x0\;addx   %y2,%y0\;addx   %z2,%z0
-     add.w     %f2,%f0\;addx   %y2,%y0\;addx   %z2,%z0"
-  [(set_attr "type" "multi")
-   (set_attr "length" "8,6")
+   add %w2,%w0\;addx   %x2,%x0\;addx   %y2,%y0\;addx   %z2,%z0
+   add.w       %f2,%f0\;addx   %y2,%y0\;addx   %z2,%z0
+   mov %f1,%f0\;mov    %e1,%e0\;add.w  %f2,%f0\;addx   %y2,%y0\;addx   %z2,%z0"
+  [(set_attr "type" "arith")
+   (set_attr "length" "8,6,20")
    (set_attr "cc" "clobber")])
 
-(define_insn ""
-  [(set (match_operand:SI 0 "register_operand" "=l,l")
-       (plus:SI (match_operand:SI 1 "register_operand" "%0,0")
-                (match_operand:SI 2 "nonmemory_operand" "n,r")))]
-  ""
+;; ??? 4 can be handled in one insn on the 300h.
+;; ??? Should the 'n' constraint be 'i' here?
+;; ??? We don't handle (reg + symbol_ref) which the 300h can handle.
+
+(define_insn "addsi_h8300h"
+  [(set (match_operand:SI 0 "register_operand" "=ra,ra,ra,ra,r,ra")
+       (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0")
+                (match_operand:SI 2 "nonmemory_operand" "K,M,L,N,n,ra")))]
+  "TARGET_H8300H"
   "@
-     add       %w2,%w0\;addx   %x2,%x0\;addx   %y2,%y0\;addx   %z2,%z0
-     add.w     %f2,%f0\;addx   %y2,%y0\;addx   %z2,%z0"
-  [(set_attr "type" "arith")
-   (set_attr "length" "8,6")
-   (set_attr "cc" "clobber")])
+   adds        %S2,%S0
+   adds        #2,%S0\;adds    %C2,%S0
+   subs        %M2,%S0
+   subs        #2,%S0\;subs    %M2,%S0
+   add.l       %S2,%S0
+   add.l       %S2,%S0"
+  [(set_attr "type" "multi,multi,multi,multi,arith,arith")
+   (set_attr "length" "2,4,2,4,6,2")
+   (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,clobber,clobber")])
 
-(define_expand "addsi3"
-  [(set (match_dup 3) (match_operand:SI 1 "register_operand" ""))
-   (set (match_dup 3)
-       (plus:SI (match_dup 3)
-                (match_operand:SI 2 "nonmemory_operand" "")))
-   (set (match_operand:SI 0 "register_operand" "") (match_dup 3))]
-  ""
-  "
-{
-  operands[3] = gen_rtx (REG, SImode, 0);
-}")
-\f
-;; ----------------------------------------------------------------------;
-;; Subtract instructions
 ;; ----------------------------------------------------------------------
-
-(define_insn ""
-  [(set (match_operand:HI 0 "register_operand" "=ra,ra,ra,r")
-       (minus:HI (match_operand:HI 1 "general_operand" "0,0,0,0")
-                 (match_operand:HI 2 "nonmemory_operand" "K,M,ra,n")))]
-  ""
-  "@
-   subs        %T2,%T0
-   subs        #2,%T0\;subs    %E2,%T0
-   sub.w       %T2,%T0
-   add.b       %E2,%s0\;addx   %F2,%t0 ; -%0"
-  [(set_attr "type" "multi")
-   (set_attr "length" "2,4,2,4")
-   (set_attr "cc" "none_0hit,none_0hit,set,clobber")])
+;; SUBTRACT INSTRUCTIONS
+;; ----------------------------------------------------------------------
 
 (define_insn "subqi3"
   [(set (match_operand:QI 0 "register_operand" "=r,r")
    (set_attr "length" "2")
    (set_attr "cc" "set")])
 
+;; ??? subs operates on the 32bit register.  We can use it because we don't
+;; use the e0-7 registers.
+;; ??? 4 can be handled in one insn on the 300h.
+;; ??? The fourth alternative can use sub.w on the 300h.
+;; ??? Should the 'n' constraint be an 'i' here?
+
+(define_insn "subhi3_internal"
+  [(set (match_operand:HI 0 "register_operand" "=ra,ra,ra,r")
+       (minus:HI (match_operand:HI 1 "general_operand" "0,0,0,0")
+                 (match_operand:HI 2 "nonmemory_operand" "K,M,ra,n")))]
+  ""
+  "@
+   subs        %T2,%T0
+   subs        #2,%T0\;subs    %M2,%T0
+   sub.w       %T2,%T0
+   add.b       %E2,%s0\;addx   %F2,%t0 ; -%0"
+  [(set_attr "type" "multi")
+   (set_attr "length" "2,4,2,4")
+   (set_attr "cc" "none_0hit,none_0hit,set,clobber")])
+
+;; ??? Why is this here?
 (define_expand "subhi3"
   [(set (match_operand:HI 0 "register_operand" "")
        (minus:HI (match_operand:HI 1 "register_operand" "")
                  (match_operand:HI 2 "nonmemory_operand" "")))]
   ""
-  "
-{
-  if (operands[0] != operands[1])
-    emit_move_insn (operands[0], operands[1]);
-}")
+  "")
 
-(define_insn ""
-  [(set (match_operand:SI 0 "register_operand" "=l")
-       (minus:SI (match_operand:SI 1 "register_operand" "%0")
-                 (match_operand:SI 2 "register_operand" "l")))]
+(define_expand "subsi3"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (minus:SI (match_operand:SI 1 "register_operand" "")
+                 (match_operand:SI 2 "nonmemory_operand" "")))]
   ""
+  "")
+
+(define_insn "subsi3_h8300"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (minus:SI (match_operand:SI 1 "register_operand" "0")
+                 (match_operand:SI 2 "register_operand" "r")))]
+  "TARGET_H8300"
   "sub.w       %f2,%f0\;subx   %y2,%y0\;subx   %z2,%z0"
   [(set_attr "type" "arith")
    (set_attr "length" "6")
    (set_attr "cc" "clobber")])
 
-(define_expand "subsi3"
-  [(set (match_dup 3) (match_operand:SI 1 "register_operand" ""))
-   (set (match_dup 3)
-       (minus:SI (match_dup 3)
-                 (match_operand:SI 2 "nonmemory_operand" "")))
-   (set (match_operand:SI 0 "register_operand" "") (match_dup 3))]
-  ""
-  "operands[3] = gen_rtx (REG, SImode, 0);")
+;; ??? 4 can be handled in one insn on the 300h.
+
+(define_insn "subsi3_h8300h"
+  [(set (match_operand:SI 0 "register_operand" "=ra,ra,ra,r")
+       (minus:SI (match_operand:SI 1 "general_operand" "0,0,0,0")
+                 (match_operand:SI 2 "nonmemory_operand" "K,M,ra,n")))]
+  "TARGET_H8300H"
+  "@
+   subs        %T2,%T0
+   subs        #2,%T0\;subs    %E2,%T0
+   sub.l       %S2,%S0
+   sub.l       %S2,%S0"
+  [(set_attr "type" "multi")
+   (set_attr "length" "2,4,2,6")
+   (set_attr "cc" "none_0hit,none_0hit,set,set")])
 
 ;; ----------------------------------------------------------------------
-;; Multiply instruction
+;; MULTIPLY INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
+;; Note that the h8/300 can only handle umulqihi3.
+
+(define_insn "mulqihi3"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (mult:HI (sign_extend:HI (match_operand:QI 1 "general_operand" "%0"))
+                (sign_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
+  "TARGET_H8300H"
+  "mulxs.b     %X2,%T0"
+  [(set_attr "type" "multi")
+   (set_attr "length" "4")
+   (set_attr "cc" "set")])
+
+(define_insn "mulhisi3"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (mult:SI (sign_extend:SI (match_operand:HI 1 "general_operand" "%0"))
+                (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
+  "TARGET_H8300H"
+  "mulxs.w     %T2,%S0"
+  [(set_attr "type" "multi")
+   (set_attr "length" "4")
+   (set_attr "cc" "set")])
+
 (define_insn "umulqihi3"
   [(set (match_operand:HI 0 "register_operand" "=r")
-       (mult:HI (match_operand:QI 1 "general_operand" "%0")
-                (match_operand:QI 2 "register_operand" "r")))]
+       (mult:HI (zero_extend:HI (match_operand:QI 1 "general_operand" "%0"))
+                (zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
   ""
   "mulxu       %X2,%T0"
   [(set_attr "type" "multi")
    (set_attr "length" "2")
    (set_attr "cc" "none_0hit")])
 
+(define_insn "umulhisi3"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (mult:SI (zero_extend:SI (match_operand:HI 1 "general_operand" "%0"))
+                (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
+  "TARGET_H8300H"
+  "mulxu.w     %T2,%S0"
+  [(set_attr "type" "multi")
+   (set_attr "length" "2")
+   (set_attr "cc" "none_0hit")])
+
 ;; ----------------------------------------------------------------------
-;; Divide instructions
+;; DIVIDE INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
 (define_insn "udivqi3"
    (set_attr "length" "2")
    (set_attr "cc" "clobber")])
 
+;; ??? Will divxu always work here?
+
 (define_insn "divqi3"
   [(set (match_operand:QI 0 "register_operand" "=r")
        (div:QI (match_operand:HI 1 "general_operand" "0")
   [(set_attr "type" "multi")
    (set_attr "length" "2")
    (set_attr "cc" "clobber")])
-\f
+
+(define_insn "udivhi3"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (udiv:HI (match_operand:SI 1 "general_operand" "0")
+                (match_operand:HI 2 "register_operand" "r")))]
+  "TARGET_H8300H"
+  "divxu.w     %T2,%S0"
+  [(set_attr "type" "multi")
+   (set_attr "length" "2")
+   (set_attr "cc" "clobber")])
+
+(define_insn "divhi3"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (div:HI (match_operand:SI 1 "general_operand" "0")
+               (match_operand:HI 2 "register_operand" "r")))]
+  "TARGET_H8300H"
+  "divxs.w     %T2,%S0"
+  [(set_attr "type" "multi")
+   (set_attr "length" "4")
+   (set_attr "cc" "clobber")])
+
 ;; ----------------------------------------------------------------------
-;; And instructions
+;; MOD INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
-(define_insn "andqi3"
-  [(set (match_operand:QI 0 "general_operand" "=r")
-       (and:QI (match_operand:QI 1 "general_operand" "%0")
-               (match_operand:QI 2 "general_operand" "rn")))]
+(define_insn "umodqi3"
+  [(set (match_operand:QI 0 "register_operand" "=r")
+       (umod:QI (match_operand:HI 1 "general_operand" "0")
+                (match_operand:QI 2 "register_operand" "r")))]
   ""
-  "and %X2,%X0"
+  "divxu       %X2,%T0\;mov %t0,%s0"
+  [(set_attr "type" "multi")
+   (set_attr "length" "4")
+   (set_attr "cc" "clobber")])
+
+(define_insn "modqi3"
+  [(set (match_operand:QI 0 "register_operand" "=r")
+       (mod:QI (match_operand:HI 1 "general_operand" "0")
+               (match_operand:QI 2 "register_operand" "r")))]
+  "TARGET_H8300H"
+  "divxs.b     %X2,%T0\;mov %t0,%s0"
+  [(set_attr "type" "multi")
+   (set_attr "length" "6")
+   (set_attr "cc" "clobber")])
+
+(define_insn "umodhi3"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (umod:HI (match_operand:SI 1 "general_operand" "0")
+                (match_operand:HI 2 "register_operand" "r")))]
+  "TARGET_H8300H"
+  "divxu.w     %T2,%S0\;mov %e0,%f0"
+  [(set_attr "type" "multi")
+   (set_attr "length" "4")
+   (set_attr "cc" "clobber")])
+
+(define_insn "modhi3"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (mod:HI (match_operand:SI 1 "general_operand" "0")
+               (match_operand:HI 2 "register_operand" "r")))]
+  "TARGET_H8300H"
+  "divxs.w     %T2,%S0\;mov %e0,%f0"
+  [(set_attr "type" "multi")
+   (set_attr "length" "6")
+   (set_attr "cc" "clobber")])
+
+;; ----------------------------------------------------------------------
+;; AND INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+(define_insn "andqi3_internal"
+  [(set (match_operand:QI 0 "bit_operand" "=r,U")
+       (and:QI (match_operand:QI 1 "bit_operand" "%0,0")
+               (match_operand:QI 2 "nonmemory_operand" "rn,O")))]
+  "register_operand (operands[0], QImode) || o_operand (operands[2], QImode)"
+  "@
+   and %X2,%X0
+   bclr        %W2,%X0"
   [(set_attr "type" "arith")
-   (set_attr "length" "2")
-   (set_attr "cc" "set")])
+   (set_attr "length" "2,4")
+   (set_attr "cc" "set,none_0hit")])
+
+(define_expand "andqi3"
+  [(set (match_operand:QI 0 "bit_operand" "=r,U")
+       (and:QI (match_operand:QI 1 "bit_operand" "%0,0")
+               (match_operand:QI 2 "nonmemory_operand" "rn,O")))]
+  ""
+  "
+{
+  if (fix_bit_operand (operands, 'O', AND))
+    DONE;
+}")
+
+;; ??? Should have a bclr case here also.
 
 (define_insn "andhi3"
   [(set (match_operand:HI 0 "register_operand" "=r")
        (and:HI (match_operand:HI 1 "register_operand" "%0")
-               (match_operand:HI 2 "general_operand" "ri")))]
+               (match_operand:HI 2 "nonmemory_operand" "ri")))]
   ""
-  "and %s2,%s0\;and    %t2,%t0"
+  "*
+{
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      int i = INTVAL (operands[2]);
+      if ((i & 0x00ff) != 0x00ff) 
+       output_asm_insn (\"and  %s2,%s0\", operands);
+      if ((i & 0xff00) != 0xff00) 
+       output_asm_insn (\"and  %t2,%t0\", operands);
+      return \"\";
+    }
+  return \"and %s2,%s0\;and    %t2,%t0;\";
+}"
   [(set_attr "type" "multi")
    (set_attr "length" "4")
    (set_attr "cc" "clobber")])
-\f
+
+;; ??? There is an iorsi3 for TARGET_H8300.  Should we have andsi3?
+
+(define_insn "andsi3"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (and:SI (match_operand:SI 1 "register_operand" "%0,0")
+               (match_operand:SI 2 "nonmemory_operand" "r,i")))]
+  "TARGET_H8300H"
+  "@
+   and %S2,%S0
+   and %S2,%S0"
+  [(set_attr "type" "arith")
+   (set_attr "length" "4,6")
+   (set_attr "cc" "clobber")])
+
 ;; ----------------------------------------------------------------------
-;; Or instructions
+;; OR INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
-(define_insn "iorqi3"
-  [(set (match_operand:QI 0 "general_operand" "=r,U")
-       (ior:QI (match_operand:QI 1 "general_operand" "%0,0")
-               (match_operand:QI 2 "general_operand" "rn,P")))]
-  ""
+(define_insn "iorqi3_internal"
+  [(set (match_operand:QI 0 "bit_operand" "=U,r")
+       (ior:QI (match_operand:QI 1 "bit_operand" "%0,0")
+               (match_operand:QI 2 "nonmemory_operand" "P,rn")))]
+  "register_operand (operands[0], QImode) || p_operand (operands[2], QImode)"
   "@
-   or  %X2,%X0
-   bset        %V2,%X0"
+   bset        %V2,%X0
+   or  %X2,%X0"
   [(set_attr "type" "arith")
-   (set_attr "length" "2,4")
-   (set_attr "cc" "set,none_0hit")])
+   (set_attr "length" "4,2")
+   (set_attr "cc" "none_0hit,set")])
+
+(define_expand "iorqi3"
+  [(set (match_operand:QI 0 "bit_operand" "=r,U")
+       (ior:QI (match_operand:QI 1 "bit_operand" "%0,0")
+               (match_operand:QI 2 "nonmemory_operand" "rn,P")))]
+  ""
+  "
+{
+  if (fix_bit_operand (operands, 'P', IOR))
+    DONE;
+}")
+
+;; ??? Should have a bset case here also.
 
 (define_insn "iorhi3"
   [(set (match_operand:HI 0 "general_operand" "=r,r")
        (ior:HI (match_operand:HI 1 "general_operand" "%0,0")
                (match_operand:HI 2 "general_operand" "J,ri")))]
   ""
-  "@
-   or  %s2,%s0
-   or  %s2,%s0\;or     %t2,%t0"
+  "*
+{
+  if (TARGET_H8300)
+    {
+      if (GET_CODE (operands[2]) == CONST_INT)
+       {
+         int i = INTVAL (operands[2]);
+         if ((i & 0x00ff) != 0) 
+           output_asm_insn (\"or       %s2,%s0\", operands);
+         if ((i & 0xff00) != 0) 
+           output_asm_insn (\"or       %t2,%t0\", operands);
+         return \"\";
+       }
+      return \"or      %s2,%s0\;or     %t2,%t0; %2 or2\";
+    }
+  else
+    {
+      return \"or      %S2,%S0\";
+    }
+}"
   [(set_attr "type" "multi")
    (set_attr "length" "2,4")
    (set_attr "cc" "clobber,clobber")])
-\f
+
+(define_insn "iorsi3"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (ior:SI (match_operand:SI 1 "register_operand" "%0")
+               (match_operand:SI 2 "nonmemory_operand" "ri")))]
+  ""
+  "*
+{
+  if (TARGET_H8300)
+    {
+      if (GET_CODE (operands[2]) == CONST_INT)
+       {
+         int i = INTVAL (operands[2]);
+         if ((i & 0x000000ff) != 0) 
+           output_asm_insn (\"or       %w2,%w0\", operands);
+         if ((i & 0x0000ff00) != 0) 
+           output_asm_insn (\"or       %x2,%x0\", operands);
+         if ((i & 0x00ff0000) != 0) 
+           output_asm_insn (\"or       %y2,%y0\", operands);
+         if ((i & 0xff000000) != 0) 
+           output_asm_insn (\"or       %z2,%z0\", operands);
+         return \"\";
+       }
+      return \"or      %w2,%w0\;or     %x2,%x0\;or     %y2,%y0\;or     %z2,%z0\;\";
+    }
+  else
+    {
+      return \"or      %S2,%S0\";
+    }
+}"
+  [(set_attr "type" "multi")
+   (set_attr "length" "8")
+   (set_attr "cc" "clobber")])
+
 ;; ----------------------------------------------------------------------
-;; Xor instructions
+;; XOR INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
-(define_insn "xorqi3"
-  [(set (match_operand:QI 0 "general_operand" "=r")
-       (xor:QI (match_operand:QI 1 "general_operand" "%0")
-               (match_operand:QI 2 "nonmemory_operand" "ri")))]
-  ""
-  "xor %X2,%X0"
+(define_insn "xorqi3_internal"
+  [(set (match_operand:QI 0 "bit_operand" "=r,U")
+       (xor:QI (match_operand:QI 1 "bit_operand" "%0,0")
+               (match_operand:QI 2 "nonmemory_operand" "rn,P")))]
+  "register_operand (operands[0], QImode) || p_operand (operands[2], QImode)"
+  "@
+   xor %X2,%X0
+   bnot        %V2,%X0"
   [(set_attr "type" "arith")
-   (set_attr "length" "2")
-   (set_attr "cc" "set")])
+   (set_attr "length" "2,4")
+   (set_attr "cc" "set,none_0hit")])
+
+(define_expand "xorqi3"
+  [(set (match_operand:QI 0 "bit_operand" "=r,U")
+       (xor:QI (match_operand:QI 1 "bit_operand" "%0,0")
+               (match_operand:QI 2 "nonmemory_operand" "rn,O")))]
+  ""
+  "
+{
+  if (fix_bit_operand (operands, 'O', XOR))
+    DONE;
+}")
 
 (define_insn "xorhi3"
-  [(set (match_operand:HI 0 "general_operand" "=r")
+  [(set (match_operand:HI 0 "register_operand" "=r")
        (xor:HI (match_operand:HI 1 "general_operand" "%0")
                (match_operand:HI 2 "nonmemory_operand" "ri")))]
   ""
-  "xor %s2,%s0\;xor    %t2,%t0"
+  "*
+{
+  if (TARGET_H8300)
+    return \"xor       %s2,%s0\;xor    %t2,%t0\";
+  else
+    return \"xor       %S2,%S0\";
+}"
   [(set_attr "type" "multi")
    (set_attr "length" "4")
    (set_attr "cc" "clobber")])
-\f
+
+;; ??? There is an iorsi3 for TARGET_H8300.  Should we have xorsi3?
+
+(define_insn "xorsi3"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (xor:SI (match_operand:SI 1 "register_operand" "%0,0")
+               (match_operand:SI 2 "nonmemory_operand" "r,i")))]
+  "TARGET_H8300H"
+  "@
+   xor %S2,%S0
+   xor %S2,%S0"
+  [(set_attr "type" "arith")
+   (set_attr "length" "4,6")
+   (set_attr "cc" "clobber")])
+
 ;; ----------------------------------------------------------------------
-;; Negation instructions
+;; NEGATION INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
 (define_insn "negqi2"
   "neg %X0"
   [(set_attr "type" "arith")
    (set_attr "length" "2")
-   (set_attr "cc" "set")])
+   (set_attr "cc" "clobber")])
 
 (define_expand "neghi2"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (neg:HI (match_operand:HI 1 "general_operand" "0")))]
+  ""
+  "
+{
+  if (TARGET_H8300)
+    {
+      emit_insn (gen_neghi2_h8300 (operands[0], operands[1]));
+      DONE;
+    }
+}")
+
+(define_expand "neghi2_h8300"
   [(set (match_dup 2)
        (not:HI (match_operand:HI 1 "register_operand" "r")))
    (set (match_dup 2) (plus:HI (match_dup 2) (const_int 1)))
    (set (match_operand:HI 0 "register_operand" "=r")
        (match_dup 2))]
   ""
-  "operands[2] = gen_reg_rtx (HImode);")
+  "{ operands[2] = gen_reg_rtx (HImode); }")
+
+(define_insn "neghi2_h8300h"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (neg:HI (match_operand:HI 1 "general_operand" "0")))]
+  "TARGET_H8300H"
+  "neg %T0"
+  [(set_attr "type" "arith")
+   (set_attr "length" "2")
+   (set_attr "cc" "clobber")])
 
 (define_expand "negsi2"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (neg:SI (match_operand:SI 1 "general_operand" "0")))]
+  ""
+  "
+{
+  if (TARGET_H8300)
+    {
+      emit_insn (gen_negsi2_h8300 (operands[0], operands[1]));
+      DONE;
+    }
+}")
+
+(define_expand "negsi2_h8300"
   [(set (match_dup 2)
        (not:SI (match_operand:SI 1 "register_operand" "r")))
    (set (match_dup 2) (plus:SI (match_dup 2) (const_int 1)))
    (set (match_operand:SI 0 "register_operand" "=r")
        (match_dup 2))]
   ""
-  "operands[2] = gen_reg_rtx (SImode);")
-\f
+  "{ operands[2] = gen_reg_rtx(SImode); }")
+
+(define_insn "negsi2_h8300h"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (neg:SI (match_operand:SI 1 "general_operand" "0")))]
+  "TARGET_H8300H"
+  "neg %S0"
+  [(set_attr "type" "arith")
+   (set_attr "length" "2")
+   (set_attr "cc" "clobber")])
+
 ;; ----------------------------------------------------------------------
-;; Not instructions
+;; NOT INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
 (define_insn "one_cmplqi2"
   [(set (match_operand:HI 0 "register_operand" "=r")
        (not:HI (match_operand:HI 1 "general_operand" "0")))]
   ""
-  "not %s0\;not        %t0"
+  "*
+{
+  if (TARGET_H8300)
+    return \"not       %s0\;not        %t0\";
+  else
+    return \"not       %T0\";
+}"
   [(set_attr "type" "arith")
    (set_attr "length" "4")
    (set_attr "cc" "clobber")])
   [(set (match_operand:SI 0 "register_operand" "=r")
        (not:SI (match_operand:SI 1 "general_operand" "0")))]
   ""
-  "not %w0\;not        %x0\;not        %y0\;not        %z0"
+  "*
+{
+  if (TARGET_H8300)
+    return \"not       %w0\;not        %x0\;not        %y0\;not        %z0\";
+  else
+    return \"not       %S0\";
+}"
   [(set_attr "type" "arith")
+;; ??? length is wrong for 300h
    (set_attr "length" "8")
    (set_attr "cc" "clobber")])
-\f
+
 ;; ----------------------------------------------------------------------
-;; Conditional branches
+;; JUMP INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
+;; Conditional jump instructions
+
 (define_expand "ble"
   [(set (pc)
        (if_then_else (le (cc0)
   ""
   "")
 
-(define_insn ""
+(define_insn "branch_true"
   [(set (pc)
-       (if_then_else 
-        (match_operator 1 "comparison_operator" [(cc0) (const_int 0)])
-        (label_ref (match_operand 0 "" ""))
-        (pc)))]
+       (if_then_else (match_operator 1 "comparison_operator"
+                                     [(cc0) (const_int 0)])
+                     (label_ref (match_operand 0 "" ""))
+                     (pc)))]
   ""
   "*
 {
   if (get_attr_length (insn) == 2) 
-   return \"b%j1       %l0\";
+    return \"b%j1      %l0\";
+  else if (get_attr_length (insn) == 4) 
+    return \"b%j1      %l0:16\";
   else
-   return \"b%k1       %L0\;jmp        @%l0\;%L0:\";
+    return \"b%k1      %L0\;jmp        @%l0\;%L0:\";
 }" 
 [(set_attr "type" "branch")
+ [(set_attr "type" "branch")
    (set_attr "cc" "none")])
 
-(define_insn ""
+(define_insn "branch_false"
   [(set (pc)
-       (if_then_else
-        (match_operator 1 "comparison_operator" [(cc0) (const_int 0)])
-        (pc)
-        (label_ref (match_operand 0 "" ""))))]
+       (if_then_else (match_operator 1 "comparison_operator"
+                                     [(cc0) (const_int 0)])
+                     (pc)
+                     (label_ref (match_operand 0 "" ""))))]
   ""
+;; ??? We don't take advantage of 16 bit relative jumps in the 300h.
   "*
 {
   if (get_attr_length (insn) == 2) 
-   return \"b%k1       %l0\";
+    return \"b%k1      %l0\";
+  else if (get_attr_length (insn) == 4) 
+    return \"b%k1      %l0:16\";
   else
-   return \"b%j1       %L0\;jmp        @%l0\;%L0:\";
+    return \"b%j1      %L0\;jmp        @%l0\;%L0:\";
 }"
   [(set_attr "type" "branch")
    (set_attr "cc" "none")])
-\f
-;; ----------------------------------------------------------------------
-;; Unconditional branches
-;; ----------------------------------------------------------------------
+
+;; Unconditional and other jump instructions.
 
 (define_insn "jump"
   [(set (pc)
   ""
   "*
 {
-  if (get_attr_length (insn) == 2) 
-   return \"bra        %l0\";
+  if (get_attr_length (insn) == 2)
+    return \"bra       %l0\";
+  else if (get_attr_length (insn) == 4)
+    return \"bra       %l0:16\";
   else
-   return \"jmp        @%l0\";
+    return \"jmp       @%l0\";
 }"
   [(set_attr "type" "branch")
    (set_attr "cc" "none")])
 
-(define_insn "tablejump"
+;; This is a define expand, because pointers may be either 16 or 32 bits.
+
+(define_expand "tablejump"
+  [(parallel [(set (pc) (match_operand 0 "register_operand" "r"))
+             (use (label_ref (match_operand 1 "" "")))])]
+  ""
+  "")
+
+(define_insn "tablejump_h8300"
   [(set (pc) (match_operand:HI 0 "register_operand" ""))
    (use (label_ref (match_operand 1 "" "")))]
-  ""
+  "TARGET_H8300"
   "jmp @%0"
   [(set_attr "type" "branch")
    (set_attr "cc" "none")
    (set_attr "length" "2")])
 
-;; Call subroutine with no return value.
+(define_insn "tablejump_h8300h"
+  [(set (pc) (match_operand:SI 0 "register_operand" ""))
+   (use (label_ref (match_operand 1 "" "")))]
+  "TARGET_H8300H"
+  "jmp @%0"
+  [(set_attr "type" "branch")
+   (set_attr "cc" "none")
+   (set_attr "length" "2")])
 
-(define_insn "call"
-  [(call (match_operand:QI 0 "memory_operand" "o")
-        (match_operand:HI 1 "general_operand" "g"))]
+;; This is a define expand, because pointers may be either 16 or 32 bits.
+
+;(define_insn "indirect_jump"
+;  [(set (pc) (match_operand:HI 0 "register_operand" "r"))]
+;  ""
+;  "jmp        @%0"
+;  [(set_attr "type" "branch")
+;   (set_attr "cc" "none")
+;   (set_attr "length" "2")])
+
+(define_expand "indirect_jump"
+  [(set (pc) (match_operand 0 "jump_address_operand" "Vr"))]
+  ""
+  "")
+
+(define_insn "indirect_jump_h8300"
+  [(set (pc) (match_operand:HI 0 "jump_address_operand" "V,r"))]
+  "TARGET_H8300"
+  "@
+   jmp @%0
+   jmp @%0"
+  [(set_attr "type" "branch")
+   (set_attr "cc" "none")
+   (set_attr "length" "2")])
+
+(define_insn "indirect_jump_h8300h"
+  [(set (pc) (match_operand:SI 0 "jump_address_operand" "V,r"))]
+  "TARGET_H8300H"
+  "@
+   jmp @%0
+   jmp @%0"
+  [(set_attr "type" "branch")
+   (set_attr "cc" "none")
+   (set_attr "length" "2")])
+
+;; Call subroutine with no return value.
+
+;; ??? Even though we use HImode here, this works for the 300h.
+
+(define_insn "call"
+  [(call (match_operand:QI 0 "call_insn_operand" "or")
+        (match_operand:HI 1 "general_operand" "g"))]
   ""
   "jsr %0"
   [(set_attr "type" "call")
 ;; Call subroutine, returning value in operand 0
 ;; (which must be a hard register).
 
+;; ??? Even though we use HImode here, this works on the 300h.
+
 (define_insn "call_value"
   [(set (match_operand 0 "" "=r")
-       (call (match_operand:QI 1 "memory_operand" "o")
+       (call (match_operand:QI 1 "call_insn_operand" "or")
              (match_operand:HI 2 "general_operand" "g")))]
   ""
   "jsr %1"
    (set_attr "cc" "none")
    (set_attr "length" "2")])
 
-(define_insn "indirect_jump"
-  [(set (pc) (match_operand:HI 0 "register_operand" "r"))]
-  ""
-  "jmp @%0"
-  [(set_attr "type" "branch")
-   (set_attr "cc" "none")
-   (set_attr "length" "2")])
-\f
-;; -----------------------------------------------------------------
-;; Shifts
-;; -----------------------------------------------------------------
-
-;; All H8 shifts go one bit at a time, here they are defined with names
-;; so can use them in the expands..
-
-;; QI BIT SHIFTS
-
-(define_insn "ashlqi3_one"
-  [(set (match_operand:QI 0 "register_operand" "=r")
-       (ashift:QI (match_operand:QI 1 "register_operand" "0")
-                  (const_int 1)))]
-  ""
-  "shal %X0"
-  [(set_attr "type" "arith")
-   (set_attr "length" "2")
-   (set_attr "cc" "set")])
+;; ----------------------------------------------------------------------
+;; EXTEND INSTRUCTIONS
+;; ----------------------------------------------------------------------
 
-(define_insn "ashrqi3_one"
-  [(set (match_operand:QI 0 "register_operand" "=r")
-       (ashiftrt:QI (match_operand:QI 1 "register_operand" "0")
-                    (const_int 1)))]
+(define_insn "zero_extendqihi2"
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (zero_extend:HI (match_operand:QI 1 "general_operand" "0,g")))]
   ""
-  "shar %X0"
-  [(set_attr "type" "arith")
-   (set_attr "length" "2")
-   (set_attr "cc" "set")])
+  "*
+{
+  if (which_alternative==0)
+    return \"mov.b     #0,%t0\";
 
-(define_insn "lshrqi3_one"
-  [(set (match_operand:QI 0 "register_operand" "=r")
-       (lshiftrt:QI (match_operand:QI 1 "register_operand" "0")
-                    (const_int 1)))]
-  ""
-  "shlr %X0"
-  [(set_attr "type" "arith")
-   (set_attr "length" "2")
-   (set_attr "cc" "set")])
+  if (TARGET_H8300)
+    return \"mov.b     %X1,%s0\;mov.b  #0,%t0\";
+  else
+    {
+      /* ??? See how often this gets optimized.  */
+      if (REG_P (operands[1]) && (REGNO (operands[1]) == REGNO (operands[0])))
+       return \"extu.w %T0\";
+      else
+       return \"mov.b  %X1,%s0\;extu.w %T0\";
+    }
+}"
+  [(set_attr "type" "multi")
+;; ??? This length is wrong for one case.
+   (set_attr "length" "4")
+   (set_attr "cc" "clobber")])
 
-(define_expand "ashlqi3"
-  [(set (match_operand:QI 0 "register_operand" "=r")
-       (ashift:QI (match_operand:QI 1 "register_operand" "0")
-                  (match_operand:QI 2 "nonmemory_operand" "rn")))]
-  ""
-  "
+(define_insn "zero_extendhisi2"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (zero_extend:SI (match_operand:HI 1 "general_operand" "g")))]
+  "TARGET_H8300H"
+  "*
 {
-  if (can_shift (ASHIFT, operands, gen_ashlqi3_one, 4, 0))
-    DONE;
+  /* ??? See how often this gets optimized.  */
+  if (REG_P (operands[1]) && (REGNO (operands[1]) == REGNO (operands[0])))
+    return \"extu.l    %S0\";
   else
-    FAIL;
-}")
+    return \"mov.w     %T1,%T0\;extu.l %S0\";
+}"
+  [(set_attr "type" "multi")
+;; ??? This length is wrong for one case.
+   (set_attr "length" "4")
+   (set_attr "cc" "clobber")])
 
-(define_expand "ashrqi3"
-  [(set (match_operand:QI 0 "register_operand" "=r")
-       (ashiftrt:QI (match_operand:QI 1 "register_operand" "0")
-                    (match_operand:QI 2 "nonmemory_operand" "rn")))]
+(define_insn "extendqihi2"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (sign_extend:HI (match_operand:QI 1 "general_operand" "g")))]
   ""
-  "
+  "*
 {
-  if (can_shift (ASHIFTRT, operands, gen_ashrqi3_one, 4, 0))
-    DONE;
+  if (TARGET_H8300)
+    {
+      /* ??? See how often this gets optimized.  */
+      if (REG_P (operands[1]) && (REGNO (operands[1]) == REGNO (operands[0])))
+       return \"bld    #7,%s0\;subx    %t0,%t0\";
+      else
+       return \"mov.b  %X1,%s0\;bld    #7,%s0\;subx    %t0,%t0\";
+    }
   else
-    FAIL;
-}")
+    {
+      /* ??? See how often this gets optimized.  */
+      if (REG_P (operands[1]) && (REGNO (operands[1]) == REGNO (operands[0])))
+       return \"exts.w %T0\";
+      else
+       return \"mov.b  %X1,%s0\;exts.w %T0\";
+    }
+}"
+  [(set_attr "type" "multi")
+;; ??? Length is wrong in some cases.
+   (set_attr "length" "6")
+   (set_attr "cc" "clobber")])
 
-(define_expand "lshrqi3"
-  [(set (match_operand:QI 0 "register_operand" "=r")
-       (lshiftrt:QI (match_operand:QI 1 "register_operand" "0")
-                    (match_operand:QI 2 "nonmemory_operand" "rn")))]
+(define_expand "extendhisi2"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (sign_extend:SI (match_operand:HI 1 "general_operand" "")))]
   ""
   "
 {
-  if (can_shift (LSHIFTRT, operands, gen_lshrqi3_one, 4, 0))
-    DONE;
+  if (TARGET_H8300)
+    emit_insn (gen_extendhisi2_h8300 (operands[0], operands[1]));
   else
-    FAIL;
+    emit_insn (gen_extendhisi2_h8300h (operands[0], operands[1]));
+  DONE;
 }")
 
-;;  HI BIT SHIFTS
+(define_expand "extendhisi2_h8300"
+  [(set (reg:HI 1) (match_operand:HI 1 "general_operand" ""))
+   (set (reg:SI 0) (sign_extend:SI (reg:HI 1)))
+   (set (match_operand:SI 0 "general_operand" "" ) (reg:SI 0))]
+  "TARGET_H8300"
+  "")
 
-(define_insn "ashlhi3_one"
-  [(set (match_operand:HI 0 "register_operand" "=r")
-       (ashift:HI (match_operand:HI 1 "register_operand" "0")
-                  (const_int 1)))]
-  ""
-  "add.w       %T1,%T0"
-  [(set_attr "type" "multi")
-   (set_attr "length" "4")
-   (set_attr "cc" "set")])
+(define_expand "extendhisi2_h8300h"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (sign_extend:SI (match_operand:HI 1 "general_operand" "")))]
+  "TARGET_H8300H"
+  "")
 
-(define_insn "ashlhi3_eight"
-  [(set (match_operand:HI 0 "register_operand" "=r")
-       (ashift:HI (match_operand:HI 1 "register_operand" "0")
-                  (const_int 8)))]
-  ""
-  "mov.b       %s1,%t0\;mov.b  #0,%s0"
-  [(set_attr "type" "multi")
-   (set_attr "length" "4")
+(define_insn "extendhisi2_h8300_internal"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (sign_extend:SI (match_operand:HI 1 "register_operand" "0")))]
+  "TARGET_H8300"
+  "mov.w       %T1,%f0\;bld    #7,%x0\;subx    %y0,%y0\;subx   %z0,%z0"
+  [(set_attr "length" "10")
    (set_attr "cc" "clobber")])
 
-(define_expand "ashlhi3"
-  [(set (match_operand:HI 0 "register_operand" "")
-       (ashift:HI
-        (match_operand:HI 1 "general_operand_src" "")
-        (match_operand:HI 2 "nonmemory_operand" "")))]
-  ""
-  "
+(define_insn "extendhisi2_h8300h_internal"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (sign_extend:SI (match_operand:HI 1 "general_operand" "g")))]
+  "TARGET_H8300H"
+  "*
 {
-  if (can_shift (ASHIFT, operands, gen_ashlhi3_one, 4, gen_ashlhi3_eight)) 
-    DONE;
+  /* ??? See how often this gets optimized.  */
+  if (REG_P (operands[1]) && (REGNO (operands[1]) == REGNO (operands[0])))
+    return \"exts.l    %S0\";
   else
-    FAIL;
-}")
+    return \"mov.w     %T1,%T0\;exts.l %S0\";
+}"
+  [(set_attr "length" "10")
+   (set_attr "cc" "clobber")])
 
-(define_insn "lshrhi3_one"
-  [(set (match_operand:HI 0 "register_operand" "=r")
-       (lshiftrt:HI (match_operand:HI 1 "register_operand" "0")
-                    (const_int 1)))]
+;; ----------------------------------------------------------------------
+;; SHIFTS
+;; ----------------------------------------------------------------------
+;;
+;; We make some attempt to provide real efficient shifting.  One example is
+;; doing an 8 bit shift of a 16 bit value by moving a byte reg into the other
+;; reg and moving 0 into the former reg.
+;;
+;; We also try to achieve this in a uniform way.  IE: We don't try to achieve
+;; this in both rtl and at insn emit time.  Ideally, we'd use rtl as that would
+;; give the optimizer more cracks at the code.  However, we wish to do things
+;; like optimizing shifting the sign bit to bit 0 by rotating the other way.
+;; There is rtl to handle this (rotate + and), but the h8/300 doesn't handle
+;; 16 bit rotates.  Also, if we emit complicated rtl, combine may not be able
+;; to detect cases it can optimize.
+;;
+;; For these and other fuzzy reasons, I've decided to go the less pretty but
+;; easier "do it at insn emit time" route.
+
+;; QI BIT SHIFTS
+
+(define_expand "ashlqi3"
+  [(set (match_operand:QI 0 "register_operand" "")
+       (ashift:QI (match_operand:QI 1 "register_operand" "")
+                  (match_operand:QI 2 "nonmemory_operand" "")))]
   ""
-  "shlr        %t0\;rotxr      %s0"
-  [(set_attr "type" "multi")
-   (set_attr "length" "4")
-   (set_attr "cc" "clobber")])
+  "if (expand_a_shift (QImode, ASHIFT, operands)) DONE;else FAIL;")
 
-(define_insn "lshrhi3_eight"
-  [(set (match_operand:HI 0 "register_operand" "=r")
-       (lshiftrt:HI (match_operand:HI 1 "register_operand" "0")
-                    (const_int 8)))]
+(define_expand "ashrqi3"
+  [(set (match_operand:QI 0 "register_operand" "")
+       (ashiftrt:QI (match_operand:QI 1 "register_operand" "")
+                    (match_operand:QI 2 "nonmemory_operand" "")))]
   ""
-  "mov.b       %t1,%s0\;mov.b  #0,%t0"
-  [(set_attr "type" "multi")
-   (set_attr "length" "4")
-   (set_attr "cc" "clobber")])
+  "if (expand_a_shift (QImode, ASHIFTRT, operands)) DONE;else FAIL;")
 
-(define_expand "lshrhi3"
-  [(set (match_operand:HI 0 "register_operand" "")
-       (lshiftrt:HI
-        (match_operand:HI 1 "general_operand_src" "")
-        (match_operand:HI 2 "nonmemory_operand" "")))]
+(define_expand "lshrqi3"
+  [(set (match_operand:QI 0 "register_operand" "")
+       (lshiftrt:QI (match_operand:QI 1 "register_operand" "")
+                    (match_operand:QI 2 "nonmemory_operand" "")))]
   ""
-  "
-{
-  if (can_shift (LSHIFTRT, operands, gen_lshrhi3_one, 4, gen_lshrhi3_eight))
-    DONE;
-  else
-    FAIL;
-}")
+  "if (expand_a_shift (QImode, LSHIFTRT, operands)) DONE;else FAIL;")
 
-(define_insn "ashrhi3_one"
-  [(set (match_operand:HI 0 "register_operand" "=r")
-       (ashiftrt:HI (match_operand:HI 1 "register_operand" "0")
-                    (const_int 1)))]
+;; WARNING: The constraints on the scratch register say one is not needed
+;; for constant shifts of 1,2,3,4.  Emit_a_shift() must know this.
+
+(define_insn "shiftbyn_QI"
+  [(set (match_operand:QI 0 "register_operand" "=r,r")
+       (match_operator:QI 3 "nshift_operator" 
+                       [ (match_operand:QI 1 "register_operand" "0,0")
+                         (match_operand:QI 2 "nonmemory_operand" "IKM,rn")]))
+   (clobber (match_scratch:QI 4 "=X,&r"))]
   ""
-  "shar        %t0\;rotxr      %s0"
-  [(set_attr "type" "multi")
-   (set_attr "length" "4")
+  "* return emit_a_shift (insn, operands);"
+  [(set_attr "type" "arith")
+   (set_attr "length" "20")
+;; ??? We'd like to indicate that cc is set here, and it is for simple shifts.
+;; However, for cases that loop or are done in pieces, cc does not contain
+;; what we want.  Emit_a_shift is free to tweak cc_status as desired.
    (set_attr "cc" "clobber")])
 
-; signed shift right by 8 bits
-; fetch the carry bit from the top, copy the byte right, subtract the 
-; top byte from itself - carry.
+;; HI BIT SHIFTS
 
-(define_insn "ashrhi3_eight"
-  [(set (match_operand:HI 0 "register_operand" "=r")
-       (ashiftrt:HI (match_operand:HI 1 "register_operand" "0")
-                    (const_int 8)))]
+(define_expand "ashlhi3"
+  [(set (match_operand:HI 0 "register_operand" "")
+       (ashift:HI (match_operand:HI 1 "nonmemory_operand" "")
+                  (match_operand:QI 2 "nonmemory_operand" "")))]
   ""
-  "bld #7,%t0\;mov.b   %t0,%s0\;subx   %t0,%t0"
-  [(set_attr "type" "multi")
-   (set_attr "length" "6")
-   (set_attr "cc" "clobber")])
+  "if (expand_a_shift (HImode, ASHIFT, operands)) DONE;else FAIL;")
+
+(define_expand "lshrhi3"
+  [(set (match_operand:HI 0 "register_operand" "")
+       (lshiftrt:HI (match_operand:HI 1 "general_operand_src" "")
+                    (match_operand:QI 2 "nonmemory_operand" "")))]
+  ""
+  "if (expand_a_shift (HImode, LSHIFTRT, operands)) DONE;else FAIL;")
 
 (define_expand "ashrhi3"
   [(set (match_operand:HI 0 "register_operand" "")
-       (ashiftrt:HI
-        (match_operand:HI 1 "general_operand_src" "")
-        (match_operand:HI 2 "nonmemory_operand" "")))]
+       (ashiftrt:HI (match_operand:HI 1 "register_operand" "")
+                    (match_operand:QI 2 "nonmemory_operand" "")))]
   ""
-  "
-{
-  if (can_shift (ASHIFTRT, operands, gen_ashrhi3_one, 4, gen_ashrhi3_eight)) 
-    DONE;
-  else
-    FAIL;
-}")
+  "if (expand_a_shift (HImode, ASHIFTRT, operands)) DONE;else FAIL;")
 
-;; SI BIT SHIFTS
+;; WARNING: The constraints on the scratch register say one is not needed
+;; for constant shifts of 1,2,3,4.  Emit_a_shift() must know this.
 
-(define_insn "ashlsi3_one"
-  [(set (match_operand:SI 0 "register_operand" "=r")
-       (ashift:SI (match_operand:SI 1 "register_operand" "0")
-                  (const_int 1)))]
+(define_insn "shiftbyn_HI"
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (match_operator:HI 3 "nshift_operator" 
+                       [ (match_operand:HI 1 "register_operand" "0,0")
+                         (match_operand:QI 2 "nonmemory_operand" "IKM,rn")]))
+   (clobber (match_scratch:QI 4 "=X,&r"))]
   ""
-  "add.w       %f1,%f0\;addx   %y1,%y0\;addx   %z1,%z0"
-  [(set_attr "type" "multi")
-   (set_attr "length" "6")
+  "* return emit_a_shift (insn, operands);"
+  [(set_attr "type" "arith")
+   (set_attr "length" "20")
+;; ??? We'd like to indicate that cc is set here, and it is for simple shifts.
+;; However, for cases that loop or are done in pieces, cc does not contain
+;; what we want.  Emit_a_shift is free to tweak cc_status as desired.
    (set_attr "cc" "clobber")])
 
+;;  SI BIT SHIFTS
+
 (define_expand "ashlsi3"
   [(set (match_operand:SI 0 "register_operand" "")
        (ashift:SI
         (match_operand:SI 1 "general_operand_src" "")
-        (match_operand:SI 2 "nonmemory_operand" "")))]
+        (match_operand:QI 2 "nonmemory_operand" "")))]
   ""
-  "
-{
-  if (can_shift (ASHIFT, operands, gen_ashlsi3_one, 1, 0))
-    DONE;
-  else
-    FAIL;
-}")
-
-(define_insn "lshrsi3_one"
-  [(set (match_operand:SI 0 "register_operand" "=r")
-       (lshiftrt:SI (match_operand:SI 1 "register_operand" "0")
-                    (const_int 1)))]
-  ""
-  "shlr        %z0\;rotxr      %y0\;rotxr      %x0\;rotxr      %w0"
-  [(set_attr "type" "multi")
-   (set_attr "length" "8")
-   (set_attr "cc" "clobber")])
+  "if (expand_a_shift (SImode, ASHIFT, operands)) DONE;else FAIL;")
 
 (define_expand "lshrsi3"
   [(set (match_operand:SI 0 "register_operand" "")
        (lshiftrt:SI
         (match_operand:SI 1 "general_operand_src" "")
-        (match_operand:SI 2 "nonmemory_operand" "")))]
-  ""
-  "
-{
-  if (can_shift (LSHIFTRT, operands, gen_lshrsi3_one, 1, 0))
-    DONE;
-  else
-    FAIL;
-}")
-
-(define_insn "ashrsi3_one"
-  [(set (match_operand:SI 0 "register_operand" "=r")
-       (ashiftrt:SI (match_operand:SI 1 "register_operand" "0")
-                    (const_int 1)))]
+        (match_operand:QI 2 "nonmemory_operand" "")))]
   ""
-  "shar        %z0\;rotxr      %y0\;rotxr      %x0\;rotxr      %w0"
-  [(set_attr "type" "multi")
-   (set_attr "length" "16")
-   (set_attr "cc" "clobber")])
+  "if (expand_a_shift (SImode, LSHIFTRT, operands)) DONE;else FAIL;")
 
 (define_expand "ashrsi3"
   [(set (match_operand:SI 0 "register_operand" "")
        (ashiftrt:SI
         (match_operand:SI 1 "general_operand_src" "")
-        (match_operand:SI 2 "nonmemory_operand" "")))]
+        (match_operand:QI 2 "nonmemory_operand" "")))]
   ""
-  "
-{
-  if (can_shift (ASHIFTRT, operands, gen_ashrsi3_one, 1, 0))
-    DONE;
-  else
-    FAIL;
-}")
+  "if (expand_a_shift (SImode, ASHIFTRT, operands)) DONE;else FAIL;")
 
-;; ----------------------------------------------------------------------
-;; BIT FIELDS
-;; ----------------------------------------------------------------------
+;; WARNING: The constraints on the scratch register say one is not needed
+;; for constant shifts of 1,2.  Emit_a_shift() must know this.
 
-(define_insn ""
-  [(set (zero_extract:HI (match_operand:HI 0 "register_operand" "+r")
-                        (const_int 1)
-                        (match_operand:HI 2 "general_operand" "g"))
-       (match_operand:HI 3 "general_operand" "r"))]
+(define_insn "shiftbyn_SI"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (match_operator:SI 3 "nshift_operator" 
+                       [ (match_operand:SI 1 "register_operand" "0,0")
+                         (match_operand:QI 2 "nonmemory_operand" "IK,rn")]))
+   (clobber (match_scratch:QI 4 "=X,&r"))]
   ""
-  "bld #0,%3l\;bst     %Z2,%0%Y1"
-  [(set_attr "type" "multi")
-   (set_attr "length" "4")
+  "* return emit_a_shift (insn, operands);"
+  [(set_attr "type" "arith")
+   (set_attr "length" "20")
+;; ??? We'd like to indicate that cc is set here, and it is for simple shifts.
+;; However, for cases that loop or are done in pieces, cc does not contain
+;; what we want.  Emit_a_shift is free to tweak cc_status as desired.
    (set_attr "cc" "clobber")])
 
-(define_expand "insv"
-  [(set (zero_extract:HI (match_operand:HI 0 "register_operand" "+r")
-                        (match_operand:HI 1 "general_operand" "g")
-                        (match_operand:HI 2 "general_operand" "g"))
-       (match_operand:HI 3 "general_operand" "r"))]
-  ""
-  "if (INTVAL (operands[1]) != 1) FAIL;")
+;; -----------------------------------------------------------------
+;; BIT FIELDS
+;; -----------------------------------------------------------------
+;; The H8/300 has given 1/8th of its opcode space to bitfield
+;; instuctions so let's use them as well as we can
 
-(define_insn ""
-  [(set (match_operand:HI 0 "register_operand" "=&r")
-       (zero_extract:HI (match_operand:HI 1 "register_operand" "r")
-                        (const_int 1)
-                        (match_operand:HI 3 "general_operand" "g")))]
+;; BCC and BCS patterns.
+
+(define_insn "bcs_qiqi"
+  [(set (pc)
+       (if_then_else 
+        (match_operator 1 "eq_operator"
+                        [(zero_extract:QI (match_operand:QI 2 "bit_operand" "Ur")
+                                          (const_int 1)
+                                          (match_operand:HI 3 "immediate_operand" "i"))
+                         (const_int 0)])
+        (label_ref (match_operand 0 "" ""))
+        (pc)))]
   ""
-  "sub.w       %T0,%T0\;bld    %Z3,%T1%Y1\;rotxl       %T0l"
-  [(set_attr "type" "multi")
-   (set_attr "length" "6")
+  "*
+{
+  output_asm_insn(\"bld        %Z3,%Y2\", operands);
+  if (get_attr_length (insn) == 2) 
+    return \"b%d1      %l0\";
+  else if (get_attr_length (insn) == 4) 
+    return \"b%d1      %l0:16\";
+  else
+    return \"b%g1      %L0\;jmp        @%l0\;%L0:\";
+}" 
+  [(set_attr "type" "branch")
    (set_attr "cc" "clobber")])
 
-(define_insn ""
-  [(set (match_operand:HI 0 "register_operand" "=r")
-       (sign_extract:HI (match_operand:HI 1 "register_operand" "r")
-                        (const_int 1)
-                        (match_operand:HI 3 "general_operand" "g")))]
+(define_insn "bcs_hihi"
+  [(set (pc)
+       (if_then_else 
+        (match_operator 1 "eq_operator"
+                        [(zero_extract:HI (match_operand:HI 2 "bit_operand" "Ur")
+                                          (const_int 1)
+                                          (match_operand:HI 3 "immediate_operand" "i"))
+                         (const_int 0)])
+        (label_ref (match_operand 0 "" ""))
+        (pc)))]
   ""
-  "bld %Z3,%1%Y1\;sub.x        %0l,%0l\;mov.b  %0l,%0h"
-  [(set_attr "type" "multi")
-   (set_attr "length" "6")
+  "*
+{
+  output_asm_insn(\"bld        %Z3,%Y2\", operands);
+  if (get_attr_length (insn) == 2) 
+    return \"%d1       %l0\";
+  else if (get_attr_length (insn) == 4) 
+    return \"%d1       %l0:16\";
+  else
+    return \"%g1       %L0\;jmp        @%l0\;%L0:\";
+}" 
+  [(set_attr "type" "branch")
    (set_attr "cc" "clobber")])
 
-(define_expand "extzv"
-  [(set (match_operand:HI 0 "register_operand" "")
-       (zero_extract:HI (match_operand:HI 1 "register_operand" "")
-                        (match_operand:HI 2 "general_operand" "")
-                        (match_operand:HI 3 "general_operand" "")))]
+(define_insn "bcs_hiqi"
+  [(set (pc)
+       (if_then_else 
+        (match_operator 1 "eq_operator"
+                        [(zero_extract:HI (match_operand:QI 2 "bit_operand" "Ur")
+                                          (const_int 1)
+                                          (match_operand:HI 3 "immediate_operand" "i"))
+                         (const_int 0)])
+        (label_ref (match_operand 0 "" ""))
+        (pc)))]
   ""
-  "if (INTVAL (operands[2]) != 1) FAIL;")
+  "*
+{
+  output_asm_insn(\"bld        %Z3,%Y2\", operands);
+  if (get_attr_length (insn) == 2) 
+    return \"%d1       %l0\";
+  else if (get_attr_length (insn) == 4) 
+    return \"%d1       %l0:16\";
+  else
+    return \"%g1       %L0\;jmp        @%l0\;%L0:\";
+}" 
+  [(set_attr "type" "branch")
+   (set_attr "cc" "clobber")])
 
-(define_expand "extv"
-  [(set (match_operand:HI 0 "register_operand" "")
-       (sign_extract:HI (match_operand:HI 1 "register_operand" "")
-                        (match_operand:HI 2 "general_operand" "")
-                        (match_operand:HI 3 "immediate_operand" "")))]
+;; BLD and BST patterns
+
+(define_insn "extract_1"
+  [(set (match_operand:HI 0 "register_operand" "=&r")
+       (zero_extract:HI (match_operand:QI 1 "bit_operand" "Ur")
+                        (const_int 1)
+                        (match_operand:HI 2 "immediate_operand" "i")))]
   ""
-  "if (INTVAL (operands[2]) != 1)  FAIL;")
-\f
-;; ----------------------------------------------------------------------
-;; Conversions
-;; ----------------------------------------------------------------------
+  "sub.w       %0,%0\;bld      %Z2,%Y1\;bst    #0,%X0")
 
-(define_insn "zero_extendqihi2"
-  [(set (match_operand:HI 0 "register_operand" "=r")
-       (zero_extend:HI
-        (match_operand:QI 1 "general_operand" "g")))]
+(define_insn "extract_1_hi"
+  [(set (match_operand:HI 0 "register_operand" "=&r")
+       (zero_extract:HI (match_operand:HI 1 "bit_operand" "Ur")
+                        (const_int 1)
+                        (match_operand:HI 2 "immediate_operand" "i")))]
   ""
-  "mov.b       %X1,%s0\;mov.b  #0,%t0"
-  [(set_attr "type" "multi")
-   (set_attr "length" "4")
-   (set_attr "cc" "clobber")])
+  "sub.w       %0,%0\;bld      %Z2,%Y1\;bst    #0,%X0")
 
-(define_insn "extendqihi2"
-  [(set (match_operand:HI 0 "register_operand" "=r")
-       (sign_extend:HI
-        (match_operand:QI 1 "register_operand" "r")))]
+(define_insn "insert_1"
+  [(set (zero_extract:HI (match_operand:QI 0 "bit_operand" "+Ur")
+                        (const_int 1)
+                        (match_operand:HI 1 "immediate_operand" "i"))
+       (zero_extract:HI (match_operand:QI 2 "bit_operand" "Ur")
+                        (const_int 1)
+                        (const_int 0)))]
   ""
-  "*
+  "bld #0,%X2\;bst     %Z1,%Y0 ; i1")
+
+;; This is how combine canonicalizes this pattern.  This is perhaps a bug
+;; in combine.c, but there is no problem with writing it this way so we do.
+(define_insn "extract_insert_1"
+  [(set (zero_extract:QI (match_operand:QI 0 "bit_operand" "+Ur")
+                        (const_int 1)
+                        (match_operand:HI 1 "immediate_operand" "i"))
+       (lshiftrt:QI (match_operand:QI 2 "bit_operand" "Ur")
+                    (match_operand:HI 3 "immediate_operand" "i")))]
+ ""
+ "bld  %Z3,%Y2\;bst    %Z1,%Y0; ei1")
+
+;; BAND, BOR, and BXOR patterns
+
+(define_insn "bitlogical_1"
+  [(set (match_operand:HI 0 "bit_operand" "=Ur")
+       (match_operator:HI 4 "bit_operator"
+          [(zero_extract:HI (match_operand:QI 1 "bit_operand" "Ur")
+                            (const_int 1)
+                            (match_operand:HI 2 "immediate_operand" "i"))
+           (match_operand:HI 3 "bit_operand" "0")]))]
+  ""
+  "bld %Z2,%Y1\;%b4    #0,%X0\;bst     #0,%X0; bl1")
+
+(define_insn "bitlogical_1_hi"
+  [(set (match_operand:HI 0 "bit_operand" "=Ur")
+       (match_operator:HI 4 "bit_operator"
+          [(zero_extract:HI (match_operand:HI 1 "bit_operand" "Ur")
+                            (const_int 1)
+                            (match_operand:HI 2 "immediate_operand" "i"))
+           (match_operand:HI 3 "bit_operand" "0")]))]
+  ""
+  "bld %Z2,%Y1\;%b4    #0,%X0\;bst     #0,%X0; bl2")
+
+(define_insn "bitlogical_2"
+  [(set (match_operand:HI 0 "bit_operand" "=Ur")
+       (match_operator:HI 5 "bit_operator"
+          [(zero_extract:HI (match_operand:QI 1 "bit_operand" "Ur")
+                            (const_int 1)
+                            (match_operand:HI 2 "immediate_operand" "i"))
+           (zero_extract:HI (match_operand:QI 3 "bit_operand" "Ur")
+                            (const_int 1)
+                            (match_operand:HI 4 "immediate_operand" "i"))]))]
+  ""
+  "bld %Z2,%Y1\;%b5    %Z4,%Y3\;bst    #0,%X0; bl3")
+
+(define_insn "bitlogical_2_hi"
+  [(set (match_operand:HI 0 "bit_operand" "=Ur")
+       (match_operator:HI 5 "bit_operator"
+          [(zero_extract:HI (match_operand:HI 1 "bit_operand" "Ur")
+                            (const_int 1)
+                            (match_operand:HI 2 "immediate_operand" "i"))
+           (zero_extract:HI (match_operand:HI 3 "bit_operand" "Ur")
+                            (const_int 1)
+                            (match_operand:HI 4 "immediate_operand" "i"))]))]
+  ""
+  "bld %Z2,%Y1\;%b5    %Z4,%Y3\;bst    #0,%X0; bl3")
+
+;; This is how combine canonicalizes this pattern.  This is perhaps a bug
+;; in combine.c, but there is no problem with writing it this way so we do.
+(define_insn "bitlogical_3"
+  [(set (zero_extract:QI (match_operand:QI 0 "bit_operand" "+Ur")
+                        (const_int 1)
+                        (match_operand:HI 1 "immediate_operand" "i"))
+       (match_operator:QI 6 "bit_operator"
+          [(lshiftrt:QI (match_operand:QI 2 "bit_operand" "Ur")
+                        (match_operand:HI 3 "immediate_operand" "i"))
+           (lshiftrt:QI (match_operand:QI 4 "bit_operand" "Ur")
+                        (match_operand:HI 5 "immediate_operand" "i"))]))]
+  ""
+  "bld %Z3,%Y2\;%b6    %Z5,%Y4\;bst    %Z1,%Y0; bl5")
+                                                    
+;; This is how combine canonicalizes this pattern.  This is perhaps a bug
+;; in combine.c, but there is no problem with writing it this way so we do.
+(define_insn "bitnot_1"
+  [(set (zero_extract:QI (match_operand:QI 0 "bit_operand" "=Ur")
+                        (const_int 1)
+                        (match_operand:HI 1 "immediate_operand" "i"))
+       (lshiftrt:QI (xor:QI (match_operand:QI 2 "bit_operand" "0")
+                            (match_operand:HI 3 "immediate_operand" "i"))
+                    (match_operand:HI 4 "immediate_operand" "1")))]
+  "GET_CODE (operands[3]) == CONST_INT && GET_CODE (operands[1]) == CONST_INT
+   && exact_log2 (INTVAL (operands[3])) == INTVAL (operands[1])"
+  "bnot        %Z1,%Y0")
+
+;; ??? Implement BIAND, BIOR, BIXOR
+
+;; ??? Implement BILD, BIST
+
+;; ??? Apparently general_operand for the 1st and 2nd operands is useful,
+;; but I don't know why.  --Jim
+
+(define_expand "insv"
+  [(set (zero_extract:HI (match_operand:QI 0 "bit_operand" "Ur")
+                        (match_operand:HI 1 "general_operand" "g")
+                        (match_operand:HI 2 "general_operand" "g"))
+       (zero_extract:HI (match_operand:QI 3 "bit_operand" "Ur")
+                        (const_int 1)
+                        (const_int 0)))]
+;; ??? This should have word mode which is SImode for the h8/300h.
+  "TARGET_H8300"
+  "
 {
-  if (REGNO (operands[1]) != REGNO (operands[0]))
-   return \"mov.b      %X1,%s0\;bld    #7,%s0\;subx    %t0,%t0\";
-  else
-   return \"bld        #7,%s0\;subx    %t0,%t0\";
-}"
-  [(set_attr "type" "multi")
+  if (INTVAL (operands[1]) != 1)
+    FAIL;
+
+  /* ??? HACK ???
+     This INSV pattern is wrong.  It should use HImode for operand 3.
+     Also, the zero_extract around operand 3 is superfluous and should be
+     deleted.  Fixing this is more work than we care to do for the moment,
+     because it means most of the above patterns would need to be rewritten,
+     and we also need more combine.c patches to make this work.
+
+     So, for now, we work around this bug by simply not accepting any bitfield
+     inserts that have a position greater than fits in QImode.  */
+
+  if (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) >= 8)
+    FAIL;
+
+  /* The bit_operand predicate accepts any memory durint RTL generation, but
+     only 'U' memory afterwards, so if this is a MEM operand, we must force
+     it to be valid for 'U' by reloading the address.  */
+
+  if (GET_CODE (operands[0]) == MEM && ! EXTRA_CONSTRAINT (operands[0], 'U'))
+    {
+      rtx mem;
+      mem = gen_rtx (MEM, GET_MODE (operands[0]),
+                    copy_to_mode_reg (Pmode, XEXP (operands[0], 0)));
+      RTX_UNCHANGING_P (mem) = RTX_UNCHANGING_P (operands[0]);
+      MEM_IN_STRUCT_P (mem) = MEM_IN_STRUCT_P (operands[0]);
+      MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[0]);
+      operands[0] = mem;
+    }
+
+  /* Likewise for operands[3].  */
+
+  if (GET_CODE (operands[3]) == MEM && ! EXTRA_CONSTRAINT (operands[3], 'U'))
+    {
+      rtx mem;
+      mem = gen_rtx (MEM, GET_MODE (operands[3]),
+                    copy_to_mode_reg (Pmode, XEXP (operands[3], 0)));
+      RTX_UNCHANGING_P (mem) = RTX_UNCHANGING_P (operands[3]);
+      MEM_IN_STRUCT_P (mem) = MEM_IN_STRUCT_P (operands[3]);
+      MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[3]);
+      operands[3] = mem;
+    }
+}")
+
+;; ??? Apparently general_operand for the 2nd and 3rd operands is useful,
+;; but I don't know why.  --Jim
+
+(define_expand "extzv"
+  [(set (match_operand:HI 0 "register_operand" "") 
+       (zero_extract:HI (match_operand:QI 1 "bit_operand" "")
+                        (match_operand:HI 2 "general_operand" "g")
+                        (match_operand:HI 3 "general_operand" "g")))]
+;; ??? This should have word mode which is SImode for the h8/300h.
+  "TARGET_H8300"
+  "
+{
+  if (INTVAL (operands[2]) != 1)
+    FAIL;
+
+  /* The bit_operand predicate accepts any memory durint RTL generation, but
+     only 'U' memory afterwards, so if this is a MEM operand, we must force
+     it to be valid for 'U' by reloading the address.  */
+
+  if (GET_CODE (operands[1]) == MEM && ! EXTRA_CONSTRAINT (operands[1], 'U'))
+    {
+      rtx mem;
+      mem = gen_rtx (MEM, GET_MODE (operands[1]),
+                    copy_to_mode_reg (Pmode, XEXP (operands[1], 0)));
+      RTX_UNCHANGING_P (mem) = RTX_UNCHANGING_P (operands[1]);
+      MEM_IN_STRUCT_P (mem) = MEM_IN_STRUCT_P (operands[1]);
+      MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[1]);
+      operands[1] = mem;
+    }
+}")
+
+;; -----------------------------------------------------------------
+;; STACK POINTER MANIPULATIONS
+;; -----------------------------------------------------------------
+
+;; This pattern is needed because there is no way on the H8/300
+;; to add a 16 bit immediate value to the stack pointer in one 
+;; instruction, which could leave an invalid instruction if interrupted
+;; half way through.  Here we add to the stack pointer from a
+;; register.
+
+(define_insn "stack_pointer_manip"
+  [(set (match_operand:HI 0 "register_operand" "=&ra")
+       (plus:HI (match_operand:HI 1 "general_operand_src" "g")
+                (match_operand:HI 2 "register_operand" "ra")))]
+  "TARGET_H8300"
+  "mov.w       %T1,%T0\;add.w  %T2,%T0"
+  [(set_attr "type" "arith")
    (set_attr "length" "6")
-   (set_attr "cc" "clobber")])
+   (set_attr "cc" "set")])
 
-(define_insn "extendhisi2_one"
-  [(set (match_operand:SI 0 "register_operand" "=l")
-       (sign_extend:SI (match_operand:HI 1 "register_operand" "0")))]
-  ""
-  "mov.w       %T1,%f0\;bld    #7,%x0\;subx    %y0,%y0\;subx   %z0,%z0"
-  [(set_attr "length" "10")
-   (set_attr "cc" "clobber")])
 
-(define_expand "extendhisi2"
-  [(set (reg:HI 1) (match_operand:HI 1 "general_operand" ""))
-   (set (reg:SI 0) (sign_extend:SI (reg:HI 1)))
-   (set (match_operand:SI 0 "general_operand" "" ) (reg:SI 0))]
+;; -------------------------------------------
+;; BLK moves
+;; -------------------------------------------
+
+(define_expand "movstrhi"
+  [(parallel [(set (mem:BLK (match_operand:BLK 0 "general_operand" ""))
+                  (mem:BLK (match_operand:BLK 1 "general_operand" "")))
+            (use (match_operand:HI 2 "general_operand" ""))
+            (use (match_operand:HI 3 "immediate_operand" ""))
+            (clobber (match_dup 3))
+  ])]
   ""
-  "")
-\f
-;; ----------------------------------------------------------------------
-;; peepholes
-;; ----------------------------------------------------------------------
+  "
+{
+       rtx src_ptr = copy_to_mode_reg (Pmode, XEXP(operands[1], 0));
+       rtx dst_ptr = copy_to_mode_reg (Pmode, XEXP(operands[0], 0));
+       
+        int max = GET_CODE (operands[2]) == CONST_INT
+         ? MIN (INTVAL (operands[2]), INTVAL (operands[3])) : 1;
+       enum machine_mode mode = max >= 2 ? HImode : QImode;
+       rtx tmpreg = gen_reg_rtx (mode);
+       rtx increment = mode == QImode ? const1_rtx : const2_rtx;
+       rtx length = operands[2];
+       rtx label = gen_label_rtx ();
+       rtx end_src_ptr = gen_reg_rtx (Pmode);
+
+/*     emit_move_insn (length, gen_rtx(MINUS, HImode, length, increment));*/
+       FAIL;
+       if (Pmode == HImode)
+         emit_insn (gen_addhi3 (end_src_ptr, src_ptr, length));
+       else
+         emit_insn (gen_addsi3 (end_src_ptr, src_ptr, length));
+
+       emit_label (label);
+       emit_move_insn (tmpreg, gen_rtx (MEM, mode, src_ptr));
+       emit_move_insn (gen_rtx (MEM, mode, dst_ptr), tmpreg);
+       emit_insn (gen_rtx (SET, VOIDmode, src_ptr,
+                           gen_rtx (PLUS, Pmode, src_ptr, increment)));
+       emit_insn (gen_rtx (SET, VOIDmode, dst_ptr,
+                           gen_rtx (PLUS, Pmode, dst_ptr, increment)));
+
+       emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx,
+                           gen_rtx (COMPARE, Pmode, src_ptr, end_src_ptr)));
+       emit_jump_insn (gen_bne (label));
+
+       DONE;   
+}")
 
-;; notice a move which could be predecremented
+;; ----------------------------------------------
+;; Peepholes go at the end.
+;; ----------------------------------------------
 
-(define_peephole 
-  [(set (match_operand:HI 1 "register_operand" "")
-       (plus:HI (match_dup 1) (const_int -1)))
-   (set (mem:HI (match_dup 1))
-       (match_operand:HI 0 "register_operand" ""))]
-  "REGNO (operands[1]) != REGNO (operands[0])"
-  "mov.w       %T0,@-%T1"
-  [(set_attr "length" "2")
+;; Notice when two byte moves in a row could be a word move.
+
+(define_peephole
+  [(set (match_operand:QI 0 "register_operand" "=r")
+       (mem:QI (plus:HI (match_operand:HI 1 "register_operand" "ra")
+                        (match_operand:HI 2 "immediate_operand" "n"))))
+   (set (match_operand:QI 3 "register_operand" "=r")
+       (mem:QI (plus:HI (match_dup 1)
+                        (match_operand:HI 4 "immediate_operand" "n"))))]
+  "(INTVAL(operands[2]) == INTVAL(operands[4])+1) && REGNO(operands[0]) +1 == REGNO(operands[3])"
+  "mov.w       @(%u4,%T1),%T0"
+  [(set_attr "length" "6")
    (set_attr "cc" "set")])
 
+(define_peephole
+  [(set (mem:QI (plus:HI (match_operand:HI 1 "register_operand" "ra")
+                        (match_operand:HI 2 "immediate_operand" "n")))
+       (match_operand:QI 0 "register_operand" "r"))
+   (set (mem:QI (plus:HI (match_dup 1)
+                        (match_operand:HI 4 "immediate_operand" "n")))
+       (match_operand:QI 3 "register_operand" "r"))]
+  "(INTVAL(operands[2]) == INTVAL(operands[4])+1) && REGNO(operands[0]) +1 == REGNO(operands[3])"
+  "mov.w       %T0,@(%u4,%T1)"
+  [(set_attr "length" "6")
+   (set_attr "cc" "set")])
+
+;; Notice a move which could be post incremented.
+
 (define_peephole 
-  [(set (match_operand:HI 1 "register_operand" "")
-       (plus:HI (match_dup 1) (const_int -1)))
-   (set (mem:QI (match_dup 1))
-       (match_operand:QI 0 "register_operand" ""))]
-  "REGNO (operands[1]) != REGNO (operands[0])"
-  "mov.b       %X0,@-%T1"
+  [(set (match_operand:QI 0 "register_operand" "")
+       (mem:QI (match_operand:HI 1 "register_operand" "")))
+   (set (match_dup 1) (plus:HI (match_dup 1) (const_int 1)))]
+  "REGNO(operands[1]) != REGNO(operands[0])"
+  "mov.b       @%T1+,%X0"
   [(set_attr "length" "2")
    (set_attr "cc" "set")])
 
-;; notice a move which could be post incremented
-
 (define_peephole 
   [(set (match_operand:HI 0 "register_operand" "")
        (mem:HI (match_operand:HI 1 "register_operand" "")))
    (set (match_dup 1) (plus:HI (match_dup 1) (const_int 2)))]
-  "REGNO (operands[1]) != REGNO (operands[0])"
+  "REGNO(operands[1]) != REGNO(operands[0])"
   "mov.w       @%T1+,%T0"
   [(set_attr "length" "2")
    (set_attr "cc" "set")])
 
+;; Notice a move which could be predecremented.
+
 (define_peephole 
-  [(set (match_operand:QI 0 "register_operand" "")
-       (mem:QI (match_operand:HI 1 "register_operand" "")))
-   (set (match_dup 1) (plus:HI (match_dup 1) (const_int 1)))]
-  "REGNO (operands[1]) != REGNO (operands[0])"
-  "mov.b       @%T1+,%X0"
+  [(set (match_operand:HI 1 "register_operand" "")
+       (plus:HI (match_dup 1) (const_int -1)))
+   (set (mem:QI (match_dup 1))
+               (match_operand:QI 0 "register_operand" ""))]
+  "REGNO(operands[1]) != REGNO(operands[0])"
+  "mov.b       %X0,@-%T1"
   [(set_attr "length" "2")
    (set_attr "cc" "set")])
 
-;; notice when two byte moves in a row could be a word move
-
-(define_peephole
-  [(set (mem:QI (plus:HI (match_operand:HI 1 "register_operand" "ra")
-                        (match_operand:HI 2 "immediate_operand" "n")))
-       (match_operand:QI 0 "register_operand" "r"))
-   (set (mem:QI (plus:HI (match_dup 1)
-                        (match_operand:HI 4 "immediate_operand" "n")))
-       (match_operand:QI 3 "register_operand" "r"))]
-  "(INTVAL (operands[2]) == INTVAL (operands[4]) + 1) 
-   && (REGNO (operands[0]) + 1 == REGNO (operands[3]))"
-  "mov.w       %T0,@(%u4,%T1)"
-  [(set_attr "length" "6")
+(define_peephole 
+  [(set (match_operand:HI 1 "register_operand" "")
+       (plus:HI (match_dup 1) (const_int -1)))
+   (set (mem:HI (match_dup 1))
+               (match_operand:HI 0 "register_operand" ""))]
+  "REGNO(operands[1]) != REGNO(operands[0])"
+  "mov.w       %T0,@-%T1"
+  [(set_attr "length" "2")
    (set_attr "cc" "set")])
 
-(define_peephole
-  [(set (match_operand:QI 0 "register_operand" "=r")
-       (mem:QI (plus:HI (match_operand:HI 1 "register_operand" "ra")
-                        (match_operand:HI 2 "immediate_operand" "n"))))
-   (set (match_operand:QI 3 "register_operand" "=r")
-       (mem:QI (plus:HI (match_dup 1)
-                        (match_operand:HI 4 "immediate_operand" "n"))))]
-  "(INTVAL (operands[2]) == INTVAL (operands[4]) + 1) 
-   && (REGNO (operands[0]) + 1 == REGNO (operands[3]))"
-  "mov.w       @(%u4,%T1),%T0"
-  [(set_attr "length" "6")
-   (set_attr "cc" "set")])
+;(define_insn ""
+;  [(set (match_operand:HI 0 "register_operand" "=r")
+;      (MEM:HI (match_operand:HI 1 "register_operand" "r")))
+;   (set (match_operand:HI 3 "register_operand" "=r")
+;      (zero_extract:HI (match_dup 0)
+;                       (const_int 1)
+;                       (match_operand:HI 2 "general_operand" "g")))
+;   (set (MEM:HI (match_dup 1) (match_dup 3)))]
+;  ""
+;  "bld        #0,%3l\;bst     %Z2,%0%Y1"
+;  [(set_attr "type" "multi")
+;   (set_attr "length" "4")
+;   (set_attr "cc" "clobber")])
+
+(define_insn "fancybset1"
+  [(set (match_operand:QI 0 "bit_operand" "=Ur")
+       (ior:QI (subreg:QI 
+                (ashift:HI (const_int 1)
+                           (subreg:QI (match_operand:HI 1 "register_operand" "ri") 0)) 0)
+               (match_dup 0)))]
+  ""
+  "bset        %X1,%X0")       
+
+(define_insn "fancybset"
+  [(set (match_operand:QI 0 "bit_operand" "=Ur")
+       (ior:QI (subreg:QI 
+                (ashift:HI (const_int 1)
+                           (match_operand:HI 1 "nonmemory_operand" "ri") ) 0)
+               (match_operand:QI 2 "general_operand" "Ur")))]
+  ""
+  "mov.b       %X2,%X0\;bset   %X1,%X0")       
+
+
+(define_insn "fancybclr4"
+  [(set (match_operand:QI 0 "general_operand" "=Ur,Ur")
+       (and:QI 
+        (subreg:QI 
+         (rotate:HI (const_int -2)
+                    (match_operand:HI 2 "nonmemory_operand" "ri,ri") ) 0)
+        (match_operand:QI 1 "general_operand" "0,Ur")))
+   (clobber (match_scratch:HI 3 "=X,&r"))]
+  ""
+  "@
+   bclr        %X2,%X0; l1
+   mov.b       %X1,%X3\;mov.b  %3,%0\;bclr     %X2,%X0; l3")
+
+(define_insn "fancybclr5"
+  [(set (match_operand:QI 0 "general_operand" "=Ur,Ur")
+       (and:QI 
+        (subreg:QI 
+         (rotate:HI (const_int -2)
+                    (match_operand:QI 2 "nonmemory_operand" "ri,ri")) 0)
+        (match_operand:QI 1 "general_operand" "0,Ur")))
+   (clobber (match_scratch:HI 3 "=X,&r"))]
+  ""
+  "@
+   bclr        %X2,%X0; l1
+   mov.b       %X1,%X3\;mov.b  %3,%0\;bclr     %X2,%X0;l2")
+
+(define_insn "fancybclr2"
+  [(set (match_operand:QI 0 "general_operand" "=U,r")
+       (and:QI 
+        (subreg:QI 
+         (rotate:HI (const_int -2)
+                    (match_operand:HI 2 "nonmemory_operand" "ri,ri") ) 0)
+        (match_operand:QI 1 "general_operand" "0,0")))]
+  ""
+  "bclr        %X2,%X0")
+
+(define_insn "fancybclr3"
+  [(set (match_operand:QI 0 "general_operand" "=U,r")
+       (and:QI 
+        (subreg:QI 
+         (rotate:HI (const_int -2)
+                    (match_operand:QI 2 "nonmemory_operand" "ri,ri")) 0)
+        (match_operand:QI 1 "general_operand" "0,0")))]
+  ""
+  "bclr        %X2,%X0")
+
+(define_insn "fancybclr"
+  [(set (match_operand:QI 0 "general_operand" "=r")
+       (and:QI (not:QI (match_operand:QI 1 "general_operand" "0"))
+               (match_operand:QI 2 "general_operand" "r")))]
+  ""
+  "not %X0\;and        %X2,%X0")
+
+(define_insn "fancybsetp3"
+  [(set (match_operand:QI 0 "bit_operand" "=Ur")
+       (ior:QI (subreg:QI (ashift:HI (const_int 1)
+                                     (match_operand:QI 1 "register_operand" "r")) 0)
+               (match_operand:QI 2 "bit_operand" "0")))]
+  ""
+  "bset        %X1,%X0")
+
+(define_insn "fancybsetp2"
+  [(set (match_operand:QI 0 "general_operand" "=r,U")
+       (ior:QI (subreg:QI (ashift:HI (const_int 1)
+                                     (match_operand:QI 1 "register_operand" "r,r")) 0)
+               (match_operand:QI 2 "general_operand" "U,r")))]
+  ""
+  "mov.b       %X2,%X0\;bset   %X1,%X0")
+       
+(define_insn "fancybnot"
+  [(set (match_operand:QI 0 "bit_operand" "=Ur")
+       (xor:QI (subreg:QI (ashift:HI (const_int 1)
+                                     (match_operand:QI 1 "register_operand" "r")) 0)
+               (match_operand:QI 2 "bit_operand" "0")))]
+
+  ""
+  "bnot        %X1,%X0")
+
+(define_insn "fancy_btst"
+  [(set (pc)
+       (if_then_else (eq (zero_extract:HI (zero_extend:HI (match_operand:QI 0 "general_operand" "Ur"))
+                                          (const_int 1)
+                                          (match_operand:HI 1 "nonmemory_operand" "rn"))
+                         (const_int 0))
+                     (label_ref (match_operand 2 "" ""))
+                     (pc)))]
+  ""
+  "*
+{
+  if (get_attr_length (insn) == 2)
+    return \"btst      %X1,%X0\;beq    %l2\";
+  else if (get_attr_length (insn) == 4)
+    return \"btst      %X1,%X0\;beq    %l2:16\";
+  else
+    return \"btst      %X1,%X0\;bne    %L0\;jmp        @%l2\;%L0:\";
+}"
+  [(set_attr "type" "branch")
+   (set_attr "cc" "clobber")])
+
+(define_insn "fancy_btst1"
+  [(set (pc)
+       (if_then_else (ne (zero_extract:HI (zero_extend:HI (match_operand:QI 0 "general_operand" "Ur"))
+                                          (const_int 1)
+                                          (match_operand:HI 1 "nonmemory_operand" "rn"))
+                         (const_int 0))
+                     (label_ref (match_operand 2 "" ""))
+                     (pc)))]
+  ""
+  "*
+{
+  if (get_attr_length (insn) == 2)
+    return \"btst      %X1,%X0\;bne    %l2\";
+  else if (get_attr_length (insn) == 4)
+    return \"btst      %X1,%X0\;bne    %l2:16\";
+  else
+    return \"btst      %X1,%X0\;beq    %L0\;jmp        @%l2\;%L0:\";
+}"
+  [(set_attr "type" "branch")
+   (set_attr "cc" "clobber")])
+
+(define_insn "pxor"
+  [(set (zero_extract:QI (match_operand:QI 0 "bit_operand" "=r,U")
+                        (const_int 1)
+                        (match_operand 1 "immediate_operand" "n,n"))
+       (and:QI (not:QI (match_operand:QI 2 "bit_operand" "r,U"))
+                       (const_int 1)))]
+  ""
+  "bld #0,%X2\;bist    %1,%0"
+  [(set_attr "type" "arith")
+   (set_attr "length" "4")
+   (set_attr "cc" "clobber")])