;;- Machine description for GNU compiler, Convex Version
;;  Copyright (C) 1988, 1994, 1995, 1998, 1999 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, 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;; Attribute specifications

; Target CPU
(define_attr "cpu" "c1,c32,c34,c38"
  (const (symbol_ref "(enum attr_cpu) target_cpu")))

;; Instruction classification

(define_attr "type"
  "alu,xalu,mldw,mldl,mldb,mst,adds,addd,mulw,mull,muls,muld,divw,divl,divs,divd,shfw,shfl,cvts,cvtd"
  (const_string "alu"))

;; Instruction times

(define_function_unit "mem" 1 0
  (and (eq_attr "cpu" "c1") (eq_attr "type" "mldw")) 2 0)
(define_function_unit "mem" 1 0
  (and (eq_attr "cpu" "c1") (eq_attr "type" "mldl")) 4 0)
(define_function_unit "mem" 1 0
  (and (eq_attr "cpu" "c32") (eq_attr "type" "mldw,mldl")) 2 0)
(define_function_unit "mem" 1 0
  (and (eq_attr "cpu" "c34") (eq_attr "type" "mldw,mldl")) 4 0)
(define_function_unit "mem" 1 0
  (and (eq_attr "cpu" "c38") (eq_attr "type" "mldw,mldl")) 2 0)

(define_function_unit "mem" 1 0
  (and (eq_attr "cpu" "c32") (eq_attr "type" "mldb")) 9 0)
(define_function_unit "mem" 1 0
  (and (eq_attr "cpu" "c34") (eq_attr "type" "mldb")) 36 0)
(define_function_unit "mem" 1 0
  (and (eq_attr "cpu" "c38") (eq_attr "type" "mldb")) 21 0)

(define_function_unit "mem" 1 0
  (and (eq_attr "cpu" "c1") (eq_attr "type" "xalu")) 1 0)
(define_function_unit "mem" 1 0
  (and (eq_attr "cpu" "c32") (eq_attr "type" "xalu")) 1 0)
(define_function_unit "mem" 1 0
  (and (eq_attr "cpu" "c34") (eq_attr "type" "xalu")) 5 0)
(define_function_unit "mem" 1 0
  (and (eq_attr "cpu" "c38") (eq_attr "type" "xalu")) 2 0)

(define_function_unit "add" 1 0
  (and (eq_attr "cpu" "c1") (eq_attr "type" "adds,addd")) 3 2)
(define_function_unit "add" 1 0
  (and (eq_attr "cpu" "c32") (eq_attr "type" "adds,addd")) 2 1)
(define_function_unit "add" 1 0
  (and (eq_attr "cpu" "c34") (eq_attr "type" "adds,addd")) 5 2)
(define_function_unit "add" 1 0
  (and (eq_attr "cpu" "c38") (eq_attr "type" "adds,addd")) 2 1)

(define_function_unit "mul" 1 0
  (and (eq_attr "cpu" "c1") (eq_attr "type" "mulw,muls")) 3 2)
(define_function_unit "mul" 1 0
  (and (eq_attr "cpu" "c32") (eq_attr "type" "mulw,muls")) 4 2)
(define_function_unit "mul" 1 0
  (and (eq_attr "cpu" "c34") (eq_attr "type" "mulw,muls")) 6 2)
(define_function_unit "mul" 1 0
  (and (eq_attr "cpu" "c38") (eq_attr "type" "mulw,muls")) 3 2)

(define_function_unit "mul" 1 0
  (and (eq_attr "cpu" "c1") (eq_attr "type" "mull,muld")) 4 3)
(define_function_unit "mul" 1 0
  (and (eq_attr "cpu" "c32") (eq_attr "type" "mull")) 10 7)
(define_function_unit "mul" 1 0
  (and (eq_attr "cpu" "c32") (eq_attr "type" "muld")) 5 2)
(define_function_unit "mul" 1 0
  (and (eq_attr "cpu" "c34") (eq_attr "type" "mull,muld")) 7 3)
(define_function_unit "mul" 1 0
  (and (eq_attr "cpu" "c38") (eq_attr "type" "mull,muld")) 4 3)

(define_function_unit "div" 1 0
  (and (eq_attr "cpu" "c1") (eq_attr "type" "divw")) 24 24)
(define_function_unit "div" 1 0
  (and (eq_attr "cpu" "c32") (eq_attr "type" "divw")) 44 6)
(define_function_unit "div" 1 0
  (and (eq_attr "cpu" "c34") (eq_attr "type" "divw")) 14 10)
(define_function_unit "div" 1 0
  (and (eq_attr "cpu" "c38") (eq_attr "type" "divw")) 11 10)

(define_function_unit "div" 1 0
  (and (eq_attr "cpu" "c1") (eq_attr "type" "divl")) 41 42)
(define_function_unit "div" 1 0
  (and (eq_attr "cpu" "c32") (eq_attr "type" "divl")) 76 5)
(define_function_unit "div" 1 0
  (and (eq_attr "cpu" "c34") (eq_attr "type" "divl")) 22 18)
(define_function_unit "div" 1 0
  (and (eq_attr "cpu" "c38") (eq_attr "type" "divl")) 19 18)

(define_function_unit "div" 1 0
  (and (eq_attr "cpu" "c1") (eq_attr "type" "divs")) 22 22)
(define_function_unit "div" 1 0
  (and (eq_attr "cpu" "c32") (eq_attr "type" "divs")) 8 6)
(define_function_unit "div" 1 0
  (and (eq_attr "cpu" "c34") (eq_attr "type" "divs")) 13 9)
(define_function_unit "div" 1 0
  (and (eq_attr "cpu" "c38") (eq_attr "type" "divs")) 10 9)

(define_function_unit "div" 1 0
  (and (eq_attr "cpu" "c1") (eq_attr "type" "divd")) 37 38)
(define_function_unit "div" 1 0
  (and (eq_attr "cpu" "c32") (eq_attr "type" "divd")) 12 8)
(define_function_unit "div" 1 0
  (and (eq_attr "cpu" "c34") (eq_attr "type" "divd")) 20 16)
(define_function_unit "div" 1 0
  (and (eq_attr "cpu" "c38") (eq_attr "type" "divd")) 17 16)

(define_function_unit "misc" 1 0
  (and (eq_attr "cpu" "c1") (eq_attr "type" "cvts,cvtd")) 4 3)
(define_function_unit "misc" 1 0
  (and (eq_attr "cpu" "c32") (eq_attr "type" "cvts")) 9 7)
(define_function_unit "misc" 1 0
  (and (eq_attr "cpu" "c32") (eq_attr "type" "cvtd")) 9 6)
(define_function_unit "misc" 1 0
  (and (eq_attr "cpu" "c34") (eq_attr "type" "cvts")) 6 2)
(define_function_unit "misc" 1 0
  (and (eq_attr "cpu" "c34") (eq_attr "type" "cvtd")) 6 1)
(define_function_unit "misc" 1 0
  (and (eq_attr "cpu" "c38") (eq_attr "type" "cvts,cvtd")) 3 1)

(define_function_unit "misc" 1 0
  (and (eq_attr "cpu" "c1") (eq_attr "type" "shfw,shfl")) 3 2)
(define_function_unit "misc" 1 0
  (and (eq_attr "cpu" "c32") (eq_attr "type" "shfw")) 7 5)
(define_function_unit "misc" 1 0
  (and (eq_attr "cpu" "c32") (eq_attr "type" "shfl")) 7 4)
(define_function_unit "misc" 1 0
  (and (eq_attr "cpu" "c38") (eq_attr "type" "shfw,shfl")) 3 1)

(define_function_unit "mystery_latch" 1 1
  (and (eq_attr "type" "!alu,mldw,mldl,adds,addd") (eq_attr "cpu" "c32")) 2 2)

;(define_function_unit "ip" 1 1
;  (and (eq_attr "cpu" "c1")
;       (eq_attr "type" "divw,divl,divs,divd,xalu")) 2 2)
;(define_function_unit "ip" 1 1
;  (and (eq_attr "cpu" "c1")
;       (eq_attr "type" "!divw,divl,divs,divd,xalu")) 1 1)
;(define_function_unit "ip" 1 1
;  (and (eq_attr "cpu" "c32")
;       (eq_attr "type" "mull,muld,divl,divd,shfl,cvtd,xalu")) 2 2)
;(define_function_unit "ip" 1 1
;  (and (eq_attr "cpu" "c32")
;       (eq_attr "type" "!mull,muld,divl,divd,shfl,cvtd,xalu")) 1 1)
;(define_function_unit "ip" 1 1
;  (and (eq_attr "cpu" "c34")
;       (eq_attr "type" "addd,mull,muld,divl,divd,cvtd,xalu")) 2 2)
;(define_function_unit "ip" 1 1
;  (and (eq_attr "cpu" "c34")
;       (eq_attr "type" "!addd,mull,muld,divl,divd,cvtd,xalu")) 1 1)

;; Make the first thing a real insn in case of genattrtab bug

(define_insn "nop"
  [(const_int 0)]
  ""
  "nop")

;; Moves

(define_expand "movdf"
  [(set (match_operand:DF 0 "general_operand" "")
	(match_operand:DF 1 "general_operand" ""))]
  ""
  "if (GET_CODE (operands[0]) != REG)
     operands[1] = force_reg (DFmode, operands[1]);")

(define_insn ""
  [(set (match_operand:DF 0 "general_operand" "=d,d,d,d,d,<,m")
	(match_operand:DF 1 "general_operand"  "d,Q,m,G,H,d,d"))]
  "register_operand (operands[0], DFmode)
   || register_operand (operands[1], DFmode)"
  "@
   mov %1,%0
   ldb.d %1,%0
   ld.d %1,%0
   ld.d %u1,%0
   ld.l %v1,%0
   psh.l %1
   st.d %1,%0"
  [(set_attr "type" "alu,mldb,mldl,alu,alu,alu,mst")])

;; This is here so we can load any result of RTL constant folding
;; but do not use it on constants that can be loaded from memory.
;; It is never better and can be worse.

(define_insn ""
  [(set (match_operand:DF 0 "register_operand" "=d")
	(match_operand:DF 1 "const_double_operand" "F"))]
  "CONST_DOUBLE_MEM (operands[1]) == const0_rtx"
  "ld.u %u1,%0\;ld.w %v1,%0"
  [(set_attr "type" "xalu")])

(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 ""
  [(set (match_operand:SF 0 "general_operand" "=d,d,d,d,<,m")
	(match_operand:SF 1 "general_operand" "d,Q,m,F,d,d"))]
  "register_operand (operands[0], SFmode)
   || register_operand (operands[1], SFmode)"
  "@
   mov.s %1,%0
   ldb.s %1,%0
   ld.s %1,%0
   ld.s %1,%0
   psh.w %1
   st.s %1,%0"
  [(set_attr "type" "alu,mldb,mldw,alu,alu,mst")])

(define_expand "movdi"
  [(set (match_operand:DI 0 "general_operand" "")
	(match_operand:DI 1 "general_operand" ""))]
  ""
  "if (GET_CODE (operands[0]) != REG)
     operands[1] = force_reg (DImode, operands[1]);")

(define_insn ""
  [(set (match_operand:DI 0 "general_operand" "=d,d,d,d,d,<,m")
	(match_operand:DI 1 "general_operand" "d,Q,m,G,HI,d,d"))]
  "register_operand (operands[0], DImode)
   || register_operand (operands[1], DImode)"
  "@
   mov %1,%0
   ldb.l %1,%0
   ld.l %1,%0
   ld.d %u1,%0
   ld.l %1,%0
   psh.l %1
   st.l %1,%0"
  [(set_attr "type" "alu,mldb,mldl,alu,alu,alu,mst")])

;; This is here so we can load any result of RTL constant folding
;; but do not use it on constants that can be loaded from memory.
;; It is never better and can be worse.

(define_insn ""
  [(set (match_operand:DI 0 "register_operand" "=d")
	(match_operand:DI 1 "const_double_operand" "F"))]
  "CONST_DOUBLE_MEM (operands[1]) == const0_rtx"
  "ld.u %u1,%0\;ld.w %v1,%0"
  [(set_attr "type" "xalu")])

(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 ""
  [(set (match_operand:SI 0 "push_operand" "=<,<")
	(match_operand:SI 1 "nonmemory_operand" "Ad,i"))]
  ""
  "@
   psh.w %1
   pshea %a1")

(define_insn ""
  [(set (match_operand:SI 0 "general_operand" "=d,r,d,r,r,m")
	(match_operand:SI 1 "general_operand" "d,r,Q,m,i,r"))]
  "register_operand (operands[0], SImode)
   || register_operand (operands[1], SImode)"
  "@
   mov.w %1,%0
   mov %1,%0
   ldb.w %1,%0
   ld.w %1,%0
   ld.w %1,%0
   st.w %1,%0"
  [(set_attr "type" "alu,alu,mldb,mldw,alu,mst")])

(define_expand "movstrictsi"
  [(set (strict_low_part (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 ""
  [(set (strict_low_part (match_operand:SI 0 "general_operand" "+d,r,d,r,r,m"))
	(match_operand:SI 1 "general_operand" "d,r,Q,m,i,r"))]
  "register_operand (operands[0], SImode)
   || register_operand (operands[1], SImode)"
  "@
   mov.w %1,%0
   mov %1,%0
   ldb.w %1,%0
   ld.w %1,%0
   ld.w %1,%0
   st.w %1,%0"
  [(set_attr "type" "alu,alu,mldb,mldw,alu,mst")])

(define_expand "movhi"
  [(set (match_operand:HI 0 "general_operand" "")
	(match_operand:HI 1 "general_operand" ""))]
  ""
  "if (GET_CODE (operands[0]) != REG)
     operands[1] = force_reg (HImode, operands[1]);")

(define_insn ""
  [(set (match_operand:HI 0 "general_operand" "=d,r,d,r,r,<,m")
	(match_operand:HI 1 "general_operand" "d,r,Q,m,i,Ad,r"))]
  "register_operand (operands[0], HImode)
   || register_operand (operands[1], HImode)"
  "@
   mov.w %1,%0
   mov %1,%0
   ldb.h %1,%0
   ld.h %1,%0
   ld.w %1,%0
   psh.w %1
   st.h %1,%0"
  [(set_attr "type" "alu,alu,mldb,mldw,alu,alu,mst")])

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

(define_insn ""
  [(set (match_operand:QI 0 "general_operand" "=d,r,d,r,r,<,m")
	(match_operand:QI 1 "general_operand" "d,r,Q,m,i,Ad,r"))]
  "register_operand (operands[0], QImode)
   || register_operand (operands[1], QImode)"
  "@
   mov.w %1,%0
   mov %1,%0
   ldb.b %1,%0
   ld.b %1,%0
   ld.w %1,%0
   psh.w %1
   st.b %1,%0"
  [(set_attr "type" "alu,alu,mldb,mldw,alu,alu,mst")])

;; Expand block moves manually to get code that pipelines the loads.

(define_expand "movstrsi"
  [(set (match_operand:BLK 0 "memory_operand" "=m")
	(match_operand:BLK 1 "memory_operand" "m"))
   (use (match_operand:SI 2 "const_int_operand" "i"))
   (use (match_operand:SI 3 "const_int_operand" "i"))]
  ""
  " expand_movstr (operands); DONE; ")

;; Extension and truncation insns.
;; Those for integer source operand
;; are ordered widest source type first.

(define_insn "truncsiqi2"
  [(set (match_operand:QI 0 "register_operand" "=d,a")
	(truncate:QI (match_operand:SI 1 "register_operand" "d,a")))]
  ""
  "cvtw.b %1,%0")

(define_insn "truncsihi2"
  [(set (match_operand:HI 0 "register_operand" "=d,a")
	(truncate:HI (match_operand:SI 1 "register_operand" "d,a")))]
  ""
  "cvtw.h %1,%0")

(define_insn "trunchiqi2"
  [(set (match_operand:QI 0 "register_operand" "=r")
	(truncate:QI (match_operand:HI 1 "register_operand" "0")))]
  ""
  "")

(define_insn "truncdisi2"
  [(set (match_operand:SI 0 "register_operand" "=d")
	(truncate:SI (match_operand:DI 1 "register_operand" "d")))]
  ""
  "cvtl.w %1,%0")

(define_insn "extendsidi2"
  [(set (match_operand:DI 0 "register_operand" "=d")
	(sign_extend:DI (match_operand:SI 1 "register_operand" "d")))]
  ""
  "cvtw.l %1,%0")

(define_insn "extendhisi2"
  [(set (match_operand:SI 0 "register_operand" "=d,a")
	(sign_extend:SI (match_operand:HI 1 "register_operand" "d,a")))]
  ""
  "cvth.w %1,%0")

(define_insn "extendqihi2"
  [(set (match_operand:HI 0 "register_operand" "=d,a")
	(sign_extend:HI (match_operand:QI 1 "register_operand" "d,a")))]
  ""
  "cvtb.w %1,%0")

(define_insn "extendqisi2"
  [(set (match_operand:SI 0 "register_operand" "=d,a")
	(sign_extend:SI (match_operand:QI 1 "register_operand" "d,a")))]
  ""
  "cvtb.w %1,%0")

(define_insn "extendsfdf2"
  [(set (match_operand:DF 0 "register_operand" "=d")
	(float_extend:DF (match_operand:SF 1 "register_operand" "d")))]
  ""
  "cvts.d %1,%0"
  [(set_attr "type" "cvts")])

(define_insn "truncdfsf2"
  [(set (match_operand:SF 0 "register_operand" "=d")
	(float_truncate:SF (match_operand:DF 1 "register_operand" "d")))]
  ""
  "cvtd.s %1,%0"
  [(set_attr "type" "cvtd")])

(define_insn "zero_extendhisi2"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(zero_extend:SI (match_operand:HI 1 "register_operand" "0")))]
  ""
  "and #0xffff,%0")

(define_insn "zero_extendqihi2"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(zero_extend:HI (match_operand:QI 1 "register_operand" "0")))]
  ""
  "and #0xff,%0")

(define_insn "zero_extendqisi2"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(zero_extend:SI (match_operand:QI 1 "register_operand" "0")))]
  ""
  "and #0xff,%0")

(define_insn "zero_extendsidi2"
  [(set (match_operand:DI 0 "register_operand" "=d")
	(zero_extend:DI (match_operand:SI 1 "register_operand" "0")))]
  ""
  "ld.u #0,%0")

;; Fix-to-float conversion insns.
;; Note that the ones that start with SImode come first.
;; That is so that an operand that is a CONST_INT
;; (and therefore lacks a specific machine mode).
;; will be recognized as SImode (which is always valid)
;; rather than as QImode or HImode.

(define_insn "floatsisf2"
  [(set (match_operand:SF 0 "register_operand" "=d")
	(float:SF (match_operand:SI 1 "register_operand" "d")))]
  ""
  "cvtw.s %1,%0"
  [(set_attr "type" "cvts")])

(define_insn "floatdisf2"
  [(set (match_operand:SF 0 "register_operand" "=d")
	(float:SF (match_operand:DI 1 "register_operand" "d")))]
  ""
  "cvtl.s %1,%0"
  [(set_attr "type" "cvtd")])

(define_insn "floatsidf2"
  [(set (match_operand:DF 0 "register_operand" "=d")
	(float:DF (match_operand:SI 1 "register_operand" "d")))]
  "! TARGET_C1"
  "cvtw.d %1,%0"
  [(set_attr "type" "cvts")])

(define_insn "floatdidf2"
  [(set (match_operand:DF 0 "register_operand" "=d")
	(float:DF (match_operand:DI 1 "register_operand" "d")))]
  ""
  "cvtl.d %1,%0"
  [(set_attr "type" "cvtd")])

;; These are a little slower than gcc's normal way of doing unsigned
;; DI floats (if the DI number is "negative") but they avoid double
;; rounding and they avoid explicit constants.

(define_expand "floatunsdidf2"
  [(set (match_operand:DF 0 "register_operand" "=d")
	(float:DF (match_operand:DI 1 "register_operand" "d")))
   (set (cc0) (compare:DI (match_dup 3) (match_dup 1)))
   (set (pc)
	(if_then_else (le (cc0) (const_int 0))
		      (label_ref (match_dup 4))
		      (pc)))
   (set (match_dup 2) (lshiftrt:DI (match_dup 1) (const_int 1)))
   (set (match_dup 0) (float:DF (match_dup 2)))
   (set (match_dup 0) (plus:DF (match_dup 0) (match_dup 0)))
   (match_dup 4)
   (set (match_dup 0) (match_dup 0))]
  ""
  "
{
  operands[2] = gen_reg_rtx (DImode);
  operands[3] = force_reg (DImode, const0_rtx);
  operands[4] = gen_label_rtx ();
}")

(define_expand "floatunsdisf2"
  [(set (match_operand:SF 0 "register_operand" "=d")
	(float:SF (match_operand:DI 1 "register_operand" "d")))
   (set (cc0) (compare:DI (match_dup 3) (match_dup 1)))
   (set (pc)
	(if_then_else (le (cc0) (const_int 0))
		      (label_ref (match_dup 4))
		      (pc)))
   (set (match_dup 2) (lshiftrt:DI (match_dup 1) (const_int 1)))
   (set (match_dup 0) (float:SF (match_dup 2)))
   (set (match_dup 0) (plus:SF (match_dup 0) (match_dup 0)))
   (match_dup 4)
   (set (match_dup 0) (match_dup 0))]
  ""
  "
{
  operands[2] = gen_reg_rtx (DImode);
  operands[3] = force_reg (DImode, const0_rtx);
  operands[4] = gen_label_rtx ();
}")

;; These patterns are identical to gcc's default action 
;; if DI->DF and DI->SF are not present.  There are here
;; only to prevent SI->*F from promoting to DI->*F.

(define_expand "floatunssidf2"
  [(set (match_dup 2)
	(zero_extend:DI (match_operand:SI 1 "register_operand" "")))
   (set (match_operand:DF 0 "register_operand" "")
	(float:DF (match_dup 2)))]
  ""
  "operands[2] = gen_reg_rtx (DImode);")

(define_expand "floatunssisf2"
  [(set (match_dup 2)
        (zero_extend:DI (match_operand:SI 1 "register_operand" "")))
   (set (match_operand:SF 0 "register_operand" "")
        (float:SF (match_dup 2)))]
  ""
  "operands[2] = gen_reg_rtx (DImode);")

;; Float-to-fix conversion insns.

(define_insn "fix_truncsfsi2"
  [(set (match_operand:SI 0 "register_operand" "=d")
	(fix:SI (fix:SF (match_operand:SF 1 "register_operand" "d"))))]
  ""
  "cvts.w %1,%0"
  [(set_attr "type" "cvts")])

(define_insn "fix_truncsfdi2"
  [(set (match_operand:DI 0 "register_operand" "=d")
	(fix:DI (fix:SF (match_operand:SF 1 "register_operand" "d"))))]
  ""
  "cvts.l %1,%0"
  [(set_attr "type" "cvts")])

(define_insn "fix_truncdfsi2"
  [(set (match_operand:SI 0 "register_operand" "=d")
	(fix:SI (fix:DF (match_operand:DF 1 "register_operand" "d"))))]
  ""
  "cvtd.l %1,%0"
  [(set_attr "type" "cvtd")])

(define_insn "fix_truncdfdi2"
  [(set (match_operand:DI 0 "register_operand" "=d")
	(fix:DI (fix:DF (match_operand:DF 1 "register_operand" "d"))))]
  ""
  "cvtd.l %1,%0"
  [(set_attr "type" "cvtd")])

;;- All kinds of add instructions.

(define_insn "adddf3"
  [(set (match_operand:DF 0 "register_operand" "=d")
	(plus:DF (match_operand:DF 1 "register_operand" "%0")
		 (match_operand:DF 2 "register_operand" "d")))]
  ""
  "add.d %2,%0"
  [(set_attr "type" "addd")])

(define_insn "addsf3"
  [(set (match_operand:SF 0 "register_operand" "=d")
	(plus:SF (match_operand:SF 1 "register_operand" "%0")
		 (match_operand:SF 2 "nonmemory_operand" "dF")))]
  ""
  "add.s %2,%0"
  [(set_attr "type" "adds")])

(define_insn "adddi3"
  [(set (match_operand:DI 0 "register_operand" "=d")
	(plus:DI (match_operand:DI 1 "register_operand" "%0")
		 (match_operand:DI 2 "register_operand" "d")))]
  ""
  "add.l %2,%0")

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

(define_insn ""
  [(set (match_operand:SI 0 "register_operand" "=a")
	(plus:SI (match_operand:SI 1 "register_operand" "%A")
		 (match_operand:SI 2 "immediate_operand" "i")))]
  "operands[1] == frame_pointer_rtx || operands[1] == arg_pointer_rtx"
  "ldea %a2(%1),%0")

(define_insn ""
  [(set (match_operand:SI 0 "register_operand" "=a")
	(plus:SI (match_operand:SI 1 "register_operand" "%a")
		 (match_operand:SI 2 "nonmemory_operand" "ri")))]
  "operands[1] == stack_pointer_rtx && operands[0] != stack_pointer_rtx"
  "mov %1,%0\;add.w %2,%0")

(define_insn ""
  [(set (match_operand:SI 0 "push_operand" "=<")
	(plus:SI (match_operand:SI 1 "register_operand" "A")
		 (match_operand:SI 2 "immediate_operand" "i")))]
  "operands[1] != stack_pointer_rtx"
  "pshea %a2(%1)"
  [(set_attr "type" "mst")])

(define_insn ""
  [(set (match_operand:SI 0 "register_operand" "=d,a,a")
	(plus:SI (match_operand:SI 1 "register_operand" "%0,0,A")
		 (match_operand:SI 2 "nonmemory_operand" "di,ri,i")))]
  "TARGET_C1"
  "@
   add.w %2,%0
   add.w %2,%0
   ldea %a2(%1),%0")

(define_insn ""
  [(set (match_operand:SI 0 "register_operand" "=d,a,r")
	(plus:SI (match_operand:SI 1 "register_operand" "%0,0,A")
		 (match_operand:SI 2 "nonmemory_operand" "di,ri,i")))]
  ""
  "@
   add.w %2,%0
   add.w %2,%0
   ldea %a2(%1),%0")

(define_insn "addhi3"
  [(set (match_operand:HI 0 "register_operand" "=d,a")
	(plus:HI (match_operand:HI 1 "register_operand" "%0,0")
		 (match_operand:HI 2 "nonmemory_operand" "di,ai")))]
  ""
  "add.h %2,%0")

(define_insn "addqi3"
  [(set (match_operand:QI 0 "register_operand" "=d,d")
	(plus:QI (match_operand:QI 1 "register_operand" "%0,0")
		 (match_operand:QI 2 "nonmemory_operand" "d,i")))]
  ""
  "@
   add.b %2,%0
   add.w %2,%0")

;;- All kinds of subtract instructions.

(define_insn "subdf3"
  [(set (match_operand:DF 0 "register_operand" "=d")
	(minus:DF (match_operand:DF 1 "register_operand" "0")
		  (match_operand:DF 2 "register_operand" "d")))]
  ""
  "sub.d %2,%0"
  [(set_attr "type" "addd")])

(define_insn "subsf3"
  [(set (match_operand:SF 0 "register_operand" "=d")
	(minus:SF (match_operand:SF 1 "register_operand" "0")
		  (match_operand:SF 2 "nonmemory_operand" "dF")))]
  ""
  "sub.s %2,%0"
  [(set_attr "type" "adds")])

(define_insn "subdi3"
  [(set (match_operand:DI 0 "register_operand" "=d")
	(minus:DI (match_operand:DI 1 "register_operand" "0")
		  (match_operand:DI 2 "register_operand" "d")))]
  ""
  "sub.l %2,%0")

(define_insn "subsi3"
  [(set (match_operand:SI 0 "register_operand" "=d,a,?d,?a")
	(minus:SI (match_operand:SI 1 "nonmemory_operand" "0,0,di,ai")
		  (match_operand:SI 2 "nonmemory_operand" "di,ai,0,0")))]
  ""
  "@
  sub.w %2,%0
  sub.w %2,%0
  sub.w %1,%0\;neg.w %0,%0
  sub.w %1,%0\;neg.w %0,%0")

(define_insn "subhi3"
  [(set (match_operand:HI 0 "register_operand" "=d,a")
	(minus:HI (match_operand:HI 1 "register_operand" "0,0")
		  (match_operand:HI 2 "nonmemory_operand" "di,ai")))]
  ""
  "sub.h %2,%0")

(define_insn "subqi3"
  [(set (match_operand:QI 0 "register_operand" "=d,d")
	(minus:QI (match_operand:QI 1 "register_operand" "0,0")
		  (match_operand:QI 2 "nonmemory_operand" "d,i")))]
  ""
  "@
   sub.b %2,%0
   sub.w %2,%0")

;;- Multiply instructions.

(define_insn "muldf3"
  [(set (match_operand:DF 0 "register_operand" "=d")
	(mult:DF (match_operand:DF 1 "register_operand" "%0")
		 (match_operand:DF 2 "register_operand" "d")))]
  ""
  "mul.d %2,%0"
  [(set_attr "type" "muld")])

(define_insn "mulsf3"
  [(set (match_operand:SF 0 "register_operand" "=d")
	(mult:SF (match_operand:SF 1 "register_operand" "%0")
		 (match_operand:SF 2 "nonmemory_operand" "dF")))]
  ""
  "mul.s %2,%0"
  [(set_attr "type" "muls")])

(define_insn "muldi3"
  [(set (match_operand:DI 0 "register_operand" "=d")
	(mult:DI (match_operand:DI 1 "register_operand" "%0")
		 (match_operand:DI 2 "register_operand" "d")))]
  ""
  "mul.l %2,%0"
  [(set_attr "type" "mull")])

(define_insn "mulsi3"
  [(set (match_operand:SI 0 "register_operand" "=d,a")
	(mult:SI (match_operand:SI 1 "register_operand" "%0,0")
		 (match_operand:SI 2 "nonmemory_operand" "di,ai")))]
  ""
  "mul.w %2,%0"
  [(set_attr "type" "mulw")])

(define_insn "mulhi3"
  [(set (match_operand:HI 0 "register_operand" "=d,a")
	(mult:HI (match_operand:HI 1 "register_operand" "%0,0")
		 (match_operand:HI 2 "nonmemory_operand" "di,ai")))]
  ""
  "mul.h %2,%0"
  [(set_attr "type" "mulw")])

(define_insn "mulqi3"
  [(set (match_operand:QI 0 "register_operand" "=d,d")
	(mult:QI (match_operand:QI 1 "register_operand" "%0,0")
		 (match_operand:QI 2 "nonmemory_operand" "d,i")))]
  ""
  "@
   mul.b %2,%0
   mul.w %2,%0"
  [(set_attr "type" "mulw,mulw")])

;;- Divide instructions.

(define_insn "divdf3"
  [(set (match_operand:DF 0 "register_operand" "=d")
	(div:DF (match_operand:DF 1 "register_operand" "0")
		(match_operand:DF 2 "register_operand" "d")))]
  ""
  "div.d %2,%0"
  [(set_attr "type" "divd")])

(define_insn "divsf3"
  [(set (match_operand:SF 0 "register_operand" "=d")
	(div:SF (match_operand:SF 1 "register_operand" "0")
		(match_operand:SF 2 "nonmemory_operand" "dF")))]
  ""
  "div.s %2,%0"
  [(set_attr "type" "divs")])

(define_insn "divdi3"
  [(set (match_operand:DI 0 "register_operand" "=d")
	(div:DI (match_operand:DI 1 "register_operand" "0")
		(match_operand:DI 2 "register_operand" "d")))]
  ""
  "div.l %2,%0"
  [(set_attr "type" "divl")])

(define_expand "udivsi3"
  [(set (match_dup 3)
	(zero_extend:DI (match_operand:SI 1 "register_operand" "")))
   (set (match_dup 4)
	(zero_extend:DI (match_operand:SI 2 "register_operand" "")))
   (set (match_dup 3)
	(div:DI (match_dup 3) (match_dup 4)))
   (set (match_operand:SI 0 "register_operand" "")
	(subreg:SI (match_dup 3) 0))]
  ""
  "operands[3] = gen_reg_rtx (DImode);
   operands[4] = gen_reg_rtx (DImode); ")

(define_insn "udivdi3"
  [(set (match_operand:DI 0 "register_operand" "=d")
	(udiv:DI (match_operand:DI 1 "register_operand" "d")
		 (match_operand:DI 2 "register_operand" "d")))]
  ""
  "psh.l %2\;psh.l %1\;callq udiv64\;pop.l %0\;add.w #8,sp")

(define_insn "divsi3"
  [(set (match_operand:SI 0 "register_operand" "=d,a")
	(div:SI (match_operand:SI 1 "register_operand" "0,0")
		(match_operand:SI 2 "nonmemory_operand" "di,ai")))]
  ""
  "div.w %2,%0"
  [(set_attr "type" "divw")])

(define_insn "divhi3"
  [(set (match_operand:HI 0 "register_operand" "=d,a")
	(div:HI (match_operand:HI 1 "register_operand" "0,0")
		(match_operand:HI 2 "nonmemory_operand" "di,ai")))]
  ""
  "div.h %2,%0"
  [(set_attr "type" "divw")])

(define_insn "divqi3"
  [(set (match_operand:QI 0 "register_operand" "=d")
	(div:QI (match_operand:QI 1 "register_operand" "0")
		(match_operand:QI 2 "register_operand" "d")))]
  ""
  "div.b %2,%0"
  [(set_attr "type" "divw")])

;;- Bit clear instructions.

(define_insn ""
  [(set (match_operand:DI 0 "register_operand" "=d")
	(and:DI (match_operand:DI 1 "register_operand" "%0")
		(match_operand:DI 2 "" "")))]
  "(GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0)
   || (GET_CODE (operands[2]) == CONST_DOUBLE
       && CONST_DOUBLE_HIGH (operands[2]) == -1)"
  "and %2,%0")

(define_insn "anddi3"
  [(set (match_operand:DI 0 "register_operand" "=d")
	(and:DI (match_operand:DI 1 "register_operand" "%0")
		(match_operand:DI 2 "register_operand" "d")))]
  ""
  "and %2,%0")

(define_insn "andsi3"
  [(set (match_operand:SI 0 "register_operand" "=d,a")
	(and:SI (match_operand:SI 1 "register_operand" "%0,0")
		(match_operand:SI 2 "nonmemory_operand" "di,ai")))]
  ""
  "and %2,%0")

(define_insn "andhi3"
  [(set (match_operand:HI 0 "register_operand" "=d,a")
	(and:HI (match_operand:HI 1 "register_operand" "%0,0")
		(match_operand:HI 2 "nonmemory_operand" "di,ai")))]
  ""
  "and %2,%0")

(define_insn "andqi3"
  [(set (match_operand:QI 0 "register_operand" "=d,a")
	(and:QI (match_operand:QI 1 "register_operand" "%0,0")
		(match_operand:QI 2 "nonmemory_operand" "di,ai")))]
  ""
  "and %2,%0")

;;- Bit set instructions.

(define_insn ""
  [(set (match_operand:DI 0 "register_operand" "=d")
	(ior:DI (match_operand:DI 1 "register_operand" "%0")
		(match_operand:DI 2 "" "")))]
  "(GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 0)
   || (GET_CODE (operands[2]) == CONST_DOUBLE
       && CONST_DOUBLE_HIGH (operands[2]) == 0)"
  "or %2,%0")

(define_insn "iordi3"
  [(set (match_operand:DI 0 "register_operand" "=d")
	(ior:DI (match_operand:DI 1 "register_operand" "%0")
		(match_operand:DI 2 "register_operand" "d")))]
  ""
  "or %2,%0")

(define_insn "iorsi3"
  [(set (match_operand:SI 0 "register_operand" "=d,a")
	(ior:SI (match_operand:SI 1 "register_operand" "%0,0")
		(match_operand:SI 2 "nonmemory_operand" "di,ai")))]
  ""
  "or %2,%0")

(define_insn "iorhi3"
  [(set (match_operand:HI 0 "register_operand" "=d,a")
	(ior:HI (match_operand:HI 1 "register_operand" "%0,0")
		(match_operand:HI 2 "nonmemory_operand" "di,ai")))]
  ""
  "or %2,%0")

(define_insn "iorqi3"
  [(set (match_operand:QI 0 "register_operand" "=d,a")
	(ior:QI (match_operand:QI 1 "register_operand" "%0,0")
		(match_operand:QI 2 "nonmemory_operand" "di,ai")))]
  ""
  "or %2,%0")

;;- xor instructions.

(define_insn ""
  [(set (match_operand:DI 0 "register_operand" "=d")
	(xor:DI (match_operand:DI 1 "register_operand" "%0")
		(match_operand:DI 2 "" "")))]
  "(GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 0)
   || (GET_CODE (operands[2]) == CONST_DOUBLE
       && CONST_DOUBLE_HIGH (operands[2]) == 0)"
  "xor %2,%0")

(define_insn "xordi3"
  [(set (match_operand:DI 0 "register_operand" "=d")
	(xor:DI (match_operand:DI 1 "register_operand" "%0")
		(match_operand:DI 2 "register_operand" "d")))]
  ""
  "xor %2,%0")

(define_insn "xorsi3"
  [(set (match_operand:SI 0 "register_operand" "=d,a")
	(xor:SI (match_operand:SI 1 "register_operand" "%0,0")
		(match_operand:SI 2 "nonmemory_operand" "di,ai")))]
  ""
  "xor %2,%0")

(define_insn "xorhi3"
  [(set (match_operand:HI 0 "register_operand" "=d,a")
	(xor:HI (match_operand:HI 1 "register_operand" "%0,0")
		(match_operand:HI 2 "nonmemory_operand" "di,ai")))]
  ""
  "xor %2,%0")

(define_insn "xorqi3"
  [(set (match_operand:QI 0 "register_operand" "=d,a")
	(xor:QI (match_operand:QI 1 "register_operand" "%0,0")
		(match_operand:QI 2 "nonmemory_operand" "di,ai")))]
  ""
  "xor %2,%0")

(define_insn "negdf2"
  [(set (match_operand:DF 0 "register_operand" "=d")
	(neg:DF (match_operand:DF 1 "register_operand" "d")))]
  ""
  "neg.d %1,%0"
  [(set_attr "type" "addd")])

(define_insn "negsf2"
  [(set (match_operand:SF 0 "register_operand" "=d")
	(neg:SF (match_operand:SF 1 "register_operand" "d")))]
  ""
  "neg.s %1,%0"
  [(set_attr "type" "adds")])

(define_insn "negdi2"
  [(set (match_operand:DI 0 "register_operand" "=d")
	(neg:DI (match_operand:DI 1 "register_operand" "d")))]
  ""
  "neg.l %1,%0")

(define_insn "negsi2"
  [(set (match_operand:SI 0 "register_operand" "=d,a")
	(neg:SI (match_operand:SI 1 "register_operand" "d,a")))]
  ""
  "neg.w %1,%0")

(define_insn "neghi2"
  [(set (match_operand:HI 0 "register_operand" "=d,a")
	(neg:HI (match_operand:HI 1 "register_operand" "d,a")))]
  ""
  "neg.h %1,%0")

(define_insn "negqi2"
  [(set (match_operand:QI 0 "register_operand" "=d")
	(neg:QI (match_operand:QI 1 "register_operand" "d")))]
  ""
  "neg.b %1,%0")

(define_insn "one_cmpldi2"
  [(set (match_operand:DI 0 "register_operand" "=d")
	(not:DI (match_operand:DI 1 "register_operand" "d")))]
  ""
  "not %1,%0")

(define_insn "one_cmplsi2"
  [(set (match_operand:SI 0 "register_operand" "=d,a")
	(not:SI (match_operand:SI 1 "register_operand" "d,a")))]
  ""
  "not %1,%0")

(define_insn "one_cmplhi2"
  [(set (match_operand:HI 0 "register_operand" "=d,a")
	(not:HI (match_operand:HI 1 "register_operand" "d,a")))]
  ""
  "not %1,%0")

(define_insn "one_cmplqi2"
  [(set (match_operand:QI 0 "register_operand" "=d,a")
	(not:QI (match_operand:QI 1 "register_operand" "d,a")))]
  ""
  "not %1,%0")

;;- Shifts
;;
;; The extreme profusion of patterns here is due to the different-speed
;; shifts on different machines, and the C1's lack of word shift S-register
;; instructions.

;; SImode

;; Arithmetic left 1, 1 cycle on all machines via add

(define_insn ""
  [(set (match_operand:SI 0 "register_operand" "=r")
	(ashift:SI (match_operand:SI 1 "register_operand" "0")
		   (const_int 1)))]
  ""
  "add.w %0,%0")

;; C34 general shift is 1 cycle

(define_insn ""
  [(set (match_operand:SI 0 "register_operand" "=d,a")
	(ashift:SI (match_operand:SI 1 "register_operand" "0,0")
		   (match_operand:SI 2 "nonmemory_operand" "di,ai")))]
  "TARGET_C34"
  "@
   shf.w %2,%0
   shf %2,%0"
  [(set_attr "type" "shfw,shfw")])

;; else shift left 0..7 is 1 cycle if we use an A register

(define_insn ""
  [(set (match_operand:SI 0 "register_operand" "=a,?d")
	(ashift:SI (match_operand:SI 1 "register_operand" "0,0")
		   (match_operand:SI 2 "immediate_operand" "ai,di")))]
  "TARGET_C1 && INTVAL (operands[2]) < (unsigned) 8"
  "@
   shf %2,%0
   shf %2,%0"
  [(set_attr "type" "alu,shfl")])

(define_insn ""
  [(set (match_operand:SI 0 "register_operand" "=a,?d")
	(ashift:SI (match_operand:SI 1 "register_operand" "0,0")
		   (match_operand:SI 2 "immediate_operand" "ai,di")))]
  "INTVAL (operands[2]) < (unsigned) 8"
  "@
   shf %2,%0
   shf.w %2,%0"
  [(set_attr "type" "alu,shfw")])

;; else general left shift

(define_insn ""
  [(set (match_operand:SI 0 "register_operand" "=d,a")
	(ashift:SI (match_operand:SI 1 "register_operand" "0,0")
		   (match_operand:SI 2 "nonmemory_operand" "di,ai")))]
  "TARGET_C1"
  "@
   shf %2,%0
   shf %2,%0"
  [(set_attr "type" "shfl,shfw")])

;; but C2 left shift by a constant is faster via multiply

(define_insn ""
  [(set (match_operand:SI 0 "register_operand" "=r")
	(ashift:SI (match_operand:SI 1 "register_operand" "0")
		   (match_operand:SI 2 "const_int_operand" "i")))]
  "TARGET_C2 && INTVAL (operands[2]) < (unsigned) 32"
  "mul.w %z2,%0"
  [(set_attr "type" "mulw")])

(define_insn "ashlsi3"
  [(set (match_operand:SI 0 "register_operand" "=d,a")
	(ashift:SI (match_operand:SI 1 "register_operand" "0,0")
		   (match_operand:SI 2 "nonmemory_operand" "di,ai")))]
  ""
  "@
   shf.w %2,%0
   shf %2,%0"
  [(set_attr "type" "shfw,shfw")])

;; Logical right, general
;; The hardware wants the negative of the shift count

(define_expand "lshrsi3"
  [(set (match_operand:SI 0 "register_operand" "")
	(lshiftrt:SI (match_operand:SI 1 "register_operand" "")
		     (neg:SI (match_operand:SI 2 "nonmemory_operand" ""))))]
  ""
  "operands[2] = negate_rtx (SImode, operands[2]);")

;; C1 lacks word shift S reg

(define_insn ""
  [(set
    (match_operand:SI 0 "register_operand" "=a,?d")
    (lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0")
		 (neg:SI (match_operand:SI 2 "nonmemory_operand" "ai,di"))))]
  "TARGET_C1"
  "@
   shf %2,%0
   ld.u #0,%0\;shf %2,%0"
  [(set_attr "type" "shfw,shfl")])

;; general case

(define_insn ""
  [(set
    (match_operand:SI 0 "register_operand" "=d,a")
    (lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0")
		 (neg:SI (match_operand:SI 2 "nonmemory_operand" "di,ai"))))]
  ""
  "@
   shf.w %2,%0
   shf %2,%0"
  [(set_attr "type" "shfw,shfw")])

;; Patterns without neg produced by constant folding

(define_insn ""
  [(set
    (match_operand:SI 0 "register_operand" "=a,?d")
    (lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0")
		 (match_operand:SI 2 "immediate_operand" "i,i")))]
  "TARGET_C1"
  "@
   shf #%n2,%0
   ld.u #0,%0\;shf #%n2,%0"
  [(set_attr "type" "shfw,shfl")])

(define_insn ""
  [(set
    (match_operand:SI 0 "register_operand" "=d,a")
    (lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0")
		 (match_operand:SI 2 "immediate_operand" "i,i")))]
  ""
  "@
   shf.w #%n2,%0
   shf #%n2,%0"
  [(set_attr "type" "shfw,shfw")])

;; Arithmetic right, general
;; Sign-extend to 64 bits, then shift that.  Works for 0..32.

(define_expand "ashrsi3"
  [(set (match_operand:SI 0 "register_operand" "")
	(ashiftrt:SI (match_operand:SI 1 "register_operand" "")
		     (neg:SI (match_operand:SI 2 "nonmemory_operand" ""))))]
  ""
  "operands[2] = negate_rtx (SImode, operands[2]);")

(define_insn ""
  [(set (match_operand:SI 0 "register_operand" "=d,&d")
	(ashiftrt:SI (match_operand:SI 1 "register_operand" "0,d")
		     (neg:SI
		      (match_operand:SI 2 "nonmemory_operand" "di,di"))))]
  ""
  "cvtw.l %1,%0\;shf %2,%0"
  [(set_attr "type" "shfl,shfl")])

(define_insn ""
  [(set (match_operand:SI 0 "register_operand" "=d")
	(ashiftrt:SI (match_operand:SI 1 "register_operand" "d")
		     (match_operand:SI 2 "immediate_operand" "i")))]
  ""
  "cvtw.l %1,%0\;shf #%n2,%0"
  [(set_attr "type" "shfl")])

;; DImode
;; Arithmetic left, 1-cycle

(define_insn ""
  [(set (match_operand:DI 0 "register_operand" "=d")
	(ashift:DI (match_operand:DI 1 "register_operand" "0")
		   (const_int 1)))]
  ""
  "add.l %0,%0")

;; Arithmetic left, general

(define_insn "ashldi3"
  [(set (match_operand:DI 0 "register_operand" "=d")
	(ashift:DI (match_operand:DI 1 "register_operand" "0")
		   (match_operand:SI 2 "nonmemory_operand" "di")))]
  ""
  "shf %2,%0"
  [(set_attr "type" "shfl")])

;; Can omit zero- or sign-extend if shift is 32 or more.

(define_insn ""
  [(set (match_operand:DI 0 "register_operand" "=d")
	(ashift:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "0"))
		   (match_operand:SI 2 "const_int_operand" "i")))]
  "INTVAL (operands[2]) >= 32"
  "shf %2,%0"
  [(set_attr "type" "shfl")])

(define_insn ""
  [(set (match_operand:DI 0 "register_operand" "=d")
	(ashift:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "0"))
		   (match_operand:SI 2 "const_int_operand" "i")))]
  "INTVAL (operands[2]) >= 32"
  "shf %2,%0"
  [(set_attr "type" "shfl")])

;; Logical right, general

(define_expand "lshrdi3"
  [(set (match_operand:DI 0 "register_operand" "")
	(lshiftrt:DI (match_operand:DI 1 "register_operand" "")
		     (neg:SI (match_operand:SI 2 "nonmemory_operand" ""))))]
  ""
  "operands[2] = negate_rtx (SImode, operands[2]);")

(define_insn ""
  [(set (match_operand:DI 0 "register_operand" "=d")
	(lshiftrt:DI (match_operand:DI 1 "register_operand" "0")
		     (neg:SI (match_operand:SI 2 "nonmemory_operand" "di"))))]
  ""
  "shf %2,%0"
  [(set_attr "type" "shfl")])

(define_insn ""
  [(set (match_operand:DI 0 "register_operand" "=d")
	(lshiftrt:DI (match_operand:DI 1 "register_operand" "0")
		     (match_operand:SI 2 "immediate_operand" "i")))]
  ""
  "shf #%n2,%0"
  [(set_attr "type" "shfl")])

;; Arithmetic right, general
;; Use
;;     ((a >> b) ^ signbit) - signbit
;; where signbit is (1 << 63) >> b
;; Works for 0..63.  Does not work for 64; unfortunate but valid.

(define_expand "ashrdi3"
  [(set (match_operand:DI 0 "register_operand" "")
	(lshiftrt:DI (match_operand:DI 1 "register_operand" "")
		     (neg:SI (match_operand:SI 2 "nonmemory_operand" ""))))
   (set (match_dup 3) (lshiftrt:DI (match_dup 3) (neg:SI (match_dup 2))))
   (set (match_dup 0) (xor:DI (match_dup 0) (match_dup 3)))
   (set (match_dup 0) (minus:DI (match_dup 0) (match_dup 3)))]
  ""
  "
{
  if (GET_CODE (operands[2]) == CONST_INT)
    switch (INTVAL (operands[2]))
      {
      case 32:
	emit_insn (gen_ashrdi3_32 (operands[0], operands[1]));
	DONE;
      }

  operands[2] = negate_rtx (SImode, operands[2]);
  operands[3] = force_reg (DImode, immed_double_const (0, 1 << 31, DImode));
}")

;; Arithmetic right 32, a common case that can save a couple of insns.

(define_expand "ashrdi3_32"
  [(set (match_operand:DI 0 "register_operand" "")
	(lshiftrt:DI (match_operand:DI 1 "register_operand" "")
		     (const_int 32)))
   (set (match_dup 0)
	(sign_extend:DI (subreg:SI (match_dup 0) 0)))]
  ""
  "")

;; __builtin instructions

(define_insn "sqrtdf2"
  [(set (match_operand:DF 0 "register_operand" "=d")
	(sqrt:DF (match_operand:DF 1 "register_operand" "0")))]
  "! TARGET_C1 && flag_unsafe_math_optimizations"
  "sqrt.d %0"
  [(set_attr "type" "divd")])

(define_insn "sqrtsf2"
  [(set (match_operand:SF 0 "register_operand" "=d")
	(sqrt:SF (match_operand:SF 1 "register_operand" "0")))]
  "! TARGET_C1 && flag_unsafe_math_optimizations"
  "sqrt.s %0"
  [(set_attr "type" "divs")])

(define_insn "sindf2"
  [(set (match_operand:DF 0 "register_operand" "=d")
	(unspec:DF [(match_operand:DF 1 "register_operand" "0")] 1))]
  "! TARGET_C1 && flag_unsafe_math_optimizations"
  "sin.d %0")

(define_insn "sinsf2"
  [(set (match_operand:SF 0 "register_operand" "=d")
	(unspec:SF [(match_operand:SF 1 "register_operand" "0")] 1))]
  "! TARGET_C1 && flag_unsafe_math_optimizations"
  "sin.s %0")

(define_insn "cosdf2"
  [(set (match_operand:DF 0 "register_operand" "=d")
	(unspec:DF [(match_operand:DF 1 "register_operand" "0")] 2))]
  "! TARGET_C1 && flag_unsafe_math_optimizations"
  "cos.d %0")

(define_insn "cossf2"
  [(set (match_operand:SF 0 "register_operand" "=d")
	(unspec:SF [(match_operand:SF 1 "register_operand" "0")] 2))]
  "! TARGET_C1 && flag_unsafe_math_optimizations"
  "cos.s %0")

(define_insn "ftruncdf2"
  [(set (match_operand:DF 0 "register_operand" "=d")
	(fix:DF (match_operand:DF 1 "register_operand" "d")))]
  "! TARGET_C1"
  "frint.d %1,%0"
  [(set_attr "type" "cvtd")])

(define_insn "ftruncsf2"
  [(set (match_operand:SF 0 "register_operand" "=d")
	(fix:SF (match_operand:SF 1 "register_operand" "d")))]
  "! TARGET_C1"
  "frint.s %1,%0"
  [(set_attr "type" "cvts")])

(define_insn ""
  [(set (match_operand:SI 0 "register_operand" "=d")
	(minus:SI (ffs:SI (match_operand:SI 1 "register_operand" "d"))
		  (const_int 1)))]
  ""
  "tzc %1,%0\;le.w #32,%0\;jbrs.f L0%=\;ld.w #-1,%0\\nL0%=:")

(define_expand "ffssi2"
  [(set (match_operand:SI 0 "register_operand" "=d")
	(minus:SI (ffs:SI (match_operand:SI 1 "register_operand" "d"))
		  (const_int 1)))
   (set (match_dup 0)
	(plus:SI (match_dup 0)
		 (const_int 1)))]
  ""
  "")

(define_insn "abssf2"
  [(set (match_operand:SF 0 "register_operand" "=d")
	(abs:SF (match_operand:SF 1 "register_operand" "0")))]
  ""
  "and #0x7fffffff,%0")

(define_expand "absdf2"
  [(set (subreg:DI (match_operand:DF 0 "register_operand" "=d") 0)
	(and:DI (subreg:DI (match_operand:DF 1 "register_operand" "d") 0)
		(match_dup 2)))]
  ""
  "operands[2] = force_reg (DImode,
                            immed_double_const (-1, 0x7fffffff, DImode));")

;;- Compares

(define_insn "cmpdi"
  [(set (cc0)
	(compare (match_operand:DI 0 "register_operand" "d")
		 (match_operand:DI 1 "register_operand" "d")))]
  ""
  "* return output_cmp (operands[0], operands[1], 'l');")

(define_insn ""
  [(set (cc0) (match_operand:DI 0 "register_operand" "d"))
   (clobber (match_scratch:DI 1 "=d"))]
  "next_insn_tests_no_inequality (insn)"
  "* return output_cmp (operands[0], operands[1], 'L');")

(define_insn "cmpsi"
  [(set (cc0)
	(compare (match_operand:SI 0 "register_operand" "d,a")
		 (match_operand:SI 1 "nonmemory_operand" "di,ai")))]
  ""
  "* return output_cmp (operands[0], operands[1], 'w');")

(define_insn "cmphi"
  [(set (cc0)
	(compare (match_operand:HI 0 "register_operand" "d,a")
		 (match_operand:HI 1 "nonmemory_operand" "di,ai")))]
  ""
  "* return output_cmp (operands[0], operands[1], 'h');")

; cmpqi is intentionally omitted.
;
; gcc will sign-extend or zero-extend the operands to the next
; wider mode, HImode.
;
; For reg .cmp. constant, we just go with the halfword immediate
; instruction.  Perhaps the widening insn can be cse'd or combined away.
; If not, we're still as good as loading a byte constant into a register
; to do a reg-reg byte compare.
;
; The following patterns pick up cases that can use reg .cmp. reg after all.

(define_insn ""
  [(set (cc0)
	(compare
	 (sign_extend:HI (match_operand:QI 0 "register_operand" "d"))
	 (sign_extend:HI (match_operand:QI 1 "register_operand" "d"))))]
  ""
  "* return output_cmp (operands[0], operands[1], 'b');")

(define_insn ""
  [(set (cc0)
	(compare
	 (ashift:HI (subreg:HI (match_operand:QI 0 "register_operand" "d") 0)
		    (const_int 8))
	 (ashift:HI (subreg:HI (match_operand:QI 1 "register_operand" "d") 0)
		    (const_int 8))))]
  ""
  "* return output_cmp (operands[0], operands[1], 'b');")

(define_insn ""
  [(set (cc0)
	(compare (match_operand:QI 0 "register_operand" "d")
		 (match_operand:QI 1 "register_operand" "d")))]
  ""
  "* return output_cmp (operands[0], operands[1], 'b');")

(define_insn ""
  [(set (cc0) (match_operand:QI 0 "register_operand" "d"))
   (clobber (match_scratch:QI 1 "=d"))]
  "next_insn_tests_no_inequality (insn)"
  "* return output_cmp (operands[0], operands[1], 'B');")

(define_insn ""
  [(set (cc0) (subreg (match_operand:QI 0 "register_operand" "d") 0))
   (clobber (match_scratch:QI 1 "=d"))]
  "next_insn_tests_no_inequality (insn)"
  "* return output_cmp (operands[0], operands[1], 'B');")

(define_insn ""
  [(set (cc0)
	(zero_extend (subreg (match_operand:QI 0 "register_operand" "d") 0)))
   (clobber (match_scratch:QI 1 "=d"))]
  "next_insn_tests_no_inequality (insn)"
  "* return output_cmp (operands[0], operands[1], 'B');")

(define_insn "cmpdf"
  [(set (cc0)
	(compare (match_operand:DF 0 "register_operand" "d")
		 (match_operand:DF 1 "register_operand" "d")))]
  ""
  "* return output_cmp (operands[0], operands[1], 'd');")

(define_insn "cmpsf"
  [(set (cc0)
	(compare (match_operand:SF 0 "register_operand" "d")
		 (match_operand:SF 1 "nonmemory_cmpsf_operand" "dF")))]
  ""
  "* return output_cmp (operands[0], operands[1], 's');")

;; decrement-and-set-cc0 insns.
;;
;; The most important case where we can use the carry bit from an
;; arithmetic insn to eliminate a redundant compare is the decrement in
;; constructs like while (n--) and while (--n >= 0).  
;;
;; We do it with combine patterns instead of NOTICE_UPDATE_CC because
;; the decrement needs to be kept at the end of the block during scheduling.
;; 
;; These patterns must have memory alternatives because reload refuses
;; to do output reloads for an insn that sets cc0 (since it does not
;; want to clobber cc0 with its moves).  Convex moves do not clobber
;; cc0, but there is no evident way to get reload to know that.

(define_insn ""
  [(set (cc0)
	(match_operand:SI 0 "register_operand" "+r,*m"))
   (set (match_dup 0)
	(plus:SI (match_dup 0)
		 (const_int -1)))]
  "next_insn_tests_no_inequality (insn)"
  "*
{
  if (which_alternative == 0)
    {
      output_cmp (operands[0], constm1_rtx, 'W');
      return \"add.w #-1,%0\";
    }
  else
    {
      output_cmp (gen_rtx_REG (SImode, 7), constm1_rtx, 'W');
      return \"psh.w s7\;ld.w %0,s7\;add.w #-1,s7\;st.w s7,%0\;pop.w s7\";
    }
}")
     
(define_insn ""
  [(set (cc0)
	(plus:SI (match_operand:SI 0 "register_operand" "+r,*m")
		 (const_int -1)))
   (set (match_dup 0)
	(plus:SI (match_dup 0)
		 (const_int -1)))]
  "find_reg_note (next_cc0_user (insn), REG_NONNEG, 0)"
  "*
{
  if (which_alternative == 0)
    {
      output_cmp (operands[0], const0_rtx, 'W');
      return \"add.w #-1,%0\";
    }
  else
    {
      output_cmp (gen_rtx_REG (SImode, 7), const0_rtx, 'W');
      return \"psh.w s7\;ld.w %0,s7\;add.w #-1,s7\;st.w s7,%0\;pop.w s7\";
    }
}")

(define_insn ""
  [(set (cc0)
	(match_operand:HI 0 "register_operand" "+r,*m"))
   (set (match_dup 0)
	(plus:HI (match_dup 0)
		 (const_int -1)))]
  "next_insn_tests_no_inequality (insn)"
  "*
{
  if (which_alternative == 0)
    {
      output_cmp (operands[0], constm1_rtx, 'H');
      return \"add.h #-1,%0\";
    }
  else
    {
      output_cmp (gen_rtx_REG (HImode, 7), constm1_rtx, 'H');
      return \"psh.w s7\;ld.h %0,s7\;add.h #-1,s7\;st.h s7,%0\;pop.w s7\";
    }
}")
     
(define_insn ""
  [(set (cc0)
	(plus:HI (match_operand:HI 0 "register_operand" "+r,*m")
		 (const_int -1)))
   (set (match_dup 0)
	(plus:HI (match_dup 0)
		 (const_int -1)))]
  "find_reg_note (next_cc0_user (insn), REG_NONNEG, 0)"
  "*
{
  if (which_alternative == 0)
    {
      output_cmp (operands[0], const0_rtx, 'H');
      return \"add.h #-1,%0\";
    }
  else
    {
      output_cmp (gen_rtx_REG (HImode, 7), const0_rtx, 'H');
      return \"psh.w s7\;ld.h %0,s7\;add.h #-1,s7\;st.h s7,%0\;pop.w s7\";
    }
}")

;;- Jumps

(define_insn "jump"
  [(set (pc)
	(label_ref (match_operand 0 "" "")))]
  ""
  "jbr %l0")

(define_insn "beq"
  [(set (pc)
	(if_then_else (eq (cc0)
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "* return output_condjump (operands[0], \"eq\", 't'); ")

(define_insn "bne"
  [(set (pc)
	(if_then_else (ne (cc0)
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "* return output_condjump (operands[0], \"eq\", 'f'); ")

(define_insn "bgt"
  [(set (pc)
	(if_then_else (gt (cc0)
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "* return output_condjump (operands[0], \"le\", 'f'); ")

(define_insn "bgtu"
  [(set (pc)
	(if_then_else (gtu (cc0)
			   (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "* return output_condjump (operands[0], \"leu\", 'f'); ")

(define_insn "blt"
  [(set (pc)
	(if_then_else (lt (cc0)
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "* return output_condjump (operands[0], \"lt\", 't'); ")

(define_insn "bltu"
  [(set (pc)
	(if_then_else (ltu (cc0)
			   (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "* return output_condjump (operands[0], \"ltu\", 't'); ")

(define_insn "bge"
  [(set (pc)
	(if_then_else (ge (cc0)
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "* return output_condjump (operands[0], \"lt\", 'f'); ")

(define_insn "bgeu"
  [(set (pc)
	(if_then_else (geu (cc0)
			   (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "* return output_condjump (operands[0], \"ltu\", 'f'); ")

(define_insn "ble"
  [(set (pc)
	(if_then_else (le (cc0)
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "* return output_condjump (operands[0], \"le\", 't'); ")

(define_insn "bleu"
  [(set (pc)
	(if_then_else (leu (cc0)
			   (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "* return output_condjump (operands[0], \"leu\", 't'); ")

(define_insn ""
  [(set (pc)
	(if_then_else (eq (cc0)
			  (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))]
  ""
  "* return output_condjump (operands[0], \"eq\", 'f'); ")

(define_insn ""
  [(set (pc)
	(if_then_else (ne (cc0)
			  (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))]
  ""
  "* return output_condjump (operands[0], \"eq\", 't'); ")

(define_insn ""
  [(set (pc)
	(if_then_else (gt (cc0)
			  (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))]
  ""
  "* return output_condjump (operands[0], \"le\", 't'); ")

(define_insn ""
  [(set (pc)
	(if_then_else (gtu (cc0)
			   (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))]
  ""
  "* return output_condjump (operands[0], \"leu\", 't'); ")

(define_insn ""
  [(set (pc)
	(if_then_else (lt (cc0)
			  (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))]
  ""
  "* return output_condjump (operands[0], \"lt\", 'f'); ")

(define_insn ""
  [(set (pc)
	(if_then_else (ltu (cc0)
			   (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))]
  ""
  "* return output_condjump (operands[0], \"ltu\", 'f'); ")

(define_insn ""
  [(set (pc)
	(if_then_else (ge (cc0)
			  (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))]
  ""
  "* return output_condjump (operands[0], \"lt\", 't'); ")

(define_insn ""
  [(set (pc)
	(if_then_else (geu (cc0)
			   (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))]
  ""
  "* return output_condjump (operands[0], \"ltu\", 't'); ")

(define_insn ""
  [(set (pc)
	(if_then_else (le (cc0)
			  (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))]
  ""
  "* return output_condjump (operands[0], \"le\", 'f'); ")

(define_insn ""
  [(set (pc)
	(if_then_else (leu (cc0)
			   (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))]
  ""
  "* return output_condjump (operands[0], \"leu\", 'f'); ")

;;- Calls

(define_expand "call_pop"
  [(parallel [(call (match_operand:QI 0 "memory_operand" "m")
		    (match_operand:SI 1 "const_int_operand" "i"))
	      (match_operand:SI 2 "const_int_operand" "i")
	      (match_operand:SI 3 "const_int_operand" "i")
	      (reg:SI 8)])]
  ""
  "")

(define_insn ""
  [(call (match_operand:QI 0 "memory_operand" "m")
	 (match_operand:SI 1 "const_int_operand" "i"))
   (match_operand:SI 2 "const_int_operand" "i")
   (match_operand:SI 3 "const_int_operand" "i")
   (match_operand:SI 4 "" "")]
  ""
  "* return output_call (insn, &operands[0]);")

(define_expand "call_value_pop"
  [(parallel [(set (match_operand 0 "" "=g")
		   (call (match_operand:QI 1 "memory_operand" "m")
			 (match_operand:SI 2 "const_int_operand" "i")))
	      (match_operand:SI 3 "const_int_operand" "i")
	      (match_operand:SI 4 "const_int_operand" "i")
	      (reg:SI 8)])]
  ""
  "")

(define_insn ""
  [(set (match_operand 0 "" "=g")
	(call (match_operand:QI 1 "memory_operand" "m")
	      (match_operand:SI 2 "const_int_operand" "i")))
   (match_operand:SI 3 "const_int_operand" "i")
   (match_operand:SI 4 "const_int_operand" "i")
   (match_operand:SI 5 "" "")]
  ""
  "* return output_call (insn, &operands[1]); ")

;; Call subroutine returning any type.

(define_expand "untyped_call"
  [(parallel [(call (match_operand 0 "" "")
                  (const_int 0))
            (match_operand 1 "" "")
            (match_operand 2 "" "")])]
  ""
  "
{
  int i;

  emit_call_insn (gen_call_pop (operands[0], const0_rtx,
				const0_rtx, const0_rtx));

  for (i = 0; i < XVECLEN (operands[2], 0); i++)
    {
      rtx set = XVECEXP (operands[2], 0, i);
      emit_move_insn (SET_DEST (set), SET_SRC (set));
    }

  /* The optimizer does not know that the call sets the function value
     registers we stored in the result block.  We avoid problems by
     claiming that all hard registers are used and clobbered at this
     point.  */
  emit_insn (gen_blockage ());

  DONE;
}")

;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
;; all of memory.  This blocks insns from being moved across this point.

(define_insn "blockage"
  [(unspec_volatile [(const_int 0)] 0)]
  ""
  "")

(define_expand "return"
  [(return)]
  ""
  " replace_arg_pushes (); ")

(define_insn ""
  [(return)]
  ""
  "rtn")

(define_expand "prologue"
  [(const_int 0)]
  ""
  "
{
  emit_ap_optimizations ();
  DONE; 
}")

(define_insn "tablejump"
  [(set (pc) (match_operand:SI 0 "address_operand" "p"))
   (use (label_ref (match_operand 1 "" "")))]
  ""
  "jmp %a0")

(define_insn "indirect_jump"
  [(set (pc) (match_operand:SI 0 "address_operand" "p"))]
  ""
  "jmp %a0")
