diff gcc/config/c6x/c6x.md @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children 84e7813d76e9
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gcc/config/c6x/c6x.md	Fri Oct 27 22:46:09 2017 +0900
@@ -0,0 +1,3134 @@
+;; Machine description for TI C6X.
+;; Copyright (C) 2010-2017 Free Software Foundation, Inc.
+;; Contributed by Andrew Jenner <andrew@codesourcery.com>
+;; Contributed by Bernd Schmidt <bernds@codesourcery.com>
+;; Contributed by CodeSourcery.
+;;
+;; This file is part of GCC.
+;;
+;; GCC 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 3, or (at your option)
+;; any later version.
+;;
+;; GCC 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 GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+
+;; Register names
+
+(define_constants
+  [(REG_A0 0)
+   (REG_A1 1)
+   (REG_A2 2)
+   (REG_A3 3)
+   (REG_A4 4)
+   (REG_A5 5)
+   (REG_A6 6)
+   (REG_A7 7)
+   (REG_A8 8)
+   (REG_A9 9)
+   (REG_A10 10)
+   (REG_A11 11)
+   (REG_A12 12)
+   (REG_A13 13)
+   (REG_A14 14)
+   (REG_A15 15)
+   (REG_A16 16)
+   (REG_A17 17)
+   (REG_A18 18)
+   (REG_A19 19)
+   (REG_A20 20)
+   (REG_A21 21)
+   (REG_A22 22)
+   (REG_A23 23)
+   (REG_A24 24)
+   (REG_A25 25)
+   (REG_A26 26)
+   (REG_A27 27)
+   (REG_A28 28)
+   (REG_A29 29)
+   (REG_A30 30)
+   (REG_A31 31)
+   (REG_B0 32)
+   (REG_B1 33)
+   (REG_B2 34)
+   (REG_B3 35)
+   (REG_B4 36)
+   (REG_B5 37)
+   (REG_B6 38)
+   (REG_B7 39)
+   (REG_B8 40)
+   (REG_B9 41)
+   (REG_B10 42)
+   (REG_B11 43)
+   (REG_B12 44)
+   (REG_B13 45)
+   (REG_B14 46)
+   (REG_SP 47)
+   (REG_B15 47)
+   (REG_B16 48)
+   (REG_B17 49)
+   (REG_B18 50)
+   (REG_B19 51)
+   (REG_B20 52)
+   (REG_B21 53)
+   (REG_B22 54)
+   (REG_B23 55)
+   (REG_B24 56)
+   (REG_B25 57)
+   (REG_B26 58)
+   (REG_B27 59)
+   (REG_B28 60)
+   (REG_B29 61)
+   (REG_B30 62)
+   (REG_B31 63)
+   (REG_FRAME 64)
+   (REG_ARGP 65)
+   (REG_ILC 66)])
+
+(define_c_enum "unspec" [
+   UNSPEC_NOP
+   UNSPEC_RCP
+   UNSPEC_MISALIGNED_ACCESS
+   UNSPEC_ADDKPC
+   UNSPEC_SETUP_DSBT
+   UNSPEC_LOAD_GOT
+   UNSPEC_LOAD_SDATA
+   UNSPEC_BITREV
+   UNSPEC_GOTOFF
+   UNSPEC_MVILC
+   UNSPEC_REAL_JUMP
+   UNSPEC_REAL_LOAD
+   UNSPEC_REAL_MULT
+   UNSPEC_JUMP_SHADOW
+   UNSPEC_LOAD_SHADOW
+   UNSPEC_MULT_SHADOW
+   UNSPEC_EPILOGUE_BARRIER
+   UNSPEC_ATOMIC
+   UNSPEC_CLR
+   UNSPEC_EXT
+   UNSPEC_EXTU
+   UNSPEC_SUBC
+   UNSPEC_AVG
+])
+
+(define_c_enum "unspecv" [
+   UNSPECV_BLOCKAGE
+   UNSPECV_SPLOOP
+   UNSPECV_SPKERNEL
+   UNSPECV_EH_RETURN
+   UNSPECV_CAS
+])
+
+;; -------------------------------------------------------------------------
+;; Instruction attributes
+;; -------------------------------------------------------------------------
+
+(define_attr "cpu"
+  "c62x,c64x,c64xp,c67x,c67xp,c674x"
+  (const (symbol_ref "(enum attr_cpu)c6x_arch")))
+
+;; Define a type for each insn which is used in the scheduling description.
+;; These correspond to the types defined in chapter 4 of the C674x manual.
+(define_attr "type"
+  "unknown,single,mpy2,store,storen,mpy4,load,loadn,branch,call,callp,dp2,fp4,
+   intdp,cmpdp,adddp,mpy,mpyi,mpyid,mpydp,mpyspdp,mpysp2dp,spkernel,sploop,
+   mvilc,blockage,shadow,load_shadow,mult_shadow,atomic"
+  (const_string "single"))
+
+;; The register file used by an instruction's destination register.
+;; The function destreg_file computes this; instructions can override the
+;; attribute if they aren't a single_set.
+(define_attr "dest_regfile"
+  "unknown,any,a,b"
+  (cond [(eq_attr "type" "single,load,mpy2,mpy4,dp2,fp4,intdp,cmpdp,adddp,mpy,mpyi,mpyid,mpydp,mpyspdp,mpysp2dp")
+	 (cond [(match_operand 0 "a_register" "") (const_string "a")
+		(match_operand 0 "b_register" "") (const_string "b")]
+	       (const_string "unknown"))
+	 (eq_attr "type" "store")
+		(cond [(match_operand 1 "a_register" "") (const_string "a")
+		       (match_operand 1 "b_register" "") (const_string "b")]
+	       (const_string "unknown"))]
+	(const_string "unknown")))
+
+(define_attr "addr_regfile"
+  "unknown,a,b"
+  (const_string "unknown"))
+
+(define_attr "cross"
+  "n,y"
+  (const_string "n"))
+
+;; This describes the relationship between operands and register files.
+;; For example, "sxs" means that operands 0 and 2 determine the side of
+;; the machine, and operand 1 can optionally use the cross path.  "dt" and
+;; "td" are used to describe loads and stores.
+;; Used for register renaming in loops for improving modulo scheduling.
+(define_attr "op_pattern"
+  "unknown,dt,td,sx,sxs,ssx"
+  (cond [(eq_attr "type" "load") (const_string "td")
+	 (eq_attr "type" "store") (const_string "dt")]
+	(const_string "unknown")))
+
+(define_attr "has_shadow"
+  "n,y"
+  (const_string "n"))
+
+;; The number of cycles the instruction takes to finish.  Any cycles above
+;; the first are delay slots.
+(define_attr "cycles" ""
+  (cond [(eq_attr "type" "branch,call") (const_int 6)
+	 (eq_attr "type" "load,loadn") (const_int 5)
+	 (eq_attr "type" "dp2") (const_int 2)
+	 (eq_attr "type" "mpy2") (const_int 2)
+	 (eq_attr "type" "mpy4") (const_int 4)
+	 (eq_attr "type" "fp4") (const_int 4)
+	 (eq_attr "type" "mvilc") (const_int 4)
+	 (eq_attr "type" "cmpdp") (const_int 2)
+	 (eq_attr "type" "intdp") (const_int 5)
+	 (eq_attr "type" "adddp") (const_int 7)
+	 (eq_attr "type" "mpydp") (const_int 10)
+	 (eq_attr "type" "mpyi") (const_int 9)
+	 (eq_attr "type" "mpyid") (const_int 10)
+	 (eq_attr "type" "mpyspdp") (const_int 7)
+	 (eq_attr "type" "mpysp2dp") (const_int 5)]
+	(const_int 1)))
+
+;; The number of cycles during which the instruction reserves functional
+;; units.
+(define_attr "reserve_cycles" ""
+  (cond [(eq_attr "type" "cmpdp") (const_int 2)
+	 (eq_attr "type" "adddp") (const_int 2)
+	 (eq_attr "type" "mpydp") (const_int 4)
+	 (eq_attr "type" "mpyi") (const_int 4)
+	 (eq_attr "type" "mpyid") (const_int 4)
+	 (eq_attr "type" "mpyspdp") (const_int 2)]
+	(const_int 1)))
+
+(define_attr "predicable" "no,yes"
+  (const_string "yes"))
+
+(define_attr "enabled" "no,yes"
+  (const_string "yes"))
+
+;; Specify which units can be used by a given instruction.  Normally,
+;; dest_regfile is used to select between the two halves of the machine.
+;; D_ADDR is for load/store instructions; they use the D unit and use
+;; addr_regfile to choose between D1 and D2.
+
+(define_attr "units62"
+  "unknown,d,d_addr,l,m,s,dl,ds,dls,ls"
+  (const_string "unknown"))
+
+(define_attr "units64"
+  "unknown,d,d_addr,l,m,s,dl,ds,dls,ls"
+  (const_string "unknown"))
+
+(define_attr "units64p"
+  "unknown,d,d_addr,l,m,s,dl,ds,dls,ls"
+  (attr "units64"))
+
+(define_attr "units67"
+  "unknown,d,d_addr,l,m,s,dl,ds,dls,ls"
+  (attr "units62"))
+
+(define_attr "units67p"
+  "unknown,d,d_addr,l,m,s,dl,ds,dls,ls"
+  (attr "units67"))
+
+(define_attr "units674"
+  "unknown,d,d_addr,l,m,s,dl,ds,dls,ls"
+  (attr "units64"))
+
+(define_attr "units"
+  "unknown,d,d_addr,l,m,s,dl,ds,dls,ls"
+  (cond [(eq_attr "cpu" "c62x")
+	   (attr "units62")
+	 (eq_attr "cpu" "c67x")
+	   (attr "units67")
+	 (eq_attr "cpu" "c67xp")
+	   (attr "units67p")
+	 (eq_attr "cpu" "c64x")
+	   (attr "units64")
+	 (eq_attr "cpu" "c64xp")
+	   (attr "units64p")
+	 (eq_attr "cpu" "c674x")
+	   (attr "units674")
+	]
+	(const_string "unknown")))
+
+(define_automaton "c6x_1,c6x_2,c6x_m1,c6x_m2,c6x_t1,c6x_t2,c6x_branch")
+(automata_option "no-comb-vect")
+(automata_option "ndfa")
+(automata_option "collapse-ndfa")
+
+(define_query_cpu_unit "d1,l1,s1" "c6x_1")
+(define_cpu_unit "x1" "c6x_1")
+(define_cpu_unit "l1w,s1w" "c6x_1")
+(define_query_cpu_unit "m1" "c6x_m1")
+(define_cpu_unit "m1w" "c6x_m1")
+(define_cpu_unit "t1" "c6x_t1")
+(define_query_cpu_unit "d2,l2,s2" "c6x_2")
+(define_cpu_unit "x2" "c6x_2")
+(define_cpu_unit "l2w,s2w" "c6x_2")
+(define_query_cpu_unit "m2" "c6x_m2")
+(define_cpu_unit "m2w" "c6x_m2")
+(define_cpu_unit "t2" "c6x_t2")
+;; A special set of units used to identify specific reservations, rather than
+;; just units.
+(define_query_cpu_unit "fps1,fpl1,adddps1,adddpl1" "c6x_1")
+(define_query_cpu_unit "fps2,fpl2,adddps2,adddpl2" "c6x_2")
+
+;; There can be up to two branches in one cycle (on the .s1 and .s2
+;; units), but some instructions must not be scheduled in parallel
+;; with a branch.  We model this by reserving either br0 or br1 for a
+;; normal branch, and both of them for an insn such as callp.
+;; Another constraint is that two branches may only execute in parallel
+;; if one uses an offset, and the other a register.  We can distinguish
+;; these by the dest_regfile attribute; it is "any" iff the branch uses
+;; an offset.  br0 is reserved for these, while br1 is reserved for
+;; branches using a register.
+(define_cpu_unit "br0,br1" "c6x_branch")
+
+(include "c6x-sched.md")
+
+;; Some reservations which aren't generated from c6x-sched.md.in
+
+(define_insn_reservation "branch_s1any" 6
+  (and (eq_attr "type" "branch")
+       (and (eq_attr "cross" "n")
+	    (and (eq_attr "units" "s")
+		 (eq_attr "dest_regfile" "any"))))
+  "s1+s1w+br0")
+
+;; For calls, we also reserve the units needed in the following cycles
+;; to load the return address.  There are two options; using addkpc or
+;; mvkh/mvkl.  The code in c6x_reorg knows whether to use one of these
+;; or whether to use callp.  The actual insns are emitted only after
+;; the final scheduling pass is complete.
+;; We always reserve S2 for PC-relative call insns, since that allows
+;; us to turn them into callp insns later on.
+(define_insn_reservation "call_addkpc_s1any" 6
+  (and (eq_attr "type" "call")
+       (and (ne (symbol_ref "TARGET_INSNS_64") (const_int 0))
+	    (and (eq_attr "cross" "n")
+		 (and (eq_attr "units" "s")
+		      (eq_attr "dest_regfile" "any")))))
+  "s2+s2w+br0,s2+s2w+br0+br1")
+
+(define_insn_reservation "call_mvk_s1any" 6
+  (and (eq_attr "type" "call")
+       (and (eq (symbol_ref "TARGET_INSNS_64") (const_int 0))
+	    (and (eq_attr "cross" "n")
+		 (and (eq_attr "units" "s")
+		      (eq_attr "dest_regfile" "any")))))
+  "s2+s2w+br0,s2+s2w,s2+s2w")
+
+(define_reservation "all" "s1+s2+d1+d2+l1+l2+m1+m2")
+
+(define_insn_reservation "callp_s1" 1
+  (and (eq_attr "type" "callp") (eq_attr "dest_regfile" "a"))
+  "s1+s1w,all*5")
+
+(define_insn_reservation "callp_s2" 1
+  (and (eq_attr "type" "callp") (eq_attr "dest_regfile" "b"))
+  "s2+s2w,all*5")
+
+;; Constraints
+
+(include "constraints.md")
+
+;; Predicates
+
+(include "predicates.md")
+
+;; General predication pattern.
+
+(define_cond_exec
+  [(match_operator 0 "eqne_operator"
+    [(match_operand 1 "predicate_register" "AB")
+     (const_int 0)])]
+  ""
+  "")
+
+;; -------------------------------------------------------------------------
+;; NOP instruction
+;; -------------------------------------------------------------------------
+
+(define_insn "nop"
+  [(const_int 0)]
+  ""
+  "nop")
+
+(define_insn "nop_count"
+  [(unspec [(match_operand 0 "const_int_operand" "n")] UNSPEC_NOP)]
+  ""
+  "%|%.\\tnop\\t%0")
+
+;; -------------------------------------------------------------------------
+;; Move instructions
+;; -------------------------------------------------------------------------
+
+(define_mode_iterator QIHIM [QI HI])
+(define_mode_iterator SIDIM [SI DI])
+(define_mode_iterator SIDIVM [SI DI V2HI V4QI])
+(define_mode_iterator VEC4M [V2HI V4QI])
+(define_mode_iterator VEC8M [V2SI V4HI V8QI])
+(define_mode_iterator SISFVM [SI SF V2HI V4QI])
+(define_mode_iterator DIDFM [DI DF])
+(define_mode_iterator DIDFVM [DI DF V2SI V4HI V8QI])
+(define_mode_iterator SFDFM [SF DF])
+(define_mode_iterator M32 [QI HI SI SF V2HI V4QI])
+
+;; The C6X LO_SUM and HIGH are backwards - HIGH sets the low bits, and
+;; LO_SUM adds in the high bits.  Fortunately these are opaque operations
+;; so this does not matter.
+(define_insn "movsi_lo_sum"
+  [(set (match_operand:SI 0 "register_operand" "=ab")
+	(lo_sum:SI (match_operand:SI 1 "register_operand" "0")
+		   (match_operand:SI 2 "const_int_or_symbolic_operand" "i")))]
+  "reload_completed"
+  "%|%.\\tmvkh\\t%$\\t%2, %0"
+  [(set_attr "units" "s")])
+
+(define_insn "movsi_high"
+  [(set (match_operand:SI 0 "register_operand" "=ab")
+	(high:SI (match_operand:SI 1 "const_int_or_symbolic_operand" "i")))]
+  "reload_completed"
+  "%|%.\\tmvkl\\t%$\\t%1, %0"
+  [(set_attr "units" "s")])
+
+(define_insn "movsi_gotoff_lo_sum"
+  [(set (match_operand:SI 0 "register_operand" "=ab")
+	(lo_sum:SI (match_operand:SI 1 "register_operand" "0")
+		   (unspec:SI [(match_operand:SI 2 "symbolic_operand" "S2")]
+			      UNSPEC_GOTOFF)))]
+  "flag_pic == 2"
+  "%|%.\\tmvkh\\t%$\\t$dpr_got%2, %0"
+  [(set_attr "units" "s")])
+
+(define_insn "movsi_gotoff_high"
+  [(set (match_operand:SI 0 "register_operand" "=ab")
+	(high:SI (unspec:SI [(match_operand:SI 1 "symbolic_operand" "S2")]
+			    UNSPEC_GOTOFF)))]
+  "flag_pic == 2"
+  "%|%.\\tmvkl\\t%$\\t$dpr_got%1, %0"
+  [(set_attr "units" "s")])
+
+;; Normally we'd represent this as a normal load insn, but we can't currently
+;; represent the addressing mode.
+(define_insn "load_got_gotoff"
+  [(set (match_operand:SI 0 "register_operand" "=a,b")
+	(unspec:SI [(match_operand:SI 1 "register_operand" "Z,Z")
+		    (match_operand:SI 2 "register_operand" "b,b")]
+		   UNSPEC_GOTOFF))]
+  "flag_pic == 2"
+  "%|%.\\tldw\\t%$\\t*+%1[%2], %0"
+  [(set_attr "type" "load")
+   (set_attr "units" "d_addr")
+   (set_attr "op_pattern" "unknown")
+   (set_attr "dest_regfile" "a,b")
+   (set_attr "addr_regfile" "b")])
+
+(define_insn "*movstricthi_high"
+  [(set (match_operand:SI 0 "register_operand" "+ab")
+	(ior:SI (and:SI (match_dup 0) (const_int 65535))
+		(ashift:SI (match_operand:SI 1 "const_int_operand" "IuB")
+			   (const_int 16))))]
+  "reload_completed"
+  "%|%.\\tmvklh\\t%$\\t%1, %0"
+  [(set_attr "units" "s")])
+
+;; Break up SImode loads of immediate operands.
+
+(define_split
+  [(set (match_operand:SI 0 "register_operand" "")
+	(match_operand:SI 1 "const_int_operand" ""))]
+  "reload_completed
+   && !satisfies_constraint_IsB (operands[1])"
+  [(set (match_dup 0) (match_dup 2))
+   (set (match_dup 0) (ior:SI (and:SI (match_dup 0) (const_int 65535))
+			      (ashift:SI (match_dup 3) (const_int 16))))]
+{
+  HOST_WIDE_INT val = INTVAL (operands[1]);
+  operands[2] = GEN_INT (trunc_int_for_mode (val, HImode));
+  operands[3] = GEN_INT ((val >> 16) & 65535);
+})
+
+(define_split
+  [(set (match_operand:VEC4M 0 "register_operand" "")
+	(match_operand:VEC4M 1 "const_vector_operand" ""))]
+  "reload_completed"
+  [(set (match_dup 2) (match_dup 3))]
+{
+  unsigned HOST_WIDE_INT mask, val;
+  machine_mode inner_mode = GET_MODE_INNER (<MODE>mode);
+  int i;
+
+  val = 0;
+  mask = GET_MODE_MASK (inner_mode);
+  if (TARGET_BIG_ENDIAN)
+    {
+      for (i = 0; i < GET_MODE_NUNITS (<MODE>mode); i++)
+	{
+	  val <<= GET_MODE_BITSIZE (inner_mode);
+	  val |= INTVAL (CONST_VECTOR_ELT (operands[1], i)) & mask;
+	}
+    }
+  else
+    {
+      i = GET_MODE_NUNITS (<MODE>mode);
+      while (i-- > 0)
+	{
+	  val <<= GET_MODE_BITSIZE (inner_mode);
+	  val |= INTVAL (CONST_VECTOR_ELT (operands[1], i)) & mask;
+	}
+    }
+  operands[2] = gen_rtx_REG (SImode, REGNO (operands[0]));
+  operands[3] = GEN_INT (trunc_int_for_mode (val, SImode));
+})
+
+(define_split
+  [(set (match_operand:VEC8M 0 "register_operand" "")
+	(match_operand:VEC8M 1 "const_vector_operand" ""))]
+  "reload_completed"
+  [(set (match_dup 2) (match_dup 3))
+   (set (match_dup 4) (match_dup 5))]
+{
+  unsigned HOST_WIDE_INT mask;
+  unsigned HOST_WIDE_INT val[2];
+  rtx lo_half, hi_half;
+  machine_mode inner_mode = GET_MODE_INNER (<MODE>mode);
+  int i, j;
+
+  split_di (operands, 1, &lo_half, &hi_half);
+
+  val[0] = val[1] = 0;
+  mask = GET_MODE_MASK (inner_mode);
+  if (TARGET_BIG_ENDIAN)
+    {
+      for (i = 0, j = 1; i < GET_MODE_NUNITS (<MODE>mode); i++)
+	{
+	  if (i * 2 == GET_MODE_NUNITS (<MODE>mode))
+	    j--;
+	  val[j] <<= GET_MODE_BITSIZE (inner_mode);
+	  val[j] |= INTVAL (CONST_VECTOR_ELT (operands[1], i)) & mask;
+	}
+    }
+  else
+    {
+      i = GET_MODE_NUNITS (<MODE>mode);
+      j = 1;
+      while (i-- > 0)
+        {
+	  val[j] <<= GET_MODE_BITSIZE (inner_mode);
+	  val[j] |= INTVAL (CONST_VECTOR_ELT (operands[1], i)) & mask;
+	  if (i * 2 == GET_MODE_NUNITS (<MODE>mode))
+	    j--;
+	}
+    }
+  operands[2] = lo_half;
+  operands[3] = GEN_INT (trunc_int_for_mode (val[0], SImode));
+  operands[4] = hi_half;
+  operands[5] = GEN_INT (trunc_int_for_mode (val[1], SImode));
+})
+
+(define_split
+  [(set (match_operand:SF 0 "register_operand" "")
+	(match_operand:SF 1 "immediate_operand" ""))]
+  "reload_completed"
+  [(set (match_dup 2) (match_dup 3))
+   (set (match_dup 2) (ior:SI (and:SI (match_dup 2) (const_int 65535))
+			      (ashift:SI (match_dup 4) (const_int 16))))]
+{
+  long values;
+
+  gcc_assert (GET_CODE (operands[1]) == CONST_DOUBLE);
+
+  REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (operands[1]), values);
+
+  operands[2] = gen_rtx_REG (SImode, true_regnum (operands[0]));
+  operands[3] = GEN_INT (trunc_int_for_mode (values, HImode));
+  if (values >= -32768 && values < 32768)
+    {
+      emit_move_insn (operands[2], operands[3]);
+      DONE;
+    }
+  operands[4] = GEN_INT ((values >> 16) & 65535);
+})
+
+(define_split
+  [(set (match_operand:SI 0 "register_operand" "")
+	(match_operand:SI 1 "symbolic_operand" ""))]
+  "reload_completed
+   && (!TARGET_INSNS_64PLUS
+       || !sdata_symbolic_operand (operands[1], SImode))"
+  [(set (match_dup 0) (high:SI (match_dup 1)))
+   (set (match_dup 0) (lo_sum:SI (match_dup 0) (match_dup 1)))]
+  "")
+
+;; Normally, we represent the load of an sdata address as a normal
+;; move of a SYMBOL_REF.  In DSBT mode, B14 is not constant, so we
+;; should show the dependency.
+(define_insn "load_sdata_pic"
+  [(set (match_operand:SI 0 "register_operand" "=a,b")
+	(plus:SI (match_operand:SI 1 "pic_register_operand" "Z,Z")
+		 (unspec:SI [(match_operand:SI 2 "sdata_symbolic_operand" "S0,S0")]
+			    UNSPEC_LOAD_SDATA)))]
+  "flag_pic"
+  "@
+   %|%.\\tadda%D2\\t%$\\t%1, %2, %0
+   %|%.\\tadda%D2\\t%$\\t%1, %2, %0"
+  [(set_attr "units" "d")
+   (set_attr "cross" "y,n")
+   (set_attr "op_pattern" "unknown")
+   (set_attr "predicable" "no")])
+
+;; Move instruction patterns
+
+(define_mode_attr LDST_SUFFIX [(QI "b") (HI "h")
+			       (SI "w") (SF "w") (V2HI "w") (V4QI "w")
+			       (DI "dw") (V2SI "dw") (V4HI "dw") (V8QI "dw")])
+
+(define_insn "mov<mode>_insn"
+ [(set (match_operand:QIHIM 0 "nonimmediate_operand"
+        "=a,b, a, b, ab, ab,a,?a, b,?b, Q, R, R, Q")
+       (match_operand:QIHIM 1 "general_operand"
+         "a,b,?b,?a,Is5,IsB,Q, R, R, Q, a,?a, b,?b"))]
+  "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) == REG"
+ "@
+  %|%.\\tmv\\t%$\\t%1, %0
+  %|%.\\tmv\\t%$\\t%1, %0
+  %|%.\\tmv\\t%$\\t%1, %0
+  %|%.\\tmv\\t%$\\t%1, %0
+  %|%.\\tmvk\\t%$\\t%1, %0
+  %|%.\\tmvk\\t%$\\t%1, %0
+  %|%.\\tld<LDST_SUFFIX>\\t%$\\t%1, %0
+  %|%.\\tld<LDST_SUFFIX>\\t%$\\t%1, %0
+  %|%.\\tld<LDST_SUFFIX>\\t%$\\t%1, %0
+  %|%.\\tld<LDST_SUFFIX>\\t%$\\t%1, %0
+  %|%.\\tst<LDST_SUFFIX>\\t%$\\t%1, %0
+  %|%.\\tst<LDST_SUFFIX>\\t%$\\t%1, %0
+  %|%.\\tst<LDST_SUFFIX>\\t%$\\t%1, %0
+  %|%.\\tst<LDST_SUFFIX>\\t%$\\t%1, %0"
+  [(set_attr "type" "*,*,*,*,*,*,load,load,load,load,store,store,store,store")
+   (set_attr "units62" "dls,dls,ls,ls,s,s,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr")
+   (set_attr "units64" "dls,dls,ls,ls,dl,s,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr")
+   (set_attr "op_pattern" "sx,sx,sx,sx,*,*,*,*,*,*,*,*,*,*")
+   (set_attr "addr_regfile" "*,*,*,*,*,*,a,b,b,a,a,b,b,a")
+   (set_attr "dest_regfile" "*,*,*,*,*,*,a,a,b,b,a,a,b,b")
+   (set_attr "cross" "n,n,y,y,n,n,n,y,n,y,n,y,n,y")])
+
+(define_insn "mov<mode>_insn"
+ [(set (match_operand:SISFVM 0 "nonimmediate_operand"
+        "=a,b, a, b, ab, ab,a,b,ab,a,?a, b,?b, Q, R, R, Q")
+       (match_operand:SISFVM 1 "general_operand"
+         "a,b,?b,?a,Is5,IsB,S0,S0,Si,Q, R, R, Q, a,?a, b,?b"))]
+  "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) == REG
+    || (GET_CODE (operands[1]) == SUBREG && REG_P (SUBREG_REG (operands[1]))))"
+ "@
+  %|%.\\tmv\\t%$\\t%1, %0
+  %|%.\\tmv\\t%$\\t%1, %0
+  %|%.\\tmv\\t%$\\t%1, %0
+  %|%.\\tmv\\t%$\\t%1, %0
+  %|%.\\tmvk\\t%$\\t%1, %0
+  %|%.\\tmvk\\t%$\\t%1, %0
+  %|%.\\tadda%D1\\t%$\\tB14, %1, %0
+  %|%.\\tadda%D1\\t%$\\tB14, %1, %0
+  #
+  %|%.\\tldw\\t%$\\t%1, %0
+  %|%.\\tldw\\t%$\\t%1, %0
+  %|%.\\tldw\\t%$\\t%1, %0
+  %|%.\\tldw\\t%$\\t%1, %0
+  %|%.\\tstw\\t%$\\t%1, %0
+  %|%.\\tstw\\t%$\\t%1, %0
+  %|%.\\tstw\\t%$\\t%1, %0
+  %|%.\\tstw\\t%$\\t%1, %0"
+  [(set_attr "type" "*,*,*,*,*,*,*,*,*,load,load,load,load,store,store,store,store")
+   (set_attr "units62" "dls,dls,ls,ls,s,s,d,d,*,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr")
+   (set_attr "units64" "dls,dls,ls,ls,dl,s,d,d,*,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr")
+   (set_attr "op_pattern" "sx,sx,sx,sx,*,*,*,*,*,*,*,*,*,*,*,*,*")
+   (set_attr "addr_regfile" "*,*,*,*,*,*,*,*,*,a,b,b,a,a,b,b,a")
+   (set_attr "dest_regfile" "*,*,*,*,*,*,*,*,*,a,a,b,b,a,a,b,b")
+   (set_attr "cross" "n,n,y,y,n,n,y,n,*,n,y,n,y,n,y,n,y")
+   (set_attr "predicable" "yes,yes,yes,yes,yes,yes,no,no,yes,yes,yes,yes,yes,yes,yes,yes,yes")])
+
+(define_insn "*mov<mode>_insn"
+  [(set (match_operand:DIDFVM 0 "nonimmediate_operand"
+         "=a,b, a, b,ab,a,?a, b,?b, Q, R, R, Q")
+        (match_operand:DIDFVM 1 "general_operand"
+          "a,b,?b,?a,iF,Q, R, R, Q, a,?a, b,?b"))]
+  "(!MEM_P (operands[0]) || REG_P (operands[1])
+    || (GET_CODE (operands[1]) == SUBREG && REG_P (SUBREG_REG (operands[1]))))"
+{
+  if (MEM_P (operands[1]) && TARGET_LDDW)
+    return "%|%.\\tlddw\\t%$\\t%1, %0";
+  if (MEM_P (operands[0]) && TARGET_STDW)
+    return "%|%.\\tstdw\\t%$\\t%1, %0";
+  if (TARGET_INSNS_64PLUS && REG_P (operands[0]) && REG_P (operands[1])
+      && A_REGNO_P (REGNO (operands[0])) == A_REGNO_P (REGNO (operands[1])))
+    return "%|%.\\tdmv\\t%$\\t%P1, %p1, %0";
+  return "#";
+}
+  [(set_attr "units" "s,s,*,*,*,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr")
+   (set_attr "addr_regfile" "*,*,*,*,*,a,b,b,a,a,b,b,a")
+   (set_attr "dest_regfile" "*,*,*,*,*,a,a,b,b,a,a,b,b")
+   (set_attr "type" "*,*,*,*,*,load,load,load,load,store,store,store,store")
+   (set_attr "cross" "n,n,y,y,*,n,y,n,y,n,y,n,y")])
+
+(define_split
+  [(set (match_operand:DIDFVM 0 "nonimmediate_operand" "")
+  	(match_operand:DIDFVM 1 "general_operand" ""))]
+  "reload_completed
+   && !((MEM_P (operands[0]) && TARGET_STDW)
+ 	|| (MEM_P (operands[1]) && TARGET_LDDW))
+   && !const_vector_operand (operands[1], <MODE>mode)
+   && !(TARGET_INSNS_64PLUS && REG_P (operands[0]) && REG_P (operands[1])
+	&& A_REGNO_P (REGNO (operands[0])) == A_REGNO_P (REGNO (operands[1])))"
+  [(set (match_dup 2) (match_dup 3))
+   (set (match_dup 4) (match_dup 5))]
+{
+  rtx lo_half[2], hi_half[2];
+  split_di (operands, 2, lo_half, hi_half);
+
+  /* We can't have overlap for a register-register move, but if
+     memory is involved, we have to make sure we don't clobber the
+     address.  */
+  if (reg_overlap_mentioned_p (lo_half[0], hi_half[1]))
+    {
+      operands[2] = hi_half[0];
+      operands[3] = hi_half[1];
+      operands[4] = lo_half[0];
+      operands[5] = lo_half[1];
+    }
+  else
+    {
+      operands[2] = lo_half[0];
+      operands[3] = lo_half[1];
+      operands[4] = hi_half[0];
+      operands[5] = hi_half[1];
+    }
+})
+
+(define_insn "real_load<mode>"
+  [(unspec [(match_operand 0 "const_int_operand" "JA,JA,JB,JB")
+	    (match_operand:M32 1 "memory_operand" "Q,R,R,Q")]
+	   UNSPEC_REAL_LOAD)]
+  ""
+  "%|%.\\tld<LDST_SUFFIX>\\t%$\\t%1, %k0"
+  [(set_attr "type" "load")
+   (set_attr "units" "d_addr")
+   (set_attr "addr_regfile" "a,b,b,a")
+   (set_attr "dest_regfile" "a,a,b,b")
+   (set_attr "cross" "n,y,n,y")])
+
+(define_insn "real_load<mode>"
+  [(unspec [(match_operand 0 "const_int_operand" "JA,JA,JB,JB")
+	    (match_operand:DIDFVM 1 "memory_operand" "Q,R,R,Q")]
+	   UNSPEC_REAL_LOAD)]
+  "TARGET_LDDW"
+  "%|%.\\tlddw\\t%$\\t%1, %K0"
+  [(set_attr "type" "load")
+   (set_attr "units" "d_addr")
+   (set_attr "addr_regfile" "a,b,b,a")
+   (set_attr "dest_regfile" "a,a,b,b")
+   (set_attr "cross" "n,y,n,y")])
+
+(define_insn "load_shadow"
+  [(set (match_operand 0 "register_operand" "=ab")
+ 	(unspec [(pc)] UNSPEC_LOAD_SHADOW))]
+  ""
+  ";; load to %0 occurs"
+  [(set_attr "type" "load_shadow")])
+
+(define_insn "mult_shadow"
+  [(set (match_operand 0 "register_operand" "=ab")
+ 	(unspec [(pc)] UNSPEC_MULT_SHADOW))]
+  ""
+  ";; multiplication occurs and stores to %0"
+  [(set_attr "type" "mult_shadow")])
+
+
+(define_mode_iterator MOV [QI HI SI SF DI DF V2HI V4QI V2SI V4HI V8QI])
+
+(define_expand "mov<mode>"
+  [(set (match_operand:MOV 0 "nonimmediate_operand" "")
+	(match_operand:MOV 1 "general_operand" ""))]
+  ""
+{
+  if (expand_move (operands, <MODE>mode))
+    DONE;
+})
+
+(define_expand "movmisalign<mode>"
+  [(set (match_operand:SIDIVM 0 "nonimmediate_operand"	      "")
+	(unspec:SIDIVM [(match_operand:SIDIVM 1 "nonimmediate_operand" "")]
+		       UNSPEC_MISALIGNED_ACCESS))]
+  "TARGET_INSNS_64"
+{
+  if (MEM_P (operands[0]))
+    {
+      emit_insn (gen_movmisalign<mode>_store (operands[0], operands[1]));
+      DONE;
+    }
+})
+
+(define_insn_and_split "movmisalign<mode>_store"
+  [(set (match_operand:SIDIVM 0 "memory_operand" "=W,Q,T,Q,T")
+	(unspec:SIDIVM [(match_operand:SIDIVM 1 "register_operand" "r,a,b,b,a")]
+		       UNSPEC_MISALIGNED_ACCESS))
+   (clobber (match_scratch:SI 2 "=r,X,X,X,X"))]
+  "TARGET_INSNS_64"
+  "@
+   #
+   %|%.\\tstn<LDST_SUFFIX>\\t%$\\t%1, %0
+   %|%.\\tstn<LDST_SUFFIX>\\t%$\\t%1, %0
+   %|%.\\tstn<LDST_SUFFIX>\\t%$\\t%1, %0
+   %|%.\\tstn<LDST_SUFFIX>\\t%$\\t%1, %0"
+  "&& reload_completed && satisfies_constraint_W (operands[0])"
+  [(parallel
+    [(set (match_dup 3) (unspec:SIDIVM [(match_dup 1)] UNSPEC_MISALIGNED_ACCESS))
+     (clobber (match_dup 4))])]
+{
+  rtx addr = XEXP (operands[0], 0);
+  rtx tmpreg = operands[2];
+
+  if (GET_CODE (addr) == PLUS && XEXP (addr, 0) == stack_pointer_rtx
+      && GET_CODE (XEXP (addr, 1)) == CONST_INT)
+    {
+      unsigned HOST_WIDE_INT val = INTVAL (XEXP (addr, 1));
+      val &= GET_MODE_SIZE (<MODE>mode) - 1;
+      if (val == 0)
+	{
+	  emit_move_insn (operands[0], operands[1]);
+	  DONE;
+	}
+    }
+  operands[3] = change_address (operands[0], <MODE>mode, tmpreg);
+  emit_move_insn (tmpreg, addr);
+  operands[4] = gen_rtx_SCRATCH (SImode);
+}
+  [(set_attr "type" "storen")
+   (set_attr "units" "d_addr")
+   (set_attr "addr_regfile" "*,a,b,a,b")
+   (set_attr "dest_regfile" "*,a,b,b,a")
+   (set_attr "cross" "*,n,n,y,y")])
+
+(define_insn_and_split "movmisalign<mode>_load"
+  [(set (match_operand:SIDIVM 0 "register_operand" "=ab,a,b,b,a")
+	(unspec:SIDIVM [(match_operand:SIDIVM 1 "memory_operand" "W,Q,T,Q,T")]
+		       UNSPEC_MISALIGNED_ACCESS))]
+  "TARGET_INSNS_64"
+  "@
+   #
+   %|%.\\tldn<LDST_SUFFIX>\\t%$\\t%1, %0
+   %|%.\\tldn<LDST_SUFFIX>\\t%$\\t%1, %0
+   %|%.\\tldn<LDST_SUFFIX>\\t%$\\t%1, %0
+   %|%.\\tldn<LDST_SUFFIX>\\t%$\\t%1, %0"
+  "&& reload_completed && satisfies_constraint_W (operands[1])"
+  [(set (match_dup 0) (unspec:SIDIVM [(match_dup 2)] UNSPEC_MISALIGNED_ACCESS))]
+{
+  rtx addr = XEXP (operands[1], 0);
+  rtx tmpreg = (GET_MODE (operands[0]) == SImode ? operands[0]
+		: operand_subword_force (operands[0], 0, DImode));
+
+  if (GET_CODE (addr) == PLUS && XEXP (addr, 0) == stack_pointer_rtx
+      && GET_CODE (XEXP (addr, 1)) == CONST_INT)
+    {
+      unsigned HOST_WIDE_INT val = INTVAL (XEXP (addr, 1));
+      val &= GET_MODE_SIZE (<MODE>mode) - 1;
+      if (val == 0)
+	{
+	  emit_move_insn (operands[0], operands[1]);
+	  DONE;
+	}
+    }
+  operands[2] = change_address (operands[1], <MODE>mode, tmpreg);
+  emit_move_insn (tmpreg, addr);
+}
+  [(set_attr "type" "loadn")
+   (set_attr "units" "d_addr")
+   (set_attr "addr_regfile" "*,a,b,a,b")
+   (set_attr "dest_regfile" "*,a,b,b,a")
+   (set_attr "cross" "*,n,n,y,y")])
+
+;;
+
+;; -------------------------------------------------------------------------
+;; Extensions/extractions
+;; -------------------------------------------------------------------------
+
+(define_code_iterator any_extract [zero_extract sign_extract])
+(define_code_iterator any_ext [zero_extend sign_extend])
+
+(define_code_attr ext_name [(zero_extend "zero_extend") (sign_extend "sign_extend")])
+
+(define_code_attr u [(zero_extend "u") (sign_extend "")])
+
+(define_code_attr z [(zero_extract "z") (sign_extract "")])
+(define_code_attr zu [(zero_extract "u") (sign_extract "")])
+
+(define_mode_attr ext_shift [(QI "24") (HI "16")])
+
+(define_insn "<ext_name><mode>si2"
+ [(set (match_operand:SI 0 "register_operand" "=a,b,a,?a, b,?b")
+       (any_ext:SI (match_operand:QIHIM 1 "nonimmediate_operand" "a,b,Q, R, R, Q")))]
+  ""
+ "@
+  %|%.\\text<u>\\t%$\\t%1, <ext_shift>, <ext_shift>, %0
+  %|%.\\text<u>\\t%$\\t%1, <ext_shift>, <ext_shift>, %0
+  %|%.\\tld<LDST_SUFFIX><u>\\t%$\\t%1, %0
+  %|%.\\tld<LDST_SUFFIX><u>\\t%$\\t%1, %0
+  %|%.\\tld<LDST_SUFFIX><u>\\t%$\\t%1, %0
+  %|%.\\tld<LDST_SUFFIX><u>\\t%$\\t%1, %0"
+  [(set_attr "type" "*,*,load,load,load,load")
+   (set_attr "units" "s,s,d_addr,d_addr,d_addr,d_addr")
+   (set_attr "addr_regfile" "*,*,a,b,b,a")
+   (set_attr "dest_regfile" "*,*,a,a,b,b")
+   (set_attr "cross" "n,n,n,y,n,y")])
+
+(define_insn "*ext<z>v_const"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=a,b")
+	(any_extract:SI (match_operand:SI 1 "register_operand" "a,b")
+			(match_operand:SI 2 "const_int_operand" "n,n")
+			(match_operand:SI 3 "const_int_operand" "n,n")))]
+  "INTVAL (operands[3]) >= 0
+   && INTVAL (operands[2]) + INTVAL (operands[3]) <= 32"
+{
+  int pos = INTVAL (operands[3]);
+  int len = INTVAL (operands[2]);
+  rtx xop[4];
+  xop[0] = operands[0];
+  xop[1] = operands[1];
+  xop[2] = GEN_INT (32 - pos - len);
+  xop[3] = GEN_INT (32 - len);
+
+  output_asm_insn ("%|%.\\text<zu>\\t%$\\t%1, %2, %3, %0", xop);
+  return "";
+}
+  [(set_attr "units" "s")
+   (set_attr "cross" "n")])
+
+(define_expand "ext<z>v"
+  [(set (match_operand:SI 0 "register_operand" "")
+	(any_extract:SI (match_operand:SI 1 "register_operand" "")
+			(match_operand:SI 2 "const_int_operand" "")
+			(match_operand:SI 3 "const_int_operand" "")))]
+  ""
+{
+   if (INTVAL (operands[2]) < 0
+       || INTVAL (operands[2]) + INTVAL (operands[3]) > 32)
+     FAIL;
+})
+
+(define_insn "real_<ext_name><mode>"
+  [(unspec [(match_operand 0 "const_int_operand" "JA,JA,JB,JB")
+	    (any_ext:SI (match_operand:QIHIM 1 "memory_operand" "Q,R,R,Q"))]
+	   UNSPEC_REAL_LOAD)]
+  ""
+  "%|%.\\tld<LDST_SUFFIX><u>\\t%$\\t%1, %k0"
+  [(set_attr "type" "load")
+   (set_attr "units" "d_addr")
+   (set_attr "addr_regfile" "a,b,b,a")
+   (set_attr "dest_regfile" "a,a,b,b")
+   (set_attr "cross" "n,y,n,y")])
+
+(define_insn "clrr"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+	(unspec:SI [(match_operand:SI 1 "register_operand" "0,0,0,0")
+		    (match_operand:SI 2 "register_operand" "a,b,?b,?a")
+		    (match_operand:SI 3 "reg_or_const_int_operand" "ai,bi,a,b")]
+		   UNSPEC_CLR))]
+  ""
+{
+  if (CONST_INT_P (operands[2]))
+    {
+      rtx xops[4];
+      int v1 = INTVAL (operands[2]);
+      int v2 = (v1 >> 5) & 0x1f;
+      v1 &= 0x1f;
+      xops[0] = operands[0];
+      xops[1] = operands[1];
+      xops[2] = GEN_INT (v1);
+      xops[3] = GEN_INT (v2);
+      output_asm_insn ("%|%.\\tclr\\t%$\\t%1, %3, %2, %0", xops);
+      return "";
+    }
+  return "%|%.\\tclr\\t%$\\t%2, %3, %0";
+}
+  [(set_attr "units" "s")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "extr"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+	(unspec:SI [(match_operand:SI 1 "register_operand" "a,b,?b,?a")
+		    (match_operand:SI 2 "reg_or_const_int_operand" "ai,bi,a,b")]
+		   UNSPEC_EXT))]
+  ""
+{
+  if (CONST_INT_P (operands[2]))
+    {
+      rtx xops[4];
+      int v1 = INTVAL (operands[2]);
+      int v2 = (v1 >> 5) & 0x1f;
+      v1 &= 0x1f;
+      xops[0] = operands[0];
+      xops[1] = operands[1];
+      xops[2] = GEN_INT (v1);
+      xops[3] = GEN_INT (v2);
+      output_asm_insn ("%|%.\\text\\t%$\\t%1, %3, %2, %0", xops);
+      return "";
+    }
+  return "%|%.\\text\\t%$\\t%1, %2, %0";
+}
+  [(set_attr "units" "s")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "extru"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+	(unspec:SI [(match_operand:SI 1 "register_operand" "a,b,?b,?a")
+		    (match_operand:SI 2 "reg_or_const_int_operand" "ai,bi,a,b")]
+		   UNSPEC_EXTU))]
+  ""
+{
+  if (CONST_INT_P (operands[2]))
+    {
+      rtx xops[4];
+      int v1 = INTVAL (operands[2]);
+      int v2 = (v1 >> 5) & 0x1f;
+      v1 &= 0x1f;
+      xops[0] = operands[0];
+      xops[1] = operands[1];
+      xops[2] = GEN_INT (v1);
+      xops[3] = GEN_INT (v2);
+      output_asm_insn ("%|%.\\textu\\t%$\\t%1, %3, %2, %0", xops);
+      return "";
+    }
+  return "%|%.\\textu\\t%$\\t%1, %2, %0";
+}
+  [(set_attr "units" "s")
+   (set_attr "cross" "n,y,n,y")])
+
+;; -------------------------------------------------------------------------
+;; Compare instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "scmpsi_insn"
+  [(set (match_operand:SI 0 "register_operand" "=ab,a,b,a,b")
+	(match_operator:SI 1 "eqltgt_operator"
+	   [(match_operand:SI 2 "register_operand" "ab,a,b,?b,?a")
+	    (match_operand:SI 3 "reg_or_scst5_operand" "Is5,aIs5,bIs5,aIs5,bIs5")]))]
+  ""
+  "%|%.\\tcmp%C1\\t%$\\t%3, %2, %0"
+  [(set_attr "units" "l")
+   (set (attr "cross")
+	(symbol_ref "CROSS_OPERANDS (operands[0], operands[2])"))])
+
+(define_insn "*ucmpsi_insn_64"
+  [(set (match_operand:SI 0 "register_operand" "=ab,a,b,a,b")
+	(match_operator:SI 1 "ltugtu_operator"
+	   [(match_operand:SI 2 "register_operand" "ab,a,b,?b,?a")
+	    (match_operand:SI 3 "reg_or_ucst5_operand" "Iu5,aIu5,bIu5,aIu5,bIu5")]))]
+  "TARGET_INSNS_64"
+  "%|%.\\tcmp%C1\\t%$\\t%3, %2, %0"
+  [(set_attr "units" "l")
+   (set (attr "cross")
+	(symbol_ref "CROSS_OPERANDS (operands[0], operands[2])"))])
+
+(define_insn "*ucmpsi_insn"
+  [(set (match_operand:SI 0 "register_operand" "=ab,a,b,a,b")
+	(match_operator:SI 1 "ltugtu_operator"
+	   [(match_operand:SI 2 "register_operand" "ab,a,b,?b,?a")
+	    (match_operand:SI 3 "reg_or_ucst4_operand" "Iu4,aIu4,bIu4,aIu4,bIu4")]))]
+  "!TARGET_INSNS_64"
+  "%|%.\\tcmp%C1\\t%$\\t%3, %2, %0"
+  [(set_attr "units" "l")
+   (set (attr "cross")
+	(symbol_ref "CROSS_OPERANDS (operands[0], operands[2])"))])
+
+(define_code_iterator andior_eqne [eq ne])
+(define_code_attr andior_name [(eq "and") (ne "ior")])
+(define_code_attr andior_condmod [(eq "") (ne "!")])
+
+(define_insn "*scmpsi_<andior_name>_insn"
+  [(set (match_operand:SI 0 "register_operand" "=A,B,A,B")
+	(if_then_else:SI
+	 (andior_eqne:SI (match_operand:SI 4 "register_operand" "0,0,0,0")
+			 (const_int 0))
+	 (match_dup 4)
+	 (match_operator:SI 1 "eqltgt_operator"
+	  [(match_operand:SI 2 "register_operand" "a,b,?b,?a")
+	   (match_operand:SI 3 "reg_or_scst5_operand" "aIs5,bIs5,aIs5,bIs5")])))]
+  ""
+  "%|[<andior_condmod>%4]\\tcmp%C1\\t%$\\t%3, %2, %0"
+  [(set_attr "units" "l")
+   (set_attr "cross" "n,n,y,y")
+   (set_attr "predicable" "no")])
+
+(define_insn "*ucmpsi_<andior_name>_insn_64"
+  [(set (match_operand:SI 0 "register_operand" "=A,B,A,B")
+	(if_then_else:SI
+	 (andior_eqne:SI (match_operand:SI 4 "register_operand" "0,0,0,0")
+			 (const_int 0))
+	 (match_dup 4)
+	 (match_operator:SI 1 "ltugtu_operator"
+	  [(match_operand:SI 2 "register_operand" "a,b,?b,?a")
+	   (match_operand:SI 3 "reg_or_ucst5_operand" "aIu5,bIu5,aIu5,bIu5")])))]
+  "TARGET_INSNS_64"
+  "%|[<andior_condmod>%4]\\tcmp%C1\\t%$\\t%3, %2, %0"
+  [(set_attr "units" "l")
+   (set_attr "cross" "n,n,y,y")
+   (set_attr "predicable" "no")])
+
+(define_insn "*ucmpsi_<andior_name>_insn"
+  [(set (match_operand:SI 0 "register_operand" "=A,B,A,B")
+	(if_then_else:SI
+	 (andior_eqne:SI (match_operand:SI 4 "register_operand" "0,0,0,0")
+			 (const_int 0))
+	 (match_dup 4)
+	 (match_operator:SI 1 "ltugtu_operator"
+	  [(match_operand:SI 2 "register_operand" "a,b,?b,?a")
+	   (match_operand:SI 3 "reg_or_ucst4_operand" "aIu4,bIu4,aIu4,bIu4")])))]
+  "!TARGET_INSNS_64"
+  "%|[<andior_condmod>%4]\\tcmp%C1\\t%$\\t%3, %2, %0"
+  [(set_attr "units" "l")
+   (set_attr "cross" "n,n,y,y")
+   (set_attr "predicable" "no")])
+
+(define_expand "cmpsi_<andior_name>"
+  [(set (match_operand:SI 0 "register_operand" "")
+	(if_then_else:SI
+	 (andior_eqne:SI (match_operand:SI 4 "register_operand" "0,0,0,0")
+			 (const_int 0))
+	 (match_dup 4)
+	 (match_operator:SI 1 "c6x_comparison_operator"
+	  [(match_operand:SI 2 "register_operand" "")
+	   (match_operand:SI 3 "reg_or_const_int_operand" "")])))]
+  ""
+{
+  if (c6x_force_op_for_comparison_p (GET_CODE (operands[1]), operands[3]))
+    operands[3] = force_reg (SImode, operands[3]);
+})
+
+(define_insn "*cmpsf_insn"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+	(match_operator:SI 1 "eqltgt_operator"
+	   [(match_operand:SF 2 "register_operand" "a,b,a,b")
+	    (match_operand:SF 3 "register_operand" "a,b,?b,?a")]))]
+  "TARGET_FP"
+  "%|%.\\tcmp%c1sp\\t%$\\t%2, %3, %0"
+  [(set_attr "units" "s")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "*cmpdf_insn"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+	(match_operator:SI 1 "eqltgt_operator"
+	   [(match_operand:DF 2 "register_operand" "a,b,a,b")
+	    (match_operand:DF 3 "register_operand" "a,b,?b,?a")]))]
+  "TARGET_FP"
+  "%|%.\\tcmp%c1dp\\t%$\\t%2, %3, %0"
+  [(set_attr "type" "cmpdp")
+   (set_attr "units" "s")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_expand "cmp<mode>_<andior_name>"
+  [(set (match_operand:SI 0 "register_operand" "")
+	(if_then_else:SI
+	 (andior_eqne:SI (match_operand:SI 4 "register_operand" "0,0,0,0")
+			 (const_int 0))
+	 (match_dup 4)
+	 (match_operator:SI 1 "eqltgt_operator"
+	   [(match_operand:SFDFM 2 "register_operand" "")
+	    (match_operand:SFDFM 3 "register_operand" "")])))]
+  "TARGET_FP")
+
+(define_insn "*cmpsf_<andior_name>_insn"
+  [(set (match_operand:SI 0 "register_operand" "=A,B,A,B")
+	(if_then_else:SI
+	 (andior_eqne:SI (match_operand:SI 4 "register_operand" "0,0,0,0")
+			 (const_int 0))
+	 (match_dup 4)
+	 (match_operator:SI 1 "eqltgt_operator"
+	   [(match_operand:SF 2 "register_operand" "a,b,a,b")
+	    (match_operand:SF 3 "register_operand" "a,b,?b,?a")])))]
+  "TARGET_FP"
+  "%|[<andior_condmod>%4]\\tcmp%c1sp\\t%$\\t%2, %3, %0"
+  [(set_attr "units" "s")
+   (set_attr "cross" "n,n,y,y")
+   (set_attr "predicable" "no")])
+
+;; reload_reg_class_lower will ensure that two-word reloads are allocated first,
+;; which could exhaust the predicate registers if we used just "a" and "b"
+;; constraints on operands 2 and 3.
+(define_insn "*cmpdf_<andior_name>_insn"
+  [(set (match_operand:SI 0 "register_operand" "=A,B,A,B")
+	(if_then_else:SI
+	 (andior_eqne:SI (match_operand:SI 4 "register_operand" "0,0,0,0")
+			 (const_int 0))
+	 (match_dup 4)
+	 (match_operator:SI 1 "eqltgt_operator"
+	   [(match_operand:DF 2 "register_operand" "Da,Db,Da,Db")
+	    (match_operand:DF 3 "register_operand" "Da,Db,?Db,?Da")])))]
+  "TARGET_FP"
+  "%|[<andior_condmod>%4]\\tcmp%c1dp\\t%$\\t%2, %3, %0"
+  [(set_attr "type" "cmpdp")
+   (set_attr "units" "s")
+   (set_attr "cross" "n,n,y,y")
+   (set_attr "predicable" "no")])
+
+(define_split
+  [(set (match_operand:SI 0 "register_operand" "")
+	(ior:SI (match_operand 1 "c6x_any_comparison_operand" "")
+		(match_operand 2 "c6x_any_comparison_operand" "")))]
+  "!reg_overlap_mentioned_p (operands[0], operands[2])"
+  [(set (match_dup 0) (match_dup 1))
+   (set (match_dup 0)
+	(if_then_else:SI (ne:SI (match_dup 0) (const_int 0))
+			 (match_dup 0)
+			 (match_dup 2)))])
+
+(define_split
+  [(set (match_operand:SI 0 "register_operand" "")
+	(and:SI (match_operand 1 "c6x_any_comparison_operand" "")
+		(match_operand 2 "c6x_any_comparison_operand" "")))]
+  "!reg_overlap_mentioned_p (operands[0], operands[2])"
+  [(set (match_dup 0) (match_dup 1))
+   (set (match_dup 0)
+	(if_then_else:SI (eq:SI (match_dup 0) (const_int 0))
+			 (match_dup 0)
+			 (match_dup 2)))])
+
+
+;; -------------------------------------------------------------------------
+;; setcc instructions
+;; -------------------------------------------------------------------------
+
+(define_expand "cstoresi4"
+  [(set (match_operand:SI 0 "register_operand" "")
+	(match_operator:SI 1 "comparison_operator"
+	 [(match_operand:SI 2 "register_operand" "")
+	  (match_operand:SI 3 "reg_or_ucst4_operand" "")]))]
+  ""
+{
+  if (!c6x_comparison_operator (operands[1], SImode))
+    {
+      rtx tmpreg = gen_reg_rtx (SImode);
+      rtx t = gen_rtx_fmt_ee (reverse_condition (GET_CODE (operands[1])),
+			      SImode, operands[2], operands[3]);
+      emit_insn (gen_rtx_SET (tmpreg, t));
+      emit_insn (gen_scmpsi_insn (operands[0],
+				  gen_rtx_fmt_ee (EQ, SImode, tmpreg, const0_rtx),
+				  tmpreg, const0_rtx));
+      DONE;
+    }
+})
+
+;; -------------------------------------------------------------------------
+;; Jump instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "indirect_jump"
+  [(set (pc) (match_operand:SI 0 "register_operand" "a,b"))]
+  ""
+  "%|%.\\tb\\t%$\\t%0"
+  [(set_attr "type" "branch")
+   (set_attr "units" "s")
+   (set_attr "cross" "y,n")
+   (set_attr "dest_regfile" "b")])
+
+(define_insn "jump"
+  [(set (pc)
+	(label_ref (match_operand 0 "" "")))]
+  ""
+  "%|%.\\tb\\t%$\\t%l0"
+  [(set_attr "type" "branch")
+   (set_attr "units" "s")
+   (set_attr "dest_regfile" "any")])
+
+(define_expand "tablejump"
+  [(parallel [(set (pc) (match_operand:SI 0 "register_operand" ""))
+              (use (label_ref (match_operand 1 "" "")))])]
+  "!flag_pic || !TARGET_INSNS_64"
+{
+})
+
+(define_insn "*tablejump_internal"
+  [(set (pc) (match_operand:SI 0 "register_operand" "b"))
+   (use (label_ref (match_operand 1 "" "")))]
+  "!flag_pic || !TARGET_INSNS_64"
+  "%|\\tb\\t%$\\t%0"
+  [(set_attr "type" "branch")
+   (set_attr "predicable" "no")
+   (set_attr "units" "s")
+   (set_attr "dest_regfile" "b")])
+
+;; Implement switch statements when generating PIC code.  Switches are
+;; implemented by `tablejump' when not using -fpic.
+
+;; Emit code here to do the range checking and make the index zero based.
+;; operand 0 is the index
+;; operand 1 is the lower bound
+;; operand 2 is the range of indices (highest - lowest + 1)
+;; operand 3 is the label that precedes the table itself
+;; operand 4 is the fall through label
+
+(define_expand "casesi"
+  [(use (match_operand:SI 0 "register_operand" ""))
+   (use (match_operand:SI 1 "const_int_operand" ""))
+   (use (match_operand:SI 2 "const_int_operand" ""))
+   (use (match_operand 3 "" ""))
+   (use (match_operand 4 "" ""))]
+  "flag_pic && TARGET_INSNS_64"
+{
+  rtx indx;
+  rtx low = operands[1];
+  rtx range = operands[2];
+  rtx table = operands[3];
+  rtx fail = operands[4];
+
+  gcc_assert (GET_CODE (operands[1]) == CONST_INT);
+  gcc_assert (GET_CODE (operands[2]) == CONST_INT);
+
+  if (!reg_or_ucst4_operand (range, SImode))
+    range = force_reg (SImode, range);
+
+  /* If low bound is 0, we don't have to subtract it.  */
+  if (INTVAL (operands[1]) == 0)
+    indx = operands[0];
+  else
+    {
+      rtx offset = GEN_INT (-INTVAL (low));
+      indx = gen_reg_rtx (SImode);
+      if (!addsi_operand (offset, SImode))
+        offset = force_reg (SImode, offset);
+      emit_insn (gen_addsi3 (indx, operands[0], offset));
+    }
+  emit_cmp_and_jump_insns (indx, range, GTU, NULL_RTX, SImode, 1, fail);
+
+  emit_jump_insn (gen_casesi_internal (indx, table));
+  DONE;
+})
+
+;; This is the only instance in this file where a pattern emits more than
+;; one instruction.  The concern here is that the addkpc insn could otherwise
+;; be scheduled too far away from the label.  A tablejump always ends an
+;; extended basic block, so it shouldn't happen that the scheduler places
+;; something in the delay slots.
+(define_insn "casesi_internal"
+  [(set (pc)
+	(mem:SI (plus:SI (mult:SI (match_operand:SI 0 "register_operand" "b")
+				  (const_int 4))
+			 (label_ref (match_operand 1 "" "")))))
+   (clobber (match_scratch:SI 2 "=&b"))
+   (clobber (match_scratch:SI 3 "=b"))]
+  "flag_pic && TARGET_INSNS_64"
+  "addkpc\t.s2\t%l1,%2, 0\n\t\tldw\t.d2t2\t*+%2[%0], %3\n\t\tnop\t\t4\n\t\tadd\t.l2\t%2, %3, %3\n\t\tb\t.s2\t%3"
+  [(set_attr "type" "branch")
+   (set_attr "predicable" "no")
+   (set_attr "dest_regfile" "b")])
+
+(define_expand "cbranch<mode>4"
+  [(set (pc)
+	(if_then_else (match_operator 0 "comparison_operator"
+		       [(match_operand:SIDIM 1 "register_operand" "")
+			(match_operand:SIDIM 2 "reg_or_const_int_operand" "")])
+		      (label_ref (match_operand 3 "" ""))
+		      (pc)))]
+  ""
+{
+  rtx t = c6x_expand_compare (operands[0], VOIDmode);
+  operands[0] = t;
+  operands[1] = XEXP (t, 0);
+  operands[2] = XEXP (t, 1);
+})
+
+(define_expand "cbranch<mode>4"
+  [(set (pc)
+	(if_then_else (match_operator 0 "c6x_fp_comparison_operator"
+		       [(match_operand:SFDFM 1 "register_operand" "")
+			(match_operand:SFDFM 2 "register_operand" "")])
+		      (label_ref (match_operand 3 "" ""))
+		      (pc)))]
+  ""
+{
+  rtx t = c6x_expand_compare (operands[0], VOIDmode);
+  operands[0] = t;
+  operands[1] = XEXP (t, 0);
+  operands[2] = XEXP (t, 1);
+})
+
+(define_insn "br_true"
+  [(set (pc)
+	(if_then_else (match_operator 0 "predicate_operator"
+			[(match_operand:SI 1 "register_operand" "AB")
+			 (const_int 0)])
+		      (label_ref (match_operand 2 "" ""))
+		      (pc)))]
+  ""
+  "%|[%J0]\\tb\\t%$\\t%l2"
+  [(set_attr "type" "branch")
+   (set_attr "predicable" "no")
+   (set_attr "units" "s")
+   (set_attr "dest_regfile" "any")])
+
+(define_insn "br_false"
+  [(set (pc)
+	(if_then_else (match_operator 0 "predicate_operator"
+			[(match_operand:SI 1 "register_operand" "AB")
+			 (const_int 0)])
+		      (pc)
+		      (label_ref (match_operand 2 "" ""))))]
+  ""
+  "%|[%j0]\\tb\\t%$\\t%l2"
+  [(set_attr "type" "branch")
+   (set_attr "predicable" "no")
+   (set_attr "units" "s")
+   (set_attr "dest_regfile" "any")])
+
+(define_expand "return"
+  [(parallel
+    [(return)
+     (use (reg:SI REG_B3))])]
+  "reload_completed && get_frame_size () == 0 && c6x_nsaved_regs () == 0")
+
+;; We can't expand this before we know where the link register is stored.
+(define_insn_and_split "eh_return"
+  [(unspec_volatile [(match_operand:SI 0 "register_operand" "ab")]
+		    UNSPECV_EH_RETURN)
+   (clobber (match_scratch:SI 1 "=&ab"))]
+  ""
+  "#"
+  "&& reload_completed"
+  [(const_int 0)]
+  "
+  {
+    c6x_set_return_address (operands[0], operands[1]);
+    DONE;
+  }"
+)
+
+;; -------------------------------------------------------------------------
+;; Doloop
+;; -------------------------------------------------------------------------
+
+; operand 0 is the loop count pseudo register
+; operand 1 is the label to jump to at the top of the loop
+(define_expand "doloop_end"
+  [(parallel [(set (pc) (if_then_else
+			  (ne (match_operand:SI 0 "" "")
+			      (const_int 1))
+			  (label_ref (match_operand 1 "" ""))
+			  (pc)))
+	      (set (match_dup 0)
+		   (plus:SI (match_dup 0)
+			    (const_int -1)))
+	      (clobber (match_dup 2))])] ; match_scratch
+  "TARGET_INSNS_64PLUS && optimize"
+{
+  /* The loop optimizer doesn't check the predicates... */
+  if (GET_MODE (operands[0]) != SImode)
+    FAIL;
+  operands[2] = gen_rtx_SCRATCH (SImode);
+})
+
+(define_insn "mvilc"
+  [(set (reg:SI REG_ILC)
+	(unspec [(match_operand:SI 0 "register_operand" "a,b")] UNSPEC_MVILC))]
+  "TARGET_INSNS_64PLUS"
+  "%|%.\\tmvc\\t%$\\t%0, ILC"
+  [(set_attr "predicable" "no")
+   (set_attr "cross" "y,n")
+   (set_attr "units" "s")
+   (set_attr "dest_regfile" "b")
+   (set_attr "type" "mvilc")])
+  
+(define_insn "sploop"
+  [(unspec_volatile [(match_operand:SI 0 "const_int_operand" "i")
+		     (reg:SI REG_ILC)]
+		    UNSPECV_SPLOOP)]
+  "TARGET_INSNS_64PLUS"
+  "%|%.\\tsploop\t%0"
+  [(set_attr "predicable" "no")
+   (set_attr "type" "sploop")])
+  
+(define_insn "spkernel"
+  [(set (pc)
+	(if_then_else
+	 (ne (unspec_volatile:SI
+	      [(match_operand:SI 0 "const_int_operand" "i")
+	       (match_operand:SI 1 "const_int_operand" "i")]
+	      UNSPECV_SPKERNEL)
+	     (const_int 1))
+	 (label_ref (match_operand 2 "" ""))
+	 (pc)))]
+  "TARGET_INSNS_64PLUS"
+  "%|%.\\tspkernel\t%0, %1"
+  [(set_attr "predicable" "no")
+   (set_attr "type" "spkernel")])
+  
+(define_insn "loop_end"
+  [(set (pc)
+	(if_then_else (ne (match_operand:SI 3 "nonimmediate_operand" "0,0,0,*r")
+			  (const_int 1))
+		      (label_ref (match_operand 1 "" ""))
+		      (pc)))
+   (set (match_operand:SI 0 "nonimmediate_operand" "=AB,*r,m,m")
+	(plus:SI (match_dup 3)
+		 (const_int -1)))
+   (clobber (match_scratch:SI 2 "=X,&AB,&AB,&AB"))]
+  "TARGET_INSNS_64PLUS && optimize"
+  "#"
+  [(set_attr "type" "spkernel")])
+
+(define_split
+  [(set (pc)
+	(if_then_else (ne (match_operand:SI 3 "nonimmediate_operand" "")
+			  (const_int 1))
+		      (label_ref (match_operand 1 "" ""))
+		      (pc)))
+   (set (match_operand:SI 0 "memory_operand" "")
+	(plus:SI (match_dup 3)
+		 (const_int -1)))
+   (clobber (match_scratch 2))]
+  ""
+  [(set (match_dup 2) (plus:SI (match_dup 3) (const_int -1)))
+   (set (match_dup 0) (match_dup 2))
+   (set (pc)
+	(if_then_else (ne (match_dup 2) (const_int 0))
+		      (label_ref (match_dup 1))
+		      (pc)))]
+{
+  if (!REG_P (operands[3]))
+    {
+      emit_move_insn (operands[2], operands[3]);
+      operands[3] = operands[2];
+    }
+})
+
+;; -------------------------------------------------------------------------
+;; Delayed-branch real jumps and shadows
+;; -------------------------------------------------------------------------
+
+(define_insn "real_jump"
+  [(unspec [(match_operand 0 "c6x_jump_operand" "a,b,S3") (const_int 0)]
+	   UNSPEC_REAL_JUMP)]
+  ""
+{
+  if (GET_CODE (operands[0]) == LABEL_REF)
+    return "%|%.\\tb\\t%$\\t%l0";
+  return "%|%.\\tb\\t%$\\t%0";
+}
+  [(set_attr "type" "branch")
+   (set_attr "has_shadow" "y")
+   (set_attr "units" "s")
+   (set_attr "cross" "y,n,n")
+   (set_attr "dest_regfile" "b,b,any")])
+
+(define_insn "real_call"
+  [(unspec [(match_operand 0 "c6x_call_operand" "a,b,S1") (const_int 1)]
+	   UNSPEC_REAL_JUMP)
+   (clobber (reg:SI REG_B3))]
+  ""
+  "%|%.\\tcall\\t%$\\t%0"
+  [(set_attr "type" "call")
+   (set_attr "has_shadow" "y")
+   (set_attr "predicable" "no")
+   (set_attr "units" "s")
+   (set_attr "cross" "y,n,n")
+   (set_attr "dest_regfile" "b,b,any")])
+
+(define_insn "real_ret"
+  [(unspec [(match_operand 0 "register_operand" "a,b") (const_int 2)]
+	   UNSPEC_REAL_JUMP)]
+  ""
+  "%|%.\\tret\\t%$\\t%0"
+  [(set_attr "type" "branch")
+   (set_attr "has_shadow" "y")
+   (set_attr "units" "s")
+   (set_attr "cross" "y,n")
+   (set_attr "dest_regfile" "b")])
+
+;; computed_jump_p returns true if it finds a constant; so use one in the
+;; unspec.
+(define_insn "indirect_jump_shadow"
+  [(set (pc) (unspec [(const_int 1)] UNSPEC_JUMP_SHADOW))]
+  ""
+  ";; indirect jump occurs"
+  [(set_attr "type" "shadow")])
+
+;; Operand 0 may be a PARALLEL which isn't handled by output_operand, so
+;; we don't try to print it.
+(define_insn "indirect_call_value_shadow"
+  [(set (match_operand 0 "" "")
+	(call (unspec [(pc)] UNSPEC_JUMP_SHADOW)
+	      (const_int 0)))]
+  ""
+  ";; indirect call occurs, with return value"
+  [(set_attr "type" "shadow")])
+
+(define_insn "indirect_sibcall_shadow"
+  [(call (unspec [(pc)] UNSPEC_JUMP_SHADOW)
+	 (const_int 0))]
+  "SIBLING_CALL_P (insn)"
+  ";; indirect sibcall occurs"
+  [(set_attr "type" "shadow")])
+
+(define_insn "indirect_call_shadow"
+  [(call (unspec [(pc)] UNSPEC_JUMP_SHADOW)
+	 (const_int 0))]
+  ""
+  ";; indirect call occurs"
+  [(set_attr "type" "shadow")])
+
+(define_insn "call_value_shadow"
+  [(set (match_operand 0 "" "")
+	(call (unspec [(match_operand 1 "" "")] UNSPEC_JUMP_SHADOW)
+	      (const_int 0)))]
+  ""
+  ";; call to %1 occurs, with return value"
+  [(set_attr "type" "shadow")])
+
+(define_insn "call_shadow"
+  [(call (unspec [(match_operand 0 "" "")] UNSPEC_JUMP_SHADOW)
+	 (const_int 0))]
+  "!SIBLING_CALL_P (insn)"
+  ";; call to %0 occurs"
+  [(set_attr "type" "shadow")])
+
+(define_insn "sibcall_shadow"
+  [(call (unspec [(match_operand 0 "" "")] UNSPEC_JUMP_SHADOW)
+	 (const_int 0))]
+  "SIBLING_CALL_P (insn)"
+  ";; sibcall to %0 occurs"
+  [(set_attr "type" "shadow")])
+
+(define_insn "jump_shadow"
+  [(set (pc) (unspec [(match_operand 0 "" "")] UNSPEC_JUMP_SHADOW))]
+  ""
+  ";; jump to %0 occurs"
+  [(set_attr "type" "shadow")])
+
+(define_insn "condjump_shadow"
+  [(set (pc)
+	(if_then_else (eq (unspec [(const_int 0)] UNSPEC_JUMP_SHADOW)
+			  (const_int 0))
+		      (match_operand 0 "" "")
+		      (pc)))]
+  ""
+  ";; condjump to %0 occurs"
+  [(set_attr "type" "shadow")])
+
+(define_insn "return_shadow"
+  [(unspec [(const_int 0)] UNSPEC_JUMP_SHADOW)
+   (return)]
+  ""
+  ";; return occurs"
+  [(set_attr "type" "shadow")])
+
+;; -------------------------------------------------------------------------
+;; Add instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "addsi3"
+  [(set (match_operand:SI 0 "register_operand"
+              "=a   ,b   , a, b, a, b,    a,    b, ab,  a,  b,  a,  b,ab")
+    (plus:SI (match_operand:SI 1 "register_operand"
+              "%a   ,b   , a, b, b, a,    b,    a,  0,  a,  b,  z,  z,0")
+  	     (match_operand:SI 2 "addsi_operand"
+               "aIs5,bIs5,?b,?a,?a,?b,?aIs5,?bIs5,I5x,I5x,I5x,Iux,Iux,IsB")))]
+  ""
+{
+  if (CONSTANT_P (operands[2]))
+    {
+      HOST_WIDE_INT val = INTVAL (operands[2]);
+
+      if (c6x_get_unit_specifier (insn) == 'd')
+	{
+	  bool issp = (TARGET_INSNS_64PLUS
+		       && operands[1] == stack_pointer_rtx
+		       && GET_CODE (PATTERN (insn)) != COND_EXEC);
+
+	  if (get_attr_cross (insn) == CROSS_N)
+	    {
+	      if (satisfies_constraint_Iu5 (operands[2]))
+		return "%|%.\\tadd\\t%$\\t%1, %2, %0";
+	      else if (satisfies_constraint_In5 (operands[2]))
+		return "%|%.\\tsub\\t%$\\t%1, %n2, %0";
+	    }
+
+	  if (issp && val > 0 && val < 32768)
+	    {
+	      return "%|%.\\taddab\\t%$\\t%1, %2, %0";
+	    }
+	  if ((val & 1) == 0 && ((val >= -62 && val <= 62)
+				 || (issp && val > 0 && val < 65536)))
+	    {
+	      if (val < 0)
+		return "%|%.\\tsubah\\t%$\\t%1, %r2, %0";
+	      else
+		return "%|%.\\taddah\\t%$\\t%1, %r2, %0";
+	    }
+	  else if ((val & 3) == 0 && ((val >= -124 && val <= 124)
+				       || (issp && val > 0 && val < 131072)))
+	    {
+	      if (val < 0)
+		return "%|%.\\tsubaw\\t%$\\t%1, %R2, %0";
+	      else
+		return "%|%.\\taddaw\\t%$\\t%1, %R2, %0";
+	    }
+	  else if ((val & 7) == 0 && val > 0 && val <= 248)
+	    {
+	      rtx xop[3];
+	      xop[0] = operands[0];
+	      xop[1] = operands[1];
+	      xop[2] = GEN_INT (val >> 3);
+	      output_asm_insn ("%|%.\\taddad\\t%$\\t%1, %2, %0", xop);
+	      return "";
+	    }
+	}
+      else
+        {
+	  if (satisfies_constraint_Is5 (operands[2]))
+	    return "%|%.\\tadd\\t%$\\t%2, %1, %0";
+	}
+      gcc_assert (rtx_equal_p (operands[0], operands[1]));
+      return "%|%.\\taddk\\t%$\\t%2, %0";
+    }
+  if (which_alternative == 4 || which_alternative == 5)
+    return "%|%.\\tadd\\t%$\\t%2, %1, %0";
+  else
+    return "%|%.\\tadd\\t%$\\t%1, %2, %0";
+}
+  [(set_attr "units62" "dls,dls,ls,ls,ls,ls,ls,ls,s,d,d,*,*,s")
+   (set_attr "units67" "dls,dls,ls,ls,ls,ls,ls,ls,ds,d,d,*,*,s")
+   (set_attr "units64" "dls,dls,dls,dls,dls,dls,ls,ls,ds,d,d,d,d,s")
+   (set_attr "cross" "n,n,y,y,y,y,y,y,n,n,n,y,n,n")
+   (set_attr "predicable" "yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,no,no,yes")])
+
+(define_insn "subsi3"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b,a,b")
+	(minus:SI (match_operand:SI 1 "reg_or_scst5_operand" "a,b,aIs5,bIs5,bIs5,aIs5")
+		  (match_operand:SI 2 "register_operand" "a,b,a,b,?a,?b")))]
+  ""
+  "%|%.\\tsub\\t%$\\t%1, %2, %0"
+  [(set_attr "units62" "dls,dls,ls,ls,l,l")
+   (set_attr "units64" "dls,dls,ls,ls,ls,ls")
+   (set_attr "cross" "n,n,n,n,y,y")])
+
+(define_insn "*addshiftsi"
+  [(set (match_operand:SI 0 "register_operand" "=a,b")
+	(plus:SI (mult:SI (match_operand:SI 2 "register_operand" "a,b")
+			  (match_operand:SI 3 "adda_scale_operand" "n,n"))
+		 (match_operand:SI 1 "register_operand" "a,b")))]
+  ""
+  "%|%.\\tadda%d3\\t%$\\t%1, %2, %0"
+  [(set_attr "units" "d")])
+
+(define_insn "*subshiftsi"
+  [(set (match_operand:SI 0 "register_operand" "=a,b")
+	(minus:SI (match_operand:SI 1 "register_operand" "a,b")
+		  (mult:SI (match_operand:SI 2 "register_operand" "a,b")
+			   (match_operand:SI 3 "suba_scale_operand" "n,n"))))]
+  ""
+  "%|%.\\tsuba%d3\\t%$\\t%1, %2, %0"
+  [(set_attr "units" "d")])
+
+(define_insn "addsidi3_widen"
+  [(set (match_operand:DI 0 "register_operand" "=a,b,a,b")
+	(plus:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%a,b,a,b"))
+		 (zero_extend:DI (match_operand:SI 2 "register_operand" "a,b,?b,?a"))))]
+  ""
+  "%|%.\\taddu\\t%$\\t%1, %2, %0"
+  [(set_attr "units" "l")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_expand "adddi3"
+  [(set (match_operand:DI 0 "register_operand" "")
+	(plus:DI (match_operand:DI 1 "register_operand" "")
+		 (match_operand:DI 2 "register_operand" "")))]
+  ""
+{
+  rtx tmp;
+  rtx lo_half[3], hi_half[3];
+  split_di (operands + 1, 2, lo_half + 1, hi_half + 1);
+  if (reg_overlap_mentioned_p (operands[0], hi_half[1])
+      || reg_overlap_mentioned_p (operands[0], hi_half[2]))
+    tmp = gen_reg_rtx (DImode);
+  else
+    tmp = operands[0];
+  split_di (&tmp, 1, lo_half, hi_half);
+  emit_insn (gen_addsidi3_widen (tmp, lo_half[1], lo_half[2]));
+  emit_insn (gen_addsi3 (hi_half[0], copy_rtx (hi_half[0]), hi_half[1]));
+  emit_insn (gen_addsi3 (copy_rtx (hi_half[0]),
+			 copy_rtx (hi_half[0]), hi_half[2]));
+  if (tmp != operands[0])
+    emit_move_insn (operands[0], tmp);
+  DONE;
+})
+
+(define_insn "addsf3"
+  [(set (match_operand:SF 0 "register_operand" "=a,b,a,b")
+	(plus:SF (match_operand:SF 1 "register_operand" "%a,b,a,b")
+		 (match_operand:SF 2 "register_operand" "a,b,?b,?a")))]
+  "TARGET_FP"
+  "%|%.\\taddsp\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "fp4")
+   (set_attr "units67" "l")
+   (set_attr "units67p" "ls")
+   (set_attr "units674" "ls")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "adddf3"
+  [(set (match_operand:DF 0 "register_operand" "=a,b,a,b")
+	(plus:DF (match_operand:DF 1 "register_operand" "%a,b,a,b")
+		 (match_operand:DF 2 "register_operand" "a,b,?b,?a")))]
+  "TARGET_FP"
+  "%|%.\\tadddp\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "adddp")
+   (set_attr "units67" "l")
+   (set_attr "units67p" "ls")
+   (set_attr "units674" "ls")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "subsf3"
+  [(set (match_operand:SF 0 "register_operand" "=a,b, a, b, a, b")
+	(minus:SF (match_operand:SF 1 "register_operand" "a,b, b, a, a, b")
+		  (match_operand:SF 2 "register_operand" "a,b,?a,?b,?b,?a")))]
+  "TARGET_FP"
+  "%|%.\\tsubsp\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "fp4")
+   (set_attr "units67" "l")
+   (set_attr "units67p" "ls")
+   (set_attr "units674" "ls")
+   (set_attr "cross" "n,n,y,y,y,y")])
+
+(define_insn "subdf3"
+  [(set (match_operand:DF 0 "register_operand" "=a,b, a, b, a, b")
+	(minus:DF (match_operand:DF 1 "register_operand" "a,b, b, a, a, b")
+		  (match_operand:DF 2 "register_operand" "a,b,?a,?b,?b,?a")))]
+  "TARGET_FP"
+  "%|%.\\tsubdp\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "adddp")
+   (set_attr "units67" "l")
+   (set_attr "units67p" "ls")
+   (set_attr "units674" "ls")
+   (set_attr "cross" "n,n,y,y,y,y")])
+
+;; -------------------------------------------------------------------------
+;; Logical instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "andsi3"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b,a,b")
+	(and:SI (match_operand:SI 1 "register_operand" "%a,b,b,a,a,b")
+		(match_operand:SI 2 "andsi_operand" "aIs5,bIs5,?aIs5,?bIs5,aJc,bJc")))]
+  ""
+{
+  if (which_alternative < 4)
+    return "%|%.\\tand\\t%$\\t%2, %1, %0";
+  else
+    return "%|%.\\tclr\\t%$\\t%1, %f2, %F2, %0";
+}
+  [(set_attr "units62" "ls,ls,ls,ls,s,s")
+   (set_attr "units64" "dls,dls,dls,dls,s,s")
+   (set_attr "cross" "n,n,y,y,n,n")])
+
+(define_insn "iorsi3"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b,a,b")
+	(ior:SI (match_operand:SI 1 "register_operand" "%a,b,b,a,a,b")
+		(match_operand:SI 2 "iorsi_operand" "aIs5,bIs5,?aIs5,?bIs5,aJs,bJs")))]
+  ""
+{
+  if (which_alternative < 4)
+    return "%|%.\\tor\\t%$\\t%2, %1, %0";
+  else
+    return "%|%.\\tset\\t%$\\t%1, %s2, %S2, %0";
+}
+  [(set_attr "units62" "ls,ls,ls,ls,s,s")
+   (set_attr "units64" "dls,dls,dls,dls,s,s")
+   (set_attr "cross" "n,n,y,y,n,n")])
+
+(define_insn "xorsi3"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+	(xor:SI (match_operand:SI 1 "register_operand" "%a,b,b,a")
+		(match_operand:SI 2 "reg_or_scst5_operand" "aIs5,bIs5,?aIs5,?bIs5")))]
+  ""
+  "%|%.\\txor\\t%$\\t%2, %1, %0"
+  [(set_attr "units62" "ls")
+   (set_attr "units64" "dls")
+   (set_attr "cross" "n,n,y,y")])
+
+;; -------------------------------------------------------------------------
+;; Conversions
+;; -------------------------------------------------------------------------
+
+(define_insn "extendsfdf2"
+  [(set (match_operand:DF 0 "register_operand" "=a,b,a,b")
+	(float_extend:DF (match_operand:SF 1 "register_operand" "a,b,?b,?a")))]
+  "TARGET_FP"
+  "%|%.\\tspdp\\t%$\\t%1,%0"
+  [(set_attr "type" "dp2")
+   (set_attr "units" "s")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "truncdfsf2"
+  [(set (match_operand:SF 0 "register_operand" "=a,b")
+	(float_truncate:SF (match_operand:DF 1 "register_operand" "a,b")))]
+  "TARGET_FP"
+  "%|%.\\tdpsp\\t%$\\t%1,%0"
+  [(set_attr "type" "fp4")
+   (set_attr "units" "l")
+   (set_attr "cross" "n")])
+
+;;;; Convert between signed integer types and floating point.
+(define_insn "floatsisf2"
+  [(set (match_operand:SF 0 "register_operand" "=a,b,a,b")
+	(float:SF (match_operand:SI 1 "register_operand" "a,b,?b,?a")))]
+  "TARGET_FP"
+  "%|%.\\tintsp\\t%$\\t%1,%0"
+  [(set_attr "type" "fp4")
+   (set_attr "units" "l")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "floatunssisf2"
+  [(set (match_operand:SF 0 "register_operand" "=a,b,a,b")
+	(unsigned_float:SF (match_operand:SI 1 "register_operand" "a,b,?b,?a")))]
+  "TARGET_FP"
+  "%|%.\\tintspu\\t%$\\t%1,%0"
+  [(set_attr "type" "fp4")
+   (set_attr "units" "l")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "floatsidf2"
+  [(set (match_operand:DF 0 "register_operand" "=a,b,a,b")
+	(float:DF (match_operand:SI 1 "register_operand" "a,b,?b,?a")))]
+  "TARGET_FP"
+  "%|%.\\tintdp\\t%$\\t%1,%0"
+  [(set_attr "type" "intdp")
+   (set_attr "units" "l")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "floatunssidf2"
+  [(set (match_operand:DF 0 "register_operand" "=a,b,a,b")
+	(unsigned_float:DF (match_operand:SI 1 "register_operand" "a,b,?b,?a")))]
+  "TARGET_FP"
+  "%|%.\\tintdpu\\t%$\\t%1,%0"
+  [(set_attr "type" "intdp")
+   (set_attr "units" "l")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "fix_truncsfsi2"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+	(fix:SI (match_operand:SF 1 "register_operand" "a,b,?b,?a")))]
+  "TARGET_FP"
+  "%|%.\\tsptrunc\\t%$\\t%1,%0"
+  [(set_attr "type" "fp4")
+   (set_attr "units" "l")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "fix_truncdfsi2"
+  [(set (match_operand:SI 0 "register_operand" "=a,b")
+	(fix:SI (match_operand:DF 1 "register_operand" "a,b")))]
+  "TARGET_FP"
+  "%|%.\\tdptrunc\\t%$\\t%1,%0"
+  [(set_attr "type" "fp4")
+   (set_attr "units" "l")
+   (set_attr "cross" "n")])
+
+;; -------------------------------------------------------------------------
+;; Saturating arithmetic
+;; -------------------------------------------------------------------------
+
+(define_insn "saddsi3"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b,a,b,a,b")
+	(ss_plus:SI (match_operand:SI 1 "register_operand" "a,b,?b,?a,a,b,?b,?a")
+		    (match_operand:SI 2 "reg_or_const_int_operand" "a,b,a,b,aIs5,bIs5,aIs5,bIs5")))]
+  ""
+  "%|%.\\tsadd\\t%$\\t%2, %1, %0"
+  [(set_attr "units" "ls,ls,ls,ls,l,l,l,l")
+   (set_attr "cross" "n,n,y,y,n,n,y,y")])
+
+(define_insn "ssubsi3"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+	(ss_minus:SI (match_operand:SI 1 "reg_or_scst5_operand" "aIs5,bIs5,?bIs5,?aIs5")
+		     (match_operand:SI 2 "register_operand" "a,b,a,b")))]
+  ""
+  "%|%.\\tssub\\t%$\\t%1, %2, %0"
+  [(set_attr "units" "l")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "subcsi3"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+	(unspec:SI
+	 [(match_operand:SI 1 "register_operand" "a,b,a,b")
+	  (match_operand:SI 2 "register_operand" "a,b,?b,?a")]
+	 UNSPEC_SUBC))]
+  ""
+  "%|%.\\tsubc\\t%$\\t%1, %2, %0"
+  [(set_attr "units" "l")
+   (set_attr "cross" "n,n,y,y")])
+
+;; -------------------------------------------------------------------------
+;; Call instructions
+;; -------------------------------------------------------------------------
+
+(define_expand "call"
+ [(match_operand 0 "" "")]
+ ""
+{
+  c6x_expand_call (NULL_RTX, operands[0], false);
+  DONE;
+})
+
+(define_expand "call_value"
+  [(match_operand 0 "" "")
+   (match_operand 1 "" "")]
+ ""
+{
+  c6x_expand_call (operands[0], operands[1], false);
+  DONE;
+})
+
+(define_expand "sibcall"
+ [(match_operand 0 "" "")]
+ ""
+{
+  c6x_expand_call (NULL_RTX, operands[0], true);
+  cfun->machine->contains_sibcall = true;
+  DONE;
+})
+
+(define_expand "sibcall_value"
+  [(match_operand 0 "" "")
+   (match_operand 1 "" "")]
+ ""
+{
+  c6x_expand_call (operands[0], operands[1], true);
+  cfun->machine->contains_sibcall = true;
+  DONE;
+})
+
+(define_insn "call_internal"
+  [(call (mem (match_operand:SI 0 "c6x_call_operand" "S1,a,b"))
+	 (const_int 0))]
+  "!SIBLING_CALL_P (insn)"
+  "%|%.\\tcall\\t%$\\t%0"
+  [(set_attr "type" "call")
+   (set_attr "predicable" "no")
+   (set_attr "units" "s")
+   (set_attr "dest_regfile" "any,b,b")
+   (set_attr "cross" "n,y,n")])
+
+(define_insn "call_value_internal"
+  [(set (match_operand 0 "" "")
+	(call (mem (match_operand:SI 1 "c6x_call_operand" "S1,a,b"))
+	      (const_int 0)))]
+  ""
+  "%|%.\\tcall\\t%$\\t%1"
+  [(set_attr "type" "call")
+   (set_attr "predicable" "no")
+   (set_attr "units" "s")
+   (set_attr "dest_regfile" "any,b,b")
+   (set_attr "cross" "n,y,n")])
+
+(define_insn "sibcall_internal"
+  [(call (mem (match_operand:SI 0 "c6x_call_operand" "S1,C"))
+	 (const_int 0))]
+  "SIBLING_CALL_P (insn)"
+  "%|%.\\tb\\t%$\\t%0"
+  [(set_attr "type" "branch")
+   (set_attr "predicable" "no")
+   (set_attr "units" "s")
+   (set_attr "dest_regfile" "any,b")])
+
+(define_insn "callp"
+  [(call (mem (match_operand:SI 0 "c6x_call_operand" "S1"))
+	 (const_int 0))
+   (unspec [(const_int 6)] UNSPEC_NOP)]
+  "!SIBLING_CALL_P (insn)"
+  "%|%.\\tcallp\\t%$\\t%0, B3"
+  [(set_attr "type" "callp")
+   (set_attr "predicable" "no")
+   (set_attr "units" "s")
+   (set_attr "dest_regfile" "b")
+   (set_attr "cross" "n")])
+
+(define_insn "callp_value"
+  [(set (match_operand:SI 0 "register_operand" "")
+	(call (mem (match_operand:SI 1 "c6x_call_operand" "S1"))
+	      (const_int 0)))
+   (unspec [(const_int 6)] UNSPEC_NOP)]
+  "!SIBLING_CALL_P (insn)"
+  "%|%.\\tcallp\\t%$\\t%1, B3"
+  [(set_attr "type" "callp")
+   (set_attr "predicable" "no")
+   (set_attr "units" "s")
+   (set_attr "dest_regfile" "b")
+   (set_attr "cross" "n")])
+
+(define_insn "return_internal"
+  [(return)
+   (use (match_operand:SI 0 "register_operand" "b"))]
+  "reload_completed"
+  "%|%.\\tret\\t%$\\t%0"
+  [(set_attr "type" "branch")
+   (set_attr "units" "s")
+   (set_attr "dest_regfile" "b")])
+
+(define_insn "addkpc"
+  [(set (match_operand:SI 0 "register_operand" "=b")
+	(unspec:SI [(match_operand 1 "" "")] UNSPEC_ADDKPC))
+   (unspec [(match_operand 2 "const_int_operand" "n")] UNSPEC_NOP)]
+  "TARGET_INSNS_64"
+  "%|%.\\taddkpc\\t%$\\t%l1, %0, %2"
+  [(set_attr "units" "s")
+   (set_attr "dest_regfile" "b")])
+
+;; -------------------------------------------------------------------------
+;; Unary operations
+;; -------------------------------------------------------------------------
+
+(define_insn "negsi2"
+  [(set (match_operand:SI 0 "register_operand" "=a, a, b, b")
+        (neg:SI (match_operand:SI 1 "register_operand" "a,?b, b,?a")))]
+  ""
+  "%|%.\\tneg\\t%$\\t%1, %0"
+  [(set_attr "units" "ls")
+   (set_attr "cross" "n,y,n,y")])
+
+(define_insn "one_cmplsi2"
+  [(set (match_operand:SI 0 "register_operand" "=a, a, b, b")
+	(not:SI (match_operand:SI 1 "register_operand" "a,?b, b,?a")))]
+  ""
+  "%|%.\\tnot\\t%$\\t%1, %0"
+  [(set_attr "units" "ls")
+   (set_attr "cross" "n,y,n,y")])
+
+(define_insn "clrsbsi2"
+  [(set (match_operand:SI 0 "register_operand" "=a, a, b, b")
+	(clrsb:SI (match_operand:SI 1 "register_operand" "a,?b, b,?a")))]
+  ""
+  "%|%.\\tnorm\\t%$\\t%1, %0"
+  [(set_attr "units" "l")
+   (set_attr "cross" "n,y,n,y")])
+
+(define_insn "clzsi2"
+  [(set (match_operand:SI 0 "register_operand" "=a, a, b, b")
+	(clz:SI (match_operand:SI 1 "register_operand" "a,?b, b,?a")))]
+  ""
+  "%|%.\\tlmbd\\t%$\\t1, %1, %0"
+  [(set_attr "units" "l")
+   (set_attr "cross" "n,y,n,y")])
+
+;; bitrevsi2 is defined in c6x-mult.md.in.
+
+(define_expand "ctzsi2"
+  [(set (match_operand:SI 0 "register_operand" "")
+	(ctz:SI (match_operand:SI 1 "register_operand" "")))]
+  "TARGET_INSNS_64"
+{
+  rtx tmpreg = gen_reg_rtx (SImode);
+  emit_insn (gen_bitrevsi2 (tmpreg, operands[1]));
+  emit_insn (gen_clzsi2 (operands[0], tmpreg));
+  DONE;
+})
+
+(define_expand "ctzdi2"
+  [(set (match_operand:DI 0 "register_operand" "")
+	(ctz:DI (match_operand:DI 1 "register_operand" "")))]
+  "TARGET_INSNS_64"
+{
+  rtx tmpreg = gen_reg_rtx (DImode);
+  rtx out;
+  emit_insn (gen_bitrevsi2 (gen_highpart (SImode, tmpreg),
+			    gen_lowpart (SImode, operands[1])));
+  emit_insn (gen_bitrevsi2 (gen_lowpart (SImode, tmpreg),
+			    gen_highpart (SImode, operands[1])));
+  out = expand_unop (DImode, clz_optab, tmpreg, operands[0], 1);
+  if (!rtx_equal_p (out, operands[0]))
+    emit_move_insn (operands[0], out);
+  DONE;
+})
+
+(define_insn "ssabssi2"
+  [(set (match_operand:SI 0 "register_operand" "=a, a, b, b")
+        (ss_abs:SI (match_operand:SI 1 "register_operand" "a,?b, b,?a")))]
+  ""
+  "%|%.\\tabs\\t%$\\t%1, %0"
+  [(set_attr "units" "l")
+   (set_attr "cross" "n,y,n,y")])
+
+;; -------------------------------------------------------------------------
+;; Shift instructions
+;; -------------------------------------------------------------------------
+
+(define_code_iterator any_shift [ss_ashift ashift ashiftrt lshiftrt])
+(define_code_iterator any_rshift [ashiftrt lshiftrt])
+(define_code_attr shift_code [(ss_ashift "ss_ashl") (ashift "ashl")
+			      (ashiftrt "ashr") (lshiftrt "lshr")])
+(define_code_attr shift_insn [(ss_ashift "sshl") (ashift "shl")
+			      (ashiftrt "shr") (lshiftrt "shru")])
+
+(define_insn "<shift_code>si3"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+        (any_shift:SI (match_operand:SI 1 "register_operand" "a,b,?b,?a")
+		      (match_operand:SI 2 "reg_or_ucst5_operand" "aIu5,bIu5,aIu5,bIu5")))]
+  ""
+  "%|%.\\t<shift_insn>\\t%$\\t%1, %2, %0"
+  [(set_attr "units" "s")
+   (set_attr "cross" "n,n,y,y")])
+
+;; See c6x-mult.md.in for the rotlsi3 pattern.
+
+(define_insn "rotrdi3_16"
+  [(set (match_operand:DI 0 "register_operand" "=a,b")
+        (rotatert:DI (match_operand:DI 1 "register_operand" "a,b")
+		     (const_int 16)))]
+  "TARGET_INSNS_64PLUS"
+  "%|%.\\tdpackx2\\t%$\\t%P1, %p1, %0"
+  [(set_attr "units" "l")
+   (set_attr "cross" "n")])
+
+(define_insn "shlmbsi3"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+        (ior:SI (ashift:SI (match_operand:SI 1 "register_operand" "a,b,?b,?a")
+			   (const_int 8))
+		(lshiftrt:SI (match_operand:SI 2 "register_operand" "a,b,a,b")
+			     (const_int 24))))]
+  "TARGET_INSNS_64"
+  "%|%.\\tshlmb\\t%$\\t%2, %1, %0"
+  [(set_attr "units" "ls")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_expand "ashldi3"
+  [(set (match_operand:DI 0 "register_operand" "")
+        (ashift:DI (match_operand:DI 1 "register_operand" "")
+		   (match_operand:SI 2 "const_int_operand" "")))]
+  "TARGET_INSNS_64"
+{
+  if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) == 8)
+    {
+      rtx lo0, lo1, hi0, hi1, tmp;
+      lo0 = gen_lowpart (SImode, operands[0]);
+      hi0 = gen_highpart (SImode, operands[0]);
+      lo1 = gen_lowpart (SImode, operands[1]);
+      hi1 = gen_highpart (SImode, operands[1]);
+      if (reg_overlap_mentioned_p (hi0, lo1))
+        tmp = gen_reg_rtx (SImode);
+      else
+        tmp = hi0;
+      emit_insn (gen_shlmbsi3 (tmp, hi1, lo1));
+      emit_insn (gen_ashlsi3 (lo0, lo1, operands[2]));
+      if (tmp != hi0)
+        emit_move_insn (hi0, tmp);
+      DONE;
+    }
+  FAIL;
+})
+
+(define_expand "rotrdi3"
+  [(set (match_operand:DI 0 "register_operand" "")
+        (rotatert:DI (match_operand:DI 1 "register_operand" "")
+		     (match_operand:SI 2 "const_int_operand" "")))]
+  "TARGET_INSNS_64PLUS"
+{
+  if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) == 16)
+    {
+      emit_insn (gen_rotrdi3_16 (operands[0], operands[1]));
+      DONE;
+    }
+  FAIL;
+})
+
+(define_insn "bswapv2hi2"
+  [(set (match_operand:V2HI 0 "register_operand" "=a,b,a,b")
+        (bswap:V2HI (match_operand:V2HI 1 "register_operand" "a,b,?b,?a")))]
+  "TARGET_INSNS_64"
+  "%|%.\\tswap4\\t%$\\t%1, %0"
+  [(set_attr "units" "l")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_expand "bswapsi2"
+  [(set (match_operand:SI 0 "register_operand" "")
+	(bswap:SI (match_operand:SI 1 "register_operand" "")))]
+  "TARGET_INSNS_64"
+{
+  rtx tmpreg = gen_reg_rtx (SImode);
+  rtx tmpv2 = gen_lowpart (V2HImode, tmpreg);
+  rtx op0v2 = gen_lowpart (V2HImode, operands[0]);
+  emit_insn (gen_rotlsi3 (tmpreg, operands[1], GEN_INT (16)));
+  emit_insn (gen_bswapv2hi2 (op0v2, tmpv2));
+  DONE;
+})
+
+;; -------------------------------------------------------------------------
+;; Division
+;; -------------------------------------------------------------------------
+
+(define_insn "divsi3_insn"
+  [(set (reg:SI REG_A4) (div:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+   (clobber (reg:SI REG_A0))
+   (clobber (reg:SI REG_A1))
+   (clobber (reg:SI REG_A2))
+   (clobber (reg:SI REG_A6))
+   (clobber (reg:SI REG_B0))
+   (clobber (reg:SI REG_B1))
+   (clobber (reg:SI REG_B2))
+   (clobber (reg:SI REG_B3))
+   (clobber (reg:SI REG_B4))
+   (clobber (reg:SI REG_B5))
+   (clobber (reg:SI REG_B30))
+   (clobber (reg:SI REG_B31))]
+  ""
+  "%|%.\\tcall\\t%$\\t__c6xabi_divi"
+  [(set_attr "type" "call")
+   (set_attr "dest_regfile" "any")
+   (set_attr "units" "s")
+   (set_attr "cross" "n")])
+
+(define_insn "divsi3_insn_indcall"
+  [(set (reg:SI REG_A4) (div:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+   (use (match_operand:SI 0 "register_operand" "b"))
+   (clobber (reg:SI REG_A0))
+   (clobber (reg:SI REG_A1))
+   (clobber (reg:SI REG_A2))
+   (clobber (reg:SI REG_A6))
+   (clobber (reg:SI REG_B0))
+   (clobber (reg:SI REG_B1))
+   (clobber (reg:SI REG_B2))
+   (clobber (reg:SI REG_B3))
+   (clobber (reg:SI REG_B4))
+   (clobber (reg:SI REG_B5))
+   (clobber (reg:SI REG_B30))
+   (clobber (reg:SI REG_B31))]
+  ""
+  "%|%.\\tcall\\t%$\\t%0"
+  [(set_attr "type" "call")
+   (set_attr "dest_regfile" "any")
+   (set_attr "units" "s")
+   (set_attr "cross" "n")])
+
+(define_insn "udivsi3_insn"
+  [(set (reg:SI REG_A4) (udiv:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+   (clobber (reg:SI REG_A0))
+   (clobber (reg:SI REG_A1))
+   (clobber (reg:SI REG_A2))
+   (clobber (reg:SI REG_A6))
+   (clobber (reg:SI REG_B0))
+   (clobber (reg:SI REG_B1))
+   (clobber (reg:SI REG_B2))
+   (clobber (reg:SI REG_B3))
+   (clobber (reg:SI REG_B4))
+   (clobber (reg:SI REG_B30))
+   (clobber (reg:SI REG_B31))]
+  ""
+  "%|%.\\tcall\\t%$\\t__c6xabi_divu"
+  [(set_attr "type" "call")
+   (set_attr "dest_regfile" "any")
+   (set_attr "units" "s")
+   (set_attr "cross" "n")])
+
+(define_insn "udivsi3_insn_indcall"
+  [(set (reg:SI REG_A4) (udiv:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+   (use (match_operand:SI 0 "register_operand" "b"))
+   (clobber (reg:SI REG_A0))
+   (clobber (reg:SI REG_A1))
+   (clobber (reg:SI REG_A2))
+   (clobber (reg:SI REG_A6))
+   (clobber (reg:SI REG_B0))
+   (clobber (reg:SI REG_B1))
+   (clobber (reg:SI REG_B2))
+   (clobber (reg:SI REG_B3))
+   (clobber (reg:SI REG_B4))
+   (clobber (reg:SI REG_B30))
+   (clobber (reg:SI REG_B31))]
+  ""
+  "%|%.\\tcall\\t%$\\t%0"
+  [(set_attr "type" "call")
+   (set_attr "dest_regfile" "any")
+   (set_attr "units" "s")
+   (set_attr "cross" "n")])
+
+(define_insn "modsi3_insn"
+  [(set (reg:SI REG_A4) (mod:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+   (clobber (reg:SI REG_A1))
+   (clobber (reg:SI REG_A2))
+   (clobber (reg:SI REG_A5))
+   (clobber (reg:SI REG_A6))
+   (clobber (reg:SI REG_B0))
+   (clobber (reg:SI REG_B1))
+   (clobber (reg:SI REG_B2))
+   (clobber (reg:SI REG_B3))
+   (clobber (reg:SI REG_B4))
+   (clobber (reg:SI REG_B30))
+   (clobber (reg:SI REG_B31))]
+  ""
+  "%|%.\\tcall\\t%$\\t__c6xabi_remi"
+  [(set_attr "type" "call")
+   (set_attr "dest_regfile" "any")
+   (set_attr "units" "s")
+   (set_attr "cross" "n")])
+
+(define_insn "modsi3_insn_indcall"
+  [(set (reg:SI REG_A4) (mod:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+   (use (match_operand:SI 0 "register_operand" "b"))
+   (clobber (reg:SI REG_A1))
+   (clobber (reg:SI REG_A2))
+   (clobber (reg:SI REG_A5))
+   (clobber (reg:SI REG_A6))
+   (clobber (reg:SI REG_B0))
+   (clobber (reg:SI REG_B1))
+   (clobber (reg:SI REG_B2))
+   (clobber (reg:SI REG_B3))
+   (clobber (reg:SI REG_B4))
+   (clobber (reg:SI REG_B30))
+   (clobber (reg:SI REG_B31))]
+  ""
+  "%|%.\\tcall\\t%$\\t%0"
+  [(set_attr "type" "call")
+   (set_attr "dest_regfile" "any")
+   (set_attr "units" "s")
+   (set_attr "cross" "n")])
+
+(define_insn "divmodsi4_insn"
+  [(set (reg:SI REG_A4) (div:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+   (set (reg:SI REG_A5) (mod:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+   (clobber (reg:SI REG_A1))
+   (clobber (reg:SI REG_A2))
+   (clobber (reg:SI REG_A6))
+   (clobber (reg:SI REG_B0))
+   (clobber (reg:SI REG_B1))
+   (clobber (reg:SI REG_B2))
+   (clobber (reg:SI REG_B3))
+   (clobber (reg:SI REG_B4))
+   (clobber (reg:SI REG_B30))
+   (clobber (reg:SI REG_B31))]
+  ""
+  "%|%.\\tcall\\t%$\\t__c6xabi_divremi"
+  [(set_attr "type" "call")
+   (set_attr "dest_regfile" "any")
+   (set_attr "units" "s")
+   (set_attr "cross" "n")])
+
+(define_insn "divmodsi4_insn_indcall"
+  [(set (reg:SI REG_A4) (div:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+   (set (reg:SI REG_A5) (mod:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+   (use (match_operand:SI 0 "register_operand" "b"))
+   (clobber (reg:SI REG_A1))
+   (clobber (reg:SI REG_A2))
+   (clobber (reg:SI REG_A5))
+   (clobber (reg:SI REG_A6))
+   (clobber (reg:SI REG_B0))
+   (clobber (reg:SI REG_B1))
+   (clobber (reg:SI REG_B2))
+   (clobber (reg:SI REG_B3))
+   (clobber (reg:SI REG_B4))
+   (clobber (reg:SI REG_B30))
+   (clobber (reg:SI REG_B31))]
+  ""
+  "%|%.\\tcall\\t%$\\t%0"
+  [(set_attr "type" "call")
+   (set_attr "dest_regfile" "any")
+   (set_attr "units" "s")
+   (set_attr "cross" "n")])
+
+(define_insn "umodsi3_insn"
+  [(set (reg:SI REG_A4) (umod:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+   (clobber (reg:SI REG_A1))
+   (clobber (reg:SI REG_A5))
+   (clobber (reg:SI REG_A7))
+   (clobber (reg:SI REG_B0))
+   (clobber (reg:SI REG_B1))
+   (clobber (reg:SI REG_B2))
+   (clobber (reg:SI REG_B3))
+   (clobber (reg:SI REG_B4))
+   (clobber (reg:SI REG_B30))
+   (clobber (reg:SI REG_B31))]
+  ""
+  "%|%.\\tcall\\t%$\\t__c6xabi_remu"
+  [(set_attr "type" "call")
+   (set_attr "dest_regfile" "any")
+   (set_attr "units" "s")
+   (set_attr "cross" "n")])
+
+(define_insn "umodsi3_insn_indcall"
+  [(set (reg:SI REG_A4) (umod:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+   (use (match_operand:SI 0 "register_operand" "b"))
+   (clobber (reg:SI REG_A1))
+   (clobber (reg:SI REG_A5))
+   (clobber (reg:SI REG_A7))
+   (clobber (reg:SI REG_B0))
+   (clobber (reg:SI REG_B1))
+   (clobber (reg:SI REG_B2))
+   (clobber (reg:SI REG_B3))
+   (clobber (reg:SI REG_B4))
+   (clobber (reg:SI REG_B30))
+   (clobber (reg:SI REG_B31))]
+  ""
+  "%|%.\\tcall\\t%$\\t%0"
+  [(set_attr "type" "call")
+   (set_attr "dest_regfile" "any")
+   (set_attr "units" "s")
+   (set_attr "cross" "n")])
+
+(define_insn "udivmodsi4_insn"
+  [(set (reg:SI REG_A4) (udiv:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+   (set (reg:SI REG_A5) (umod:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+   (clobber (reg:SI REG_A0))
+   (clobber (reg:SI REG_A1))
+   (clobber (reg:SI REG_A2))
+   (clobber (reg:SI REG_A6))
+   (clobber (reg:SI REG_B0))
+   (clobber (reg:SI REG_B1))
+   (clobber (reg:SI REG_B2))
+   (clobber (reg:SI REG_B3))
+   (clobber (reg:SI REG_B4))
+   (clobber (reg:SI REG_B30))
+   (clobber (reg:SI REG_B31))]
+  ""
+  "%|%.\\tcall\\t%$\\t__c6xabi_divremu"
+  [(set_attr "type" "call")
+   (set_attr "dest_regfile" "any")
+   (set_attr "units" "s")
+   (set_attr "cross" "n")])
+
+(define_insn "udivmodsi4_insn_indcall"
+  [(set (reg:SI REG_A4) (udiv:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+   (set (reg:SI REG_A5) (umod:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+   (use (match_operand:SI 0 "register_operand" "b"))
+   (clobber (reg:SI REG_A0))
+   (clobber (reg:SI REG_A1))
+   (clobber (reg:SI REG_A2))
+   (clobber (reg:SI REG_A6))
+   (clobber (reg:SI REG_B0))
+   (clobber (reg:SI REG_B1))
+   (clobber (reg:SI REG_B2))
+   (clobber (reg:SI REG_B3))
+   (clobber (reg:SI REG_B4))
+   (clobber (reg:SI REG_B30))
+   (clobber (reg:SI REG_B31))]
+  ""
+  "%|%.\\tcall\\t%$\\t%0"
+  [(set_attr "type" "call")
+   (set_attr "dest_regfile" "any")
+   (set_attr "units" "s")
+   (set_attr "cross" "n")])
+
+(define_insn_and_split "divmodsi4"
+  [(set (match_operand:SI 0 "register_operand" "")
+	(div:SI (match_operand:SI 1 "register_operand" "")
+		   (match_operand:SI 2 "register_operand" "")))
+   (set (match_operand:SI 3 "register_operand" "")
+	(mod:SI (match_dup 1) (match_dup 2)))
+   (clobber (reg:SI REG_A0))
+   (clobber (reg:SI REG_A1))
+   (clobber (reg:SI REG_A2))
+   (clobber (reg:SI REG_A4))
+   (clobber (reg:SI REG_A5))
+   (clobber (reg:SI REG_A6))
+   (clobber (reg:SI REG_B0))
+   (clobber (reg:SI REG_B1))
+   (clobber (reg:SI REG_B2))
+   (clobber (reg:SI REG_B3))
+   (clobber (reg:SI REG_B4))
+   (clobber (reg:SI REG_B5))
+   (clobber (reg:SI REG_B30))
+   (clobber (reg:SI REG_B31))]
+  ""
+  "#"
+  ""
+  [(const_int 0)]
+{
+  rtx reg = NULL_RTX;
+
+  if (TARGET_LONG_CALLS)
+    {
+      if (reload_completed)
+	reg = gen_rtx_REG (SImode, REG_A6);
+      else
+        reg = gen_reg_rtx (SImode);
+    }
+  emit_move_insn (gen_rtx_REG (SImode, REG_A4), operands[1]);
+  emit_move_insn (gen_rtx_REG (SImode, REG_B4), operands[2]);
+  if (find_reg_note (curr_insn, REG_UNUSED, operands[3]))
+    {
+      if (TARGET_LONG_CALLS)
+	{
+	  emit_move_insn (reg, optab_libfunc (sdiv_optab, SImode));
+	  emit_insn (gen_divsi3_insn_indcall (reg));
+	}
+      else
+        emit_insn (gen_divsi3_insn ());
+      emit_move_insn (operands[0], gen_rtx_REG (SImode, REG_A4));
+    }
+  else if (find_reg_note (curr_insn, REG_UNUSED, operands[0]))
+    {
+      if (TARGET_LONG_CALLS)
+	{
+	  emit_move_insn (reg, optab_libfunc (smod_optab, SImode));
+	  emit_insn (gen_modsi3_insn_indcall (reg));
+	}
+      else
+        emit_insn (gen_modsi3_insn ());
+      emit_move_insn (operands[3], gen_rtx_REG (SImode, REG_A4));
+    }
+  else
+    {
+      if (TARGET_LONG_CALLS)
+	{
+	  emit_move_insn (reg, optab_libfunc (sdivmod_optab, SImode));
+	  emit_insn (gen_divmodsi4_insn_indcall (reg));
+	}
+      else
+        emit_insn (gen_divmodsi4_insn ());
+      emit_move_insn (operands[0], gen_rtx_REG (SImode, REG_A4));
+      emit_move_insn (operands[3], gen_rtx_REG (SImode, REG_A5));
+    }
+  DONE;
+})
+
+(define_insn_and_split "udivmodsi4"
+  [(set (match_operand:SI 0 "register_operand" "")
+	(udiv:SI (match_operand:SI 1 "register_operand" "")
+		   (match_operand:SI 2 "register_operand" "")))
+   (set (match_operand:SI 3 "register_operand" "")
+	(umod:SI (match_dup 1) (match_dup 2)))
+   (clobber (reg:SI REG_A0))
+   (clobber (reg:SI REG_A1))
+   (clobber (reg:SI REG_A2))
+   (clobber (reg:SI REG_A4))
+   (clobber (reg:SI REG_A5))
+   (clobber (reg:SI REG_A6))
+   (clobber (reg:SI REG_A7))
+   (clobber (reg:SI REG_B0))
+   (clobber (reg:SI REG_B1))
+   (clobber (reg:SI REG_B2))
+   (clobber (reg:SI REG_B3))
+   (clobber (reg:SI REG_B4))
+   (clobber (reg:SI REG_B30))
+   (clobber (reg:SI REG_B31))]
+  ""
+  "#"
+  ""
+  [(const_int 0)]
+{
+  rtx reg = NULL_RTX;
+
+  if (TARGET_LONG_CALLS)
+    {
+      if (reload_completed)
+	reg = gen_rtx_REG (SImode, REG_A6);
+      else
+        reg = gen_reg_rtx (SImode);
+    }
+
+  emit_move_insn (gen_rtx_REG (SImode, REG_A4), operands[1]);
+  emit_move_insn (gen_rtx_REG (SImode, REG_B4), operands[2]);
+  if (find_reg_note (curr_insn, REG_UNUSED, operands[3]))
+    {
+      if (TARGET_LONG_CALLS)
+	{
+	  emit_move_insn (reg, optab_libfunc (udiv_optab, SImode));
+	  emit_insn (gen_udivsi3_insn_indcall (reg));
+	}
+      else
+        emit_insn (gen_udivsi3_insn ());
+      emit_move_insn (operands[0], gen_rtx_REG (SImode, REG_A4));
+    }
+  else if (find_reg_note (curr_insn, REG_UNUSED, operands[0]))
+    {
+      if (TARGET_LONG_CALLS)
+	{
+	  emit_move_insn (reg, optab_libfunc (umod_optab, SImode));
+	  emit_insn (gen_umodsi3_insn_indcall (reg));
+	}
+      else
+        emit_insn (gen_umodsi3_insn ());
+      emit_move_insn (operands[3], gen_rtx_REG (SImode, REG_A4));
+    }
+  else
+    {
+      if (TARGET_LONG_CALLS)
+	{
+	  emit_move_insn (reg, optab_libfunc (udivmod_optab, SImode));
+	  emit_insn (gen_udivmodsi4_insn_indcall (reg));
+	}
+      else
+        emit_insn (gen_udivmodsi4_insn ());
+      emit_move_insn (operands[0], gen_rtx_REG (SImode, REG_A4));
+      emit_move_insn (operands[3], gen_rtx_REG (SImode, REG_A5));
+    }
+  DONE;
+})
+
+;; -------------------------------------------------------------------------
+;; Multiplication
+;; See c6x-mult.md.in for define_insn patterns.
+;; -------------------------------------------------------------------------
+
+(define_expand "mulhisi3"
+  [(set (match_operand:SI 0 "register_operand" "")
+        (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" ""))
+                 (sign_extend:SI (match_operand:HI 2 "reg_or_scst5_operand" ""))))]
+  ""
+{
+  if (CONSTANT_P (operands[2]))
+    {
+      emit_insn (gen_mulhisi3_const (operands[0], operands[1], operands[2]));
+      DONE;
+    }
+})
+
+(define_expand "usmulhisi3"
+  [(set (match_operand:SI 0 "register_operand" "")
+        (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" ""))
+                 (sign_extend:SI (match_operand:HI 2 "reg_or_scst5_operand" ""))))]
+ ""
+{
+  if (CONSTANT_P (operands[2]))
+    {
+      emit_insn (gen_usmulhisi3_const (operands[0], operands[1], operands[2]));
+      DONE;
+    }
+})
+
+(define_expand "mulsi3"
+  [(set (match_operand:SI 0 "register_operand" "")
+	(mult:SI (match_operand:SI 1 "register_operand" "")
+		 (match_operand:SI 2 "register_operand" "")))]
+  ""
+{
+  if (!TARGET_MPY32)
+    {
+      rtx lo1 = gen_lowpart (HImode, operands[1]);
+      rtx lo2 = gen_lowpart (HImode, operands[2]);
+      /*   (N * AH + AL) * (N * BH + BL)
+         = N*(AH * BL + BH * AL) + AL*BL  */
+      rtx tmp1 = gen_reg_rtx (SImode);
+      rtx tmp2 = gen_reg_rtx (SImode);
+      rtx tmp3 = gen_reg_rtx (SImode);
+      emit_insn (gen_umulhisi3 (tmp1, lo1, lo2));
+      emit_insn (gen_umulhisi3_lh (tmp2, lo1, operands[2]));
+      emit_insn (gen_umulhisi3_hl (tmp3, operands[1], lo2));
+      emit_insn (gen_addsi3 (tmp2, tmp2, tmp3));
+      emit_insn (gen_ashlsi3 (tmp2, tmp2, GEN_INT (16)));
+      emit_insn (gen_addsi3 (operands[0], tmp1, tmp2));
+      DONE;
+    }
+})
+
+;; -------------------------------------------------------------------------
+;; Floating point multiplication
+;; -------------------------------------------------------------------------
+
+(define_insn "mulsf3"
+  [(set (match_operand:SF 0 "register_operand" "=a,b,a,b")
+	(mult:SF (match_operand:SF 1 "register_operand" "%a,b,?a,?b")
+		 (match_operand:SF 2 "register_operand" "a,b,b,a")))]
+  "TARGET_FP"
+  "%|%.\\tmpysp\\t%$\\t%1, %2, %0"
+ [(set_attr "type" "mpy4")
+  (set_attr "units" "m")
+  (set_attr "cross" "n,n,y,y")])
+
+(define_insn "muldf3"
+  [(set (match_operand:DF 0 "register_operand" "=a,b")
+	(mult:DF (match_operand:DF 1 "register_operand" "%a,b")
+		 (match_operand:DF 2 "register_operand" "a,b")))]
+  "TARGET_FP"
+  "%|%.\\tmpydp\\t%$\\t%1, %2, %0"
+ [(set_attr "type" "mpydp")
+  (set_attr "units" "m")
+  (set_attr "cross" "n")])
+
+;; Note that mpyspdp and mpysp2dp are available on C67x, despite what the
+;; manual says.
+(define_insn "*muldf_ext1"
+  [(set (match_operand:DF 0 "register_operand" "=a,b,a,b")
+	(mult:DF (float_extend:DF (match_operand:SF 1 "register_operand" "a,b,a,b"))
+		 (match_operand:DF 2 "register_operand" "a,b,?b,?a")))]
+  "TARGET_FP_EXT"
+  "%|%.\\tmpyspdp\\t%$\\t%1, %2, %0"
+ [(set_attr "type" "mpyspdp")
+  (set_attr "units" "m")
+  (set_attr "cross" "n,n,y,y")])
+
+(define_insn "*muldf_ext2"
+  [(set (match_operand:DF 0 "register_operand" "=a,b,a,b")
+	(mult:DF (float_extend:DF (match_operand:SF 1 "register_operand" "%a,b,a,b"))
+		 (float_extend:DF (match_operand:SF 2 "register_operand" "a,b,?b,?a"))))]
+  "TARGET_FP_EXT"
+  "%|%.\\tmpysp2dp\\t%$\\t%1, %2, %0"
+ [(set_attr "type" "mpysp2dp")
+  (set_attr "units" "m")
+  (set_attr "cross" "n,n,y,y")])
+
+;; -------------------------------------------------------------------------
+;; Floating point division
+;; -------------------------------------------------------------------------
+
+(define_insn "rcpsf2"
+  [(set (match_operand:SF 0 "register_operand" "=a,b,a,b")
+	(unspec:SF [(match_operand:SF 1 "register_operand" "a,b,?b,?a")]
+		   UNSPEC_RCP))]
+  "TARGET_FP"
+  "%|%.\\trcpsp\\t%$\\t%1, %0"
+ [(set_attr "units" "s")
+  (set_attr "cross" "n,n,y,y")])
+
+(define_insn "rcpdf2"
+  [(set (match_operand:DF 0 "register_operand" "=a,b")
+	(unspec:DF [(match_operand:DF 1 "register_operand" "a,b")]
+		   UNSPEC_RCP))]
+  "TARGET_FP"
+  "%|%.\\trcpdp\\t%$\\t%1, %0"
+ [(set_attr "type" "dp2")
+  (set_attr "units" "s")
+  (set_attr "cross" "n")])
+
+(define_expand "divsf3"
+  [(set (match_dup 4)
+	(unspec:SF [(match_operand:SF 2 "register_operand" "")]
+		   UNSPEC_RCP))
+   (set (match_dup 5) (mult:SF (match_dup 2) (match_dup 4)))
+   (set (match_dup 6) (minus:SF (match_dup 3) (match_dup 5)))
+   (set (match_dup 4) (mult:SF (match_dup 4) (match_dup 6)))
+   (set (match_dup 5) (mult:SF (match_dup 2) (match_dup 4)))
+   (set (match_dup 6) (minus:SF (match_dup 3) (match_dup 5)))
+   (set (match_dup 4) (mult:SF (match_dup 4) (match_dup 6)))
+   (set (match_operand:SF 0 "register_operand" "")
+	(mult:SF (match_operand:SF 1 "register_operand")
+		 (match_dup 4)))]
+  "TARGET_FP && flag_reciprocal_math"
+{
+  operands[3] = force_reg (SFmode,
+			   const_double_from_real_value (dconst2, SFmode));
+  operands[4] = gen_reg_rtx (SFmode);
+  operands[5] = gen_reg_rtx (SFmode);
+  operands[6] = gen_reg_rtx (SFmode);
+})
+
+(define_expand "divdf3"
+  [(set (match_dup 4)
+	(unspec:DF [(match_operand:DF 2 "register_operand" "")]
+		   UNSPEC_RCP))
+   (set (match_dup 5) (mult:DF (match_dup 2) (match_dup 4)))
+   (set (match_dup 6) (minus:DF (match_dup 3) (match_dup 5)))
+   (set (match_dup 4) (mult:DF (match_dup 4) (match_dup 6)))
+   (set (match_dup 5) (mult:DF (match_dup 2) (match_dup 4)))
+   (set (match_dup 6) (minus:DF (match_dup 3) (match_dup 5)))
+   (set (match_dup 4) (mult:DF (match_dup 4) (match_dup 6)))
+   (set (match_dup 5) (mult:DF (match_dup 2) (match_dup 4)))
+   (set (match_dup 6) (minus:DF (match_dup 3) (match_dup 5)))
+   (set (match_dup 4) (mult:DF (match_dup 4) (match_dup 6)))
+   (set (match_operand:DF 0 "register_operand" "")
+	(mult:DF (match_operand:DF 1 "register_operand")
+		 (match_dup 4)))]
+  "TARGET_FP && flag_reciprocal_math"
+{
+  operands[3] = force_reg (DFmode,
+			   const_double_from_real_value (dconst2, DFmode));
+  operands[4] = gen_reg_rtx (DFmode);
+  operands[5] = gen_reg_rtx (DFmode);
+  operands[6] = gen_reg_rtx (DFmode);
+})
+
+;; -------------------------------------------------------------------------
+;; Block moves
+;; -------------------------------------------------------------------------
+
+(define_expand "movmemsi"
+  [(use (match_operand:BLK 0 "memory_operand" ""))
+   (use (match_operand:BLK 1 "memory_operand" ""))
+   (use (match_operand:SI 2 "nonmemory_operand" ""))
+   (use (match_operand:SI 3 "const_int_operand" ""))
+   (use (match_operand:SI 4 "const_int_operand" ""))
+   (use (match_operand:SI 5 "const_int_operand" ""))]
+  ""
+{
+ if (c6x_expand_movmem (operands[0], operands[1], operands[2], operands[3],
+			operands[4], operands[5]))
+   DONE;
+ else
+   FAIL;
+})
+
+;; -------------------------------------------------------------------------
+;; Prologue and epilogue.
+;; -------------------------------------------------------------------------
+
+;; 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)] UNSPECV_BLOCKAGE)]
+  ""
+  ""
+  [(set_attr "type" "blockage")])
+
+(define_insn "push_rts"
+  [(set (mem:SI (reg:SI REG_SP)) (reg:SI REG_B14))
+   (set (mem:DI (plus:SI (reg:SI REG_SP) (const_int -8))) (reg:DI REG_A14))
+   (set (mem:DI (plus:SI (reg:SI REG_SP) (const_int -16))) (reg:DI REG_B12))
+   (set (mem:DI (plus:SI (reg:SI REG_SP) (const_int -24))) (reg:DI REG_A12))
+   (set (mem:DI (plus:SI (reg:SI REG_SP) (const_int -32))) (reg:DI REG_B10))
+   (set (mem:DI (plus:SI (reg:SI REG_SP) (const_int -40))) (reg:DI REG_A10))
+   (set (mem:DI (plus:SI (reg:SI REG_SP) (const_int -48))) (reg:DI REG_B2))
+   (set (reg:SI REG_SP) (plus:SI (reg:SI REG_SP) (const_int -56)))
+   (unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)
+   (clobber (reg:SI REG_A3))]
+  "TARGET_INSNS_64PLUS"
+  "%|%.\\tcallp\\t%$\\t__c6xabi_push_rts, a3"
+  [(set_attr "type" "callp")
+   (set_attr "dest_regfile" "a")
+   (set_attr "units" "s")
+   (set_attr "cross" "n")])
+
+(define_insn "pop_rts"
+  [(set (reg:SI REG_B14) (mem:SI (plus:SI (reg:SI REG_SP) (const_int 56))))
+   (set (reg:DI REG_A14) (mem:DI (plus:SI (reg:SI REG_SP) (const_int 48))))
+   (set (reg:DI REG_B12) (mem:DI (plus:SI (reg:SI REG_SP) (const_int 40))))
+   (set (reg:DI REG_A12) (mem:DI (plus:SI (reg:SI REG_SP) (const_int 32))))
+   (set (reg:DI REG_B10) (mem:DI (plus:SI (reg:SI REG_SP) (const_int 24))))
+   (set (reg:DI REG_A10) (mem:DI (plus:SI (reg:SI REG_SP) (const_int 16))))
+   (set (reg:DI REG_B2) (mem:DI (plus:SI (reg:SI REG_SP) (const_int 8))))
+   (set (reg:SI REG_SP) (plus:SI (reg:SI REG_SP) (const_int 56)))
+   (clobber (reg:SI REG_A3))
+   (return)]
+  "TARGET_INSNS_64PLUS"
+  "%|%.\\tretp\\t%$\\t__c6xabi_pop_rts, a3"
+  [(set_attr "type" "callp")
+   (set_attr "dest_regfile" "a")
+   (set_attr "units" "s")
+   (set_attr "cross" "n")])
+
+(define_expand "prologue"
+  [(const_int 1)]
+  ""
+  "c6x_expand_prologue (); DONE;")
+
+(define_expand "epilogue"
+  [(const_int 1)]
+  ""
+  "c6x_expand_epilogue (false); DONE;")
+
+(define_expand "sibcall_epilogue"
+  [(return)]
+  ""
+{
+  c6x_expand_epilogue (true);
+  DONE;
+})
+
+(define_insn "setup_dsbt"
+  [(set (match_operand:SI 0 "pic_register_operand" "+Z")
+	(unspec:SI [(match_dup 0)
+		    (match_operand:SI 1 "symbolic_operand" "")]
+		   UNSPEC_SETUP_DSBT))]
+  "TARGET_DSBT"
+  "%|%.\\tldw\\t%$\\t*+%0($DSBT_index%1), %0"
+  [(set_attr "type" "load")
+   (set_attr "units" "d_addr")
+   (set_attr "dest_regfile" "b")
+   (set_attr "addr_regfile" "b")])
+
+
+;; A dummy use/set to prevent prologue and epiloge overlapping.
+;; This can be caused by sched-ebb in the presence of multiple
+;; exit sequences, and causes the unwinding table generation to explode.
+(define_insn "epilogue_barrier"
+ [(set (match_operand:SI 0 "register_operand" "")
+       (unspec:SI [(match_operand:SI 1 "register_operand" "")]
+		  UNSPEC_EPILOGUE_BARRIER))]
+ ""
+ ""
+ [(set_attr "type" "blockage")])
+
+;; -------------------------------------------------------------------------
+;; Vector insns
+;; -------------------------------------------------------------------------
+
+(define_code_iterator logical [and ior xor])
+(define_code_attr logical_insn [(and "and") (ior "ior") (xor "xor")])
+(define_code_attr logical_opcode [(and "and") (ior "or") (xor "xor")])
+(define_code_iterator plusminus [plus minus])
+(define_code_attr plusminus_insn [(plus "add") (minus "sub")])
+(define_code_iterator ss_plusminus [ss_plus ss_minus])
+(define_code_attr ss_plusminus_insn [(ss_plus "add") (ss_minus "sub")])
+
+;; Vector logical insns
+
+(define_insn "<logical_insn><mode>3"
+  [(set (match_operand:VEC4M 0 "register_operand" "=a,b,a,b")
+	(logical:VEC4M (match_operand:VEC4M 1 "register_operand" "a,b,a,b")
+		      (match_operand:VEC4M 2 "register_operand" "a,b,?b,?a")))]
+  ""
+  "%|%.\\t<logical_opcode>\\t%$\\t%1, %2, %0"
+  [(set_attr "units62" "ls")
+   (set_attr "units64" "dls")
+   (set_attr "cross" "n,n,y,y")])
+
+;; Vector add/subtract
+
+(define_insn "<plusminus_insn>v2hi3"
+  [(set (match_operand:V2HI 0 "register_operand" "=a,b,a,b")
+	(plusminus:V2HI (match_operand:V2HI 1 "register_operand" "a,b,a,b")
+			(match_operand:V2HI 2 "register_operand" "a,b,?b,?a")))]
+  ""
+  "%|%.\\t<plusminus_insn>2\\t%$\\t%1, %2, %0"
+ [(set_attr "units62" "l")
+  (set_attr "units64" "dls")
+  (set_attr "cross" "n,n,y,y")])
+
+(define_insn "<plusminus_insn>v4qi3"
+  [(set (match_operand:V4QI 0 "register_operand" "=a,b,a,b")
+	(plusminus:V4QI (match_operand:V4QI 1 "register_operand" "a,b,a,b")
+			(match_operand:V4QI 2 "register_operand" "a,b,?b,?a")))]
+  "TARGET_INSNS_64"
+  "%|%.\\t<plusminus_insn>4\\t%$\\t%1, %2, %0"
+ [(set_attr "units" "l")
+  (set_attr "cross" "n,n,y,y")])
+
+(define_insn "ss_addv2hi3"
+  [(set (match_operand:V2HI 0 "register_operand" "=a,b,a,b")
+	(ss_plus:V2HI (match_operand:V2HI 1 "register_operand" "a,b,a,b")
+		      (match_operand:V2HI 2 "register_operand" "a,b,?b,?a")))]
+  "TARGET_INSNS_64"
+  "%|%.\\tsadd2\\t%$\\t%1, %2, %0"
+ [(set_attr "units" "s")
+  (set_attr "cross" "n,n,y,y")])
+
+(define_insn "ss_subv2hi3"
+  [(set (match_operand:V2HI 0 "register_operand" "=a,b,a,b")
+	(ss_minus:V2HI (match_operand:V2HI 1 "register_operand" "a,b,a,b")
+		       (match_operand:V2HI 2 "register_operand" "a,b,?b,?a")))]
+  "TARGET_INSNS_64"
+  "%|%.\\tssub2\\t%$\\t%1, %2, %0"
+ [(set_attr "units" "l")
+  (set_attr "cross" "n,n,y,y")])
+
+(define_insn "us_addv4qi3"
+  [(set (match_operand:V4QI 0 "register_operand" "=a,b,a,b")
+	(ss_plus:V4QI (match_operand:V4QI 1 "register_operand" "a,b,a,b")
+		      (match_operand:V4QI 2 "register_operand" "a,b,?b,?a")))]
+  "TARGET_INSNS_64"
+  "%|%.\\tsaddu4\\t%$\\t%1, %2, %0"
+ [(set_attr "units" "s")
+  (set_attr "cross" "n,n,y,y")])
+
+;; Vector/scalar min/max
+
+(define_mode_iterator SMINMAX [HI V2HI])
+(define_mode_iterator UMINMAX [QI V4QI])
+
+(define_insn "smax<mode>3"
+  [(set (match_operand:SMINMAX 0 "register_operand" "=a,b,a,b")
+	(smax:SMINMAX (match_operand:SMINMAX 1 "register_operand" "a,b,a,b")
+		      (match_operand:SMINMAX 2 "register_operand" "a,b,?b,?a")))]
+  "TARGET_INSNS_64"
+  "%|%.\\tmax2\\t%$\\t%1, %2, %0"
+  [(set_attr "units64" "l")
+   (set_attr "units64p" "ls")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "smin<mode>3"
+  [(set (match_operand:SMINMAX 0 "register_operand" "=a,b,a,b")
+	(smin:SMINMAX (match_operand:SMINMAX 1 "register_operand" "a,b,a,b")
+		      (match_operand:SMINMAX 2 "register_operand" "a,b,?b,?a")))]
+  "TARGET_INSNS_64"
+  "%|%.\\tmin2\\t%$\\t%1, %2, %0"
+  [(set_attr "units64" "l")
+   (set_attr "units64p" "ls")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "umax<mode>3"
+  [(set (match_operand:UMINMAX 0 "register_operand" "=a,b,a,b")
+	(umax:UMINMAX (match_operand:UMINMAX 1 "register_operand" "a,b,a,b")
+		      (match_operand:UMINMAX 2 "register_operand" "a,b,?b,?a")))]
+  "TARGET_INSNS_64"
+  "%|%.\\tmaxu4\\t%$\\t%1, %2, %0"
+  [(set_attr "units" "l")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "umin<mode>3"
+  [(set (match_operand:UMINMAX 0 "register_operand" "=a,b,a,b")
+	(umin:UMINMAX (match_operand:UMINMAX 1 "register_operand" "a,b,a,b")
+		      (match_operand:UMINMAX 2 "register_operand" "a,b,?b,?a")))]
+  "TARGET_INSNS_64"
+  "%|%.\\tminu4\\t%$\\t%1, %2, %0"
+  [(set_attr "units" "l")
+   (set_attr "cross" "n,n,y,y")])
+
+;; Vector shifts
+
+(define_insn "<shift_code>v2hi3"
+  [(set (match_operand:V2HI 0 "register_operand" "=a,b,a,b")
+        (any_rshift:V2HI (match_operand:V2HI 1 "register_operand" "a,b,?b,?a")
+			 (match_operand:SI 2 "reg_or_ucst5_operand" "aIu5,bIu5,aIu5,bIu5")))]
+  "TARGET_INSNS_64"
+  "%|%.\\t<shift_insn>2\\t%$\\t%1, %2, %0"
+  [(set_attr "units" "s")
+   (set_attr "cross" "n,n,y,y")])
+
+;; See c6x-mult.md.in for avg2/avgu4
+
+;; Widening vector multiply and dot product.
+;; See c6x-mult.md.in for the define_insn patterns
+
+(define_expand "sdot_prodv2hi"
+  [(match_operand:SI 0 "register_operand" "")
+   (match_operand:V2HI 1 "register_operand" "")
+   (match_operand:V2HI 2 "register_operand" "")
+   (match_operand:SI 3 "register_operand" "")]
+  "TARGET_INSNS_64"
+{
+  rtx t = gen_reg_rtx (SImode);
+  emit_insn (gen_dotv2hi (t, operands[1], operands[2]));
+  emit_insn (gen_addsi3 (operands[0], operands[3], t));
+  DONE;
+})
+
+;; Unary vector operations
+
+(define_insn "ssabsv2hi2"
+  [(set (match_operand:V2HI 0 "register_operand" "=a, a, b, b")
+        (ss_abs:V2HI (match_operand:V2HI 1 "register_operand" "a,?b, b,?a")))]
+  "TARGET_INSNS_64"
+  "%|%.\\tabs2\\t%$\\t%1, %0"
+  [(set_attr "units" "l")
+   (set_attr "cross" "n,y,n,y")])
+
+;; Pack insns
+
+(define_insn "*packv2hi_insv"
+  [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+a,b,a,b,ab")
+			 (const_int 16)
+			 (const_int 16))
+	(match_operand:SI 1 "nonmemory_operand" "a,b,?b,?a,n"))]
+  "TARGET_INSNS_64"
+  "@
+   %|%.\\tpack2\\t%$\\t%1, %0, %0
+   %|%.\\tpack2\\t%$\\t%1, %0, %0
+   %|%.\\tpack2\\t%$\\t%1, %0, %0
+   %|%.\\tpack2\\t%$\\t%1, %0, %0
+   %|%.\\tmvklh\\t%$\\t%1, %0"
+  [(set_attr "units" "ls")
+   (set_attr "cross" "n,n,y,y,n")])
+
+(define_insn "movstricthi"
+  [(set (strict_low_part (match_operand:HI 0 "register_operand" "+a,b,a,b"))
+	(match_operand:HI 1 "register_operand" "a,b,?b,?a"))]
+  "TARGET_INSNS_64"
+  "%|%.\\tpackhl2\\t%$\\t%0, %1, %0"
+  [(set_attr "units" "ls")
+   (set_attr "cross" "n,n,y,y")])
+
+(include "c6x-mult.md")
+(include "sync.md")