OSDN Git Service

* First cut at support for the H8/S.
[pf3gnuchains/gcc-fork.git] / gcc / config / h8300 / h8300.md
index a68d54c..a1709ef 100644 (file)
 (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.
+;; Many logical operations should have "bit" variants if only one
+;; bit is going to be operated on.
 
-(define_attr "type" "branch,return,call,arith,move,float,multi"
+;; (and (logical op) (const_int X))
+;; If const_int only specifies a few bits (like a single byte in a 4 byte
+;; operation, then it's more efficient to only apply the and and logical_op
+;; to the bits we care about.
+
+;; Some of the extend instructions accept a general_operand_src, which
+;; allows all the normal memory addressing modes.  The length computations
+;; don't take this into account.  The lengths in the MD file should be
+;; "worst case" and then be adjusted to their correct values by
+;; h8300_adjust_insn_length.
+
+;; On the h8300h, adds/subs operate on the 32bit "er" registers.  Right
+;; now GCC doesn't expose the "e" half to the compiler, so using add/subs
+;; for addhi and subhi is safe.
+;; Long term, we want to expose the "e" half to the compiler (gives us
+;; 8 more 16bit registers).  At that point addhi and subhi can't use adds/subs.
+
+;; There's currently no way to have a insv/extzv expander for the h8/300h
+;; because word_mode is different for the h8/300 and h8/300h.
+
+;; Shifts/rotates by small constants should be handled by special
+;; patterns so we get the length and cc status correct.
+
+;; Bitfield operations no longer accept memory operands.  We need
+;; to add variants which operate on memory back to the MD.
+
+;; ??? Implement remaining bit ops available on the h8300
+
+(define_attr "type" "branch,arith"
   (const_string "arith"))
 
 ;; The size of instructions in bytes.
                                               (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 6)))]
        (const_int 200)))
 
 ;; Condition code settings.
   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 "length") (if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4)))
    (set_attr "cc" "set")])
 
-;; ??? Use of the `c' constraint doesn't seem right.
-(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"))]
+(define_insn ""
+  [(set (match_operand:QI 0 "general_operand_dst" "=r,r,<,r,r,m")
+       (match_operand:QI 1 "general_operand_src" "I,r>,r,n,m,r"))]
   "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))
+   mov.b       %R1,%X0
+   mov.b       %X1,%R0
+   mov.b       %R1,%X0
+   mov.b       %R1,%X0
+   mov.b       %X1,%R0"
+  [(set_attr_alternative "length"
+     [(const_int 2) (const_int 2) (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 2) (const_int 4))
-      (const_int 4)])
-   (set_attr "cc" "set_zn_c0,set,set,set,set,clobber")])
+      (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))])
+   (set_attr "cc" "set_zn_c0,set,set,set,set,set")])
 
 (define_expand "movqi"
   [(set (match_operand:QI 0 "general_operand_dst" "")
 }")
 
 (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"))]
+  [(set (strict_low_part (match_operand:QI 0 "general_operand_dst" "=r,r,r,r"))
+                        (match_operand:QI 1 "general_operand_src" "I,r,n,m"))]
   ""
   "@
    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_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_zn_c0,set,set,set,set")])
+   mov.b       %R1,%X0
+   mov.b       %R1,%X0"
+  [(set_attr_alternative "length"
+     [(const_int 2) (const_int 2) (const_int 2)
+      (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))])
+   (set_attr "cc" "set_zn_c0,set,set,set")])
    
 ;; movhi
 
+;; ??? We use push.l on the h8300h to push a 16bit value?!?  We have
+;; 16bit push insns!
 (define_insn "movhi_push"
   [(set (match_operand:HI 0 "push_operand" "=<")
-       (match_operand:HI 1 "register_operand" "ra"))]
+       (match_operand:HI 1 "register_operand" "r"))]
   ""
   "*
 {
   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 "length") (if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4)))
    (set_attr "cc" "set")])
 
-(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"))]
-  ""
+(define_insn ""
+  [(set (match_operand:HI 0 "general_operand_dst" "=r,r,<,r,r,m")
+       (match_operand:HI 1 "general_operand_src" "I,r>,r,i,m,r"))]
+  "register_operand (operands[0],HImode)
+   || register_operand (operands[1], HImode)"
   "@
    sub.w       %T0,%T0
    mov.w       %T1,%T0
    mov.w       %T1,%T0
    mov.w       %T1,%T0
+   mov.w       %T1,%T0
    mov.w       %T1,%T0"
-  [(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))
+  [(set_attr_alternative "length"
+     [(const_int 2) (const_int 2) (const_int 2) (const_int 4)
       (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_zn_c0,set,set,set,set")])
+      (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))])
+   (set_attr "cc" "set_zn_c0,set,set,set,set,set")])
 
 (define_expand "movhi"
   [(set (match_operand:HI 0 "general_operand_dst" "")
 }")
 
 (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"))]
+  [(set (strict_low_part (match_operand:HI 0 "general_operand_dst" "=r,r,r,r"))
+                        (match_operand:HI 1 "general_operand_src" "I,r,i,m"))]
   ""
   "@
    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_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_zn_c0,set,set,set,set")])
+  [(set_attr_alternative "length"
+     [(const_int 2) (const_int 2) (const_int 4)
+      (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))])
+   (set_attr "cc" "set_zn_c0,set,set,set")])
 
 ;; movsi
 
       if (do_movsi (operands))
        DONE;
     }
-  else /* TARGET_H8300H */
+  else
     {
       /* One of the ops has to be in a register.  */
       if (!register_operand (operand1, SImode)
       if (do_movsi (operands))
        DONE;
     }
-  else /* TARGET_H8300H */
+  else
     {
       /* One of the ops has to be in a register.  */
       if (!register_operand (operand1, SFmode)
 
 (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,>"))]
+       (match_operand:SI 1 "general_operand_src" "I,r,io,r,r,>"))]
   "TARGET_H8300
    && (register_operand (operands[0], SImode)
        || register_operand (operands[1], SImode))"
        }
       else 
        {
-         return \"mov.w        %e1,%e0\;mov.w  %f1,%f0\";
+         /* See if either half is zero.  If so, use sub.w to clear
+            that half.  */
+       if (GET_CODE (operands[1]) == CONST_INT)
+         {
+           if ((INTVAL (operands[1]) & 0xffff) == 0)
+             return \"mov.w    %e1,%e0\;sub.w  %f0,%f0\";
+           if (((INTVAL (operands[1]) >> 16) & 0xffff) == 0)
+             return \"sub.w    %e0,%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\";
+       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,4")
+  [(set_attr "length" "4,4,8,8,4,4")
    (set_attr "cc" "clobber")])
 
 (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,>"))]
+       (match_operand:SF 1 "general_operand_src" "I,r,io,r,r,>"))]
   "TARGET_H8300
    && (register_operand (operands[0], SFmode)
        || register_operand (operands[1], SFmode))"
 
     }
 }"
-  [(set_attr "type" "move")
-   (set_attr "length" "4,4,8,8,4,4")
+  [(set_attr "length" "4,4,8,8,4,4")
    (set_attr "cc" "clobber")])
 
 (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
+  [(set (match_operand:SI 0 "general_operand_dst" "=r,r,r,m,<,r")
+       (match_operand:SI 1 "general_operand_src" "I,r,im,r,r,>"))]
+  "(TARGET_H8300H || TARGET_H8300S)
    && (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" "2,2,8,8,4,4")
+  "*
+{
+  if (which_alternative == 0)
+    return \"sub.l     %S0,%S0\";
+  if (GET_CODE (operands[1]) == CONST_INT)
+    {
+      int val = INTVAL (operands[1]);
+
+      /* Look for constants which can be made by adding an 8-bit
+        number to zero in one of the two low bytes.  */
+      if (val == (val & 0xff))
+       {
+         operands[1] = GEN_INT ((char)val & 0xff);
+         return \"sub.l %S0,%S0\;add.b %1,%w0\";
+       }
+     
+      if (val == (val & 0xff00))
+       {
+         operands[1] = GEN_INT ((char)(val >> 8) & 0xff);
+         return \"sub.l %S0,%S0\;add.b %1,%x0\";
+       }
+
+      /* Now look for small negative numbers.  We can subtract them
+        from zero to get the desired constant.  */
+      if (val == -4 || val == -2 || val == -1)
+       {
+         operands[1] = GEN_INT (-INTVAL (operands[1]));
+         return \"sub.l %S0,%S0\;subs %1,%S0\";
+       }
+    }
+   return \"mov.l      %S1,%S0\";
+}"
+  [(set_attr "length" "2,2,10,10,4,4")
    (set_attr "cc" "set_zn_c0,set,set,set,set,set")])
 
 (define_insn "movsf_h8300h"
-  [(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_H8300H
+  [(set (match_operand:SF 0 "general_operand_dst" "=r,r,r,m,<,r")
+       (match_operand:SF 1 "general_operand_src" "I,r,im,r,r,>"))]
+  "(TARGET_H8300H || TARGET_H8300S)
    && (register_operand (operands[0], SFmode)
        || register_operand (operands[1], SFmode))"
   "@
    mov.l       %S1,%S0
    mov.l       %S1,%S0
    mov.l       %S1,%S0"
-  [(set_attr "type" "move")
-   (set_attr "length" "2,2,8,8,4,4")
+  [(set_attr "length" "2,2,10,10,4,4")
    (set_attr "cc" "set_zn_c0,set,set,set,set,set")])
 \f
 ;; ----------------------------------------------------------------------
 ;; TEST INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
+(define_insn ""
+  [(set (cc0) (zero_extract:QI (match_operand:QI 0 "bit_memory_operand" "rU")
+                              (const_int 1)
+                              (match_operand:QI 1 "const_int_operand" "n")))]
+  ""
+  "btst        %Z1,%R0"
+  [(set_attr "length" "2")
+   (set_attr "cc" "set_zn_c0")])
+
+(define_insn ""
+  [(set (cc0) (zero_extract:HI (match_operand:QI 0 "bit_memory_operand" "rU")
+                              (const_int 1)
+                              (match_operand:QI 1 "const_int_operand" "n")))]
+  ""
+  "btst        %Z1,%Y0"
+  [(set_attr "length" "2")
+   (set_attr "cc" "set_zn_c0")])
+
+(define_insn ""
+  [(set (cc0) (zero_extract:SI (match_operand:QI 0 "bit_memory_operand" "rU")
+                              (const_int 1)
+                              (match_operand:QI 1 "const_int_operand" "n")))]
+  ""
+  "btst        %Z1,%Y0"
+  [(set_attr "length" "2")
+   (set_attr "cc" "set_zn_c0")])
+
+(define_insn ""
+  [(set (cc0) (zero_extract:QI (match_operand:HI 0 "register_operand" "r")
+                              (const_int 1)
+                              (match_operand:HI 1 "const_int_operand" "n")))]
+  ""
+  "btst        %Z1,%R0"
+  [(set_attr "length" "2")
+   (set_attr "cc" "set_zn_c0")])
+  
+(define_insn ""
+  [(set (cc0) (zero_extract:HI (match_operand:HI 0 "register_operand" "r")
+                              (const_int 1)
+                              (match_operand:HI 1 "const_int_operand" "n")))]
+  ""
+  "btst        %Z1,%Y0"
+  [(set_attr "length" "2")
+   (set_attr "cc" "set_zn_c0")])
+
+(define_insn ""
+  [(set (cc0) (zero_extract:SI (match_operand:HI 0 "register_operand" "r")
+                              (const_int 1)
+                              (match_operand:HI 1 "const_int_operand" "n")))]
+  ""
+  "btst        %Z1,%Y0"
+  [(set_attr "length" "2")
+   (set_attr "cc" "set_zn_c0")])
+
 (define_insn "tstqi"
-  [(set (cc0) (match_operand:QI 0 "register_operand" "ra"))]
+  [(set (cc0) (match_operand:QI 0 "register_operand" "r"))]
   ""
-  "cmp.b       #0,%X0"
-  [(set_attr "type" "arith")
-   (set_attr "length" "2")
+  "mov.b       %X0,%X0"
+  [(set_attr "length" "2")
    (set_attr "cc" "set")])
 
 (define_insn "tsthi"
-  [(set (cc0) (match_operand:HI 0 "general_operand" "ra"))]
+  [(set (cc0) (match_operand:HI 0 "register_operand" "r"))]
   ""
   "mov.w       %T0,%T0"
-  [(set_attr "type" "arith")
-   (set_attr "length" "2")
+  [(set_attr "length" "2")
    (set_attr "cc" "set")])
 
 (define_insn "tstsi"
-  [(set (cc0) (match_operand:SI 0 "general_operand" "ra"))]
-  "TARGET_H8300H"
+  [(set (cc0) (match_operand:SI 0 "register_operand" "r"))]
+  "TARGET_H8300H || TARGET_H8300S"
   "mov.l       %S0,%S0"
-  [(set_attr "type" "arith")
-   (set_attr "length" "2")
+  [(set_attr "length" "2")
    (set_attr "cc" "set")])
 
 (define_insn "cmpqi"
   [(set (cc0)
-       (compare:QI (match_operand:QI 0 "register_operand" "ra")
-                   (match_operand:QI 1 "nonmemory_operand" "rai")))]
+       (compare:QI (match_operand:QI 0 "register_operand" "r")
+                   (match_operand:QI 1 "nonmemory_operand" "rn")))]
   ""
   "cmp.b       %X1,%X0"
-  [(set_attr "type" "arith")
-   (set_attr "length" "2")
+  [(set_attr "length" "2")
    (set_attr "cc" "compare")])
 
-;; ??? 300h can have an immediate operand here.
-
-(define_insn "cmphi"
+(define_expand "cmphi"
   [(set (cc0)
-       (compare:HI (match_operand:HI 0 "register_operand" "ra")
-                   (match_operand:HI 1 "register_operand" "ra")))]
+       (compare:HI (match_operand:HI 0 "register_operand" "")
+                   (match_operand:HI 1 "nonmemory_operand" "")))]
   ""
+  "
+{
+  /* Force operand1 into a register if we're compiling
+     for the h8/300.  */
+  if (GET_CODE (operands[1]) != REG && TARGET_H8300)
+    operands[1] = force_reg (HImode, operands[1]);
+}")
+
+(define_insn ""
+  [(set (cc0)
+       (compare:HI (match_operand:HI 0 "register_operand" "r")
+                   (match_operand:HI 1 "register_operand" "r")))]
+  "TARGET_H8300"
   "cmp.w       %T1,%T0"
-  [(set_attr "type" "arith")
-   (set_attr "length" "2")
+  [(set_attr "length" "2")
    (set_attr "cc" "compare")])
 
-;; ??? 300h can have an immediate operand here.
+(define_insn ""
+  [(set (cc0)
+       (compare:HI (match_operand:HI 0 "register_operand" "r,r")
+                   (match_operand:HI 1 "nonmemory_operand" "r,n")))]
+  "TARGET_H8300H || TARGET_H8300S"
+  "cmp.w       %T1,%T0"
+  [(set_attr "length" "2,4")
+   (set_attr "cc" "compare,compare")])
 
 (define_insn "cmpsi"
   [(set (cc0)
-       (compare:SI (match_operand:SI 0 "register_operand" "ra")
-                   (match_operand:SI 1 "register_operand" "ra")))]
-  "TARGET_H8300H"
+       (compare:SI (match_operand:SI 0 "register_operand" "r,r")
+                   (match_operand:SI 1 "nonmemory_operand" "r,i")))]
+  "TARGET_H8300H || TARGET_H8300S"
   "cmp.l       %S1,%S0"
-  [(set_attr "type" "arith")
-   (set_attr "length" "2")
-   (set_attr "cc" "compare")])
+  [(set_attr "length" "2,6")
+   (set_attr "cc" "compare,compare")])
 \f
 ;; ----------------------------------------------------------------------
 ;; ADD INSTRUCTIONS
 (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")))]
+                (match_operand:QI 2 "nonmemory_operand" "rn")))]
   ""
   "add.b       %X2,%X0"
-  [(set_attr "type" "arith")
-   (set_attr "length" "2")
+  [(set_attr "length" "2")
    (set_attr "cc" "set_zn_c0")])
 
-;; h8300h: 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_expand "addhi3"
+  [(set (match_operand:HI 0 "register_operand" "")
+       (plus:HI (match_operand:HI 1 "register_operand" "")
+                (match_operand:HI 2 "nonmemory_operand" "")))]
+  ""
+  "")
 
-(define_insn "addhi3"
-  [(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")))]
+;; Specialized version using adds/subs.  This must come before
+;; the more general patterns below.
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (plus:HI (match_operand:HI 1 "register_operand" "%0")
+                (match_operand:HI 2 "adds_subs_operand" "n")))]
   ""
+  "* return output_adds_subs (operands);"
+  [(set_attr "cc" "none_0hit")
+   (set (attr "length")
+        (if_then_else (ne (match_operand:HI 2 "one_insn_adds_subs_operand" "")
+                         (const_int 0))
+                     (const_int 2)
+                     (const_int 4)))])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=&r,r,&r")
+       (plus:HI (match_operand:HI 1 "register_operand" "%0,0,g")
+                (match_operand:HI 2 "nonmemory_operand" "n,r,r")))]
+  "TARGET_H8300"
   "@
-   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
+   mov.w        %T1,%T0\;add.w  %T2,%T0"
+  [(set_attr "length" "4,2,6")
+   (set_attr "cc" "clobber,set_zn_c0,set_zn_c0")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (plus:HI (match_operand:HI 1 "register_operand" "%0,0")
+                (match_operand:HI 2 "nonmemory_operand" "n,r")))]
+  "TARGET_H8300H || TARGET_H8300S"
+  "@
+   add.w       %T2,%T0
    add.w       %T2,%T0"
-  [(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_zn_c0")])
+  [(set_attr "length" "4,2")
+   (set_attr "cc" "set_zn_c0,set_zn_c0")])
 
 (define_expand "addsi3"
   [(set (match_operand:SI 0 "register_operand" "")
   ""
   "")
 
+;; Specialized version using adds/subs.  This must come before
+;; the more general patterns below.
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (match_operand:SI 1 "register_operand" "%0")
+                (match_operand:SI 2 "adds_subs_operand" "n")))]
+  "TARGET_H8300H || TARGET_H8300S"
+  "* return output_adds_subs (operands);"
+  [(set_attr "cc" "none_0hit")
+   (set (attr "length")
+        (if_then_else (ne (match_operand:HI 2 "one_insn_adds_subs_operand" "")
+                         (const_int 0))
+                     (const_int 2)
+                     (const_int 4)))])
+
 (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")
   "@
    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")
+   mov.w       %f1,%f0\;mov.w  %e1,%e0\;add.w  %f2,%f0\;addx   %y2,%y0\;addx   %z2,%z0"
+  [(set_attr "length" "8,6,10")
    (set_attr "cc" "clobber")])
 
-;; ??? 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"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (plus:SI (match_operand:SI 1 "register_operand" "%0,0")
+                (match_operand:SI 2 "nonmemory_operand" "i,r")))]
+  "TARGET_H8300H || TARGET_H8300S"
   "@
-   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,set_zn_c0,set_zn_c0")])
+  [(set_attr "length" "6,2")
+   (set_attr "cc" "set_zn_c0,set_zn_c0")])
 
 ;; ----------------------------------------------------------------------
 ;; SUBTRACT INSTRUCTIONS
 (define_insn "subqi3"
   [(set (match_operand:QI 0 "register_operand" "=r,r")
        (minus:QI (match_operand:QI 1 "register_operand" "0,0")
-                 (match_operand:QI 2 "nonmemory_operand" "r,i")))]
+                 (match_operand:QI 2 "nonmemory_operand" "r,n")))]
   ""
   "@
    sub.b       %X2,%X0
    add.b       %G2,%X0"
-  [(set_attr "type" "arith")
-   (set_attr "length" "2")
+  [(set_attr "length" "2")
    (set_attr "cc" "set_zn_c0")])
 
-;; h8300h: 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_expand "subhi3"
+  [(set (match_operand:HI 0 "register_operand" "")
+       (minus:HI (match_operand:HI 1 "general_operand" "")
+                 (match_operand:HI 2 "nonmemory_operand" "")))]
+  ""
+  "")
 
-(define_insn "subhi3"
-  [(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")))]
+;; Specialized version using adds/subs.  This must come before
+;; the more general patterns below.  This may not be needed
+;; due to instruction canonicalization.
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (minus:HI (match_operand:HI 1 "register_operand" "r")
+                 (match_operand:HI 2 "adds_subs_operand" "n")))]
   ""
+  "*
+{
+  operands[2] = GEN_INT (-INTVAL (operands[2]));
+  return output_adds_subs (operands);
+}"
+  [(set_attr "cc" "none_0hit")
+   (set (attr "length")
+        (if_then_else (ne (match_operand:HI 2 "one_insn_adds_subs_operand" "")
+                         (const_int 0))
+                     (const_int 2)
+                     (const_int 4)))])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r,&r")
+       (minus:HI (match_operand:HI 1 "general_operand" "0,0")
+                 (match_operand:HI 2 "nonmemory_operand" "r,n")))]
+  "TARGET_H8300"
+  "@
+   sub.w       %T2,%T0
+   add.b       %E2,%s0\;addx   %F2,%t0"
+  [(set_attr "length" "2,4")
+   (set_attr "cc" "set_zn_c0,clobber")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r,&r")
+       (minus:HI (match_operand:HI 1 "general_operand" "0,0")
+                 (match_operand:HI 2 "nonmemory_operand" "r,n")))]
+  "TARGET_H8300H || TARGET_H8300S"
   "@
-   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_zn_c0,clobber")])
+   sub.w       %T2,%T0"
+  [(set_attr "length" "2,4")
+   (set_attr "cc" "set_zn_c0,set_zn_c0")])
 
 (define_expand "subsi3"
   [(set (match_operand:SI 0 "register_operand" "")
                  (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 "length" "6")
    (set_attr "cc" "clobber")])
 
-;; ??? 4 can be handled in one insn on the 300h.
+;; Specialized version using adds/subs.  This must come before
+;; the more general patterns below.  This may not be needed
+;; due to instruction canonicalization.
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (minus:SI (match_operand:SI 1 "general_operand" "0")
+                 (match_operand:SI 2 "adds_subs_operand" "n")))]
+  "TARGET_H8300H || TARGET_H8300S"
+  "*
+{
+  operands[2] = GEN_INT (-INTVAL (operands[2]));
+  return output_adds_subs (operands);
+}"
+  [(set_attr "cc" "none_0hit")
+   (set (attr "length")
+        (if_then_else (ne (match_operand:HI 2 "one_insn_adds_subs_operand" "")
+                         (const_int 0))
+                     (const_int 2)
+                     (const_int 4)))])
 
 (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"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (minus:SI (match_operand:SI 1 "general_operand" "0,0")
+                 (match_operand:SI 2 "nonmemory_operand" "r,i")))]
+  "TARGET_H8300H || TARGET_H8300S"
   "@
-   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_zn_c0,set_zn_c0")])
+  [(set_attr "length" "2,6")
+   (set_attr "cc" "set_zn_c0,set_zn_c0")])
 \f
 ;; ----------------------------------------------------------------------
 ;; MULTIPLY INSTRUCTIONS
   [(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"
+  "TARGET_H8300H || TARGET_H8300S"
   "mulxs.b     %X2,%T0"
-  [(set_attr "type" "multi")
-   (set_attr "length" "4")
+  [(set_attr "length" "4")
    (set_attr "cc" "set_zn_c0")])
 
 (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"
+  "TARGET_H8300H || TARGET_H8300S"
   "mulxs.w     %T2,%S0"
-  [(set_attr "type" "multi")
-   (set_attr "length" "4")
+  [(set_attr "length" "4")
    (set_attr "cc" "set_zn_c0")])
 
 (define_insn "umulqihi3"
                 (zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
   ""
   "mulxu       %X2,%T0"
-  [(set_attr "type" "multi")
-   (set_attr "length" "2")
+  [(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"
+  "TARGET_H8300H || TARGET_H8300S"
   "mulxu.w     %T2,%S0"
-  [(set_attr "type" "multi")
-   (set_attr "length" "2")
+  [(set_attr "length" "2")
    (set_attr "cc" "none_0hit")])
 
 ;; ----------------------------------------------------------------------
 
 (define_insn "udivqi3"
   [(set (match_operand:QI 0 "register_operand" "=r")
-       (udiv:QI (match_operand:HI 1 "general_operand" "0")
-                (match_operand:QI 2 "register_operand" "r")))]
+       (truncate:QI
+         (udiv:HI
+           (match_operand:HI 1 "general_operand" "0")
+           (zero_extend:HI (match_operand:QI 2 "register_operand" "r")))))]
   ""
   "divxu       %X2,%T0"
-  [(set_attr "type" "multi")
-   (set_attr "length" "2")
+  [(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")
-               (match_operand:QI 2 "register_operand" "r")))]
+       (truncate:QI
+         (div:HI
+           (match_operand:HI 1 "general_operand" "0")
+           (sign_extend:HI (match_operand:QI 2 "register_operand" "r")))))]
   ""
   "divxu       %X2,%T0"
-  [(set_attr "type" "multi")
-   (set_attr "length" "2")
+  [(set_attr "length" "2")
    (set_attr "cc" "clobber")])
 
 (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"
+       (truncate:HI
+         (udiv:SI
+           (match_operand:SI 1 "general_operand" "0")
+           (zero_extend:SI (match_operand:HI 2 "register_operand" "r")))))]
+  "TARGET_H8300H || TARGET_H8300S"
   "divxu.w     %T2,%S0"
-  [(set_attr "type" "multi")
-   (set_attr "length" "2")
+  [(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"
+       (truncate:HI
+         (div:SI
+           (match_operand:SI 1 "general_operand" "0")
+           (sign_extend:SI (match_operand:HI 2 "register_operand" "r")))))]
+  "TARGET_H8300H || TARGET_H8300S"
   "divxs.w     %T2,%S0"
-  [(set_attr "type" "multi")
-   (set_attr "length" "4")
+  [(set_attr "length" "4")
    (set_attr "cc" "clobber")])
 
 ;; ----------------------------------------------------------------------
 
 (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")))]
+       (truncate:QI
+         (umod:HI
+           (match_operand:HI 1 "general_operand" "0")
+           (zero_extend:HI (match_operand:QI 2 "register_operand" "r")))))]
   ""
   "divxu       %X2,%T0\;mov %t0,%s0"
-  [(set_attr "type" "multi")
-   (set_attr "length" "4")
+  [(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"
+       (truncate:QI
+         (mod:HI
+           (match_operand:HI 1 "general_operand" "0")
+           (sign_extend:HI (match_operand:QI 2 "register_operand" "r")))))]
+  "TARGET_H8300H || TARGET_H8300S"
   "divxs.b     %X2,%T0\;mov %t0,%s0"
-  [(set_attr "type" "multi")
-   (set_attr "length" "6")
+  [(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"
+       (truncate:HI
+         (umod:SI
+           (match_operand:SI 1 "general_operand" "0")
+           (zero_extend:SI (match_operand:HI 2 "register_operand" "r")))))]
+  "TARGET_H8300H || TARGET_H8300S"
   "divxu.w     %T2,%S0\;mov %e0,%f0"
-  [(set_attr "type" "multi")
-   (set_attr "length" "4")
+  [(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"
+       (truncate:HI
+         (mod:SI
+           (match_operand:SI 1 "general_operand" "0")
+           (sign_extend:SI (match_operand:HI 2 "register_operand" "r")))))]
+  "TARGET_H8300H || TARGET_H8300S"
   "divxs.w     %T2,%S0\;mov %e0,%f0"
-  [(set_attr "type" "multi")
-   (set_attr "length" "6")
+  [(set_attr "length" "6")
    (set_attr "cc" "clobber")])
 \f
 ;; ----------------------------------------------------------------------
 ;; AND INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
-(define_insn "andqi3_internal"
+(define_insn ""
   [(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,4")
+   bclr        %W2,%R0"
+  [(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")))]
+  [(set (match_operand:QI 0 "bit_operand" "")
+       (and:QI (match_operand:QI 1 "bit_operand" "")
+               (match_operand:QI 2 "nonmemory_operand" "")))]
   ""
   "
 {
     DONE;
 }")
 
-;; ??? Should have a bclr case here also.
-;; ??? This should be symmetric with iorhi3.
-
 (define_insn "andhi3"
   [(set (match_operand:HI 0 "register_operand" "=r")
        (and:HI (match_operand:HI 1 "register_operand" "%0")
   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 \"\";
     }
+  if (TARGET_H8300H || TARGET_H8300S)
+    return \"and.w %T2,%T0\";
   return \"and %s2,%s0\;and    %t2,%t0;\";
 }"
-  [(set_attr "type" "multi")
-   (set_attr "length" "4")
+  [(set_attr "length" "4")
    (set_attr "cc" "clobber")])
 
-;; ??? 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" "set")])
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (and:SI (match_operand:SI 1 "register_operand" "%0")
+               (match_operand:SI 2 "nonmemory_operand" "rn")))]
+  ""
+  "*
+{
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      int i = INTVAL (operands[2]);
+      int upper_cleared, lower_cleared;
+
+      /* The h8300h can't do byte-wise operations on the
+        upper 16bits of 32bit registers.  However, if
+        those bits aren't going to change, or they're
+        going to be zero'd out, then we can work on the
+        low-order bits.  */
+      if ((TARGET_H8300H || TARGET_H8300S)
+         && ((i & 0xffff0000) != 0xffff0000
+             || (i & 0xffff0000) == 0x00000000))
+        return \"and.l %S2,%S0\";
+
+      lower_cleared = 0;
+      if ((i & 0x0000ffff) == 0x00000000)
+       {
+         output_asm_insn (\"sub.w      %f0,%f0\", operands);
+         lower_cleared = 1;
+       }
+
+      upper_cleared = 0;
+      if ((i & 0xffff0000) == 0x00000000)
+       {
+         output_asm_insn (\"sub.w      %e0,%e0\", operands);
+         upper_cleared = 1;
+       }
+
+      if ((i & 0x000000ff) != 0x000000ff && !lower_cleared)
+       output_asm_insn (\"and  %w2,%w0\", operands);
+      if ((i & 0x0000ff00) != 0x0000ff00 && !lower_cleared)
+       output_asm_insn (\"and  %x2,%x0\", operands);
+      if ((i & 0x00ff0000) != 0x00ff0000 && !upper_cleared) 
+       output_asm_insn (\"and  %y2,%y0\", operands);
+      if ((i & 0xff000000) != 0xff000000 && !upper_cleared) 
+       output_asm_insn (\"and  %z2,%z0\", operands);
+      return \"\";
+    }
+  if (TARGET_H8300H || TARGET_H8300S)
+    return \"and.l     %S2,%S0\";
+  return \"and %w2,%w0\;and    %x2,%x0\;and    %y2,%y0\;and    %z2,%z0\;\";
+}"
+  [(set_attr "length" "8")
+   (set_attr "cc" "clobber")])
+
 
 ;; ----------------------------------------------------------------------
 ;; OR INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
-(define_insn "iorqi3_internal"
-  [(set (match_operand:QI 0 "bit_operand" "=U,r")
+(define_insn ""
+  [(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" "P,rn")))]
+               (match_operand:QI 2 "nonmemory_operand" "rn,P")))]
   "register_operand (operands[0], QImode) || p_operand (operands[2], QImode)"
   "@
-   bset        %V2,%X0
-   or  %X2,%X0"
-  [(set_attr "type" "arith")
-   (set_attr "length" "4,2")
-   (set_attr "cc" "none_0hit,set")])
+   or  %X2,%X0
+   bset        %V2,%R0"
+  [(set_attr "length" "2,4")
+   (set_attr "cc" "set,none_0hit")])
 
 (define_expand "iorqi3"
   [(set (match_operand:QI 0 "bit_operand" "=r,U")
     DONE;
 }")
 
-;; ??? Should have a bset case here also.
-;; ??? This should be symmetric with andhi3.
-
 (define_insn "iorhi3"
   [(set (match_operand:HI 0 "general_operand" "=r,r")
        (ior:HI (match_operand:HI 1 "general_operand" "%0,0")
   ""
   "*
 {
-  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
+  if (GET_CODE (operands[2]) == CONST_INT)
     {
-      return \"or      %S2,%S0\";
+      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 \"\";
     }
+  if (TARGET_H8300H || TARGET_H8300S)
+    return \"or.w      %T2,%T0\";
+  return \"or  %s2,%s0\;or     %t2,%t0; %2 or2\";
 }"
-  [(set_attr "type" "multi")
-   (set_attr "length" "2,4")
+  [(set_attr "length" "2,4")
    (set_attr "cc" "clobber,clobber")])
 
 (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")))]
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (ior:SI (match_operand:SI 1 "register_operand" "%0,0")
+               (match_operand:SI 2 "nonmemory_operand" "J,rn")))]
   ""
   "*
 {
-  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
+  if (GET_CODE (operands[2]) == CONST_INT)
     {
-      return \"or      %S2,%S0\";
+      int i = INTVAL (operands[2]);
+
+      /* The h8300h can't do byte-wise operations on the
+        upper 16bits of 32bit registers.  However, if
+        those bits aren't going to change, then we can
+        work on the low-order bits.  */
+      if ((TARGET_H8300H || TARGET_H8300S)
+         && (i & 0xffff0000) != 0x00000000)
+        return \"or.l  %S2,%S0\";
+       
+      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 \"\";
     }
+  if (TARGET_H8300H || TARGET_H8300S)
+    return \"or.l      %S2,%S0\";
+  return \"or  %w2,%w0\;or     %x2,%x0\;or     %y2,%y0\;or     %z2,%z0\;\";
 }"
-  [(set_attr "type" "multi")
-   (set_attr "length" "8")
-   (set_attr "cc" "clobber")])
+  [(set_attr "length" "2,8")
+   (set_attr "cc" "clobber,clobber")])
 
 ;; ----------------------------------------------------------------------
 ;; XOR INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
-(define_insn "xorqi3_internal"
+(define_insn ""
   [(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,4")
+   bnot        %V2,%R0"
+  [(set_attr "length" "2,4")
    (set_attr "cc" "set,none_0hit")])
 
 (define_expand "xorqi3"
     DONE;
 }")
 
-;; ??? This should be symmetric with andhi3.
-
 (define_insn "xorhi3"
-  [(set (match_operand:HI 0 "register_operand" "=r")
-       (xor:HI (match_operand:HI 1 "general_operand" "%0")
-               (match_operand:HI 2 "nonmemory_operand" "rn")))]
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (xor:HI (match_operand:HI 1 "general_operand" "%0,0")
+               (match_operand:HI 2 "nonmemory_operand" "J,rn")))]
   ""
   "*
 {
-  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")])
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      int i = INTVAL (operands[2]);
 
-;; ??? There is an iorsi3 for TARGET_H8300.  Should we have xorsi3?
+      if ((i & 0x00ff) != 0) 
+       output_asm_insn (\"xor  %s2,%s0\", operands);
+      if ((i & 0xff00) != 0) 
+       output_asm_insn (\"xor  %t2,%t0\", operands);
+      return \"\";
+    }
+  if (TARGET_H8300H || TARGET_H8300S)
+    return \"xor.w     %T2,%T0\";
+  return \"xor %s2,%s0\;xor    %t2,%t0\";
+}"
+  [(set_attr "length" "2,4")
+   (set_attr "cc" "clobber,clobber")])
 
 (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" "set")])
+               (match_operand:SI 2 "nonmemory_operand" "J,rn")))]
+  ""
+  "*
+{
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      int i = INTVAL (operands[2]);
+
+      /* The h8300h can't do byte-wise operations on the
+        upper 16bits of 32bit registers.  However, if
+        those bits aren't going to change, then we can
+        work on the low-order bits.  */
+      if ((TARGET_H8300H || TARGET_H8300S)
+         && (i & 0xffff0000) != 0x00000000)
+        return \"xor.l %S2,%S0\";
+
+      if ((i & 0x000000ff) != 0) 
+       output_asm_insn (\"xor  %w2,%w0\", operands);
+      if ((i & 0x0000ff00) != 0) 
+       output_asm_insn (\"xor  %x2,%x0\", operands);
+      if ((i & 0x00ff0000) != 0) 
+       output_asm_insn (\"xor  %y2,%y0\", operands);
+      if ((i & 0xff000000) != 0) 
+       output_asm_insn (\"xor  %z2,%z0\", operands);
+      return \"\";
+    }
+  if (TARGET_H8300H || TARGET_H8300S)
+    return \"xor.l     %S2,%S0\";
+  return \"xor %w2,%w0\;xor    %x2,%x0\;xor    %y2,%y0\;xor    %z2,%z0\;\";
+}"
+  [(set_attr "length" "2,8")
+   (set_attr "cc" "clobber,clobber")])
 \f
 ;; ----------------------------------------------------------------------
 ;; NEGATION INSTRUCTIONS
        (neg:QI (match_operand:QI 1 "general_operand" "0")))]
   ""
   "neg %X0"
-  [(set_attr "type" "arith")
-   (set_attr "length" "2")
+  [(set_attr "length" "2")
    (set_attr "cc" "set_zn_c0")])
 
 (define_expand "neghi2"
 (define_insn "neghi2_h8300h"
   [(set (match_operand:HI 0 "register_operand" "=r")
        (neg:HI (match_operand:HI 1 "general_operand" "0")))]
-  "TARGET_H8300H"
+  "TARGET_H8300H || TARGET_H8300S"
   "neg %T0"
-  [(set_attr "type" "arith")
-   (set_attr "length" "2")
+  [(set_attr "length" "2")
    (set_attr "cc" "set_zn_c0")])
 
 (define_expand "negsi2"
 (define_insn "negsi2_h8300h"
   [(set (match_operand:SI 0 "register_operand" "=r")
        (neg:SI (match_operand:SI 1 "general_operand" "0")))]
-  "TARGET_H8300H"
+  "TARGET_H8300H || TARGET_H8300S"
   "neg %S0"
-  [(set_attr "type" "arith")
-   (set_attr "length" "2")
+  [(set_attr "length" "2")
    (set_attr "cc" "set_zn_c0")])
 
 ;; ----------------------------------------------------------------------
        (not:QI (match_operand:QI 1 "general_operand" "0")))]
   ""
   "not %X0"
-  [(set_attr "type" "arith")
-   (set_attr "length" "2")
+  [(set_attr "length" "2")
    (set_attr "cc" "set")])
 
 (define_insn "one_cmplhi2"
   else
     return \"not       %T0\";
 }"
-  [(set_attr "type" "arith")
-   (set_attr "length" "4")
-   (set_attr "cc" "clobber")])
+  [(set_attr "cc" "clobber")
+   (set (attr "length")
+       (if_then_else (eq (symbol_ref "TARGET_H8300H || TARGET_H8300S")
+                         (const_int 0))
+                     (const_int 4)
+                     (const_int 2)))])
 
 (define_insn "one_cmplsi2"
   [(set (match_operand:SI 0 "register_operand" "=r")
   else
     return \"not       %S0\";
 }"
-  [(set_attr "type" "arith")
-;; ??? length is wrong for 300h
-   (set_attr "length" "8")
-   (set_attr "cc" "clobber")])
+  [(set_attr "cc" "clobber")
+   (set (attr "length")
+       (if_then_else (eq (symbol_ref "TARGET_H8300H || TARGET_H8300S")
+                         (const_int 0))
+                     (const_int 8)
+                     (const_int 2)))])
+                       
 \f
 ;; ----------------------------------------------------------------------
 ;; JUMP INSTRUCTIONS
                      (pc)
                      (label_ref (match_operand 0 "" ""))))]
   ""
-;; ??? We don't take advantage of 16 bit relative jumps in the 300h.
   "*
 {
   /* If we erroneously deleted a compare insn (which can happen if we need
    (use (label_ref (match_operand 1 "" "")))]
   "TARGET_H8300"
   "jmp @%0"
-  [(set_attr "type" "branch")
-   (set_attr "cc" "none")
+  [(set_attr "cc" "none")
    (set_attr "length" "2")])
 
 (define_insn "tablejump_h8300h"
   [(set (pc) (match_operand:SI 0 "register_operand" "r"))
    (use (label_ref (match_operand 1 "" "")))]
-  "TARGET_H8300H"
+  "TARGET_H8300H || TARGET_H8300S"
   "jmp @%0"
-  [(set_attr "type" "branch")
-   (set_attr "cc" "none")
+  [(set_attr "cc" "none")
    (set_attr "length" "2")])
 
 ;; This is a define expand, because pointers may be either 16 or 32 bits.
 
 (define_expand "indirect_jump"
-  [(set (pc) (match_operand 0 "jump_address_operand" "Vr"))]
+  [(set (pc) (match_operand 0 "jump_address_operand" ""))]
   ""
   "")
 
 (define_insn "indirect_jump_h8300"
-  [(set (pc) (match_operand:HI 0 "jump_address_operand" "V,r"))]
+  [(set (pc) (match_operand:HI 0 "jump_address_operand" "Vr"))]
   "TARGET_H8300"
-  "@
-   jmp @%0
-   jmp @%0"
-  [(set_attr "type" "branch")
-   (set_attr "cc" "none")
+  "jmp @%0"
+  [(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 (pc) (match_operand:SI 0 "jump_address_operand" "Vr"))]
+  "TARGET_H8300H || TARGET_H8300S"
+  "jmp @%0"
+  [(set_attr "cc" "none")
    (set_attr "length" "2")])
 
 ;; Call subroutine with no return value.
   [(call (match_operand:QI 0 "call_insn_operand" "or")
         (match_operand:HI 1 "general_operand" "g"))]
   ""
-  "jsr %0"
-  [(set_attr "type" "call")
-   (set_attr "cc" "clobber")
-   (set_attr "length" "4")])
+  "*
+{
+  if (GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF
+      && SYMBOL_REF_FLAG (XEXP (operands[0], 0)))
+    return \"jsr\\t\@%0:8\";
+  else
+    return \"jsr\\t%0\";
+}"
+  [(set_attr "cc" "clobber")
+   (set (attr "length")
+     (if_then_else (match_operand:QI 0 "small_call_insn_operand" "")
+                  (const_int 4)
+                  (const_int 8)))])
 
 ;; Call subroutine, returning value in operand 0
 ;; (which must be a hard register).
        (call (match_operand:QI 1 "call_insn_operand" "or")
              (match_operand:HI 2 "general_operand" "g")))]
   ""
-  "jsr %1"
-  [(set_attr "type" "call")
-   (set_attr "cc" "clobber")
-   (set_attr "length" "4")])
+  "*
+{
+  if (GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF
+      && SYMBOL_REF_FLAG (XEXP (operands[1], 0)))
+    return \"jsr\\t\@%1:8\";
+  else
+    return \"jsr\\t%1\";
+}"
+  [(set_attr "cc" "clobber")
+   (set (attr "length")
+     (if_then_else (match_operand:QI 0 "small_call_insn_operand" "")
+                  (const_int 4)
+                  (const_int 8)))])
 
 (define_insn "nop"
   [(const_int 0)]
   ""
   "nop"
-  [(set_attr "type" "multi")
-   (set_attr "cc" "none")
+  [(set_attr "cc" "none")
    (set_attr "length" "2")])
 \f
 ;; ----------------------------------------------------------------------
 
 (define_insn "zero_extendqihi2"
   [(set (match_operand:HI 0 "register_operand" "=r,r")
-       (zero_extend:HI (match_operand:QI 1 "general_operand" "0,g")))]
+       (zero_extend:HI (match_operand:QI 1 "general_operand_src" "0,g>")))]
   ""
-  "*
+  "@
+  mov.b        #0,%t0
+  mov.b        %R1,%s0\;mov.b  #0,%t0"
+  [(set_attr "length" "2,4")
+   (set_attr "cc" "clobber,clobber")])
+
+;; The compiler can synthesize a 300H variant of this which is
+;; just as efficient as one that we'd create
+(define_insn "zero_extendqisi2"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (zero_extend:SI (match_operand:QI 1 "general_operand_src" "0,g>")))]
+  "TARGET_H8300"
+  "@
+  mov.b        #0,%x0\;sub.w %e0,%e0
+  mov.b        %R1,%w0\;mov.b  #0,%x0\;sub.w %e0,%e0"
+  [(set_attr "length" "4,6")
+   (set_attr "cc" "clobber,clobber")])
+
+(define_expand "zero_extendhisi2"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (zero_extend:SI (match_operand:HI 1 "general_operand" "")))]
+  ""
+  "
 {
-  if (which_alternative==0)
-    return \"mov.b     #0,%t0\";
+  extern int optimize;
 
-  if (TARGET_H8300)
-    return \"mov.b     %X1,%s0\;mov.b  #0,%t0\";
-  else
+  if (TARGET_H8300
+      && GET_CODE (operands[1]) != CONST_INT
+      && !optimize)
     {
-      /* ??? 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\";
+      emit_insn (gen_zero_extendhisi2_h8300 (operands[0], operands[1]));
+      DONE;
     }
-}"
-  [(set_attr "type" "multi")
-;; ??? This length is wrong for one case.
-   (set_attr "length" "4")
-   (set_attr "cc" "clobber")])
+}")
 
-(define_insn "zero_extendhisi2"
-  [(set (match_operand:SI 0 "register_operand" "=r")
-       (zero_extend:SI (match_operand:HI 1 "general_operand" "g")))]
-  "TARGET_H8300H"
-  "*
-{
-  /* ??? See how often this gets optimized.  */
-  if (REG_P (operands[1]) && (REGNO (operands[1]) == REGNO (operands[0])))
-    return \"extu.l    %S0\";
-  else
-    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")])
+;; This is used when not optimizing.  It avoids severe code explosion
+;; due to poor register allocation.
+(define_expand "zero_extendhisi2_h8300"
+  [(set (reg:HI 1) (match_operand:HI 1 "general_operand" ""))
+   (set (reg:SI 0) (zero_extend:SI (reg:HI 1)))
+   (set (match_operand:SI 0 "general_operand" "" ) (reg:SI 0))]
+  "TARGET_H8300"
+  "")
 
-(define_insn "extendqihi2"
-  [(set (match_operand:HI 0 "register_operand" "=r")
-       (sign_extend:HI (match_operand:QI 1 "general_operand" "g")))]
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (zero_extend:SI (match_operand:HI 1 "general_operand_src" "0,g>")))]
+  "TARGET_H8300"
+  "@
+  sub.w        %e0,%e0
+  mov.w %e1,%f0\;sub.w %e0,%e0"
+  [(set_attr "length" "2,4")
+   (set_attr "cc" "clobber,clobber")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (zero_extend:SI (match_operand:HI 1 "general_operand_src" "0,g>")))]
+  "TARGET_H8300H || TARGET_H8300S"
+  "@
+  extu.l       %S0
+  mov.w        %T1,%T0\;extu.l %S0"
+  [(set_attr "length" "2,4")
+   (set_attr "cc" "set,set")])
+
+(define_expand "extendqihi2"
+  [(set (match_operand:HI 0 "register_operand" "")
+       (sign_extend:HI (match_operand:QI 1 "general_operand" "")))]
   ""
-  "*
-{
-  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
-    {
-      /* ??? 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_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (sign_extend:HI (match_operand:QI 1 "general_operand_src" "0,g>")))]
+  "TARGET_H8300"
+  "@
+  bld  #7,%s0\;subx    %t0,%t0
+  mov.b        %R1,%s0\;bld    #7,%s0\;subx    %t0,%t0"
+  [(set_attr "length" "4,6")
+   (set_attr "cc" "clobber,clobber")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (sign_extend:HI (match_operand:QI 1 "general_operand_src" "0,g>")))]
+  "TARGET_H8300H || TARGET_H8300S"
+  "@
+  exts.w       %T0
+  mov.b        %R1,%s0\;exts.w %T0"
+  [(set_attr "length" "2,4")
+   (set_attr "cc" "set,set")])
+
+;; The compiler can synthesize a 300H variant of this which is
+;; just as efficient as one that we'd create
+(define_insn "extendqisi2"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (sign_extend:SI (match_operand:QI 1 "general_operand_src" "0,g>")))]
+  "TARGET_H8300"
+  "@
+  bld  #7,%w0\;subx    %x0,%x0\;subx   %y0,%y0\;subx   %z0,%z0
+  mov.b %R1,%w0\;bld   #7,%w0\;subx    %x0,%x0\;subx   %y0,%y0\;subx   %z0,%z0"
+  [(set_attr "length" "8,10")
+   (set_attr "cc" "clobber,clobber")])
 
 (define_expand "extendhisi2"
   [(set (match_operand:SI 0 "register_operand" "")
   ""
   "
 {
-  if (TARGET_H8300)
-    emit_insn (gen_extendhisi2_h8300 (operands[0], operands[1]));
-  else
-    emit_insn (gen_extendhisi2_h8300h (operands[0], operands[1]));
-  DONE;
+  extern int optimize;
+  if (TARGET_H8300
+      && GET_CODE (operands[1]) != CONST_INT
+      && !optimize)
+    {
+      emit_insn (gen_extendhisi2_h8300 (operands[0], operands[1]));
+      DONE;
+    }
 }")
 
+;; This is used when not optimizing.  It avoids severe code explosion
+;; due to poor register allocation.
 (define_expand "extendhisi2_h8300"
   [(set (reg:HI 1) (match_operand:HI 1 "general_operand" ""))
    (set (reg:SI 0) (sign_extend:SI (reg:HI 1)))
   "TARGET_H8300"
   "")
 
-(define_expand "extendhisi2_h8300h"
-  [(set (match_operand:SI 0 "register_operand" "")
-       (sign_extend:SI (match_operand:HI 1 "general_operand" "")))]
-  "TARGET_H8300H"
-  "")
-
-(define_insn "extendhisi2_h8300_internal"
-  [(set (match_operand:SI 0 "register_operand" "=r")
-       (sign_extend:SI (match_operand:HI 1 "register_operand" "0")))]
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (sign_extend:SI (match_operand:HI 1 "general_operand_src" "0,g>")))]
   "TARGET_H8300"
-  "mov.w       %T1,%f0\;bld    #7,%x0\;subx    %y0,%y0\;subx   %z0,%z0"
-  [(set_attr "length" "10")
-   (set_attr "cc" "clobber")])
+  "@
+  bld  #7,%x0\;subx    %y0,%y0\;subx   %z0,%z0
+  mov.w        %T1,%f0\;bld    #7,%x0\;subx    %y0,%y0\;subx   %z0,%z0"
+  [(set_attr "length" "6,8")
+   (set_attr "cc" "clobber,clobber")])
 
-(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"
-  "*
-{
-  /* ??? See how often this gets optimized.  */
-  if (REG_P (operands[1]) && (REGNO (operands[1]) == REGNO (operands[0])))
-    return \"exts.l    %S0\";
-  else
-    return \"mov.w     %T1,%T0\;exts.l %S0\";
-}"
-  [(set_attr "length" "10")
-   (set_attr "cc" "clobber")])
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (sign_extend:SI (match_operand:HI 1 "general_operand_src" "0,g>")))]
+  "TARGET_H8300H || TARGET_H8300S"
+  "@
+  exts.l       %S0
+  mov.w        %T1,%T0\;exts.l %S0"
+  [(set_attr "length" "2,4")
+   (set_attr "cc" "set,set")])
 \f
 ;; ----------------------------------------------------------------------
 ;; SHIFTS
   ""
   "if (expand_a_shift (QImode, LSHIFTRT, operands)) DONE;else FAIL;")
 
-;; 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"
+(define_insn ""
   [(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")]))
+                         (match_operand:QI 2 "nonmemory_operand" "KM,rn")]))
    (clobber (match_scratch:QI 4 "=X,&r"))]
   ""
   "* 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 "length" "20")
    (set_attr "cc" "clobber")])
 
 ;; HI BIT SHIFTS
 
 (define_expand "lshrhi3"
   [(set (match_operand:HI 0 "register_operand" "")
-       (lshiftrt:HI (match_operand:HI 1 "general_operand_src" "")
+       (lshiftrt:HI (match_operand:HI 1 "general_operand" "")
                     (match_operand:QI 2 "nonmemory_operand" "")))]
   ""
   "if (expand_a_shift (HImode, LSHIFTRT, operands)) DONE;else FAIL;")
   ""
   "if (expand_a_shift (HImode, ASHIFTRT, operands)) DONE;else FAIL;")
 
-;; 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_HI"
+(define_insn ""
   [(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")]))
+                         (match_operand:QI 2 "nonmemory_operand" "KM,rn")]))
    (clobber (match_scratch:QI 4 "=X,&r"))]
   ""
   "* 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 "length" "20")
    (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 1 "general_operand" "")
         (match_operand:QI 2 "nonmemory_operand" "")))]
   ""
   "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 1 "general_operand" "")
         (match_operand:QI 2 "nonmemory_operand" "")))]
   ""
   "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 1 "general_operand" "")
         (match_operand:QI 2 "nonmemory_operand" "")))]
   ""
   "if (expand_a_shift (SImode, ASHIFTRT, operands)) DONE;else FAIL;")
 
-;; 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 "shiftbyn_SI"
+(define_insn ""
   [(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")]))
+                         (match_operand:QI 2 "nonmemory_operand" "K,rn")]))
    (clobber (match_scratch:QI 4 "=X,&r"))]
   ""
   "* 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 "length" "20")
    (set_attr "cc" "clobber")])
 \f
 ;; -----------------------------------------------------------------
 ;; The H8/300 has given 1/8th of its opcode space to bitfield
 ;; instructions so let's use them as well as we can.
 
-;; 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)))]
-  ""
-  "*
-{
-  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 "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)))]
-  ""
-  "*
-{
-  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_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)))]
-  ""
-  "*
-{
-  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")])
-
-;; BLD and BST patterns
+;; You'll never believe all these patterns perform one basic action --
+;; load a bit from the source, optionally invert the bit, then store it
+;; in the destination (which is known to be zero)..  
+;;
+;; Combine obviously need some work to better identify this situation and
+;; canonicalize the form better.
 
-(define_insn "extract_1"
+;; 
+;; Normal loads with a 16bit destination.
+;; 
+;; Yes, both cases are needed.
+;;
+(define_insn ""
   [(set (match_operand:HI 0 "register_operand" "=&r")
-       (zero_extract:HI (match_operand:QI 1 "bit_operand" "Ur")
+       (zero_extract:HI (match_operand:HI 1 "register_operand" "r")
                         (const_int 1)
-                        (match_operand:HI 2 "immediate_operand" "i")))]
+                        (match_operand:HI 2 "immediate_operand" "n")))]
   ""
-  "sub.w       %0,%0\;bld      %Z2,%Y1\;bst    #0,%X0")
+  "sub.w       %0,%0\;bld      %Z2,%Y1\;bst    #0,%X0"
+  [(set_attr "cc" "clobber")
+   (set_attr "length" "6")])
 
-(define_insn "extract_1_hi"
+(define_insn ""
   [(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")))]
-  ""
-  "sub.w       %0,%0\;bld      %Z2,%Y1\;bst    #0,%X0")
-
-(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")
+       (subreg:HI (zero_extract:SI
+                    (match_operand:HI 1 "register_operand" "r")
+                    (const_int 1)
+                    (match_operand:HI 2 "immediate_operand" "n")) 1))]
+  ""
+  "sub.w       %0,%0\;bld      %Z2,%Y1\;bst    #0,%X0"
+  [(set_attr "cc" "clobber")
+   (set_attr "length" "6")])
+
+;; 
+;; Inverted loads with a 16bit destination.
+;; 
+;; Yes, all four cases are needed.
+;;
 
-;; 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")
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=&r")
+       (zero_extract:HI (xor:HI (match_operand:HI 1 "register_operand" "r")
+                                (match_operand:HI 3 "p_operand" "P"))
                         (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")
+                        (match_operand:HI 2 "const_int_operand" "n")))]
+  "(1 << INTVAL (operands[2])) == INTVAL (operands[3])"
+  "sub.w       %0,%0\;bild     %Z2,%Y1\;bst    #0,%X0"
+  [(set_attr "cc" "clobber")
+   (set_attr "length" "8")])
 
-(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")]))]
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=&r")
+       (and:HI (not:HI 
+                 (lshiftrt:HI
+                   (match_operand:HI 1 "bit_operand" "Ur")
+                   (match_operand:HI 2 "const_int_operand" "n")))
+               (const_int 1)))]
   ""
-  "bld %Z2,%Y1\;%b4    #0,%X0\;bst     #0,%X0; bl2")
+  "sub.w       %0,%0\;bild     %Z2,%Y1\;bst    #0,%X0"
+  [(set_attr "cc" "clobber")
+   (set_attr "length" "8")])
 
-(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"))]))]
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=&r")
+       (and:HI (not:HI 
+                 (subreg:HI 
+                   (lshiftrt:SI
+                     (match_operand:SI 1 "register_operand" "Ur")
+                     (match_operand:SI 2 "const_int_operand" "n")) 1))
+               (const_int 1)))]
+  "INTVAL (operands[2]) < 16"
+  "sub.w       %0,%0\;bild     %Z2,%Y1\;bst    #0,%X0"
+  [(set_attr "cc" "clobber")
+   (set_attr "length" "8")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=&r")
+       (and:HI (not:HI 
+                 (subreg:HI 
+                   (lshiftrt:SI
+                     (match_operand:SI 1 "bit_operand" "Ur")
+                     (match_operand:SI 2 "const_int_operand" "n")) 0))
+               (const_int 1)))]
+  "(TARGET_H8300H || TARGET_H8300S)
+   && INTVAL (operands[2]) < 16"
+  "sub.w       %0,%0\;bild     %Z2,%Y1\;bst    #0,%X0"
+  [(set_attr "cc" "clobber")
+   (set_attr "length" "8")])
+
+;; 
+;; Normal loads with a 32bit destination.
+;; 
+;; Yes, all three cases are needed.
+;;
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=&r")
+       (zero_extract:SI (match_operand:HI 1 "register_operand" "r")
+                        (const_int 1)
+                        (match_operand:HI 2 "const_int_operand" "n")))]
   ""
-  "bld %Z2,%Y1\;%b5    %Z4,%Y3\;bst    #0,%X0; bl3")
+  "* return output_simode_bld (0, 0, operands);"
+  [(set_attr "cc" "clobber")
+   (set (attr "length")
+       (if_then_else (eq (symbol_ref "TARGET_H8300H || TARGET_H8300S")
+                         (const_int 0))
+                     (const_int 10)
+                     (const_int 8)))])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=&r")
+       (and:SI (zero_extend:SI 
+                  (lshiftrt:QI
+                    (match_operand:QI 1 "bit_operand" "Ur")
+                    (match_operand:QI 2 "const_int_operand" "n")))
+               (const_int 1)))]
+  ""
+  "* return output_simode_bld (0, 0, operands);"
+  [(set_attr "cc" "clobber")
+   (set (attr "length")
+       (if_then_else (eq (symbol_ref "TARGET_H8300H || TARGET_H8300S")
+                         (const_int 0))
+                     (const_int 10)
+                     (const_int 8)))])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=&r")
+       (and:SI (zero_extend:SI 
+                  (lshiftrt:HI
+                     (match_operand:HI 1 "bit_operand" "Ur")
+                     (match_operand:HI 2 "const_int_operand" "n")))
+               (const_int 1)))]
+  ""
+  "* return output_simode_bld (0, 0, operands);"
+  [(set_attr "cc" "clobber")
+   (set (attr "length")
+       (if_then_else (eq (symbol_ref "TARGET_H8300H || TARGET_H8300S")
+                         (const_int 0))
+                     (const_int 10)
+                     (const_int 8)))])
 
-(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")
+;; 
+;; Inverted loads with a 32bit destination.
+;; 
+;; Yes, all seven cases are needed.
+;;
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=&r")
+       (and:SI (not:SI
+                 (zero_extend:SI (match_operand:HI 1 "register_operand" "r")))
+               (match_operand:SI 2 "p_operand" "P")))]
+  ""
+  "* return output_simode_bld (1, 1, operands);"
+  [(set_attr "cc" "clobber")
+   (set (attr "length")
+       (if_then_else (eq (symbol_ref "TARGET_H8300H || TARGET_H8300S")
+                         (const_int 0))
+                     (const_int 10)
+                     (const_int 8)))])
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=&r")
+       (and:SI (not:SI
+                 (zero_extend:SI
+                   (lshiftrt:HI (match_operand:HI 1 "bit_operand" "Ur")
+                                (match_operand:HI 2 "const_int_operand" "n"))))
+               (const_int 1)))]
+  ""
+  "* return output_simode_bld (1, 0, operands);"
+  [(set_attr "cc" "clobber")
+   (set (attr "length")
+       (if_then_else (eq (symbol_ref "TARGET_H8300H || TARGET_H8300S")
+                         (const_int 0))
+                     (const_int 10)
+                     (const_int 8)))])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=&r")
+       (and:SI (not:SI
+                 (zero_extend:SI (match_operand:QI 1 "register_operand" "r")))
+               (match_operand:SI 2 "p_operand" "P")))]
+  ""
+  "* return output_simode_bld (1, 1, operands);"
+  [(set_attr "cc" "clobber")
+   (set (attr "length")
+       (if_then_else (eq (symbol_ref "TARGET_H8300H || TARGET_H8300S")
+                         (const_int 0))
+                     (const_int 10)
+                     (const_int 8)))])
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=&r")
+       (and:SI (not:SI
+                 (zero_extend:SI
+                   (lshiftrt:QI (match_operand:QI 1 "bit_operand" "Ur")
+                                (match_operand:QI 2 "const_int_operand" "n"))))
+               (const_int 1)))]
+  ""
+  "* return output_simode_bld (1, 0, operands);"
+  [(set_attr "cc" "clobber")
+   (set (attr "length")
+       (if_then_else (eq (symbol_ref "TARGET_H8300H || TARGET_H8300S")
+                         (const_int 0))
+                     (const_int 10)
+                     (const_int 8)))])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=&r")
+       (and:SI (not:SI
+                 (subreg:SI 
+                    (lshiftrt:HI
+                       (match_operand:HI 1 "bit_operand" "Ur")
+                       (match_operand:HI 2 "const_int_operand" "n")) 0))
+               (const_int 1)))]
+  "1"
+  "* return output_simode_bld (1, 0, operands);"
+  [(set_attr "cc" "clobber")
+   (set (attr "length")
+       (if_then_else (eq (symbol_ref "TARGET_H8300H || TARGET_H8300S")
+                         (const_int 0))
+                     (const_int 10)
+                     (const_int 8)))])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=&r")
+       (and:SI (not:SI
+                 (subreg:SI 
+                    (lshiftrt:QI
+                       (match_operand:QI 1 "bit_operand" "Ur")
+                       (match_operand:QI 2 "const_int_operand" "n")) 0))
+               (const_int 1)))]
+  "1"
+  "* return output_simode_bld (1, 0, operands);"
+  [(set_attr "cc" "clobber")
+   (set (attr "length")
+       (if_then_else (eq (symbol_ref "TARGET_H8300H || TARGET_H8300S")
+                         (const_int 0))
+                     (const_int 10)
+                     (const_int 8)))])
 
-;; 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")
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=&r")
+       (zero_extract:SI (xor:HI (match_operand:HI 1 "register_operand" "r")
+                                (match_operand:HI 3 "p_operand" "P"))
                         (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
+                        (match_operand:HI 2 "const_int_operand" "n")))]
+  "(1 << INTVAL (operands[2])) == INTVAL (operands[3])"
+  "sub.w       %0,%0\;bild     %Z2,%Y1\;bst    #0,%X0"
+  [(set_attr "cc" "clobber")
+   (set_attr "length" "8")])
 
 (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.
+  [(set (zero_extract:HI (match_operand:HI 0 "general_operand" "")
+                        (match_operand:HI 1 "general_operand" "")
+                        (match_operand:HI 2 "general_operand" ""))
+       (match_operand:HI 3 "general_operand" ""))]
   "TARGET_H8300"
   "
 {
+  /* We only have single bit bitfield instructions.  */
   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)
+  /* For now, we don't allow memory operands.  */
+  if (GET_CODE (operands[0]) == MEM
+      || GET_CODE (operands[3]) == MEM)
     FAIL;
-
-  /* The bit_operand predicate accepts any memory during 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_insn ""
+  [(set (zero_extract:HI (match_operand:HI 0 "register_operand" "+r")
+                        (const_int 1)
+                        (match_operand:HI 1 "immediate_operand" "n"))
+       (match_operand:HI 2 "register_operand" "r"))]
+  ""
+  "bld #0,%R2\;bst     %Z1,%Y0 ; i1"
+  [(set_attr "cc" "clobber")
+   (set_attr "length" "4")])
 
 (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.
+       (zero_extract:HI (match_operand:HI 1 "bit_operand" "")
+                        (match_operand:HI 2 "general_operand" "")
+                        (match_operand:HI 3 "general_operand" "")))]
   "TARGET_H8300"
   "
 {
+  /* We only have single bit bitfield instructions.  */
   if (INTVAL (operands[2]) != 1)
     FAIL;
 
-  /* The bit_operand predicate accepts any memory during 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;
-    }
+  /* For now, we don't allow memory operands.  */
+  if (GET_CODE (operands[1]) == MEM)
+    FAIL;
 }")
-\f
-;; -----------------------------------------------------------------
-;; 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" "set_zn_c0")])
 
+;; BAND, BOR, and BXOR patterns
 
-;; -------------------------------------------
-;; BLK moves
-;; -------------------------------------------
+(define_insn ""
+  [(set (match_operand:HI 0 "bit_operand" "=Ur")
+       (match_operator:HI 4 "bit_operator"
+          [(zero_extract:HI (match_operand:HI 1 "register_operand" "r")
+                            (const_int 1)
+                            (match_operand:HI 2 "immediate_operand" "n"))
+           (match_operand:HI 3 "bit_operand" "0")]))]
+  ""
+  "bld %Z2,%Y1\;%b4    #0,%R0\;bst     #0,%R0; bl1"
+  [(set_attr "cc" "clobber")
+   (set_attr "length" "6")])
 
-(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))
-  ])]
+(define_insn ""
+  [(set (match_operand:HI 0 "bit_operand" "=Ur")
+       (match_operator:HI 5 "bit_operator"
+          [(zero_extract:HI (match_operand:HI 1 "register_operand" "r")
+                            (const_int 1)
+                            (match_operand:HI 2 "immediate_operand" "n"))
+           (zero_extract:HI (match_operand:HI 3 "register_operand" "r")
+                            (const_int 1)
+                            (match_operand:HI 4 "immediate_operand" "n"))]))]
   ""
-  "
-{
-       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;   
-}")
+  "bld %Z2,%Y1\;%b5    %Z4,%Y3\;bst    #0,%R0; bl3"
+  [(set_attr "cc" "clobber")
+   (set_attr "length" "6")])
+
 \f
 ;; ----------------------------------------------
 ;; Peepholes go at the end.
 
 (define_peephole
   [(set (match_operand:QI 0 "register_operand" "=r")
-       (mem:QI (plus:HI (match_operand:HI 1 "register_operand" "ra")
+       (mem:QI (plus:HI (match_operand:HI 1 "register_operand" "r")
                         (match_operand:HI 2 "immediate_operand" "n"))))
    (set (match_operand:QI 3 "register_operand" "=r")
        (mem:QI (plus:HI (match_dup 1)
    (set_attr "cc" "set")])
 
 (define_peephole
-  [(set (mem:QI (plus:HI (match_operand:HI 1 "register_operand" "ra")
+  [(set (mem:QI (plus:HI (match_operand:HI 1 "register_operand" "r")
                         (match_operand:HI 2 "immediate_operand" "n")))
        (match_operand:QI 0 "register_operand" "r"))
    (set (mem:QI (plus:HI (match_dup 1)
   [(set_attr "length" "2")
    (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 1 "general_operand" "Ur"))
-                                          (const_int 1)
-                                          (match_operand:HI 2 "nonmemory_operand" "rn"))
-                         (const_int 0))
-                     (label_ref (match_operand 0 "" ""))
-                     (pc)))]
-  ""
-  "*
-{
-  if (get_attr_length (insn) == 2)
-    return \"btst      %X2,%X1\;beq    %l0\";
-  else if (get_attr_length (insn) == 4)
-    return \"btst      %X2,%X1\;beq    %l0:16\";
-  else
-    return \"btst      %X2,%X1\;bne    %L1\;jmp        @%l0\;%L1:\";
-}"
-  [(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 1 "general_operand" "Ur"))
-                                          (const_int 1)
-                                          (match_operand:HI 2 "nonmemory_operand" "rn"))
-                         (const_int 0))
-                     (label_ref (match_operand 0 "" ""))
-                     (pc)))]
-  ""
-  "*
-{
-  if (get_attr_length (insn) == 2)
-    return \"btst      %X2,%X1\;bne    %l0\";
-  else if (get_attr_length (insn) == 4)
-    return \"btst      %X2,%X1\;bne    %l0:16\";
-  else
-    return \"btst      %X2,%X1\;beq    %L1\;jmp        @%l0\;%L1:\";
-}"
-  [(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")])