;; GCC machine description for Hitachi H8/300
;; Copyright (C) 1992, 1993, 1994, 1995, 1996 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")))

;; ??? 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 patterns have overly conservative lengths.  In particular:
;;
;;	* movXX insns using register indirect addressing.
;; 	* insns referencing the 8-bit area with an 8-bit address.

;; Loading some 32bit integer constants could be done more
;; efficiently.  For example loading the value 4 as a 32bit
;; is normally done via mov.l #4,erX.  sub.l erX,erX, inc.l #4,erX 
;; would be more efficient time and space-wise.  Similar sequences
;; can be found using bit-set insns dec, etc

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

;; Should be HI & SImode tstXX insns which test one bit using btst.
;;
;; Some insns allow general operations, but lengths don't take
;; into account that a general operand may be a memory reference
;; with a long length.  (EXTEND insns)

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

;; ??? Implement remaining bit ops available on the h8300

(define_attr "type" "branch,bcs,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)))
         (eq_attr "type" "bcs")
	 (if_then_else (and (ge (minus (pc) (match_dup 0))
				(const_int -120))
			    (le (minus (pc) (match_dup 0))
				(const_int 120)))
		       (if_then_else
			 (match_operand 2 "register_operand" "")
			 (const_int 4)
			 (const_int 6))
		       (if_then_else (and (eq_attr "cpu" "h8300h")
					  (and (ge (minus (pc) (match_dup 0))
						   (const_int -32000))
					       (le (minus (pc) (match_dup 0))
						   (const_int 32000))))
				     (if_then_else
				       (match_operand 2 "register_operand" "")
				       (const_int 6)
				       (const_int 8))
				     (if_then_else
				       (match_operand 2 "register_operand" "")
				       (const_int 8)
				       (const_int 10))))]
	(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 - insn sets flags z,n.  v,c are set to 0.
;;	(c may not really be set to 0 but that's ok, we don't need it anyway).
;; set_zn_c0 - insn sets z,n to usable values.  v is unknown.  c may or may not
;;	be known (if it isn't that's ok, we don't need it anyway).
;; compare - compare instruction
;; clobber - value of cc is unknown
(define_attr "cc" "none,none_0hit,set,set_zn_c0,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")])

(define_insn "movqi_internal"
  [(set (match_operand:QI 0 "general_operand_dst" "=r,r,<,r,o")
	(match_operand:QI 1 "general_operand_src" "I,r>,r,io,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	%X1,%R0"
  [(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))
      (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))])
   (set_attr "cc" "set_zn_c0,set,set,set,set")])

(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"))
			 (match_operand:QI 1 "general_operand_src" "I,r,io"))]
  ""
  "@
   sub.b	%X0,%X0
   mov.b	%X1,%X0
   mov.b	%R1,%X0"
  [(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 "cc" "set_zn_c0,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" "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")])

(define_insn "movhi_internal"
  [(set (match_operand:HI 0 "general_operand_dst" "=r,r,<,r,o")
	(match_operand:HI 1 "general_operand_src" "I,r>,r,ion,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"
  [(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))
      (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))])
   (set_attr "cc" "set_zn_c0,set,set,set,set")])

(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"))
			 (match_operand:HI 1 "general_operand_src" "I,r,io"))]
  ""
  "@
   sub.w	%T0,%T0
   mov.w	%T1,%T0
   mov.w	%T1,%T0"
  [(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 "cc" "set_zn_c0,set,set")])

;; 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 /* TARGET_H8300H */
    {
      /* One of the ops has to be in a register.  */
      if (!register_operand (operand1, SImode)
	  && !register_operand (operand0, SImode))
	{
	  operands[1] = copy_to_mode_reg (SImode, operand1);
	}
    }
}")

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

(define_insn "movsi_h8300"
  [(set (match_operand:SI 0 "general_operand_dst" "=r,r,r,o,<,r")
	(match_operand:SI 1 "general_operand_src" "I,r,ion,r,r,>"))]
  "TARGET_H8300
   && (register_operand (operands[0], SImode)
       || register_operand (operands[1], SImode))"
  "*
{
  int rn = -1;
  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,ion,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_h8300h"
  [(set (match_operand:SI 0 "general_operand_dst" "=r,r,r,o,<,r")
	(match_operand:SI 1 "general_operand_src" "I,r,ion,r,r,>"))]
  "TARGET_H8300H
   && (register_operand (operands[0], SImode)
       || register_operand (operands[1], SImode))"
  "*
{
  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
   && (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_c0,set,set,set,set,set")])

;; ----------------------------------------------------------------------
;; TEST INSTRUCTIONS
;; ----------------------------------------------------------------------

(define_insn ""
  [(set (cc0) (and:QI (match_operand:QI 0 "bit_operand" "Ur")
		      (match_operand:QI 1 "o_operand" "O")))]
  ""
  "btst %W1,%R0"
  [(set_attr "length" "2")
   (set_attr "cc" "set_zn_c0")])
  
(define_insn "tstqi"
  [(set (cc0) (match_operand:QI 0 "general_operand" "r"))]
  ""
  "mov.b	%X0,%X0"
  [(set_attr "length" "2")
   (set_attr "cc" "set")])

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

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

(define_insn "cmpqi"
  [(set (cc0)
	(compare:QI (match_operand:QI 0 "register_operand" "r")
		    (match_operand:QI 1 "nonmemory_operand" "ri")))]
  ""
  "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_H8300H)
    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_H8300H"
  "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")
		    (match_operand:HI 1 "nonmemory_operand" "ri")))]
  "TARGET_H8300H"
  "cmp.w	%T1,%T0"
  [(set_attr "length" "2")
   (set_attr "cc" "compare")])

(define_insn "cmpsi"
  [(set (cc0)
	(compare:SI (match_operand:SI 0 "register_operand" "r")
		    (match_operand:SI 1 "nonmemory_operand" "ri")))]
  "TARGET_H8300H"
  "cmp.l	%S1,%S0"
  [(set_attr "length" "2")
   (set_attr "cc" "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" "ri")))]
  ""
  "add.b	%X2,%X0"
  [(set_attr "length" "2")
   (set_attr "cc" "set_zn_c0")])

(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" "i")))]
  ""
  "* return output_adds_subs (operands);"
  [(set_attr "length" "4")
   (set_attr "cc" "none_0hit")])

(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_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" "i,r")))]
  "TARGET_H8300H"
  "@
   add.w	%T2,%T0
   add.w	%T2,%T0"
  [(set_attr "length" "4,2")
   (set_attr "cc" "set_zn_c0,set_zn_c0")])

(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" "i")))]
  "TARGET_H8300H"
  "* return output_adds_subs (operands);"
  [(set_attr "length" "4")
   (set_attr "cc" "none_0hit")])

(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	%f1,%f0\;mov	%e1,%e0\;add.w	%f2,%f0\;addx	%y2,%y0\;addx	%z2,%z0"
  [(set_attr "length" "8,6,20")
   (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"
  "@
   add.l	%S2,%S0
   add.l	%S2,%S0"
  [(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")))]
  ""
  "@
   sub.b	%X2,%X0
   add.b	%G2,%X0"
  [(set_attr "length" "2")
   (set_attr "cc" "set_zn_c0")])

(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" "i")))]
  ""
  "*
{
  operands[2] = GEN_INT (-INTVAL (operands[2]));
  return output_adds_subs (operands);
}"
  [(set_attr "length" "4")
   (set_attr "cc" "none_0hit")])

(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 ; -%0"
  [(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,i")))]
  "TARGET_H8300H"
  "@
   sub.w	%T2,%T0
   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" "")
	(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" "i")))]
  "TARGET_H8300H"
  "*
{
  operands[2] = GEN_INT (-INTVAL (operands[2]));
  return output_adds_subs (operands);
}"
  [(set_attr "length" "4")
   (set_attr "cc" "none_0hit")])

(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"
  "@
   sub.l	%S2,%S0
   sub.l	%S2,%S0"
  [(set_attr "length" "2,6")
   (set_attr "cc" "set_zn_c0,set_zn_c0")])

;; ----------------------------------------------------------------------
;; MULTIPLY INSTRUCTIONS
;; ----------------------------------------------------------------------

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

(define_insn "mulqihi3"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(mult:HI (sign_extend:HI (match_operand:QI 1 "general_operand" "%0"))
		 (sign_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
  "TARGET_H8300H"
  "mulxs.b	%X2,%T0"
  [(set_attr "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"
  "mulxs.w	%T2,%S0"
  [(set_attr "length" "4")
   (set_attr "cc" "set_zn_c0")])

(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"
  "mulxu.w	%T2,%S0"
  [(set_attr "length" "2")
   (set_attr "cc" "none_0hit")])

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

(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")))]
  ""
  "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")
	(div:QI (match_operand:HI 1 "general_operand" "0")
		(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")
	(udiv:HI (match_operand:SI 1 "general_operand" "0")
		 (match_operand:HI 2 "register_operand" "r")))]
  "TARGET_H8300H"
  "divxu.w	%T2,%S0"
  [(set_attr "length" "2")
   (set_attr "cc" "clobber")])

(define_insn "divhi3"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(div:HI (match_operand:SI 1 "general_operand" "0")
		(match_operand:HI 2 "register_operand" "r")))]
  "TARGET_H8300H"
  "divxs.w	%T2,%S0"
  [(set_attr "length" "4")
   (set_attr "cc" "clobber")])

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

(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")))]
  ""
  "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")
	(mod:QI (match_operand:HI 1 "general_operand" "0")
		(match_operand:QI 2 "register_operand" "r")))]
  "TARGET_H8300H"
  "divxs.b	%X2,%T0\;mov %t0,%s0"
  [(set_attr "length" "6")
   (set_attr "cc" "clobber")])

(define_insn "umodhi3"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(umod:HI (match_operand:SI 1 "general_operand" "0")
		 (match_operand:HI 2 "register_operand" "r")))]
  "TARGET_H8300H"
  "divxu.w	%T2,%S0\;mov %e0,%f0"
  [(set_attr "length" "4")
   (set_attr "cc" "clobber")])

(define_insn "modhi3"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(mod:HI (match_operand:SI 1 "general_operand" "0")
		(match_operand:HI 2 "register_operand" "r")))]
  "TARGET_H8300H"
  "divxs.w	%T2,%S0\;mov %e0,%f0"
  [(set_attr "length" "6")
   (set_attr "cc" "clobber")])

;; ----------------------------------------------------------------------
;; AND INSTRUCTIONS
;; ----------------------------------------------------------------------

(define_insn "andqi3_internal"
  [(set (match_operand:QI 0 "bit_operand" "=r,U")
	(and:QI (match_operand:QI 1 "bit_operand" "%0,0")
		(match_operand:QI 2 "nonmemory_operand" "rn,O")))]
  "register_operand (operands[0], QImode) || o_operand (operands[2], QImode)"
  "@
   and	%X2,%X0
   bclr	%W2,%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")))]
  ""
  "
{
  if (fix_bit_operand (operands, 'O', AND))
    DONE;
}")

(define_insn "andhi3"
  [(set (match_operand:HI 0 "register_operand" "=r,r")
	(and:HI (match_operand:HI 1 "register_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) != 0x00ff) 
	output_asm_insn (\"and	%s2,%s0\", operands);
      if ((i & 0xff00) != 0xff00) 
	output_asm_insn (\"and	%t2,%t0\", operands);
      return \"\";
    }
  if (TARGET_H8300H)
    return \"and.w %T2,%T0\";
  return \"and	%s2,%s0\;and	%t2,%t0;\";
}"
  [(set_attr "length" "2,4")
   (set_attr "cc" "clobber,clobber")])

(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" "J,rn")))]
  ""
  "*
{
  if (GET_CODE (operands[2]) == CONST_INT)
    {
      int i = INTVAL (operands[2]);

      /* ??? If we used e0..e7, then we could sub.w eX,eX to
	 clear the high word if (i & 0xffff0000) == 0.  */

      /* 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
	  && (i & 0xffff0000) != 0xffff0000)
        return \"and.l	%S2,%S0\";

      if ((i & 0x000000ff) != 0x000000ff) 
	output_asm_insn (\"and	%w2,%w0\", operands);
      if ((i & 0x0000ff00) != 0x0000ff00) 
	output_asm_insn (\"and	%x2,%x0\", operands);
      if ((i & 0x00ff0000) != 0x00ff0000) 
	output_asm_insn (\"and	%y2,%y0\", operands);
      if ((i & 0xff000000) != 0xff000000) 
	output_asm_insn (\"and	%z2,%z0\", operands);
      return \"\";
    }
  if (TARGET_H8300H)
    return \"and.l	%S2,%S0\";
  return \"and	%w2,%w0\;and	%x2,%x0\;and	%y2,%y0\;and	%z2,%z0\;\";
}"
  [(set_attr "length" "2,8")
   (set_attr "cc" "clobber,clobber")])

;; ----------------------------------------------------------------------
;; OR INSTRUCTIONS
;; ----------------------------------------------------------------------

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

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

(define_insn "xorhi3"
  [(set (match_operand:HI 0 "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)
    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
	  && (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)
    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_c0")])

(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"
  "neg	%T0"
  [(set_attr "length" "2")
   (set_attr "cc" "set_zn_c0")])

(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"
  "neg	%S0"
  [(set_attr "length" "2")
   (set_attr "cc" "set_zn_c0")])

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

(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") (const_int 0))
		      (const_int 8)
		      (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") (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 we erroneously deleted a compare insn (which can happen if we need
     CC bits set that aren't), emit the compare.  */
  if (restore_compare_p (operands[1]))
    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	%L0\;jmp	@%l0\;%L0:\";
}" 
 [(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 we erroneously deleted a compare insn (which can happen if we need
     CC bits set that aren't), emit the compare.  */
  if (restore_compare_p (operands[1]))
    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	%L0\;jmp	@%l0\;%L0:\";
}"
  [(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"
  "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" "Vr"))]
  ""
  "")

(define_insn "indirect_jump_h8300"
  [(set (pc) (match_operand:HI 0 "jump_address_operand" "V,r"))]
  "TARGET_H8300"
  "@
   jmp	@%0
   jmp	@%0"
  [(set_attr "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 "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" "")))]
  ""
  "
{
  extern int optimize;

  if (TARGET_H8300
      && GET_CODE (operands[1]) != CONST_INT
      && !optimize)
    {
      emit_insn (gen_zero_extendhisi2_h8300 (operands[0], operands[1]));
      DONE;
    }
}")


;; I don't know why, but if I try to simplify extendhisi2 in the
;; natural way, I get about a 2X code bloat on the h8300 without
;; optimization, and a small bloat with optimization.  Weird.
(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"
  "@
  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" "")))]
  ""
  "")

(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"
  "@
  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" "")
	(sign_extend:SI (match_operand:HI 1 "general_operand" "")))]
  ""
  "
{
  extern int optimize;
  if (TARGET_H8300
      && GET_CODE (operands[1]) != CONST_INT
      && !optimize)
    {
      emit_insn (gen_extendhisi2_h8300 (operands[0], operands[1]));
      DONE;
    }
}")

;; I don't know why, but if I try to simplify extendhisi2 in the
;; natural way, I get about a 2X code bloat on the h8300 without
;; optimization, and a small bloat with optimization.  Weird.
(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"
  "@
  exts.l	%S0
  mov.w	%T1,%T0\;exts.l	%S0"
  [(set_attr "length" "2,4")
   (set_attr "cc" "set,set")])

;; ----------------------------------------------------------------------
;; 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;")

;; WARNING: The constraints on the scratch register say one is not needed
;; for constant shifts of 1,2,3,4.  Emit_a_shift() must know this.

(define_insn "shiftbyn_QI"
  [(set (match_operand:QI 0 "register_operand" "=r,r")
	(match_operator:QI 3 "nshift_operator" 
			[ (match_operand:QI 1 "register_operand" "0,0")
			  (match_operand:QI 2 "nonmemory_operand" "IKM,rn")]))
   (clobber (match_scratch:QI 4 "=X,&r"))]
  ""
  "* return emit_a_shift (insn, operands);"
  [(set_attr "length" "20")
;; ??? We'd like to indicate that cc is set here, and it is for simple shifts.
;; However, for cases that loop or are done in pieces, cc does not contain
;; what we want.  Emit_a_shift is free to tweak cc_status as desired.
   (set_attr "cc" "clobber")])

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

;; 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"
  [(set (match_operand:HI 0 "register_operand" "=r,r")
	(match_operator:HI 3 "nshift_operator" 
			[ (match_operand:HI 1 "register_operand" "0,0")
			  (match_operand:QI 2 "nonmemory_operand" "IKM,rn")]))
   (clobber (match_scratch:QI 4 "=X,&r"))]
  ""
  "* return emit_a_shift (insn, operands);"
  [(set_attr "length" "20")
;; ??? We'd like to indicate that cc is set here, and it is for simple shifts.
;; However, for cases that loop or are done in pieces, cc does not contain
;; what we want.  Emit_a_shift is free to tweak cc_status as desired.
   (set_attr "cc" "clobber")])

;;  SI BIT SHIFTS

(define_expand "ashlsi3"
  [(set (match_operand:SI 0 "register_operand" "")
	(ashift:SI
	 (match_operand:SI 1 "general_operand" "")
	 (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;")

;; 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"
  [(set (match_operand:SI 0 "register_operand" "=r,r")
	(match_operator:SI 3 "nshift_operator" 
			[ (match_operand:SI 1 "register_operand" "0,0")
			  (match_operand:QI 2 "nonmemory_operand" "IK,rn")]))
   (clobber (match_scratch:QI 4 "=X,&r"))]
  ""
  "* return emit_a_shift (insn, operands);"
  [(set_attr "length" "20")
;; ??? We'd like to indicate that cc is set here, and it is for simple shifts.
;; However, for cases that loop or are done in pieces, cc does not contain
;; what we want.  Emit_a_shift is free to tweak cc_status as desired.
   (set_attr "cc" "clobber")])

;; -----------------------------------------------------------------
;; 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.

;; BCC and BCS patterns.

(define_insn ""
  [(set (pc)
	(if_then_else 
	 (match_operator 1 "eq_operator"
			 [(zero_extract:QI 
			    (match_operand:HI 2 "register_operand" "r")
			    (const_int 1)
			    (match_operand:HI 3 "immediate_operand" "i"))
			  (const_int 0)])
	 (label_ref (match_operand 0 "" ""))
	 (pc)))]
  ""
  "*
{
  /* The length of this insn includes the bld insn below.  We
     compute the length of the branch without the bld so we
     can easily choose the right branch length.  */
  int branch_length = get_attr_length (insn);

  if (! register_operand (operands[2], HImode))
    branch_length -= 4;
  else
    branch_length -= 2;

  output_asm_insn(\"bld	%Z3,%Y2\", operands);
  if (branch_length == 2) 
    return \"%d1	%l0\";
  else if (branch_length == 4) 
    return \"%d1	%l0:16\";
  else
    return \"%g1	%L0\;jmp	@%l0\;%L0:\";
}" 
  [(set_attr "type" "bcs")
   (set_attr "cc" "clobber")])

(define_insn ""
  [(set (pc)
	(if_then_else 
	 (match_operator 1 "eq_operator"
			 [(zero_extract:HI
			    (match_operand:HI 2 "register_operand" "r")
			    (const_int 1)
			    (match_operand:HI 3 "immediate_operand" "i"))
			  (const_int 0)])
	 (label_ref (match_operand 0 "" ""))
	 (pc)))]
  ""
  "*
{
  /* The length of this insn includes the bld insn below.  We
     compute the length of the branch without the bld so we
     can easily choose the right branch length.  */
  int branch_length = get_attr_length (insn);

  if (! register_operand (operands[2], HImode))
    branch_length -= 4;
  else
    branch_length -= 2;

  output_asm_insn(\"bld	%Z3,%Y2\", operands);
  if (branch_length == 2) 
    return \"%d1	%l0\";
  else if (branch_length == 4) 
    return \"%d1	%l0:16\";
  else
    return \"%g1	%L0\;jmp	@%l0\;%L0:\";
}" 
  [(set_attr "type" "bcs")
   (set_attr "cc" "clobber")])

(define_insn ""
  [(set (pc)
	(if_then_else 
	 (match_operator 1 "eq_operator"
			 [(zero_extract:HI
			    (match_operand:HI 2 "register_operand" "U")
			    (const_int 1)
			    (match_operand:HI 3 "immediate_operand" "i"))
			  (const_int 0)])
	 (pc)
	 (label_ref (match_operand 0 "" ""))))]
  ""
  "*
{
  /* The length of this insn includes the bld insn below.  We
     compute the length of the branch without the bld so we
     can easily choose the right branch length.  */
  int branch_length = get_attr_length (insn);

  if (! register_operand (operands[2], HImode))
    branch_length -= 4;
  else
    branch_length -= 2;

  output_asm_insn(\"bld	%Z3,%Y2\", operands);
  if (branch_length == 2) 
    return \"%d1	%l0\";
  else if (branch_length == 4) 
    return \"%d1	%l0:16\";
  else
    return \"%g1	%L0\;jmp	@%l0\;%L0:\";
}" 
  [(set_attr "type" "bcs")
   (set_attr "cc" "clobber")])

(define_insn ""
  [(set (pc)
	(if_then_else 
	 (match_operator 1 "eq_operator"
			 [(zero_extract:QI 
			    (match_operand:HI 2 "register_operand" "r")
			    (const_int 1)
			    (match_operand:HI 3 "immediate_operand" "i"))
			  (const_int 0)])
	 (pc)
	 (label_ref (match_operand 0 "" ""))))]
  ""
  "*
{
  /* The length of this insn includes the bld insn below.  We
     compute the length of the branch without the bld so we
     can easily choose the right branch length.  */
  int branch_length = get_attr_length (insn);

  if (! register_operand (operands[2], HImode))
    branch_length -= 4;
  else
    branch_length -= 2;

  output_asm_insn(\"bld	%Z3,%Y2\", operands);
  if (branch_length == 2) 
    return \"%d1	%l0\";
  else if (branch_length == 4) 
    return \"%d1	%l0:16\";
  else
    return \"%g1	%L0\;jmp	@%l0\;%L0:\";
}" 
  [(set_attr "type" "bcs")
   (set_attr "cc" "clobber")])

;; 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" "i")))]
  ""
  "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" "i")) 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 && 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") (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") (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") (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") (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") (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") (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") (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") (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") (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" "i"))
	(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" "i"))
	    (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" "i"))
	    (zero_extract:HI (match_operand:HI 3 "register_operand" "r")
			     (const_int 1)
			     (match_operand:HI 4 "immediate_operand" "i"))]))]
  ""
  "bld	%Z2,%Y1\;%b5	%Z4,%Y3\;bst	#0,%R0; bl3"
  [(set_attr "cc" "clobber")
   (set_attr "length" "6")])


;; -------------------------------------------
;; BLK moves
;; -------------------------------------------

(define_expand "movstrhi"
  [(parallel [(set (mem:BLK (match_operand:BLK 0 "general_operand" ""))
		   (mem:BLK (match_operand:BLK 1 "general_operand" "")))
	     (use (match_operand:HI 2 "general_operand" ""))
	     (use (match_operand:HI 3 "immediate_operand" ""))
	     (clobber (match_dup 3))
  ])]
  ""
  "
{
	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;	
}")

;; ----------------------------------------------
;; 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")])

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

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

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

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

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

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

(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_src" "Ur>")))]
  ""
  "mov.b	%R2,%R0\;bset	%X1,%R0"
  [(set_attr "length" "4")
   (set_attr "cc" "clobber")])

(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,%R0; l1
   mov.b	%R1,%X3\;mov.b	%3,%0\;bclr	%X2,%R0; l3"
  [(set_attr "length" "8")
   (set_attr "cc" "clobber")])

(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,%R0; l1
   mov.b	%R1,%X3\;mov.b	%3,%0\;bclr	%X2,%R0;l2"
  [(set_attr "length" "8")
   (set_attr "cc" "clobber")])

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

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

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

(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_src" "U,r>")))]
  ""
  "mov.b	%R2,%R0\;bset	%X1,%R0"
  [(set_attr "length" "4")
   (set_attr "cc" "clobber")])
	
(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,%R0"
  [(set_attr "length" "2")
   (set_attr "cc" "clobber")])

(define_insn "pxor"
  [(set (zero_extract:QI (match_operand:HI 0 "register_operand" "=r,r")
			 (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,%R2\;bist	%1,%0"
  [(set_attr "length" "4")
   (set_attr "cc" "clobber")])

(define_insn ""
  [(set (match_operand:QI 0 "register_operand" "=r")
	(and:QI (not:QI (match_operand:QI 1 "register_operand" "0"))
		(match_operand:QI 2 "nonmemory_operand" "rJ")))]
  ""
  "not.b	%X0\;and.b	%X2,%X0"
  [(set_attr "length" "4")
   (set_attr "cc" "clobber")])

(define_insn ""
  [(set (match_operand:HI 0 "register_operand" "=r")
	(and:HI (not:HI (match_operand:HI 1 "register_operand" "0"))
		(match_operand:HI 2 "nonmemory_operand" "rJ")))]
  "TARGET_H8300H"
  "not.w	%T0\;and.w	%T2,%T0"
  [(set_attr "length" "4")
   (set_attr "cc" "clobber")])

(define_insn ""
  [(set (match_operand:SI 0 "register_operand" "=r")
	(and:SI (not:SI (match_operand:SI 1 "register_operand" "0"))
		(match_operand:QI 2 "nonmemory_operand" "rJ")))]
  "TARGET_H8300H"
  "not.l	%S0\;and.l	%S2,%S0"
  [(set_attr "length" "4")
   (set_attr "cc" "clobber")])

