;; GCC machine description for Hitachi H8/300
;; Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.

;;   Contributed by Steve Chamberlain (sac@cygnus.com),
;;   Jim Wilson (wilson@cygnus.com), and Doug Evans (dje@cygnus.com).

;; This file is part of GNU CC.

;; GNU CC is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.

;; GNU CC is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU CC; see the file COPYING.  If not, write to
;; the Free Software Foundation, 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;; The original PO technology requires these to be ordered by speed,
;; so that assigner will pick the fastest.

;; See file "rtl.def" for documentation on define_insn, match_*, et. al.

(define_attr "cpu" "h8300,h8300h"
  (const (symbol_ref "cpu_type")))

;; Many logical operations should have "bit" variants if only one
;; bit is going to be operated on.

;; (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.

(define_attr "length" "" 
  (cond [(eq_attr "type" "branch")
	 (if_then_else (and (ge (minus (pc) (match_dup 0))
				(const_int -120))
			    (le (minus (pc) (match_dup 0))
				(const_int 120)))
		       (const_int 2)
		       (if_then_else (and (eq_attr "cpu" "h8300h")
					  (and (ge (minus (pc) (match_dup 0))
						   (const_int -32000))
					       (le (minus (pc) (match_dup 0))
						   (const_int 32000))))
				     (const_int 4)
				     (const_int 6)))]
	(const_int 200)))

;; Condition code settings.
;; none - insn does not affect cc
;; none_0hit - insn does not affect cc but it does modify operand 0
;;	This attribute is used to keep track of when operand 0 changes.
;; 	See the description of NOTICE_UPDATE_CC for more info.
;; set_znv - insn sets z,n,v to usable values (like a tst insn); c is unknown.
;; set_zn  - insn sets z,n to usable values; v,c are unknown.
;; compare - compare instruction
;; clobber - value of cc is unknown
(define_attr "cc" "none,none_0hit,set_znv,set_zn,compare,clobber"
  (const_string "clobber"))

;; ----------------------------------------------------------------------
;; MOVE INSTRUCTIONS
;; ----------------------------------------------------------------------

;; movqi

(define_insn "movqi_push"
  [(set (match_operand:QI 0 "push_operand" "=<")
	(match_operand:QI 1 "register_operand" "r"))]
  ""
  "*
{
  if (TARGET_H8300)
    return \"push.w	%T1\";
  else
    return \"push.l	%S1\";
}"
  [(set (attr "length") (if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4)))
   (set_attr "cc" "set_znv")])

(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	%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 4) (const_int 8))])
   (set_attr "cc" "set_zn,set_znv,set_znv,set_znv,set_znv,set_znv")])

(define_expand "movqi"
  [(set (match_operand:QI 0 "general_operand_dst" "")
	(match_operand:QI 1 "general_operand_src" ""))]
  ""
  "
{
  /* One of the ops has to be in a register */
  if (!register_operand(operand0, QImode)
      && !register_operand(operand1, QImode))
    {
      operands[1] = copy_to_mode_reg(QImode, operand1);
    }
}")

(define_insn "movstrictqi"
  [(set (strict_low_part (match_operand:QI 0 "general_operand_dst" "=r,r,r,r"))
			 (match_operand:QI 1 "general_operand_src" "I,r,n,m"))]
  ""
  "@
   sub.b	%X0,%X0
   mov.b	%X1,%X0
   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,set_znv,set_znv,set_znv")])
   
;; 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" "r"))]
  ""
  "*
{
  if (TARGET_H8300)
    return \"push.w	%T1\";
  else
    return \"push.l	%S1\";
}"
  [(set (attr "length") (if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4)))
   (set_attr "cc" "set_znv")])

(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_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 4) (const_int 8))])
   (set_attr "cc" "set_zn,set_znv,set_znv,set_znv,set_znv,set_znv")])

(define_expand "movhi"
  [(set (match_operand:HI 0 "general_operand_dst" "")
	(match_operand:HI 1 "general_operand_src" ""))]
  ""
  "
{
  /* One of the ops has to be in a register */
  if (!register_operand(operand1, HImode)
      && !register_operand(operand0, HImode))
    {
      operands[1] = copy_to_mode_reg(HImode, operand1);
    }
}")

(define_insn "movstricthi"
  [(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"
  [(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,set_znv,set_znv,set_znv")])

;; movsi

(define_expand "movsi"
  [(set (match_operand:SI 0 "general_operand_dst" "")
	(match_operand:SI 1 "general_operand_src" ""))]
  ""
  "
{
  if (TARGET_H8300)
    {
      if (do_movsi (operands))
	DONE;
    }
  else
    {
      /* One of the ops has to be in a register.  */
      if (!register_operand (operand1, SImode)
	  && !register_operand (operand0, SImode))
	{
	  operands[1] = copy_to_mode_reg (SImode, operand1);
	}
    }
}")

(define_expand "movsf"
  [(set (match_operand:SF 0 "general_operand_dst" "")
	(match_operand:SF 1 "general_operand_src" ""))]
  ""
  "
{
  if (TARGET_H8300)
    {
      if (do_movsi (operands))
	DONE;
    }
  else
    {
      /* One of the ops has to be in a register.  */
      if (!register_operand (operand1, SFmode)
	  && !register_operand (operand0, SFmode))
	{
	  operands[1] = copy_to_mode_reg (SFmode, operand1);
	}
    }
}")

(define_insn "movsi_h8300"
  [(set (match_operand:SI 0 "general_operand_dst" "=r,r,r,o,<,r")
	(match_operand:SI 1 "general_operand_src" "I,r,io,r,r,>"))]
  "TARGET_H8300
   && (register_operand (operands[0], SImode)
       || register_operand (operands[1], SImode))"
  "*
{
  int rn = -1;
  switch (which_alternative)
    {
    case 0:
      return \"sub.w	%e0,%e0\;sub.w	%f0,%f0\";
    case 1:
      if (REGNO(operands[0]) < REGNO(operands[1]))
	return \"mov.w	%e1,%e0\;mov.w	%f1,%f0\";
      else 
	return \"mov.w	%f1,%f0\;mov.w	%e1,%e0\";
    case 2:
      /* Make sure we don't trample the register we index with.  */
    
      if (GET_CODE(operands[1]) == MEM) 
	{
	  rtx inside = XEXP (operands[1],0);
	  if  (REG_P (inside)) 
	    {
	      rn = REGNO(inside);
	    }
	  else if (GET_CODE (inside) == PLUS) 
	    {
	      rtx lhs = XEXP (inside,0);
	      rtx rhs = XEXP (inside,1);
	      if (REG_P (lhs)) rn = REGNO (lhs);
	      if (REG_P (rhs)) rn = REGNO (rhs);
	    }
	}
      if (rn == REGNO (operands[0])) 	
	{
	  /* Move the second word first.  */
	  return \"mov.w	%f1,%f0\;mov.w	%e1,%e0\";
	}
      else 
	{
	  /* 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\";
    case 4:
      return \"mov.w	%f1,%T0\;mov.w	%e1,%T0\";
    case 5:
      return \"mov.w	%T1,%e0\;mov.w	%T1,%f0\";
    }
}"
  [(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,io,r,r,>"))]
  "TARGET_H8300
   && (register_operand (operands[0], SFmode)
       || register_operand (operands[1], SFmode))"
  "*
{
  /* Copy of the movsi stuff */
  int rn = -1;
  switch (which_alternative)
    {
    case 0:
      return \"sub.w	%e0,%e0\;sub.w	%f0,%f0\";
    case 1:
      if (REGNO(operands[0]) < REGNO(operands[1]))
	return \"mov.w	%e1,%e0\;mov.w	%f1,%f0\";
      else 
	return \"mov.w	%f1,%f0\;mov.w	%e1,%e0\";
    case 2:
      /* Make sure we don't trample the register we index with.  */
    
      if (GET_CODE (operands[1]) == MEM) 
	{
	  rtx inside = XEXP (operands[1],0);
	  if (REG_P (inside))
	    {
	      rn = REGNO (inside);
	    }
	  else if (GET_CODE (inside) == PLUS) 
	    {
	      rtx lhs = XEXP (inside,0);
	      rtx rhs = XEXP (inside,1);
	      if (REG_P (lhs)) rn = REGNO (lhs);
	      if (REG_P (rhs)) rn = REGNO (rhs);
	    }
	}
      if (rn == REGNO (operands[0]))
	{
	  /* move the second word first */
	  return \"mov.w	%f1,%f0\;mov.w	%e1,%e0\";
	}
      else 
	{
	  return \"mov.w	%e1,%e0\;mov.w	%f1,%f0\";
	}
    
    case 3:
      return \"mov.w	%e1,%e0\;mov.w	%f1,%f0\";
    case 4:
      return \"mov.w	%f1,%T0\;mov.w	%e1,%T0\";
    case 5:
      return \"mov.w	%T1,%e0\;mov.w	%T1,%f0\";

    }
}"
  [(set_attr "length" "4,4,8,8,4,4")
   (set_attr "cc" "clobber")])

(define_insn "movsi_h8300hs"
  [(set (match_operand:SI 0 "general_operand_dst" "=r,r,r,m,<,r,*a,*a,r")
	(match_operand:SI 1 "general_operand_src" "I,r,im,r,r,>,I,r,*a"))]
  "(TARGET_H8300S || TARGET_H8300H)
   && (register_operand (operands[0], SImode)
       || register_operand (operands[1], SImode))"
  "*
{
  if (which_alternative == 0)
    return \"sub.l	%S0,%S0\";
  if (which_alternative == 6)
    return \"clrmac\";
  if (which_alternative == 7)
    return \"clrmac\;ldmac %1,macl\";
  if (which_alternative == 8)
    return \"stmac macl,%0\";
  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,2,6,4")
   (set_attr "cc" "set_zn,set_znv,set_znv,set_znv,set_znv,set_znv,none_0hit,none_0hit,set_znv")])

(define_insn "movsf_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))"
  "@
   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 "length" "2,2,10,10,4,4")
   (set_attr "cc" "set_zn,set_znv,set_znv,set_znv,set_znv,set_znv")])

;; ----------------------------------------------------------------------
;; 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")])

(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")])

(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")])

(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")])
  
(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")])

(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")])

(define_insn "tstqi"
  [(set (cc0) (match_operand:QI 0 "register_operand" "r"))]
  ""
  "mov.b	%X0,%X0"
  [(set_attr "length" "2")
   (set_attr "cc" "set_znv")])

(define_insn "tsthi"
  [(set (cc0) (match_operand:HI 0 "register_operand" "r"))]
  ""
  "mov.w	%T0,%T0"
  [(set_attr "length" "2")
   (set_attr "cc" "set_znv")])

(define_insn "tstsi"
  [(set (cc0) (match_operand:SI 0 "register_operand" "r"))]
  "TARGET_H8300H || TARGET_H8300S"
  "mov.l	%S0,%S0"
  [(set_attr "length" "2")
   (set_attr "cc" "set_znv")])

(define_insn "cmpqi"
  [(set (cc0)
	(compare:QI (match_operand:QI 0 "register_operand" "r")
		    (match_operand:QI 1 "nonmemory_operand" "rn")))]
  ""
  "cmp.b	%X1,%X0"
  [(set_attr "length" "2")
   (set_attr "cc" "compare")])

(define_expand "cmphi"
  [(set (cc0)
	(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 "length" "2")
   (set_attr "cc" "compare")])

(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" "r,r")
		    (match_operand:SI 1 "nonmemory_operand" "r,i")))]
  "TARGET_H8300H || TARGET_H8300S"
  "cmp.l	%S1,%S0"
  [(set_attr "length" "2,6")
   (set_attr "cc" "compare,compare")])

;; ----------------------------------------------------------------------
;; 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" "rn")))]
  ""
  "add.b	%X2,%X0"
  [(set_attr "length" "2")
   (set_attr "cc" "set_zn")])

(define_expand "addhi3"
  [(set (match_operand:HI 0 "register_operand" "")
	(plus:HI (match_operand:HI 1 "register_operand" "")
		 (match_operand:HI 2 "nonmemory_operand" "")))]
  ""
  "")

;; 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"
  "@
   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,set_zn")])

(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 "length" "4,2")
   (set_attr "cc" "set_zn,set_zn")])

(define_expand "addsi3"
  [(set (match_operand:SI 0 "register_operand" "")
	(plus:SI (match_operand:SI 1 "register_operand" "")
		 (match_operand:SI 2 "nonmemory_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")
		 (match_operand:SI 2 "nonmemory_operand" "n,r,r")))]
  "TARGET_H8300"
  "@
   add	%w2,%w0\;addx	%x2,%x0\;addx	%y2,%y0\;addx	%z2,%z0
   add.w	%f2,%f0\;addx	%y2,%y0\;addx	%z2,%z0
   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")])

(define_insn "addsi_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"
  "@
   add.l	%S2,%S0
   add.l	%S2,%S0"
  [(set_attr "length" "6,2")
   (set_attr "cc" "set_zn,set_zn")])

;; ----------------------------------------------------------------------
;; 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,n")))]
  ""
  "@
   sub.b	%X2,%X0
   add.b	%G2,%X0"
  [(set_attr "length" "2")
   (set_attr "cc" "set_zn")])

(define_expand "subhi3"
  [(set (match_operand:HI 0 "register_operand" "")
	(minus:HI (match_operand:HI 1 "general_operand" "")
		  (match_operand:HI 2 "nonmemory_operand" "")))]
  ""
  "")

;; 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,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"
  "@
   sub.w	%T2,%T0
   sub.w	%T2,%T0"
  [(set_attr "length" "2,4")
   (set_attr "cc" "set_zn,set_zn")])

(define_expand "subsi3"
  [(set (match_operand:SI 0 "register_operand" "")
	(minus:SI (match_operand:SI 1 "register_operand" "")
		  (match_operand:SI 2 "nonmemory_operand" "")))]
  ""
  "")

(define_insn "subsi3_h8300"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(minus:SI (match_operand:SI 1 "register_operand" "0")
		  (match_operand:SI 2 "register_operand" "r")))]
  "TARGET_H8300"
  "sub.w	%f2,%f0\;subx	%y2,%y0\;subx	%z2,%z0"
  [(set_attr "length" "6")
   (set_attr "cc" "clobber")])

;; 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" "=r,r")
	(minus:SI (match_operand:SI 1 "general_operand" "0,0")
		  (match_operand:SI 2 "nonmemory_operand" "r,i")))]
  "TARGET_H8300H || TARGET_H8300S"
  "@
   sub.l	%S2,%S0
   sub.l	%S2,%S0"
  [(set_attr "length" "2,6")
   (set_attr "cc" "set_zn,set_zn")])

;; ----------------------------------------------------------------------
;; MULTIPLY INSTRUCTIONS
;; ----------------------------------------------------------------------

;; Note that the h8/300 can only handle umulqihi3.

(define_insn "mulqihi3"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(mult:HI (sign_extend:HI (match_operand:QI 1 "general_operand" "%0"))
		 (sign_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
  "TARGET_H8300H || TARGET_H8300S"
  "mulxs.b	%X2,%T0"
  [(set_attr "length" "4")
   (set_attr "cc" "set_zn")])

(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_H8300S"
  "mulxs.w	%T2,%S0"
  [(set_attr "length" "4")
   (set_attr "cc" "set_zn")])

(define_insn "umulqihi3"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(mult:HI (zero_extend:HI (match_operand:QI 1 "general_operand" "%0"))
		 (zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
  ""
  "mulxu	%X2,%T0"
  [(set_attr "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_H8300S"
  "mulxu.w	%T2,%S0"
  [(set_attr "length" "2")
   (set_attr "cc" "none_0hit")])

;; This is a "bridge" instruction.  Combine can't cram enough insns
;; together to crate a MAC instruction directly, but it can create
;; this instruction, which then allows combine to create the real
;; MAC insn.
;;
;; Unfortunately, if combine doesn't create a MAC instruction, this
;; insn must generate reasonably correct code.  Egad.
(define_insn ""
  [(set (match_operand:SI 0 "register_operand" "=a")
	(mult:SI
	  (sign_extend:SI
	    (mem:HI (post_inc:SI (match_operand:SI 1 "register_operand" "r"))))
	  (sign_extend:SI
	    (mem:HI (post_inc:SI (match_operand:SI 2 "register_operand" "r"))))))]
  "TARGET_H8300S"
  "clrmac\;mac	%2,%1"
  [(set_attr "length" "6")
   (set_attr "cc" "none_0hit")])

(define_insn ""
  [(set (match_operand:SI 0 "register_operand" "=a")
	(plus (mult:SI
	  (sign_extend:SI (mem:HI
	    (post_inc:SI (match_operand:SI 1 "register_operand" "r"))))
	  (sign_extend:SI (mem:HI
	    (post_inc:SI (match_operand:SI 2 "register_operand" "r")))))
	      (match_operand:SI 3 "register_operand" "0")))]
  "TARGET_H8300S"
  "mac	%2,%1"
  [(set_attr "length" "4")
   (set_attr "cc" "none_0hit")])

;; ----------------------------------------------------------------------
;; DIVIDE INSTRUCTIONS
;; ----------------------------------------------------------------------

(define_insn "udivqi3"
  [(set (match_operand:QI 0 "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 "length" "2")
   (set_attr "cc" "clobber")])

;; ??? Will divxu always work here?

(define_insn "divqi3"
  [(set (match_operand:QI 0 "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 "length" "2")
   (set_attr "cc" "clobber")])

(define_insn "udivhi3"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(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 "length" "2")
   (set_attr "cc" "clobber")])

(define_insn "divhi3"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(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 "length" "4")
   (set_attr "cc" "clobber")])

;; ----------------------------------------------------------------------
;; MOD INSTRUCTIONS
;; ----------------------------------------------------------------------

(define_insn "umodqi3"
  [(set (match_operand:QI 0 "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 "length" "4")
   (set_attr "cc" "clobber")])

(define_insn "modqi3"
  [(set (match_operand:QI 0 "register_operand" "=r")
	(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 "length" "6")
   (set_attr "cc" "clobber")])

(define_insn "umodhi3"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(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 "length" "4")
   (set_attr "cc" "clobber")])

(define_insn "modhi3"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(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 "length" "6")
   (set_attr "cc" "clobber")])

;; ----------------------------------------------------------------------
;; AND INSTRUCTIONS
;; ----------------------------------------------------------------------

(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,%R0"
  [(set_attr "length" "2,4")
   (set_attr "cc" "set_znv,none_0hit")])

(define_expand "andqi3"
  [(set (match_operand:QI 0 "bit_operand" "")
	(and:QI (match_operand:QI 1 "bit_operand" "")
		(match_operand:QI 2 "nonmemory_operand" "")))]
  ""
  "
{
  if (fix_bit_operand (operands, 'O', AND))
    DONE;
}")

(define_insn "andhi3"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(and:HI (match_operand:HI 1 "register_operand" "%0")
		(match_operand:HI 2 "nonmemory_operand" "rn")))]
  ""
  "*
{
  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 "length" "4")
   (set_attr "cc" "clobber")])

(define_insn "andsi3"
  [(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 ""
  [(set (match_operand:QI 0 "bit_operand" "=r,U")
	(ior:QI (match_operand:QI 1 "bit_operand" "%0,0")
		(match_operand:QI 2 "nonmemory_operand" "rn,P")))]
  "register_operand (operands[0], QImode) || p_operand (operands[2], QImode)"
  "@
   or	%X2,%X0
   bset	%V2,%R0"
  [(set_attr "length" "2,4")
   (set_attr "cc" "set_znv,none_0hit")])

(define_expand "iorqi3"
  [(set (match_operand:QI 0 "bit_operand" "=r,U")
	(ior:QI (match_operand:QI 1 "bit_operand" "%0,0")
		(match_operand:QI 2 "nonmemory_operand" "rn,P")))]
  ""
  "
{
  if (fix_bit_operand (operands, 'P', IOR))
    DONE;
}")

(define_insn "iorhi3"
  [(set (match_operand:HI 0 "general_operand" "=r,r")
	(ior:HI (match_operand:HI 1 "general_operand" "%0,0")
		(match_operand:HI 2 "general_operand" "J,rn")))]
  ""
  "*
{
  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 \"\";
    }
  if (TARGET_H8300H || TARGET_H8300S)
    return \"or.w	%T2,%T0\";
  return \"or	%s2,%s0\;or	%t2,%t0; %2 or2\";
}"
  [(set_attr "length" "2,4")
   (set_attr "cc" "clobber,clobber")])

(define_insn "iorsi3"
  [(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 (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 \"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 "length" "2,8")
   (set_attr "cc" "clobber,clobber")])

;; ----------------------------------------------------------------------
;; XOR INSTRUCTIONS
;; ----------------------------------------------------------------------

(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,%R0"
  [(set_attr "length" "2,4")
   (set_attr "cc" "set_znv,none_0hit")])

(define_expand "xorqi3"
  [(set (match_operand:QI 0 "bit_operand" "=r,U")
	(xor:QI (match_operand:QI 1 "bit_operand" "%0,0")
		(match_operand:QI 2 "nonmemory_operand" "rn,O")))]
  ""
  "
{
  if (fix_bit_operand (operands, 'O', XOR))
    DONE;
}")

(define_insn "xorhi3"
  [(set (match_operand:HI 0 "register_operand" "=r,r")
	(xor:HI (match_operand:HI 1 "general_operand" "%0,0")
		(match_operand:HI 2 "nonmemory_operand" "J,rn")))]
  ""
  "*
{
  if (GET_CODE (operands[2]) == CONST_INT)
    {
      int i = INTVAL (operands[2]);

      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" "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")])

;; ----------------------------------------------------------------------
;; NEGATION INSTRUCTIONS
;; ----------------------------------------------------------------------

(define_insn "negqi2"
  [(set (match_operand:QI 0 "register_operand" "=r")
	(neg:QI (match_operand:QI 1 "general_operand" "0")))]
  ""
  "neg	%X0"
  [(set_attr "length" "2")
   (set_attr "cc" "set_zn")])

(define_expand "neghi2"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(neg:HI (match_operand:HI 1 "general_operand" "0")))]
  ""
  "
{
  if (TARGET_H8300)
    {
      emit_insn (gen_neghi2_h8300 (operands[0], operands[1]));
      DONE;
    }
}")

(define_expand "neghi2_h8300"
  [(set (match_dup 2)
	(not:HI (match_operand:HI 1 "register_operand" "r")))
   (set (match_dup 2) (plus:HI (match_dup 2) (const_int 1)))
   (set (match_operand:HI 0 "register_operand" "=r")
	(match_dup 2))]
  ""
  "{ operands[2] = gen_reg_rtx (HImode); }")

(define_insn "neghi2_h8300h"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(neg:HI (match_operand:HI 1 "general_operand" "0")))]
  "TARGET_H8300H || TARGET_H8300S"
  "neg	%T0"
  [(set_attr "length" "2")
   (set_attr "cc" "set_zn")])

(define_expand "negsi2"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(neg:SI (match_operand:SI 1 "general_operand" "0")))]
  ""
  "
{
  if (TARGET_H8300)
    {
      emit_insn (gen_negsi2_h8300 (operands[0], operands[1]));
      DONE;
    }
}")

(define_expand "negsi2_h8300"
  [(set (match_dup 2)
	(not:SI (match_operand:SI 1 "register_operand" "r")))
   (set (match_dup 2) (plus:SI (match_dup 2) (const_int 1)))
   (set (match_operand:SI 0 "register_operand" "=r")
	(match_dup 2))]
  ""
  "{ operands[2] = gen_reg_rtx(SImode); }")

(define_insn "negsi2_h8300h"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(neg:SI (match_operand:SI 1 "general_operand" "0")))]
  "TARGET_H8300H || TARGET_H8300S"
  "neg	%S0"
  [(set_attr "length" "2")
   (set_attr "cc" "set_zn")])

;; ----------------------------------------------------------------------
;; NOT INSTRUCTIONS
;; ----------------------------------------------------------------------

(define_insn "one_cmplqi2"
  [(set (match_operand:QI 0 "register_operand" "=r")
	(not:QI (match_operand:QI 1 "general_operand" "0")))]
  ""
  "not	%X0"
  [(set_attr "length" "2")
   (set_attr "cc" "set_znv")])

(define_insn "one_cmplhi2"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(not:HI (match_operand:HI 1 "general_operand" "0")))]
  ""
  "*
{
  if (TARGET_H8300)
    return \"not	%s0\;not	%t0\";
  else
    return \"not	%T0\";
}"
  [(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")
	(not:SI (match_operand:SI 1 "general_operand" "0")))]
  ""
  "*
{
  if (TARGET_H8300)
    return \"not	%w0\;not	%x0\;not	%y0\;not	%z0\";
  else
    return \"not	%S0\";
}"
  [(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)))])
			

;; ----------------------------------------------------------------------
;; JUMP INSTRUCTIONS
;; ----------------------------------------------------------------------

;; Conditional jump instructions

(define_expand "ble"
  [(set (pc)
	(if_then_else (le (cc0)
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "")

(define_expand "bleu"
  [(set (pc)
	(if_then_else (leu (cc0)
			   (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "")

(define_expand "bge"
  [(set (pc)
	(if_then_else (ge (cc0)
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "")

(define_expand "bgeu"
  [(set (pc)
	(if_then_else (geu (cc0)
			   (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "")

(define_expand "blt"
  [(set (pc)
	(if_then_else (lt (cc0)
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "")

(define_expand "bltu"
  [(set (pc)
	(if_then_else (ltu (cc0)
			   (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "")

(define_expand "bgt"
  [(set (pc)
	(if_then_else (gt (cc0)
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "")

(define_expand "bgtu"
  [(set (pc)
	(if_then_else (gtu (cc0)
			   (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "")

(define_expand "beq"
  [(set (pc)
	(if_then_else (eq (cc0)
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "")

(define_expand "bne"
  [(set (pc)
	(if_then_else (ne (cc0)
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "")

(define_insn "branch_true"
  [(set (pc)
	(if_then_else (match_operator 1 "comparison_operator"
				      [(cc0) (const_int 0)])
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "*
{
  if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0
      && (GET_CODE (operands[1]) == GT
          || GET_CODE (operands[1]) == GE
          || GET_CODE (operands[1]) == LE
          || GET_CODE (operands[1]) == LT))
    {
      cc_status.flags &= ~CC_OVERFLOW_UNUSABLE;
      return 0;
    }

  if (get_attr_length (insn) == 2) 
    return \"b%j1	%l0\";
  else if (get_attr_length (insn) == 4) 
    return \"b%j1	%l0:16\";
  else
    return \"b%k1	.Lh8BR%=\;jmp	@%l0\\n.Lh8BR%=:\";
}" 
 [(set_attr "type" "branch")
   (set_attr "cc" "none")])

(define_insn "branch_false"
  [(set (pc)
	(if_then_else (match_operator 1 "comparison_operator"
				      [(cc0) (const_int 0)])
		      (pc)
		      (label_ref (match_operand 0 "" ""))))]
  ""
  "*
{
  if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0
      && (GET_CODE (operands[1]) == GT
          || GET_CODE (operands[1]) == GE
          || GET_CODE (operands[1]) == LE
          || GET_CODE (operands[1]) == LT))
    {
      cc_status.flags &= ~CC_OVERFLOW_UNUSABLE;
      return 0;
    }

  if (get_attr_length (insn) == 2) 
    return \"b%k1	%l0\";
  else if (get_attr_length (insn) == 4) 
    return \"b%k1	%l0:16\";
  else
    return \"b%j1	.Lh8BR%=\;jmp	@%l0\\n.Lh8BR%=:\";
}"
  [(set_attr "type" "branch")
   (set_attr "cc" "none")])

;; Unconditional and other jump instructions.

(define_insn "jump"
  [(set (pc)
	(label_ref (match_operand 0 "" "")))]
  ""
  "*
{
  if (get_attr_length (insn) == 2)
    return \"bra	%l0\";
  else if (get_attr_length (insn) == 4)
    return \"bra	%l0:16\";
  else
    return \"jmp	@%l0\";
}"
  [(set_attr "type" "branch")
   (set_attr "cc" "none")])

;; This is a define expand, because pointers may be either 16 or 32 bits.

(define_expand "tablejump"
  [(parallel [(set (pc) (match_operand 0 "register_operand" "r"))
	      (use (label_ref (match_operand 1 "" "")))])]
  ""
  "")

(define_insn "tablejump_h8300"
  [(set (pc) (match_operand:HI 0 "register_operand" "r"))
   (use (label_ref (match_operand 1 "" "")))]
  "TARGET_H8300"
  "jmp	@%0"
  [(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_H8300S"
  "jmp	@%0"
  [(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" ""))]
  ""
  "")

(define_insn "indirect_jump_h8300"
  [(set (pc) (match_operand:HI 0 "jump_address_operand" "Vr"))]
  "TARGET_H8300"
  "jmp	@%0"
  [(set_attr "cc" "none")
   (set_attr "length" "2")])

(define_insn "indirect_jump_h8300h"
  [(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.

;; ??? Even though we use HImode here, this works for the 300h.

(define_insn "call"
  [(call (match_operand:QI 0 "call_insn_operand" "or")
	 (match_operand:HI 1 "general_operand" "g"))]
  ""
  "*
{
  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).

;; ??? Even though we use HImode here, this works on the 300h.

(define_insn "call_value"
  [(set (match_operand 0 "" "=r")
	(call (match_operand:QI 1 "call_insn_operand" "or")
	      (match_operand:HI 2 "general_operand" "g")))]
  ""
  "*
{
  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 "cc" "none")
   (set_attr "length" "2")])

;; ----------------------------------------------------------------------
;; EXTEND INSTRUCTIONS
;; ----------------------------------------------------------------------

(define_insn "zero_extendqihi2"
  [(set (match_operand:HI 0 "register_operand" "=r,r")
	(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 (TARGET_H8300
      && GET_CODE (operands[1]) != CONST_INT
      && !optimize)
    {
      emit_insn (gen_zero_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 "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 ""
  [(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_znv,set_znv")])

(define_expand "extendqihi2"
  [(set (match_operand:HI 0 "register_operand" "")
	(sign_extend:HI (match_operand:QI 1 "general_operand" "")))]
  ""
  "")

(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_znv,set_znv")])

;; 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" "")
	(sign_extend:SI (match_operand:HI 1 "general_operand" "")))]
  ""
  "
{
  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)))
   (set (match_operand:SI 0 "general_operand" "" ) (reg:SI 0))]
  "TARGET_H8300"
  "")

(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"
  "@
  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 ""
  [(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_znv,set_znv")])

;; ----------------------------------------------------------------------
;; SHIFTS
;; ----------------------------------------------------------------------
;;
;; We make some attempt to provide real efficient shifting.  One example is
;; doing an 8 bit shift of a 16 bit value by moving a byte reg into the other
;; reg and moving 0 into the former reg.
;;
;; We also try to achieve this in a uniform way.  IE: We don't try to achieve
;; this in both rtl and at insn emit time.  Ideally, we'd use rtl as that would
;; give the optimizer more cracks at the code.  However, we wish to do things
;; like optimizing shifting the sign bit to bit 0 by rotating the other way.
;; There is rtl to handle this (rotate + and), but the h8/300 doesn't handle
;; 16 bit rotates.  Also, if we emit complicated rtl, combine may not be able
;; to detect cases it can optimize.
;;
;; For these and other fuzzy reasons, I've decided to go the less pretty but
;; easier "do it at insn emit time" route.

;; QI BIT SHIFTS

(define_expand "ashlqi3"
  [(set (match_operand:QI 0 "register_operand" "")
	(ashift:QI (match_operand:QI 1 "register_operand" "")
		   (match_operand:QI 2 "nonmemory_operand" "")))]
  ""
  "if (expand_a_shift (QImode, ASHIFT, operands)) DONE;else FAIL;")

(define_expand "ashrqi3"
  [(set (match_operand:QI 0 "register_operand" "")
	(ashiftrt:QI (match_operand:QI 1 "register_operand" "")
		     (match_operand:QI 2 "nonmemory_operand" "")))]
  ""
  "if (expand_a_shift (QImode, ASHIFTRT, operands)) DONE;else FAIL;")

(define_expand "lshrqi3"
  [(set (match_operand:QI 0 "register_operand" "")
	(lshiftrt:QI (match_operand:QI 1 "register_operand" "")
		     (match_operand:QI 2 "nonmemory_operand" "")))]
  ""
  "if (expand_a_shift (QImode, LSHIFTRT, operands)) DONE;else FAIL;")

(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" "KM,rn")]))
   (clobber (match_scratch:QI 4 "=X,&r"))]
  ""
  "* return emit_a_shift (insn, operands);"
  [(set_attr "length" "20")
   (set_attr "cc" "clobber")])

;; HI BIT SHIFTS

(define_expand "ashlhi3"
  [(set (match_operand:HI 0 "register_operand" "")
	(ashift:HI (match_operand:HI 1 "nonmemory_operand" "")
		   (match_operand:QI 2 "nonmemory_operand" "")))]
  ""
  "if (expand_a_shift (HImode, ASHIFT, operands)) DONE;else FAIL;")

(define_expand "lshrhi3"
  [(set (match_operand:HI 0 "register_operand" "")
	(lshiftrt:HI (match_operand:HI 1 "general_operand" "")
		     (match_operand:QI 2 "nonmemory_operand" "")))]
  ""
  "if (expand_a_shift (HImode, LSHIFTRT, operands)) DONE;else FAIL;")

(define_expand "ashrhi3"
  [(set (match_operand:HI 0 "register_operand" "")
	(ashiftrt:HI (match_operand:HI 1 "register_operand" "")
		     (match_operand:QI 2 "nonmemory_operand" "")))]
  ""
  "if (expand_a_shift (HImode, ASHIFTRT, operands)) DONE;else FAIL;")

(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" "KM,rn")]))
   (clobber (match_scratch:QI 4 "=X,&r"))]
  ""
  "* return emit_a_shift (insn, operands);"
  [(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" "")
	 (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" "")
	 (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" "")
	 (match_operand:QI 2 "nonmemory_operand" "")))]
  ""
  "if (expand_a_shift (SImode, ASHIFTRT, operands)) DONE;else FAIL;")

(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" "K,rn")]))
   (clobber (match_scratch:QI 4 "=X,&r"))]
  ""
  "* return emit_a_shift (insn, operands);"
  [(set_attr "length" "20")
   (set_attr "cc" "clobber")])

;; -----------------------------------------------------------------
;; BIT FIELDS
;; -----------------------------------------------------------------
;; The H8/300 has given 1/8th of its opcode space to bitfield
;; instructions so let's use them as well as we can.

;; 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.

;; 
;; 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:HI 1 "register_operand" "r")
			 (const_int 1)
			 (match_operand:HI 2 "immediate_operand" "n")))]
  ""
  "sub.w	%0,%0\;bld	%Z2,%Y1\;bst	#0,%X0"
  [(set_attr "cc" "clobber")
   (set_attr "length" "6")])

(define_insn ""
  [(set (match_operand:HI 0 "register_operand" "=&r")
	(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.
;;

(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 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 ""
  [(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)))]
  ""
  "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 "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")))]
  ""
  "* 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)))])

;; 
;; 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)))])

(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 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: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;

  /* For now, we don't allow memory operands.  */
  if (GET_CODE (operands[0]) == MEM
      || GET_CODE (operands[3]) == MEM)
    FAIL;
}")

(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: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;

  /* For now, we don't allow memory operands.  */
  if (GET_CODE (operands[1]) == MEM)
    FAIL;
}")

;; BAND, BOR, and BXOR patterns

(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_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"))]))]
  ""
  "bld	%Z2,%Y1\;%b5	%Z4,%Y3\;bst	#0,%R0; bl3"
  [(set_attr "cc" "clobber")
   (set_attr "length" "6")])


;; ----------------------------------------------
;; Peepholes go at the end.
;; ----------------------------------------------

;; Notice when two byte moves in a row could be a word move.

(define_peephole
  [(set (match_operand:QI 0 "register_operand" "=r")
	(mem:QI (plus:HI (match_operand:HI 1 "register_operand" "r")
			 (match_operand:HI 2 "immediate_operand" "n"))))
   (set (match_operand:QI 3 "register_operand" "=r")
	(mem:QI (plus:HI (match_dup 1)
			 (match_operand:HI 4 "immediate_operand" "n"))))]
  "(INTVAL(operands[2]) == INTVAL(operands[4])+1) && REGNO(operands[0]) +1 == REGNO(operands[3])"
  "mov.w	@(%u4,%T1),%T0"
  [(set_attr "length" "6")
   (set_attr "cc" "set_znv")])

(define_peephole
  [(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)
			 (match_operand:HI 4 "immediate_operand" "n")))
	(match_operand:QI 3 "register_operand" "r"))]
  "(INTVAL(operands[2]) == INTVAL(operands[4])+1) && REGNO(operands[0]) +1 == REGNO(operands[3])"
  "mov.w	%T0,@(%u4,%T1)"
  [(set_attr "length" "6")
   (set_attr "cc" "set_znv")])

;; Notice a move which could be post incremented.

(define_peephole 
  [(set (match_operand:QI 0 "register_operand" "")
	(mem:QI (match_operand:HI 1 "register_operand" "")))
   (set (match_dup 1) (plus:HI (match_dup 1) (const_int 1)))]
  "REGNO(operands[1]) != REGNO(operands[0])"
  "mov.b	@%T1+,%X0"
  [(set_attr "length" "2")
   (set_attr "cc" "set_znv")])

(define_peephole 
  [(set (match_operand:HI 0 "register_operand" "")
	(mem:HI (match_operand:HI 1 "register_operand" "")))
   (set (match_dup 1) (plus:HI (match_dup 1) (const_int 2)))]
  "REGNO(operands[1]) != REGNO(operands[0])"
  "mov.w	@%T1+,%T0"
  [(set_attr "length" "2")
   (set_attr "cc" "set_znv")])

;; Notice a move which could be predecremented.

(define_peephole 
  [(set (match_operand:HI 1 "register_operand" "")
	(plus:HI (match_dup 1) (const_int -1)))
   (set (mem:QI (match_dup 1))
		(match_operand:QI 0 "register_operand" ""))]
  "REGNO(operands[1]) != REGNO(operands[0])"
  "mov.b	%X0,@-%T1"
  [(set_attr "length" "2")
   (set_attr "cc" "set_znv")])

(define_peephole 
  [(set (match_operand:HI 1 "register_operand" "")
	(plus:HI (match_dup 1) (const_int -1)))
   (set (mem:HI (match_dup 1))
		(match_operand:HI 0 "register_operand" ""))]
  "REGNO(operands[1]) != REGNO(operands[0])"
  "mov.w	%T0,@-%T1"
  [(set_attr "length" "2")
   (set_attr "cc" "set_znv")])

