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

;; Some move patterns have conditions which check that one operand
;; is a register.  Shouldn't all of them have such a condition?

;; Consistently use "a" constraint.  Probably makes little difference
;; in the generated code, but it's easy to do.

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


(define_attr "type" "branch,bcs,return,call,arith,move,float,multi"
  (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))))
	 (eq_attr "type" "move")	(const_int 4)
	 (eq_attr "type" "return")	(const_int 2)
	 (eq_attr "type" "float")	(const_int 12)
	 (eq_attr "type" "call")	(const_int 4)]
	(const_int 200)))

;; 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 "type" "move")
   (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 "type" "move")
   (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 "type" "move")
   (set_attr_alternative "length"
     [(const_int 2) (const_int 2)
      (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))])
   (set_attr "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" "ra"))]
  ""
  "*
{
  if (TARGET_H8300)
    return \"push.w	%T1\";
  else
    return \"push.l	%S1\";
}"
  [(set_attr "type" "move")
   (set (attr "length") (if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4)))
   (set_attr "cc" "set")])

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

(define_insn "movsi_h8300h"
  [(set (match_operand:SI 0 "general_operand_dst" "=ra,ra,ra,o,<,ra")
	(match_operand:SI 1 "general_operand_src" "I,ra,ion,ra,ra,>"))]
  "TARGET_H8300H
   && (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 "type" "move")
   (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 "type" "move")
   (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 "type" "arith")
   (set_attr "length" "2")
   (set_attr "cc" "set_zn_c0")])
  
(define_insn "tstqi"
  [(set (cc0) (match_operand:QI 0 "general_operand" "ra"))]
  ""
  "mov.b	%X0,%X0"
  [(set_attr "type" "arith")
   (set_attr "length" "2")
   (set_attr "cc" "set")])

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

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

(define_insn "cmpqi"
  [(set (cc0)
	(compare:QI (match_operand:QI 0 "register_operand" "ra")
		    (match_operand:QI 1 "nonmemory_operand" "rai")))]
  ""
  "cmp.b	%X1,%X0"
  [(set_attr "type" "arith")
   (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" "ra")
		    (match_operand:HI 1 "register_operand" "ra")))]
  "!TARGET_H8300H"
  "cmp.w	%T1,%T0"
  [(set_attr "type" "arith")
   (set_attr "length" "2")
   (set_attr "cc" "compare")])

(define_insn ""
  [(set (cc0)
	(compare:HI (match_operand:HI 0 "register_operand" "ra")
		    (match_operand:HI 1 "nonmemory_operand" "rai")))]
  "TARGET_H8300H"
  "cmp.w	%T1,%T0"
  [(set_attr "type" "arith")
   (set_attr "length" "2")
   (set_attr "cc" "compare")])

(define_insn "cmpsi"
  [(set (cc0)
	(compare:SI (match_operand:SI 0 "register_operand" "ra")
		    (match_operand:SI 1 "nonmemory_operand" "rai")))]
  "TARGET_H8300H"
  "cmp.l	%S1,%S0"
  [(set_attr "type" "arith")
   (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 "type" "arith")
   (set_attr "length" "2")
   (set_attr "cc" "set_zn_c0")])

;; h8300h: adds operates on the 32bit register.  We can use it because we don't
;; use the e0-7 registers.

(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" "=ra")
	(plus:HI (match_operand:HI 1 "register_operand" "%0")
		 (match_operand:HI 2 "adds_subs_operand" "i")))]
  ""
  "* return output_adds_subs (operands);"
  [(set_attr "type" "arith")
   (set_attr "length" "4")
   (set_attr "cc" "none_0hit")])

(define_insn ""
  [(set (match_operand:HI 0 "register_operand" "=&ra,ra")
	(plus:HI (match_operand:HI 1 "register_operand" "%0,0")
		 (match_operand:HI 2 "nonmemory_operand" "n,ra")))]
  "TARGET_H8300"
  "@
   add.b	%s2,%s0\;addx	%t2,%t0 
   add.w	%T2,%T0"
  [(set_attr "type" "multi,arith")
   (set_attr "length" "4,2")
   (set_attr "cc" "clobber,set_zn_c0")])

(define_insn ""
  [(set (match_operand:HI 0 "register_operand" "=ra,ra")
	(plus:HI (match_operand:HI 1 "register_operand" "%0,0")
		 (match_operand:HI 2 "nonmemory_operand" "i,ra")))]
  "TARGET_H8300H"
  "@
   add.w	%T2,%T0
   add.w	%T2,%T0"
  [(set_attr "type" "arith,arith")
   (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" "=ra")
	(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 "type" "arith")
   (set_attr "length" "4")
   (set_attr "cc" "none_0hit")])

(define_insn "addsi_h8300"
  [(set (match_operand:SI 0 "register_operand" "=ra,ra,&ra")
	(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 "type" "arith")
   (set_attr "length" "8,6,20")
   (set_attr "cc" "clobber")])

(define_insn "addsi_h8300h"
  [(set (match_operand:SI 0 "register_operand" "=ra,ra")
	(plus:SI (match_operand:SI 1 "register_operand" "%0,0")
		 (match_operand:SI 2 "nonmemory_operand" "i,ra")))]
  "TARGET_H8300H"
  "@
   add.l	%S2,%S0
   add.l	%S2,%S0"
  [(set_attr "type" "arith,arith")
   (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 "type" "arith")
   (set_attr "length" "2")
   (set_attr "cc" "set_zn_c0")])

;; h8300h: subs operates on the 32bit register.  We can use it because we don't
;; use the e0-7 registers.

(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" "=ra")
	(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 "type" "arith")
   (set_attr "length" "4")
   (set_attr "cc" "none_0hit")])

(define_insn ""
  [(set (match_operand:HI 0 "register_operand" "=ra,&ra")
	(minus:HI (match_operand:HI 1 "general_operand" "0,0")
		  (match_operand:HI 2 "nonmemory_operand" "ra,n")))]
  "TARGET_H8300"
  "@
   sub.w	%T2,%T0
   add.b	%E2,%s0\;addx	%F2,%t0 ; -%0"
  [(set_attr "type" "arith,multi")
   (set_attr "length" "2,4")
   (set_attr "cc" "set_zn_c0,clobber")])

(define_insn ""
  [(set (match_operand:HI 0 "register_operand" "=ra,&ra")
	(minus:HI (match_operand:HI 1 "general_operand" "0,0")
		  (match_operand:HI 2 "nonmemory_operand" "ra,i")))]
  "TARGET_H8300H"
  "@
   sub.w	%T2,%T0
   sub.w	%T2,%T0"
  [(set_attr "type" "arith")
   (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 "type" "arith")
   (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" "=ra")
	(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 "type" "arith")
   (set_attr "length" "4")
   (set_attr "cc" "none_0hit")])

(define_insn "subsi3_h8300h"
  [(set (match_operand:SI 0 "register_operand" "=ra,ra")
	(minus:SI (match_operand:SI 1 "general_operand" "0,0")
		  (match_operand:SI 2 "nonmemory_operand" "ra,i")))]
  "TARGET_H8300H"
  "@
   sub.l	%S2,%S0
   sub.l	%S2,%S0"
  [(set_attr "type" "arith")
   (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 "type" "multi")
   (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 "type" "multi")
   (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 "type" "multi")
   (set_attr "length" "2")
   (set_attr "cc" "none_0hit")])

(define_insn "umulhisi3"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(mult:SI (zero_extend:SI (match_operand:HI 1 "general_operand" "%0"))
		 (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
  "TARGET_H8300H"
  "mulxu.w	%T2,%S0"
  [(set_attr "type" "multi")
   (set_attr "length" "2")
   (set_attr "cc" "none_0hit")])

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

(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 "type" "multi")
   (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 "type" "multi")
   (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 "type" "multi")
   (set_attr "length" "2")
   (set_attr "cc" "clobber")])

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

;; ----------------------------------------------------------------------
;; 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 "type" "multi")
   (set_attr "length" "4")
   (set_attr "cc" "clobber")])

(define_insn "modqi3"
  [(set (match_operand:QI 0 "register_operand" "=r")
	(mod:QI (match_operand:HI 1 "general_operand" "0")
		(match_operand:QI 2 "register_operand" "r")))]
  "TARGET_H8300H"
  "divxs.b	%X2,%T0\;mov %t0,%s0"
  [(set_attr "type" "multi")
   (set_attr "length" "6")
   (set_attr "cc" "clobber")])

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

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

(define_insn "andqi3_internal"
  [(set (match_operand:QI 0 "bit_operand" "=r,U")
	(and:QI (match_operand:QI 1 "bit_operand" "%0,0")
		(match_operand:QI 2 "nonmemory_operand" "rn,O")))]
  "register_operand (operands[0], QImode) || o_operand (operands[2], QImode)"
  "@
   and	%X2,%X0
   bclr	%W2,%R0"
  [(set_attr "type" "arith")
   (set_attr "length" "2,4")
   (set_attr "cc" "set,none_0hit")])

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

;; ??? Should have a bclr case here also.
;; ??? This should be symmetric with iorhi3.

(define_insn "andhi3"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(and:HI (match_operand:HI 1 "register_operand" "%0")
		(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 \"\";
    }
  return \"and	%s2,%s0\;and	%t2,%t0;\";
}"
  [(set_attr "type" "multi")
   (set_attr "length" "4")
   (set_attr "cc" "clobber")])

;; ??? There is an iorsi3 for TARGET_H8300.  Should we have andsi3?

(define_insn "andsi3"
  [(set (match_operand:SI 0 "register_operand" "=r,r")
	(and:SI (match_operand:SI 1 "register_operand" "%0,0")
		(match_operand:SI 2 "nonmemory_operand" "r,i")))]
  "TARGET_H8300H"
  "@
   and	%S2,%S0
   and	%S2,%S0"
  [(set_attr "type" "arith")
   (set_attr "length" "4,6")
   (set_attr "cc" "set")])

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

(define_insn "iorqi3_internal"
  [(set (match_operand:QI 0 "bit_operand" "=U,r")
	(ior:QI (match_operand:QI 1 "bit_operand" "%0,0")
		(match_operand:QI 2 "nonmemory_operand" "P,rn")))]
  "register_operand (operands[0], QImode) || p_operand (operands[2], QImode)"
  "@
   bset	%V2,%R0
   or	%X2,%X0"
  [(set_attr "type" "arith")
   (set_attr "length" "4,2")
   (set_attr "cc" "none_0hit,set")])

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

;; ??? Should have a bset case here also.
;; ??? This should be symmetric with andhi3.

(define_insn "iorhi3"
  [(set (match_operand:HI 0 "general_operand" "=r,r")
	(ior:HI (match_operand:HI 1 "general_operand" "%0,0")
		(match_operand:HI 2 "general_operand" "J,rn")))]
  ""
  "*
{
  if (TARGET_H8300)
    {
      if (GET_CODE (operands[2]) == CONST_INT)
	{
	  int i = INTVAL (operands[2]);
	  if ((i & 0x00ff) != 0) 
	    output_asm_insn (\"or	%s2,%s0\", operands);
	  if ((i & 0xff00) != 0) 
	    output_asm_insn (\"or	%t2,%t0\", operands);
	  return \"\";
	}
      return \"or	%s2,%s0\;or	%t2,%t0; %2 or2\";
    }
  else
    {
      return \"or	%S2,%S0\";
    }
}"
  [(set_attr "type" "multi")
   (set_attr "length" "2,4")
   (set_attr "cc" "clobber,clobber")])

(define_insn "iorsi3"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(ior:SI (match_operand:SI 1 "register_operand" "%0")
		(match_operand:SI 2 "nonmemory_operand" "ri")))]
  ""
  "*
{
  if (TARGET_H8300)
    {
      if (GET_CODE (operands[2]) == CONST_INT)
	{
	  int i = INTVAL (operands[2]);
	  if ((i & 0x000000ff) != 0) 
	    output_asm_insn (\"or	%w2,%w0\", operands);
	  if ((i & 0x0000ff00) != 0) 
	    output_asm_insn (\"or	%x2,%x0\", operands);
	  if ((i & 0x00ff0000) != 0) 
	    output_asm_insn (\"or	%y2,%y0\", operands);
	  if ((i & 0xff000000) != 0) 
	    output_asm_insn (\"or	%z2,%z0\", operands);
	  return \"\";
	}
      return \"or	%w2,%w0\;or	%x2,%x0\;or	%y2,%y0\;or	%z2,%z0\;\";
    }
  else
    {
      return \"or	%S2,%S0\";
    }
}"
  [(set_attr "type" "multi")
   (set_attr "length" "8")
   (set_attr "cc" "clobber")])

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

(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 "type" "arith")
   (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;
}")

;; ??? This should be symmetric with andhi3.

(define_insn "xorhi3"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(xor:HI (match_operand:HI 1 "general_operand" "%0")
		(match_operand:HI 2 "nonmemory_operand" "rn")))]
  ""
  "*
{
  if (TARGET_H8300)
    return \"xor	%s2,%s0\;xor	%t2,%t0\";
  else
    return \"xor	%S2,%S0\";
}"
  [(set_attr "type" "multi")
   (set_attr "length" "4")
   (set_attr "cc" "clobber")])

;; ??? There is an iorsi3 for TARGET_H8300.  Should we have xorsi3?

(define_insn "xorsi3"
  [(set (match_operand:SI 0 "register_operand" "=r,r")
	(xor:SI (match_operand:SI 1 "register_operand" "%0,0")
		(match_operand:SI 2 "nonmemory_operand" "r,i")))]
  "TARGET_H8300H"
  "@
   xor	%S2,%S0
   xor	%S2,%S0"
  [(set_attr "type" "arith")
   (set_attr "length" "4,6")
   (set_attr "cc" "set")])

;; ----------------------------------------------------------------------
;; 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 "type" "arith")
   (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 "type" "arith")
   (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 "type" "arith")
   (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 "type" "arith")
   (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 "type" "arith")
   (set_attr "length" "4")
   (set_attr "cc" "clobber")])

(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 "type" "arith")
   (set_attr "cc" "clobber")
   (set (attr "length")
	(if_then_else (eq (symbol_ref "TARGET_H8300H") (const_int 0))
		      (const_int 8)
		      (const_int 4)))])
			

;; ----------------------------------------------------------------------
;; 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 "type" "branch")
   (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 "type" "branch")
   (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 "type" "branch")
   (set_attr "cc" "none")
   (set_attr "length" "2")])

(define_insn "indirect_jump_h8300h"
  [(set (pc) (match_operand:SI 0 "jump_address_operand" "V,r"))]
  "TARGET_H8300H"
  "@
   jmp @%0
   jmp @%0"
  [(set_attr "type" "branch")
   (set_attr "cc" "none")
   (set_attr "length" "2")])

;; Call subroutine with no return value.

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

(define_insn "call"
  [(call (match_operand:QI 0 "call_insn_operand" "or")
	 (match_operand:HI 1 "general_operand" "g"))]
  ""
  "*
{
  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 "type" "call")
   (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 "type" "call")
   (set_attr "cc" "clobber")
   (set (attr "length")
     (if_then_else (match_operand:QI 0 "small_call_insn_operand" "")
		   (const_int 4)
		   (const_int 8)))])

(define_insn "nop"
  [(const_int 0)]
  ""
  "nop"
  [(set_attr "type" "multi")
   (set_attr "cc" "none")
   (set_attr "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" "0,g")))]
  ""
  "*
{
  if (which_alternative==0)
    return \"mov.b	#0,%t0\";

  if (TARGET_H8300)
    return \"mov.b	%R1,%s0\;mov.b	#0,%t0\";
  else
    {
      /* ??? See how often this gets optimized.  */
      if (REG_P (operands[1]) && (REGNO (operands[1]) == REGNO (operands[0])))
	return \"extu.w	%T0\";
      else
	return \"mov.b	%R1,%s0\;extu.w	%T0\";
    }
}"
  [(set_attr "type" "multi")
;; ??? This length is wrong for one case.
   (set_attr "length" "4")
   (set_attr "cc" "clobber")])

(define_insn "zero_extendhisi2"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(zero_extend:SI (match_operand:HI 1 "general_operand" "g")))]
  "TARGET_H8300H"
  "*
{
  /* ??? See how often this gets optimized.  */
  if (REG_P (operands[1]) && (REGNO (operands[1]) == REGNO (operands[0])))
    return \"extu.l	%S0\";
  else
    return \"mov.w	%T1,%T0\;extu.l	%S0\";
}"
  [(set_attr "type" "multi")
;; ??? This length is wrong for one case.
   (set_attr "length" "4")
   (set_attr "cc" "clobber")])

(define_insn "extendqihi2"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(sign_extend:HI (match_operand:QI 1 "general_operand" "g")))]
  ""
  "*
{
  if (TARGET_H8300)
    {
      /* ??? See how often this gets optimized.  */
      if (REG_P (operands[1]) && (REGNO (operands[1]) == REGNO (operands[0])))
	return \"bld	#7,%s0\;subx	%t0,%t0\";
      else
	return \"mov.b	%R1,%s0\;bld	#7,%s0\;subx	%t0,%t0\";
    }
  else
    {
      /* ??? See how often this gets optimized.  */
      if (REG_P (operands[1]) && (REGNO (operands[1]) == REGNO (operands[0])))
	return \"exts.w	%T0\";
      else
	return \"mov.b	%R1,%s0\;exts.w	%T0\";
    }
}"
  [(set_attr "type" "multi")
;; ??? Length is wrong in some cases.
   (set_attr "length" "6")
   (set_attr "cc" "clobber")])

(define_expand "extendhisi2"
  [(set (match_operand:SI 0 "register_operand" "")
	(sign_extend:SI (match_operand:HI 1 "general_operand" "")))]
  ""
  "
{
  if (TARGET_H8300)
    emit_insn (gen_extendhisi2_h8300 (operands[0], operands[1]));
  else
    emit_insn (gen_extendhisi2_h8300h (operands[0], operands[1]));
  DONE;
}")

(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_expand "extendhisi2_h8300h"
  [(set (match_operand:SI 0 "register_operand" "")
	(sign_extend:SI (match_operand:HI 1 "general_operand" "")))]
  "TARGET_H8300H"
  "")

(define_insn "extendhisi2_h8300_internal"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(sign_extend:SI (match_operand:HI 1 "register_operand" "0")))]
  "TARGET_H8300"
  "mov.w	%T1,%f0\;bld	#7,%x0\;subx	%y0,%y0\;subx	%z0,%z0"
  [(set_attr "length" "10")
   (set_attr "cc" "clobber")])

(define_insn "extendhisi2_h8300h_internal"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(sign_extend:SI (match_operand:HI 1 "general_operand" "g")))]
  "TARGET_H8300H"
  "*
{
  /* ??? See how often this gets optimized.  */
  if (REG_P (operands[1]) && (REGNO (operands[1]) == REGNO (operands[0])))
    return \"exts.l	%S0\";
  else
    return \"mov.w	%T1,%T0\;exts.l	%S0\";
}"
  [(set_attr "length" "10")
   (set_attr "cc" "clobber")])

;; ----------------------------------------------------------------------
;; 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 "type" "arith")
   (set_attr "length" "20")
;; ??? We'd like to indicate that cc is set here, and it is for simple shifts.
;; However, for cases that loop or are done in pieces, cc does not contain
;; what we want.  Emit_a_shift is free to tweak cc_status as desired.
   (set_attr "cc" "clobber")])

;; 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_src" "")
		     (match_operand:QI 2 "nonmemory_operand" "")))]
  ""
  "if (expand_a_shift (HImode, LSHIFTRT, operands)) DONE;else FAIL;")

(define_expand "ashrhi3"
  [(set (match_operand:HI 0 "register_operand" "")
	(ashiftrt:HI (match_operand:HI 1 "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 "type" "arith")
   (set_attr "length" "20")
;; ??? We'd like to indicate that cc is set here, and it is for simple shifts.
;; However, for cases that loop or are done in pieces, cc does not contain
;; what we want.  Emit_a_shift is free to tweak cc_status as desired.
   (set_attr "cc" "clobber")])

;;  SI BIT SHIFTS

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

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

(define_expand "ashrsi3"
  [(set (match_operand:SI 0 "register_operand" "")
	(ashiftrt:SI
	 (match_operand:SI 1 "general_operand_src" "")
	 (match_operand: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 "type" "arith")
   (set_attr "length" "20")
;; ??? We'd like to indicate that cc is set here, and it is for simple shifts.
;; However, for cases that loop or are done in pieces, cc does not contain
;; what we want.  Emit_a_shift is free to tweak cc_status as desired.
   (set_attr "cc" "clobber")])

;; -----------------------------------------------------------------
;; 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 "bcs_qiqi"
  [(set (pc)
	(if_then_else 
	 (match_operator 1 "eq_operator"
			 [(zero_extract:QI (match_operand:QI 2 "bit_operand" "Ur")
					   (const_int 1)
					   (match_operand:HI 3 "immediate_operand" "i"))
			  (const_int 0)])
	 (label_ref (match_operand 0 "" ""))
	 (pc)))]
  ""
  "*
{
  /* 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], QImode))
    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 "bcs_hihi"
  [(set (pc)
	(if_then_else 
	 (match_operator 1 "eq_operator"
			 [(zero_extract:HI (match_operand:HI 2 "bit_operand" "Ur")
					   (const_int 1)
					   (match_operand:HI 3 "immediate_operand" "i"))
			  (const_int 0)])
	 (label_ref (match_operand 0 "" ""))
	 (pc)))]
  ""
  "*
{
  /* 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], QImode))
    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 "bcs_hiqi"
  [(set (pc)
	(if_then_else 
	 (match_operator 1 "eq_operator"
			 [(zero_extract:HI (match_operand:QI 2 "bit_operand" "Ur")
					   (const_int 1)
					   (match_operand:HI 3 "immediate_operand" "i"))
			  (const_int 0)])
	 (label_ref (match_operand 0 "" ""))
	 (pc)))]
  ""
  "*
{
  /* 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], QImode))
    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")])

;; BLD and BST patterns

(define_insn "extract_1"
  [(set (match_operand:HI 0 "register_operand" "=&r")
	(zero_extract:HI (match_operand:QI 1 "bit_operand" "Ur")
			 (const_int 1)
			 (match_operand:HI 2 "immediate_operand" "i")))]
  ""
  "sub.w	%0,%0\;bld	%Z2,%Y1\;bst	#0,%X0")

(define_insn "extract_1_hi"
  [(set (match_operand:HI 0 "register_operand" "=&r")
	(zero_extract:HI (match_operand:HI 1 "bit_operand" "Ur")
			 (const_int 1)
			 (match_operand:HI 2 "immediate_operand" "i")))]
  ""
  "sub.w	%0,%0\;bld	%Z2,%Y1\;bst	#0,%X0")

(define_insn "insert_1"
  [(set (zero_extract:HI (match_operand:QI 0 "bit_operand" "+Ur")
			 (const_int 1)
			 (match_operand:HI 1 "immediate_operand" "i"))
	(zero_extract:HI (match_operand:QI 2 "bit_operand" "Ur")
			 (const_int 1)
			 (const_int 0)))]
  ""
  "bld	#0,%R2\;bst	%Z1,%Y0 ; i1")

;; This is how combine canonicalizes this pattern.  This is perhaps a bug
;; in combine.c, but there is no problem with writing it this way so we do.
(define_insn "extract_insert_1"
  [(set (zero_extract:QI (match_operand:QI 0 "bit_operand" "+Ur")
			 (const_int 1)
			 (match_operand:HI 1 "immediate_operand" "i"))
	(lshiftrt:QI (match_operand:QI 2 "bit_operand" "Ur")
		     (match_operand:HI 3 "immediate_operand" "i")))]
 ""
 "bld	%Z3,%Y2\;bst	%Z1,%Y0; ei1")

;; BAND, BOR, and BXOR patterns

(define_insn "bitlogical_1"
  [(set (match_operand:HI 0 "bit_operand" "=Ur")
	(match_operator:HI 4 "bit_operator"
	   [(zero_extract:HI (match_operand:QI 1 "bit_operand" "Ur")
			     (const_int 1)
			     (match_operand:HI 2 "immediate_operand" "i"))
	    (match_operand:HI 3 "bit_operand" "0")]))]
  ""
  "bld	%Z2,%Y1\;%b4	#0,%R0\;bst	#0,%R0; bl1")

(define_insn "bitlogical_1_hi"
  [(set (match_operand:HI 0 "bit_operand" "=Ur")
	(match_operator:HI 4 "bit_operator"
	   [(zero_extract:HI (match_operand:HI 1 "bit_operand" "Ur")
			     (const_int 1)
			     (match_operand:HI 2 "immediate_operand" "i"))
	    (match_operand:HI 3 "bit_operand" "0")]))]
  ""
  "bld	%Z2,%Y1\;%b4	#0,%R0\;bst	#0,%R0; bl2")

(define_insn "bitlogical_2"
  [(set (match_operand:HI 0 "bit_operand" "=Ur")
	(match_operator:HI 5 "bit_operator"
	   [(zero_extract:HI (match_operand:QI 1 "bit_operand" "Ur")
			     (const_int 1)
			     (match_operand:HI 2 "immediate_operand" "i"))
	    (zero_extract:HI (match_operand:QI 3 "bit_operand" "Ur")
			     (const_int 1)
			     (match_operand:HI 4 "immediate_operand" "i"))]))]
  ""
  "bld	%Z2,%Y1\;%b5	%Z4,%Y3\;bst	#0,%R0; bl3")

(define_insn "bitlogical_2_hi"
  [(set (match_operand:HI 0 "bit_operand" "=Ur")
	(match_operator:HI 5 "bit_operator"
	   [(zero_extract:HI (match_operand:HI 1 "bit_operand" "Ur")
			     (const_int 1)
			     (match_operand:HI 2 "immediate_operand" "i"))
	    (zero_extract:HI (match_operand:HI 3 "bit_operand" "Ur")
			     (const_int 1)
			     (match_operand:HI 4 "immediate_operand" "i"))]))]
  ""
  "bld	%Z2,%Y1\;%b5	%Z4,%Y3\;bst	#0,%R0; bl3")

;; This is how combine canonicalizes this pattern.  This is perhaps a bug
;; in combine.c, but there is no problem with writing it this way so we do.
(define_insn "bitlogical_3"
  [(set (zero_extract:QI (match_operand:QI 0 "bit_operand" "+Ur")
			 (const_int 1)
			 (match_operand:HI 1 "immediate_operand" "i"))
	(match_operator:QI 6 "bit_operator"
	   [(lshiftrt:QI (match_operand:QI 2 "bit_operand" "Ur")
			 (match_operand:HI 3 "immediate_operand" "i"))
	    (lshiftrt:QI (match_operand:QI 4 "bit_operand" "Ur")
			 (match_operand:HI 5 "immediate_operand" "i"))]))]
  ""
  "bld	%Z3,%Y2\;%b6	%Z5,%Y4\;bst	%Z1,%Y0; bl5")
						     
;; This is how combine canonicalizes this pattern.  This is perhaps a bug
;; in combine.c, but there is no problem with writing it this way so we do.
(define_insn "bitnot_1"
  [(set (zero_extract:QI (match_operand:QI 0 "bit_operand" "=Ur")
			 (const_int 1)
			 (match_operand:HI 1 "immediate_operand" "i"))
	(lshiftrt:QI (xor:QI (match_operand:QI 2 "bit_operand" "0")
			     (match_operand:HI 3 "immediate_operand" "i"))
		     (match_operand:HI 4 "immediate_operand" "1")))]
  "GET_CODE (operands[3]) == CONST_INT && GET_CODE (operands[1]) == CONST_INT
   && exact_log2 (INTVAL (operands[3])) == INTVAL (operands[1])"
  "bnot	%Z1,%Y0")

;; ??? Implement BIAND, BIOR, BIXOR

;; ??? Implement BILD, BIST

;; ??? Apparently general_operand for the 1st and 2nd operands is useful,
;; but I don't know why.  --Jim

(define_expand "insv"
  [(set (zero_extract:HI (match_operand:QI 0 "bit_operand" "Ur")
			 (match_operand:HI 1 "general_operand" "g")
			 (match_operand:HI 2 "general_operand" "g"))
	(zero_extract:HI (match_operand:QI 3 "bit_operand" "Ur")
			 (const_int 1)
			 (const_int 0)))]
;; ??? This should have word mode which is SImode for the h8/300h.
  "TARGET_H8300"
  "
{
  if (INTVAL (operands[1]) != 1)
    FAIL;

  /* ??? HACK ???
     This INSV pattern is wrong.  It should use HImode for operand 3.
     Also, the zero_extract around operand 3 is superfluous and should be
     deleted.  Fixing this is more work than we care to do for the moment,
     because it means most of the above patterns would need to be rewritten,
     and we also need more combine.c patches to make this work.

     So, for now, we work around this bug by simply not accepting any bitfield
     inserts that have a position greater than fits in QImode.  */

  if (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) >= 8)
    FAIL;

  /* The bit_operand predicate accepts any memory during RTL generation, but
     only 'U' memory afterwards, so if this is a MEM operand, we must force
     it to be valid for 'U' by reloading the address.  */

  if (GET_CODE (operands[0]) == MEM && ! EXTRA_CONSTRAINT (operands[0], 'U'))
    {
      rtx mem;
      mem = gen_rtx (MEM, GET_MODE (operands[0]),
		     copy_to_mode_reg (Pmode, XEXP (operands[0], 0)));
      RTX_UNCHANGING_P (mem) = RTX_UNCHANGING_P (operands[0]);
      MEM_IN_STRUCT_P (mem) = MEM_IN_STRUCT_P (operands[0]);
      MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[0]);
      operands[0] = mem;
    }

  /* Likewise for operands[3].  */

  if (GET_CODE (operands[3]) == MEM && ! EXTRA_CONSTRAINT (operands[3], 'U'))
    {
      rtx mem;
      mem = gen_rtx (MEM, GET_MODE (operands[3]),
		     copy_to_mode_reg (Pmode, XEXP (operands[3], 0)));
      RTX_UNCHANGING_P (mem) = RTX_UNCHANGING_P (operands[3]);
      MEM_IN_STRUCT_P (mem) = MEM_IN_STRUCT_P (operands[3]);
      MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[3]);
      operands[3] = mem;
    }
}")

;; ??? Apparently general_operand for the 2nd and 3rd operands is useful,
;; but I don't know why.  --Jim

(define_expand "extzv"
  [(set (match_operand:HI 0 "register_operand" "") 
	(zero_extract:HI (match_operand:QI 1 "bit_operand" "")
			 (match_operand:HI 2 "general_operand" "g")
			 (match_operand:HI 3 "general_operand" "g")))]
;; ??? This should have word mode which is SImode for the h8/300h.
  "TARGET_H8300"
  "
{
  if (INTVAL (operands[2]) != 1)
    FAIL;

  /* The bit_operand predicate accepts any memory during RTL generation, but
     only 'U' memory afterwards, so if this is a MEM operand, we must force
     it to be valid for 'U' by reloading the address.  */

  if (GET_CODE (operands[1]) == MEM && ! EXTRA_CONSTRAINT (operands[1], 'U'))
    {
      rtx mem;
      mem = gen_rtx (MEM, GET_MODE (operands[1]),
		     copy_to_mode_reg (Pmode, XEXP (operands[1], 0)));
      RTX_UNCHANGING_P (mem) = RTX_UNCHANGING_P (operands[1]);
      MEM_IN_STRUCT_P (mem) = MEM_IN_STRUCT_P (operands[1]);
      MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[1]);
      operands[1] = mem;
    }
}")

;; -----------------------------------------------------------------
;; STACK POINTER MANIPULATIONS
;; -----------------------------------------------------------------

;; This pattern is needed because there is no way on the H8/300
;; to add a 16 bit immediate value to the stack pointer in one 
;; instruction, which could leave an invalid instruction if interrupted
;; half way through.  Here we add to the stack pointer from a
;; register.

(define_insn "stack_pointer_manip"
  [(set (match_operand:HI 0 "register_operand" "=&ra")
	(plus:HI (match_operand:HI 1 "general_operand_src" "g")
		 (match_operand:HI 2 "register_operand" "ra")))]
  "TARGET_H8300"
  "mov.w	%T1,%T0\;add.w	%T2,%T0"
  [(set_attr "type" "arith")
   (set_attr "length" "6")
   (set_attr "cc" "set_zn_c0")])


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

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

;; Notice a move which could be post incremented.

(define_peephole 
  [(set (match_operand: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 ""
;  [(set (match_operand:HI 0 "register_operand" "=r")
;	(MEM:HI (match_operand:HI 1 "register_operand" "r")))
;   (set (match_operand:HI 3 "register_operand" "=r")
;	(zero_extract:HI (match_dup 0)
;			 (const_int 1)
;			 (match_operand:HI 2 "general_operand" "g")))
;   (set (MEM:HI (match_dup 1) (match_dup 3)))]
;  ""
;  "bld	#0,%3l\;bst	%Z2,%0%Y1"
;  [(set_attr "type" "multi")
;   (set_attr "length" "4")
;   (set_attr "cc" "clobber")])

(define_insn "fancybset1"
  [(set (match_operand:QI 0 "bit_operand" "=Ur")
	(ior:QI (subreg:QI 
		 (ashift:HI (const_int 1)
			    (subreg:QI (match_operand:HI 1 "register_operand" "ri") 0)) 0)
		(match_dup 0)))]
  ""
  "bset	%X1,%R0")	

(define_insn "fancybset"
  [(set (match_operand:QI 0 "bit_operand" "=Ur")
	(ior:QI (subreg:QI 
		 (ashift:HI (const_int 1)
			    (match_operand:HI 1 "nonmemory_operand" "ri") ) 0)
		(match_operand:QI 2 "general_operand" "Ur")))]
  ""
  "mov.b	%R2,%R0\;bset	%X1,%R0")	

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

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

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

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

(define_insn "fancybclr"
  [(set (match_operand:QI 0 "general_operand" "=r")
	(and:QI (not:QI (match_operand:QI 1 "general_operand" "0"))
		(match_operand:QI 2 "general_operand" "r")))]
  ""
  "not	%X0\;and	%X2,%X0")

(define_insn "fancybsetp3"
  [(set (match_operand:QI 0 "bit_operand" "=Ur")
	(ior:QI (subreg:QI (ashift:HI (const_int 1)
				      (match_operand:QI 1 "register_operand" "r")) 0)
		(match_operand:QI 2 "bit_operand" "0")))]
  ""
  "bset	%X1,%R0")

(define_insn "fancybsetp2"
  [(set (match_operand:QI 0 "general_operand" "=r,U")
	(ior:QI (subreg:QI (ashift:HI (const_int 1)
				      (match_operand:QI 1 "register_operand" "r,r")) 0)
		(match_operand:QI 2 "general_operand" "U,r")))]
  ""
  "mov.b	%R2,%R0\;bset	%X1,%R0")
	
(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")

(define_insn "fancy_btst"
  [(set (pc)
	(if_then_else (eq (zero_extract:HI (zero_extend:HI (match_operand:QI 1 "general_operand" "Ur"))
					   (const_int 1)
					   (match_operand:HI 2 "nonmemory_operand" "rn"))
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "*
{
  if (get_attr_length (insn) == 2)
    return \"btst	%X2,%R1\;beq	%l0\";
  else if (get_attr_length (insn) == 4)
    return \"btst	%X2,%R1\;beq	%l0:16\";
  else
    return \"btst	%X2,%R1\;bne	%L1\;jmp	@%l0\;%L1:\";
}"
  [(set_attr "type" "branch")
   (set_attr "cc" "clobber")])

(define_insn "fancy_btst1"
  [(set (pc)
	(if_then_else (ne (zero_extract:HI (zero_extend:HI (match_operand:QI 1 "general_operand" "Ur"))
					   (const_int 1)
					   (match_operand:HI 2 "nonmemory_operand" "rn"))
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "*
{
  if (get_attr_length (insn) == 2)
    return \"btst	%X2,%R1\;bne	%l0\";
  else if (get_attr_length (insn) == 4)
    return \"btst	%X2,%R1\;bne	%l0:16\";
  else
    return \"btst	%X2,%R1\;beq	%L1\;jmp	@%l0\;%L1:\";
}"
  [(set_attr "type" "branch")
   (set_attr "cc" "clobber")])

(define_insn "pxor"
  [(set (zero_extract:QI (match_operand:QI 0 "bit_operand" "=r,U")
			 (const_int 1)
			 (match_operand 1 "immediate_operand" "n,n"))
	(and:QI (not:QI (match_operand:QI 2 "bit_operand" "r,U"))
			(const_int 1)))]
  ""
  "bld	#0,%R2\;bist	%1,%0"
  [(set_attr "type" "arith")
   (set_attr "length" "4")
   (set_attr "cc" "clobber")])
