;; Machine description for Mitsubishi D10V for GNU C compiler
;; Copyright (C) 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
;; Contributed by Cygnus Support.

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

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

;; Machine dependent register classes used:
;;	'C'	CARRY_REGS
;;	'a'	ACCUM_REGS
;;	'b'	R2_REGS
;;	'c'	CR_REGS
;;	'd'	GENERAL_REGS
;;	'e'	EVEN_REGS
;;	'f'	F0_REGS
;;	'h'	R3_REGS
;;	'j'	R4_REGS
;;	'l'	R13_REGS
;;	'q'	R5_REGS
;;	'x'	CC_REGS
;;	'y'	F1_REGS
;;	'z'	REPEAT_REGS


;; Function unit attributes
;; Note, we lie a little bit here to make it simpler to optimize.  We pretend there
;; is a separate long functional unit for long instructions that uses both the IU & MU.
(define_attr "type" "iu,mu,either,long,unknown"
  (const_string "unknown"))

;; Length in word units
(define_attr "length" ""
  (if_then_else (eq_attr "type" "long,unknown")
		(const_int 2)
		(const_int 1)))

;; (define_function_unit NAME MULTIPLICITY SIMULTANEITY TEST READY-DELAY ISSUE-DELAY [CONFLICT-LIST])
(define_function_unit "iu" 1 1
  (and (eq_attr "type" "iu,either")
       (eq_attr "length" "1"))
  2 2
  [(eq_attr "type" "long,unknown")])

(define_function_unit "mu" 1 1
  (and (eq_attr "type" "mu,either")
       (eq_attr "length" "1"))
  2 2
  [(eq_attr "type" "long,unknown")])

(define_function_unit "long" 1 1
  (eq_attr "type" "long,unknown")
  2 2
  [(and (eq_attr "type" "iu,mu,either")
	(eq_attr "length" "1"))])

(define_function_unit "long" 1 1
  (not (eq_attr "length" "1"))
  2 2
  [(and (eq_attr "type" "iu,mu,either")
	(eq_attr "length" "1"))])


;;
;; Push/pop
;;
;;


;; Push a register onto the stack use R0 as sp
(define_insn "pushr"
  [(set:HI (mem:HI (pre_dec:HI (reg:SI 15)))
        (match_operand:HI 0 "register_operand" "r"))]
  ""
  "st	%0,@-r0"
  [(set_attr "length" "1")
;;   (set_attr "cc" "none")]
  ]
)
 

;; Pop a register off the stack using R0 as sp
(define_insn "popr"
  [(set:HI (match_operand:HI 0 "register_operand" "=r")
        (mem:HI (post_inc:HI (reg:SI 15))))]
  ""
  "ld	%0,@r0+"
  [(set_attr "length" "1")
;;   (set_attr "cc" "none")
  ]
)

;; Push a register onto the stack using R0 as sp
(define_insn "pushwr"
  [(set:SI (mem:SI (pre_dec:SI (reg:SI 15)))
        (match_operand:SI 0 "register_operand" "e"))]
  "GPR_EVEN_P(REGNO(operands[0]))"
  "st2w	%0,@-r0"
  [(set_attr "length" "1")
;;   (set_attr "cc" "none")]
  ]
)
 

;; Pop a register off the stack using R0 as sp
(define_insn "popwr"
  [(set:SI (match_operand:SI 0 "register_operand" "=e")
        (mem:SI (post_inc:SI (reg:SI 15))))]
  "GPR_EVEN_P(REGNO(operands[0]))"
  "ld2w	%0,@r0+"
  [(set_attr "length" "1")
;;   (set_attr "cc" "none")
  ]
)


;;  ....................
;;
;;	Move operations
;;
;;  ....................

;; ;; ;; ACC guard bits <- R
;; ;; (define_insn "mvtacg"
;; ;;   [(set (match_operand:SI 0 "accum_operand" "=a")
;; ;; 	(match_operand:SI 1 "register_operand" "r"))]
;; ;;   "TARGET_ACCUM"
;; ;;   "mvtacg %0,%1
;; ;; ")
;; ;; 
;; ;; ;; ACC <- Reg pair
;; ;; (define_insn "mv2wtac"
;; ;;   [(set (match_operand:SI 0 "accum_operand" "=a")
;; ;; 	(match_operand:SI 1 "register_operand" "e"))]
;; ;;   "(TARGET_ACCUM) 
;; ;;     && (GPR_EVEN_P (REGNO(operands[1])))
;; ;;   "
;; ;;   "mv2wtac %0,%1
;; ;; ")
;; ;; 
;; ;; ;; Reg <- Guard bits of ACC
;; ;; (define_insn "mvfacg"
;; ;;   [(set (match_operand:SI 0 "accum_operand" "+a")
;; ;; 	(match_operand:SI 1 "register_operand" "=r"))]
;; ;;   "TARGET_ACCUM"
;; ;;   "mvfacg %0,%1
;; ;; ")
;; ;; 
;; ;; ;; Reg <- ACC
;; ;; (define_insn "mv2wfac"
;; ;;   [(set (match_operand:SI 0 "accum_operand" "+a")
;; ;; 	(match_operand:SI 1 "register_operand" "=e"))]
;; ;;   "(TARGET_ACCUM) 
;; ;;     && (GPR_EVEN_P (REGNO(operands[1])))
;; ;;   "
;; ;;   "mv2wfac %0,%1
;; ;; ")

(define_expand "movqi"
  [(set (match_operand:QI 0 "general_operand" "")
	(match_operand:QI 1 "general_operand" ""))]
  ""
  "
{
  if (GET_CODE (operands[0]) != REG
      && (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0))
    operands[1] = force_reg (QImode, operands[1]);
}")

(define_insn "movqi_internal"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,Q,m,d,d,Q,m")
	(match_operand:QI 1 "general_operand"  "d,Q,m,d,d,L,i,O,O"))]
  "register_operand (operands[0], QImode) || register_operand (operands[1], QImode)
   || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)"
  "@
  mv %0,%1
  ldub %0,%M1
  ldub %0,%M1
  stb %1,%M0
  stb %1,%M0
  ldi %0,%1
  ldi %0,%1
  stb %.,%M0
  stb %.,%M0"
  [(set_attr "type" "either,mu,long,mu,long,either,mu,mu,mu")
   (set_attr "length" "1,1,2,1,2,1,2,1,2")])

(define_expand "movhi"
  [(set (match_operand:HI 0 "general_operand" "")
	(match_operand:HI 1 "general_operand" ""))]
  ""
  "
{
  if (GET_CODE (operands[0]) != REG
      && (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0)
      && ! reload_in_progress)
    operands[1] = force_reg (HImode, operands[1]);
}")

(define_insn "*movhi_internal"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,Q,m,c,d,d,d,Q,m")
	(match_operand:HI 1 "general_operand"  "d,Q,m,d,d,d,c,L,i,O,O"))]
  "register_operand (operands[0], HImode) || register_operand (operands[1], HImode)
   || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)"
  "* return emit_move_word (operands[0], operands[1], insn);"
  [(set_attr "type" "either,mu,long,mu,long,mu,mu,either,mu,mu,mu")
   (set_attr "length" "1,1,2,1,2,1,1,1,2,1,2")])

;; Split constants that we can into a small ldi and a shift.  This may seem
;; counter intuitive to replace one instruction by two, but the reasoning is
;; that it helps avoid nops caused by the long form of ldi and is the same
;; space if no nops where needed, and also allows such constants to be set up
;; with conditional execution.

(define_split
  [(set (match_operand:HI 0 "gpr_operand" "")
	(match_operand:HI 1 "ldi_shift_operand" ""))]
  ""
  [(set (match_dup 0) (match_dup 2))
   (set (match_dup 0) (ashift:HI (match_dup 0) (match_dup 3)))]
  "
{
  int shift = ldi_shift_operand (operands[1], HImode);
  operands[2] = GEN_INT (INTVAL (operands[1]) >> shift);
  operands[3] = GEN_INT (shift);
}")

(define_expand "movsi"
  [(set (match_operand:SI 0 "general_operand" "")
	(match_operand:SI 1 "general_operand" ""))]
  ""
  "
{
  if (GET_CODE (operands[0]) != REG)
    operands[1] = force_reg (SImode, operands[1]);

}")

(define_insn "*movsi_internal"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=e,e,e,Q,m,a,a,e,e,a")
	(match_operand:SI 1 "general_operand" "e,Q,m,e,e,e,a,a,i,O"))]
  "register_operand (operands[0], SImode) || register_operand (operands[1], SImode)"
  "* return emit_move_2words (operands[0], operands[1], insn);"
  [(set_attr "type" "either,mu,long,mu,long,mu,iu,mu,long,iu")
   (set_attr "length" "1,1,2,1,2,1,1,1,4,1")])

(define_split
  [(set (match_operand:SI 0 "gpr_operand" "")
	(match_operand:SI 1 "const_int_operand" ""))]
  "reload_completed"
  [(set (match_dup 2) (match_dup 4))
   (set (match_dup 3) (match_dup 5))]
  "
{
  operands[2] = d10v_subword (operands[0], 0, HImode, SImode);
  operands[3] = d10v_subword (operands[0], 1, HImode, SImode);
  operands[4] = GEN_INT (SIGN_EXTEND_SHORT (INTVAL (operands[1]) >> 16));
  operands[5] = GEN_INT (SIGN_EXTEND_SHORT (INTVAL (operands[1])));
}")

(define_insn "reload_insi"
  [(set (match_operand:SI 0 "register_operand" "=a,a")
	(match_operand:SI 1 "memory_operand" "Q,m"))
   (clobber (match_operand:SI 2 "gpr_operand" "=&e,e"))]
  "TARGET_ACCUM"
  "#"
  [(set_attr "type" "long,long")
   (set_attr "length" "2,3")])

(define_insn "reload_outsi"
  [(set (match_operand:SI 0 "memory_operand" "=Q,m")
	(match_operand:SI 1 "accum_operand" "a,a"))
   (clobber (match_operand:SI 2 "gpr_operand" "=&e,e"))]
  "TARGET_ACCUM"
  "#"
  [(set_attr "type" "long,long")
   (set_attr "length" "2,3")])

(define_split
  [(set (match_operand:SI 0 "nonimmediate_operand" "")
	(match_operand:SI 1 "general_operand" ""))
   (clobber (match_operand:SI 2 "gpr_operand" ""))]
  "TARGET_ACCUM && reload_completed"
  [(set (match_dup 2) (match_dup 1))
   (set (match_dup 0) (match_dup 2))]
  "")

(define_expand "movsf"
  [(set (match_operand:SF 0 "general_operand" "")
	(match_operand:SF 1 "general_operand" ""))]
  ""
  "
{
  if (GET_CODE (operands[0]) != REG)
    operands[1] = force_reg (SFmode, operands[1]);
}")

(define_insn "*movsf_internal"
  [(set (match_operand:SF 0 "nonimmediate_operand" "=e,e,e,Q,m,e")
	(match_operand:SF 1 "general_operand" "e,Q,m,e,e,F"))]
  "register_operand (operands[0], SFmode) || register_operand (operands[1], SFmode)"
  "* return emit_move_2words (operands[0], operands[1], insn);"
  [(set_attr "type" "either,mu,long,mu,long,long")
   (set_attr "length" "1,1,2,1,2,4")])

(define_split
  [(set (match_operand:SF 0 "gpr_operand" "")
	(match_operand:SF 1 "const_double_operand" ""))]
  "reload_completed"
  [(set (match_dup 2) (match_dup 4))
   (set (match_dup 3) (match_dup 5))]
  "
{
  REAL_VALUE_TYPE rv;
  HOST_WIDE_INT value;

  REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
  REAL_VALUE_TO_TARGET_SINGLE (rv, value);

  operands[2] = d10v_subword (operands[0], 0, HImode, SFmode);
  operands[3] = d10v_subword (operands[0], 1, HImode, SFmode);
  operands[4] = GEN_INT (SIGN_EXTEND_SHORT (value >> 16));
  operands[5] = GEN_INT (SIGN_EXTEND_SHORT (value));
}")

(define_insn "movcc"
  [(set (match_operand:CC 0 "register_operand" "=x")
	(match_operand:CC 1 "general_operand" "x"))]
  ""
  "cpfg %0,%1"
  [(set_attr "type" "mu")
   (set_attr "length" "1")])


;;  ....................
;;
;;	Unconditional branch, return, and case table
;;
;;  ....................

(define_insn "jump"
  [(set (pc)
	(label_ref (match_operand 0 "" "")))]
  ""
  "bra %l0"
  [(set_attr "type" "long")
   (set_attr "length" "2")])

;; Note, do not list a dependency on r13, since jump.c currently can't handle a parallel
;; operation.
(define_expand "return"
  [(return)]
  "direct_return ()"
  "")

(define_insn "return_internal"
  [(const_int 0)
   (return)]
  ""
  "jmp r13"
  [(set_attr "type" "mu")])


(define_insn "*return_1"
  [(return)]
  "direct_return () && (d10v_stack_info ())->total_size == 0"
  "*
{
  operands[0] = gen_rtx (REG, Pmode, RETURN_ADDRESS_REGNUM);
  return \"jmp %0\";
}"
  [(set_attr "type" "mu")
   (set_attr "length" "1")])

(define_insn "*return_2"
  [(return)]
  "direct_return () && (d10v_stack_info ())->total_size != 0"
  "*
{
  d10v_stack_t *info = d10v_stack_info ();

  operands[0] = gen_rtx (REG, Pmode, STACK_POINTER_REGNUM);
  operands[1] = gen_rtx (REG, Pmode, RETURN_ADDRESS_REGNUM);
  if (info->total_size == UNITS_PER_WORD && info->save_p[RETURN_ADDRESS_REGNUM])
    return \"ld %1,@%0+\;jmp %1\";

  else if (info->total_size == info->vars_size
	   && IN_RANGE_P (info->total_size, 1, 16))
    {
      operands[2] = GEN_INT (info->total_size);
      return \"addi %0,%2\;jmp %1\";
    }

  else
    fatal_insn (\"return_2 unexpected return stack\", insn);

  return \"\";
}"
  [(set_attr "type" "long")
   (set_attr "length" "2")])

(define_insn "indirect_jump"
  [(set (pc) (match_operand:HI 0 "gpr_operand" "d"))]
  ""
  "jmp %0"
  [(set_attr "type" "mu")
   (set_attr "length" "1")])

;; No operation
(define_insn "nop"
  [(const_int 0)]
  ""
  "nop"
  [(set_attr "type" "either")
   (set_attr "length" "1")])

;; Table jump for switch statements:
(define_insn "tablejump"
  [(set (pc) (match_operand:HI 0 "gpr_operand" "d"))
   (use (label_ref (match_operand 1 "" "")))]
  ""
  "jmp %0"
  [(set_attr "type" "mu")
   (set_attr "length" "1")])


;;  ....................
;;
;;	Calls
;;
;;  ....................

(define_expand "call"
  [(parallel [(call (match_operand 0 "memory_operand" "")
		    (match_operand 1 "" ""))
	      (clobber (match_scratch:HI 2 "=l"))])]
  ""
  "
{
  rtx addr;

  addr = XEXP (operands[0], 0);
  if (GET_CODE (addr) != REG && !CONSTANT_ADDRESS_P (addr))
    {
      rtx reg = gen_reg_rtx (Pmode);
      emit_move_insn (reg, addr);
      operands[0] = gen_rtx (MEM, FUNCTION_MODE, reg);
    }
}")

(define_insn "*call_internal1"
  [(call (mem:HI (match_operand:HI 0 "register_operand" "r"))
         (match_operand 1 "" "i"))
   (clobber (match_scratch:HI 2 "=l"))]			;; return address, r13
  ""
  "jl %0"
  [(set_attr "type" "mu")
   (set_attr "length" "1")])

(define_insn "*call_internal2"
  [(call (match_operand 0 "memory_operand" "m")
	 (match_operand 1 "" "i"))
   (clobber (match_scratch:HI 2 "=l"))]			;; return address, r13
  "CONSTANT_ADDRESS_P (XEXP (operands[0], 0))"
  "bl %0"
  [(set_attr "type" "long")
   (set_attr "length" "2")])

(define_expand "call_value"
  [(parallel [(set (match_operand 0 "gpr_operand" "")
		   (call (match_operand 1 "memory_operand" "m")
			 (match_operand 2 "" "i")))
	      (clobber (match_scratch:HI 3 "=l"))])]
  ""
  "
{
  rtx addr;

  addr = XEXP (operands[1], 0);
  if (GET_CODE (addr) != REG && !CONSTANT_ADDRESS_P (addr))
    {
      rtx reg = gen_reg_rtx (Pmode);
      emit_move_insn (reg, addr);
      operands[1] = gen_rtx (MEM, FUNCTION_MODE, reg);
    }
}")


;; (define_insn "*call_value_internal1"
;;  [(set (match_operand 0 "gpr_operand" "=e")
;; (call (match_operand 1 "memory_operand" "m")
;;       (match_operand 2 "" "i")))
;;   (clobber (match_scratch:HI 3 "=l"))]			;; return address, r13
;;  "GET_CODE (XEXP (operands[1], 0)) == REG"
;;  "jl %1"
;;  [(set_attr "type" "mu")
;;   (set_attr "length" "1")])
;;  
;; (define_insn "*call_value_internal2"
;;  [(set (match_operand 0 "gpr_operand" "=e")
;; (call (match_operand 1 "memory_operand" "m")
;;       (match_operand 2 "" "i")))
;;   (clobber (match_scratch:HI 3 "=l"))]			;; return address, r13
;;  "CONSTANT_ADDRESS_P (XEXP (operands[1], 0))"
;;  "bl %1"
;;  [(set_attr "type" "long")
;;   (set_attr "length" "2")])

(define_insn "*call_value_internal1"
   [(set (match_operand 0 "gpr_operand" "=e,e")
       (call (match_operand 1 "memory_operand" "R,S")
               (match_operand 2 "" "i,i")))
    (clobber (match_scratch:HI 3 "=l,l"))]                     ;; return address, r13
   ""
   "@
   jl %1
   bl %1"
   [(set_attr "type" "mu,long")
    (set_attr "length" "1,2")])



;;
;;  ....................
;;
;;	Comparisons
;;
;;  ....................

;; Flow here is rather complex:
;;
;;  1)	The cmp{hi,si,di,sf,df} routine is called.  It deposits the
;;	arguments into global variables, and the type into
;;	branch_type.  No RTL is generated.
;;
;;  2)	The appropriate branch define_expand is called, which then
;;	creates the appropriate RTL for the comparison and branch.

(define_expand "cmphi"
  [(set (cc0)
	(compare:CC (match_operand:HI 0 "gpr_operand" "")
		    (match_operand:HI 1 "arith16_operand" "")))]
  ""
  "
{
  if (operands[0])		/* avoid unused code message */
    {
      d10v_compare_op0 = operands[0];
      d10v_compare_op1 = operands[1];

      DONE;
    }
}")

(define_expand "tsthi"
  [(set (cc0)
	(match_operand:HI 0 "gpr_operand" ""))]
  ""
  "
{
  if (operands[0])		/* avoid unused code message */
    {
      d10v_compare_op0 = operands[0];
      d10v_compare_op1 = const0_rtx;
      DONE;
    }
}")

(define_expand "cmpsi"
  [(set (cc0)
	(compare:CC (match_operand:SI 0 "gpr_operand" "")
		    (match_operand:SI 1 "reg_or_0_operand" "")))]
  ""
  "
{
  if (operands[0])		/* avoid unused code message */
    {
      d10v_compare_op0 = operands[0];
      d10v_compare_op1 = operands[1];

      DONE;
    }
}")

(define_expand "tstsi"
  [(set (cc0)
	(match_operand:SI 0 "gpr_operand" ""))]
  ""
  "
{
  if (operands[0])		/* avoid unused code message */
    {
      d10v_compare_op0 = operands[0];
      d10v_compare_op1 = const0_rtx;
      DONE;
    }
}")

(define_insn "*tst_ne_true"
  [(set (match_operand:CC 0 "f0_operand" "")
	(ne:CC (and:HI (match_operand:HI 1 "gpr_operand" "d,d")
		       (match_operand:HI 2 "const_int_operand" "P,n"))
		   (const_int 0)))]
  ""
  "*
{
  int log = exact_log2_wide (INTVAL (operands[2]));

  if (IN_RANGE_P (log, 0, 15))
    {
      operands[3] = GEN_INT (15 - log);
      return \"btsti %1,%3\";
    }

  return \"tst0i %1,%2\";
}"
  [(set_attr "type" "iu,long")
   (set_attr "length" "1,2")])

; the following is wrong
;(define_insn "*tst_eq_true"
;  [(set (match_operand:CC 0 "f0_operand" "")
;	(eq:CC (and:HI (match_operand:HI 1 "gpr_operand" "d")
;		       (match_operand:HI 2 "const_int_operand" "n"))
;	       (const_int 0)))]
;  ""
;  "tst0i %1,%2"
;  [(set_attr "type" "long")
;   (set_attr "length" "2")])
;
;(define_insn "*tst_ne_false"
;  [(set (match_operand:CC_REV 0 "f0_operand" "")
;	(ne:CC_REV (and:HI (match_operand:HI 1 "gpr_operand" "d")
;			   (match_operand:HI 2 "const_int_operand" "n"))
;		   (const_int 0)))]
;  ""
;  "tst0i %1,%2"
;  [(set_attr "type" "long")
;   (set_attr "length" "2")])

(define_insn "*tst_eq_false"
  [(set (match_operand:CC_REV 0 "f0_operand" "")
	(eq:CC_REV (and:HI (match_operand:HI 1 "gpr_operand" "d,d")
			   (match_operand:HI 2 "const_int_operand" "P,n"))
		   (const_int 0)))]
  ""
  "*
{
  int log = exact_log2_wide (INTVAL (operands[2]));

  if (IN_RANGE_P (log, 0, 15))
    {
      operands[3] = GEN_INT (15 - log);
      return \"btsti %1,%3\";
    }

  return \"tst0i %1,%2\";
}"
  [(set_attr "type" "iu,long")
   (set_attr "length" "1,2")])

(define_insn "*compare_hi_true"
  [(set (match_operand:CC 0 "f0_operand" "")
	(match_operator:CC 1 "compare_operator"
			       [(match_operand:HI 2 "gpr_operand" "d,d")
			       (match_operand:HI 3 "arith16_operand" "dL,i")]))]
  "(CCmode == SELECT_CC_MODE (GET_CODE (operands[1]), operands[2], operands[3]))"
  "*
{
  d10v_emit_comparison (GET_CODE (operands[1]), operands[2], operands[3], NULL_RTX, insn, HImode, TRUE);
  return \"\";
}"
  [(set_attr "type" "either,long")
   (set_attr "length" "1,2")])

(define_insn "*compare_hi_false"
  [(set (match_operand:CC_REV 0 "f0_operand" "")
	(match_operator:CC_REV 1 "compare_operator"
			       [(match_operand:HI 2 "gpr_operand" "d,d")
			       (match_operand:HI 3 "arith16_operand" "dL,i")]))]
  "(CC_REVmode == SELECT_CC_MODE (GET_CODE (operands[1]), operands[2], operands[3]))"
  "*
{
  d10v_emit_comparison (GET_CODE (operands[1]), operands[2], operands[3], NULL_RTX, insn, HImode, TRUE);
  return \"\";
}"
  [(set_attr "type" "either,long")
   (set_attr "length" "1,2")])

(define_insn "*equality_si_true"
  [(set (match_operand:CC 0 "f0_operand" "")
	(match_operator:CC 1 "equality_operator"
			   [(match_operand:SI 2 "gpr_operand" "e,e,e")
			    (match_operand:SI 3 "arith_lower0_operand" "e,O,K")]))]
  "(CCmode == SELECT_CC_MODE (GET_CODE (operands[1]), operands[2], operands[3]))"
  "*
{
  d10v_emit_comparison (GET_CODE (operands[1]), operands[2], operands[3], NULL_RTX, insn, SImode, TRUE);
  return \"\";
}"
  [(set_attr "type" "long,long,long")
   (set_attr "length" "4,4,4")])

(define_insn "*compare_si_true"
  [(set (match_operand:CC 0 "f0_operand" "")
	(match_operator:CC 1 "compare_operator"
			   [(match_operand:SI 2 "gpr_operand" "e,e")
			    (match_operand:SI 3 "reg_or_0_operand" "e,O")]))]
  "(CCmode == SELECT_CC_MODE (GET_CODE (operands[1]), operands[2], operands[3]))"
  "*
{
  d10v_emit_comparison (GET_CODE (operands[1]), operands[2], operands[3], NULL_RTX, insn, SImode, TRUE);
  return \"\";
}"
  [(set_attr "type" "long,long")
   (set_attr "length" "4,4")])


(define_insn "*equality_si_false"
  [(set (match_operand:CC_REV 0 "f0_operand" "")
	(match_operator:CC_REV 1 "equality_operator"
			       [(match_operand:SI 2 "gpr_operand" "e,e,e")
				(match_operand:SI 3 "arith_lower0_operand" "e,O,K")]))]
  "(CC_REVmode == SELECT_CC_MODE (GET_CODE (operands[1]), operands[2], operands[3]))"
  "*
{
  d10v_emit_comparison (GET_CODE (operands[1]), operands[2], operands[3], NULL_RTX, insn, SImode, TRUE);
  return \"\";
}"
  [(set_attr "type" "long,long,long")
   (set_attr "length" "4,4,4")])

(define_insn "*compare_si_false"
  [(set (match_operand:CC_REV 0 "f0_operand" "")
	(match_operator:CC_REV 1 "compare_operator"
			       [(match_operand:SI 2 "gpr_operand" "e,e")
				(match_operand:SI 3 "reg_or_0_operand" "e,O")]))]
  "(CC_REVmode == SELECT_CC_MODE (GET_CODE (operands[1]), operands[2], operands[3]))"
  "*
{
  d10v_emit_comparison (GET_CODE (operands[1]), operands[2], operands[3], NULL_RTX, insn, SImode, TRUE);
  return \"\";
}"
  [(set_attr "type" "long,long")
   (set_attr "length" "4,4")])



;;
;;  ....................
;;
;;	Conditional moves
;;
;;  ....................

(define_expand "movqicc"
  [(set (match_operand:QI 0 "cond_move_operand" "")
       (if_then_else:QI (match_operand 1 "" "")
			(match_operand:QI 2 "cond_move_operand" "")
			(match_operand:QI 3 "cond_move_operand" "")))]
"TARGET_COND_MOVE"
  "if (! d10v_expand_movcc (operands)) FAIL; DONE;")


(define_insn "*movqicc_internal"
  [(set (match_operand:QI 0 "cond_move_operand" "=d,d,?d,d,d,?d,Q")
	(if_then_else:QI (match_operator:CC 1 "f0_compare_operator"
					    [(match_operand:CC 2 "f0_operand" "")
					     (const_int 0)])
			 (match_operand:QI 3 "cond_move_operand" "0,d,d,0,LQ,LQd,Od")
			 (match_operand:QI 4 "cond_move_operand" "d,0,d,LQ,0,LQd,Od")))]
  "TARGET_COND_MOVE
   && (GET_CODE (operands[0]) != MEM
       || GET_CODE (operands[3]) == REG
       || (GET_CODE (operands[3]) == CONST_INT && INTVAL (operands[3]) == 0)
       || GET_CODE (operands[4]) == REG
       || (GET_CODE (operands[4]) == CONST_INT && INTVAL (operands[4]) == 0))"
  "* return emit_cond_move (operands, insn);"
  [(set_attr "type" "either,either,long,long,long,long,long")
   (set_attr "length" "1,1,2,2,2,4,4")])

(define_expand "movhicc"
  [(set (match_operand:HI 0 "cond_move_operand" "")
       (if_then_else:HI (match_operand 1 "" "")
			(match_operand:HI 2 "cond_move_operand" "")
			(match_operand:HI 3 "cond_move_operand" "")))]
"TARGET_COND_MOVE"
  "if (! d10v_expand_movcc (operands)) FAIL; DONE;")


(define_insn "*movhicc_internal"
  [(set (match_operand:HI 0 "cond_move_operand" "=d,d,?d,d,d,?d,Q")
	(if_then_else:HI (match_operator:CC 1 "f0_compare_operator"
					    [(match_operand:CC 2 "f0_operand" "")
					     (const_int 0)])
			 (match_operand:HI 3 "cond_move_operand" "0,d,d,0,LQ,LQd,Od")
			 (match_operand:HI 4 "cond_move_operand" "d,0,d,LQ,0,LQd,Od")))]
  "TARGET_COND_MOVE
   && (GET_CODE (operands[0]) != MEM
       || GET_CODE (operands[3]) == REG
       || (GET_CODE (operands[3]) == CONST_INT && INTVAL (operands[3]) == 0)
       || GET_CODE (operands[4]) == REG
       || (GET_CODE (operands[4]) == CONST_INT && INTVAL (operands[4]) == 0))"
  "* return emit_cond_move (operands, insn);"
  [(set_attr "type" "either,either,long,long,long,long,long")
   (set_attr "length" "1,1,2,2,2,4,4")])

(define_expand "movsicc"
  [(set (match_operand:SI 0 "cond_move_operand" "")
       (if_then_else:SI (match_operand 1 "" "")
			(match_operand:SI 2 "cond_move_operand" "")
			(match_operand:SI 3 "cond_move_operand" "")))]
"TARGET_COND_MOVE"
  "if (! d10v_expand_movcc (operands)) FAIL; DONE;")


(define_insn "*movsicc_internal"
  [(set (match_operand:SI 0 "cond_move_operand" "=e,e,?e,Q")
	(if_then_else:SI (match_operator:CC 1 "f0_compare_operator"
					    [(match_operand:CC 2 "f0_operand" "")
					     (const_int 0)])
			 (match_operand:SI 3 "cond_move_operand" "0,Qe,Qe,e")
			 (match_operand:SI 4 "cond_move_operand" "Qe,0,Qe,e")))]
  "TARGET_COND_MOVE
   && (GET_CODE (operands[0]) != MEM
       || GET_CODE (operands[3]) == REG
       || GET_CODE (operands[4]) == REG)"
  "* return emit_cond_move (operands, insn);"
  [(set_attr "type" "long,long,long,long")
   (set_attr "length" "2,2,4,4")])

(define_expand "movsfcc"
  [(set (match_operand:SF 0 "cond_move_operand" "")
       (if_then_else:SF (match_operand 1 "" "")
			(match_operand:SF 2 "cond_move_operand" "")
			(match_operand:SF 3 "cond_move_operand" "")))]
"TARGET_COND_MOVE"
  "if (! d10v_expand_movcc (operands)) FAIL; DONE;")

(define_insn "*movsfcc_internal"
  [(set (match_operand:SF 0 "cond_move_operand" "=e,e,?e,Q")
	(if_then_else:SF (match_operator:CC 1 "f0_compare_operator"
					    [(match_operand:CC 2 "f0_operand" "")
					     (const_int 0)])
			 (match_operand:SF 3 "cond_move_operand" "0,Qe,Qe,e")
			 (match_operand:SF 4 "cond_move_operand" "Qe,0,Qe,e")))]
  "TARGET_COND_MOVE
   && (GET_CODE (operands[0]) != MEM
       || GET_CODE (operands[3]) == REG
       || GET_CODE (operands[4]) == REG)"
  "* return emit_cond_move (operands, insn);"
  [(set_attr "type" "long,long,long,long")
   (set_attr "length" "2,2,4,4")])


;;
;;  ....................
;;
;;	Conditional execution
;;
;;  ....................

(define_insn "*cond_exec_qi_store"
  [(cond_exec
    (match_operator 0 "f0_compare_operator"
		    [(match_operand:CC 1 "f0_operand" "")
		     (const_int 0)])
    (set (match_operand:QI 2 "short_memory_operand" "=Q,Q")
	 (match_operand:QI 3 "reg_or_0_operand" "d,O")))]
  ""
  "@
   stb %3,%M2 || exef0%F0
   stb %.,%M2 || exef0%F0"
  [(set_attr "type" "long")
   (set_attr "length" "2")])

(define_insn "*cond_exec_qi_load"
  [(cond_exec
    (match_operator 0 "f0_compare_operator"
		    [(match_operand:CC 1 "f0_operand" "")
		     (const_int 0)])
    (set (match_operand:QI 2 "gpr_operand" "=d,d,d")
	 (match_operand:QI 3 "cond_exec_operand" "d,L,Q")))]
  ""
  "@
   exef0%F0 || mv %2,%3
   exef0%F0 || ldi %2,%3
   ldub %2,%M3 || exef0%F0"
  [(set_attr "type" "long")
   (set_attr "length" "2")])

(define_insn "*cond_exec_hi_binary"
  [(cond_exec
    (match_operator 0 "f0_compare_operator"
		    [(match_operand:CC 1 "f0_operand" "")
		     (const_int 0)])
    (set (match_operand:HI 2 "gpr_operand" "=d")
	 (match_operator:HI 3 "binary_parallel_operator"
			    [(match_operand:HI 4 "gpr_operand" "2")
			     (match_operand:HI 5 "arith16_operand" "di")])))]
  "rtx_equal_p (operands[2], operands[4])"
  "*
{
  if (GET_CODE (operands[5]) == REG || GET_CODE (operands[5]) == SUBREG)
    switch (GET_CODE (operands[3]))
      {
      case PLUS:	return \"exef0%F0 || add %2,%5\";
      case MINUS:	return \"exef0%F0 || sub %2,%5\";
      case MULT:	return \"exef0%F0 || mul %2,%5\";
      case AND:		return \"exef0%F0 || and %2,%5\";
      case IOR:		return \"exef0%F0 || or %2,%5\";
      case XOR:		return \"exef0%F0 || xor %2,%5\";
      case ASHIFT:	return \"exef0%F0 || sll %2,%5\";
      case ASHIFTRT:	return \"exef0%F0 || sra %2,%5\";
      case LSHIFTRT:	return \"exef0%F0 || srl %2,%5\";
      default: break;
      }

  else if (GET_CODE (operands[5]) == CONST_INT)
    {
      HOST_WIDE_INT value = INTVAL (operands[5]);
      int log;

      switch (GET_CODE (operands[3]))
	{
	case PLUS:
	  if (IN_RANGE_P (value, 1, 16))
	    return \"exef0%F0 || addi %2,%5\";

	  else if (IN_RANGE_P (value, -16, -1))
	    return \"exef0%F0 || subi %2,%n5\";

	  else if (value == 0)
	    return \"\";

	  else
	    break;

	case MINUS:
	  if (IN_RANGE_P (value, 1, 16))
	    return \"exef0%F0 || subi %2,%5\";

	  else if (IN_RANGE_P (value, -16, -1))
	    return \"exef0%F0 || addi %2,%n5\";

	  else if (value == 0)
	    return \"\";

	  else
	    break;

	case IOR:
	case XOR:
	  if (value == 0)
	    return \"\";

	  log = exact_log2_wide (value);
	  if (IN_RANGE_P (log, 0, 15))
	    {
	      operands[6] = GEN_INT (15 - log);
	      return ((GET_CODE (operands[3]) == IOR)
		      ? \"exef0%F0 || bseti %2,%6\"
		      : \"exef0%F0 || bnoti %2,%6\");
	    }
	  break;

	case AND:
	  if ((value & 0xffff) == 0xffff)
	    return \"\";

	  log = exact_log2_wide (~value);
	  if (IN_RANGE_P (log, 0, 15))
	    {
	      operands[6] = GEN_INT (15 - log);
	      return \"exef0%F0 || bclri %2,%6\";
	    }
	  break;
	default: break;
	}
    }

  fatal_insn (\"cond_exec_hi_binary\", insn);
  return \"\";
}"
  [(set_attr "type" "long")
   (set_attr "length" "2")])

(define_insn "*cond_exec_hi_unary"
  [(cond_exec
    (match_operator 0 "f0_compare_operator"
		    [(match_operand:CC 1 "f0_operand" "")
		     (const_int 0)])
    (set (match_operand:HI 2 "gpr_operand" "=d")
	 (match_operator:HI 3 "unary_parallel_operator"
			    [(match_operand:HI 4 "gpr_operand" "2")])))]
  "rtx_equal_p (operands[2], operands[4])"
  "*
{
  switch (GET_CODE (operands[3]))
    {
    default: break;
    case NEG:		return \"exef0%F0 || neg %2\";
    case NOT:		return \"exef0%F0 || not %2\";
      break;
    }

  fatal_insn (\"cond_exec_hi_unary\", insn);
  return \"\";
}"
  [(set_attr "type" "long")
   (set_attr "length" "2")])

(define_insn "*cond_exec_hi_abs"
  [(cond_exec
    (match_operator 0 "f0_compare_operator"
		    [(match_operand:CC 1 "f0_operand" "")
		     (const_int 0)])
    (parallel
     [(set (match_operand:HI 2 "gpr_operand" "=d")
	   (abs:HI (match_operand:HI 3 "gpr_operand" "2")))
      (clobber (match_operand:CC 4 "f0_operand" ""))]))]
  "rtx_equal_p (operands[2], operands[3])"
  "exef0%F0 || abs %2"
  [(set_attr "type" "long")
   (set_attr "length" "2")])

(define_insn "*cond_exec_hi_minmax"
  [(cond_exec
    (match_operator 0 "f0_compare_operator"
		    [(match_operand:CC 1 "f0_operand" "")
		     (const_int 0)])
    (parallel
     [(set (match_operand:HI 2 "gpr_operand" "=d")
	   (match_operator:HI 3 "minmax_parallel_operator"
			      [(match_operand:HI 4 "gpr_operand" "%0")
			       (match_operand:HI 5 "gpr_operand" "d")]))
      (clobber (match_operand:CC 6 "f0_operand" ""))]))]
  "rtx_equal_p (operands[2], operands[4])"
  "*
{
  if (GET_CODE (operands[3]) == SMIN)
    return \"exef0%F0 || min %2,%5\";
  else
    return \"exef0%F0 || max %2,%5\";
}"
  [(set_attr "type" "long")
   (set_attr "length" "2")])

(define_insn "*cond_exec_hi_extend"
  [(cond_exec
    (match_operator 0 "f0_compare_operator"
		    [(match_operand:CC 1 "f0_operand" "")
		     (const_int 0)])
    (set (match_operand:HI 2 "gpr_operand" "=d,d")
	 (match_operator:HI 3 "extend_parallel_operator"
			    [(match_operand:QI 4 "reg_or_short_memory_operand" "d,Q")])))]
  ""
  "@
   exef0%F0 || mv%u3b %2,%4
   ld%u3b %2,%M4 || exef0%F0"
  [(set_attr "type" "long")
   (set_attr "length" "2")])

(define_insn "*cond_exec_hi_store"
  [(cond_exec
    (match_operator 0 "f0_compare_operator"
		    [(match_operand:CC 1 "f0_operand" "")
		     (const_int 0)])
    (set (match_operand:HI 2 "short_memory_operand" "=Q,Q")
	 (match_operand:HI 3 "reg_or_0_operand" "d,O")))]
  ""
  "@
   st %3,%M2 || exef0%F0
   st %.,%M2 || exef0%F0"
  [(set_attr "type" "long")
   (set_attr "length" "2")])

(define_insn "*cond_exec_hi_load"
  [(cond_exec
    (match_operator 0 "f0_compare_operator"
		    [(match_operand:CC 1 "f0_operand" "")
		     (const_int 0)])
    (set (match_operand:HI 2 "gpr_operand" "=d,d,d")
	 (match_operand:HI 3 "cond_exec_operand" "d,L,Q")))]
  ""
  "@
   exef0%F0 || mv %2,%3
   exef0%F0 || ldi %2,%3
   ld %2,%M3 || exef0%F0"
  [(set_attr "type" "long")
   (set_attr "length" "2")])

(define_insn "*cond_exec_si_binary"
  [(cond_exec
    (match_operator 0 "f0_compare_operator"
		    [(match_operand:CC 1 "f0_operand" "")
		     (const_int 0)])
    (set (match_operand:SI 2 "gpr_operand" "=e")
	 (match_operator:SI 3 "binary_parallel_operator"
			    [(match_operand:SI 4 "gpr_operand" "2")
			     (match_operand:SI 5 "gpr_operand" "e")])))]
  "rtx_equal_p (operands[2], operands[5])"
  "*
{
  if (GET_CODE (operands[2]) == REG || GET_CODE (operands[2]) == SUBREG)
    switch (GET_CODE (operands[3]))
      {
      case PLUS:  return \"exef0%F0 || add2w %2,%5\";
      case MINUS: return \"exef0%F0 || sub2w %2,%5\";
      default: break;
      }

  fatal_insn (\"cond_exec_si_binary\", insn);
  return \"\";
}"
  [(set_attr "type" "long")
   (set_attr "length" "2")])

(define_insn "*cond_exec_si_store"
  [(cond_exec
    (match_operator 0 "f0_compare_operator"
		    [(match_operand:CC 1 "f0_operand" "")
		     (const_int 0)])
    (set (match_operand:SI 2 "short_memory_operand" "=Q")
	 (match_operand:SI 3 "gpr_operand" "e")))]
  ""
  "st2w %3,%M2 || exef0%F0"
  [(set_attr "type" "long")
   (set_attr "length" "2")])

(define_insn "*cond_exec_si_load"
  [(cond_exec
    (match_operator 0 "f0_compare_operator"
		    [(match_operand:CC 1 "f0_operand" "")
		     (const_int 0)])
    (set (match_operand:SI 2 "gpr_operand" "=e,e")
	 (match_operand:SI 3 "cond_exec_operand" "e,Q")))]
  ""
  "@
   exef0%F0 || mv2w %2,%3
   ld2w %2,%M3 || exef0%F0"
  [(set_attr "type" "long")
   (set_attr "length" "2")])

(define_insn "*cond_exec_sf_store"
  [(cond_exec
    (match_operator 0 "f0_compare_operator"
		    [(match_operand:CC 1 "f0_operand" "")
		     (const_int 0)])
    (set (match_operand:SF 2 "short_memory_operand" "=Q")
	 (match_operand:SF 3 "gpr_operand" "e")))]
  ""
  "st2w %3,%M2 || exef0%F0"
  [(set_attr "type" "long")
   (set_attr "length" "2")])

(define_insn "*cond_exec_sf_load"
  [(cond_exec
    (match_operator 0 "f0_compare_operator"
		    [(match_operand:CC 1 "f0_operand" "")
		     (const_int 0)])
    (set (match_operand:SF 2 "gpr_operand" "=e,e")
	 (match_operand:SF 3 "cond_exec_operand" "e,Q")))]
  ""
  "@
   exef0%F0 || mv2w %2,%3
   ld2w %2,%M3 || exef0%F0"
  [(set_attr "type" "long")
   (set_attr "length" "2")])

;; (define_insn "*cond_exec_call"
;;   [(cond_exec
;;     (match_operator 0 "f0_compare_operator"
;; 		    [(match_operand:CC 1 "f0_operand" "")
;; 		     (const_int 0)])
;;     (parallel [(call (mem:HI (match_operand:HI 2 "gpr_operand" "d"))
;; 		     (match_operand 3 "" "i"))
;; 	       (clobber (match_scratch:HI 4 "=l"))]))]			;; return address, r13
;;   ""
;;   "jl %2 || exef0%F0"
;;   [(set_attr "type" "long")
;;    (set_attr "length" "2")])
;; 
;; (define_insn "*cond_exec_call_value"
;;   [(cond_exec
;;     (match_operator 0 "f0_compare_operator"
;; 		    [(match_operand:CC 1 "f0_operand" "")
;; 		     (const_int 0)])
;;     (parallel [(set (match_operand 2 "gpr_operand" "=r")
;; 		    (call (mem:HI (match_operand:HI 3 "gpr_operand" "d"))
;; 			  (match_operand 4 "" "i")))
;; 	       (clobber (match_scratch:HI 5 "=l"))]))]			;; return address, r13
;;   ""
;;   "jl %3 || exef0%F0"
;;   [(set_attr "type" "long")
;;    (set_attr "length" "2")])


;;
;;  ....................
;;
;;	Conditional branches
;;
;;  ....................

(define_expand "beq"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "d10v_expand_branch (EQ, operands[0]); DONE;")

(define_expand "bne"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "d10v_expand_branch (NE, operands[0]); DONE;")

(define_expand "bgt"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "d10v_expand_branch (GT, operands[0]); DONE;")

(define_expand "bge"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "d10v_expand_branch (GE, operands[0]); DONE;")

(define_expand "blt"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "d10v_expand_branch (LT, operands[0]); DONE;")

(define_expand "ble"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "d10v_expand_branch (LE, operands[0]); DONE;")

(define_expand "bgtu"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "d10v_expand_branch (GTU, operands[0]); DONE;")

(define_expand "bgeu"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "d10v_expand_branch (GEU, operands[0]); DONE;")

(define_expand "bltu"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "d10v_expand_branch (LTU, operands[0]); DONE;")

(define_expand "bleu"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "d10v_expand_branch (LEU, operands[0]); DONE;")

(define_insn "*cond_branch_0"
  [(set (pc)
	(if_then_else (match_operator:CC 0 "f0_compare_operator"
					 [(match_operand:CC 1 "f0_operand" "")
					  (const_int 0)])
		      (label_ref (match_operand 2 "" ""))
		      (pc)))]
  ""
  "*
{
    return (GET_CODE (operands[2]) == RETURN) ? \"jmp r13 || exef0%F0\" : \"brf0%F0 %l2\";
}"
  [(set_attr "type" "long")
   (set_attr "length" "2")])


;;
;;  ....................
;;
;;	Set from condition code
;;
;;  ....................

(define_expand "seq"
  [(set (match_operand:HI 0 "gpr_operand" "")
	(match_dup 1))]
  ""
  "d10v_expand_setcc (EQ, operands[0]); DONE;")

(define_expand "sne"
  [(set (match_operand:HI 0 "gpr_operand" "")
	(match_dup 1))]
  ""
  "d10v_expand_setcc (NE, operands[0]); DONE;")

(define_expand "sgt"
  [(set (match_operand:HI 0 "gpr_operand" "")
	(match_dup 1))]
  ""
  "d10v_expand_setcc (GT, operands[0]); DONE;")

(define_expand "sge"
  [(set (match_operand:HI 0 "gpr_operand" "")
	(match_dup 1))]
  ""
  "d10v_expand_setcc (GE, operands[0]); DONE;")

(define_expand "slt"
  [(set (match_operand:HI 0 "gpr_operand" "")
	(match_dup 1))]
  ""
  "d10v_expand_setcc (LT, operands[0]); DONE;")

(define_expand "sle"
  [(set (match_operand:HI 0 "gpr_operand" "")
	(match_dup 1))]
  ""
  "d10v_expand_setcc (LE, operands[0]); DONE;")

(define_expand "sgtu"
  [(set (match_operand:HI 0 "gpr_operand" "")
	(match_dup 1))]
  ""
  "d10v_expand_setcc (GTU, operands[0]); DONE;")

(define_expand "sgeu"
  [(set (match_operand:HI 0 "gpr_operand" "")
	(match_dup 1))]
  ""
  "d10v_expand_setcc (GEU, operands[0]); DONE;")

(define_expand "sltu"
  [(set (match_operand:HI 0 "gpr_operand" "")
	(match_dup 1))]
  ""
  "d10v_expand_setcc (LTU, operands[0]); DONE;")

(define_expand "sleu"
  [(set (match_operand:HI 0 "gpr_operand" "")
	(match_dup 1))]
  ""
  "d10v_expand_setcc (LEU, operands[0]); DONE;")

(define_insn "*scc"
  [(set (match_operand:HI 0 "gpr_operand" "=d")
	(match_operator:VOID 1 "f0_compare_operator"
			[(match_operand:CC 2 "f0_operand" "")
			 (const_int 0)]))]
  ""
  "setf0%F1 %0"
  [(set_attr "type" "mu")
   (set_attr "length" "1")])


;;
;;  ....................
;;
;;	Data conversion
;;
;;  ....................

(define_insn "zero_extendqihi2"
  [(set (match_operand:HI 0 "gpr_operand" "=d,d,d")
	(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "d,Q,m")))]
  ""
  "@
   mvub %0,%1
   ldub %0,%M1
   ldub %0,%M1"
  [(set_attr "type" "iu,mu,long")
   (set_attr "length" "1,1,2")])

(define_insn "zero_extendqisi2"
  [(set (match_operand:SI 0 "gpr_operand" "=d,d,d")
	(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "d,Q,m")))]
  ""
  "@
   mvub %L0,%1\;ldi %U0,0
   ldub %L0,%M1\;ldi %U0,0
   ldub %L0,%M1\;ldi %U0,0"
  [(set_attr "type" "long,long,long")
   (set_attr "length" "2,2,3")])

(define_split
  [(set (match_operand:SI 0 "gpr_operand" "")
	(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))]
  "reload_completed"
  [(set (match_dup 3) (zero_extend:HI (match_dup 1)))
   (set (match_dup 2) (const_int 0))]
  "
{
  operands[2] = d10v_subword (operands[0], 0, HImode, SImode);
  operands[3] = d10v_subword (operands[0], 1, HImode, SImode);
}")

(define_insn "zero_extendhisi2"
  [(set (match_operand:SI 0 "gpr_operand" "=e,e,e")
	(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "e,Q,m")))]
  ""
  "@
   mv %L0,%1\;ldi %U0,0
   ld %L0,%M1\;ldi %U0,0
   ld %L0,%M1\;ldi %U0,0"
  [(set_attr "type" "long,long,long")
   (set_attr "length" "2,2,3")])

(define_split
  [(set (match_operand:SI 0 "gpr_operand" "")
	(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))]
  "reload_completed"
  [(set (match_dup 3) (match_dup 1))
   (set (match_dup 2) (const_int 0))]
  "
{
  operands[2] = d10v_subword (operands[0], 0, HImode, SImode);
  operands[3] = d10v_subword (operands[0], 1, HImode, SImode);
}")

(define_insn "extendqihi2"
  [(set (match_operand:HI 0 "gpr_operand" "=d,d,d")
	(sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "d,Q,m")))]
  ""
  "@
   mvb %0,%1
   ldb %0,%M1
   ldb %0,%M1"
  [(set_attr "type" "iu,mu,long")
   (set_attr "length" "1,1,2")])

(define_insn "extendqisi2"
  [(set (match_operand:SI 0 "gpr_operand" "=e,e,e")
	(sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "e,Q,m")))]
  ""
  "@
   mvb %L0,%1\;mv %U0,%L0\;srai %U0,15
   ldb %L0,%M1\;mv %U0,%L0\;srai %U0,15
   ldb %L0,%M1\;mv %U0,%L0\;srai %U0,15"
  [(set_attr "type" "long,long,long")
   (set_attr "length" "3,3,4")])

(define_insn "extendhisi2"
  [(set (match_operand:SI 0 "gpr_operand" "=e,e,e,a")
	(sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "e,Q,m,e")))]
  ""
  "*
{
  if (ACCUM_P (REGNO (operands[0])))
    return \"mvtaclo %1,%0\";

  if (GET_CODE (operands[1]) == MEM)
    return \"ld %L0,%M1\;mv %U0,%L0\;srai %U0,15\";

  if (REGNO (operands[0]) == REGNO (operands[1]))
    return \"mv %L0,%1\;srai %U0,15\";

  return \"mv %L0,%1\;mv %U0,%L0\;srai %U0,15\";
}"
  [(set_attr "type" "long,long,long,iu")
   (set_attr "length" "3,3,4,1")])



;;
;;  ....................
;;
;;	Addition
;;
;;  ....................

(define_expand "addhi3"
  [(set (match_operand:HI 0 "gpr_operand" "")
	(plus:HI (match_operand:HI 1 "gpr_operand" "")
		 (match_operand:HI 2 "arith16_operand" "")))]
  ""
  "")

(define_insn "*addhi3_no_small_insns"
  [(set (match_operand:HI 0 "gpr_operand" "=d,d,d,d")
	(plus:HI (match_operand:HI 1 "gpr_operand" "%0,0,0,d")
		 (match_operand:HI 2 "arith16_operand" "d,I,N,n")))]
  "TARGET_NO_SMALL_INSNS || !optimize"
  "@
   add %0,%2
   addi %0,%2
   subi %0,%n2
   add3 %0,%1,%2"
  [(set_attr "type" "either,either,either,long")
   (set_attr "length" "1,1,1,2")])

(define_insn "*addhi3_small_insns"
  [(set (match_operand:HI 0 "gpr_operand" "=d,d,d,d,d,d")
	(plus:HI (match_operand:HI 1 "gpr_operand" "%0,0,0,d,d,d")
		 (match_operand:HI 2 "arith16_operand" "d,I,N,I,N,n")))]
  "TARGET_SMALL_INSNS && optimize"
  "@
   add %0,%2
   addi %0,%2
   subi %0,%n2
   mv %0,%1\;addi %0,%2
   mv %0,%1\;subi %0,%n2
   add3 %0,%1,%2"
  [(set_attr "type" "either,either,either,long,long,long")
   (set_attr "length" "1,1,1,2,2,2")])

(define_split
  [(set (match_operand:HI 0 "gpr_operand" "")
	(plus:HI (match_operand:HI 1 "gpr_operand" "")
		 (match_operand:HI 2 "const_int_operand" "")))]
  "reload_completed && TARGET_SMALL_INSNS && optimize
   && REGNO (operands[0]) != REGNO (operands[1])
   && IN_RANGE_P (INTVAL (operands[2]), -16, 16)
   && INTVAL (operands[2]) != 0"
  [(set (match_dup 0) (match_dup 1))
   (set (match_dup 0) (plus:HI (match_dup 0) (match_dup 2)))]
  "")

(define_expand "addsi3"
  [(set (match_operand:SI 0 "register_operand" "")
	(plus:SI (match_operand:SI 1 "register_operand" "")
		 (match_operand:SI 2 "register_operand" "")))]
  ""
  "")

(define_insn "*addsi3_noaccum"
  [(set (match_operand:SI 0 "gpr_operand" "=e")
	(plus:SI (match_operand:SI 1 "gpr_operand" "%0")
		 (match_operand:SI 2 "gpr_operand" "e")))]
  "!TARGET_ACCUM"
  "add2w %0,%2"
  [(set_attr "type" "iu")
   (set_attr "length" "1")])

(define_insn "*addsi3_noaddac3"
  [(set (match_operand:SI 0 "register_operand" "=e,a")
	(plus:SI (match_operand:SI 1 "register_operand" "%0,0")
		 (match_operand:SI 2 "register_operand" "e,ea")))]
  "TARGET_ACCUM && !TARGET_ADDAC3"
  "@
   add2w %0,%2
   add %0,%2"
  [(set_attr "type" "iu")
   (set_attr "length" "1")])

(define_insn "*addsi3_addac3"
  [(set (match_operand:SI 0 "register_operand" "=e,e,a")
	(plus:SI (match_operand:SI 1 "register_operand" "%0,ea,0")
		 (match_operand:SI 2 "register_operand" "e,a,ea")))]
  "TARGET_ACCUM && TARGET_ADDAC3"
  "@
   add2w %0,%2
   addac3 %0,%1,%2
   add %0,%2"
  [(set_attr "type" "iu")
   (set_attr "length" "1")])


;;
;;  ....................
;;
;;	Subtraction
;;
;;  ....................

(define_expand "subhi3"
  [(set (match_operand:HI 0 "gpr_operand" "")
	(minus:HI (match_operand:HI 1 "gpr_operand" "")
		  (match_operand:HI 2 "arith16_operand" "")))]
  ""
  "")

(define_insn "*subhi3_no_small_insns"
  [(set (match_operand:HI 0 "gpr_operand" "=d,d,d,d")
	(minus:HI (match_operand:HI 1 "gpr_operand" "0,0,0,d")
		  (match_operand:HI 2 "arith16_operand" "d,I,N,i")))]
  "TARGET_NO_SMALL_INSNS || !optimize"
  "@
   sub %0,%2
   subi %0,%2
   addi %0,%n2
   add3 %0,%1,%n2"
  [(set_attr "type" "either,either,either,long")
   (set_attr "length" "1,1,1,2")])

(define_insn "*subhi3_small_insns"
  [(set (match_operand:HI 0 "gpr_operand" "=d,d,d,d,d,d")
	(minus:HI (match_operand:HI 1 "gpr_operand" "0,0,0,d,d,d")
		  (match_operand:HI 2 "arith16_operand" "d,I,N,I,N,i")))]
  "TARGET_SMALL_INSNS && optimize"
  "@
   sub %0,%2
   subi %0,%2
   addi %0,%n2
   mv %0,%1\;subi %0,%2
   mv %0,%1\;addi %0,%n2
   add3 %0,%1,%n2"
  [(set_attr "type" "either,either,either,long,long,long")
   (set_attr "length" "1,1,1,2,2,2")])

(define_split
  [(set (match_operand:HI 0 "gpr_operand" "")
	(minus:HI (match_operand:HI 1 "gpr_operand" "")
		  (match_operand:HI 2 "const_int_operand" "")))]
  "reload_completed && TARGET_SMALL_INSNS && optimize
   && REGNO (operands[0]) != REGNO (operands[1])
   && IN_RANGE_P (INTVAL (operands[2]), -16, 16)
   && INTVAL (operands[2]) != 0"
  [(set (match_dup 0) (match_dup 1))
   (set (match_dup 0) (minus:HI (match_dup 0) (match_dup 2)))]
  "")


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

(define_insn "*subsi3_noaccum"
  [(set (match_operand:SI 0 "gpr_operand" "=e")
	(minus:SI (match_operand:SI 1 "gpr_operand" "0")
		  (match_operand:SI 2 "gpr_operand" "e")))]
  "!TARGET_ACCUM"
  "sub2w %0,%2"
  [(set_attr "type" "iu")
   (set_attr "length" "1")])

(define_insn "*subsi3_noaddac3"
  [(set (match_operand:SI 0 "register_operand" "=e,a")
	(minus:SI (match_operand:SI 1 "register_operand" "0,0")
		 (match_operand:SI 2 "register_operand" "e,ea")))]
  "TARGET_ACCUM && !TARGET_ADDAC3"
  "@
   sub2w %0,%2
   sub %0,%2"
  [(set_attr "type" "iu")
   (set_attr "length" "1")])

(define_insn "*subsi3_addac3"
  [(set (match_operand:SI 0 "register_operand" "=e,e,a")
	(minus:SI (match_operand:SI 1 "register_operand" "0,ea,0")
		  (match_operand:SI 2 "register_operand" "e,a,ea")))]
  "TARGET_ACCUM && TARGET_ADDAC3"
  "@
   sub2w %0,%2
   subac3 %0,%1,%2
   sub %0,%2"
  [(set_attr "type" "iu")
   (set_attr "length" "1")])


;;
;;  ....................
;;
;;	Negation
;;
;;  ....................

(define_insn "neghi2"
  [(set (match_operand:HI 0 "gpr_operand" "=d")
	(neg:HI (match_operand:HI 1 "gpr_operand" "0")))]
  ""
  "neg %0"
  [(set_attr "type" "either")
   (set_attr "length" "1")])

(define_expand "negsi2"
  [(parallel [(set (match_operand:SI 0 "register_operand" "")
		   (neg:SI (match_operand:SI 1 "register_operand" "")))
	      (clobber (match_dup 2))])]
  ""
  "operands[2] = gen_rtx (REG, CCmode, F0_REGNUM);")

(define_insn "*negsi2_internal"
  [(set (match_operand:SI 0 "register_operand" "=a,e")
	(neg:SI (match_operand:SI 1 "register_operand" "0,0")))
   (clobber (match_operand:CC 2 "f0_operand" ""))]
  ""
  "@
   neg %0
   not %U0\;neg %L0\;cmpeqi %L0,0\;exef0t || addi %U0,1"
  [(set_attr "type" "iu,long")
   (set_attr "length" "1,6")])


;;
;;  ....................
;;
;;	Multiplication
;;
;;  ....................

(define_insn "mulhi3"
  [(set (match_operand:HI 0 "gpr_operand" "=d")
	(mult:HI (match_operand:HI 1 "gpr_operand" "%0")
		 (match_operand:HI 2 "gpr_operand" "d")))]
  ""
  "mul %0,%2"
  [(set_attr "type" "iu")
   (set_attr "length" "1")])

(define_insn "*mulhisi3_add"
  [(set (match_operand:SI 0 "accum_operand" "=a")
	(plus:SI (mult:SI (sign_extend:SI (match_operand:HI 1 "gpr_operand" "%d"))
			  (sign_extend:SI (match_operand:HI 2 "gpr_operand" "d")))
		 (match_operand:SI 3 "register_operand" "0")))]
  "TARGET_ACCUM"
  "mac %0,%1,%2"
  [(set_attr "type" "iu")
   (set_attr "length" "1")])

(define_insn "mulhisi3"
  [(set (match_operand:SI 0 "accum_operand" "=a")
	(mult:SI (sign_extend:SI (match_operand:HI 1 "gpr_operand" "%d"))
		 (sign_extend:SI (match_operand:HI 2 "gpr_operand" "d"))))]
  "TARGET_ACCUM"
  "mulx %0,%1,%2"
  [(set_attr "type" "iu")
   (set_attr "length" "1")])

(define_insn "*umulhisi3_add"
  [(set (match_operand:SI 0 "accum_operand" "=a")
	(plus:SI (mult:SI (zero_extend:SI (match_operand:HI 1 "gpr_operand" "%d"))
			  (zero_extend:SI (match_operand:HI 2 "gpr_operand" "d")))
		 (match_operand:SI 3 "register_operand" "0")))]
  "TARGET_ACCUM"
  "macu %0,%1,%2"
  [(set_attr "type" "iu")
   (set_attr "length" "1")])

(define_insn "umulhisi3"
  [(set (match_operand:SI 0 "accum_operand" "=a")
	(mult:SI (zero_extend:SI (match_operand:HI 1 "gpr_operand" "%d"))
		 (zero_extend:SI (match_operand:HI 2 "gpr_operand" "d"))))]
  "TARGET_ACCUM"
  "mulxu %0,%1,%2"
  [(set_attr "type" "iu")
   (set_attr "length" "1")])

(define_insn "*mulhisi3_mixed_add1"
  [(set (match_operand:SI 0 "accum_operand" "=a")
	(plus:SI (mult:SI (sign_extend:SI (match_operand:HI 1 "gpr_operand" "%d"))
			  (zero_extend:SI (match_operand:HI 2 "gpr_operand" "d")))
		 (match_operand:SI 3 "register_operand" "0")))]
  "TARGET_ACCUM"
  "macsu %0,%1,%2"
  [(set_attr "type" "iu")
   (set_attr "length" "1")])

(define_insn "*mulhisi3_mixed1"
  [(set (match_operand:SI 0 "accum_operand" "=a")
	(mult:SI (sign_extend:SI (match_operand:HI 1 "gpr_operand" "%d"))
		 (zero_extend:SI (match_operand:HI 2 "gpr_operand" "d"))))]
  "TARGET_ACCUM"
  "mulxsu %0,%1,%2"
  [(set_attr "type" "iu")
   (set_attr "length" "1")])

(define_insn "*mulhisi3_mixed_add2"
  [(set (match_operand:SI 0 "accum_operand" "=a")
	(plus:SI (mult:SI (zero_extend:SI (match_operand:HI 1 "gpr_operand" "%d"))
			  (sign_extend:SI (match_operand:HI 2 "gpr_operand" "d")))
		 (match_operand:SI 3 "register_operand" "0")))]
  "TARGET_ACCUM"
  "macsu %0,%2,%1"
  [(set_attr "type" "iu")
   (set_attr "length" "1")])

(define_insn "*mulhisi3_mixed2"
  [(set (match_operand:SI 0 "accum_operand" "=a")
	(mult:SI (zero_extend:SI (match_operand:HI 1 "gpr_operand" "%d"))
		 (sign_extend:SI (match_operand:HI 2 "gpr_operand" "d"))))]
  "TARGET_ACCUM"
  "mulxsu %0,%2,%1"
  [(set_attr "type" "iu")
   (set_attr "length" "1")])

(define_insn "mulsi3"
  [(set (match_operand:SI 0 "accum_operand" "=a")
	(mult:SI (match_operand:SI 1 "gpr_operand" "e")
		 (match_operand:SI 2 "gpr_operand" "e")))]
  "TARGET_ACCUM"
  "#"
  [(set_attr "type" "long")
   (set_attr "length" "8")])

(define_split
  [(set (match_operand:SI 0 "register_operand" "")
	(mult:SI (match_operand:SI 1 "gpr_operand" "")
		 (match_operand:SI 2 "gpr_operand" "")))]
  "TARGET_ACCUM && reload_completed"
  [(set (match_dup 0)
	(mult:SI (zero_extend:SI (match_dup 3))
		 (zero_extend:SI (match_dup 6))))
   (set (match_dup 0)
	(plus:SI (mult:SI (zero_extend:SI (match_dup 4))
			  (zero_extend:SI (match_dup 5)))
		 (match_dup 0)))
   (set (match_dup 0)
	(ashift:SI (match_dup 0)
		   (const_int 16)))
   (set (match_dup 0)
	(plus:SI (mult:SI (zero_extend:SI (match_dup 4))
			  (zero_extend:SI (match_dup 6)))
		 (match_dup 0)))]
  "
{
  operands[3] = d10v_subword (operands[1], 0, HImode, SImode);
  operands[4] = d10v_subword (operands[1], 1, HImode, SImode);

  operands[5] = d10v_subword (operands[2], 0, HImode, SImode);
  operands[6] = d10v_subword (operands[2], 1, HImode, SImode);
}")


;;
;;  ....................
;;
;;	Division
;;
;;  ....................

(define_expand "divmodhi4"
  [(parallel [(set (match_operand:HI 0 "gpr_operand" "")
		   (div:HI (match_operand:HI 1 "general_operand" "")
			   (match_operand:HI 2 "general_operand" "")))
	      (set (match_operand:HI 3 "gpr_operand" "")
		   (mod:HI (match_dup 1)
			   (match_dup 2)))])]
  ""
  "
{
  d10v_expand_divmod (operands, FALSE);
  DONE;
}")

(define_expand "udivmodhi4"
  [(parallel [(set (match_operand:HI 0 "gpr_operand" "")
		   (udiv:HI (match_operand:HI 1 "general_operand" "")
			    (match_operand:HI 2 "general_operand" "")))
	      (set (match_operand:HI 3 "gpr_operand" "")
		   (umod:HI (match_dup 1)
			    (match_dup 2)))])]
  ""
  "
{
  d10v_expand_divmod (operands, TRUE);
  DONE;
}")


;;
;;  ....................
;;
;;	Logical operations
;;
;;  ....................

(define_expand "andhi3"
  [(set (match_operand:HI 0 "gpr_operand" "")
	(and:HI (match_operand:HI 1 "gpr_operand" "")
		(match_operand:HI 2 "arith16_operand" "")))]
  ""
  "")

(define_insn "*andhi3_register"
  [(set (match_operand:HI 0 "gpr_operand" "=d")
	(and:HI (match_operand:HI 1 "gpr_operand" "%0")
		(match_operand:HI 2 "gpr_operand" "d")))]
  ""
  "and %0,%2"
  [(set_attr "type" "either")
   (set_attr "length" "1")])

(define_insn "*andhi3_move"
  [(set (match_operand:HI 0 "gpr_operand" "=d")
	(and:HI (match_operand:HI 1 "gpr_operand" "%d")
		(match_operand:HI 2 "const_int_operand" "n")))]
  "(INTVAL (operands[2]) & 0xffff) == 0xffff"
  "mv %0,%1"
  [(set_attr "type" "either")
   (set_attr "length" "1")])

(define_insn "*andhi3_constant"
  [(set (match_operand:HI 0 "gpr_operand" "=d,d,d")
	(and:HI (match_operand:HI 1 "gpr_operand" "%d,0,d")
		(match_operand:HI 2 "const_int_operand" "O,J,n")))]
  ""
  "*
{
  HOST_WIDE_INT value = INTVAL (operands[2]);

  if (value == 0)
    return \"ldi %0,0\";

  if ((value & 0xffff) == 0xffff)
    return \"mv %0,%1\";

  if (IN_RANGE_P (exact_log2_wide (~value), 0, 15))
    {
      if (REGNO (operands[0]) == REGNO (operands[1]))
	return \"bclri %0,%b2\";

      if (TARGET_SMALL_INSNS && optimize)
	return \"mv %0,%1\;bclri %0,%b2\";
    }

  return \"and3 %0,%1,%2\";
}"
  [(set_attr "type" "either,iu,long")
   (set_attr "length" "1,1,2")])

(define_split
  [(set (match_operand:HI 0 "gpr_operand" "")
	(and:HI (match_operand:HI 1 "gpr_operand" "")
		(match_operand:HI 2 "const_int_operand" "")))]
  "reload_completed && TARGET_SMALL_INSNS && optimize
   && !rtx_equal_p (operands[0], operands[1])
   && IN_RANGE_P (exact_log2_wide (~ INTVAL (operands[2])), 0, 15)"
  [(set (match_dup 0) (match_dup 1))
   (set (match_dup 0) (and:HI (match_dup 0) (match_dup 2)))]
  "")

(define_insn "andsi3"
  [(set (match_operand:SI 0 "gpr_operand" "=e,e,e")
	(and:SI (match_operand:SI 1 "gpr_operand" "%0,0,?e")
		(match_operand:SI 2 "arith32_operand" "e,n,n")))]
  ""
  "#"
  [(set_attr "type" "long,long,long")
   (set_attr "length" "2,4,4")])

(define_split
  [(set (match_operand:SI 0 "gpr_operand" "")
	(and:SI (match_operand:SI 1 "gpr_operand" "")
		(match_operand:SI 2 "arith32_operand" "")))]
  "reload_completed"
  [(match_dup 3)]
  "operands[3] = d10v_split_logical_op (operands, AND);")

(define_expand "iorhi3"
  [(set (match_operand:HI 0 "gpr_operand" "")
	(ior:HI (match_operand:HI 1 "gpr_operand" "")
		(match_operand:HI 2 "arith16_operand" "")))]
  ""
  "")

(define_insn "*iorhi3_register"
  [(set (match_operand:HI 0 "gpr_operand" "=d")
	(ior:HI (match_operand:HI 1 "gpr_operand" "%0")
		(match_operand:HI 2 "gpr_operand" "d")))]
  ""
  "or %0,%2"
  [(set_attr "type" "either")
   (set_attr "length" "1")])

(define_insn "*iorhi3_neg1"
  [(set (match_operand:HI 0 "gpr_operand" "=d")
	(ior:HI (match_operand:HI 1 "gpr_operand" "d")
		(match_operand:HI 2 "const_int_operand" "n")))]
  "(INTVAL (operands[2]) & 0xffff) == 0xffff"
  "ldi %0,-1"
  [(set_attr "type" "either")
   (set_attr "length" "1")])

(define_insn "*iorhi3_constant"
  [(set (match_operand:HI 0 "gpr_operand" "=d,d,d")
	(ior:HI (match_operand:HI 1 "gpr_operand" "%d,0,d")
		(match_operand:HI 2 "const_int_operand" "O,P,n")))]
  ""
  "*
{
  HOST_WIDE_INT value = INTVAL (operands[2]);
  int log = exact_log2_wide (value);

  if (value == 0)
    return \"mv %0,%1\";

  if ((value & 0xffff) == 0xffff)
    return \"ldi %0,-1\";

  if (IN_RANGE_P (log, 0, 15))
    {
      if (REGNO (operands[0]) == REGNO (operands[1]))
	return \"bseti %0,%b2\";

      if (TARGET_SMALL_INSNS && optimize)
	return \"mv %0,%1\;bseti %0,%b2\";
    }

  return \"or3 %0,%1,%2\";
}"
  [(set_attr "type" "either,iu,long")
   (set_attr "length" "1,1,2")])

(define_split
  [(set (match_operand:HI 0 "gpr_operand" "")
	(ior:HI (match_operand:HI 1 "gpr_operand" "")
		(match_operand:HI 2 "const_int_operand" "")))]
  "reload_completed && TARGET_SMALL_INSNS && optimize
   && !rtx_equal_p (operands[0], operands[1])
   && IN_RANGE_P (exact_log2_wide (INTVAL (operands[2])), 0, 15)"
  [(set (match_dup 0) (match_dup 1))
   (set (match_dup 0) (ior:HI (match_dup 0) (match_dup 2)))]
  "")

(define_insn "iorsi3"
  [(set (match_operand:SI 0 "gpr_operand" "=e,e")
	(ior:SI (match_operand:SI 1 "gpr_operand" "%0,e")
		(match_operand:SI 2 "arith32_operand" "e,i")))]
  ""
  "#"
  [(set_attr "type" "long,long")
   (set_attr "length" "2,4")])

(define_split
  [(set (match_operand:SI 0 "gpr_operand" "")
	(ior:SI (match_operand:SI 1 "gpr_operand" "")
		(match_operand:SI 2 "arith32_operand" "")))]
  "reload_completed"
  [(match_dup 3)]
  "operands[3] = d10v_split_logical_op (operands, IOR);")

(define_expand "xorhi3"
  [(set (match_operand:HI 0 "gpr_operand" "")
	(xor:HI (match_operand:HI 1 "gpr_operand" "")
		(match_operand:HI 2 "arith16_operand" "")))]
  ""
  "")

(define_insn "*xorhi3_register"
  [(set (match_operand:HI 0 "gpr_operand" "=d")
	(xor:HI (match_operand:HI 1 "gpr_operand" "%0")
		(match_operand:HI 2 "gpr_operand" "d")))]
  ""
  "xor %0,%2"
  [(set_attr "type" "either")
   (set_attr "length" "1")])

(define_insn "*xorhi3_not"
  [(set (match_operand:HI 0 "gpr_operand" "=d,?d")
	(xor:HI (match_operand:HI 1 "gpr_operand" "%0,d")
		(match_operand:HI 2 "const_int_operand" "n,n")))]
  "(INTVAL (operands[2]) & 0xffff) == 0xffff"
  "@
   not %0
   mv %0,%1\;not %0"
  [(set_attr "type" "either,long")
   (set_attr "length" "1,2")])

(define_split
  [(set (match_operand:HI 0 "gpr_operand" "")
	(xor:HI (match_operand:HI 1 "gpr_operand" "")
		(match_operand:HI 2 "const_int_operand" "")))]
  "(INTVAL (operands[2]) & 0xffff) == 0xffff
   && !rtx_equal_p (operands[0], operands[1])"
  [(set (match_dup 0) (match_dup 1))
   (set (match_dup 0) (not:HI (match_dup 0)))]
  "")

(define_insn "*xorhi3_constant"
  [(set (match_operand:HI 0 "gpr_operand" "=d")
	(xor:HI (match_operand:HI 1 "gpr_operand" "%d")
		(match_operand:HI 2 "const_int_operand" "n")))]
  ""
  "*
{
  HOST_WIDE_INT value = INTVAL (operands[2]);
  int log = exact_log2_wide (value);

  if (value == 0)
    return \"mv %0,%1\";

  if ((value & 0xffff) == 0xffff && REGNO (operands[0]) == REGNO (operands[1]))
    return \"not %0\";

  if (IN_RANGE_P (log, 0, 15))
    {
      if (REGNO (operands[0]) == REGNO (operands[1]))
	return \"bnoti %0,%b2\";

      if (TARGET_SMALL_INSNS && optimize)
	return \"mv %0,%1\;bnoti %0,%b2\";
    }

  return \"xor3 %0,%1,%2\";
}"
  [(set_attr "type" "long")
   (set_attr "length" "2")])

(define_split
  [(set (match_operand:HI 0 "gpr_operand" "")
	(xor:HI (match_operand:HI 1 "gpr_operand" "")
		(match_operand:HI 2 "const_int_operand" "")))]
  "reload_completed && TARGET_SMALL_INSNS && optimize
   && !rtx_equal_p (operands[0], operands[1])
   && IN_RANGE_P (exact_log2_wide (INTVAL (operands[2])), 0, 15)"
  [(set (match_dup 0) (match_dup 1))
   (set (match_dup 0) (xor:HI (match_dup 0) (match_dup 2)))]
  "")

(define_insn "xorsi3"
  [(set (match_operand:SI 0 "gpr_operand" "=e,e")
	(xor:SI (match_operand:SI 1 "gpr_operand" "%0,e")
		(match_operand:SI 2 "arith32_operand" "e,i")))]
  ""
  "#"
  [(set_attr "type" "long,long")
   (set_attr "length" "2,4")])

(define_split
  [(set (match_operand:SI 0 "gpr_operand" "")
	(xor:SI (match_operand:SI 1 "gpr_operand" "")
		(match_operand:SI 2 "arith32_operand" "")))]
  "reload_completed"
  [(match_dup 3)]
  "operands[3] = d10v_split_logical_op (operands, XOR);")

(define_insn "one_cmplhi2"
  [(set (match_operand:HI 0 "gpr_operand" "=d")
	(not:HI (match_operand:HI 1 "gpr_operand" "0")))]
  ""
  "not %0"
  [(set_attr "type" "either")
   (set_attr "length" "1")])

(define_insn "one_cmplsi2"
  [(set (match_operand:SI 0 "gpr_operand" "=e")
	(not:SI (match_operand:SI 1 "gpr_operand" "0")))]
  ""
  "#"
  [(set_attr "type" "long")
   (set_attr "length" "2")])

(define_split
  [(set (match_operand:SI 0 "gpr_operand" "")
	(not:SI (match_operand:SI 1 "gpr_operand" "")))]
  "reload_completed"
  [(match_dup 2)]
  "operands[2] = d10v_split_logical_op (operands, NOT);")


;;
;;  ....................
;;
;;	Shifts
;;
;;  ....................

(define_expand "ashlhi3"
  [(set (match_operand:HI 0 "gpr_operand" "")
	(ashift:HI (match_operand:HI 1 "gpr_operand" "")
		   (match_operand:HI 2 "arith16_operand" "")))]
  ""
  "
{
  if (GET_CODE (operands[2]) == CONST_INT && !IN_RANGE_P (INTVAL (operands[2]), 0, 15))
    operands[2] = force_reg (HImode, operands[2]);
}")

(define_insn "*ashlhi3_internal"
  [(set (match_operand:HI 0 "gpr_operand" "=d,d,d")
	(ashift:HI (match_operand:HI 1 "gpr_operand" "0,0,0")
		   (match_operand:HI 2 "arith16_operand" "I,O,d")))]
  "GET_CODE (operands[2]) != CONST_INT || IN_RANGE_P (INTVAL (operands[2]), 0, 15)"
  "@
   slli %0,%2
   nop
   sll %0,%2"
  [(set_attr "type" "iu,either,iu")
   (set_attr "length" "1,1,1")])

(define_expand "ashlsi3"
  [(set (match_operand:SI 0 "register_operand" "")
	(ashift:SI (match_operand:SI 1 "register_operand" "")
		   (match_operand:HI 2 "arith16_operand" "")))]
  ""
  "
{
  if (!TARGET_ACCUM && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != 16))
    FAIL;

  if (GET_CODE (operands[2]) == CONST_INT && ((unsigned long)INTVAL (operands[2])) > 31)
    operands[2] = force_reg (HImode, operands[2]);

  if (GET_CODE (operands[2]) != CONST_INT)
    {
      emit_insn (gen_ashlsi3_variable (operands[0], operands[1], operands[2],
				       gen_reg_rtx (HImode),
				       gen_rtx (REG, CCmode, F0_REGNUM)));
      DONE;
    }
}")

(define_insn "*ashlsi3_16"
  [(set (match_operand:SI 0 "register_operand" "=e,a")
	(ashift:SI (match_operand:SI 1 "register_operand" "e,0")
		   (const_int 16)))]
  ""
  "@
   mv %U0,%L1\;ldi %L0,0
   slli %0,16"
  [(set_attr "type" "long,long")
   (set_attr "length" "2,2")])

(define_insn "*ashlsi3_constant"
  [(set (match_operand:SI 0 "accum_operand" "=a,a,a")
	(ashift:SI (match_operand:SI 1 "accum_operand" "0,0,0")
		   (match_operand:SI 2 "const_int_operand" "I,O,n")))]
  "TARGET_ACCUM && ((unsigned HOST_WIDE_INT)INTVAL (operands[2])) <= 31"
  "*
{
  HOST_WIDE_INT shift_value = INTVAL (operands[2]);

  if (shift_value == 0)
    return \"\";

  if (shift_value <= 16)
    return \"slli %0,%2\";

  operands[3] = GEN_INT (16);
  operands[4] = GEN_INT (shift_value - 16);
  return \"slli %0,%3\;slli %0,%4\";
}"
  [(set_attr "type" "iu,either,long")
   (set_attr "length" "1,1,2")])

(define_insn "ashlsi3_variable"
  [(set (match_operand:SI 0 "accum_operand" "=a")
	(ashift:SI (match_operand:SI 1 "accum_operand" "0")
		   (match_operand:HI 2 "gpr_operand" "d")))
   (clobber (match_operand:HI 3 "gpr_operand" "=&d"))
   (clobber (match_operand:CC 4 "f0_operand" ""))
   (use (const_int 0))]
  "TARGET_ACCUM"
  "#"
  [(set_attr "type" "long")
   (set_attr "length" "10")])

(define_insn "*ashlsi3_variable2"
  [(set (match_operand:SI 0 "accum_operand" "=a")
	(ashift:SI (match_operand:SI 1 "accum_operand" "0")
		   (match_operand:HI 2 "gpr_operand" "d")))
   (use (const_int 1))]
  "TARGET_ACCUM"
  "sll %0,%2"
  [(set_attr "type" "long")
   (set_attr "length" "1")])

(define_split
  [(set (match_operand:SI 0 "accum_operand" "")
	(ashift:SI (match_operand:SI 1 "accum_operand" "")
		   (match_operand:HI 2 "gpr_operand" "")))
   (clobber (match_operand:HI 3 "gpr_operand" ""))
   (clobber (match_operand:CC 4 "f0_operand" ""))
   (use (const_int 0))]
  "TARGET_ACCUM && reload_completed"
  [(set (match_dup 3)
	(and:HI (match_dup 2)
		(const_int 15)))
   (parallel [(set (match_dup 0)
		   (ashift:SI (match_dup 0)
			      (match_dup 3)))
	      (use (const_int 1))])
	
     (set (match_dup 3)
	  (not:HI (match_dup 3)))

     (set (match_dup 3)
	   (and:HI (match_dup 3) 
	           (match_dup 2)))
	
   (parallel [(set (match_dup 0)
		   (ashift:SI (match_dup 0)
			      (match_dup 3)))
	      (use (const_int 1))])]
  "")

(define_expand "ashrhi3"
  [(set (match_operand:HI 0 "gpr_operand" "")
	(ashiftrt:HI (match_operand:HI 1 "gpr_operand" "")
		     (match_operand:HI 2 "arith16_operand" "")))]
  ""
  "
{
  if (GET_CODE (operands[2]) == CONST_INT && !IN_RANGE_P (INTVAL (operands[2]), 0, 15))
    operands[2] = force_reg (HImode, operands[2]);
}")

(define_insn "*ashrhi3_internal"
  [(set (match_operand:HI 0 "gpr_operand" "=d,d,d")
	(ashiftrt:HI (match_operand:HI 1 "gpr_operand" "0,0,0")
		     (match_operand:HI 2 "arith16_operand" "I,O,d")))]
  "GET_CODE (operands[2]) != CONST_INT || IN_RANGE_P (INTVAL (operands[2]), 0, 15)"
  "@
   srai %0,%2
   nop
   sra %0,%2"
  [(set_attr "type" "iu,either,iu")
   (set_attr "length" "1,1,1")])

(define_expand "ashrsi3"
  [(set (match_operand:SI 0 "register_operand" "")
	(ashiftrt:SI (match_operand:SI 1 "register_operand" "")
		     (match_operand:HI 2 "arith16_operand" "")))]
  ""
  "
{
  if (!TARGET_ACCUM && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != 16))
    FAIL;

  if (GET_CODE (operands[2]) == CONST_INT && ((unsigned long)INTVAL (operands[2])) > 31)
    operands[2] = force_reg (HImode, operands[2]);

  if (GET_CODE (operands[2]) != CONST_INT)
    {
      emit_insn (gen_ashrsi3_variable (operands[0], operands[1], operands[2],
				       gen_reg_rtx (HImode),
				       gen_rtx (REG, CCmode, F0_REGNUM)));
      DONE;
    }
}")

(define_insn "*ashrsi3_16"
  [(set (match_operand:SI 0 "register_operand" "=e,e,a")
	(ashiftrt:SI (match_operand:SI 1 "register_operand" "0,e,0")
		     (const_int 16)))]
  ""
  "@
   mv %L0,%U1\;srai %U0,15
   mv %L0,%U1\;mv %U0,%U1\;srai %U0,15
   srai %0,16"
  [(set_attr "type" "long,long,long")
   (set_attr "length" "2,3,2")])

(define_insn "*ashrsi3_constant"
  [(set (match_operand:SI 0 "accum_operand" "=a,a,a")
	(ashiftrt:SI (match_operand:SI 1 "accum_operand" "0,0,0")
		     (match_operand:SI 2 "const_int_operand" "I,O,n")))]
  "TARGET_ACCUM && ((unsigned HOST_WIDE_INT)INTVAL (operands[2])) <= 31"
  "*
{
  HOST_WIDE_INT shift_value = INTVAL (operands[2]);

  if (shift_value == 0)
    return \"\";

  if (shift_value <= 16)
    return \"srai %0,%2\";

  operands[3] = GEN_INT (16);
  operands[4] = GEN_INT (shift_value - 16);
  return \"srai %0,%3\;srai %0,%4\";
}"
  [(set_attr "type" "iu,either,long")
   (set_attr "length" "1,1,2")])

(define_insn "ashrsi3_variable"
  [(set (match_operand:SI 0 "accum_operand" "=a")
	(ashiftrt:SI (match_operand:SI 1 "accum_operand" "0")
		     (match_operand:HI 2 "gpr_operand" "d")))
   (clobber (match_operand:HI 3 "gpr_operand" "=&d"))
   (clobber (match_operand:CC 4 "f0_operand" ""))
   (use (const_int 0))]
  "TARGET_ACCUM"
  "#"
  [(set_attr "type" "long")
   (set_attr "length" "10")])

(define_insn "*ashrsi3_variable2"
  [(set (match_operand:SI 0 "accum_operand" "=a")
	(ashiftrt:SI (match_operand:SI 1 "accum_operand" "0")
		     (match_operand:HI 2 "gpr_operand" "d")))
   (use (const_int 1))]
  "TARGET_ACCUM"
  "sra %0,%2"
  [(set_attr "type" "long")
   (set_attr "length" "1")])

(define_split
  [(set (match_operand:SI 0 "accum_operand" "")
	(ashiftrt:SI (match_operand:SI 1 "accum_operand" "")
		     (match_operand:HI 2 "gpr_operand" "")))
   (clobber (match_operand:HI 3 "gpr_operand" ""))
   (clobber (match_operand:CC 4 "f0_operand" ""))
   (use (const_int 0))]
  "TARGET_ACCUM && reload_completed"
  [(set (match_dup 3)
	(and:HI (match_dup 2)
		(const_int 15)))
   (parallel [(set (match_dup 0)
		   (ashiftrt:SI (match_dup 0)
				(match_dup 3)))
	      (use (const_int 1))])

     (set (match_dup 3)
	  (not:HI (match_dup 3)))

     (set (match_dup 3)
	   (and:HI (match_dup 3) 
	           (match_dup 2)))

   (parallel [(set (match_dup 0)
		   (ashiftrt:SI (match_dup 0)
				(match_dup 3)))
	      (use (const_int 1))])]
  "")

(define_expand "lshrhi3"
  [(set (match_operand:HI 0 "gpr_operand" "")
	(lshiftrt:HI (match_operand:HI 1 "gpr_operand" "")
		     (match_operand:HI 2 "arith16_operand" "")))]
  ""
  "
{
  if (GET_CODE (operands[2]) == CONST_INT && !IN_RANGE_P (INTVAL (operands[2]), 0, 15))
    operands[2] = force_reg (HImode, operands[2]);
}")

(define_insn "*lshrhi3_internal"
  [(set (match_operand:HI 0 "gpr_operand" "=d,d,d")
	(lshiftrt:HI (match_operand:HI 1 "gpr_operand" "0,0,0")
		     (match_operand:HI 2 "arith16_operand" "I,O,d")))]
  "GET_CODE (operands[2]) != CONST_INT || IN_RANGE_P (INTVAL (operands[2]), 0, 15)"
  "@
   srli %0,%2
   nop
   srl %0,%2"
  [(set_attr "type" "iu,either,iu")
   (set_attr "length" "1,1,1")])

(define_expand "lshrsi3"
  [(set (match_operand:SI 0 "register_operand" "")
	(lshiftrt:SI (match_operand:SI 1 "register_operand" "")
		     (match_operand:HI 2 "arith16_operand" "")))]
  ""
  "
{
  if (!TARGET_ACCUM && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != 16))
    FAIL;

  if (GET_CODE (operands[2]) == CONST_INT && ((unsigned long)INTVAL (operands[2])) > 31)
    operands[2] = force_reg (HImode, operands[2]);

  if (GET_CODE (operands[2]) != CONST_INT)
    {
      emit_insn (gen_lshrsi3_variable (operands[0], operands[1], operands[2],
				       gen_reg_rtx (HImode),
				       gen_rtx (REG, CCmode, F0_REGNUM)));
      DONE;
    }
}")

(define_insn "*lshrsi3_16"
  [(set (match_operand:SI 0 "register_operand" "=e,a")
	(lshiftrt:SI (match_operand:SI 1 "register_operand" "e,0")
		     (const_int 16)))]
  ""
  "@
   mv %L0,%U1\;ldi %U0,0
   slli %0,8\; srli %0,8\; srli %0,16"
  [(set_attr "type" "long,long")
   (set_attr "length" "2,3")])

 (define_insn "*lshrsi3_constant"
   [(set (match_operand:SI 0 "accum_operand" "=a,a,a")
 	(lshiftrt:SI (match_operand:SI 1 "accum_operand" "0,0,0")
 		     (match_operand:SI 2 "const_int_operand" "I,O,n")))]
   "TARGET_ACCUM && ((unsigned HOST_WIDE_INT)INTVAL (operands[2])) <= 31"
   "*
 {
   HOST_WIDE_INT shift_value = INTVAL (operands[2]);

   if (shift_value == 0)
     return \"slli %0,8\; srli %0,8\";

   operands[3] = GEN_INT (8); 
   operands[4] = GEN_INT (16);

   if (shift_value <= 8)	
     {
   	operands[5] = GEN_INT (8 + shift_value);
	return \"slli %0,%3\; srli %0,%5\";
     }	
 
   if (shift_value <= 24)
     {
   	operands[5] = GEN_INT (shift_value - 8);
	return \"slli %0,%3\; srli %0,%4\; srli %0,%5\";
     }
 
    operands[5] = GEN_INT (shift_value - 24);
    return \"slli %0,%3\; srli %0,%4\; srli %0,%4\; srli %0,%5\";
 }"
   [(set_attr "type" "iu,either,long")
    (set_attr "length" "1,1,2")])

(define_insn "lshrsi3_variable"
  [(set (match_operand:SI 0 "accum_operand" "=a")
	(lshiftrt:SI (match_operand:SI 1 "accum_operand" "0")
		     (match_operand:HI 2 "gpr_operand" "d")))
   (clobber (match_operand:HI 3 "gpr_operand" "=&d"))
   (clobber (match_operand:CC 4 "f0_operand" ""))
   (use (const_int 0))]
  "TARGET_ACCUM"
  "#"
  [(set_attr "type" "long")
   (set_attr "length" "10")])

(define_insn "*lshrsi3_variable2"
  [(set (match_operand:SI 0 "accum_operand" "=a")
	(lshiftrt:SI (match_operand:SI 1 "accum_operand" "0")
		     (match_operand:HI 2 "gpr_operand" "d")))
   (use (const_int 1))]
  "TARGET_ACCUM"
  "srl %0,%2"
  [(set_attr "type" "long")
   (set_attr "length" "1")])

(define_split
  [(set (match_operand:SI 0 "accum_operand" "")
	(lshiftrt:SI (match_operand:SI 1 "accum_operand" "")
		     (match_operand:HI 2 "gpr_operand" "")))
   (clobber (match_operand:HI 3 "gpr_operand" ""))
   (clobber (match_operand:CC 4 "f0_operand" ""))
   (use (const_int 0))]
  "TARGET_ACCUM && reload_completed"

  [
    (set (match_dup 0)
	(lshiftrt:SI (match_dup 0)
	             (const_int 0)))

    (set (match_dup 3)
	 (and:HI (match_dup 2)
		 (const_int 15)))

    (parallel [(set (match_dup 0)
		    (lshiftrt:SI (match_dup 0)
				 (match_dup 3)))
	      (use (const_int 1))])

     (set (match_dup 3)
	  (not:HI (match_dup 3)))

     (set (match_dup 3)
	   (and:HI (match_dup 3) 
	           (match_dup 2)))

     (parallel [(set (match_dup 0)
		     (lshiftrt:SI (match_dup 0)
				  (match_dup 3)))
	      (use (const_int 1))])]
  "")


;;
;;  ....................
;;
;;	Min/max/abs
;;
;;  ....................

(define_expand "sminhi3"
  [(parallel [(set (match_operand:HI 0 "gpr_operand" "")
		   (smin:HI (match_operand:HI 1 "gpr_operand" "")
			    (match_operand:HI 2 "reg_or_0_operand" "")))
	      (clobber (match_dup 3))])]
  ""
  "operands[3] = gen_rtx (REG, CCmode, F0_REGNUM);")

(define_insn "*sminhi3_internal"
  [(set (match_operand:HI 0 "gpr_operand" "=d,d")
	(smin:HI (match_operand:HI 1 "gpr_operand" "%0,0")
		 (match_operand:HI 2 "reg_or_0_operand" "d,O")))
   (clobber (match_operand:CC 3 "f0_operand" ""))]
  ""
  "@
   min %0,%2
   min %0,%."
  [(set_attr "type" "iu,iu")
   (set_attr "length" "1,1")])

(define_expand "sminsi3"
  [(parallel [(set (match_operand:SI 0 "gpr_operand" "")
		   (smin:SI (match_operand:SI 1 "gpr_operand" "")
			    (match_operand:SI 2 "gpr_operand" "")))
	      (clobber (match_dup 3))])]
  "TARGET_ACCUM"
  "operands[3] = gen_rtx (REG, CCmode, F0_REGNUM);")

(define_insn "*sminsi3_internal"
  [(set (match_operand:SI 0 "gpr_operand" "=a")
	(smin:SI (match_operand:SI 1 "gpr_operand" "%0")
		 (match_operand:SI 2 "gpr_operand" "ad")))
   (clobber (match_operand:CC 3 "f0_operand" ""))]
  "TARGET_ACCUM"
  "min %0,%2"
  [(set_attr "type" "iu")
   (set_attr "length" "1")])

(define_expand "smaxhi3"
  [(parallel [(set (match_operand:HI 0 "gpr_operand" "")
		   (smax:HI (match_operand:HI 1 "gpr_operand" "")
			    (match_operand:HI 2 "reg_or_0_operand" "")))
	      (clobber (match_dup 3))])]
  ""
  "operands[3] = gen_rtx (REG, CCmode, F0_REGNUM);")

(define_insn "*smaxhi3_internal"
  [(set (match_operand:HI 0 "gpr_operand" "=d,d")
	(smax:HI (match_operand:HI 1 "gpr_operand" "%0,0")
		 (match_operand:HI 2 "reg_or_0_operand" "d,O")))
   (clobber (match_operand:CC 3 "f0_operand" ""))]
  ""
  "@
   max %0,%2
   max %0,%."
  [(set_attr "type" "iu,iu")
   (set_attr "length" "1,1")])

(define_expand "smaxsi3"
  [(parallel [(set (match_operand:SI 0 "register_operand" "")
		   (smax:SI (match_operand:SI 1 "register_operand" "")
			    (match_operand:SI 2 "register_operand" "")))
	      (clobber (match_dup 3))])]
  "TARGET_ACCUM"
  "operands[3] = gen_rtx (REG, CCmode, F0_REGNUM);")

(define_insn "*smaxsi3_internal"
  [(set (match_operand:SI 0 "accum_operand" "=a")
	(smax:SI (match_operand:SI 1 "register_operand" "%0")
		 (match_operand:SI 2 "register_operand" "ad")))
   (clobber (match_operand:CC 3 "f0_operand" ""))]
  "TARGET_ACCUM"
  "max %0,%2"
  [(set_attr "type" "iu")
   (set_attr "length" "1")])

(define_expand "abshi2"
  [(parallel [(set (match_operand:HI 0 "gpr_operand" "")
		   (abs:HI (match_operand:HI 1 "gpr_operand" "")))
	      (clobber (match_dup 3))])]
  ""
  "operands[3] = gen_rtx (REG, CCmode, F0_REGNUM);")

(define_insn "*abshi2_internal"
  [(set (match_operand:HI         0 "gpr_operand" "=d")
	(abs:HI (match_operand:HI 1 "gpr_operand" "0")))
   (clobber (match_operand:CC     2 "f0_operand" ""))]
  ""
  "abs %0"
  [(set_attr "type" "either")
   (set_attr "length" "1")])

(define_expand "abssi2"
  [(parallel [(set (match_operand:SI 0 "register_operand" "")
		   (abs:SI (match_operand:SI 1 "register_operand" "")))
	      (clobber (match_dup 3))])]
  "TARGET_ACCUM"
  "operands[3] = gen_rtx (REG, CCmode, F0_REGNUM);")

(define_insn "*abssi2_internal"
  [(set (match_operand:SI         0 "accum_operand" "=a")
	(abs:SI (match_operand:SI 1 "register_operand" "0")))
   (clobber (match_operand:CC     2 "f0_operand" ""))]
  "TARGET_ACCUM"
  "abs %0"
  [(set_attr "type" "iu")
   (set_attr "length" "1")])


;;
;;  ....................
;;
;;	Peepholes
;;
;;  ....................

(define_peephole
  [(set (match_operand:HI 0 "gpr_operand" "=e") (match_operand:HI 1 "gpr_operand" "e"))
   (set (match_operand:HI 2 "gpr_operand" "=d") (match_operand:HI 3 "gpr_operand" "d"))]
  "((REGNO (operands[0]) & 1) == 0 && (REGNO (operands[2]) == REGNO (operands[0]) + 1)
    && (REGNO (operands[1]) & 1) == 0 && (REGNO (operands[3]) == REGNO (operands[1]) + 1))"
  "mv2w %0,%1"
  [(set_attr "type" "iu")
   (set_attr "length" "1")])

(define_peephole
  [(set (match_operand:HI 0 "gpr_operand" "=d") (match_operand:HI 1 "gpr_operand" "d"))
   (set (match_operand:HI 2 "gpr_operand" "=e") (match_operand:HI 3 "gpr_operand" "e"))]
  "((REGNO (operands[2]) & 1) == 0 && (REGNO (operands[2]) == REGNO (operands[0]) - 1)
    && (REGNO (operands[3]) & 1) == 0 && (REGNO (operands[3]) == REGNO (operands[1]) - 1))"
  "mv2w %2,%3"
  [(set_attr "type" "iu")
   (set_attr "length" "1")])

(define_peephole
  [(set (match_operand:HI 0 "gpr_operand" "=e,e") (match_operand:HI 1 "memory_operand" "Q,m"))
   (set (match_operand:HI 2 "gpr_operand" "=d,d") (match_operand:HI 3 "memory_operand" "Q,m"))]
  "((REGNO (operands[0]) & 1) == 0 && (REGNO (operands[2]) == REGNO (operands[0]) + 1)
   && adjacent_memory_operands (operands[1], operands[3], insn, 0)
   && !reg_mentioned_p (operands[0], operands[3]))"
  "ld2w %0,%M1"
  [(set_attr "type" "mu,mu")
   (set_attr "length" "1,2")])

(define_peephole
  [(set (match_operand:HI 0 "gpr_operand" "=d,d") (match_operand:HI 1 "memory_operand" "Q,m"))
   (set (match_operand:HI 2 "gpr_operand" "=e,e") (match_operand:HI 3 "memory_operand" "Q,m"))]
  "((REGNO (operands[2]) & 1) == 0 && (REGNO (operands[2]) == REGNO (operands[0]) - 1)
   && adjacent_memory_operands (operands[3], operands[1], insn, 1)
   && !reg_mentioned_p (operands[0], operands[3]))"
  "ld2w %2,%M3"
  [(set_attr "type" "mu,mu")
   (set_attr "length" "1,2")])

(define_peephole
  [(set (match_operand:HI 0 "memory_operand" "=Q,m") (match_operand:HI 1 "gpr_operand" "e,e"))
   (set (match_operand:HI 2 "memory_operand" "=Q,m") (match_operand:HI 3 "gpr_operand" "d,d"))]
  "((REGNO (operands[1]) & 1) == 0 && (REGNO (operands[3]) == REGNO (operands[1]) + 1)
   && adjacent_memory_operands (operands[0], operands[2], insn, 0))"
  "st2w %1,%M0"
  [(set_attr "type" "mu,mu")
   (set_attr "length" "1,2")])

(define_peephole
  [(set (match_operand:HI 0 "memory_operand" "=Q,m") (match_operand:HI 1 "gpr_operand" "d,d"))
   (set (match_operand:HI 2 "memory_operand" "=Q,m") (match_operand:HI 3 "gpr_operand" "e,e"))]
  "((REGNO (operands[3]) & 1) == 0 && (REGNO (operands[3]) == REGNO (operands[1]) - 1)
   && adjacent_memory_operands (operands[2], operands[0], insn, 1))"
  "st2w %3,%M2"
  [(set_attr "type" "mu,mu")
   (set_attr "length" "1,2")])

;; Peepholes for tst0i, tst1i, and btsti instructions
(define_peephole
  [(set (match_operand:HI 0 "gpr_operand" "=d")
	(and:HI (match_operand:HI 1 "gpr_operand" "d")
		(match_operand:HI 2 "const_int_operand" "n")))
   (set (match_operand:CC_REV 3 "f0_operand" "")
	(ne:CC_REV (match_dup 0)
		   (const_int 0)))
   (set (pc)
	(if_then_else (match_operator:CC 4 "f0_compare_operator"
					 [(match_dup 3)
					  (const_int 0)])
		      (match_operand 5 "pc_or_label_operand" "")
		      (match_operand 6 "pc_or_label_operand" "")))]
  "IN_RANGE_P (exact_log2_wide (INTVAL (operands[2])), 0, 15)
   && find_regno_note (prev_nonnote_insn (insn), REG_DEAD, REGNO (operands[0]))
   && find_regno_note (insn, REG_DEAD, F0_REGNUM)"
  "*
{
  operands[7] = GEN_INT (15 - exact_log2_wide (INTVAL (operands[2])));
  output_asm_insn (\"btsti %1,%7\", operands);

  if (operands[5] == pc_rtx)
    return (GET_CODE (operands[6]) == RETURN) ? \"jmp r13 || exef0%T4\" : \"brf0%F4 %l6\";
  else
    return (GET_CODE (operands[5]) == RETURN) ? \"jmp r13 || exef0%F4\" : \"brf0%T4 %l5\";

}"
  [(set_attr "type" "long")
   (set_attr "length" "4")])

(define_peephole
  [(set (match_operand:HI 0 "gpr_operand" "=d")
	(and:HI (not:HI (match_operand:HI 1 "gpr_operand" "d"))
		(match_operand:HI 2 "const_int_operand" "n")))
   (set (match_operand:CC_REV 3 "f0_operand" "")
	(ne:CC (match_dup 0)
	       (const_int 0)))]
  "find_regno_note (insn, REG_DEAD, REGNO (operands[0]))"
  "tst1i %1,%2"
  [(set_attr "type" "long")
   (set_attr "length" "2")])

(define_peephole
  [(set (match_operand:HI 0 "gpr_operand" "=d")
	(and:HI (match_operand:HI 1 "gpr_operand" "d")
		(match_operand:HI 2 "const_int_operand" "n")))
   (set (match_operand:CC 3 "f0_operand" "")
	(eq:CC_REV (match_dup 0)
		   (const_int 0)))]
  "IN_RANGE_P (exact_log2_wide (INTVAL (operands[2])), 0, 15)
   && find_regno_note (insn, REG_DEAD, REGNO (operands[0]))"
  "*
{
  operands[4] = GEN_INT (15 - exact_log2_wide (INTVAL (operands[2])));
  return \"btsti %1,%4\";
}"
  [(set_attr "type" "iu")
   (set_attr "length" "1")])

(define_peephole
  [(set (match_operand:HI 0 "gpr_operand" "=d")
	(and:HI (match_operand:HI 1 "gpr_operand" "d")
		(match_operand:HI 2 "const_int_operand" "n")))
   (set (match_operand:CC 3 "f0_operand" "")
	(eq:CC_REV (match_dup 0)
		   (const_int 0)))]
  "!IN_RANGE_P (exact_log2_wide (INTVAL (operands[2])), 0, 15)
   && find_regno_note (insn, REG_DEAD, REGNO (operands[0]))"
  "tst0i %1,%2"
  [(set_attr "type" "long")
   (set_attr "length" "2")])


;; ::::::::::::::::::::
;; ::
;; :: Prologue and Epilogue instructions
;; ::
;; ::::::::::::::::::::

;; Called after register allocation to add any instructions needed for
;; the prologue.  Using a prologue insn is favored compared to putting
;; all of the instructions in the TARGET_ASM_FUNCTION_PROLOGUE macro,
;; since it allows the scheduler to intermix instructions with the
;; saves of the caller saved registers.  In some cases, it might be
;; necessary to emit a barrier instruction as the last insn to prevent
;; such scheduling.
;; ;; (define_expand "prologue"
;; ;;   [(const_int 1)]
;; ;;   ""
;; ;;   "
;; ;; {
;; ;;   d10v_expand_prologue ();
;; ;;   DONE;
;; ;; }")

;; Called after register allocation to add any instructions needed for
;; the epilogue.  Using a epilogue insn is favored compared to putting
;; all of the instructions in the TARGET_ASM_FUNCTION_EPILOGUE macro,
;; since it allows the scheduler to intermix instructions with the
;; restires of the caller saved registers.  In some cases, it might be
;; necessary to emit a barrier instruction as the first insn to
;; prevent such scheduling.
;; ;; (define_expand "epilogue"
;; ;;   [(const_int 2)]
;; ;;   ""
;; ;;   "
;; ;; {
;; ;;   d10v_expand_epilogue ();
;; ;;   DONE;
;; ;; }")

;; Pseudo instruction that prevents the scheduler from moving code above this
;; point.
(define_insn "blockage"
  [(unspec_volatile [(const_int 0)] 0)]
  ""
  ""
  [(set_attr "length" "0")
   (set_attr "type" "unknown")])

;; ;
;; ; setjmp/longjmp instruction pattern(s).
;; ;
;; ; setjmp/longjmp for D10V.  The jmpbuf looks like this:
;; ;
;; ; Register		jmpbuf offset
;; ; R6			0x00
;; ; R7			0x02
;; ; R8			0x04
;; ; R9			0x06
;; ; R10			0x08
;; ; R11			0x0a
;; ; R13 (return address)	0x0c
;; ; R15 (SP)		0x0E
;; 
;; 	.text
;; 	.globl	setjmp
;; 	.type	setjmp,@function
;; 	.stabs	"setjmp.S",100,0,0,setjmp
;; 	.stabs	"int:t(0,1)=r(0,1);-65536;65535;",128,0,0,0
;; 	.stabs	"setjmp:F(0,1)",36,0,1,setjmp
;; 
;; setjmp:
;; ; Address of jmpbuf is passed in R0.  Save the appropriate registers.
;; 	st2w	r6, @r0+
;; 	st2w	r8, @r0+
;; 	st2w	r10, @r0+
;; 	st	r13, @r0+
;; 	st	r15, @r0+
;; 
;; ; Return 0 to caller
;; 	ldi	r0, 0
;; 	jmp	r13
;; .Lsetjmp:
;; 	.size	setjmp,.Lsetjmp-setjmp
;; 	.stabs	"",36,0,0,.Lsetjmp-setjmp
;; 
;; 	.globl	longjmp
;; 	.type	longjmp,@function
;; 	.stabs	"longjmp:F(0,1)",36,0,1,longjmp


(define_expand "builtin_setjmp_setup"
  [(unspec [(match_operand 0 "register_operand" "a")] 1)]
  ""
  "
{
  rtx jmp = gen_rtx_REG (Pmode, RETURN_ADDRESS_REGNUM);
  rtx r0 = gen_rtx_REG (Pmode, GPR_FIRST);

  gen_pushwr (gen_rtx_REG (Pmode, GPR_FIRST + 6));
  gen_pushwr (gen_rtx_REG (Pmode, GPR_FIRST + 8));
  gen_pushwr (gen_rtx_REG (Pmode, GPR_FIRST + 10));
  gen_pushr (gen_rtx_REG (Pmode, GPR_FIRST + 13));
  gen_pushr (gen_rtx_REG (Pmode, GPR_FIRST + 15));
  gen_movhi (r0, const0_rtx);

  emit_indirect_jump (jmp);
  DONE;
}")


;; longjmp:
;; ; Address of jmpbuf is in R0.  Restore the registers.
;; 	ld2w	r6, @r0+
;; 	ld2w	r8, @r0+
;; 	ld2w	r10, @r0+
;; 	ld	r13, @r0+
;; 	ld	r15, @r0+
;; 
;; ; Value to return to caller is in R1.  If caller attemped to return 0,
;; ; return 1 instead.
;; 
;; 	mv	r0, r1
;; 	cmpeqi	r0, 0
;; 	exef0t || ldi r0,1
;; 	jmp	r13
;; .Llongjmp:
;; 	.size	longjmp,.Llongjmp-longjmp
;; 	.stabs	"",36,0,0,.Llongjmp-longjmp
(define_insn "longjmp_internal_1"
  [(set (match_operand:HI 0 "immediate_operand" "")
        (match_operand:HI 1 "register_operand" "r"))]
  ""
  "cmpeqi	%0, %1\n\texef0t || ldi %0,1"
)


(define_expand "builtin_longjmp"
  [(unspec_volatile [(match_operand 0 "register_operand" "r")] 2)]
  ""
  "
{
  rtx jmp = gen_rtx_REG (Pmode, RETURN_ADDRESS_REGNUM);
  rtx r0 = gen_rtx_REG (Pmode, GPR_FIRST);
  rtx r1 = gen_rtx_REG (Pmode, GPR_FIRST + 1);

  /* The elements of the buffer are, in order:  */

  gen_popwr (gen_rtx_REG (Pmode, GPR_FIRST + 6));
  gen_popwr (gen_rtx_REG (Pmode, GPR_FIRST + 8));
  gen_popwr (gen_rtx_REG (Pmode, GPR_FIRST + 10));
  gen_popr (gen_rtx_REG (Pmode, GPR_FIRST + 13));
  gen_popr (gen_rtx_REG (Pmode, GPR_FIRST + 15));
  gen_movhi (r0, r1);

  gen_longjmp_internal_1 (r0, const1_rtx);
  gen_movhi (r0, const1_rtx);

  emit_indirect_jump (jmp);
  DONE;
}")

