;;- Machine description for the Hitachi H8/300 for the GNU C compiler
;;   Copyright (C) 1992, 1993 Free Software Foundation, Inc.

;; 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, 675 Mass Ave, Cambridge, MA 02139, 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 "type" "branch,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 -128))
			    (le (minus (pc) (match_dup 0))
				(const_int 128)))
		       (const_int 2)
		       (const_int 6))
	 (eq_attr "type" "move")	(const_int 4)
	 (eq_attr "type" "return")	(const_int 2)
	 (eq_attr "type" "float")	(const_int 12)
	 (eq_attr "type" "call")	(const_int 4)]
	(const_int 200)))


(define_attr "cc" "none,clobber,none_0hit,set,compare,whoops" 
  (const_string "whoops"))

;; ----------------------------------------------------------------------
;; move instructions
;; ----------------------------------------------------------------------

;; movhi

(define_insn ""
  [(set (match_operand:HI 0 "push_operand" "=<")
	(match_operand:HI 1 "register_operand" "ra"))]
  ""
  "mov.w	%T1,%T0"
  [(set_attr "type" "move")
   (set_attr "length" "2")
   (set_attr "cc" "set")])

(define_insn "movstricthi"
  [(set (strict_low_part (match_operand:HI 0 "general_operand_dst" "=r,r,r,o,<"))
	(match_operand:HI 1 "general_operand_src" "I,r,io,r,r"))]
  ""
  "@
   sub.w	%T0,%T0
   mov.w	%T1,%T0
   mov.w	%T1,%T0
   mov.w	%T1,%T0
   mov.w	%T1,%T0"
  [(set_attr "type" "move")
   (set_attr "length" "2,2,4,4,2")
   (set_attr "cc" "set")])

(define_insn ""
  [(set (match_operand:HI 0 "general_operand_dst" "=ra,ra,ra,o,<")
	(match_operand:HI 1 "general_operand_src" "I,ra,ion,ra,ra"))]
  ""
  "@
   sub.w	%T0,%T0
   mov.w	%T1,%T0
   mov.w	%T1,%T0
   mov.w	%T1,%T0
   mov.w	%T1,%T0"
  [(set_attr "type" "move")
   (set_attr "length" "2,2,4,4,2")
   (set_attr "cc" "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 ""
  [(set (match_operand:HI 0 "register_operand" "=&ra")
	(plus:HI (match_operand:HI 1 "general_operand_src" "g")
		 (match_operand:HI 2 "register_operand" "ra")))]
  ""
  "mov.w	%T1,%T0\;add.w	%T2,%T0"
  [(set_attr "type" "arith")
   (set_attr "length" "6")
   (set_attr "cc" "set")])

;; movqi

(define_insn ""
  [(set (match_operand:QI 0 "push_operand" "=<")
	(match_operand:QI 1 "register_operand" "r"))]
  ""
  "mov.w	%T1,%T0"
  [(set_attr "type" "move")
   (set_attr "length" "2")
   (set_attr "cc" "set")])

(define_insn "movstrictqi"
  [(set (strict_low_part (match_operand:QI 0 "general_operand_dst" "=r,r,r,o,<"))
	(match_operand:QI 1 "general_operand_src" "I,r,io,r,r"))]
  ""
  "@
   sub.b	%X0,%X0
   mov.b	%X1,%X0
   mov.b	%X1,%X0
   mov.b	%X1,%X0
   mov.b	%X1,%X0"
  [(set_attr "type" "move")
   (set_attr "length" "2,2,4,4,2")
   (set_attr "cc" "set")])

(define_insn ""
  [(set (match_operand:QI 0 "general_operand_dst" "=r,r,r,o,<")
	(match_operand:QI 1 "general_operand_src" "I,r,io,r,r"))]
  ""
  "@
   sub.b	%X0,%X0
   mov.b	%X1,%X0
   mov.b	%X1,%X0
   mov.b	%X1,%X0
   mov.b	%X1,%X0"
  [(set_attr "type" "move")
   (set_attr "length" "2,2,4,4,2")
   (set_attr "cc" "set")])

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

;; movsi

(define_insn ""
  [(set (match_operand:SI 0 "general_operand_dst" "=l,l,l,o,<")
	(match_operand:SI 1 "general_operand_src" "I,l,ion,l,l"))]
  ""
  "*
{
  int rn = -1;
  switch (which_alternative)
    {
    case 0:
      return \"sub.w	%e0,%e0\;sub.w	%f0,%f0\";
    case 1:
      return \"mov.w	%e1,%e0\;mov.w	%f1,%f0\";
    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\";
    }
}"
  [(set_attr "type" "move")
   (set_attr "length" "4,4,8,8,4")
   (set_attr "cc" "clobber")])

(define_insn ""
  [(set (match_operand:SI 0 "push_operand" "=<")
	(match_operand:SI 1 "register_operand" "l"))]
  ""
  "mov.w      %f1,%T0\;mov.w	%e1,%T0"
  [(set_attr "type" "move")
   (set_attr "length" "4")
   (set_attr "cc" "clobber")])

(define_expand "movsi"
  [(set (match_operand:SI 0 "general_operand_dst" "")
	(match_operand:SI 1 "general_operand_src" ""))]
  ""					
  "if (domovsi (operands)) DONE;")

(define_insn ""
  [(set (match_operand:SF 0 "general_operand_dst" "=l,l,l,o,<")
	(match_operand:SF 1 "general_operand_src" "I,l,ion,l,l"))]
  ""
  "*
{
  /* This is a copy of the movsi stuff.  */
  int rn = -1;
  switch (which_alternative)
    {
    case 0:
      return \"sub.w	%e0,%e0\;sub.w	%f0,%f0\";
    case 1:
      return \"mov.w	%e1,%e0\;mov.w	%f1,%f0\";
    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\";
   }
}"
  [(set_attr "type" "move")
   (set_attr "length" "4,4,8,8,4")
   (set_attr "cc" "clobber")])

(define_insn ""
  [(set (match_operand:SF 0 "push_operand" "=<")
	(match_operand:SF 1 "register_operand" "l"))]
  ""
  "mov.w      %f1,%T0\;mov.w	%e1,%T0"
  [(set_attr "type" "move")
   (set_attr "length" "4")
   (set_attr "cc" "clobber")])

(define_expand "movsf"
  [(set (match_operand:SF 0 "general_operand_dst" "")
	(match_operand:SF 1 "general_operand_src" ""))]
  ""					
  "if (domovsi (operands)) DONE;")

;; Block move

(define_expand "movstrhi"
  [(parallel [(set (mem:BLK (match_operand:BLK 0 "general_operand" ""))
		   (mem:BLK (match_operand:BLK 1 "general_operand" "")))
	      (use (match_operand:HI 2 "general_operand" ""))
	      (use (match_operand:HI 3 "immediate_operand" ""))
	      (clobber (match_dup 3))
	      ])]
  ""
  "
{
  rtx src_ptr = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
  rtx dst_ptr = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));

  enum machine_mode mode = INTVAL (operands[3]) >=2 ? HImode : QImode;
  rtx tmpreg = gen_reg_rtx (mode);
  rtx increment = mode == QImode  ? const1_rtx : const2_rtx;
  rtx length = operands[2];
  rtx label = gen_label_rtx ();
  rtx end_src_ptr = gen_reg_rtx (Pmode);

  emit_insn (gen_rtx (SET, VOIDmode, end_src_ptr,
		      gen_rtx (PLUS, Pmode, src_ptr, length)));

  emit_label (label);
  emit_move_insn (tmpreg, gen_rtx (MEM, mode, src_ptr));
  emit_move_insn (gen_rtx (MEM, mode, dst_ptr), tmpreg);
  emit_insn (gen_rtx (SET, VOIDmode, src_ptr,
		      gen_rtx (PLUS, Pmode, src_ptr, increment)));
  emit_insn (gen_rtx (SET, VOIDmode, dst_ptr,
		      gen_rtx (PLUS, Pmode, dst_ptr, increment)));

  emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx,
		      gen_rtx (COMPARE, HImode, src_ptr, end_src_ptr)));
  emit_jump_insn (gen_bne (label));

  DONE;	
}
")

;; ----------------------------------------------------------------------
;; Test instructions
;; ----------------------------------------------------------------------

(define_insn "tstqi"
  [(set (cc0)
	(match_operand:QI 0 "register_operand" "ra"))]
  ""
  "cmp.b	#0,%X0"
  [(set_attr "type" "arith")
   (set_attr "length" "2")
   (set_attr "cc" "set")])

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

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

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

(define_insn ""
  [(set (match_operand:HI 0 "register_operand" "=ra,ra,ra,ra,r,ra")
	(plus:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0,0")
		 (match_operand:HI 2 "nonmemory_operand" "K,M,L,N,n,ra")))]
  ""
  "@
   adds	%T2,%T0
   adds	#2,%T0\;adds	%C2,%T0
   subs	%M2,%T0
   subs	#2,%T0\;subs	%M2,%T0
   add.b	%s2,%s0\;addx	%t2,%t0 
   add.w	%T2,%T0"
  [(set_attr "type" "multi,multi,multi,multi,multi,arith")
   (set_attr "length" "2,4,2,4,4,2")
   (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,clobber,set")])

(define_expand "addhi3"
  [(set (match_operand:HI 0 "register_operand" "")
	(plus:HI (match_operand:HI 1 "register_operand" "")
		 (match_operand:HI 2 "nonmemory_operand" "")))]
  ""
  "
{
  if (operands[0] != operands[1])
    emit_move_insn (operands[0], operands[1]);
}")

(define_insn "addqi3"
  [(set (match_operand:QI 0 "register_operand" "=r")
	(plus:QI (match_operand:QI 1 "register_operand" "%0")
		 (match_operand:QI 2 "nonmemory_operand" "ri")))]
  ""
  "add.b	%X2,%X0"
  [(set_attr "type" "arith")
   (set_attr "length" "2")
   (set_attr "cc" "set")])

(define_insn ""
  [(set (match_operand:SI 0 "register_operand" "=l,l")
	(plus:SI (match_operand:SI 1 "register_operand" "%0,0")
		 (match_operand:SI 2 "nonmemory_operand" "l,n")))
   (clobber (match_operand:HI 3 "register_operand" "=&l,l"))]
  ""
  "@
     add	%w2,%w0\;addx	%x2,%x0\;addx	%y2,%y0\;addx	%z2,%z0
     add.w	%f2,%f0\;addx	%y2,%y0\;addx	%z2,%z0"
  [(set_attr "type" "multi")
   (set_attr "length" "8,6")
   (set_attr "cc" "clobber")])

(define_insn ""
  [(set (match_operand:SI 0 "register_operand" "=l,l")
	(plus:SI (match_operand:SI 1 "register_operand" "%0,0")
		 (match_operand:SI 2 "nonmemory_operand" "n,r")))]
  ""
  "@
     add	%w2,%w0\;addx	%x2,%x0\;addx	%y2,%y0\;addx	%z2,%z0
     add.w	%f2,%f0\;addx	%y2,%y0\;addx	%z2,%z0"
  [(set_attr "type" "arith")
   (set_attr "length" "8,6")
   (set_attr "cc" "clobber")])

(define_expand "addsi3"
  [(set (match_dup 3) (match_operand:SI 1 "register_operand" ""))
   (set (match_dup 3)
	(plus:SI (match_dup 3)
		 (match_operand:SI 2 "nonmemory_operand" "")))
   (set (match_operand:SI 0 "register_operand" "") (match_dup 3))]
  ""
  "
{
  operands[3] = gen_rtx (REG, SImode, 0);
}")

;; ----------------------------------------------------------------------;
;; Subtract instructions
;; ----------------------------------------------------------------------

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

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

(define_expand "subhi3"
  [(set (match_operand:HI 0 "register_operand" "")
	(minus:HI (match_operand:HI 1 "register_operand" "")
		  (match_operand:HI 2 "nonmemory_operand" "")))]
  ""
  "
{
  if (operands[0] != operands[1])
    emit_move_insn (operands[0], operands[1]);
}")

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

(define_expand "subsi3"
  [(set (match_dup 3) (match_operand:SI 1 "register_operand" ""))
   (set (match_dup 3)
	(minus:SI (match_dup 3)
		  (match_operand:SI 2 "nonmemory_operand" "")))
   (set (match_operand:SI 0 "register_operand" "") (match_dup 3))]
  ""
  "operands[3] = gen_rtx (REG, SImode, 0);")

;; ----------------------------------------------------------------------
;; Multiply instruction
;; ----------------------------------------------------------------------

(define_insn "umulqihi3"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(mult:HI (match_operand:QI 1 "general_operand" "%0")
		 (match_operand:QI 2 "register_operand" "r")))]
  ""
  "mulxu	%X2,%T0"
  [(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")])

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

(define_insn "andqi3"
  [(set (match_operand:QI 0 "general_operand" "=r")
	(and:QI (match_operand:QI 1 "general_operand" "%0")
		(match_operand:QI 2 "general_operand" "rn")))]
  ""
  "and	%X2,%X0"
  [(set_attr "type" "arith")
   (set_attr "length" "2")
   (set_attr "cc" "set")])

(define_insn "andhi3"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(and:HI (match_operand:HI 1 "register_operand" "%0")
		(match_operand:HI 2 "general_operand" "ri")))]
  ""
  "and	%s2,%s0\;and	%t2,%t0"
  [(set_attr "type" "multi")
   (set_attr "length" "4")
   (set_attr "cc" "clobber")])

;; ----------------------------------------------------------------------
;; Or instructions
;; ----------------------------------------------------------------------

(define_insn "iorqi3"
  [(set (match_operand:QI 0 "general_operand" "=r,U")
	(ior:QI (match_operand:QI 1 "general_operand" "%0,0")
		(match_operand:QI 2 "general_operand" "rn,P")))]
  ""
  "@
   or	%X2,%X0
   bset	%V2,%X0"
  [(set_attr "type" "arith")
   (set_attr "length" "2,4")
   (set_attr "cc" "set,none_0hit")])

(define_insn "iorhi3"
  [(set (match_operand:HI 0 "general_operand" "=r,r")
	(ior:HI (match_operand:HI 1 "general_operand" "%0,0")
		(match_operand:HI 2 "general_operand" "J,ri")))]
  ""
  "@
   or	%s2,%s0
   or	%s2,%s0\;or	%t2,%t0"
  [(set_attr "type" "multi")
   (set_attr "length" "2,4")
   (set_attr "cc" "clobber,clobber")])

;; ----------------------------------------------------------------------
;; Xor instructions
;; ----------------------------------------------------------------------

(define_insn "xorqi3"
  [(set (match_operand:QI 0 "general_operand" "=r")
	(xor:QI (match_operand:QI 1 "general_operand" "%0")
		(match_operand:QI 2 "nonmemory_operand" "ri")))]
  ""
  "xor	%X2,%X0"
  [(set_attr "type" "arith")
   (set_attr "length" "2")
   (set_attr "cc" "set")])

(define_insn "xorhi3"
  [(set (match_operand:HI 0 "general_operand" "=r")
	(xor:HI (match_operand:HI 1 "general_operand" "%0")
		(match_operand:HI 2 "nonmemory_operand" "ri")))]
  ""
  "xor	%s2,%s0\;xor	%t2,%t0"
  [(set_attr "type" "multi")
   (set_attr "length" "4")
   (set_attr "cc" "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 "type" "arith")
   (set_attr "length" "2")
   (set_attr "cc" "set")])

(define_expand "neghi2"
  [(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_expand "negsi2"
  [(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);")

;; ----------------------------------------------------------------------
;; 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")))]
  ""
  "not	%s0\;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")))]
  ""
  "not	%w0\;not	%x0\;not	%y0\;not	%z0"
  [(set_attr "type" "arith")
   (set_attr "length" "8")
   (set_attr "cc" "clobber")])

;; ----------------------------------------------------------------------
;; Conditional branches
;; ----------------------------------------------------------------------

(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 ""
  [(set (pc)
	(if_then_else 
	 (match_operator 1 "comparison_operator" [(cc0) (const_int 0)])
	 (label_ref (match_operand 0 "" ""))
	 (pc)))]
  ""
  "*
{
  if (get_attr_length (insn) == 2) 
   return \"b%j1	%l0\";
  else
   return \"b%k1	%L0\;jmp	@%l0\;%L0:\";
}" 
  [(set_attr "type" "branch")
   (set_attr "cc" "none")])

(define_insn ""
  [(set (pc)
	(if_then_else
	 (match_operator 1 "comparison_operator" [(cc0) (const_int 0)])
	 (pc)
	 (label_ref (match_operand 0 "" ""))))]
  ""
  "*
{
  if (get_attr_length (insn) == 2) 
   return \"b%k1	%l0\";
  else
   return \"b%j1	%L0\;jmp	@%l0\;%L0:\";
}"
  [(set_attr "type" "branch")
   (set_attr "cc" "none")])

;; ----------------------------------------------------------------------
;; Unconditional branches
;; ----------------------------------------------------------------------

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

(define_insn "tablejump"
  [(set (pc) (match_operand:HI 0 "register_operand" ""))
   (use (label_ref (match_operand 1 "" "")))]
  ""
  "jmp	@%0"
  [(set_attr "type" "branch")
   (set_attr "cc" "none")
   (set_attr "length" "2")])

;; Call subroutine with no return value.

(define_insn "call"
  [(call (match_operand:QI 0 "memory_operand" "o")
	 (match_operand:HI 1 "general_operand" "g"))]
  ""
  "jsr	%0"
  [(set_attr "type" "call")
   (set_attr "cc" "clobber")
   (set_attr "length" "4")])

;; Call subroutine, returning value in operand 0
;; (which must be a hard register).

(define_insn "call_value"
  [(set (match_operand 0 "" "=r")
	(call (match_operand:QI 1 "memory_operand" "o")
	      (match_operand:HI 2 "general_operand" "g")))]
  ""
  "jsr	%1"
  [(set_attr "type" "call")
   (set_attr "cc" "clobber")
   (set_attr "length" "4")])

(define_insn "nop"
  [(const_int 0)]
  ""
  "nop"
  [(set_attr "type" "multi")
   (set_attr "cc" "none")
   (set_attr "length" "2")])

(define_insn "indirect_jump"
  [(set (pc) (match_operand:HI 0 "register_operand" "r"))]
  ""
  "jmp	@%0"
  [(set_attr "type" "branch")
   (set_attr "cc" "none")
   (set_attr "length" "2")])

;; -----------------------------------------------------------------
;; Shifts
;; -----------------------------------------------------------------

;; All H8 shifts go one bit at a time, here they are defined with names
;; so can use them in the expands..

;; QI BIT SHIFTS

(define_insn "ashlqi3_one"
  [(set (match_operand:QI 0 "register_operand" "=r")
	(ashift:QI (match_operand:QI 1 "register_operand" "0")
		   (const_int 1)))]
  ""
  "shal %X0"
  [(set_attr "type" "arith")
   (set_attr "length" "2")
   (set_attr "cc" "set")])

(define_insn "ashrqi3_one"
  [(set (match_operand:QI 0 "register_operand" "=r")
	(ashiftrt:QI (match_operand:QI 1 "register_operand" "0")
		     (const_int 1)))]
  ""
  "shar %X0"
  [(set_attr "type" "arith")
   (set_attr "length" "2")
   (set_attr "cc" "set")])

(define_insn "lshrqi3_one"
  [(set (match_operand:QI 0 "register_operand" "=r")
	(lshiftrt:QI (match_operand:QI 1 "register_operand" "0")
		     (const_int 1)))]
  ""
  "shlr %X0"
  [(set_attr "type" "arith")
   (set_attr "length" "2")
   (set_attr "cc" "set")])

(define_expand "ashlqi3"
  [(set (match_operand:QI 0 "register_operand" "=r")
	(ashift:QI (match_operand:QI 1 "register_operand" "0")
		   (match_operand:QI 2 "nonmemory_operand" "rn")))]
  ""
  "
{
  if (can_shift (ASHIFT, operands, gen_ashlqi3_one, 4, 0))
    DONE;
  else
    FAIL;
}")

(define_expand "ashrqi3"
  [(set (match_operand:QI 0 "register_operand" "=r")
	(ashiftrt:QI (match_operand:QI 1 "register_operand" "0")
		     (match_operand:QI 2 "nonmemory_operand" "rn")))]
  ""
  "
{
  if (can_shift (ASHIFTRT, operands, gen_ashrqi3_one, 4, 0))
    DONE;
  else
    FAIL;
}")

(define_expand "lshrqi3"
  [(set (match_operand:QI 0 "register_operand" "=r")
	(lshiftrt:QI (match_operand:QI 1 "register_operand" "0")
		     (match_operand:QI 2 "nonmemory_operand" "rn")))]
  ""
  "
{
  if (can_shift (LSHIFTRT, operands, gen_lshrqi3_one, 4, 0))
    DONE;
  else
    FAIL;
}")

;;  HI BIT SHIFTS

(define_insn "ashlhi3_one"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(ashift:HI (match_operand:HI 1 "register_operand" "0")
		   (const_int 1)))]
  ""
  "add.w	%T1,%T0"
  [(set_attr "type" "multi")
   (set_attr "length" "4")
   (set_attr "cc" "set")])

(define_insn "ashlhi3_eight"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(ashift:HI (match_operand:HI 1 "register_operand" "0")
		   (const_int 8)))]
  ""
  "mov.b	%s1,%t0\;mov.b	#0,%s0"
  [(set_attr "type" "multi")
   (set_attr "length" "4")
   (set_attr "cc" "clobber")])

(define_expand "ashlhi3"
  [(set (match_operand:HI 0 "register_operand" "")
	(ashift:HI
	 (match_operand:HI 1 "general_operand_src" "")
	 (match_operand:HI 2 "nonmemory_operand" "")))]
  ""
  "
{
  if (can_shift (ASHIFT, operands, gen_ashlhi3_one, 4, gen_ashlhi3_eight)) 
    DONE;
  else
    FAIL;
}")

(define_insn "lshrhi3_one"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(lshiftrt:HI (match_operand:HI 1 "register_operand" "0")
		     (const_int 1)))]
  ""
  "shlr	%t0\;rotxr	%s0"
  [(set_attr "type" "multi")
   (set_attr "length" "4")
   (set_attr "cc" "clobber")])

(define_insn "lshlhi3_eight"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(lshiftrt:HI (match_operand:HI 1 "register_operand" "0")
		     (const_int 8)))]
  ""
  "mov.b	%t1,%s0\;mov.b	#0,%t0"
  [(set_attr "type" "multi")
   (set_attr "length" "4")
   (set_attr "cc" "clobber")])

(define_expand "lshrhi3"
  [(set (match_operand:HI 0 "register_operand" "")
	(lshiftrt:HI
	 (match_operand:HI 1 "general_operand_src" "")
	 (match_operand:HI 2 "nonmemory_operand" "")))]
  ""
  "
{
  if (can_shift (LSHIFTRT, operands, gen_lshrhi3_one, 4, gen_lshlhi3_eight))
    DONE;
  else
    FAIL;
}")

(define_insn "ashrhi3_one"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(ashiftrt:HI (match_operand:HI 1 "register_operand" "0")
		     (const_int 1)))]
  ""
  "shar	%t0\;rotxr	%s0"
  [(set_attr "type" "multi")
   (set_attr "length" "4")
   (set_attr "cc" "clobber")])

; signed shift right by 8 bits
; fetch the carry bit from the top, copy the byte right, subtract the 
; top byte from itself - carry.

(define_insn "ashrhi3_eight"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(ashiftrt:HI (match_operand:HI 1 "register_operand" "0")
		     (const_int 8)))]
  ""
  "bld	#7,%t0\;mov.b	%t0,%s0\;subx	%t0,%t0"
  [(set_attr "type" "multi")
   (set_attr "length" "6")
   (set_attr "cc" "clobber")])

(define_expand "ashrhi3"
  [(set (match_operand:HI 0 "register_operand" "")
	(ashiftrt:HI
	 (match_operand:HI 1 "general_operand_src" "")
	 (match_operand:HI 2 "nonmemory_operand" "")))]
  ""
  "
{
  if (can_shift (ASHIFTRT, operands, gen_ashrhi3_one, 4, gen_ashrhi3_eight)) 
    DONE;
  else
    FAIL;
}")

;; SI BIT SHIFTS

(define_insn "ashlsi3_one"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(ashift:SI (match_operand:SI 1 "register_operand" "0")
		   (const_int 1)))]
  ""
  "add.w	%f1,%f0\;addx	%y1,%y0\;addx	%z1,%z0"
  [(set_attr "type" "multi")
   (set_attr "length" "6")
   (set_attr "cc" "clobber")])

(define_expand "ashlsi3"
  [(set (match_operand:SI 0 "register_operand" "")
	(ashift:SI
	 (match_operand:SI 1 "general_operand_src" "")
	 (match_operand:SI 2 "nonmemory_operand" "")))]
  ""
  "
{
  if (can_shift (ASHIFT, operands, gen_ashlsi3_one, 1, 0))
    DONE;
  else
    FAIL;
}")

(define_insn "lshrsi3_one"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(lshiftrt:SI (match_operand:SI 1 "register_operand" "0")
		     (const_int 1)))]
  ""
  "shlr	%z0\;rotxr	%y0\;rotxr	%x0\;rotxr	%w0"
  [(set_attr "type" "multi")
   (set_attr "length" "8")
   (set_attr "cc" "clobber")])

(define_expand "lshrsi3"
  [(set (match_operand:SI 0 "register_operand" "")
	(lshiftrt:SI
	 (match_operand:SI 1 "general_operand_src" "")
	 (match_operand:SI 2 "nonmemory_operand" "")))]
  ""
  "
{
  if (can_shift (LSHIFTRT, operands, gen_lshrsi3_one, 1, 0))
    DONE;
  else
    FAIL;
}")

(define_insn "ashrsi3_one"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(ashiftrt:SI (match_operand:SI 1 "register_operand" "0")
		     (const_int 1)))]
  ""
  "shar	%z0\;rotxr	%y0\;rotxr	%x0\;rotxr	%w0"
  [(set_attr "type" "multi")
   (set_attr "length" "16")
   (set_attr "cc" "clobber")])

(define_expand "ashrsi3"
  [(set (match_operand:SI 0 "register_operand" "")
	(ashiftrt:SI
	 (match_operand:SI 1 "general_operand_src" "")
	 (match_operand:SI 2 "nonmemory_operand" "")))]
  ""
  "
{
  if (can_shift (ASHIFTRT, operands, gen_ashrsi3_one, 1, 0))
    DONE;
  else
    FAIL;
}")

;; ----------------------------------------------------------------------
;; BIT FIELDS
;; ----------------------------------------------------------------------

(define_insn ""
  [(set (zero_extract:HI (match_operand:HI 0 "register_operand" "+r")
			 (const_int 1)
			 (match_operand:HI 2 "general_operand" "g"))
	(match_operand:HI 3 "general_operand" "r"))]
  ""
  "bld	#0,%3l\;bst	%Z2,%0%Y1"
  [(set_attr "type" "multi")
   (set_attr "length" "4")
   (set_attr "cc" "clobber")])

(define_expand "insv"
  [(set (zero_extract:HI (match_operand:HI 0 "register_operand" "+r")
			 (match_operand:HI 1 "general_operand" "g")
			 (match_operand:HI 2 "general_operand" "g"))
	(match_operand:HI 3 "general_operand" "r"))]
  ""
  "if (INTVAL (operands[1]) != 1) FAIL;")

(define_insn ""
  [(set (match_operand:HI 0 "register_operand" "=&r")
	(zero_extract:HI (match_operand:HI 1 "register_operand" "r")
			 (const_int 1)
			 (match_operand:HI 3 "general_operand" "g")))]
  ""
  "sub.w	%T0,%T0\;bld	%Z3,%T1%Y1\;rotxl	%T0l"
  [(set_attr "type" "multi")
   (set_attr "length" "6")
   (set_attr "cc" "clobber")])

(define_insn ""
  [(set (match_operand:HI 0 "register_operand" "=r")
	(sign_extract:HI (match_operand:HI 1 "register_operand" "r")
			 (const_int 1)
			 (match_operand:HI 3 "general_operand" "g")))]
  ""
  "bld	%Z3,%1%Y1\;sub.x	%0l,%0l\;mov.b	%0l,%0h"
  [(set_attr "type" "multi")
   (set_attr "length" "6")
   (set_attr "cc" "clobber")])

(define_expand "extzv"
  [(set (match_operand:HI 0 "register_operand" "")
	(zero_extract:HI (match_operand:HI 1 "register_operand" "")
			 (match_operand:HI 2 "general_operand" "")
			 (match_operand:HI 3 "general_operand" "")))]
  ""
  "if (INTVAL (operands[2]) != 1) FAIL;")

(define_expand "extv"
  [(set (match_operand:HI 0 "register_operand" "")
	(sign_extract:HI (match_operand:HI 1 "register_operand" "")
			 (match_operand:HI 2 "general_operand" "")
			 (match_operand:HI 3 "immediate_operand" "")))]
  ""
  "if (INTVAL (operands[2]) != 1)  FAIL;")

;; ----------------------------------------------------------------------
;; Conversions
;; ----------------------------------------------------------------------

(define_insn "zero_extendqihi2"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(zero_extend:HI
	 (match_operand:QI 1 "general_operand" "g")))]
  ""
  "mov.b	%X1,%s0\;mov.b	#0,%t0"
  [(set_attr "type" "multi")
   (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 "register_operand" "r")))]
  ""
  "*
{
  if (REGNO (operands[1]) != REGNO (operands[0]))
   return \"mov.b	%X1,%s0\;bld	#7,%s0\;subx	%t0,%t0\";
  else
   return \"bld	#7,%s0\;subx	%t0,%t0\";
}"
  [(set_attr "type" "multi")
   (set_attr "length" "6")
   (set_attr "cc" "clobber")])

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

(define_expand "extendhisi2"
  [(set (reg:HI 1) (match_operand:HI 1 "general_operand" ""))
   (set (reg:SI 0) (sign_extend:SI (reg:HI 1)))
   (set (match_operand:SI 0 "general_operand" "" ) (reg:SI 0))]
  ""
  "")

;; ----------------------------------------------------------------------
;; peepholes
;; ----------------------------------------------------------------------

;; 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:HI (match_dup 1))
	(match_operand:HI 0 "register_operand" ""))]
  "REGNO (operands[1]) != REGNO (operands[0])"
  "mov.w	%T0,@-%T1"
  [(set_attr "length" "2")
   (set_attr "cc" "set")])

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

;; notice a move which could be post incremented

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

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

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

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

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