invoke.texi (C6X Options): New section.
authorBernd Schmidt <bernds@codesourcery.com>
Fri, 15 Jul 2011 09:36:40 +0000 (09:36 +0000)
committerBernd Schmidt <bernds@gcc.gnu.org>
Fri, 15 Jul 2011 09:36:40 +0000 (09:36 +0000)
gcc/
* doc/invoke.texi (C6X Options): New section.
* doc/md.texi (TI C6X family): New section.
* config.gcc: Handle tic6x, in particular tic6x-*-elf and
tic6x-*-uclinux.
* longlong.h (add_ssaaaa, __umulsidi3, umul_ppmm,
count_leading_zeros, count_trailing_zeros, UMUL_TIME, UDIV_TIME):
Provide C6X definitions.
* config/c6x/c6x.md: New file.
* config/c6x/constraints.md: New file.
* config/c6x/predicates.md: New file.
* config/c6x/c6x-sched.md.in: New file.
* config/c6x/c6x-sched.md: New file.
* config/c6x/gensched.sh: New file.
* config/c6x/c6x-mult.md.in: New file.
* config/c6x/genmult.sh: New file.
* config/c6x/c6x-mult.md: New file.
* config/c6x/sync.md: New file.
* config/c6x/c6x-protos.h: New file.
* config/c6x/sfp-machine.h: New file.
* config/c6x/c6x.c: New file.
* config/c6x/c6x.h: New file.
* config/c6x/crti.s: New file.
* config/c6x/crtn.s: New file.
* config/c6x/lib1funcs.asm: New file.
* config/c6x/c6x-modes.def: New file.
* config/c6x/genopt.sh: New file.
* config/c6x/c6x.opt: New file.
* config/c6x/c6x-tables.opt: New file.
* config/c6x/c6x-opts.h: New file.
* config/c6x/c6x-isas.def: New file.
* config/c6x/elf.h: New file.
* config/c6x/elf-common.h: New file.
* config/c6x/uclinux-elf.h: New file.
* config/c6x/t-c6x: New file.
* config/c6x/t-c6x-elf: New file.
* config/c6x/t-c6x-uclinux: New file.
* config/c6x/t-c6x-softfp: New file.
* config/c6x/gtd.c: New file.
* config/c6x/gtf.c: New file.
* config/c6x/ltd.c: New file.
* config/c6x/ltf.c: New file.
* config/c6x/ged.c: New file.
* config/c6x/gef.c: New file.
* config/c6x/led.c: New file.
* config/c6x/lef.c: New file.
* config/c6x/eqd.c: New file.
* config/c6x/eqf.c: New file.
* config/c6x/libgcc-c6xeabi.ver: New file.

contrib/
* gcc_update: Add C6X generated files.
* contrib/config-list.mk: Add c6x-elf and c6x-uclinux.

libgcc/
* config.host: Handle tic6x-*-*.
* config/c6x/c6x-abi.h: New file.

From-SVN: r176308

56 files changed:
contrib/ChangeLog
contrib/config-list.mk
contrib/gcc_update
gcc/ChangeLog
gcc/config.gcc
gcc/config/c6x/c6x-isas.def [new file with mode: 0644]
gcc/config/c6x/c6x-modes.def [new file with mode: 0644]
gcc/config/c6x/c6x-mult.md [new file with mode: 0644]
gcc/config/c6x/c6x-mult.md.in [new file with mode: 0644]
gcc/config/c6x/c6x-opts.h [new file with mode: 0644]
gcc/config/c6x/c6x-protos.h [new file with mode: 0644]
gcc/config/c6x/c6x-sched.md [new file with mode: 0644]
gcc/config/c6x/c6x-sched.md.in [new file with mode: 0644]
gcc/config/c6x/c6x-tables.opt [new file with mode: 0644]
gcc/config/c6x/c6x.c [new file with mode: 0644]
gcc/config/c6x/c6x.h [new file with mode: 0644]
gcc/config/c6x/c6x.md [new file with mode: 0644]
gcc/config/c6x/c6x.opt [new file with mode: 0644]
gcc/config/c6x/c6x_intrinsics.h [new file with mode: 0644]
gcc/config/c6x/constraints.md [new file with mode: 0644]
gcc/config/c6x/crti.s [new file with mode: 0644]
gcc/config/c6x/crtn.s [new file with mode: 0644]
gcc/config/c6x/elf-common.h [new file with mode: 0644]
gcc/config/c6x/elf.h [new file with mode: 0644]
gcc/config/c6x/eqd.c [new file with mode: 0644]
gcc/config/c6x/eqf.c [new file with mode: 0644]
gcc/config/c6x/ged.c [new file with mode: 0644]
gcc/config/c6x/gef.c [new file with mode: 0644]
gcc/config/c6x/genmult.sh [new file with mode: 0644]
gcc/config/c6x/genopt.sh [new file with mode: 0644]
gcc/config/c6x/gensched.sh [new file with mode: 0644]
gcc/config/c6x/gtd.c [new file with mode: 0644]
gcc/config/c6x/gtf.c [new file with mode: 0644]
gcc/config/c6x/led.c [new file with mode: 0644]
gcc/config/c6x/lef.c [new file with mode: 0644]
gcc/config/c6x/lib1funcs.asm [new file with mode: 0644]
gcc/config/c6x/libgcc-c6xeabi.ver [new file with mode: 0644]
gcc/config/c6x/ltd.c [new file with mode: 0644]
gcc/config/c6x/ltf.c [new file with mode: 0644]
gcc/config/c6x/predicates.md [new file with mode: 0644]
gcc/config/c6x/sfp-machine.h [new file with mode: 0644]
gcc/config/c6x/sync.md [new file with mode: 0644]
gcc/config/c6x/t-c6x [new file with mode: 0644]
gcc/config/c6x/t-c6x-elf [new file with mode: 0644]
gcc/config/c6x/t-c6x-softfp [new file with mode: 0644]
gcc/config/c6x/t-c6x-uclinux [new file with mode: 0644]
gcc/config/c6x/uclinux-elf.h [new file with mode: 0644]
gcc/doc/contrib.texi
gcc/doc/extend.texi
gcc/doc/install.texi
gcc/doc/invoke.texi
gcc/doc/md.texi
gcc/longlong.h
libgcc/ChangeLog
libgcc/config.host
libgcc/config/c6x/c6x-abi.h [new file with mode: 0644]

index d0ecb0b700a4b4d9c2c8b2116b9f7a338b1e1155..a69f810f022eed59e0a52c59741b185091407f9a 100644 (file)
@@ -1,3 +1,8 @@
+2011-07-15  Bernd Schmidt  <bernds@codesourcery.com>
+
+       * gcc_update: Add C6X generated files.
+       * contrib/config-list.mk: Add c6x-elf and c6x-uclinux.
+
 2011-07-01  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
 
        * config-list.mk (LIST): Append OPT-enable-obsolete to
index 6f05d06be19d9844f32a75a15019b9121eb72077..b421ccca25fdf0af767eebc7ed356f48d9ac5f49 100644 (file)
@@ -18,7 +18,7 @@ LIST = alpha-linux-gnu alpha-freebsd6 alpha-netbsd alpha-openbsd \
   arm-linux-androideabi arm-uclinux_eabi arm-ecos-elf arm-eabi \
   arm-symbianelf arm-rtems arm-elf arm-wince-pe avr-rtems avr-elf \
   bfin-elf bfin-uclinux bfin-linux-uclibc bfin-rtems bfin-openbsd \
-  cris-elf cris-linux crisv32-elf crisv32-linux fido-elf \
+  c6x-elf c6x-uclinux cris-elf cris-linux crisv32-elf crisv32-linux fido-elf \
   fr30-elf frv-elf frv-linux h8300-elf h8300-rtems hppa-linux-gnu \
   hppa-linux-gnuOPT-enable-sjlj-exceptions=yes hppa64-linux-gnu \
   hppa2.0-hpux10.1 hppa64-hpux11.3 \
index 3eba6c61d8a7650561da746c9fb660a2a69981e2..c368936e51e02ce6452c7e391fcfbbf48febca14 100755 (executable)
@@ -82,6 +82,9 @@ gcc/fixinc/fixincl.x: gcc/fixinc/fixincl.tpl gcc/fixinc/inclhack.def
 gcc/config/arm/arm-tune.md: gcc/config/arm/arm-cores.def gcc/config/arm/gentune.sh
 gcc/config/arm/arm-tables.opt: gcc/config/arm/arm-arches.def gcc/config/arm/arm-cores.def gcc/config/arm/arm-fpus.def gcc/config/arm/genopt.sh
 gcc/config/avr/avr-tables.opt: gcc/config/avr/avr-mcus.def gcc/config/avr/genopt.sh
+gcc/config/c6x/c6x-tables.opt: gcc/config/c6x/c6x-isas.def gcc/config/c6x/genopt.sh
+gcc/config/c6x/c6x-sched.md: gcc/config/c6x/c6x-sched.md.in gcc/config/c6x/gensched.sh
+gcc/config/c6x/c6x-mult.md: gcc/config/c6x/c6x-mult.md.in gcc/config/c6x/genmult.sh
 gcc/config/m68k/m68k-tables.opt: gcc/config/m68k/m68k-devices.def gcc/config/m68k/m68k-isas.def gcc/config/m68k/m68k-microarchs.def gcc/config/m68k/genopt.sh
 gcc/config/mips/mips-tables.opt: gcc/config/mips/mips-cpus.def gcc/config/mips/genopt.sh
 gcc/config/rs6000/rs6000-tables.opt: gcc/config/rs6000/rs6000-cpus.def gcc/config/rs6000/genopt.sh
index 8a1bb94b5f2e5c84a1c1a20685ca5c0330f8a193..ec216832686ee31c2801f93dbeea5664d2fd81cb 100644 (file)
@@ -1,3 +1,54 @@
+2011-07-15  Bernd Schmidt  <bernds@codesourcery.com>
+
+       * doc/invoke.texi (C6X Options): New section.
+       * doc/md.texi (TI C6X family): New section.
+       * config.gcc: Handle tic6x, in particular tic6x-*-elf and
+       tic6x-*-uclinux.
+       * longlong.h (add_ssaaaa, __umulsidi3, umul_ppmm,
+       count_leading_zeros, count_trailing_zeros, UMUL_TIME, UDIV_TIME):
+       Provide C6X definitions.
+       * config/c6x/c6x.md: New file.
+       * config/c6x/constraints.md: New file.
+       * config/c6x/predicates.md: New file.
+       * config/c6x/c6x-sched.md.in: New file.
+       * config/c6x/c6x-sched.md: New file.
+       * config/c6x/gensched.sh: New file.
+       * config/c6x/c6x-mult.md.in: New file.
+       * config/c6x/genmult.sh: New file.
+       * config/c6x/c6x-mult.md: New file.
+       * config/c6x/sync.md: New file.
+       * config/c6x/c6x-protos.h: New file.
+       * config/c6x/sfp-machine.h: New file.
+       * config/c6x/c6x.c: New file.
+       * config/c6x/c6x.h: New file.
+       * config/c6x/crti.s: New file.
+       * config/c6x/crtn.s: New file.
+       * config/c6x/lib1funcs.asm: New file.
+       * config/c6x/c6x-modes.def: New file.
+       * config/c6x/genopt.sh: New file.
+       * config/c6x/c6x.opt: New file.
+       * config/c6x/c6x-tables.opt: New file.
+       * config/c6x/c6x-opts.h: New file.
+       * config/c6x/c6x-isas.def: New file.
+       * config/c6x/elf.h: New file.
+       * config/c6x/elf-common.h: New file.
+       * config/c6x/uclinux-elf.h: New file.
+       * config/c6x/t-c6x: New file.
+       * config/c6x/t-c6x-elf: New file.
+       * config/c6x/t-c6x-uclinux: New file.
+       * config/c6x/t-c6x-softfp: New file.
+       * config/c6x/gtd.c: New file.
+       * config/c6x/gtf.c: New file.
+       * config/c6x/ltd.c: New file.
+       * config/c6x/ltf.c: New file.
+       * config/c6x/ged.c: New file.
+       * config/c6x/gef.c: New file.
+       * config/c6x/led.c: New file.
+       * config/c6x/lef.c: New file.
+       * config/c6x/eqd.c: New file.
+       * config/c6x/eqf.c: New file.
+       * config/c6x/libgcc-c6xeabi.ver: New file.
+
 2011-07-14  Andrew Pinski  <pinskia@gmail.com>
 
        PR tree-opt/49309
index 2b9502ba9e7d0c3567e92fa2281f3317bd9c9b59..0ca4f788e9d6cce8c9710f1396ccf06eb4eaf6c9 100644 (file)
@@ -437,6 +437,11 @@ sh[123456789lbe]*-*-* | sh-*-*)
 v850*-*-*)
        cpu_type=v850
        ;;
+tic6x-*-*)
+       cpu_type=c6x
+       extra_headers="c6x_intrinsics.h"
+       extra_options="${extra_options} c6x/c6x-tables.opt"
+       ;;
 xtensa*-*-*)
        extra_options="${extra_options} fused-madd.opt"
        ;;
@@ -2561,7 +2566,24 @@ spu-*-elf*)
        c_target_objs="${c_target_objs} spu-c.o"
        cxx_target_objs="${cxx_target_objs} spu-c.o"
        ;;
-
+tic6x-*-elf)
+       tm_file="elfos.h ${tm_file} c6x/elf-common.h c6x/elf.h"
+       tm_file="${tm_file} dbxelf.h tm-dwarf2.h newlib-stdint.h"
+       libgcc_tm_file="${libgcc_tm_file} c6x/c6x-abi.h"
+       tmake_file="c6x/t-c6x c6x/t-c6x-elf"
+       tmake_file="${tmake_file} c6x/t-c6x-softfp soft-fp/t-softfp"
+       use_collect2=no
+       ;;
+tic6x-*-uclinux)
+       tm_file="elfos.h ${tm_file} gnu-user.h linux.h c6x/elf-common.h c6x/uclinux-elf.h"
+       tm_file="${tm_file} dbxelf.h tm-dwarf2.h glibc-stdint.h"
+       tm_file="${tm_file} ./sysroot-suffix.h"
+       libgcc_tm_file="${libgcc_tm_file} c6x/c6x-abi.h"
+       tmake_file="t-slibgcc-elf-ver t-sysroot-suffix"
+       tmake_file="${tmake_file} c6x/t-c6x c6x/t-c6x-elf c6x/t-c6x-uclinux"
+       tmake_file="${tmake_file} c6x/t-c6x-softfp soft-fp/t-softfp"
+       use_collect2=no
+       ;;
 v850*-*-*)
        case ${target} in
        v850e2v3-*-*)
@@ -3500,6 +3522,20 @@ case "${target}" in
                done
                ;;
 
+       tic6x-*-*)
+               supported_defaults="arch"
+
+               case ${with_arch} in
+               "" | c62x | c64x | c64x+ | c67x | c67x+ | c674x)
+                       # OK
+                       ;;
+               *)
+                       echo "Unknown arch used in --with-arch=$with_arch." 1>&2
+                       exit 1
+                       ;;
+               esac
+               ;;
+
        v850*-*-*)
                supported_defaults=cpu
                case ${with_cpu} in
diff --git a/gcc/config/c6x/c6x-isas.def b/gcc/config/c6x/c6x-isas.def
new file mode 100644 (file)
index 0000000..8469763
--- /dev/null
@@ -0,0 +1,38 @@
+/* C6X ISA names.
+   Copyright (C) 2011
+   Free Software Foundation, Inc.
+
+   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/>.  */
+
+/* Define ISAs for the -march option, used both in C6X.c and to
+   generate c6x-tables.opt.  Before including this file, define a
+   macro:
+
+   C6X_ISA (NAME, ENUM_VALUE, FLAGS)
+
+   where NAME is the name for use with -march=, ENUM_VALUE is an enum
+   corresponding to this arch, and FLAGS is a combination of flags
+   that together specify the available instructions.  */
+
+C6X_ISA("c62x", C6X_CPU_C62X, C6X_INSNS_C62X)
+C6X_ISA("c64x", C6X_CPU_C64X, C6X_INSNS_C62X | C6X_INSNS_C64X)
+C6X_ISA("c64x+", C6X_CPU_C64XP, C6X_INSNS_C62X | C6X_INSNS_C64X | C6X_INSNS_C64XP)
+C6X_ISA("c67x", C6X_CPU_C67X, C6X_INSNS_C62X | C6X_INSNS_C67X)
+C6X_ISA("c67x+", C6X_CPU_C67XP, C6X_INSNS_C62X | C6X_INSNS_C67X | C6X_INSNS_C67XP)
+C6X_ISA("c674x", C6X_CPU_C674X,
+       (C6X_INSNS_C62X | C6X_INSNS_C64X | C6X_INSNS_C64XP | C6X_INSNS_C67X
+         | C6X_INSNS_C67XP | C6X_INSNS_C674X))
diff --git a/gcc/config/c6x/c6x-modes.def b/gcc/config/c6x/c6x-modes.def
new file mode 100644 (file)
index 0000000..a5af026
--- /dev/null
@@ -0,0 +1,24 @@
+/* Definitions of target machine for GNU compiler, for TI C6x.
+   Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+
+   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/>.  */
+
+VECTOR_MODES (INT, 4);        /*              V4QI V2HI */
+VECTOR_MODES (INT, 8);        /*         V8QI V4HI V2SI */
+
+VECTOR_MODE (FRACT, SQ, 2); /* V2SQ.  */
+VECTOR_MODE (FRACT, HQ, 2); /* V2HQ.  */
diff --git a/gcc/config/c6x/c6x-mult.md b/gcc/config/c6x/c6x-mult.md
new file mode 100644 (file)
index 0000000..ec18ba3
--- /dev/null
@@ -0,0 +1,840 @@
+;; -*- buffer-read-only: t -*-
+;; Generated automatically from c6x-mult.md.in by genmult.sh
+;; Multiplication patterns for TI C6X.
+;; This file is processed by genmult.sh to produce two variants of each
+;; pattern, a normal one and a real_mult variant for modulo scheduling.
+;; Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+;; 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/>.
+
+;; -------------------------------------------------------------------------
+;; Miscellaneous insns that execute on the M units
+;; -------------------------------------------------------------------------
+
+(define_insn "rotlsi3"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+        (rotate:SI (match_operand:SI 1 "register_operand" "a,b,?b,?a")
+                  (match_operand:SI 2 "reg_or_ucst5_operand" "aIu5,bIu5,aIu5,bIu5")))]
+  "TARGET_INSNS_64"
+  "%|%.\\trotl\\t%$\\t%1, %2, %0"
+  [(set_attr "units" "m")
+   (set_attr "type" "mpy2")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "bitrevsi2"
+  [(set (match_operand:SI 0 "register_operand" "=a,a,b,b")
+       (unspec:SI [(match_operand:SI 1 "register_operand" "a,?b,b,?a")]
+                  UNSPEC_BITREV))]
+  "TARGET_INSNS_64"
+  "%|%.\\tbitr\\t%$\\t%1, %0"
+  [(set_attr "units" "m")
+   (set_attr "type" "mpy2")
+   (set_attr "cross" "n,y,n,y")])
+
+;; Vector average.
+
+(define_insn "avgv2hi3"
+  [(set (match_operand:V2HI 0 "register_operand" "=a,b,a,b")
+        (unspec:V2HI [(match_operand:V2HI 1 "register_operand" "a,b,?b,?a")
+                     (match_operand:V2HI 2 "register_operand" "a,b,a,b")] UNSPEC_AVG))]
+  "TARGET_INSNS_64"
+  "%|%.\\tavg2\\t%$\\t%1, %2, %0"
+  [(set_attr "units" "m")
+   (set_attr "type" "mpy2")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "uavgv4qi3"
+  [(set (match_operand:V4QI 0 "register_operand" "=a,b,a,b")
+        (unspec:V4QI [(match_operand:V4QI 1 "register_operand" "a,b,?b,?a")
+                     (match_operand:V4QI 2 "register_operand" "a,b,a,b")] UNSPEC_AVG))]
+  "TARGET_INSNS_64"
+  "%|%.\\tavgu4\\t%$\\t%1, %2, %0"
+  [(set_attr "units" "m")
+   (set_attr "type" "mpy2")
+   (set_attr "cross" "n,n,y,y")])
+
+;; -------------------------------------------------------------------------
+;; Multiplication
+;; -------------------------------------------------------------------------
+
+(define_insn "mulhi3"
+  [(set (match_operand:HI 0 "register_operand" "=a,b,a,b")
+        (mult:HI (match_operand:HI 1 "register_operand" "a,b,?b,?a")
+                 (match_operand:HI 2 "reg_or_scst5_operand" "aIs5,bIs5,aIs5,bIs5")))]
+  ""
+  "%|%.\\tmpy\\t%$\\t%2, %1, %0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulhisi3_const"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,ab")
+        (mult:SI (sign_extend:SI
+                 (match_operand:HI 1 "register_operand" "a,b,?ab"))
+                 (match_operand:HI 2 "scst5_operand" "Is5,Is5,Is5")))]
+  ""
+  "%|%.\\tmpy\\t%$\\t%2, %1, %0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y")])
+
+(define_insn "*mulhisi3_insn"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+        (mult:SI (sign_extend:SI
+                 (match_operand:HI 1 "register_operand" "%a,b,?a,?b"))
+                 (sign_extend:SI
+                 (match_operand:HI 2 "reg_or_scst5_operand" "a,b,b,a"))))]
+  ""
+  "%|%.\\tmpy\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulhisi3_lh"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+        (mult:SI (sign_extend:SI
+                 (match_operand:HI 1 "register_operand" "a,b,?a,?b"))
+                 (ashiftrt:SI
+                 (match_operand:SI 2 "register_operand" "a,b,b,a")
+                 (const_int 16))))]
+  ""
+  "%|%.\\tmpylh\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulhisi3_hl"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+        (mult:SI (ashiftrt:SI
+                 (match_operand:SI 1 "register_operand" "a,b,?a,?b")
+                 (const_int 16))
+                 (sign_extend:SI
+                 (match_operand:HI 2 "register_operand" "a,b,b,a"))))]
+  ""
+  "%|%.\\tmpyhl\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulhisi3_hh"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+        (mult:SI (ashiftrt:SI
+                 (match_operand:SI 1 "register_operand" "%a,b,?a,?b")
+                 (const_int 16))
+                 (ashiftrt:SI
+                 (match_operand:SI 2 "register_operand" "a,b,b,a")
+                 (const_int 16))))]
+  ""
+  "%|%.\\tmpyh\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "umulhisi3"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+        (mult:SI (zero_extend:SI
+                 (match_operand:HI 1 "register_operand" "%a,b,?a,?b"))
+                 (zero_extend:SI
+                 (match_operand:HI 2 "register_operand" "a,b,b,a"))))]
+  ""
+  "%|%.\\tmpyu\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "umulhisi3_lh"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+        (mult:SI (zero_extend:SI
+                 (match_operand:HI 1 "register_operand" "a,b,?a,?b"))
+                 (lshiftrt:SI
+                 (match_operand:SI 2 "register_operand" "a,b,b,a")
+                 (const_int 16))))]
+  ""
+  "%|%.\\tmpylhu\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "umulhisi3_hl"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+        (mult:SI (lshiftrt:SI
+                 (match_operand:SI 1 "register_operand" "a,b,?a,?b")
+                 (const_int 16))
+                 (zero_extend:SI
+                 (match_operand:HI 2 "register_operand" "a,b,b,a"))))]
+  ""
+  "%|%.\\tmpyhlu\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "umulhisi3_hh"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+        (mult:SI (lshiftrt:SI
+                 (match_operand:SI 1 "register_operand" "%a,b,?a,?b")
+                 (const_int 16))
+                 (lshiftrt:SI
+                 (match_operand:SI 2 "register_operand" "a,b,b,a")
+                 (const_int 16))))]
+  ""
+  "%|%.\\tmpyhu\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "usmulhisi3_const"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,ab")
+        (mult:SI (zero_extend:SI
+                 (match_operand:HI 1 "register_operand" "a,b,?ab"))
+                 (match_operand:SI 2 "scst5_operand" "Is5,Is5,Is5")))]
+  ""
+  "%|%.\\tmpysu\\t%$\\t%2, %1, %0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y")])
+
+(define_insn "*usmulhisi3_insn"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+        (mult:SI (zero_extend:SI
+                 (match_operand:HI 1 "register_operand" "a,b,?a,?b"))
+                 (sign_extend:SI
+                 (match_operand:HI 2 "reg_or_scst5_operand" "aIs5,bIs5,bIs5,aIs5"))))]
+  ""
+  "%|%.\\tmpyus\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "usmulhisi3_lh"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+       (mult:SI (zero_extend:SI
+                 (match_operand:HI 1 "register_operand" "a,b,?a,?b"))
+                 (ashiftrt:SI
+                 (match_operand:SI 2 "register_operand" "a,b,b,a")
+                 (const_int 16))))]
+  ""
+  "%|%.\\tmpyluhs\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "usmulhisi3_hl"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+        (mult:SI (lshiftrt:SI
+                 (match_operand:SI 1 "register_operand" "a,b,?a,?b")
+                 (const_int 16))
+                 (sign_extend:SI
+                 (match_operand:HI 2 "register_operand" "a,b,b,a"))))]
+  ""
+  "%|%.\\tmpyhuls\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "usmulhisi3_hh"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+        (mult:SI (lshiftrt:SI
+                 (match_operand:SI 1 "register_operand" "a,b,?a,?b")
+                 (const_int 16))
+                 (ashiftrt:SI
+                 (match_operand:SI 2 "register_operand" "a,b,b,a")
+                 (const_int 16))))]
+  ""
+  "%|%.\\tmpyhus\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulsi3_insn"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+       (mult:SI (match_operand:SI 1 "register_operand" "%a,b,?a,?b")
+                (match_operand:SI 2 "register_operand" "a,b,b,a")))]
+  "TARGET_MPY32"
+  "%|%.\\tmpy32\\t%$\\t%1, %2, %0"
+ [(set_attr "type" "mpy4")
+  (set_attr "units" "m")
+  (set_attr "cross" "n,n,y,y")])
+
+(define_insn "<u>mulsidi3"
+  [(set (match_operand:DI 0 "register_operand" "=a,b,a,b")
+        (mult:DI (any_ext:DI
+                 (match_operand:SI 1 "register_operand" "%a,b,?a,?b"))
+                 (any_ext:DI
+                 (match_operand:SI 2 "register_operand" "a,b,b,a"))))]
+  "TARGET_MPY32"
+  "%|%.\\tmpy32<u>\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "mpy4")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "usmulsidi3"
+  [(set (match_operand:DI 0 "register_operand" "=a,b,a,b")
+        (mult:DI (zero_extend:DI
+                 (match_operand:SI 1 "register_operand" "a,b,?a,?b"))
+                 (sign_extend:DI
+                 (match_operand:SI 2 "register_operand" "a,b,b,a"))))]
+  "TARGET_MPY32"
+  "%|%.\\tmpy32us\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "mpy4")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+;; Widening vector multiply and dot product
+
+(define_insn "mulv2hiv2si3"
+  [(set (match_operand:V2SI 0 "register_operand" "=a,b,a,b")
+       (mult:V2SI
+        (sign_extend:V2SI (match_operand:V2HI 1 "register_operand" "a,b,a,b"))
+        (sign_extend:V2SI (match_operand:V2HI 2 "register_operand" "a,b,?b,?a"))))]
+  "TARGET_INSNS_64"
+  "%|%.\\tmpy2\\t%$\\t%1, %2, %0"
+ [(set_attr "type" "mpy4")
+  (set_attr "units" "m")
+  (set_attr "cross" "n,n,y,y")])
+
+(define_insn "umulv4qiv4hi3"
+  [(set (match_operand:V4HI 0 "register_operand" "=a,b,a,b")
+       (mult:V4HI
+        (zero_extend:V4HI (match_operand:V4QI 1 "register_operand" "a,b,a,b"))
+        (zero_extend:V4HI (match_operand:V4QI 2 "register_operand" "a,b,?b,?a"))))]
+  "TARGET_INSNS_64"
+  "%|%.\\tmpyu4\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "mpy4")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "usmulv4qiv4hi3"
+  [(set (match_operand:V4HI 0 "register_operand" "=a,b,a,b")
+       (mult:V4HI
+        (zero_extend:V4HI (match_operand:V4QI 1 "register_operand" "a,b,?b,?a"))
+        (sign_extend:V4HI (match_operand:V4QI 2 "register_operand" "a,b,a,b"))))]
+  "TARGET_INSNS_64"
+  "%|%.\\tmpyus4\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "mpy4")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "dotv2hi"
+  [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+       (plus:SI
+         (mult:SI
+           (sign_extend:SI
+             (vec_select:HI
+               (match_operand:V2HI 1 "register_operand" "a,b,a,b")
+               (parallel [(const_int 0)])))
+           (sign_extend:SI
+             (vec_select:HI
+               (match_operand:V2HI 2 "register_operand" "a,b,?b,?a")
+               (parallel [(const_int 0)]))))
+         (mult:SI
+           (sign_extend:SI
+             (vec_select:HI (match_dup 1) (parallel [(const_int 1)])))
+           (sign_extend:SI
+             (vec_select:HI (match_dup 2) (parallel [(const_int 1)]))))))]
+  "TARGET_INSNS_64"
+  "%|%.\\tdotp2\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "mpy4")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+;; Fractional multiply
+
+(define_insn "mulv2hqv2sq3"
+  [(set (match_operand:V2SQ 0 "register_operand" "=a,b,a,b")
+        (ss_mult:V2SQ
+        (fract_convert:V2SQ
+         (match_operand:V2HQ 1 "register_operand" "%a,b,?a,?b"))
+        (fract_convert:V2SQ
+         (match_operand:V2HQ 2 "register_operand" "a,b,b,a"))))]
+  ""
+  "%|%.\\tsmpy2\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "mpy4")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulhqsq3"
+  [(set (match_operand:SQ 0 "register_operand" "=a,b,a,b")
+        (ss_mult:SQ
+        (fract_convert:SQ
+         (match_operand:HQ 1 "register_operand" "%a,b,?a,?b"))
+        (fract_convert:SQ
+         (match_operand:HQ 2 "register_operand" "a,b,b,a"))))]
+  ""
+  "%|%.\\tsmpy\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulhqsq3_lh"
+  [(set (match_operand:SQ 0 "register_operand" "=a,b,a,b")
+        (ss_mult:SQ
+        (fract_convert:SQ
+         (match_operand:HQ 1 "register_operand" "a,b,?a,?b"))
+        (fract_convert:SQ
+         (truncate:HQ (match_operand:SQ 2 "register_operand" "a,b,b,a")))))]
+  ""
+  "%|%.\\tsmpylh\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulhqsq3_hl"
+  [(set (match_operand:SQ 0 "register_operand" "=a,b,a,b")
+        (ss_mult:SQ
+        (fract_convert:SQ
+         (truncate:HQ (match_operand:SQ 1 "register_operand" "a,b,b,a")))
+        (fract_convert:SQ
+         (match_operand:HQ 2 "register_operand" "a,b,b,a"))))]
+  ""
+  "%|%.\\tsmpyhl\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulhqsq3_hh"
+  [(set (match_operand:SQ 0 "register_operand" "=a,b,a,b")
+        (ss_mult:SQ
+        (fract_convert:SQ
+         (truncate:HQ (match_operand:SQ 1 "register_operand" "a,b,b,a")))
+        (fract_convert:SQ
+         (truncate:HQ (match_operand:SQ 2 "register_operand" "a,b,b,a")))))]
+  ""
+  "%|%.\\tsmpyh\\t%$\\t%1, %2, %0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+;; Multiplication patterns for TI C6X.
+;; This file is processed by genmult.sh to produce two variants of each
+;; pattern, a normal one and a real_mult variant for modulo scheduling.
+;; Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+;; 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/>.
+
+;; -------------------------------------------------------------------------
+;; Miscellaneous insns that execute on the M units
+;; -------------------------------------------------------------------------
+
+(define_insn "rotlsi3_real"
+  [(unspec [(match_operand:SI 0 "const_int_operand" "=JA,JB,JA,JB")
+        (rotate:SI (match_operand:SI 1 "register_operand" "a,b,?b,?a")
+                  (match_operand:SI 2 "reg_or_ucst5_operand" "aIu5,bIu5,aIu5,bIu5"))] UNSPEC_REAL_MULT)]
+  "TARGET_INSNS_64"
+  "%|%.\\trotl\\t%$\\t%1, %2, %k0"
+  [(set_attr "units" "m")
+   (set_attr "type" "mpy2")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "bitrevsi2_real"
+  [(unspec [(match_operand:SI 0 "const_int_operand" "=JA,JA,JB,JB")
+       (unspec:SI [(match_operand:SI 1 "register_operand" "a,?b,b,?a")]
+                  UNSPEC_BITREV)] UNSPEC_REAL_MULT)]
+  "TARGET_INSNS_64"
+  "%|%.\\tbitr\\t%$\\t%1, %k0"
+  [(set_attr "units" "m")
+   (set_attr "type" "mpy2")
+   (set_attr "cross" "n,y,n,y")])
+
+;; Vector average.
+
+(define_insn "avgv2hi3_real"
+  [(unspec [(match_operand:SI 0 "const_int_operand" "=JA,JB,JA,JB")
+        (unspec:V2HI [(match_operand:V2HI 1 "register_operand" "a,b,?b,?a")
+                     (match_operand:V2HI 2 "register_operand" "a,b,a,b")] UNSPEC_AVG)] UNSPEC_REAL_MULT)]
+  "TARGET_INSNS_64"
+  "%|%.\\tavg2\\t%$\\t%1, %2, %k0"
+  [(set_attr "units" "m")
+   (set_attr "type" "mpy2")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "uavgv4qi3_real"
+  [(unspec [(match_operand:SI 0 "const_int_operand" "=JA,JB,JA,JB")
+        (unspec:V4QI [(match_operand:V4QI 1 "register_operand" "a,b,?b,?a")
+                     (match_operand:V4QI 2 "register_operand" "a,b,a,b")] UNSPEC_AVG)] UNSPEC_REAL_MULT)]
+  "TARGET_INSNS_64"
+  "%|%.\\tavgu4\\t%$\\t%1, %2, %k0"
+  [(set_attr "units" "m")
+   (set_attr "type" "mpy2")
+   (set_attr "cross" "n,n,y,y")])
+
+;; -------------------------------------------------------------------------
+;; Multiplication
+;; -------------------------------------------------------------------------
+
+(define_insn "mulhi3_real"
+  [(unspec [(match_operand:HI 0 "const_int_operand" "=JA,JB,JA,JB")
+        (mult:HI (match_operand:HI 1 "register_operand" "a,b,?b,?a")
+                 (match_operand:HI 2 "reg_or_scst5_operand" "aIs5,bIs5,aIs5,bIs5"))] UNSPEC_REAL_MULT)]
+  ""
+  "%|%.\\tmpy\\t%$\\t%2, %1, %k0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulhisi3_const_real"
+  [(unspec [(match_operand:SI 0 "const_int_operand" "=JA,JB,JAJB")
+        (mult:SI (sign_extend:SI
+                 (match_operand:HI 1 "register_operand" "a,b,?ab"))
+                 (match_operand:HI 2 "scst5_operand" "Is5,Is5,Is5"))] UNSPEC_REAL_MULT)]
+  ""
+  "%|%.\\tmpy\\t%$\\t%2, %1, %k0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y")])
+
+(define_insn "*mulhisi3_insn_real"
+  [(unspec [(match_operand:SI 0 "const_int_operand" "=JA,JB,JA,JB")
+        (mult:SI (sign_extend:SI
+                 (match_operand:HI 1 "register_operand" "%a,b,?a,?b"))
+                 (sign_extend:SI
+                 (match_operand:HI 2 "reg_or_scst5_operand" "a,b,b,a")))] UNSPEC_REAL_MULT)]
+  ""
+  "%|%.\\tmpy\\t%$\\t%1, %2, %k0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulhisi3_lh_real"
+  [(unspec [(match_operand:SI 0 "const_int_operand" "=JA,JB,JA,JB")
+        (mult:SI (sign_extend:SI
+                 (match_operand:HI 1 "register_operand" "a,b,?a,?b"))
+                 (ashiftrt:SI
+                 (match_operand:SI 2 "register_operand" "a,b,b,a")
+                 (const_int 16)))] UNSPEC_REAL_MULT)]
+  ""
+  "%|%.\\tmpylh\\t%$\\t%1, %2, %k0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulhisi3_hl_real"
+  [(unspec [(match_operand:SI 0 "const_int_operand" "=JA,JB,JA,JB")
+        (mult:SI (ashiftrt:SI
+                 (match_operand:SI 1 "register_operand" "a,b,?a,?b")
+                 (const_int 16))
+                 (sign_extend:SI
+                 (match_operand:HI 2 "register_operand" "a,b,b,a")))] UNSPEC_REAL_MULT)]
+  ""
+  "%|%.\\tmpyhl\\t%$\\t%1, %2, %k0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulhisi3_hh_real"
+  [(unspec [(match_operand:SI 0 "const_int_operand" "=JA,JB,JA,JB")
+        (mult:SI (ashiftrt:SI
+                 (match_operand:SI 1 "register_operand" "%a,b,?a,?b")
+                 (const_int 16))
+                 (ashiftrt:SI
+                 (match_operand:SI 2 "register_operand" "a,b,b,a")
+                 (const_int 16)))] UNSPEC_REAL_MULT)]
+  ""
+  "%|%.\\tmpyh\\t%$\\t%1, %2, %k0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "umulhisi3_real"
+  [(unspec [(match_operand:SI 0 "const_int_operand" "=JA,JB,JA,JB")
+        (mult:SI (zero_extend:SI
+                 (match_operand:HI 1 "register_operand" "%a,b,?a,?b"))
+                 (zero_extend:SI
+                 (match_operand:HI 2 "register_operand" "a,b,b,a")))] UNSPEC_REAL_MULT)]
+  ""
+  "%|%.\\tmpyu\\t%$\\t%1, %2, %k0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "umulhisi3_lh_real"
+  [(unspec [(match_operand:SI 0 "const_int_operand" "=JA,JB,JA,JB")
+        (mult:SI (zero_extend:SI
+                 (match_operand:HI 1 "register_operand" "a,b,?a,?b"))
+                 (lshiftrt:SI
+                 (match_operand:SI 2 "register_operand" "a,b,b,a")
+                 (const_int 16)))] UNSPEC_REAL_MULT)]
+  ""
+  "%|%.\\tmpylhu\\t%$\\t%1, %2, %k0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "umulhisi3_hl_real"
+  [(unspec [(match_operand:SI 0 "const_int_operand" "=JA,JB,JA,JB")
+        (mult:SI (lshiftrt:SI
+                 (match_operand:SI 1 "register_operand" "a,b,?a,?b")
+                 (const_int 16))
+                 (zero_extend:SI
+                 (match_operand:HI 2 "register_operand" "a,b,b,a")))] UNSPEC_REAL_MULT)]
+  ""
+  "%|%.\\tmpyhlu\\t%$\\t%1, %2, %k0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "umulhisi3_hh_real"
+  [(unspec [(match_operand:SI 0 "const_int_operand" "=JA,JB,JA,JB")
+        (mult:SI (lshiftrt:SI
+                 (match_operand:SI 1 "register_operand" "%a,b,?a,?b")
+                 (const_int 16))
+                 (lshiftrt:SI
+                 (match_operand:SI 2 "register_operand" "a,b,b,a")
+                 (const_int 16)))] UNSPEC_REAL_MULT)]
+  ""
+  "%|%.\\tmpyhu\\t%$\\t%1, %2, %k0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "usmulhisi3_const_real"
+  [(unspec [(match_operand:SI 0 "const_int_operand" "=JA,JB,JAJB")
+        (mult:SI (zero_extend:SI
+                 (match_operand:HI 1 "register_operand" "a,b,?ab"))
+                 (match_operand:SI 2 "scst5_operand" "Is5,Is5,Is5"))] UNSPEC_REAL_MULT)]
+  ""
+  "%|%.\\tmpysu\\t%$\\t%2, %1, %k0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y")])
+
+(define_insn "*usmulhisi3_insn_real"
+  [(unspec [(match_operand:SI 0 "const_int_operand" "=JA,JB,JA,JB")
+        (mult:SI (zero_extend:SI
+                 (match_operand:HI 1 "register_operand" "a,b,?a,?b"))
+                 (sign_extend:SI
+                 (match_operand:HI 2 "reg_or_scst5_operand" "aIs5,bIs5,bIs5,aIs5")))] UNSPEC_REAL_MULT)]
+  ""
+  "%|%.\\tmpyus\\t%$\\t%1, %2, %k0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "usmulhisi3_lh_real"
+  [(unspec [(match_operand:SI 0 "const_int_operand" "=JA,JB,JA,JB")
+       (mult:SI (zero_extend:SI
+                 (match_operand:HI 1 "register_operand" "a,b,?a,?b"))
+                 (ashiftrt:SI
+                 (match_operand:SI 2 "register_operand" "a,b,b,a")
+                 (const_int 16)))] UNSPEC_REAL_MULT)]
+  ""
+  "%|%.\\tmpyluhs\\t%$\\t%1, %2, %k0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "usmulhisi3_hl_real"
+  [(unspec [(match_operand:SI 0 "const_int_operand" "=JA,JB,JA,JB")
+        (mult:SI (lshiftrt:SI
+                 (match_operand:SI 1 "register_operand" "a,b,?a,?b")
+                 (const_int 16))
+                 (sign_extend:SI
+                 (match_operand:HI 2 "register_operand" "a,b,b,a")))] UNSPEC_REAL_MULT)]
+  ""
+  "%|%.\\tmpyhuls\\t%$\\t%1, %2, %k0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "usmulhisi3_hh_real"
+  [(unspec [(match_operand:SI 0 "const_int_operand" "=JA,JB,JA,JB")
+        (mult:SI (lshiftrt:SI
+                 (match_operand:SI 1 "register_operand" "a,b,?a,?b")
+                 (const_int 16))
+                 (ashiftrt:SI
+                 (match_operand:SI 2 "register_operand" "a,b,b,a")
+                 (const_int 16)))] UNSPEC_REAL_MULT)]
+  ""
+  "%|%.\\tmpyhus\\t%$\\t%1, %2, %k0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulsi3_insn_real"
+  [(unspec [(match_operand:SI 0 "const_int_operand" "=JA,JB,JA,JB")
+       (mult:SI (match_operand:SI 1 "register_operand" "%a,b,?a,?b")
+                (match_operand:SI 2 "register_operand" "a,b,b,a"))] UNSPEC_REAL_MULT)]
+  "TARGET_MPY32"
+  "%|%.\\tmpy32\\t%$\\t%1, %2, %k0"
+ [(set_attr "type" "mpy4")
+  (set_attr "units" "m")
+  (set_attr "cross" "n,n,y,y")])
+
+(define_insn "<u>mulsidi3_real"
+  [(unspec [(match_operand:DI 0 "const_int_operand" "=JA,JB,JA,JB")
+        (mult:DI (any_ext:DI
+                 (match_operand:SI 1 "register_operand" "%a,b,?a,?b"))
+                 (any_ext:DI
+                 (match_operand:SI 2 "register_operand" "a,b,b,a")))] UNSPEC_REAL_MULT)]
+  "TARGET_MPY32"
+  "%|%.\\tmpy32<u>\\t%$\\t%1, %2, %K0"
+  [(set_attr "type" "mpy4")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "usmulsidi3_real"
+  [(unspec [(match_operand:DI 0 "const_int_operand" "=JA,JB,JA,JB")
+        (mult:DI (zero_extend:DI
+                 (match_operand:SI 1 "register_operand" "a,b,?a,?b"))
+                 (sign_extend:DI
+                 (match_operand:SI 2 "register_operand" "a,b,b,a")))] UNSPEC_REAL_MULT)]
+  "TARGET_MPY32"
+  "%|%.\\tmpy32us\\t%$\\t%1, %2, %K0"
+  [(set_attr "type" "mpy4")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+;; Widening vector multiply and dot product
+
+(define_insn "mulv2hiv2si3_real"
+  [(unspec [(match_operand:V2SI 0 "const_int_operand" "=JA,JB,JA,JB")
+       (mult:V2SI
+        (sign_extend:V2SI (match_operand:V2HI 1 "register_operand" "a,b,a,b"))
+        (sign_extend:V2SI (match_operand:V2HI 2 "register_operand" "a,b,?b,?a")))] UNSPEC_REAL_MULT)]
+  "TARGET_INSNS_64"
+  "%|%.\\tmpy2\\t%$\\t%1, %2, %k0"
+ [(set_attr "type" "mpy4")
+  (set_attr "units" "m")
+  (set_attr "cross" "n,n,y,y")])
+
+(define_insn "umulv4qiv4hi3_real"
+  [(unspec [(match_operand:V4HI 0 "const_int_operand" "=JA,JB,JA,JB")
+       (mult:V4HI
+        (zero_extend:V4HI (match_operand:V4QI 1 "register_operand" "a,b,a,b"))
+        (zero_extend:V4HI (match_operand:V4QI 2 "register_operand" "a,b,?b,?a")))] UNSPEC_REAL_MULT)]
+  "TARGET_INSNS_64"
+  "%|%.\\tmpyu4\\t%$\\t%1, %2, %k0"
+  [(set_attr "type" "mpy4")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "usmulv4qiv4hi3_real"
+  [(unspec [(match_operand:V4HI 0 "const_int_operand" "=JA,JB,JA,JB")
+       (mult:V4HI
+        (zero_extend:V4HI (match_operand:V4QI 1 "register_operand" "a,b,?b,?a"))
+        (sign_extend:V4HI (match_operand:V4QI 2 "register_operand" "a,b,a,b")))] UNSPEC_REAL_MULT)]
+  "TARGET_INSNS_64"
+  "%|%.\\tmpyus4\\t%$\\t%1, %2, %k0"
+  [(set_attr "type" "mpy4")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "dotv2hi_real"
+  [(unspec [(match_operand:SI 0 "const_int_operand" "=JA,JB,JA,JB")
+       (plus:SI
+         (mult:SI
+           (sign_extend:SI
+             (vec_select:HI
+               (match_operand:V2HI 1 "register_operand" "a,b,a,b")
+               (parallel [(const_int 0)])))
+           (sign_extend:SI
+             (vec_select:HI
+               (match_operand:V2HI 2 "register_operand" "a,b,?b,?a")
+               (parallel [(const_int 0)]))))
+         (mult:SI
+           (sign_extend:SI
+             (vec_select:HI (match_dup 1) (parallel [(const_int 1)])))
+           (sign_extend:SI
+             (vec_select:HI (match_dup 2) (parallel [(const_int 1)])))))] UNSPEC_REAL_MULT)]
+  "TARGET_INSNS_64"
+  "%|%.\\tdotp2\\t%$\\t%1, %2, %k0"
+  [(set_attr "type" "mpy4")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+;; Fractional multiply
+
+(define_insn "mulv2hqv2sq3_real"
+  [(unspec [(match_operand:SI 0 "const_int_operand" "=JA,JB,JA,JB")
+        (ss_mult:V2SQ
+        (fract_convert:V2SQ
+         (match_operand:V2HQ 1 "register_operand" "%a,b,?a,?b"))
+        (fract_convert:V2SQ
+         (match_operand:V2HQ 2 "register_operand" "a,b,b,a")))] UNSPEC_REAL_MULT)]
+  ""
+  "%|%.\\tsmpy2\\t%$\\t%1, %2, %k0"
+  [(set_attr "type" "mpy4")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulhqsq3_real"
+  [(unspec [(match_operand:SI 0 "const_int_operand" "=JA,JB,JA,JB")
+        (ss_mult:SQ
+        (fract_convert:SQ
+         (match_operand:HQ 1 "register_operand" "%a,b,?a,?b"))
+        (fract_convert:SQ
+         (match_operand:HQ 2 "register_operand" "a,b,b,a")))] UNSPEC_REAL_MULT)]
+  ""
+  "%|%.\\tsmpy\\t%$\\t%1, %2, %k0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulhqsq3_lh_real"
+  [(unspec [(match_operand:SI 0 "const_int_operand" "=JA,JB,JA,JB")
+        (ss_mult:SQ
+        (fract_convert:SQ
+         (match_operand:HQ 1 "register_operand" "a,b,?a,?b"))
+        (fract_convert:SQ
+         (truncate:HQ (match_operand:SQ 2 "register_operand" "a,b,b,a"))))] UNSPEC_REAL_MULT)]
+  ""
+  "%|%.\\tsmpylh\\t%$\\t%1, %2, %k0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulhqsq3_hl_real"
+  [(unspec [(match_operand:SI 0 "const_int_operand" "=JA,JB,JA,JB")
+        (ss_mult:SQ
+        (fract_convert:SQ
+         (truncate:HQ (match_operand:SQ 1 "register_operand" "a,b,b,a")))
+        (fract_convert:SQ
+         (match_operand:HQ 2 "register_operand" "a,b,b,a")))] UNSPEC_REAL_MULT)]
+  ""
+  "%|%.\\tsmpyhl\\t%$\\t%1, %2, %k0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulhqsq3_hh_real"
+  [(unspec [(match_operand:SI 0 "const_int_operand" "=JA,JB,JA,JB")
+        (ss_mult:SQ
+        (fract_convert:SQ
+         (truncate:HQ (match_operand:SQ 1 "register_operand" "a,b,b,a")))
+        (fract_convert:SQ
+         (truncate:HQ (match_operand:SQ 2 "register_operand" "a,b,b,a"))))] UNSPEC_REAL_MULT)]
+  ""
+  "%|%.\\tsmpyh\\t%$\\t%1, %2, %k0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
diff --git a/gcc/config/c6x/c6x-mult.md.in b/gcc/config/c6x/c6x-mult.md.in
new file mode 100644 (file)
index 0000000..96de44f
--- /dev/null
@@ -0,0 +1,419 @@
+;; Multiplication patterns for TI C6X.
+;; This file is processed by genmult.sh to produce two variants of each
+;; pattern, a normal one and a real_mult variant for modulo scheduling.
+;; Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+;; 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/>.
+
+;; -------------------------------------------------------------------------
+;; Miscellaneous insns that execute on the M units
+;; -------------------------------------------------------------------------
+
+(define_insn "rotlsi3_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:SI 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+        (rotate:SI (match_operand:SI 1 "register_operand" "a,b,?b,?a")
+                  (match_operand:SI 2 "reg_or_ucst5_operand" "aIu5,bIu5,aIu5,bIu5"))_CBRK_)]
+  "TARGET_INSNS_64"
+  "%|%.\\trotl\\t%$\\t%1, %2, %_MODk_0"
+  [(set_attr "units" "m")
+   (set_attr "type" "mpy2")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "bitrevsi2_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:SI 0 "_DESTOPERAND_" "=_A_,_A_,_B_,_B_")
+       (unspec:SI [(match_operand:SI 1 "register_operand" "a,?b,b,?a")]
+                  UNSPEC_BITREV)_CBRK_)]
+  "TARGET_INSNS_64"
+  "%|%.\\tbitr\\t%$\\t%1, %_MODk_0"
+  [(set_attr "units" "m")
+   (set_attr "type" "mpy2")
+   (set_attr "cross" "n,y,n,y")])
+
+;; Vector average.
+
+(define_insn "avgv2hi3_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:_MV2HI 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+        (unspec:V2HI [(match_operand:V2HI 1 "register_operand" "a,b,?b,?a")
+                     (match_operand:V2HI 2 "register_operand" "a,b,a,b")] UNSPEC_AVG)_CBRK_)]
+  "TARGET_INSNS_64"
+  "%|%.\\tavg2\\t%$\\t%1, %2, %_MODk_0"
+  [(set_attr "units" "m")
+   (set_attr "type" "mpy2")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "uavgv4qi3_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:_MV4QI 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+        (unspec:V4QI [(match_operand:V4QI 1 "register_operand" "a,b,?b,?a")
+                     (match_operand:V4QI 2 "register_operand" "a,b,a,b")] UNSPEC_AVG)_CBRK_)]
+  "TARGET_INSNS_64"
+  "%|%.\\tavgu4\\t%$\\t%1, %2, %_MODk_0"
+  [(set_attr "units" "m")
+   (set_attr "type" "mpy2")
+   (set_attr "cross" "n,n,y,y")])
+
+;; -------------------------------------------------------------------------
+;; Multiplication
+;; -------------------------------------------------------------------------
+
+(define_insn "mulhi3_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:HI 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+        (mult:HI (match_operand:HI 1 "register_operand" "a,b,?b,?a")
+                 (match_operand:HI 2 "reg_or_scst5_operand" "aIs5,bIs5,aIs5,bIs5"))_CBRK_)]
+  ""
+  "%|%.\\tmpy\\t%$\\t%2, %1, %_MODk_0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulhisi3_const_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:SI 0 "_DESTOPERAND_" "=_A_,_B_,_A__B_")
+        (mult:SI (sign_extend:SI
+                 (match_operand:HI 1 "register_operand" "a,b,?ab"))
+                 (match_operand:HI 2 "scst5_operand" "Is5,Is5,Is5"))_CBRK_)]
+  ""
+  "%|%.\\tmpy\\t%$\\t%2, %1, %_MODk_0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y")])
+
+(define_insn "*mulhisi3_insn_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:SI 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+        (mult:SI (sign_extend:SI
+                 (match_operand:HI 1 "register_operand" "%a,b,?a,?b"))
+                 (sign_extend:SI
+                 (match_operand:HI 2 "reg_or_scst5_operand" "a,b,b,a")))_CBRK_)]
+  ""
+  "%|%.\\tmpy\\t%$\\t%1, %2, %_MODk_0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulhisi3_lh_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:SI 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+        (mult:SI (sign_extend:SI
+                 (match_operand:HI 1 "register_operand" "a,b,?a,?b"))
+                 (ashiftrt:SI
+                 (match_operand:SI 2 "register_operand" "a,b,b,a")
+                 (const_int 16)))_CBRK_)]
+  ""
+  "%|%.\\tmpylh\\t%$\\t%1, %2, %_MODk_0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulhisi3_hl_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:SI 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+        (mult:SI (ashiftrt:SI
+                 (match_operand:SI 1 "register_operand" "a,b,?a,?b")
+                 (const_int 16))
+                 (sign_extend:SI
+                 (match_operand:HI 2 "register_operand" "a,b,b,a")))_CBRK_)]
+  ""
+  "%|%.\\tmpyhl\\t%$\\t%1, %2, %_MODk_0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulhisi3_hh_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:SI 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+        (mult:SI (ashiftrt:SI
+                 (match_operand:SI 1 "register_operand" "%a,b,?a,?b")
+                 (const_int 16))
+                 (ashiftrt:SI
+                 (match_operand:SI 2 "register_operand" "a,b,b,a")
+                 (const_int 16)))_CBRK_)]
+  ""
+  "%|%.\\tmpyh\\t%$\\t%1, %2, %_MODk_0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "umulhisi3_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:SI 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+        (mult:SI (zero_extend:SI
+                 (match_operand:HI 1 "register_operand" "%a,b,?a,?b"))
+                 (zero_extend:SI
+                 (match_operand:HI 2 "register_operand" "a,b,b,a")))_CBRK_)]
+  ""
+  "%|%.\\tmpyu\\t%$\\t%1, %2, %_MODk_0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "umulhisi3_lh_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:SI 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+        (mult:SI (zero_extend:SI
+                 (match_operand:HI 1 "register_operand" "a,b,?a,?b"))
+                 (lshiftrt:SI
+                 (match_operand:SI 2 "register_operand" "a,b,b,a")
+                 (const_int 16)))_CBRK_)]
+  ""
+  "%|%.\\tmpylhu\\t%$\\t%1, %2, %_MODk_0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "umulhisi3_hl_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:SI 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+        (mult:SI (lshiftrt:SI
+                 (match_operand:SI 1 "register_operand" "a,b,?a,?b")
+                 (const_int 16))
+                 (zero_extend:SI
+                 (match_operand:HI 2 "register_operand" "a,b,b,a")))_CBRK_)]
+  ""
+  "%|%.\\tmpyhlu\\t%$\\t%1, %2, %_MODk_0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "umulhisi3_hh_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:SI 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+        (mult:SI (lshiftrt:SI
+                 (match_operand:SI 1 "register_operand" "%a,b,?a,?b")
+                 (const_int 16))
+                 (lshiftrt:SI
+                 (match_operand:SI 2 "register_operand" "a,b,b,a")
+                 (const_int 16)))_CBRK_)]
+  ""
+  "%|%.\\tmpyhu\\t%$\\t%1, %2, %_MODk_0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "usmulhisi3_const_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:SI 0 "_DESTOPERAND_" "=_A_,_B_,_A__B_")
+        (mult:SI (zero_extend:SI
+                 (match_operand:HI 1 "register_operand" "a,b,?ab"))
+                 (match_operand:SI 2 "scst5_operand" "Is5,Is5,Is5"))_CBRK_)]
+  ""
+  "%|%.\\tmpysu\\t%$\\t%2, %1, %_MODk_0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y")])
+
+(define_insn "*usmulhisi3_insn_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:SI 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+        (mult:SI (zero_extend:SI
+                 (match_operand:HI 1 "register_operand" "a,b,?a,?b"))
+                 (sign_extend:SI
+                 (match_operand:HI 2 "reg_or_scst5_operand" "aIs5,bIs5,bIs5,aIs5")))_CBRK_)]
+  ""
+  "%|%.\\tmpyus\\t%$\\t%1, %2, %_MODk_0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "usmulhisi3_lh_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:SI 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+       (mult:SI (zero_extend:SI
+                 (match_operand:HI 1 "register_operand" "a,b,?a,?b"))
+                 (ashiftrt:SI
+                 (match_operand:SI 2 "register_operand" "a,b,b,a")
+                 (const_int 16)))_CBRK_)]
+  ""
+  "%|%.\\tmpyluhs\\t%$\\t%1, %2, %_MODk_0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "usmulhisi3_hl_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:SI 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+        (mult:SI (lshiftrt:SI
+                 (match_operand:SI 1 "register_operand" "a,b,?a,?b")
+                 (const_int 16))
+                 (sign_extend:SI
+                 (match_operand:HI 2 "register_operand" "a,b,b,a")))_CBRK_)]
+  ""
+  "%|%.\\tmpyhuls\\t%$\\t%1, %2, %_MODk_0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "usmulhisi3_hh_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:SI 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+        (mult:SI (lshiftrt:SI
+                 (match_operand:SI 1 "register_operand" "a,b,?a,?b")
+                 (const_int 16))
+                 (ashiftrt:SI
+                 (match_operand:SI 2 "register_operand" "a,b,b,a")
+                 (const_int 16)))_CBRK_)]
+  ""
+  "%|%.\\tmpyhus\\t%$\\t%1, %2, %_MODk_0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulsi3_insn_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:SI 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+       (mult:SI (match_operand:SI 1 "register_operand" "%a,b,?a,?b")
+                (match_operand:SI 2 "register_operand" "a,b,b,a"))_CBRK_)]
+  "TARGET_MPY32"
+  "%|%.\\tmpy32\\t%$\\t%1, %2, %_MODk_0"
+ [(set_attr "type" "mpy4")
+  (set_attr "units" "m")
+  (set_attr "cross" "n,n,y,y")])
+
+(define_insn "<u>mulsidi3_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:DI 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+        (mult:DI (any_ext:DI
+                 (match_operand:SI 1 "register_operand" "%a,b,?a,?b"))
+                 (any_ext:DI
+                 (match_operand:SI 2 "register_operand" "a,b,b,a")))_CBRK_)]
+  "TARGET_MPY32"
+  "%|%.\\tmpy32<u>\\t%$\\t%1, %2, %_MODK_0"
+  [(set_attr "type" "mpy4")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "usmulsidi3_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:DI 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+        (mult:DI (zero_extend:DI
+                 (match_operand:SI 1 "register_operand" "a,b,?a,?b"))
+                 (sign_extend:DI
+                 (match_operand:SI 2 "register_operand" "a,b,b,a")))_CBRK_)]
+  "TARGET_MPY32"
+  "%|%.\\tmpy32us\\t%$\\t%1, %2, %_MODK_0"
+  [(set_attr "type" "mpy4")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+;; Widening vector multiply and dot product
+
+(define_insn "mulv2hiv2si3_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:V2SI 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+       (mult:V2SI
+        (sign_extend:V2SI (match_operand:V2HI 1 "register_operand" "a,b,a,b"))
+        (sign_extend:V2SI (match_operand:V2HI 2 "register_operand" "a,b,?b,?a")))_CBRK_)]
+  "TARGET_INSNS_64"
+  "%|%.\\tmpy2\\t%$\\t%1, %2, %_MODk_0"
+ [(set_attr "type" "mpy4")
+  (set_attr "units" "m")
+  (set_attr "cross" "n,n,y,y")])
+
+(define_insn "umulv4qiv4hi3_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:V4HI 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+       (mult:V4HI
+        (zero_extend:V4HI (match_operand:V4QI 1 "register_operand" "a,b,a,b"))
+        (zero_extend:V4HI (match_operand:V4QI 2 "register_operand" "a,b,?b,?a")))_CBRK_)]
+  "TARGET_INSNS_64"
+  "%|%.\\tmpyu4\\t%$\\t%1, %2, %_MODk_0"
+  [(set_attr "type" "mpy4")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "usmulv4qiv4hi3_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:V4HI 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+       (mult:V4HI
+        (zero_extend:V4HI (match_operand:V4QI 1 "register_operand" "a,b,?b,?a"))
+        (sign_extend:V4HI (match_operand:V4QI 2 "register_operand" "a,b,a,b")))_CBRK_)]
+  "TARGET_INSNS_64"
+  "%|%.\\tmpyus4\\t%$\\t%1, %2, %_MODk_0"
+  [(set_attr "type" "mpy4")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "dotv2hi_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:SI 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+       (plus:SI
+         (mult:SI
+           (sign_extend:SI
+             (vec_select:HI
+               (match_operand:V2HI 1 "register_operand" "a,b,a,b")
+               (parallel [(const_int 0)])))
+           (sign_extend:SI
+             (vec_select:HI
+               (match_operand:V2HI 2 "register_operand" "a,b,?b,?a")
+               (parallel [(const_int 0)]))))
+         (mult:SI
+           (sign_extend:SI
+             (vec_select:HI (match_dup 1) (parallel [(const_int 1)])))
+           (sign_extend:SI
+             (vec_select:HI (match_dup 2) (parallel [(const_int 1)])))))_CBRK_)]
+  "TARGET_INSNS_64"
+  "%|%.\\tdotp2\\t%$\\t%1, %2, %_MODk_0"
+  [(set_attr "type" "mpy4")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+;; Fractional multiply
+
+(define_insn "mulv2hqv2sq3_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:_MV2SQ 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+        (ss_mult:V2SQ
+        (fract_convert:V2SQ
+         (match_operand:V2HQ 1 "register_operand" "%a,b,?a,?b"))
+        (fract_convert:V2SQ
+         (match_operand:V2HQ 2 "register_operand" "a,b,b,a")))_CBRK_)]
+  ""
+  "%|%.\\tsmpy2\\t%$\\t%1, %2, %_MODk_0"
+  [(set_attr "type" "mpy4")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulhqsq3_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:_MSQ 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+        (ss_mult:SQ
+        (fract_convert:SQ
+         (match_operand:HQ 1 "register_operand" "%a,b,?a,?b"))
+        (fract_convert:SQ
+         (match_operand:HQ 2 "register_operand" "a,b,b,a")))_CBRK_)]
+  ""
+  "%|%.\\tsmpy\\t%$\\t%1, %2, %_MODk_0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulhqsq3_lh_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:_MSQ 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+        (ss_mult:SQ
+        (fract_convert:SQ
+         (match_operand:HQ 1 "register_operand" "a,b,?a,?b"))
+        (fract_convert:SQ
+         (truncate:HQ (match_operand:SQ 2 "register_operand" "a,b,b,a"))))_CBRK_)]
+  ""
+  "%|%.\\tsmpylh\\t%$\\t%1, %2, %_MODk_0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulhqsq3_hl_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:_MSQ 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+        (ss_mult:SQ
+        (fract_convert:SQ
+         (truncate:HQ (match_operand:SQ 1 "register_operand" "a,b,b,a")))
+        (fract_convert:SQ
+         (match_operand:HQ 2 "register_operand" "a,b,b,a")))_CBRK_)]
+  ""
+  "%|%.\\tsmpyhl\\t%$\\t%1, %2, %_MODk_0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
+
+(define_insn "mulhqsq3_hh_VARIANT_"
+  [(_SET_ _OBRK_(match_operand:_MSQ 0 "_DESTOPERAND_" "=_A_,_B_,_A_,_B_")
+        (ss_mult:SQ
+        (fract_convert:SQ
+         (truncate:HQ (match_operand:SQ 1 "register_operand" "a,b,b,a")))
+        (fract_convert:SQ
+         (truncate:HQ (match_operand:SQ 2 "register_operand" "a,b,b,a"))))_CBRK_)]
+  ""
+  "%|%.\\tsmpyh\\t%$\\t%1, %2, %_MODk_0"
+  [(set_attr "type" "mpy2")
+   (set_attr "units" "m")
+   (set_attr "cross" "n,n,y,y")])
diff --git a/gcc/config/c6x/c6x-opts.h b/gcc/config/c6x/c6x-opts.h
new file mode 100644 (file)
index 0000000..7c00813
--- /dev/null
@@ -0,0 +1,36 @@
+/* Definitions for option handling for TI C6X.
+   Copyright (C) 2011
+   Free Software Foundation, Inc.
+
+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/>.  */
+
+#ifndef C6X_OPTS_H
+#define C6X_OPTS_H
+
+/* An enumeration of all supported target devices.  */
+typedef enum c6x_cpu_type
+{
+#define C6X_ISA(NAME,ENUM_VALUE,FLAGS)         \
+  ENUM_VALUE,
+#include "c6x-isas.def"
+#undef C6X_ISA
+  unk_isa
+} c6x_cpu_t;
+
+enum c6x_sdata { C6X_SDATA_NONE, C6X_SDATA_DEFAULT, C6X_SDATA_ALL };
+
+#endif
diff --git a/gcc/config/c6x/c6x-protos.h b/gcc/config/c6x/c6x-protos.h
new file mode 100644 (file)
index 0000000..b835ffc
--- /dev/null
@@ -0,0 +1,66 @@
+/* Prototypes for exported functions defined in c6x.c.
+   Copyright (C) 2010, 2011
+   Free Software Foundation, Inc.
+   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/>.  */
+
+#ifndef GCC_C6X_PROTOS_H
+#define GCC_C6X_PROTOS_H
+
+/* Functions defined in c6x.c.  */
+
+#ifdef RTX_CODE
+extern void c6x_init_cumulative_args (CUMULATIVE_ARGS *, const_tree, rtx, int);
+extern bool c6x_block_reg_pad_upward (enum machine_mode, const_tree, bool);
+
+extern bool c6x_legitimate_address_p_1 (enum machine_mode, rtx, bool, bool);
+extern bool c6x_mem_operand (rtx, enum reg_class, bool);
+extern bool expand_move (rtx *, enum machine_mode);
+
+extern bool c6x_long_call_p (rtx);
+extern void c6x_expand_call (rtx, rtx, bool);
+extern rtx c6x_expand_compare (rtx, enum machine_mode);
+extern bool c6x_force_op_for_comparison_p (enum rtx_code, rtx);
+extern bool c6x_expand_movmem (rtx, rtx, rtx, rtx, rtx, rtx);
+
+extern rtx c6x_subword (rtx, bool);
+extern void split_di (rtx *, int, rtx *, rtx *);
+extern bool c6x_valid_mask_p (HOST_WIDE_INT);
+
+extern char c6x_get_unit_specifier (rtx);
+
+extern void c6x_final_prescan_insn(rtx insn, rtx *opvec, int noperands);
+
+extern int c6x_nsaved_regs (void);
+extern HOST_WIDE_INT c6x_initial_elimination_offset (int, int);
+extern void c6x_expand_prologue (void);
+extern void c6x_expand_epilogue (bool);
+
+extern rtx c6x_return_addr_rtx (int);
+
+extern void c6x_set_return_address (rtx, rtx);
+#endif
+
+extern void c6x_override_options (void);
+extern void c6x_optimization_options (int, int);
+
+extern void c6x_output_file_unwind (FILE *);
+
+extern void c6x_function_end (FILE *, const char *);
+
+#endif /* GCC_C6X_PROTOS_H */
diff --git a/gcc/config/c6x/c6x-sched.md b/gcc/config/c6x/c6x-sched.md
new file mode 100644 (file)
index 0000000..6cb4b66
--- /dev/null
@@ -0,0 +1,934 @@
+;; -*- buffer-read-only: t -*-
+;; Generated automatically from c6x-sched.md.in by gensched.sh
+
+;; Definitions for side 1, cross n
+
+;; Scheduling description for TI C6X.
+;; Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+;; 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/>.
+
+;; Input file for gensched.sh We process this file multiple times,
+;; replacing 1 with either 1 or 2 for each of the sides of the
+;; machine, and a correspondingly with "a" or "b".  n and
+;;  are replaced with yes/no and the appropriate reservation.
+
+(define_insn_reservation "load_d1n" 5
+  (and (eq_attr "type" "load")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "d_addr")
+                (eq_attr "addr_regfile" "a"))))
+  "d1+t1")
+
+(define_insn_reservation "store_d1n" 1
+  (and (eq_attr "type" "store")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "d_addr")
+                (eq_attr "addr_regfile" "a"))))
+  "d1+t1")
+
+(define_insn_reservation "loadn_d1n" 5
+  (and (eq_attr "type" "loadn")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "d_addr")
+                (eq_attr "addr_regfile" "a"))))
+  "d1+t1+t2")
+
+(define_insn_reservation "storen_d1n" 1
+  (and (eq_attr "type" "storen")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "d_addr")
+                (eq_attr "addr_regfile" "a"))))
+  "d1+t1+t2")
+
+(define_insn_reservation "single_d1n" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "d")
+                (eq_attr "dest_regfile" "a"))))
+  "d1")
+
+(define_insn_reservation "single_l1n" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "l")
+                (eq_attr "dest_regfile" "a"))))
+  "l1+l1w")
+
+(define_insn_reservation "fp4_l1n" 4
+  (and (eq_attr "type" "fp4")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "l")
+                (eq_attr "dest_regfile" "a"))))
+  "l1,nothing*2,l1w")
+
+(define_insn_reservation "intdp_l1n" 5
+  (and (eq_attr "type" "intdp")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "l")
+                (eq_attr "dest_regfile" "a"))))
+  "l1,nothing*2,l1w*2")
+
+(define_insn_reservation "adddp_l1n" 7
+  (and (eq_attr "type" "adddp")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "l")
+                (eq_attr "dest_regfile" "a"))))
+  "(l1)*2,nothing*3,l1w*2")
+
+(define_insn_reservation "branch_s1n" 6
+  (and (eq_attr "type" "branch")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "a"))))
+  "(s1+s1w)+br1")
+
+(define_insn_reservation "call_addkpc_s1n" 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" "a")))))
+  "(s1+s1w)+br1,s2+br0+br1")
+
+(define_insn_reservation "call_mvk_s1n" 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" "a")))))
+  "(s1+s1w)+br1,s2,s2")
+
+(define_insn_reservation "single_s1n" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "a"))))
+  "(s1+s1w)")
+
+(define_insn_reservation "cmpdp_s1n" 2
+  (and (eq_attr "type" "cmpdp")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "a"))))
+  "s1,(s1)+s1w")
+
+(define_insn_reservation "dp2_s1n" 2
+  (and (eq_attr "type" "dp2")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "a"))))
+  "s1+s1w,s1w")
+
+(define_insn_reservation "fp4_s1n" 4
+  (and (eq_attr "type" "fp4")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "a"))))
+  "s1,nothing*2,s1w")
+
+(define_insn_reservation "mvilc4_s1n" 4
+  (and (eq_attr "type" "mvilc")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "a"))))
+  "(s1+s1w)")
+
+(define_insn_reservation "single_dl1n" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "dl")
+                (eq_attr "dest_regfile" "a"))))
+  "(d1|(l1+l1w))")
+
+(define_insn_reservation "single_ds1n" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "ds")
+                (eq_attr "dest_regfile" "a"))))
+  "(d1|(s1+s1w))")
+
+(define_insn_reservation "single_ls1n" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "ls")
+                (eq_attr "dest_regfile" "a"))))
+  "((l1+l1w)|(s1+s1w))")
+
+(define_insn_reservation "dp2_l1n" 2
+  (and (eq_attr "type" "dp2")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "l")
+                (eq_attr "dest_regfile" "a"))))
+  "l1+l1w,l1w")
+
+(define_insn_reservation "fp4_ls1n" 4
+  (and (eq_attr "type" "fp4")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "ls")
+                (eq_attr "dest_regfile" "a"))))
+  "(s1,nothing*2,s1w)|(l1,nothing*2,l1w)")
+
+(define_insn_reservation "adddp_ls1n" 7
+  (and (eq_attr "type" "adddp")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "ls")
+                (eq_attr "dest_regfile" "a"))))
+  "((s1)*2,nothing*3,s1w*2)|((l1)*2,nothing*3,l1w*2)")
+
+(define_insn_reservation "single_dls1n" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "dls")
+                (eq_attr "dest_regfile" "a"))))
+  "(d1|(l1+l1w)|(s1+s1w))")
+
+(define_insn_reservation "mpy2_m1n" 2
+  (and (eq_attr "type" "mpy2")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "m")
+                (eq_attr "dest_regfile" "a"))))
+  "m1,m1w")
+
+(define_insn_reservation "mpy4_m1n" 4
+  (and (eq_attr "type" "mpy4")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "m")
+                (eq_attr "dest_regfile" "a"))))
+  "m1,nothing,nothing,m1w")
+
+(define_insn_reservation "mpydp_m1n" 10
+  (and (eq_attr "type" "mpydp")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "m")
+                (eq_attr "dest_regfile" "a"))))
+  "(m1)*4,nothing*4,m1w*2")
+
+(define_insn_reservation "mpyspdp_m1n" 7
+  (and (eq_attr "type" "mpyspdp")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "m")
+                (eq_attr "dest_regfile" "a"))))
+  "(m1)*2,nothing*3,m1w*2")
+
+(define_insn_reservation "mpysp2dp_m1n" 5
+  (and (eq_attr "type" "mpysp2dp")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "m")
+                (eq_attr "dest_regfile" "a"))))
+  "m1,nothing*2,m1w*2")
+
+;; Definitions for side 2, cross n
+
+;; Scheduling description for TI C6X.
+;; Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+;; 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/>.
+
+;; Input file for gensched.sh We process this file multiple times,
+;; replacing 2 with either 1 or 2 for each of the sides of the
+;; machine, and b correspondingly with "a" or "b".  n and
+;;  are replaced with yes/no and the appropriate reservation.
+
+(define_insn_reservation "load_d2n" 5
+  (and (eq_attr "type" "load")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "d_addr")
+                (eq_attr "addr_regfile" "b"))))
+  "d2+t2")
+
+(define_insn_reservation "store_d2n" 1
+  (and (eq_attr "type" "store")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "d_addr")
+                (eq_attr "addr_regfile" "b"))))
+  "d2+t2")
+
+(define_insn_reservation "loadn_d2n" 5
+  (and (eq_attr "type" "loadn")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "d_addr")
+                (eq_attr "addr_regfile" "b"))))
+  "d2+t1+t2")
+
+(define_insn_reservation "storen_d2n" 1
+  (and (eq_attr "type" "storen")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "d_addr")
+                (eq_attr "addr_regfile" "b"))))
+  "d2+t1+t2")
+
+(define_insn_reservation "single_d2n" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "d")
+                (eq_attr "dest_regfile" "b"))))
+  "d2")
+
+(define_insn_reservation "single_l2n" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "l")
+                (eq_attr "dest_regfile" "b"))))
+  "l2+l2w")
+
+(define_insn_reservation "fp4_l2n" 4
+  (and (eq_attr "type" "fp4")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "l")
+                (eq_attr "dest_regfile" "b"))))
+  "l2,nothing*2,l2w")
+
+(define_insn_reservation "intdp_l2n" 5
+  (and (eq_attr "type" "intdp")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "l")
+                (eq_attr "dest_regfile" "b"))))
+  "l2,nothing*2,l2w*2")
+
+(define_insn_reservation "adddp_l2n" 7
+  (and (eq_attr "type" "adddp")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "l")
+                (eq_attr "dest_regfile" "b"))))
+  "(l2)*2,nothing*3,l2w*2")
+
+(define_insn_reservation "branch_s2n" 6
+  (and (eq_attr "type" "branch")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "b"))))
+  "(s2+s2w)+br1")
+
+(define_insn_reservation "call_addkpc_s2n" 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" "b")))))
+  "(s2+s2w)+br1,s2+br0+br1")
+
+(define_insn_reservation "call_mvk_s2n" 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" "b")))))
+  "(s2+s2w)+br1,s2,s2")
+
+(define_insn_reservation "single_s2n" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "b"))))
+  "(s2+s2w)")
+
+(define_insn_reservation "cmpdp_s2n" 2
+  (and (eq_attr "type" "cmpdp")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "b"))))
+  "s2,(s2)+s2w")
+
+(define_insn_reservation "dp2_s2n" 2
+  (and (eq_attr "type" "dp2")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "b"))))
+  "s2+s2w,s2w")
+
+(define_insn_reservation "fp4_s2n" 4
+  (and (eq_attr "type" "fp4")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "b"))))
+  "s2,nothing*2,s2w")
+
+(define_insn_reservation "mvilc4_s2n" 4
+  (and (eq_attr "type" "mvilc")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "b"))))
+  "(s2+s2w)")
+
+(define_insn_reservation "single_dl2n" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "dl")
+                (eq_attr "dest_regfile" "b"))))
+  "(d2|(l2+l2w))")
+
+(define_insn_reservation "single_ds2n" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "ds")
+                (eq_attr "dest_regfile" "b"))))
+  "(d2|(s2+s2w))")
+
+(define_insn_reservation "single_ls2n" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "ls")
+                (eq_attr "dest_regfile" "b"))))
+  "((l2+l2w)|(s2+s2w))")
+
+(define_insn_reservation "dp2_l2n" 2
+  (and (eq_attr "type" "dp2")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "l")
+                (eq_attr "dest_regfile" "b"))))
+  "l2+l2w,l2w")
+
+(define_insn_reservation "fp4_ls2n" 4
+  (and (eq_attr "type" "fp4")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "ls")
+                (eq_attr "dest_regfile" "b"))))
+  "(s2,nothing*2,s2w)|(l2,nothing*2,l2w)")
+
+(define_insn_reservation "adddp_ls2n" 7
+  (and (eq_attr "type" "adddp")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "ls")
+                (eq_attr "dest_regfile" "b"))))
+  "((s2)*2,nothing*3,s2w*2)|((l2)*2,nothing*3,l2w*2)")
+
+(define_insn_reservation "single_dls2n" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "dls")
+                (eq_attr "dest_regfile" "b"))))
+  "(d2|(l2+l2w)|(s2+s2w))")
+
+(define_insn_reservation "mpy2_m2n" 2
+  (and (eq_attr "type" "mpy2")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "m")
+                (eq_attr "dest_regfile" "b"))))
+  "m2,m2w")
+
+(define_insn_reservation "mpy4_m2n" 4
+  (and (eq_attr "type" "mpy4")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "m")
+                (eq_attr "dest_regfile" "b"))))
+  "m2,nothing,nothing,m2w")
+
+(define_insn_reservation "mpydp_m2n" 10
+  (and (eq_attr "type" "mpydp")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "m")
+                (eq_attr "dest_regfile" "b"))))
+  "(m2)*4,nothing*4,m2w*2")
+
+(define_insn_reservation "mpyspdp_m2n" 7
+  (and (eq_attr "type" "mpyspdp")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "m")
+                (eq_attr "dest_regfile" "b"))))
+  "(m2)*2,nothing*3,m2w*2")
+
+(define_insn_reservation "mpysp2dp_m2n" 5
+  (and (eq_attr "type" "mpysp2dp")
+       (and (eq_attr "cross" "n")
+           (and (eq_attr "units" "m")
+                (eq_attr "dest_regfile" "b"))))
+  "m2,nothing*2,m2w*2")
+
+;; Definitions for side 1, cross y
+
+;; Scheduling description for TI C6X.
+;; Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+;; 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/>.
+
+;; Input file for gensched.sh We process this file multiple times,
+;; replacing 1 with either 1 or 2 for each of the sides of the
+;; machine, and a correspondingly with "a" or "b".  y and
+;; +x1 are replaced with yes/no and the appropriate reservation.
+
+(define_insn_reservation "load_d1y" 5
+  (and (eq_attr "type" "load")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "d_addr")
+                (eq_attr "addr_regfile" "a"))))
+  "d1+t2")
+
+(define_insn_reservation "store_d1y" 1
+  (and (eq_attr "type" "store")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "d_addr")
+                (eq_attr "addr_regfile" "a"))))
+  "d1+t2")
+
+(define_insn_reservation "loadn_d1y" 5
+  (and (eq_attr "type" "loadn")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "d_addr")
+                (eq_attr "addr_regfile" "a"))))
+  "d1+t1+t2")
+
+(define_insn_reservation "storen_d1y" 1
+  (and (eq_attr "type" "storen")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "d_addr")
+                (eq_attr "addr_regfile" "a"))))
+  "d1+t1+t2")
+
+(define_insn_reservation "single_d1y" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "d")
+                (eq_attr "dest_regfile" "a"))))
+  "d1+x1")
+
+(define_insn_reservation "single_l1y" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "l")
+                (eq_attr "dest_regfile" "a"))))
+  "l1+l1w+x1")
+
+(define_insn_reservation "fp4_l1y" 4
+  (and (eq_attr "type" "fp4")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "l")
+                (eq_attr "dest_regfile" "a"))))
+  "l1+x1,nothing*2,l1w")
+
+(define_insn_reservation "intdp_l1y" 5
+  (and (eq_attr "type" "intdp")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "l")
+                (eq_attr "dest_regfile" "a"))))
+  "l1+x1,nothing*2,l1w*2")
+
+(define_insn_reservation "adddp_l1y" 7
+  (and (eq_attr "type" "adddp")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "l")
+                (eq_attr "dest_regfile" "a"))))
+  "(l1+x1)*2,nothing*3,l1w*2")
+
+(define_insn_reservation "branch_s1y" 6
+  (and (eq_attr "type" "branch")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "a"))))
+  "(s1+s1w)+x1+br1")
+
+(define_insn_reservation "call_addkpc_s1y" 6
+  (and (eq_attr "type" "call")
+       (and (ne (symbol_ref "TARGET_INSNS_64") (const_int 0))
+           (and (eq_attr "cross" "y")
+                (and (eq_attr "units" "s")
+                     (eq_attr "dest_regfile" "a")))))
+  "(s1+s1w)+x1+br1,s2+br0+br1")
+
+(define_insn_reservation "call_mvk_s1y" 6
+  (and (eq_attr "type" "call")
+       (and (eq (symbol_ref "TARGET_INSNS_64") (const_int 0))
+           (and (eq_attr "cross" "y")
+                (and (eq_attr "units" "s")
+                     (eq_attr "dest_regfile" "a")))))
+  "(s1+s1w)+x1+br1,s2,s2")
+
+(define_insn_reservation "single_s1y" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "a"))))
+  "(s1+s1w)+x1")
+
+(define_insn_reservation "cmpdp_s1y" 2
+  (and (eq_attr "type" "cmpdp")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "a"))))
+  "s1+x1,(s1+x1)+s1w")
+
+(define_insn_reservation "dp2_s1y" 2
+  (and (eq_attr "type" "dp2")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "a"))))
+  "s1+s1w+x1,s1w")
+
+(define_insn_reservation "fp4_s1y" 4
+  (and (eq_attr "type" "fp4")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "a"))))
+  "s1+x1,nothing*2,s1w")
+
+(define_insn_reservation "mvilc4_s1y" 4
+  (and (eq_attr "type" "mvilc")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "a"))))
+  "(s1+s1w)+x1")
+
+(define_insn_reservation "single_dl1y" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "dl")
+                (eq_attr "dest_regfile" "a"))))
+  "(d1|(l1+l1w))+x1")
+
+(define_insn_reservation "single_ds1y" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "ds")
+                (eq_attr "dest_regfile" "a"))))
+  "(d1|(s1+s1w))+x1")
+
+(define_insn_reservation "single_ls1y" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "ls")
+                (eq_attr "dest_regfile" "a"))))
+  "((l1+l1w)|(s1+s1w))+x1")
+
+(define_insn_reservation "dp2_l1y" 2
+  (and (eq_attr "type" "dp2")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "l")
+                (eq_attr "dest_regfile" "a"))))
+  "l1+l1w+x1,l1w")
+
+(define_insn_reservation "fp4_ls1y" 4
+  (and (eq_attr "type" "fp4")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "ls")
+                (eq_attr "dest_regfile" "a"))))
+  "(s1+x1,nothing*2,s1w)|(l1+x1,nothing*2,l1w)")
+
+(define_insn_reservation "adddp_ls1y" 7
+  (and (eq_attr "type" "adddp")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "ls")
+                (eq_attr "dest_regfile" "a"))))
+  "((s1+x1)*2,nothing*3,s1w*2)|((l1+x1)*2,nothing*3,l1w*2)")
+
+(define_insn_reservation "single_dls1y" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "dls")
+                (eq_attr "dest_regfile" "a"))))
+  "(d1|(l1+l1w)|(s1+s1w))+x1")
+
+(define_insn_reservation "mpy2_m1y" 2
+  (and (eq_attr "type" "mpy2")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "m")
+                (eq_attr "dest_regfile" "a"))))
+  "m1+x1,m1w")
+
+(define_insn_reservation "mpy4_m1y" 4
+  (and (eq_attr "type" "mpy4")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "m")
+                (eq_attr "dest_regfile" "a"))))
+  "m1+x1,nothing,nothing,m1w")
+
+(define_insn_reservation "mpydp_m1y" 10
+  (and (eq_attr "type" "mpydp")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "m")
+                (eq_attr "dest_regfile" "a"))))
+  "(m1+x1)*4,nothing*4,m1w*2")
+
+(define_insn_reservation "mpyspdp_m1y" 7
+  (and (eq_attr "type" "mpyspdp")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "m")
+                (eq_attr "dest_regfile" "a"))))
+  "(m1+x1)*2,nothing*3,m1w*2")
+
+(define_insn_reservation "mpysp2dp_m1y" 5
+  (and (eq_attr "type" "mpysp2dp")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "m")
+                (eq_attr "dest_regfile" "a"))))
+  "m1+x1,nothing*2,m1w*2")
+
+;; Definitions for side 2, cross y
+
+;; Scheduling description for TI C6X.
+;; Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+;; 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/>.
+
+;; Input file for gensched.sh We process this file multiple times,
+;; replacing 2 with either 1 or 2 for each of the sides of the
+;; machine, and b correspondingly with "a" or "b".  y and
+;; +x2 are replaced with yes/no and the appropriate reservation.
+
+(define_insn_reservation "load_d2y" 5
+  (and (eq_attr "type" "load")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "d_addr")
+                (eq_attr "addr_regfile" "b"))))
+  "d2+t1")
+
+(define_insn_reservation "store_d2y" 1
+  (and (eq_attr "type" "store")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "d_addr")
+                (eq_attr "addr_regfile" "b"))))
+  "d2+t1")
+
+(define_insn_reservation "loadn_d2y" 5
+  (and (eq_attr "type" "loadn")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "d_addr")
+                (eq_attr "addr_regfile" "b"))))
+  "d2+t1+t2")
+
+(define_insn_reservation "storen_d2y" 1
+  (and (eq_attr "type" "storen")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "d_addr")
+                (eq_attr "addr_regfile" "b"))))
+  "d2+t1+t2")
+
+(define_insn_reservation "single_d2y" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "d")
+                (eq_attr "dest_regfile" "b"))))
+  "d2+x2")
+
+(define_insn_reservation "single_l2y" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "l")
+                (eq_attr "dest_regfile" "b"))))
+  "l2+l2w+x2")
+
+(define_insn_reservation "fp4_l2y" 4
+  (and (eq_attr "type" "fp4")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "l")
+                (eq_attr "dest_regfile" "b"))))
+  "l2+x2,nothing*2,l2w")
+
+(define_insn_reservation "intdp_l2y" 5
+  (and (eq_attr "type" "intdp")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "l")
+                (eq_attr "dest_regfile" "b"))))
+  "l2+x2,nothing*2,l2w*2")
+
+(define_insn_reservation "adddp_l2y" 7
+  (and (eq_attr "type" "adddp")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "l")
+                (eq_attr "dest_regfile" "b"))))
+  "(l2+x2)*2,nothing*3,l2w*2")
+
+(define_insn_reservation "branch_s2y" 6
+  (and (eq_attr "type" "branch")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "b"))))
+  "(s2+s2w)+x2+br1")
+
+(define_insn_reservation "call_addkpc_s2y" 6
+  (and (eq_attr "type" "call")
+       (and (ne (symbol_ref "TARGET_INSNS_64") (const_int 0))
+           (and (eq_attr "cross" "y")
+                (and (eq_attr "units" "s")
+                     (eq_attr "dest_regfile" "b")))))
+  "(s2+s2w)+x2+br1,s2+br0+br1")
+
+(define_insn_reservation "call_mvk_s2y" 6
+  (and (eq_attr "type" "call")
+       (and (eq (symbol_ref "TARGET_INSNS_64") (const_int 0))
+           (and (eq_attr "cross" "y")
+                (and (eq_attr "units" "s")
+                     (eq_attr "dest_regfile" "b")))))
+  "(s2+s2w)+x2+br1,s2,s2")
+
+(define_insn_reservation "single_s2y" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "b"))))
+  "(s2+s2w)+x2")
+
+(define_insn_reservation "cmpdp_s2y" 2
+  (and (eq_attr "type" "cmpdp")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "b"))))
+  "s2+x2,(s2+x2)+s2w")
+
+(define_insn_reservation "dp2_s2y" 2
+  (and (eq_attr "type" "dp2")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "b"))))
+  "s2+s2w+x2,s2w")
+
+(define_insn_reservation "fp4_s2y" 4
+  (and (eq_attr "type" "fp4")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "b"))))
+  "s2+x2,nothing*2,s2w")
+
+(define_insn_reservation "mvilc4_s2y" 4
+  (and (eq_attr "type" "mvilc")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "b"))))
+  "(s2+s2w)+x2")
+
+(define_insn_reservation "single_dl2y" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "dl")
+                (eq_attr "dest_regfile" "b"))))
+  "(d2|(l2+l2w))+x2")
+
+(define_insn_reservation "single_ds2y" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "ds")
+                (eq_attr "dest_regfile" "b"))))
+  "(d2|(s2+s2w))+x2")
+
+(define_insn_reservation "single_ls2y" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "ls")
+                (eq_attr "dest_regfile" "b"))))
+  "((l2+l2w)|(s2+s2w))+x2")
+
+(define_insn_reservation "dp2_l2y" 2
+  (and (eq_attr "type" "dp2")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "l")
+                (eq_attr "dest_regfile" "b"))))
+  "l2+l2w+x2,l2w")
+
+(define_insn_reservation "fp4_ls2y" 4
+  (and (eq_attr "type" "fp4")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "ls")
+                (eq_attr "dest_regfile" "b"))))
+  "(s2+x2,nothing*2,s2w)|(l2+x2,nothing*2,l2w)")
+
+(define_insn_reservation "adddp_ls2y" 7
+  (and (eq_attr "type" "adddp")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "ls")
+                (eq_attr "dest_regfile" "b"))))
+  "((s2+x2)*2,nothing*3,s2w*2)|((l2+x2)*2,nothing*3,l2w*2)")
+
+(define_insn_reservation "single_dls2y" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "dls")
+                (eq_attr "dest_regfile" "b"))))
+  "(d2|(l2+l2w)|(s2+s2w))+x2")
+
+(define_insn_reservation "mpy2_m2y" 2
+  (and (eq_attr "type" "mpy2")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "m")
+                (eq_attr "dest_regfile" "b"))))
+  "m2+x2,m2w")
+
+(define_insn_reservation "mpy4_m2y" 4
+  (and (eq_attr "type" "mpy4")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "m")
+                (eq_attr "dest_regfile" "b"))))
+  "m2+x2,nothing,nothing,m2w")
+
+(define_insn_reservation "mpydp_m2y" 10
+  (and (eq_attr "type" "mpydp")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "m")
+                (eq_attr "dest_regfile" "b"))))
+  "(m2+x2)*4,nothing*4,m2w*2")
+
+(define_insn_reservation "mpyspdp_m2y" 7
+  (and (eq_attr "type" "mpyspdp")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "m")
+                (eq_attr "dest_regfile" "b"))))
+  "(m2+x2)*2,nothing*3,m2w*2")
+
+(define_insn_reservation "mpysp2dp_m2y" 5
+  (and (eq_attr "type" "mpysp2dp")
+       (and (eq_attr "cross" "y")
+           (and (eq_attr "units" "m")
+                (eq_attr "dest_regfile" "b"))))
+  "m2+x2,nothing*2,m2w*2")
diff --git a/gcc/config/c6x/c6x-sched.md.in b/gcc/config/c6x/c6x-sched.md.in
new file mode 100644 (file)
index 0000000..271109b
--- /dev/null
@@ -0,0 +1,230 @@
+;; Scheduling description for TI C6X.
+;; Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+;; 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/>.
+
+;; Input file for gensched.sh We process this file multiple times,
+;; replacing _N_ with either 1 or 2 for each of the sides of the
+;; machine, and _RF_ correspondingly with "a" or "b".  _CROSS_ and
+;; _CUNIT_ are replaced with yes/no and the appropriate reservation.
+
+(define_insn_reservation "load_d_N__CROSS_" 5
+  (and (eq_attr "type" "load")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "d_addr")
+                (eq_attr "addr_regfile" "_RF_"))))
+  "d_N_+t_NX_")
+
+(define_insn_reservation "store_d_N__CROSS_" 1
+  (and (eq_attr "type" "store")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "d_addr")
+                (eq_attr "addr_regfile" "_RF_"))))
+  "d_N_+t_NX_")
+
+(define_insn_reservation "loadn_d_N__CROSS_" 5
+  (and (eq_attr "type" "loadn")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "d_addr")
+                (eq_attr "addr_regfile" "_RF_"))))
+  "d_N_+t1+t2")
+
+(define_insn_reservation "storen_d_N__CROSS_" 1
+  (and (eq_attr "type" "storen")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "d_addr")
+                (eq_attr "addr_regfile" "_RF_"))))
+  "d_N_+t1+t2")
+
+(define_insn_reservation "single_d_N__CROSS_" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "d")
+                (eq_attr "dest_regfile" "_RF_"))))
+  "d_N__CUNIT_")
+
+(define_insn_reservation "single_l_N__CROSS_" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "l")
+                (eq_attr "dest_regfile" "_RF_"))))
+  "l_N_+l_N_w_CUNIT_")
+
+(define_insn_reservation "fp4_l_N__CROSS_" 4
+  (and (eq_attr "type" "fp4")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "l")
+                (eq_attr "dest_regfile" "_RF_"))))
+  "l_N__CUNIT_,nothing*2,l_N_w")
+
+(define_insn_reservation "intdp_l_N__CROSS_" 5
+  (and (eq_attr "type" "intdp")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "l")
+                (eq_attr "dest_regfile" "_RF_"))))
+  "l_N__CUNIT_,nothing*2,l_N_w*2")
+
+(define_insn_reservation "adddp_l_N__CROSS_" 7
+  (and (eq_attr "type" "adddp")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "l")
+                (eq_attr "dest_regfile" "_RF_"))))
+  "(l_N__CUNIT_)*2,nothing*3,l_N_w*2")
+
+(define_insn_reservation "branch_s_N__CROSS_" 6
+  (and (eq_attr "type" "branch")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "_RF_"))))
+  "(s_N_+s_N_w)_CUNIT_+br1")
+
+(define_insn_reservation "call_addkpc_s_N__CROSS_" 6
+  (and (eq_attr "type" "call")
+       (and (ne (symbol_ref "TARGET_INSNS_64") (const_int 0))
+           (and (eq_attr "cross" "_CROSS_")
+                (and (eq_attr "units" "s")
+                     (eq_attr "dest_regfile" "_RF_")))))
+  "(s_N_+s_N_w)_CUNIT_+br1,s2+br0+br1")
+
+(define_insn_reservation "call_mvk_s_N__CROSS_" 6
+  (and (eq_attr "type" "call")
+       (and (eq (symbol_ref "TARGET_INSNS_64") (const_int 0))
+           (and (eq_attr "cross" "_CROSS_")
+                (and (eq_attr "units" "s")
+                     (eq_attr "dest_regfile" "_RF_")))))
+  "(s_N_+s_N_w)_CUNIT_+br1,s2,s2")
+
+(define_insn_reservation "single_s_N__CROSS_" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "_RF_"))))
+  "(s_N_+s_N_w)_CUNIT_")
+
+(define_insn_reservation "cmpdp_s_N__CROSS_" 2
+  (and (eq_attr "type" "cmpdp")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "_RF_"))))
+  "s_N__CUNIT_,(s_N__CUNIT_)+s_N_w")
+
+(define_insn_reservation "dp2_s_N__CROSS_" 2
+  (and (eq_attr "type" "dp2")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "_RF_"))))
+  "s_N_+s_N_w_CUNIT_,s_N_w")
+
+(define_insn_reservation "fp4_s_N__CROSS_" 4
+  (and (eq_attr "type" "fp4")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "_RF_"))))
+  "s_N__CUNIT_,nothing*2,s_N_w")
+
+(define_insn_reservation "mvilc4_s_N__CROSS_" 4
+  (and (eq_attr "type" "mvilc")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "s")
+                (eq_attr "dest_regfile" "_RF_"))))
+  "(s_N_+s_N_w)_CUNIT_")
+
+(define_insn_reservation "single_dl_N__CROSS_" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "dl")
+                (eq_attr "dest_regfile" "_RF_"))))
+  "(d_N_|(l_N_+l_N_w))_CUNIT_")
+
+(define_insn_reservation "single_ds_N__CROSS_" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "ds")
+                (eq_attr "dest_regfile" "_RF_"))))
+  "(d_N_|(s_N_+s_N_w))_CUNIT_")
+
+(define_insn_reservation "single_ls_N__CROSS_" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "ls")
+                (eq_attr "dest_regfile" "_RF_"))))
+  "((l_N_+l_N_w)|(s_N_+s_N_w))_CUNIT_")
+
+(define_insn_reservation "dp2_l_N__CROSS_" 2
+  (and (eq_attr "type" "dp2")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "l")
+                (eq_attr "dest_regfile" "_RF_"))))
+  "l_N_+l_N_w_CUNIT_,l_N_w")
+
+(define_insn_reservation "fp4_ls_N__CROSS_" 4
+  (and (eq_attr "type" "fp4")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "ls")
+                (eq_attr "dest_regfile" "_RF_"))))
+  "(s_N__CUNIT_,nothing*2,s_N_w)|(l_N__CUNIT_,nothing*2,l_N_w)")
+
+(define_insn_reservation "adddp_ls_N__CROSS_" 7
+  (and (eq_attr "type" "adddp")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "ls")
+                (eq_attr "dest_regfile" "_RF_"))))
+  "((s_N__CUNIT_)*2,nothing*3,s_N_w*2)|((l_N__CUNIT_)*2,nothing*3,l_N_w*2)")
+
+(define_insn_reservation "single_dls_N__CROSS_" 1
+  (and (eq_attr "type" "single")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "dls")
+                (eq_attr "dest_regfile" "_RF_"))))
+  "(d_N_|(l_N_+l_N_w)|(s_N_+s_N_w))_CUNIT_")
+
+(define_insn_reservation "mpy2_m_N__CROSS_" 2
+  (and (eq_attr "type" "mpy2")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "m")
+                (eq_attr "dest_regfile" "_RF_"))))
+  "m_N__CUNIT_,m_N_w")
+
+(define_insn_reservation "mpy4_m_N__CROSS_" 4
+  (and (eq_attr "type" "mpy4")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "m")
+                (eq_attr "dest_regfile" "_RF_"))))
+  "m_N__CUNIT_,nothing,nothing,m_N_w")
+
+(define_insn_reservation "mpydp_m_N__CROSS_" 10
+  (and (eq_attr "type" "mpydp")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "m")
+                (eq_attr "dest_regfile" "_RF_"))))
+  "(m_N__CUNIT_)*4,nothing*4,m_N_w*2")
+
+(define_insn_reservation "mpyspdp_m_N__CROSS_" 7
+  (and (eq_attr "type" "mpyspdp")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "m")
+                (eq_attr "dest_regfile" "_RF_"))))
+  "(m_N__CUNIT_)*2,nothing*3,m_N_w*2")
+
+(define_insn_reservation "mpysp2dp_m_N__CROSS_" 5
+  (and (eq_attr "type" "mpysp2dp")
+       (and (eq_attr "cross" "_CROSS_")
+           (and (eq_attr "units" "m")
+                (eq_attr "dest_regfile" "_RF_"))))
+  "m_N__CUNIT_,nothing*2,m_N_w*2")
diff --git a/gcc/config/c6x/c6x-tables.opt b/gcc/config/c6x/c6x-tables.opt
new file mode 100644 (file)
index 0000000..e012e9e
--- /dev/null
@@ -0,0 +1,43 @@
+; -*- buffer-read-only: t -*-
+; Generated automatically by genopt.sh from c6x-isas.def.
+;
+; Copyright (C) 2011 Free Software Foundation, Inc.
+;
+; 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/>.
+
+Enum
+Name(c6x_isa) Type(int)
+Known C6X ISAs (for use with the -march= option):
+
+EnumValue
+Enum(c6x_isa) String(c62x) Value(0)
+
+EnumValue
+Enum(c6x_isa) String(c64x) Value(1)
+
+EnumValue
+Enum(c6x_isa) String(c64x+) Value(2)
+
+EnumValue
+Enum(c6x_isa) String(c67x) Value(3)
+
+EnumValue
+Enum(c6x_isa) String(c67x+) Value(4)
+
+EnumValue
+Enum(c6x_isa) String(c674x) Value(5)
+
diff --git a/gcc/config/c6x/c6x.c b/gcc/config/c6x/c6x.c
new file mode 100644 (file)
index 0000000..deb2f53
--- /dev/null
@@ -0,0 +1,5572 @@
+/* Target Code for TI C6X
+   Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+   Contributed by Andrew Jenner <andrew@codesourcery.com>
+   Contributed by Bernd Schmidt <bernds@codesourcery.com>
+
+   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/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "tree.h"
+#include "insn-flags.h"
+#include "output.h"
+#include "insn-attr.h"
+#include "insn-codes.h"
+#include "expr.h"
+#include "regs.h"
+#include "optabs.h"
+#include "recog.h"
+#include "ggc.h"
+#include "sched-int.h"
+#include "timevar.h"
+#include "tm_p.h"
+#include "tm-preds.h"
+#include "tm-constrs.h"
+#include "df.h"
+#include "integrate.h"
+#include "diagnostic-core.h"
+#include "cgraph.h"
+#include "cfglayout.h"
+#include "langhooks.h"
+#include "target.h"
+#include "target-def.h"
+#include "sel-sched.h"
+#include "debug.h"
+#include "opts.h"
+
+/* Table of supported architecture variants.  */
+typedef struct
+{
+  const char *arch;
+  enum c6x_cpu_type type;
+  unsigned short features;
+} c6x_arch_table;
+
+/* A list of all ISAs, mapping each one to a representative device.
+   Used for -march selection.  */
+static const c6x_arch_table all_isas[] =
+{
+#define C6X_ISA(NAME,DEVICE,FLAGS) \
+  { NAME, DEVICE, FLAGS },
+#include "c6x-isas.def"
+#undef C6X_ISA
+  { NULL, C6X_CPU_C62X, 0 }
+};
+
+/* This is the parsed result of the "-march=" option, if given.  */
+enum c6x_cpu_type c6x_arch = C6X_DEFAULT_ARCH;
+
+/* A mask of insn types that are allowed by the architecture selected by
+   the -march option.  */
+unsigned long c6x_insn_mask = C6X_DEFAULT_INSN_MASK;
+
+/* The instruction that is being output (as obtained from FINAL_PRESCAN_INSN).
+ */
+static rtx c6x_current_insn = NULL_RTX;
+
+/* A decl we build to access __c6xabi_DSBT_base.  */
+static GTY(()) tree dsbt_decl;
+\f
+/* Determines whether we run our final scheduling pass or not.  We always
+   avoid the normal second scheduling pass.  */
+static int c6x_flag_schedule_insns2;
+
+/* Determines whether we run variable tracking in machine dependent
+   reorganization.  */
+static int c6x_flag_var_tracking;
+
+/* Determines whether we use modulo scheduling.  */
+static int c6x_flag_modulo_sched;
+
+/* Record the state of flag_pic before we set it to 1 for DSBT.  */
+int c6x_initial_flag_pic;
+\f
+typedef struct
+{
+  /* We record the clock cycle for every insn during scheduling.  */
+  int clock;
+  /* After scheduling, we run assign_reservations to choose unit
+     reservations for all insns.  These are recorded here.  */
+  int reservation;
+  /* Records the new condition for insns which must be made
+     conditional after scheduling.  An entry of NULL_RTX means no such
+     change is necessary.  */
+  rtx new_cond;
+  /* True for the first insn that was scheduled in an ebb.  */
+  bool ebb_start;
+} c6x_sched_insn_info;
+
+DEF_VEC_O(c6x_sched_insn_info);
+DEF_VEC_ALLOC_O(c6x_sched_insn_info, heap);
+
+/* Record a c6x_sched_insn_info structure for every insn in the function.  */
+static VEC(c6x_sched_insn_info, heap) *insn_info;
+
+#define INSN_INFO_LENGTH (VEC_length (c6x_sched_insn_info, insn_info))
+#define INSN_INFO_ENTRY(N) (*VEC_index (c6x_sched_insn_info, insn_info, (N)))
+
+static bool done_cfi_sections;
+
+/* The DFA names of the units, in packet order.  */
+static const char *const c6x_unit_names[] =
+{
+  "d1", "l1", "s1", "m1",
+  "d2", "l2", "s2", "m2",
+};
+
+#define RESERVATION_FLAG_D 1
+#define RESERVATION_FLAG_L 2
+#define RESERVATION_FLAG_S 4
+#define RESERVATION_FLAG_M 8
+#define RESERVATION_FLAG_DL (RESERVATION_FLAG_D | RESERVATION_FLAG_L)
+#define RESERVATION_FLAG_DS (RESERVATION_FLAG_D | RESERVATION_FLAG_S)
+#define RESERVATION_FLAG_LS (RESERVATION_FLAG_L | RESERVATION_FLAG_S)
+#define RESERVATION_FLAG_DLS (RESERVATION_FLAG_D | RESERVATION_FLAG_LS)
+
+#define RESERVATION_S1 2
+#define RESERVATION_S2 6
+\f
+/* Register map for debugging.  */
+int const dbx_register_map[FIRST_PSEUDO_REGISTER] =
+{
+  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,        /* A0 - A15.  */
+  37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,  /* A16 - A32.  */
+  50, 51, 52,
+  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,  /* B0 - B15.  */
+  29, 30, 31,
+  53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,  /* B16 - B32.  */
+  66, 67, 68,
+  -1, -1, -1                                           /* FP, ARGP, ILC.  */
+};
+\f
+/* Allocate a new, cleared machine_function structure.  */
+
+static struct machine_function *
+c6x_init_machine_status (void)
+{
+  return ggc_alloc_cleared_machine_function ();
+}
+
+/* Implement TARGET_OPTION_OVERRIDE.  */
+
+static void
+c6x_option_override (void)
+{
+  if (global_options_set.x_c6x_arch_option)
+    {
+      c6x_arch = all_isas[c6x_arch_option].type;
+      c6x_insn_mask &= ~C6X_INSNS_ALL_CPU_BITS;
+      c6x_insn_mask |= all_isas[c6x_arch_option].features;
+    }
+
+  c6x_flag_schedule_insns2 = flag_schedule_insns_after_reload;
+  flag_schedule_insns_after_reload = 0;
+
+  c6x_flag_modulo_sched = flag_modulo_sched;
+  flag_modulo_sched = 0;
+
+  init_machine_status = c6x_init_machine_status;
+
+  if (flag_pic && !TARGET_DSBT)
+    {
+      error ("-fpic and -fPIC not supported without -mdsbt on this target");
+      flag_pic = 0;
+    }
+  c6x_initial_flag_pic = flag_pic;
+  if (TARGET_DSBT && !flag_pic)
+    flag_pic = 1;
+}
+
+
+/* Implement the TARGET_CONDITIONAL_REGISTER_USAGE hook.  */
+
+static void
+c6x_conditional_register_usage (void)
+{
+  int i;
+  if (c6x_arch == C6X_CPU_C62X || c6x_arch == C6X_CPU_C67X)
+    for (i = 16; i < 32; i++)
+      {
+       fixed_regs[i] = 1;
+       fixed_regs[32 + i] = 1;
+      }
+  if (TARGET_INSNS_64)
+    {
+      SET_HARD_REG_BIT (reg_class_contents[(int)PREDICATE_A_REGS],
+                       REG_A0);
+      SET_HARD_REG_BIT (reg_class_contents[(int)PREDICATE_REGS],
+                       REG_A0);
+      CLEAR_HARD_REG_BIT (reg_class_contents[(int)NONPREDICATE_A_REGS],
+                         REG_A0);
+      CLEAR_HARD_REG_BIT (reg_class_contents[(int)NONPREDICATE_REGS],
+                         REG_A0);
+    }
+}
+\f
+static GTY(()) rtx eqdf_libfunc;
+static GTY(()) rtx nedf_libfunc;
+static GTY(()) rtx ledf_libfunc;
+static GTY(()) rtx ltdf_libfunc;
+static GTY(()) rtx gedf_libfunc;
+static GTY(()) rtx gtdf_libfunc;
+static GTY(()) rtx eqsf_libfunc;
+static GTY(()) rtx nesf_libfunc;
+static GTY(()) rtx lesf_libfunc;
+static GTY(()) rtx ltsf_libfunc;
+static GTY(()) rtx gesf_libfunc;
+static GTY(()) rtx gtsf_libfunc;
+static GTY(()) rtx strasgi_libfunc;
+static GTY(()) rtx strasgi64p_libfunc;
+
+/* Implement the TARGET_INIT_LIBFUNCS macro.  We use this to rename library
+   functions to match the C6x ABI.  */
+
+static void
+c6x_init_libfuncs (void)
+{
+  /* Double-precision floating-point arithmetic.  */
+  set_optab_libfunc (add_optab, DFmode, "__c6xabi_addd");
+  set_optab_libfunc (sdiv_optab, DFmode, "__c6xabi_divd");
+  set_optab_libfunc (smul_optab, DFmode, "__c6xabi_mpyd");
+  set_optab_libfunc (neg_optab, DFmode, "__c6xabi_negd");
+  set_optab_libfunc (sub_optab, DFmode, "__c6xabi_subd");
+
+  /* Single-precision floating-point arithmetic.  */
+  set_optab_libfunc (add_optab, SFmode, "__c6xabi_addf");
+  set_optab_libfunc (sdiv_optab, SFmode, "__c6xabi_divf");
+  set_optab_libfunc (smul_optab, SFmode, "__c6xabi_mpyf");
+  set_optab_libfunc (neg_optab, SFmode, "__c6xabi_negf");
+  set_optab_libfunc (sub_optab, SFmode, "__c6xabi_subf");
+
+  /* Floating-point comparisons.  */
+  eqsf_libfunc = init_one_libfunc ("__c6xabi_eqf");
+  nesf_libfunc = init_one_libfunc ("__c6xabi_neqf");
+  lesf_libfunc = init_one_libfunc ("__c6xabi_lef");
+  ltsf_libfunc = init_one_libfunc ("__c6xabi_ltf");
+  gesf_libfunc = init_one_libfunc ("__c6xabi_gef");
+  gtsf_libfunc = init_one_libfunc ("__c6xabi_gtf");
+  eqdf_libfunc = init_one_libfunc ("__c6xabi_eqd");
+  nedf_libfunc = init_one_libfunc ("__c6xabi_neqd");
+  ledf_libfunc = init_one_libfunc ("__c6xabi_led");
+  ltdf_libfunc = init_one_libfunc ("__c6xabi_ltd");
+  gedf_libfunc = init_one_libfunc ("__c6xabi_ged");
+  gtdf_libfunc = init_one_libfunc ("__c6xabi_gtd");
+
+  set_optab_libfunc (eq_optab, SFmode, NULL);
+  set_optab_libfunc (ne_optab, SFmode, "__c6xabi_neqf");
+  set_optab_libfunc (gt_optab, SFmode, NULL);
+  set_optab_libfunc (ge_optab, SFmode, NULL);
+  set_optab_libfunc (lt_optab, SFmode, NULL);
+  set_optab_libfunc (le_optab, SFmode, NULL);
+  set_optab_libfunc (unord_optab, SFmode, "__c6xabi_unordf");
+  set_optab_libfunc (eq_optab, DFmode, NULL);
+  set_optab_libfunc (ne_optab, DFmode, "__c6xabi_neqd");
+  set_optab_libfunc (gt_optab, DFmode, NULL);
+  set_optab_libfunc (ge_optab, DFmode, NULL);
+  set_optab_libfunc (lt_optab, DFmode, NULL);
+  set_optab_libfunc (le_optab, DFmode, NULL);
+  set_optab_libfunc (unord_optab, DFmode, "__c6xabi_unordd");
+
+  /* Floating-point to integer conversions.  */
+  set_conv_libfunc (sfix_optab, SImode, DFmode, "__c6xabi_fixdi");
+  set_conv_libfunc (ufix_optab, SImode, DFmode, "__c6xabi_fixdu");
+  set_conv_libfunc (sfix_optab, DImode, DFmode, "__c6xabi_fixdlli");
+  set_conv_libfunc (ufix_optab, DImode, DFmode, "__c6xabi_fixdull");
+  set_conv_libfunc (sfix_optab, SImode, SFmode, "__c6xabi_fixfi");
+  set_conv_libfunc (ufix_optab, SImode, SFmode, "__c6xabi_fixfu");
+  set_conv_libfunc (sfix_optab, DImode, SFmode, "__c6xabi_fixflli");
+  set_conv_libfunc (ufix_optab, DImode, SFmode, "__c6xabi_fixfull");
+
+  /* Conversions between floating types.  */
+  set_conv_libfunc (trunc_optab, SFmode, DFmode, "__c6xabi_cvtdf");
+  set_conv_libfunc (sext_optab, DFmode, SFmode, "__c6xabi_cvtfd");
+
+  /* Integer to floating-point conversions.  */
+  set_conv_libfunc (sfloat_optab, DFmode, SImode, "__c6xabi_fltid");
+  set_conv_libfunc (ufloat_optab, DFmode, SImode, "__c6xabi_fltud");
+  set_conv_libfunc (sfloat_optab, DFmode, DImode, "__c6xabi_fltllid");
+  set_conv_libfunc (ufloat_optab, DFmode, DImode, "__c6xabi_fltulld");
+  set_conv_libfunc (sfloat_optab, SFmode, SImode, "__c6xabi_fltif");
+  set_conv_libfunc (ufloat_optab, SFmode, SImode, "__c6xabi_fltuf");
+  set_conv_libfunc (sfloat_optab, SFmode, DImode, "__c6xabi_fltllif");
+  set_conv_libfunc (ufloat_optab, SFmode, DImode, "__c6xabi_fltullf");
+
+  /* Long long.  */
+  set_optab_libfunc (smul_optab, DImode, "__c6xabi_mpyll");
+  set_optab_libfunc (ashl_optab, DImode, "__c6xabi_llshl");
+  set_optab_libfunc (lshr_optab, DImode, "__c6xabi_llshru");
+  set_optab_libfunc (ashr_optab, DImode, "__c6xabi_llshr");
+
+  set_optab_libfunc (sdiv_optab, SImode, "__c6xabi_divi");
+  set_optab_libfunc (udiv_optab, SImode, "__c6xabi_divu");
+  set_optab_libfunc (smod_optab, SImode, "__c6xabi_remi");
+  set_optab_libfunc (umod_optab, SImode, "__c6xabi_remu");
+  set_optab_libfunc (sdivmod_optab, SImode, "__c6xabi_divremi");
+  set_optab_libfunc (udivmod_optab, SImode, "__c6xabi_divremu");
+  set_optab_libfunc (sdiv_optab, DImode, "__c6xabi_divlli");
+  set_optab_libfunc (udiv_optab, DImode, "__c6xabi_divull");
+  set_optab_libfunc (smod_optab, DImode, "__c6xabi_remlli");
+  set_optab_libfunc (umod_optab, DImode, "__c6xabi_remull");
+  set_optab_libfunc (udivmod_optab, DImode, "__c6xabi_divremull");
+
+  /* Block move.  */
+  strasgi_libfunc = init_one_libfunc ("__c6xabi_strasgi");
+  strasgi64p_libfunc = init_one_libfunc ("__c6xabi_strasgi_64plus");
+}
+
+/* Begin the assembly file.  */
+
+static void
+c6x_file_start (void)
+{
+  /* Variable tracking should be run after all optimizations which change order
+     of insns.  It also needs a valid CFG.  This can't be done in
+     c6x_override_options, because flag_var_tracking is finalized after
+     that.  */
+  c6x_flag_var_tracking = flag_var_tracking;
+  flag_var_tracking = 0;
+
+  done_cfi_sections = false;
+  default_file_start ();
+
+  /* Arrays are aligned to 8-byte boundaries.  */
+  asm_fprintf (asm_out_file,
+              "\t.c6xabi_attribute Tag_ABI_array_object_alignment, 0\n");
+  asm_fprintf (asm_out_file,
+              "\t.c6xabi_attribute Tag_ABI_array_object_align_expected, 0\n");
+
+  /* Stack alignment is 8 bytes.  */
+  asm_fprintf (asm_out_file,
+              "\t.c6xabi_attribute Tag_ABI_stack_align_needed, 0\n");
+  asm_fprintf (asm_out_file,
+              "\t.c6xabi_attribute Tag_ABI_stack_align_preserved, 0\n");
+
+#if 0 /* FIXME: Reenable when TI's tools are fixed.  */
+  /* ??? Ideally we'd check flag_short_wchar somehow.  */
+  asm_fprintf (asm_out_file, "\t.c6xabi_attribute Tag_ABI_wchar_t, %d\n", 2);
+#endif
+
+  /* We conform to version 1.0 of the ABI.  */
+  asm_fprintf (asm_out_file,
+              "\t.c6xabi_attribute Tag_ABI_conformance, \"1.0\"\n");
+
+}
+
+/* The LTO frontend only enables exceptions when it sees a function that
+   uses it.  This changes the return value of dwarf2out_do_frame, so we
+   have to check before every function.  */
+
+void
+c6x_output_file_unwind (FILE * f)
+{
+  if (done_cfi_sections)
+    return;
+
+  /* Output a .cfi_sections directive if we aren't
+     already doing so for debug info.  */
+  if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG
+           && dwarf2out_do_frame ())
+    {
+      asm_fprintf (f, "\t.cfi_sections .c6xabi.exidx\n");
+      done_cfi_sections = true;
+    }
+}
+
+/* Output unwind directives at the end of a function.  */
+
+static void
+c6x_output_fn_unwind (FILE * f)
+{
+  /* Return immediately if we are not generating unwinding tables.  */
+  if (! (flag_unwind_tables || flag_exceptions))
+    return;
+
+  /* If this function will never be unwound, then mark it as such.  */
+  if (!(flag_unwind_tables || crtl->uses_eh_lsda)
+      && (TREE_NOTHROW (current_function_decl)
+         || crtl->all_throwers_are_sibcalls))
+    fputs("\t.cantunwind\n", f);
+
+  fputs ("\t.endp\n", f);
+}
+
+\f
+/* Stack and Calling.  */
+
+int argument_registers[10] =
+{
+  REG_A4, REG_B4,
+  REG_A6, REG_B6,
+  REG_A8, REG_B8,
+  REG_A10, REG_B10,
+  REG_A12, REG_B12
+};
+
+/* Implements the macro INIT_CUMULATIVE_ARGS defined in c6x.h.  */
+
+void
+c6x_init_cumulative_args (CUMULATIVE_ARGS *cum, const_tree fntype, rtx libname,
+                         int n_named_args ATTRIBUTE_UNUSED)
+{
+  cum->count = 0;
+  cum->nregs = 10;
+  if (!libname && fntype)
+    {
+      /* We need to find out the number of named arguments.  Unfortunately,
+        for incoming arguments, N_NAMED_ARGS is set to -1.  */
+      if (stdarg_p (fntype))
+       cum->nregs = type_num_arguments (fntype) - 1;
+      if (cum->nregs > 10)
+       cum->nregs = 10;
+    }
+}
+
+/* Implements the macro FUNCTION_ARG defined in c6x.h.  */
+
+static rtx
+c6x_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
+                 const_tree type, bool named ATTRIBUTE_UNUSED)
+{
+  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
+  if (cum->count >= cum->nregs)
+    return NULL_RTX;
+  if (type)
+    {
+      HOST_WIDE_INT size = int_size_in_bytes (type);
+      if (TARGET_BIG_ENDIAN && AGGREGATE_TYPE_P (type))
+       {
+         if (size > 4)
+           {
+             rtx reg1 = gen_rtx_REG (SImode, argument_registers[cum->count] + 1);
+             rtx reg2 = gen_rtx_REG (SImode, argument_registers[cum->count]);
+             rtvec vec = gen_rtvec (2, gen_rtx_EXPR_LIST (VOIDmode, reg1, const0_rtx),
+                                    gen_rtx_EXPR_LIST (VOIDmode, reg2, GEN_INT (4)));
+             return gen_rtx_PARALLEL (mode, vec);
+           }
+       }
+    }
+  return gen_rtx_REG (mode, argument_registers[cum->count]);
+}
+
+static void
+c6x_function_arg_advance (cumulative_args_t cum_v,
+                         enum machine_mode mode ATTRIBUTE_UNUSED,
+                         const_tree type ATTRIBUTE_UNUSED,
+                         bool named ATTRIBUTE_UNUSED)
+{
+  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
+  cum->count++;
+}
+
+
+/* Return true if BLOCK_REG_PADDING (MODE, TYPE, FIRST) should return
+   upward rather than downward.  */
+
+bool
+c6x_block_reg_pad_upward (enum machine_mode mode ATTRIBUTE_UNUSED,
+                         const_tree type, bool first)
+{
+  HOST_WIDE_INT size;
+
+  if (!TARGET_BIG_ENDIAN)
+    return true;
+  if (!first)
+    return true;
+  if (!type)
+    return true;
+  size = int_size_in_bytes (type);
+  return size == 3;
+}
+
+/* Implement TARGET_FUNCTION_ARG_BOUNDARY.  */
+
+static unsigned int
+c6x_function_arg_boundary (enum machine_mode mode, const_tree type)
+{
+  unsigned int boundary = type ? TYPE_ALIGN (type) : GET_MODE_BITSIZE (mode);
+
+  if (boundary > BITS_PER_WORD)
+    return 2 * BITS_PER_WORD;
+
+  if (mode == BLKmode)
+    {
+      HOST_WIDE_INT size = int_size_in_bytes (type);
+      if (size > 4)
+       return 2 * BITS_PER_WORD;
+      if (boundary < BITS_PER_WORD)
+       {
+         if (size >= 3)
+           return BITS_PER_WORD;
+         if (size >= 2)
+           return 2 * BITS_PER_UNIT;
+       }
+    }
+  return boundary;
+}
+
+/* Implement TARGET_FUNCTION_ARG_ROUND_BOUNDARY.  */
+static unsigned int
+c6x_function_arg_round_boundary (enum machine_mode mode, const_tree type)
+{
+  return c6x_function_arg_boundary (mode, type);
+}
+
+/* TARGET_FUNCTION_VALUE implementation.  Returns an RTX representing the place
+   where function FUNC returns or receives a value of data type TYPE.  */
+
+static rtx
+c6x_function_value (const_tree type, const_tree func ATTRIBUTE_UNUSED,
+                   bool outgoing ATTRIBUTE_UNUSED)
+{
+  /* Functions return values in register A4.  When returning aggregates, we may
+     have to adjust for endianness.  */
+  if (TARGET_BIG_ENDIAN && type && AGGREGATE_TYPE_P (type))
+    {
+      HOST_WIDE_INT size = int_size_in_bytes (type);
+      if (size > 4)
+       {
+
+         rtx reg1 = gen_rtx_REG (SImode, REG_A4 + 1);
+         rtx reg2 = gen_rtx_REG (SImode, REG_A4);
+         rtvec vec = gen_rtvec (2, gen_rtx_EXPR_LIST (VOIDmode, reg1, const0_rtx),
+                                gen_rtx_EXPR_LIST (VOIDmode, reg2, GEN_INT (4)));
+         return gen_rtx_PARALLEL (TYPE_MODE (type), vec);
+       }
+    }
+  return gen_rtx_REG (TYPE_MODE (type), REG_A4);
+}
+
+/* Implement TARGET_LIBCALL_VALUE.  */
+
+static rtx
+c6x_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
+{
+  return gen_rtx_REG (mode, REG_A4);
+}
+
+/* TARGET_STRUCT_VALUE_RTX implementation.  */
+
+static rtx
+c6x_struct_value_rtx (tree type ATTRIBUTE_UNUSED, int incoming ATTRIBUTE_UNUSED)
+{
+  return gen_rtx_REG (Pmode, REG_A3);
+}
+
+/* Implement TARGET_FUNCTION_VALUE_REGNO_P.  */
+
+static bool
+c6x_function_value_regno_p (const unsigned int regno)
+{
+  return regno == REG_A4;
+}
+
+/* Types larger than 64 bit, and variable sized types, are passed by
+   reference.  The callee must copy them; see c6x_callee_copies.  */
+
+static bool
+c6x_pass_by_reference (cumulative_args_t cum_v ATTRIBUTE_UNUSED,
+                      enum machine_mode mode, const_tree type,
+                      bool named ATTRIBUTE_UNUSED)
+{
+  int size = -1;
+  if (type)
+    size = int_size_in_bytes (type);
+  else if (mode != VOIDmode)
+    size = GET_MODE_SIZE (mode);
+  return size > 2 * UNITS_PER_WORD || size == -1;
+}
+
+/* Decide whether a type should be returned in memory (true)
+   or in a register (false).  This is called by the macro
+   TARGET_RETURN_IN_MEMORY.  */
+
+static bool
+c6x_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
+{
+  int size = int_size_in_bytes (type);
+  return size > 2 * UNITS_PER_WORD || size == -1;
+}
+
+/* Values which must be returned in the most-significant end of the return
+   register.  */
+
+static bool
+c6x_return_in_msb (const_tree valtype)
+{
+  HOST_WIDE_INT size = int_size_in_bytes (valtype);
+  return TARGET_BIG_ENDIAN && AGGREGATE_TYPE_P (valtype) && size == 3;
+}
+
+/* Implement TARGET_CALLEE_COPIES.  */
+
+static bool
+c6x_callee_copies (cumulative_args_t cum_v ATTRIBUTE_UNUSED,
+                  enum machine_mode mode ATTRIBUTE_UNUSED,
+                  const_tree type ATTRIBUTE_UNUSED,
+                  bool named ATTRIBUTE_UNUSED)
+{
+  return true;
+}
+
+/* Return the type to use as __builtin_va_list.  */
+static tree
+c6x_build_builtin_va_list (void)
+{
+  return build_pointer_type (char_type_node);
+}
+\f
+static void
+c6x_asm_trampoline_template (FILE *f)
+{
+  fprintf (f, "\t.long\t0x0000002b\n"); /* mvkl .s2 fnlow,B0 */
+  fprintf (f, "\t.long\t0x01000028\n"); /* || mvkl .s1 sclow,A2 */
+  fprintf (f, "\t.long\t0x0000006b\n"); /* mvkh .s2 fnhigh,B0 */
+  fprintf (f, "\t.long\t0x01000068\n"); /* || mvkh .s1 schigh,A2 */
+  fprintf (f, "\t.long\t0x00000362\n"); /* b .s2 B0 */
+  fprintf (f, "\t.long\t0x00008000\n"); /* nop 5 */
+  fprintf (f, "\t.long\t0x00000000\n"); /* nop */
+  fprintf (f, "\t.long\t0x00000000\n"); /* nop */
+}
+
+/* Emit RTL insns to initialize the variable parts of a trampoline at
+   TRAMP. FNADDR is an RTX for the address of the function's pure
+   code.  CXT is an RTX for the static chain value for the function.  */
+
+static void
+c6x_initialize_trampoline (rtx tramp, tree fndecl, rtx cxt)
+{
+  rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
+  rtx t1 = copy_to_reg (fnaddr);
+  rtx t2 = copy_to_reg (cxt);
+  rtx mask = gen_reg_rtx (SImode);
+  int i;
+
+  emit_block_move (tramp, assemble_trampoline_template (),
+                  GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
+
+  emit_move_insn (mask, GEN_INT (0xffff << 7));
+
+  for (i = 0; i < 4; i++)
+    {
+      rtx mem = adjust_address (tramp, SImode, i * 4);
+      rtx t = (i & 1) ? t2 : t1;
+      rtx v1 = gen_reg_rtx (SImode);
+      rtx v2 = gen_reg_rtx (SImode);
+      emit_move_insn (v1, mem);
+      if (i < 2)
+       emit_insn (gen_ashlsi3 (v2, t, GEN_INT (7)));
+      else
+       emit_insn (gen_lshrsi3 (v2, t, GEN_INT (9)));
+      emit_insn (gen_andsi3 (v2, v2, mask));
+      emit_insn (gen_iorsi3 (v2, v2, v1));
+      emit_move_insn (mem, v2);
+    }
+#ifdef CLEAR_INSN_CACHE
+  tramp = XEXP (tramp, 0);
+  emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__gnu_clear_cache"),
+                    LCT_NORMAL, VOIDmode, 2, tramp, Pmode,
+                    plus_constant (tramp, TRAMPOLINE_SIZE), Pmode);
+#endif
+}
+\f
+/* Determine whether c6x_output_mi_thunk can succeed.  */
+
+static bool
+c6x_can_output_mi_thunk (const_tree thunk ATTRIBUTE_UNUSED,
+                        HOST_WIDE_INT delta ATTRIBUTE_UNUSED,
+                        HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
+                        const_tree function ATTRIBUTE_UNUSED)
+{
+  return !TARGET_LONG_CALLS;
+}
+
+/* Output the assembler code for a thunk function.  THUNK is the
+   declaration for the thunk function itself, FUNCTION is the decl for
+   the target function.  DELTA is an immediate constant offset to be
+   added to THIS.  If VCALL_OFFSET is nonzero, the word at
+   *(*this + vcall_offset) should be added to THIS.  */
+
+static void
+c6x_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
+                    tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta,
+                    HOST_WIDE_INT vcall_offset, tree function)
+{
+  rtx xops[5];
+  /* The this parameter is passed as the first argument.  */
+  rtx this_rtx = gen_rtx_REG (Pmode, REG_A4);
+
+  c6x_current_insn = NULL_RTX;
+
+  xops[4] = XEXP (DECL_RTL (function), 0);
+  if (!vcall_offset)
+    {
+      output_asm_insn ("b .s2 \t%4", xops);
+      if (!delta)
+       output_asm_insn ("nop 5", xops);
+    }
+
+  /* Adjust the this parameter by a fixed constant.  */
+  if (delta)
+    {
+      xops[0] = GEN_INT (delta);
+      xops[1] = this_rtx;
+      if (delta >= -16 && delta <= 15)
+       {
+         output_asm_insn ("add .s1 %0, %1, %1", xops);
+         if (!vcall_offset)
+           output_asm_insn ("nop 4", xops);
+       }
+      else if (delta >= 16 && delta < 32)
+       {
+         output_asm_insn ("add .d1 %0, %1, %1", xops);
+         if (!vcall_offset)
+           output_asm_insn ("nop 4", xops);
+       }
+      else if (delta >= -32768 && delta < 32768)
+       {
+         output_asm_insn ("mvk .s1 %0, A0", xops);
+         output_asm_insn ("add .d1 %1, A0, %1", xops);
+         if (!vcall_offset)
+           output_asm_insn ("nop 3", xops);
+       }
+      else
+       {
+         output_asm_insn ("mvkl .s1 %0, A0", xops);
+         output_asm_insn ("mvkh .s1 %0, A0", xops);
+         output_asm_insn ("add .d1 %1, A0, %1", xops);
+         if (!vcall_offset)
+           output_asm_insn ("nop 3", xops);
+       }
+    }
+
+  /* Adjust the this parameter by a value stored in the vtable.  */
+  if (vcall_offset)
+    {
+      rtx a0tmp = gen_rtx_REG (Pmode, REG_A0);
+      rtx a3tmp = gen_rtx_REG (Pmode, REG_A3);
+
+      xops[1] = a3tmp;
+      xops[2] = a0tmp;
+      xops[3] = gen_rtx_MEM (Pmode, a0tmp);
+      output_asm_insn ("mv .s1 a4, %2", xops);
+      output_asm_insn ("ldw .d1t1 %3, %2", xops);
+
+      /* Adjust the this parameter.  */
+      xops[0] = gen_rtx_MEM (Pmode, plus_constant (a0tmp, vcall_offset));
+      if (!memory_operand (xops[0], Pmode))
+       {
+         rtx tmp2 = gen_rtx_REG (Pmode, REG_A1);
+         xops[0] = GEN_INT (vcall_offset);
+         xops[1] = tmp2;
+         output_asm_insn ("mvkl .s1 %0, %1", xops);
+         output_asm_insn ("mvkh .s1 %0, %1", xops);
+         output_asm_insn ("nop 2", xops);
+         output_asm_insn ("add .d1 %2, %1, %2", xops);
+         xops[0] = gen_rtx_MEM (Pmode, a0tmp);
+       }
+      else
+       output_asm_insn ("nop 4", xops);
+      xops[2] = this_rtx;
+      output_asm_insn ("ldw .d1t1 %0, %1", xops);
+      output_asm_insn ("|| b .s2 \t%4", xops);
+      output_asm_insn ("nop 4", xops);
+      output_asm_insn ("add .d1 %2, %1, %2", xops);
+    }
+}
+\f
+/* Return true if EXP goes in small data/bss.  */
+
+static bool
+c6x_in_small_data_p (const_tree exp)
+{
+  /* We want to merge strings, so we never consider them small data.  */
+  if (TREE_CODE (exp) == STRING_CST)
+    return false;
+
+  /* Functions are never small data.  */
+  if (TREE_CODE (exp) == FUNCTION_DECL)
+    return false;
+
+  if (TREE_CODE (exp) == VAR_DECL && DECL_WEAK (exp))
+    return false;
+
+  if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp))
+    {
+      const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (exp));
+
+      if (strcmp (section, ".neardata") == 0
+         || strncmp (section, ".neardata.", 10) == 0
+         || strncmp (section, ".gnu.linkonce.s.", 16) == 0
+         || strcmp (section, ".bss") == 0
+         || strncmp (section, ".bss.", 5) == 0
+         || strncmp (section, ".gnu.linkonce.sb.", 17) == 0
+         || strcmp (section, ".rodata") == 0
+         || strncmp (section, ".rodata.", 8) == 0
+         || strncmp (section, ".gnu.linkonce.s2.", 17) == 0)
+       return true;
+    }
+  else
+    return PLACE_IN_SDATA_P (exp);
+
+  return false;
+}
+
+/* Return a section for X.  The only special thing we do here is to
+   honor small data.  We don't have a tree type, so we can't use the
+   PLACE_IN_SDATA_P macro we use everywhere else; we choose to place
+   everything sized 8 bytes or smaller into small data.  */
+
+static section *
+c6x_select_rtx_section (enum machine_mode mode, rtx x,
+                       unsigned HOST_WIDE_INT align)
+{
+  if (c6x_sdata_mode == C6X_SDATA_ALL
+      || (c6x_sdata_mode != C6X_SDATA_NONE && GET_MODE_SIZE (mode) <= 8))
+    /* ??? Consider using mergeable sdata sections.  */
+    return sdata_section;
+  else
+    return default_elf_select_rtx_section (mode, x, align);
+}
+
+static section *
+c6x_elf_select_section (tree decl, int reloc,
+                       unsigned HOST_WIDE_INT align)
+{
+  const char *sname = NULL;
+  unsigned int flags = SECTION_WRITE;
+  if (c6x_in_small_data_p (decl))
+    {
+      switch (categorize_decl_for_section (decl, reloc))
+       {
+       case SECCAT_SRODATA:
+         sname = ".rodata";
+         flags = 0;
+         break;
+       case SECCAT_SDATA:
+         sname = ".neardata";
+         break;
+       case SECCAT_SBSS:
+         sname = ".bss";
+         flags |= SECTION_BSS;
+       default:
+         break;
+       }
+    }
+  else
+    {
+      switch (categorize_decl_for_section (decl, reloc))
+       {
+       case SECCAT_DATA:
+         sname = ".fardata";
+         break;
+       case SECCAT_DATA_REL:
+         sname = ".fardata.rel";
+         break;
+       case SECCAT_DATA_REL_LOCAL:
+         sname = ".fardata.rel.local";
+         break;
+       case SECCAT_DATA_REL_RO:
+         sname = ".fardata.rel.ro";
+         break;
+       case SECCAT_DATA_REL_RO_LOCAL:
+         sname = ".fardata.rel.ro.local";
+         break;
+       case SECCAT_BSS:
+         sname = ".far";
+         flags |= SECTION_BSS;
+         break;
+       case SECCAT_RODATA:
+         sname = ".const";
+         flags = 0;
+         break;
+       case SECCAT_SRODATA:
+       case SECCAT_SDATA:
+       case SECCAT_SBSS:
+         gcc_unreachable ();
+       default:
+         break;
+       }
+    }
+  if (sname)
+    {
+      /* We might get called with string constants, but get_named_section
+        doesn't like them as they are not DECLs.  Also, we need to set
+        flags in that case.  */
+      if (!DECL_P (decl))
+       return get_section (sname, flags, NULL);
+      return get_named_section (decl, sname, reloc);
+    }
+
+  return default_elf_select_section (decl, reloc, align);
+}
+
+/* Build up a unique section name, expressed as a
+   STRING_CST node, and assign it to DECL_SECTION_NAME (decl).
+   RELOC indicates whether the initial value of EXP requires
+   link-time relocations.  */
+
+static void ATTRIBUTE_UNUSED
+c6x_elf_unique_section (tree decl, int reloc)
+{
+  const char *prefix = NULL;
+  /* We only need to use .gnu.linkonce if we don't have COMDAT groups.  */
+  bool one_only = DECL_ONE_ONLY (decl) && !HAVE_COMDAT_GROUP;
+
+  if (c6x_in_small_data_p (decl))
+    {
+      switch (categorize_decl_for_section (decl, reloc))
+       {
+       case SECCAT_SDATA:
+          prefix = one_only ? ".s" : ".neardata";
+         break;
+       case SECCAT_SBSS:
+          prefix = one_only ? ".sb" : ".bss";
+         break;
+       case SECCAT_SRODATA:
+          prefix = one_only ? ".s2" : ".rodata";
+         break;
+       case SECCAT_RODATA_MERGE_STR:
+       case SECCAT_RODATA_MERGE_STR_INIT:
+       case SECCAT_RODATA_MERGE_CONST:
+       case SECCAT_RODATA:
+       case SECCAT_DATA:
+       case SECCAT_DATA_REL:
+       case SECCAT_DATA_REL_LOCAL:
+       case SECCAT_DATA_REL_RO:
+       case SECCAT_DATA_REL_RO_LOCAL:
+         gcc_unreachable ();
+       default:
+         /* Everything else we place into default sections and hope for the
+            best.  */
+         break;
+       }
+    }
+  else
+    {
+      switch (categorize_decl_for_section (decl, reloc))
+       {
+       case SECCAT_DATA:
+       case SECCAT_DATA_REL:
+       case SECCAT_DATA_REL_LOCAL:
+       case SECCAT_DATA_REL_RO:
+       case SECCAT_DATA_REL_RO_LOCAL:
+          prefix = one_only ? ".fd" : ".fardata";
+         break;
+       case SECCAT_BSS:
+          prefix = one_only ? ".fb" : ".far";
+         break;
+       case SECCAT_RODATA:
+       case SECCAT_RODATA_MERGE_STR:
+       case SECCAT_RODATA_MERGE_STR_INIT:
+       case SECCAT_RODATA_MERGE_CONST:
+          prefix = one_only ? ".fr" : ".const";
+         break;
+       case SECCAT_SRODATA:
+       case SECCAT_SDATA:
+       case SECCAT_SBSS:
+         gcc_unreachable ();
+       default:
+         break;
+       }
+    }
+
+  if (prefix)
+    {
+      const char *name, *linkonce;
+      char *string;
+
+      name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+      name = targetm.strip_name_encoding (name);
+
+      /* If we're using one_only, then there needs to be a .gnu.linkonce
+        prefix to the section name.  */
+      linkonce = one_only ? ".gnu.linkonce" : "";
+
+      string = ACONCAT ((linkonce, prefix, ".", name, NULL));
+
+      DECL_SECTION_NAME (decl) = build_string (strlen (string), string);
+      return;
+    }
+  default_unique_section (decl, reloc);
+}
+
+static unsigned int
+c6x_section_type_flags (tree decl, const char *name, int reloc)
+{
+  unsigned int flags = 0;
+
+  if (strcmp (name, ".far") == 0
+      || strncmp (name, ".far.", 5) == 0)
+    flags |= SECTION_BSS;
+
+  flags |= default_section_type_flags (decl, name, reloc);
+
+  return flags;
+}
+\f
+/* Checks whether the given CALL_EXPR would use a caller saved
+   register.  This is used to decide whether sibling call optimization
+   could be performed on the respective function call.  */
+
+static bool
+c6x_call_saved_register_used (tree call_expr)
+{
+  CUMULATIVE_ARGS cum_v;
+  cumulative_args_t cum;
+  HARD_REG_SET call_saved_regset;
+  tree parameter;
+  enum machine_mode mode;
+  tree type;
+  rtx parm_rtx;
+  int i;
+
+  INIT_CUMULATIVE_ARGS (cum_v, NULL, NULL, 0, 0);
+  cum = pack_cumulative_args (&cum_v);
+
+  COMPL_HARD_REG_SET (call_saved_regset, call_used_reg_set);
+  for (i = 0; i < call_expr_nargs (call_expr); i++)
+    {
+      parameter = CALL_EXPR_ARG (call_expr, i);
+      gcc_assert (parameter);
+
+      /* For an undeclared variable passed as parameter we will get
+        an ERROR_MARK node here.  */
+      if (TREE_CODE (parameter) == ERROR_MARK)
+       return true;
+
+      type = TREE_TYPE (parameter);
+      gcc_assert (type);
+
+      mode = TYPE_MODE (type);
+      gcc_assert (mode);
+
+      if (pass_by_reference (&cum_v, mode, type, true))
+       {
+         mode = Pmode;
+         type = build_pointer_type (type);
+       }
+
+       parm_rtx = c6x_function_arg (cum, mode, type, 0);
+
+       c6x_function_arg_advance (cum, mode, type, 0);
+
+       if (!parm_rtx)
+        continue;
+
+       if (REG_P (parm_rtx)
+          && overlaps_hard_reg_set_p (call_saved_regset, GET_MODE (parm_rtx),
+                                      REGNO (parm_rtx)))
+        return true;
+       if (GET_CODE (parm_rtx) == PARALLEL)
+        {
+          int n = XVECLEN (parm_rtx, 0);
+          while (n-- > 0)
+            {
+              rtx x = XEXP (XVECEXP (parm_rtx, 0, n), 0);
+              if (REG_P (x)
+                  && overlaps_hard_reg_set_p (call_saved_regset,
+                                              GET_MODE (x), REGNO (x)))
+                return true;
+            }
+        }
+    }
+  return false;
+}
+
+/* Decide whether we can make a sibling call to a function.  DECL is the
+   declaration of the function being targeted by the call and EXP is the
+   CALL_EXPR representing the call.  */
+
+static bool
+c6x_function_ok_for_sibcall (tree decl, tree exp)
+{
+  /* Registers A10, A12, B10 and B12 are available as arguments
+     register but unfortunately caller saved. This makes functions
+     needing these registers for arguments not suitable for
+     sibcalls.  */
+  if (c6x_call_saved_register_used (exp))
+    return false;
+
+  if (!flag_pic)
+    return true;
+
+  if (TARGET_DSBT)
+    {
+      /* When compiling for DSBT, the calling function must be local,
+        so that when we reload B14 in the sibcall epilogue, it will
+        not change its value.  */
+      struct cgraph_local_info *this_func;
+
+      if (!decl)
+       /* Not enough information.  */
+       return false;
+
+      this_func = cgraph_local_info (current_function_decl);
+      return this_func->local;
+    }
+
+  return true;
+}
+
+/* Return true if DECL is known to be linked into section SECTION.  */
+
+static bool
+c6x_function_in_section_p (tree decl, section *section)
+{
+  /* We can only be certain about functions defined in the same
+     compilation unit.  */
+  if (!TREE_STATIC (decl))
+    return false;
+
+  /* Make sure that SYMBOL always binds to the definition in this
+     compilation unit.  */
+  if (!targetm.binds_local_p (decl))
+    return false;
+
+  /* If DECL_SECTION_NAME is set, assume it is trustworthy.  */
+  if (!DECL_SECTION_NAME (decl))
+    {
+      /* Make sure that we will not create a unique section for DECL.  */
+      if (flag_function_sections || DECL_ONE_ONLY (decl))
+       return false;
+    }
+
+  return function_section (decl) == section;
+}
+
+/* Return true if a call to OP, which is a SYMBOL_REF, must be expanded
+   as a long call.  */
+bool
+c6x_long_call_p (rtx op)
+{
+  tree decl;
+
+  if (!TARGET_LONG_CALLS)
+    return false;
+
+  decl = SYMBOL_REF_DECL (op);
+
+  /* Try to determine whether the symbol is in the same section as the current
+     function.  Be conservative, and only cater for cases in which the
+     whole of the current function is placed in the same section.  */
+  if (decl != NULL_TREE
+      && !flag_reorder_blocks_and_partition
+      && TREE_CODE (decl) == FUNCTION_DECL
+      && c6x_function_in_section_p (decl, current_function_section ()))
+    return false;
+
+  return true;
+}
+
+/* Emit the sequence for a call.  */
+void
+c6x_expand_call (rtx retval, rtx address, bool sibcall)
+{
+  rtx callee = XEXP (address, 0);
+  rtx call_insn;
+
+  if (!c6x_call_operand (callee, Pmode))
+    {
+      callee = force_reg (Pmode, callee);
+      address = change_address (address, Pmode, callee);
+    }
+  call_insn = gen_rtx_CALL (VOIDmode, address, const0_rtx);
+  if (sibcall)
+    {
+      call_insn = emit_call_insn (call_insn);
+      use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn),
+              gen_rtx_REG (Pmode, REG_B3));
+    }
+  else
+    {
+      if (retval == NULL_RTX)
+       call_insn = emit_call_insn (call_insn);
+      else
+       call_insn = emit_call_insn (gen_rtx_SET (GET_MODE (retval), retval,
+                                                call_insn));
+    }
+  if (flag_pic)
+    use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), pic_offset_table_rtx);
+}
+
+/* Legitimize PIC addresses.  If the address is already position-independent,
+   we return ORIG.  Newly generated position-independent addresses go into a
+   reg.  This is REG if nonzero, otherwise we allocate register(s) as
+   necessary.  PICREG is the register holding the pointer to the PIC offset
+   table.  */
+
+static rtx
+legitimize_pic_address (rtx orig, rtx reg, rtx picreg)
+{
+  rtx addr = orig;
+  rtx new_rtx = orig;
+
+  if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
+    {
+      int unspec = UNSPEC_LOAD_GOT;
+      rtx tmp;
+
+      if (reg == 0)
+       {
+         gcc_assert (can_create_pseudo_p ());
+         reg = gen_reg_rtx (Pmode);
+       }
+      if (flag_pic == 2)
+       {
+         if (can_create_pseudo_p ())
+           tmp = gen_reg_rtx (Pmode);
+         else
+           tmp = reg;
+         emit_insn (gen_movsi_gotoff_high (tmp, addr));
+         emit_insn (gen_movsi_gotoff_lo_sum (tmp, tmp, addr));
+         emit_insn (gen_load_got_gotoff (reg, picreg, tmp));
+       }
+      else
+       {
+         tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), unspec);
+         new_rtx = gen_const_mem (Pmode, gen_rtx_PLUS (Pmode, picreg, tmp));
+
+         emit_move_insn (reg, new_rtx);
+       }
+      if (picreg == pic_offset_table_rtx)
+       crtl->uses_pic_offset_table = 1;
+      return reg;
+    }
+
+  else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
+    {
+      rtx base;
+
+      if (GET_CODE (addr) == CONST)
+       {
+         addr = XEXP (addr, 0);
+         gcc_assert (GET_CODE (addr) == PLUS);
+       }
+
+      if (XEXP (addr, 0) == picreg)
+       return orig;
+
+      if (reg == 0)
+       {
+         gcc_assert (can_create_pseudo_p ());
+         reg = gen_reg_rtx (Pmode);
+       }
+
+      base = legitimize_pic_address (XEXP (addr, 0), reg, picreg);
+      addr = legitimize_pic_address (XEXP (addr, 1),
+                                    base == reg ? NULL_RTX : reg,
+                                    picreg);
+
+      if (GET_CODE (addr) == CONST_INT)
+       {
+         gcc_assert (! reload_in_progress && ! reload_completed);
+         addr = force_reg (Pmode, addr);
+       }
+
+      if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
+       {
+         base = gen_rtx_PLUS (Pmode, base, XEXP (addr, 0));
+         addr = XEXP (addr, 1);
+       }
+
+      return gen_rtx_PLUS (Pmode, base, addr);
+    }
+
+  return new_rtx;
+}
+
+/* Expand a move operation in mode MODE.  The operands are in OPERANDS.
+   Returns true if no further code must be generated, false if the caller
+   should generate an insn to move OPERANDS[1] to OPERANDS[0].  */
+
+bool
+expand_move (rtx *operands, enum machine_mode mode)
+{
+  rtx dest = operands[0];
+  rtx op = operands[1];
+
+  if ((reload_in_progress | reload_completed) == 0
+      && GET_CODE (dest) == MEM && GET_CODE (op) != REG)
+    operands[1] = force_reg (mode, op);
+  else if (mode == SImode && symbolic_operand (op, SImode))
+    {
+      if (flag_pic)
+       {
+         if (sdata_symbolic_operand (op, SImode))
+           {
+             emit_insn (gen_load_sdata_pic (dest, pic_offset_table_rtx, op));
+             crtl->uses_pic_offset_table = 1;
+             return true;
+           }
+         else
+           {
+             rtx temp = (reload_completed || reload_in_progress
+                         ? dest : gen_reg_rtx (Pmode));
+
+             operands[1] = legitimize_pic_address (op, temp,
+                                                   pic_offset_table_rtx);
+           }
+       }
+      else if (reload_completed
+              && !sdata_symbolic_operand (op, SImode))
+       {
+         emit_insn (gen_movsi_high (dest, op));
+         emit_insn (gen_movsi_lo_sum (dest, dest, op));
+         return true;
+       }
+    }
+  return false;
+}
+
+/* This function is called when we're about to expand an integer compare
+   operation which performs COMPARISON.  It examines the second operand,
+   and if it is an integer constant that cannot be used directly on the
+   current machine in a comparison insn, it returns true.  */
+bool
+c6x_force_op_for_comparison_p (enum rtx_code code, rtx op)
+{
+  if (!CONST_INT_P (op) || satisfies_constraint_Iu4 (op))
+    return false;
+
+  if ((code == EQ || code == LT || code == GT)
+       && !satisfies_constraint_Is5 (op))
+    return true;
+  if ((code == GTU || code == LTU)
+      && (!TARGET_INSNS_64 || !satisfies_constraint_Iu5 (op)))
+    return true;
+
+  return false;
+}
+
+/* Emit comparison instruction if necessary, returning the expression
+   that holds the compare result in the proper mode.  Return the comparison
+   that should be used in the jump insn.  */
+
+rtx
+c6x_expand_compare (rtx comparison, enum machine_mode mode)
+{
+  enum rtx_code code = GET_CODE (comparison);
+  rtx op0 = XEXP (comparison, 0);
+  rtx op1 = XEXP (comparison, 1);
+  rtx cmp;
+  enum rtx_code jump_code = code;
+  enum machine_mode op_mode = GET_MODE (op0);
+
+  if (op_mode == DImode && (code == NE || code == EQ) && op1 == const0_rtx)
+    {
+      rtx t = gen_reg_rtx (SImode);
+      emit_insn (gen_iorsi3 (t, gen_lowpart (SImode, op0),
+                            gen_highpart (SImode, op0)));
+      op_mode = SImode;
+      cmp = t;
+    }
+  else if (op_mode == DImode)
+    {
+      rtx lo[2], high[2];
+      rtx cmp1, cmp2;
+
+      if (code == NE || code == GEU || code == LEU || code == GE || code == LE)
+       {
+         code = reverse_condition (code);
+         jump_code = EQ;
+       }
+      else
+       jump_code = NE;
+
+      split_di (&op0, 1, lo, high);
+      split_di (&op1, 1, lo + 1, high + 1);
+
+      if (c6x_force_op_for_comparison_p (code, high[1])
+         || c6x_force_op_for_comparison_p (EQ, high[1]))
+       high[1] = force_reg (SImode, high[1]);
+
+      cmp1 = gen_reg_rtx (SImode);
+      cmp2 = gen_reg_rtx (SImode);
+      emit_insn (gen_rtx_SET (VOIDmode, cmp1,
+                             gen_rtx_fmt_ee (code, SImode, high[0], high[1])));
+      if (code == EQ)
+       {
+         if (c6x_force_op_for_comparison_p (code, lo[1]))
+           lo[1] = force_reg (SImode, lo[1]);
+         emit_insn (gen_rtx_SET (VOIDmode, cmp2,
+                                 gen_rtx_fmt_ee (code, SImode, lo[0], lo[1])));
+         emit_insn (gen_andsi3 (cmp1, cmp1, cmp2));
+       }
+      else
+       {
+         emit_insn (gen_rtx_SET (VOIDmode, cmp2,
+                                 gen_rtx_EQ (SImode, high[0], high[1])));
+         if (code == GT)
+           code = GTU;
+         else if (code == LT)
+           code = LTU;
+         if (c6x_force_op_for_comparison_p (code, lo[1]))
+           lo[1] = force_reg (SImode, lo[1]);
+         emit_insn (gen_cmpsi_and (cmp2, gen_rtx_fmt_ee (code, SImode,
+                                                         lo[0], lo[1]),
+                                   lo[0], lo[1], cmp2));
+         emit_insn (gen_iorsi3 (cmp1, cmp1, cmp2));
+       }
+      cmp = cmp1;
+    }
+  else if (TARGET_FP && !flag_finite_math_only
+          && (op_mode == DFmode || op_mode == SFmode)
+          && code != EQ && code != NE && code != LT && code != GT
+          && code != UNLE && code != UNGE)
+    {
+      enum rtx_code code1, code2, code3;
+      rtx (*fn) (rtx, rtx, rtx, rtx, rtx);
+
+      jump_code = NE;
+      code3 = UNKNOWN;
+      switch (code)
+       {
+       case UNLT:
+       case UNGT:
+         jump_code = EQ;
+         /* fall through */
+       case LE:
+       case GE:
+         code1 = code == LE || code == UNGT ? LT : GT;
+         code2 = EQ;
+         break;
+
+       case UNORDERED:
+         jump_code = EQ;
+         /* fall through */
+       case ORDERED:
+         code3 = EQ;
+         /* fall through */
+       case LTGT:
+         code1 = LT;
+         code2 = GT;
+         break;
+
+       case UNEQ:
+         code1 = LT;
+         code2 = GT;
+         jump_code = EQ;
+         break;
+
+       default:
+         gcc_unreachable ();
+       }
+
+      cmp = gen_reg_rtx (SImode);
+      emit_insn (gen_rtx_SET (VOIDmode, cmp,
+                             gen_rtx_fmt_ee (code1, SImode, op0, op1)));
+      fn = op_mode == DFmode ? gen_cmpdf_ior : gen_cmpsf_ior;
+      emit_insn (fn (cmp, gen_rtx_fmt_ee (code2, SImode, op0, op1),
+                    op0, op1, cmp));
+      if (code3 != UNKNOWN)
+       emit_insn (fn (cmp, gen_rtx_fmt_ee (code3, SImode, op0, op1),
+                      op0, op1, cmp));
+    }
+  else if (op_mode == SImode && (code == NE || code == EQ) && op1 == const0_rtx)
+    cmp = op0;
+  else
+    {
+      bool is_fp_libfunc;
+      is_fp_libfunc = !TARGET_FP && (op_mode == DFmode || op_mode == SFmode);
+
+      if ((code == NE || code == GEU || code == LEU || code == GE || code == LE)
+         && !is_fp_libfunc)
+       {
+         code = reverse_condition (code);
+         jump_code = EQ;
+       }
+      else if (code == UNGE)
+       {
+         code = LT;
+         jump_code = EQ;
+       }
+      else if (code == UNLE)
+       {
+         code = GT;
+         jump_code = EQ;
+       }
+      else
+       jump_code = NE;
+
+      if (is_fp_libfunc)
+       {
+         rtx insns;
+         rtx libfunc;
+         switch (code)
+           {
+           case EQ:
+             libfunc = op_mode == DFmode ? eqdf_libfunc : eqsf_libfunc;
+             break;
+           case NE:
+             libfunc = op_mode == DFmode ? nedf_libfunc : nesf_libfunc;
+             break;
+           case GT:
+             libfunc = op_mode == DFmode ? gtdf_libfunc : gtsf_libfunc;
+             break;
+           case GE:
+             libfunc = op_mode == DFmode ? gedf_libfunc : gesf_libfunc;
+             break;
+           case LT:
+             libfunc = op_mode == DFmode ? ltdf_libfunc : ltsf_libfunc;
+             break;
+           case LE:
+             libfunc = op_mode == DFmode ? ledf_libfunc : lesf_libfunc;
+             break;
+           default:
+             gcc_unreachable ();
+           }
+         start_sequence ();
+
+         cmp = emit_library_call_value (libfunc, 0, LCT_CONST, SImode, 2,
+                                        op0, op_mode, op1, op_mode);
+         insns = get_insns ();
+         end_sequence ();
+
+         emit_libcall_block (insns, cmp, cmp,
+                             gen_rtx_fmt_ee (code, SImode, op0, op1));
+       }
+      else
+       {
+         cmp = gen_reg_rtx (SImode);
+         if (c6x_force_op_for_comparison_p (code, op1))
+           op1 = force_reg (SImode, op1);
+         emit_insn (gen_rtx_SET (VOIDmode, cmp,
+                                 gen_rtx_fmt_ee (code, SImode, op0, op1)));
+       }
+    }
+
+  return gen_rtx_fmt_ee (jump_code, mode, cmp, const0_rtx);
+}
+
+/* Return one word of double-word value OP.  HIGH_P is true to select the
+   high part, false to select the low part.  When encountering auto-increment
+   addressing, we make the assumption that the low part is going to be accessed
+   first.  */
+
+rtx
+c6x_subword (rtx op, bool high_p)
+{
+  unsigned int byte;
+  enum machine_mode mode;
+
+  mode = GET_MODE (op);
+  if (mode == VOIDmode)
+    mode = DImode;
+
+  if (TARGET_BIG_ENDIAN ? !high_p : high_p)
+    byte = UNITS_PER_WORD;
+  else
+    byte = 0;
+
+  if (MEM_P (op))
+    {
+      rtx addr = XEXP (op, 0);
+      if (GET_CODE (addr) == PLUS || REG_P (addr))
+       return adjust_address (op, word_mode, byte);
+      /* FIXME: should really support autoincrement addressing for
+        multi-word modes.  */
+      gcc_unreachable ();
+    }
+
+  return simplify_gen_subreg (word_mode, op, mode, byte);
+}
+
+/* Split one or more DImode RTL references into pairs of SImode
+   references.  The RTL can be REG, offsettable MEM, integer constant, or
+   CONST_DOUBLE.  "operands" is a pointer to an array of DImode RTL to
+   split and "num" is its length.  lo_half and hi_half are output arrays
+   that parallel "operands".  */
+
+void
+split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
+{
+  while (num--)
+    {
+      rtx op = operands[num];
+
+      lo_half[num] = c6x_subword (op, false);
+      hi_half[num] = c6x_subword (op, true);
+    }
+}
+
+/* Return true if VAL is a mask valid for a clr instruction.  */
+bool
+c6x_valid_mask_p (HOST_WIDE_INT val)
+{
+  int i;
+  for (i = 0; i < 32; i++)
+    if (!(val & ((unsigned HOST_WIDE_INT)1 << i)))
+      break;
+  for (; i < 32; i++)
+    if (val & ((unsigned HOST_WIDE_INT)1 << i))
+      break;
+  for (; i < 32; i++)
+    if (!(val & ((unsigned HOST_WIDE_INT)1 << i)))
+      return false;
+  return true;
+}
+
+/* Expand a block move for a movmemM pattern.  */
+
+bool
+c6x_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp,
+                  rtx expected_align_exp ATTRIBUTE_UNUSED,
+                  rtx expected_size_exp ATTRIBUTE_UNUSED)
+{
+  unsigned HOST_WIDE_INT align = 1;
+  unsigned HOST_WIDE_INT src_mem_align, dst_mem_align, min_mem_align;
+  unsigned HOST_WIDE_INT count = 0, offset = 0;
+  unsigned int biggest_move = TARGET_STDW ? 8 : 4;
+
+  if (CONST_INT_P (align_exp))
+    align = INTVAL (align_exp);
+
+  src_mem_align = MEM_ALIGN (src) / BITS_PER_UNIT;
+  dst_mem_align = MEM_ALIGN (dst) / BITS_PER_UNIT;
+  min_mem_align = MIN (src_mem_align, dst_mem_align);
+
+  if (min_mem_align > align)
+    align = min_mem_align / BITS_PER_UNIT;
+  if (src_mem_align < align)
+    src_mem_align = align;
+  if (dst_mem_align < align)
+    dst_mem_align = align;
+
+  if (CONST_INT_P (count_exp))
+    count = INTVAL (count_exp);
+  else
+    return false;
+
+  /* Make sure we don't need to care about overflow later on.  */
+  if (count > ((unsigned HOST_WIDE_INT) 1 << 30))
+    return false;
+
+  if (count >= 28 && (count & 3) == 0 && align >= 4)
+    {
+      tree dst_expr = MEM_EXPR (dst);
+      tree src_expr = MEM_EXPR (src);
+      rtx fn = TARGET_INSNS_64PLUS ? strasgi64p_libfunc : strasgi_libfunc;
+      rtx srcreg = force_reg (Pmode, XEXP (src, 0));
+      rtx dstreg = force_reg (Pmode, XEXP (dst, 0));
+
+      if (src_expr)
+       mark_addressable (src_expr);
+      if (dst_expr)
+       mark_addressable (dst_expr);
+      emit_library_call (fn, LCT_NORMAL, VOIDmode, 3,
+                        dstreg, Pmode, srcreg, Pmode, count_exp, SImode);
+      return true;
+    }
+
+  if (biggest_move > align && !TARGET_INSNS_64)
+    biggest_move = align;
+
+  if (count / biggest_move > 7)
+    return false;
+
+  while (count > 0)
+    {
+      rtx reg, reg_lowpart;
+      enum machine_mode srcmode, dstmode;
+      unsigned HOST_WIDE_INT src_size, dst_size, src_left;
+      int shift;
+      rtx srcmem, dstmem;
+
+      while (biggest_move > count)
+       biggest_move /= 2;
+
+      src_size = dst_size = biggest_move;
+      if (src_size > src_mem_align && src_size == 2)
+       src_size = 1;
+      if (dst_size > dst_mem_align && dst_size == 2)
+       dst_size = 1;
+
+      if (dst_size > src_size)
+       dst_size = src_size;
+
+      srcmode = mode_for_size (src_size * BITS_PER_UNIT, MODE_INT, 0);
+      dstmode = mode_for_size (dst_size * BITS_PER_UNIT, MODE_INT, 0);
+      if (src_size >= 4)
+       reg_lowpart = reg = gen_reg_rtx (srcmode);
+      else
+       {
+         reg = gen_reg_rtx (SImode);
+         reg_lowpart = gen_lowpart (srcmode, reg);
+       }
+
+      srcmem = adjust_address (copy_rtx (src), srcmode, offset);
+
+      if (src_size > src_mem_align)
+       {
+         enum insn_code icode = (srcmode == SImode ? CODE_FOR_movmisalignsi
+                                 : CODE_FOR_movmisaligndi);
+         emit_insn (GEN_FCN (icode) (reg_lowpart, srcmem));
+       }
+      else
+       emit_move_insn (reg_lowpart, srcmem);
+
+      src_left = src_size;
+      shift = TARGET_BIG_ENDIAN ? (src_size - dst_size) * BITS_PER_UNIT  : 0;
+      while (src_left > 0)
+       {
+         rtx dstreg = reg_lowpart;
+
+         if (src_size > dst_size)
+           {
+             rtx srcword = reg;
+             int shift_amount = shift & (BITS_PER_WORD - 1);
+             if (src_size > 4)
+               srcword = operand_subword_force (srcword, src_left >= 4 ? 0 : 4,
+                                                SImode);
+             if (shift_amount > 0)
+               {
+                 dstreg = gen_reg_rtx (SImode);
+                 emit_insn (gen_lshrsi3 (dstreg, srcword,
+                                         GEN_INT (shift_amount)));
+               }
+             else
+               dstreg = srcword;
+             dstreg = gen_lowpart (dstmode, dstreg);
+           }
+
+         dstmem = adjust_address (copy_rtx (dst), dstmode, offset);
+         if (dst_size > dst_mem_align)
+           {
+             enum insn_code icode = (dstmode == SImode ? CODE_FOR_movmisalignsi
+                                     : CODE_FOR_movmisaligndi);
+             emit_insn (GEN_FCN (icode) (dstmem, dstreg));
+           }
+         else
+           emit_move_insn (dstmem, dstreg);
+
+         if (TARGET_BIG_ENDIAN)
+           shift -= dst_size * BITS_PER_UNIT;
+         else
+           shift += dst_size * BITS_PER_UNIT;
+         offset += dst_size;
+         src_left -= dst_size;
+       }
+      count -= src_size;
+    }
+  return true;
+}
+\f
+/* Subroutine of print_address_operand, print a single address offset OFF for
+   a memory access of mode MEM_MODE, choosing between normal form and scaled
+   form depending on the type of the insn.  Misaligned memory references must
+   use the scaled form.  */
+
+static void
+print_address_offset (FILE *file, rtx off, enum machine_mode mem_mode)
+{
+  rtx pat;
+
+  if (c6x_current_insn != NULL_RTX)
+    {
+      pat = PATTERN (c6x_current_insn);
+      if (GET_CODE (pat) == COND_EXEC)
+       pat = COND_EXEC_CODE (pat);
+      if (GET_CODE (pat) == PARALLEL)
+       pat = XVECEXP (pat, 0, 0);
+
+      if (GET_CODE (pat) == SET
+         && GET_CODE (SET_SRC (pat)) == UNSPEC
+         && XINT (SET_SRC (pat), 1) == UNSPEC_MISALIGNED_ACCESS)
+       {
+         gcc_assert (CONST_INT_P (off)
+                     && (INTVAL (off) & (GET_MODE_SIZE (mem_mode) - 1)) == 0);
+         fprintf (file, "[" HOST_WIDE_INT_PRINT_DEC "]",
+                  INTVAL (off) / GET_MODE_SIZE (mem_mode));
+         return;
+       }
+    }
+  fputs ("(", file);
+  output_address (off);
+  fputs (")", file);
+}
+
+static bool
+c6x_print_operand_punct_valid_p (unsigned char c)
+{
+  return c == '$' || c == '.' || c == '|';
+}
+
+static void c6x_print_operand (FILE *, rtx, int);
+
+/* Subroutine of c6x_print_operand; used to print a memory reference X to FILE.  */
+
+static void
+c6x_print_address_operand (FILE *file, rtx x, enum machine_mode mem_mode)
+{
+  rtx off;
+  switch (GET_CODE (x))
+    {
+    case PRE_MODIFY:
+    case POST_MODIFY:
+      if (GET_CODE (x) == POST_MODIFY)
+       output_address (XEXP (x, 0));
+      off = XEXP (XEXP (x, 1), 1);
+      if (XEXP (x, 0) == stack_pointer_rtx)
+       {
+         if (GET_CODE (x) == PRE_MODIFY)
+           gcc_assert (INTVAL (off) > 0);
+         else
+           gcc_assert (INTVAL (off) < 0);
+       }
+      if (CONST_INT_P (off) && INTVAL (off) < 0)
+       {
+         fprintf (file, "--");
+         off = GEN_INT (-INTVAL (off));
+       }
+      else
+       fprintf (file, "++");
+      if (GET_CODE (x) == PRE_MODIFY)
+       output_address (XEXP (x, 0));
+      print_address_offset (file, off, mem_mode);
+      break;
+
+    case PLUS:
+      off = XEXP (x, 1);
+      if (CONST_INT_P (off) && INTVAL (off) < 0)
+       {
+         fprintf (file, "-");
+         off = GEN_INT (-INTVAL (off));
+       }
+      else
+       fprintf (file, "+");
+      output_address (XEXP (x, 0));
+      print_address_offset (file, off, mem_mode);
+      break;
+
+    case PRE_DEC:
+      gcc_assert (XEXP (x, 0) != stack_pointer_rtx);
+      fprintf (file, "--");
+      output_address (XEXP (x, 0));
+      fprintf (file, "[1]");
+      break;
+    case PRE_INC:
+      fprintf (file, "++");
+      output_address (XEXP (x, 0));
+      fprintf (file, "[1]");
+      break;
+    case POST_INC:
+      gcc_assert (XEXP (x, 0) != stack_pointer_rtx);
+      output_address (XEXP (x, 0));
+      fprintf (file, "++[1]");
+      break;
+    case POST_DEC:
+      output_address (XEXP (x, 0));
+      fprintf (file, "--[1]");
+      break;
+
+    case SYMBOL_REF:
+    case CONST:
+    case LABEL_REF:
+      gcc_assert (sdata_symbolic_operand (x, Pmode));
+      fprintf (file, "+B14(");
+      output_addr_const (file, x);
+      fprintf (file, ")");
+      break;
+
+    case UNSPEC:
+      switch (XINT (x, 1))
+       {
+       case UNSPEC_LOAD_GOT:
+         fputs ("$GOT(", file);
+         output_addr_const (file, XVECEXP (x, 0, 0));
+         fputs (")", file);
+         break;
+       case UNSPEC_LOAD_SDATA:
+         output_addr_const (file, XVECEXP (x, 0, 0));
+         break;
+       default:
+         gcc_unreachable ();
+       }
+      break;
+
+    default:
+      gcc_assert (GET_CODE (x) != MEM);
+      c6x_print_operand (file, x, 0);
+      break;
+    }
+}
+
+/* Return a single character, which is either 'l', 's', 'd' or 'm', which
+   specifies the functional unit used by INSN.  */
+
+char
+c6x_get_unit_specifier (rtx insn)
+{
+  enum attr_units units;
+
+  if (insn_info)
+    {
+      int unit = INSN_INFO_ENTRY (INSN_UID (insn)).reservation;
+      return c6x_unit_names[unit][0];
+    }
+
+  units = get_attr_units (insn);
+  switch (units)
+    {
+    case UNITS_D:
+    case UNITS_DL:
+    case UNITS_DS:
+    case UNITS_DLS:
+    case UNITS_D_ADDR:
+      return 'd';
+      break;
+    case UNITS_L:
+    case UNITS_LS:
+      return 'l';
+      break;
+    case UNITS_S:
+      return 's';
+      break;
+    case UNITS_M:
+      return 'm';
+      break;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Prints the unit specifier field.  */
+static void
+c6x_print_unit_specifier_field (FILE *file, rtx insn)
+{
+  enum attr_units units = get_attr_units (insn);
+  enum attr_cross cross = get_attr_cross (insn);
+  enum attr_dest_regfile rf = get_attr_dest_regfile (insn);
+  int half;
+  char unitspec;
+
+  if (units == UNITS_D_ADDR)
+    {
+      enum attr_addr_regfile arf = get_attr_addr_regfile (insn);
+      int t_half;
+      gcc_assert (arf != ADDR_REGFILE_UNKNOWN);
+      half = arf == ADDR_REGFILE_A ? 1 : 2;
+      t_half = rf == DEST_REGFILE_A ? 1 : 2;
+      fprintf (file, ".d%dt%d", half, t_half);
+      return;
+    }
+
+  if (insn_info)
+    {
+      int unit = INSN_INFO_ENTRY (INSN_UID (insn)).reservation;
+      fputs (".", file);
+      fputs (c6x_unit_names[unit], file);
+      if (cross == CROSS_Y)
+       fputs ("x", file);
+      return;
+    }
+
+  gcc_assert (rf != DEST_REGFILE_UNKNOWN);
+  unitspec = c6x_get_unit_specifier (insn);
+  half = rf == DEST_REGFILE_A ? 1 : 2;
+  fprintf (file, ".%c%d%s", unitspec, half, cross == CROSS_Y ? "x" : "");
+}
+
+/* Output assembly language output for the address ADDR to FILE.  */
+static void
+c6x_print_operand_address (FILE *file, rtx addr)
+{
+  c6x_print_address_operand (file, addr, VOIDmode);
+}
+
+/* Print an operand, X, to FILE, with an optional modifier in CODE.
+
+   Meaning of CODE:
+   $ -- print the unit specifier field for the instruction.
+   . -- print the predicate for the instruction or an emptry string for an
+        unconditional one.
+   | -- print "||" if the insn should be issued in parallel with the previous
+        one.
+
+   C -- print an opcode suffix for a reversed condition
+   d -- H, W or D as a suffix for ADDA, based on the factor given by the
+        operand
+   D -- print either B, H, W or D as a suffix for ADDA, based on the size of
+        the operand
+   J -- print a predicate
+   j -- like J, but use reverse predicate
+   k -- treat a CONST_INT as a register number and print it as a register
+   k -- like k, but print out a doubleword register
+   n -- print an integer operand, negated
+   p -- print the low part of a DImode register
+   P -- print the high part of a DImode register
+   r -- print the absolute value of an integer operand, shifted right by 1
+   R -- print the absolute value of an integer operand, shifted right by 2
+   f -- the first clear bit in an integer operand assumed to be a mask for
+        a clr instruction
+   F -- the last clear bit in such a mask
+   s -- the first set bit in an integer operand assumed to be a mask for
+        a set instruction
+   S -- the last set bit in such a mask
+   U -- print either 1 or 2, depending on the side of the machine used by
+        the operand  */
+
+static void
+c6x_print_operand (FILE *file, rtx x, int code)
+{
+  int i;
+  HOST_WIDE_INT v;
+  tree t;
+  enum machine_mode mode;
+
+  if (code == '|')
+    {
+      if (GET_MODE (c6x_current_insn) != TImode)
+       fputs ("||", file);
+      return;
+    }
+  if (code == '$')
+    {
+      c6x_print_unit_specifier_field (file, c6x_current_insn);
+      return;
+    }
+
+  if (code == '.')
+    {
+      x = current_insn_predicate;
+      if (x)
+       {
+         unsigned int regno = REGNO (XEXP (x, 0));
+         fputs ("[", file);
+         if (GET_CODE (x) == EQ)
+           fputs ("!", file);
+         fputs (reg_names [regno], file);
+         fputs ("]", file);
+       }
+      return;
+    }
+
+  mode = GET_MODE (x);
+
+  switch (code)
+    {
+    case 'C':
+    case 'c':
+      {
+       enum rtx_code c = GET_CODE (x);
+       if (code == 'C')
+         c = swap_condition (c);
+       fputs (GET_RTX_NAME (c), file);
+      }
+      return;
+
+    case 'J':
+    case 'j':
+      {
+       unsigned int regno = REGNO (XEXP (x, 0));
+       if ((GET_CODE (x) == EQ) == (code == 'J'))
+         fputs ("!", file);
+        fputs (reg_names [regno], file);
+      }
+      return;
+
+    case 'k':
+      gcc_assert (GET_CODE (x) == CONST_INT);
+      v = INTVAL (x);
+      fprintf (file, "%s", reg_names[v]);
+      return;
+    case 'K':
+      gcc_assert (GET_CODE (x) == CONST_INT);
+      v = INTVAL (x);
+      gcc_assert ((v & 1) == 0);
+      fprintf (file, "%s:%s", reg_names[v + 1], reg_names[v]);
+      return;
+
+    case 's':
+    case 'S':
+    case 'f':
+    case 'F':
+      gcc_assert (GET_CODE (x) == CONST_INT);
+      v = INTVAL (x);
+      for (i = 0; i < 32; i++)
+       {
+         HOST_WIDE_INT tst = v & 1;
+         if (((code == 'f' || code == 'F') && !tst)
+             || ((code == 's' || code == 'S') && tst))
+           break;
+         v >>= 1;
+       }
+      if (code == 'f' || code == 's')
+       {
+         fprintf (file, "%d", i);
+         return;
+       }
+      for (;i < 32; i++)
+       {
+         HOST_WIDE_INT tst = v & 1;
+         if ((code == 'F' && tst) || (code == 'S' && !tst))
+           break;
+         v >>= 1;
+       }
+      fprintf (file, "%d", i - 1);
+      return;
+
+    case 'n':
+      gcc_assert (GET_CODE (x) == CONST_INT);
+      output_addr_const (file, GEN_INT (-INTVAL (x)));
+      return;
+
+    case 'r':
+      gcc_assert (GET_CODE (x) == CONST_INT);
+      v = INTVAL (x);
+      if (v < 0)
+       v = -v;
+      output_addr_const (file, GEN_INT (v >> 1));
+      return;
+
+    case 'R':
+      gcc_assert (GET_CODE (x) == CONST_INT);
+      v = INTVAL (x);
+      if (v < 0)
+       v = -v;
+      output_addr_const (file, GEN_INT (v >> 2));
+      return;
+
+    case 'd':
+      gcc_assert (GET_CODE (x) == CONST_INT);
+      v = INTVAL (x);
+      fputs (v == 2 ? "h" : v == 4 ? "w" : "d", file);
+      return;
+
+    case 'p':
+    case 'P':
+      gcc_assert (GET_CODE (x) == REG);
+      v = REGNO (x);
+      if (code == 'P')
+       v++;
+      fputs (reg_names[v], file);
+      return;
+
+    case 'D':
+      v = 0;
+      if (GET_CODE (x) == CONST)
+       {
+         x = XEXP (x, 0);
+         gcc_assert (GET_CODE (x) == PLUS);
+         gcc_assert (GET_CODE (XEXP (x, 1)) == CONST_INT);
+         v = INTVAL (XEXP (x, 1));
+         x = XEXP (x, 0);
+
+       }
+      gcc_assert (GET_CODE (x) == SYMBOL_REF);
+
+      t = SYMBOL_REF_DECL (x);
+      if (DECL_P (t))
+       v |= DECL_ALIGN_UNIT (t);
+      else
+       v |= TYPE_ALIGN_UNIT (TREE_TYPE (t));
+      if (v & 1)
+       fputs ("b", file);
+      else if (v & 2)
+       fputs ("h", file);
+      else
+       fputs ("w", file);
+      return;
+
+    case 'U':
+      if (MEM_P (x))
+       {
+         x = XEXP (x, 0);
+         if (GET_CODE (x) == PLUS
+             || GET_RTX_CLASS (GET_CODE (x)) == RTX_AUTOINC)
+           x = XEXP (x, 0);
+         if (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF)
+           {
+             gcc_assert (sdata_symbolic_operand (x, Pmode));
+             fputs ("2", file);
+             return;
+           }
+       }
+      gcc_assert (REG_P (x));
+      if (A_REGNO_P (REGNO (x)))
+       fputs ("1", file);
+      if (B_REGNO_P (REGNO (x)))
+       fputs ("2", file);
+      return;
+
+    default:
+      switch (GET_CODE (x))
+       {
+       case REG:
+         if (GET_MODE_SIZE (mode) == 8)
+           fprintf (file, "%s:%s", reg_names[REGNO (x) + 1],
+                    reg_names[REGNO (x)]);
+         else
+           fprintf (file, "%s", reg_names[REGNO (x)]);
+         break;
+
+       case MEM:
+         fputc ('*', file);
+         gcc_assert (XEXP (x, 0) != stack_pointer_rtx);
+         c6x_print_address_operand (file, XEXP (x, 0), GET_MODE (x));
+         break;
+
+       case SYMBOL_REF:
+         fputc ('(', file);
+         output_addr_const (file, x);
+         fputc (')', file);
+         break;
+
+       case CONST_INT:
+         output_addr_const (file, x);
+         break;
+
+       case CONST_DOUBLE:
+         output_operand_lossage ("invalid const_double operand");
+         break;
+
+       default:
+         output_addr_const (file, x);
+       }
+    }
+}
+\f
+/* Return TRUE if OP is a valid memory address with a base register of
+   class C.  If SMALL_OFFSET is true, we disallow memory references which would
+   require a long offset with B14/B15.  */
+
+bool
+c6x_mem_operand (rtx op, enum reg_class c, bool small_offset)
+{
+  enum machine_mode mode = GET_MODE (op);
+  rtx base = XEXP (op, 0);
+  switch (GET_CODE (base))
+    {
+    case REG:
+      break;
+    case PLUS:
+      if (small_offset
+         && (XEXP (base, 0) == stack_pointer_rtx
+             || XEXP (base, 0) == pic_offset_table_rtx))
+       {
+         if (!c6x_legitimate_address_p_1 (mode, base, true, true))
+           return false;
+       }
+
+      /* fall through */
+    case PRE_INC:
+    case PRE_DEC:
+    case PRE_MODIFY:
+    case POST_INC:
+    case POST_DEC:
+    case POST_MODIFY:
+      base = XEXP (base, 0);
+      break;
+
+    case CONST:
+    case LABEL_REF:
+    case SYMBOL_REF:
+      gcc_assert (sdata_symbolic_operand (base, Pmode));
+      return !small_offset && c == B_REGS;
+
+    default:
+      return false;
+    }
+  return TEST_HARD_REG_BIT (reg_class_contents[ (int) (c)], REGNO (base));
+}
+
+/* Returns true if X is a valid address for use in a memory reference
+   of mode MODE.  If STRICT is true, we do not allow pseudo registers
+   in the address.  NO_LARGE_OFFSET is true if we are examining an
+   address for use in a load or store misaligned instruction, or
+   recursively examining an operand inside a PRE/POST_MODIFY.  */
+
+bool
+c6x_legitimate_address_p_1 (enum machine_mode mode, rtx x, bool strict,
+                           bool no_large_offset)
+{
+  int size, size1;
+  HOST_WIDE_INT off;
+  enum rtx_code code = GET_CODE (x);
+
+  switch (code)
+    {
+    case PRE_MODIFY:
+    case POST_MODIFY:
+      /* We can't split these into word-sized pieces yet.  */
+      if (!TARGET_STDW && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
+       return false;
+      if (GET_CODE (XEXP (x, 1)) != PLUS)
+       return false;
+      if (!c6x_legitimate_address_p_1 (mode, XEXP (x, 1), strict, true))
+       return false;
+      if (!rtx_equal_p (XEXP (x, 0), XEXP (XEXP (x, 1), 0)))
+       return false;
+
+      /* fall through */
+    case PRE_INC:
+    case PRE_DEC:
+    case POST_INC:
+    case POST_DEC:
+      /* We can't split these into word-sized pieces yet.  */
+      if (!TARGET_STDW && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
+       return false;
+      x = XEXP (x, 0);
+      if (!REG_P (x))
+       return false;
+
+      /* fall through */
+    case REG:
+      if (strict)
+       return REGNO_OK_FOR_BASE_STRICT_P (REGNO (x));
+      else
+       return REGNO_OK_FOR_BASE_NONSTRICT_P (REGNO (x));
+
+    case PLUS:
+      if (!REG_P (XEXP (x, 0))
+         || !c6x_legitimate_address_p_1 (mode, XEXP (x, 0), strict, false))
+       return false;
+      /* We cannot ensure currently that both registers end up in the
+        same register file.  */
+      if (REG_P (XEXP (x, 1)))
+       return false;
+
+      if (mode == BLKmode)
+       size = 4;
+      else if (mode == VOIDmode)
+       /* ??? This can happen during ivopts.  */
+       size = 1;
+      else
+       size = GET_MODE_SIZE (mode);
+
+      if (flag_pic
+         && GET_CODE (XEXP (x, 1)) == UNSPEC
+         && XINT (XEXP (x, 1), 1) == UNSPEC_LOAD_SDATA
+         && XEXP (x, 0) == pic_offset_table_rtx
+         && sdata_symbolic_operand (XVECEXP (XEXP (x, 1), 0, 0), SImode))
+       return !no_large_offset && size <= 4;
+      if (flag_pic == 1
+         && mode == Pmode
+         && GET_CODE (XEXP (x, 1)) == UNSPEC
+         && XINT (XEXP (x, 1), 1) == UNSPEC_LOAD_GOT
+         && XEXP (x, 0) == pic_offset_table_rtx
+         && (GET_CODE (XVECEXP (XEXP (x, 1), 0, 0)) == SYMBOL_REF
+             || GET_CODE (XVECEXP (XEXP (x, 1), 0, 0)) == LABEL_REF))
+       return !no_large_offset;
+      if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+       return false;
+
+      off = INTVAL (XEXP (x, 1));
+
+      /* If the machine does not have doubleword load/stores, we'll use
+        word size accesses.  */
+      size1 = size;
+      if (size == 2 * UNITS_PER_WORD && !TARGET_STDW)
+       size = UNITS_PER_WORD;
+
+      if (((HOST_WIDE_INT)size1 - 1) & off)
+       return false;
+      off /= size;
+      if (off > -32 && off < (size1 == size ? 32 : 28))
+       return true;
+      if (no_large_offset || code != PLUS || XEXP (x, 0) != stack_pointer_rtx
+         || size1 > UNITS_PER_WORD)
+       return false;
+      return off >= 0 && off < 32768;
+
+    case CONST:
+    case SYMBOL_REF:
+    case LABEL_REF:
+      return (!no_large_offset
+             /* With -fpic, we must wrap it in an unspec to show the B14
+                dependency.  */
+             && !flag_pic
+             && GET_MODE_SIZE (mode) <= UNITS_PER_WORD
+             && sdata_symbolic_operand (x, Pmode));
+
+    default:
+      return false;
+    }
+}
+
+static bool
+c6x_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
+{
+  return c6x_legitimate_address_p_1 (mode, x, strict, false);
+}
+
+static bool
+c6x_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED,
+                          rtx x ATTRIBUTE_UNUSED)
+{
+  return true;
+}
+\f
+/* Implements TARGET_PREFERRED_RENAME_CLASS.  */
+static reg_class_t
+c6x_preferred_rename_class (reg_class_t cl)
+{
+  if (cl == A_REGS)
+    return NONPREDICATE_A_REGS;
+  if (cl == B_REGS)
+    return NONPREDICATE_B_REGS;
+  if (cl == ALL_REGS || cl == GENERAL_REGS)
+    return NONPREDICATE_REGS;
+  return NO_REGS;
+}
+\f
+/* Implements FINAL_PRESCAN_INSN.  */
+void
+c6x_final_prescan_insn (rtx insn, rtx *opvec ATTRIBUTE_UNUSED,
+                       int noperands ATTRIBUTE_UNUSED)
+{
+  c6x_current_insn = insn;
+}
+\f
+/* A structure to describe the stack layout of a function.  The layout is
+   as follows:
+
+   [saved frame pointer (or possibly padding0)]
+   --> incoming stack pointer, new hard frame pointer
+   [saved call-used regs]
+   [optional padding1]
+   --> soft frame pointer
+   [frame]
+   [outgoing arguments]
+   [optional padding2]
+
+  The structure members are laid out in this order.  */
+
+struct c6x_frame
+{
+  int padding0;
+  /* Number of registers to save.  */
+  int nregs;
+  int padding1;
+  HOST_WIDE_INT frame;
+  int outgoing_arguments_size;
+  int padding2;
+
+  HOST_WIDE_INT to_allocate;
+  /* The offsets relative to the incoming stack pointer (which
+     becomes HARD_FRAME_POINTER).  */
+  HOST_WIDE_INT frame_pointer_offset;
+  HOST_WIDE_INT b3_offset;
+
+  /* True if we should call push_rts/pop_rts to save and restore
+     registers.  */
+  bool push_rts;
+};
+
+/* Return true if we need to save and modify the PIC register in the
+   prologue.  */
+
+static bool
+must_reload_pic_reg_p (void)
+{
+  struct cgraph_local_info *i = NULL;
+
+  if (!TARGET_DSBT)
+    return false;
+
+  i = cgraph_local_info (current_function_decl);
+
+  if ((crtl->uses_pic_offset_table || !current_function_is_leaf) && !i->local)
+    return true;
+  return false;
+}
+
+/* Return 1 if we need to save REGNO.  */
+static int
+c6x_save_reg (unsigned int regno)
+{
+  return ((df_regs_ever_live_p (regno)
+          && !call_used_regs[regno]
+          && !fixed_regs[regno])
+         || (regno == RETURN_ADDR_REGNO
+             && (df_regs_ever_live_p (regno)
+                 || !current_function_is_leaf))
+         || (regno == PIC_OFFSET_TABLE_REGNUM && must_reload_pic_reg_p ()));
+}
+
+/* Examine the number of regs NREGS we've determined we must save.
+   Return true if we should use __c6xabi_push_rts/__c6xabi_pop_rts for
+   prologue and epilogue.  */
+
+static bool
+use_push_rts_p (int nregs)
+{
+  if (TARGET_INSNS_64PLUS && optimize_function_for_size_p (cfun)
+      && !cfun->machine->contains_sibcall
+      && !cfun->returns_struct
+      && !TARGET_LONG_CALLS
+      && nregs >= 6 && !frame_pointer_needed)
+    return true;
+  return false;
+}
+
+/* Return number of saved general prupose registers.  */
+
+int
+c6x_nsaved_regs (void)
+{
+  int nregs = 0;
+  int regno;
+
+  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+    if (c6x_save_reg (regno))
+      nregs++;
+  return nregs;
+}
+
+/* The safe debug order mandated by the ABI.  */
+static unsigned reg_save_order[] =
+{
+  REG_A10, REG_A11, REG_A12, REG_A13,
+  REG_A14, REG_B3,
+  REG_B10, REG_B11, REG_B12, REG_B13,
+  REG_B14, REG_A15
+};
+
+#define N_SAVE_ORDER (sizeof reg_save_order / sizeof *reg_save_order)
+
+/* Compute the layout of the stack frame and store it in FRAME.  */
+
+static void
+c6x_compute_frame_layout (struct c6x_frame *frame)
+{
+  HOST_WIDE_INT size = get_frame_size ();
+  HOST_WIDE_INT offset;
+  int nregs;
+
+  /* We use the four bytes which are technically inside the caller's frame,
+     usually to save the frame pointer.  */
+  offset = -4;
+  frame->padding0 = 0;
+  nregs = c6x_nsaved_regs ();
+  frame->push_rts = false;
+  frame->b3_offset = 0;
+  if (use_push_rts_p (nregs))
+    {
+      frame->push_rts = true;
+      frame->b3_offset = (TARGET_BIG_ENDIAN ? -12 : -13) * 4;
+      nregs = 14;
+    }
+  else if (c6x_save_reg (REG_B3))
+    {
+      int idx;
+      for (idx = N_SAVE_ORDER - 1; reg_save_order[idx] != REG_B3; idx--)
+       {
+         if (c6x_save_reg (reg_save_order[idx]))
+           frame->b3_offset -= 4;
+       }
+    }
+  frame->nregs = nregs;
+
+  if (size == 0 && nregs == 0)
+    {
+      frame->padding0 = 4;
+      frame->padding1 = frame->padding2 = 0;
+      frame->frame_pointer_offset = frame->to_allocate = 0;
+      frame->outgoing_arguments_size = 0;
+      return;
+    }
+
+  if (!frame->push_rts)
+    offset += frame->nregs * 4;
+
+  if (offset == 0 && size == 0 && crtl->outgoing_args_size == 0
+      && !current_function_is_leaf)
+    /* Don't use the bottom of the caller's frame if we have no
+       allocation of our own and call other functions.  */
+    frame->padding0 = frame->padding1 = 4;
+  else if (offset & 4)
+    frame->padding1 = 4;
+  else
+    frame->padding1 = 0;
+
+  offset += frame->padding0 + frame->padding1;
+  frame->frame_pointer_offset = offset;
+  offset += size;
+
+  frame->outgoing_arguments_size = crtl->outgoing_args_size;
+  offset += frame->outgoing_arguments_size;
+
+  if ((offset & 4) == 0)
+    frame->padding2 = 8;
+  else
+    frame->padding2 = 4;
+  frame->to_allocate = offset + frame->padding2;
+}
+
+/* Return the offset between two registers, one to be eliminated, and the other
+   its replacement, at the start of a routine.  */
+
+HOST_WIDE_INT
+c6x_initial_elimination_offset (int from, int to)
+{
+  struct c6x_frame frame;
+  c6x_compute_frame_layout (&frame);
+
+  if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
+    return 0;
+  else if (from == FRAME_POINTER_REGNUM
+          && to == HARD_FRAME_POINTER_REGNUM)
+    return -frame.frame_pointer_offset;
+  else
+    {
+      gcc_assert (to == STACK_POINTER_REGNUM);
+
+      if (from == ARG_POINTER_REGNUM)
+       return frame.to_allocate + (frame.push_rts ? 56 : 0);
+
+      gcc_assert (from == FRAME_POINTER_REGNUM);
+      return frame.to_allocate - frame.frame_pointer_offset;
+    }
+}
+
+/* Given FROM and TO register numbers, say whether this elimination is
+   allowed.  Frame pointer elimination is automatically handled.  */
+
+static bool
+c6x_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
+{
+  if (to == STACK_POINTER_REGNUM)
+    return !frame_pointer_needed;
+  return true;
+}
+
+/* Emit insns to increment the stack pointer by OFFSET.  If
+   FRAME_RELATED_P, set the RTX_FRAME_RELATED_P flag on the insns.
+   Does nothing if the offset is zero.  */
+
+static void
+emit_add_sp_const (HOST_WIDE_INT offset, bool frame_related_p)
+{
+  rtx to_add = GEN_INT (offset);
+  rtx orig_to_add = to_add;
+  rtx insn;
+
+  if (offset == 0)
+    return;
+
+  if (offset < -32768 || offset > 32767)
+    {
+      rtx reg = gen_rtx_REG (SImode, REG_A0);
+      rtx low = GEN_INT (trunc_int_for_mode (offset, HImode));
+
+      insn = emit_insn (gen_movsi_high (reg, low));
+      if (frame_related_p)
+       RTX_FRAME_RELATED_P (insn) = 1;
+      insn = emit_insn (gen_movsi_lo_sum (reg, reg, to_add));
+      if (frame_related_p)
+       RTX_FRAME_RELATED_P (insn) = 1;
+      to_add = reg;
+    }
+  insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
+                               to_add));
+  if (frame_related_p)
+    {
+      if (REG_P (to_add))
+       add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+                     gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+                                  gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+                                                orig_to_add)));
+
+      RTX_FRAME_RELATED_P (insn) = 1;
+    }
+}
+
+/* Prologue and epilogue.  */
+void
+c6x_expand_prologue (void)
+{
+  struct c6x_frame frame;
+  rtx insn, mem;
+  int nsaved = 0;
+  HOST_WIDE_INT initial_offset, off, added_already;
+
+  c6x_compute_frame_layout (&frame);
+
+  if (flag_stack_usage_info)
+    current_function_static_stack_size = frame.to_allocate;
+
+  initial_offset = -frame.to_allocate;
+  if (frame.push_rts)
+    {
+      emit_insn (gen_push_rts ());
+      nsaved = frame.nregs;
+    }
+
+  /* If the offsets would be too large for the memory references we will
+     create to save registers, do the stack allocation in two parts.
+     Ensure by subtracting 8 that we don't store to the word pointed to
+     by the stack pointer.  */
+  if (initial_offset < -32768)
+    initial_offset = -frame.frame_pointer_offset - 8;
+
+  if (frame.to_allocate > 0)
+    gcc_assert (initial_offset != 0);
+
+  off = -initial_offset + 4 - frame.padding0;
+
+  mem = gen_frame_mem (Pmode, stack_pointer_rtx);
+
+  added_already = 0;
+  if (frame_pointer_needed)
+    {
+      rtx fp_reg = gen_rtx_REG (SImode, REG_A15);
+      /* We go through some contortions here to both follow the ABI's
+        recommendation that FP == incoming SP, and to avoid writing or
+        reading the word pointed to by the stack pointer.  */
+      rtx addr = gen_rtx_POST_MODIFY (Pmode, stack_pointer_rtx,
+                                     gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+                                                   GEN_INT (-8)));
+      insn = emit_move_insn (gen_frame_mem (Pmode, addr), fp_reg);
+      RTX_FRAME_RELATED_P (insn) = 1;
+      nsaved++;
+      insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx, stack_pointer_rtx,
+                                   GEN_INT (8)));
+      RTX_FRAME_RELATED_P (insn) = 1;
+      off -= 4;
+      added_already = -8;
+    }
+
+  emit_add_sp_const (initial_offset - added_already, true);
+
+  if (nsaved < frame.nregs)
+    {
+      unsigned i;
+
+      for (i = 0; i < N_SAVE_ORDER; i++)
+       {
+         int idx = N_SAVE_ORDER - i - 1;
+         unsigned regno = reg_save_order[idx];
+         rtx reg;
+         enum machine_mode save_mode = SImode;
+
+         if (regno == REG_A15 && frame_pointer_needed)
+           /* Already saved.  */
+           continue;
+         if (!c6x_save_reg (regno))
+           continue;
+
+         if (TARGET_STDW && (off & 4) == 0 && off <= 256
+             && (regno & 1) == 1
+             && i + 1 < N_SAVE_ORDER
+             && reg_save_order[idx - 1] == regno - 1
+             && c6x_save_reg (regno - 1))
+           {
+             save_mode = DImode;
+             regno--;
+             i++;
+           }
+         reg = gen_rtx_REG (save_mode, regno);
+         off -= GET_MODE_SIZE (save_mode);
+
+         insn = emit_move_insn (adjust_address (mem, save_mode, off),
+                                reg);
+         RTX_FRAME_RELATED_P (insn) = 1;
+
+         nsaved += HARD_REGNO_NREGS (regno, save_mode);
+       }
+    }
+  gcc_assert (nsaved == frame.nregs);
+  emit_add_sp_const (-frame.to_allocate - initial_offset, true);
+  if (must_reload_pic_reg_p ())
+    {
+      if (dsbt_decl == NULL)
+       {
+         tree t;
+
+         t = build_index_type (integer_one_node);
+         t = build_array_type (integer_type_node, t);
+         t = build_decl (BUILTINS_LOCATION, VAR_DECL,
+                         get_identifier ("__c6xabi_DSBT_BASE"), t);
+         DECL_ARTIFICIAL (t) = 1;
+         DECL_IGNORED_P (t) = 1;
+         DECL_EXTERNAL (t) = 1;
+         TREE_STATIC (t) = 1;
+         TREE_PUBLIC (t) = 1;
+         TREE_USED (t) = 1;
+
+         dsbt_decl = t;
+       }
+      emit_insn (gen_setup_dsbt (pic_offset_table_rtx,
+                                XEXP (DECL_RTL (dsbt_decl), 0)));
+    }
+}
+
+void
+c6x_expand_epilogue (bool sibcall)
+{
+  unsigned i;
+  struct c6x_frame frame;
+  rtx mem;
+  HOST_WIDE_INT off;
+  int nsaved = 0;
+
+  c6x_compute_frame_layout (&frame);
+
+  mem = gen_frame_mem (Pmode, stack_pointer_rtx);
+
+  /* Insert a dummy set/use of the stack pointer.  This creates a
+     scheduler barrier between the prologue saves and epilogue restores. */
+  emit_insn (gen_epilogue_barrier (stack_pointer_rtx, stack_pointer_rtx));
+
+  /* If the offsets would be too large for the memory references we will
+     create to restore registers, do a preliminary stack adjustment here.  */
+  off = frame.to_allocate - frame.frame_pointer_offset + frame.padding1;
+  if (frame.push_rts)
+    {
+      nsaved = frame.nregs;
+    }
+  else
+    {
+      if (frame.to_allocate > 32768)
+       {
+         /* Don't add the entire offset so that we leave an unused word
+            above the stack pointer.  */
+         emit_add_sp_const ((off - 16) & ~7, false);
+         off &= 7;
+         off += 16;
+       }
+      for (i = 0; i < N_SAVE_ORDER; i++)
+       {
+         unsigned regno = reg_save_order[i];
+         rtx reg;
+         enum machine_mode save_mode = SImode;
+
+         if (!c6x_save_reg (regno))
+           continue;
+         if (regno == REG_A15 && frame_pointer_needed)
+           continue;
+
+         if (TARGET_STDW && (off & 4) == 0 && off < 256
+             && (regno & 1) == 0
+             && i + 1 < N_SAVE_ORDER
+             && reg_save_order[i + 1] == regno + 1
+             && c6x_save_reg (regno + 1))
+           {
+             save_mode = DImode;
+             i++;
+           }
+         reg = gen_rtx_REG (save_mode, regno);
+
+         emit_move_insn (reg, adjust_address (mem, save_mode, off));
+
+         off += GET_MODE_SIZE (save_mode);
+         nsaved += HARD_REGNO_NREGS (regno, save_mode);
+       }
+    }
+  if (!frame_pointer_needed)
+    emit_add_sp_const (off + frame.padding0 - 4, false);
+  else
+    {
+      rtx fp_reg = gen_rtx_REG (SImode, REG_A15);
+      rtx addr = gen_rtx_PRE_MODIFY (Pmode, stack_pointer_rtx,
+                                     gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+                                                   GEN_INT (8)));
+      emit_insn (gen_addsi3 (stack_pointer_rtx, hard_frame_pointer_rtx,
+                            GEN_INT (-8)));
+      emit_move_insn (fp_reg, gen_frame_mem (Pmode, addr));
+      nsaved++;
+    }
+  gcc_assert (nsaved == frame.nregs);
+  if (!sibcall)
+    {
+      if (frame.push_rts)
+       emit_jump_insn (gen_pop_rts ());
+      else
+       emit_jump_insn (gen_return_internal (gen_rtx_REG (SImode,
+                                                         RETURN_ADDR_REGNO)));
+    }
+}
+
+/* Return the value of the return address for the frame COUNT steps up
+   from the current frame, after the prologue.
+   We punt for everything but the current frame by returning const0_rtx.  */
+
+rtx
+c6x_return_addr_rtx (int count)
+{
+  if (count != 0)
+    return const0_rtx;
+
+  return get_hard_reg_initial_val (Pmode, RETURN_ADDR_REGNO);
+}
+\f
+/* Return true iff TYPE is one of the shadow types.  */
+static bool
+shadow_type_p (enum attr_type type)
+{
+  return (type == TYPE_SHADOW || type == TYPE_LOAD_SHADOW
+         || type == TYPE_MULT_SHADOW);
+}
+
+/* Return true iff INSN is a shadow pattern.  */
+static bool
+shadow_p (rtx insn)
+{
+  if (!NONDEBUG_INSN_P (insn) || recog_memoized (insn) < 0)
+    return false;
+  return shadow_type_p (get_attr_type (insn));
+}
+
+/* Return true iff INSN is a shadow or blockage pattern.  */
+static bool
+shadow_or_blockage_p (rtx insn)
+{
+  enum attr_type type;
+  if (!NONDEBUG_INSN_P (insn) || recog_memoized (insn) < 0)
+    return false;
+  type = get_attr_type (insn);
+  return shadow_type_p (type) || type == TYPE_BLOCKAGE;
+}
+\f
+/* Translate UNITS into a bitmask of units we can reserve for this
+   insn.  */
+static int
+get_reservation_flags (enum attr_units units)
+{
+  switch (units)
+    {
+    case UNITS_D:
+    case UNITS_D_ADDR:
+      return RESERVATION_FLAG_D;
+    case UNITS_L:
+      return RESERVATION_FLAG_L;
+    case UNITS_S:
+      return RESERVATION_FLAG_S;
+    case UNITS_M:
+      return RESERVATION_FLAG_M;
+    case UNITS_LS:
+      return RESERVATION_FLAG_LS;
+    case UNITS_DL:
+      return RESERVATION_FLAG_DL;
+    case UNITS_DS:
+      return RESERVATION_FLAG_DS;
+    case UNITS_DLS:
+      return RESERVATION_FLAG_DLS;
+    default:
+      return 0;
+    }
+}
+
+/* Compute the side of the machine used by INSN, which reserves UNITS.
+   This must match the reservations in the scheduling description.  */
+static int
+get_insn_side (rtx insn, enum attr_units units)
+{
+  if (units == UNITS_D_ADDR)
+    return (get_attr_addr_regfile (insn) == ADDR_REGFILE_A ? 0 : 1);
+  else
+    {
+      enum attr_dest_regfile rf = get_attr_dest_regfile (insn);
+      if (rf == DEST_REGFILE_ANY)
+       return get_attr_type (insn) == TYPE_BRANCH ? 0 : 1;
+      else
+       return rf == DEST_REGFILE_A ? 0 : 1;
+    }
+}
+
+/* After scheduling, walk the insns between HEAD and END and assign unit
+   reservations.  */
+static void
+assign_reservations (rtx head, rtx end)
+{
+  rtx insn;
+  for (insn = head; insn != NEXT_INSN (end); insn = NEXT_INSN (insn))
+    {
+      rtx within;
+      int pass;
+      int rsrv[2];
+      int rsrv_count[2][4];
+
+      if (GET_MODE (insn) != TImode)
+       continue;
+
+      rsrv[0] = rsrv[1] = 0;
+      memset (rsrv_count, 0, sizeof rsrv_count);
+
+      /* Walk through the insns that occur in the same cycle.  We use multiple
+        passes to assign units, assigning for insns with the most specific
+        requirements first.  */
+      for (pass = 0; pass < 4; pass++)
+       for (within = insn;
+            (within != NEXT_INSN (end)
+             && (within == insn || GET_MODE (within) != TImode));
+            within = NEXT_INSN (within))
+         {
+           int this_rsrv, side;
+           int icode;
+           enum attr_units units;
+           int j;
+
+           if (!NONDEBUG_INSN_P (within))
+             continue;
+           icode = recog_memoized (within);
+           if (icode < 0)
+             continue;
+           units = get_attr_units (within);
+           this_rsrv = get_reservation_flags (units);
+           if (this_rsrv == 0)
+             continue;
+           side = get_insn_side (within, units);
+
+           if ((this_rsrv & (this_rsrv - 1)) == 0)
+             {
+               int t = exact_log2 (this_rsrv) + side * 4;
+               rsrv[side] |= this_rsrv;
+               INSN_INFO_ENTRY (INSN_UID (within)).reservation = t;
+               continue;
+             }
+
+           if (pass == 1)
+             {
+               for (j = 0; j < 4; j++)
+                 if (this_rsrv & (1 << j))
+                   rsrv_count[side][j]++;
+               continue;
+             }
+           if ((pass == 2 && this_rsrv != RESERVATION_FLAG_DLS)
+               || (pass == 3 && this_rsrv == RESERVATION_FLAG_DLS))
+             {
+               int best = -1, best_cost = INT_MAX;
+               for (j = 0; j < 4; j++)
+                 if ((this_rsrv & (1 << j))
+                     && !(rsrv[side] & (1 << j))
+                     && rsrv_count[side][j] < best_cost)
+                   {
+                     best_cost = rsrv_count[side][j];
+                     best = j;
+                   }
+               gcc_assert (best != -1);
+               rsrv[side] |= 1 << best;
+               for (j = 0; j < 4; j++)
+                 if ((this_rsrv & (1 << j)) && j != best)
+                   rsrv_count[side][j]--;
+
+               INSN_INFO_ENTRY (INSN_UID (within)).reservation
+                 = best + side * 4;
+             }
+         }
+    }
+}
+\f
+/* Backend scheduling state.  */
+typedef struct c6x_sched_context
+{
+  /* The current scheduler clock, saved in the sched_reorder hook.  */
+  int curr_sched_clock;
+
+  /* Number of insns issued so far in this cycle.  */
+  int issued_this_cycle;
+
+  /* We record the time at which each jump occurs in JUMP_CYCLES.  The
+     theoretical maximum for number of jumps in flight is 12: 2 every
+     cycle, with a latency of 6 cycles each.  This is a circular
+     buffer; JUMP_CYCLE_INDEX is the pointer to the start.  Earlier
+     jumps have a higher index.  This array should be accessed through
+     the jump_cycle function.  */
+  int jump_cycles[12];
+  int jump_cycle_index;
+
+  /* In parallel with jump_cycles, this array records the opposite of
+     the condition used in each pending jump.  This is used to
+     predicate insns that are scheduled in the jump's delay slots.  If
+     this is NULL_RTX no such predication happens.  */
+  rtx jump_cond[12];
+
+  /* Similar to the jump_cycles mechanism, but here we take into
+     account all insns with delay slots, to avoid scheduling asms into
+     the delay slots.  */
+  int delays_finished_at;
+
+  /* The following variable value is the last issued insn.  */
+  rtx last_scheduled_insn;
+
+  int reg_n_accesses[FIRST_PSEUDO_REGISTER];
+  int reg_n_xaccesses[FIRST_PSEUDO_REGISTER];
+  int reg_set_in_cycle[FIRST_PSEUDO_REGISTER];
+
+  int tmp_reg_n_accesses[FIRST_PSEUDO_REGISTER];
+  int tmp_reg_n_xaccesses[FIRST_PSEUDO_REGISTER];
+} *c6x_sched_context_t;
+
+/* The current scheduling state.  */
+static struct c6x_sched_context ss;
+
+/* Set when we discover while processing an insn that it would lead to too
+   many accesses of the same register.  */
+static bool reg_access_stall;
+
+/* Look up the jump cycle with index N.  For an out-of-bounds N, we return 0,
+   so the caller does not specifically have to test for it.  */
+static int
+get_jump_cycle (int n)
+{
+  if (n >= 12)
+    return 0;
+  n += ss.jump_cycle_index;
+  if (n >= 12)
+    n -= 12;
+  return ss.jump_cycles[n];
+}
+
+/* Look up the jump condition with index N.  */
+static rtx
+get_jump_cond (int n)
+{
+  if (n >= 12)
+    return NULL_RTX;
+  n += ss.jump_cycle_index;
+  if (n >= 12)
+    n -= 12;
+  return ss.jump_cond[n];
+}
+
+/* Return the index of the first jump that occurs after CLOCK_VAR.  If no jump
+   has delay slots beyond CLOCK_VAR, return -1.  */
+static int
+first_jump_index (int clock_var)
+{
+  int retval = -1;
+  int n = 0;
+  for (;;)
+    {
+      int t = get_jump_cycle (n);
+      if (t <= clock_var)
+       break;
+      retval = n;
+      n++;
+    }
+  return retval;
+}
+
+/* Add a new entry in our scheduling state for a jump that occurs in CYCLE
+   and has the opposite condition of COND.  */
+static void
+record_jump (int cycle, rtx cond)
+{
+  if (ss.jump_cycle_index == 0)
+    ss.jump_cycle_index = 11;
+  else
+    ss.jump_cycle_index--;
+  ss.jump_cycles[ss.jump_cycle_index] = cycle;
+  ss.jump_cond[ss.jump_cycle_index] = cond;
+}
+
+/* Set the clock cycle of INSN to CYCLE.  Also clears the insn's entry in
+   new_conditions.  */
+static void
+insn_set_clock (rtx insn, int cycle)
+{
+  unsigned uid = INSN_UID (insn);
+
+  if (uid >= INSN_INFO_LENGTH)
+    VEC_safe_grow (c6x_sched_insn_info, heap, insn_info, uid * 5 / 4 + 10);
+
+  INSN_INFO_ENTRY (uid).clock = cycle;
+  INSN_INFO_ENTRY (uid).new_cond = NULL;
+  INSN_INFO_ENTRY (uid).ebb_start = false;
+}
+
+/* Return the clock cycle we set for the insn with uid UID.  */
+static int
+insn_uid_get_clock (int uid)
+{
+  return INSN_INFO_ENTRY (uid).clock;
+}
+
+/* Return the clock cycle we set for INSN.  */
+static int
+insn_get_clock (rtx insn)
+{
+  return insn_uid_get_clock (INSN_UID (insn));
+}
+
+/* Examine INSN, and if it is a conditional jump of any kind, return
+   the opposite of the condition in which it branches.  Otherwise,
+   return NULL_RTX.  */
+static rtx
+condjump_opposite_condition (rtx insn)
+{
+  rtx pat = PATTERN (insn);
+  int icode = INSN_CODE (insn);
+  rtx x = NULL;
+
+  if (icode == CODE_FOR_br_true || icode == CODE_FOR_br_false)
+    {
+      x = XEXP (SET_SRC (pat), 0);
+      if (icode == CODE_FOR_br_false)
+       return x;
+    }
+  if (GET_CODE (pat) == COND_EXEC)
+    {
+      rtx t = COND_EXEC_CODE (pat);
+      if ((GET_CODE (t) == PARALLEL
+          && GET_CODE (XVECEXP (t, 0, 0)) == RETURN)
+         || (GET_CODE (t) == UNSPEC && XINT (t, 1) == UNSPEC_REAL_JUMP)
+         || (GET_CODE (t) == SET && SET_DEST (t) == pc_rtx))
+       x = COND_EXEC_TEST (pat);
+    }
+
+  if (x != NULL_RTX)
+    {
+      enum rtx_code code = GET_CODE (x);
+      x = gen_rtx_fmt_ee (code == EQ ? NE : EQ,
+                         GET_MODE (x), XEXP (x, 0),
+                         XEXP (x, 1));
+    }
+  return x;
+}
+
+/* Return true iff COND1 and COND2 are exactly opposite conditions
+   one of them NE and the other EQ.  */
+static bool
+conditions_opposite_p (rtx cond1, rtx cond2)
+{
+  return (rtx_equal_p (XEXP (cond1, 0), XEXP (cond2, 0))
+         && rtx_equal_p (XEXP (cond1, 1), XEXP (cond2, 1))
+         && GET_CODE (cond1) == reverse_condition (GET_CODE (cond2)));
+}
+
+/* Return true if we can add a predicate COND to INSN, or if INSN
+   already has that predicate.  If DOIT is true, also perform the
+   modification.  */
+static bool
+predicate_insn (rtx insn, rtx cond, bool doit)
+{
+  int icode;
+  if (cond == NULL_RTX)
+    {
+      gcc_assert (!doit);
+      return false;
+    }
+
+  if (get_attr_predicable (insn) == PREDICABLE_YES
+      && GET_CODE (PATTERN (insn)) != COND_EXEC)
+    {
+      if (doit)
+       {
+         rtx newpat = gen_rtx_COND_EXEC (VOIDmode, cond, PATTERN (insn));
+         PATTERN (insn) = newpat;
+         INSN_CODE (insn) = -1;
+       }
+      return true;
+    }
+  if (GET_CODE (PATTERN (insn)) == COND_EXEC
+      && rtx_equal_p (COND_EXEC_TEST (PATTERN (insn)), cond))
+    return true;
+  icode = INSN_CODE (insn);
+  if (icode == CODE_FOR_real_jump
+      || icode == CODE_FOR_jump
+      || icode == CODE_FOR_indirect_jump)
+    {
+      rtx pat = PATTERN (insn);
+      rtx dest = (icode == CODE_FOR_real_jump ? XVECEXP (pat, 0, 0)
+                 : icode == CODE_FOR_jump ? XEXP (SET_SRC (pat), 0)
+                 : SET_SRC (pat));
+      if (doit)
+       {
+         rtx newpat;
+         if (REG_P (dest))
+           newpat = gen_rtx_COND_EXEC (VOIDmode, cond, PATTERN (insn));
+         else
+           newpat = gen_br_true (cond, XEXP (cond, 0), dest);
+         PATTERN (insn) = newpat;
+         INSN_CODE (insn) = -1;
+       }
+      return true;
+    }
+  if (INSN_CODE (insn) == CODE_FOR_br_true)
+    {
+      rtx br_cond = XEXP (SET_SRC (PATTERN (insn)), 0);
+      return rtx_equal_p (br_cond, cond);
+    }
+  if (INSN_CODE (insn) == CODE_FOR_br_false)
+    {
+      rtx br_cond = XEXP (SET_SRC (PATTERN (insn)), 0);
+      return conditions_opposite_p (br_cond, cond);
+    }
+  return false;
+}
+
+/* Initialize SC.  Used by c6x_init_sched_context and c6x_sched_init.  */
+static void
+init_sched_state (c6x_sched_context_t sc)
+{
+  sc->last_scheduled_insn = NULL_RTX;
+  sc->issued_this_cycle = 0;
+  memset (sc->jump_cycles, 0, sizeof sc->jump_cycles);
+  memset (sc->jump_cond, 0, sizeof sc->jump_cond);
+  sc->jump_cycle_index = 0;
+  sc->delays_finished_at = 0;
+  sc->curr_sched_clock = 0;
+
+  memset (sc->reg_n_accesses, 0, sizeof sc->reg_n_accesses);
+  memset (sc->reg_n_xaccesses, 0, sizeof sc->reg_n_xaccesses);
+  memset (sc->reg_set_in_cycle, 0, sizeof sc->reg_set_in_cycle);
+}
+
+/* Allocate store for new scheduling context.  */
+static void *
+c6x_alloc_sched_context (void)
+{
+  return xmalloc (sizeof (struct c6x_sched_context));
+}
+
+/* If CLEAN_P is true then initializes _SC with clean data,
+   and from the global context otherwise.  */
+static void
+c6x_init_sched_context (void *_sc, bool clean_p)
+{
+  c6x_sched_context_t sc = (c6x_sched_context_t) _sc;
+
+  if (clean_p)
+    {
+      init_sched_state (sc);
+    }
+  else
+    *sc = ss;
+}
+
+/* Sets the global scheduling context to the one pointed to by _SC.  */
+static void
+c6x_set_sched_context (void *_sc)
+{
+  c6x_sched_context_t sc = (c6x_sched_context_t) _sc;
+
+  gcc_assert (sc != NULL);
+  ss = *sc;
+}
+
+/* Free _SC.  */
+static void
+c6x_free_sched_context (void *_sc)
+{
+  free (_sc);
+}
+
+/* Provide information about speculation capabilities, and set the
+   DO_BACKTRACKING flag.  */
+static void
+c6x_set_sched_flags (spec_info_t spec_info)
+{
+  unsigned int *flags = &(current_sched_info->flags);
+
+  if (*flags & SCHED_EBB)
+    {
+      *flags |= DO_BACKTRACKING;
+    }
+
+  spec_info->mask = 0;
+}
+
+/* Implement the TARGET_SCHED_ISSUE_RATE hook.  */
+
+static int
+c6x_issue_rate (void)
+{
+  return 8;
+}
+
+/* We're beginning a new block.  Initialize data structures as necessary.  */
+
+static void
+c6x_sched_init (FILE *dump ATTRIBUTE_UNUSED,
+               int sched_verbose ATTRIBUTE_UNUSED,
+               int max_ready ATTRIBUTE_UNUSED)
+{
+  init_sched_state (&ss);
+}
+
+static void
+c6x_mark_regno_read (int regno, bool cross)
+{
+  int t = ++ss.tmp_reg_n_accesses[regno];
+
+  if (t > 4)
+    reg_access_stall = true;
+
+  if (cross)
+    {
+      int set_cycle = ss.reg_set_in_cycle[regno];
+      /* This must be done in this way rather than by tweaking things in
+        adjust_cost, since the stall occurs even for insns with opposite
+        predicates, and the scheduler may not even see a dependency.  */
+      if (set_cycle > 0 && set_cycle == ss.curr_sched_clock)
+       reg_access_stall = true;
+      /* This doesn't quite do anything yet as we're only modeling one
+        x unit.  */
+      ++ss.tmp_reg_n_xaccesses[regno];
+    }
+}
+
+/* Note that REG is read in the insn being examined.  If CROSS, it
+   means the access is through a cross path.  Update the temporary reg
+   access arrays, and set REG_ACCESS_STALL if the insn can't be issued
+   in the current cycle.  */
+
+static void
+c6x_mark_reg_read (rtx reg, bool cross)
+{
+  unsigned regno = REGNO (reg);
+  unsigned nregs = hard_regno_nregs[regno][GET_MODE (reg)];
+
+  while (nregs-- > 0)
+    c6x_mark_regno_read (regno + nregs, cross);
+}
+
+/* Note that register REG is written in cycle CYCLES.  */
+
+static void
+c6x_mark_reg_written (rtx reg, int cycles)
+{
+  unsigned regno = REGNO (reg);
+  unsigned nregs = hard_regno_nregs[regno][GET_MODE (reg)];
+
+  while (nregs-- > 0)
+    ss.reg_set_in_cycle[regno + nregs] = cycles;
+}
+
+/* Update the register state information for an instruction whose
+   body is X.  Return true if the instruction has to be delayed until the
+   next cycle.  */
+
+static bool
+c6x_registers_update (rtx insn)
+{
+  enum attr_cross cross;
+  enum attr_dest_regfile destrf;
+  int i, nops;
+  rtx x;
+
+  if (!reload_completed || recog_memoized (insn) < 0)
+    return false;
+
+  reg_access_stall = false;
+  memcpy (ss.tmp_reg_n_accesses, ss.reg_n_accesses,
+         sizeof ss.tmp_reg_n_accesses);
+  memcpy (ss.tmp_reg_n_xaccesses, ss.reg_n_xaccesses,
+         sizeof ss.tmp_reg_n_xaccesses);
+
+  extract_insn (insn);
+
+  cross = get_attr_cross (insn);
+  destrf = get_attr_dest_regfile (insn);
+
+  nops = recog_data.n_operands;
+  x = PATTERN (insn);
+  if (GET_CODE (x) == COND_EXEC)
+    {
+      c6x_mark_reg_read (XEXP (XEXP (x, 0), 0), false);
+      nops -= 2;
+    }
+
+  for (i = 0; i < nops; i++)
+    {
+      rtx op = recog_data.operand[i];
+      if (recog_data.operand_type[i] == OP_OUT)
+       continue;
+      if (REG_P (op))
+       {
+         bool this_cross = cross;
+         if (destrf == DEST_REGFILE_A && A_REGNO_P (REGNO (op)))
+           this_cross = false;
+         if (destrf == DEST_REGFILE_B && B_REGNO_P (REGNO (op)))
+           this_cross = false;
+         c6x_mark_reg_read (op, this_cross);
+       }
+      else if (MEM_P (op))
+       {
+         op = XEXP (op, 0);
+         switch (GET_CODE (op))
+           {
+           case POST_INC:
+           case PRE_INC:
+           case POST_DEC:
+           case PRE_DEC:
+             op = XEXP (op, 0);
+             /* fall through */
+           case REG:
+             c6x_mark_reg_read (op, false);
+             break;
+           case POST_MODIFY:
+           case PRE_MODIFY:
+             op = XEXP (op, 1);
+             gcc_assert (GET_CODE (op) == PLUS);
+             /* fall through */
+           case PLUS:
+             c6x_mark_reg_read (XEXP (op, 0), false);
+             if (REG_P (XEXP (op, 1)))
+               c6x_mark_reg_read (XEXP (op, 1), false);
+             break;
+           case SYMBOL_REF:
+           case LABEL_REF:
+           case CONST:
+             c6x_mark_regno_read (REG_B14, false);
+             break;
+           default:
+             gcc_unreachable ();
+           }
+       }
+      else if (!CONSTANT_P (op) && strlen (recog_data.constraints[i]) > 0)
+       gcc_unreachable ();
+    }
+  return reg_access_stall;
+}
+
+/* Helper function for the TARGET_SCHED_REORDER and
+   TARGET_SCHED_REORDER2 hooks.  If scheduling an insn would be unsafe
+   in the current cycle, move it down in the ready list and return the
+   number of non-unsafe insns.  */
+
+static int
+c6x_sched_reorder_1 (rtx *ready, int *pn_ready, int clock_var)
+{
+  int n_ready = *pn_ready;
+  rtx *e_ready = ready + n_ready;
+  rtx *insnp;
+  int first_jump;
+
+  /* Keep track of conflicts due to a limit number of register accesses,
+     and due to stalls incurred by too early accesses of registers using
+     cross paths.  */
+
+  for (insnp = ready; insnp < e_ready; insnp++)
+    {
+      rtx insn = *insnp;
+      int icode = recog_memoized (insn);
+      bool is_asm = (icode < 0
+                    && (GET_CODE (PATTERN (insn)) == ASM_INPUT
+                        || asm_noperands (PATTERN (insn)) >= 0));
+      bool no_parallel = (is_asm
+                         || (icode >= 0
+                             && get_attr_type (insn) == TYPE_ATOMIC));
+
+      /* We delay asm insns until all delay slots are exhausted.  We can't
+        accurately tell how many cycles an asm takes, and the main scheduling
+        code always assumes at least 1 cycle, which may be wrong.  */
+      if ((no_parallel
+          && (ss.issued_this_cycle > 0 || clock_var < ss.delays_finished_at))
+         || c6x_registers_update (insn))
+       {
+         memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx));
+         *ready = insn;
+         n_ready--;
+         ready++;
+       }
+      else if (shadow_p (insn))
+       {
+         memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx));
+         *ready = insn;
+       }
+    }
+
+  /* Ensure that no other jump is scheduled in jump delay slots, since
+     it would put the machine into the wrong state.  Also, we must
+     avoid scheduling insns that have a latency longer than the
+     remaining jump delay slots, as the code at the jump destination
+     won't be prepared for it.
+
+     However, we can relax this condition somewhat.  The rest of the
+     scheduler will automatically avoid scheduling an insn on which
+     the jump shadow depends so late that its side effect happens
+     after the jump.  This means that if we see an insn with a longer
+     latency here, it can safely be scheduled if we can ensure that it
+     has a predicate opposite of the previous jump: the side effect
+     will happen in what we think of as the same basic block.  In
+     c6x_variable_issue, we will record the necessary predicate in
+     new_conditions, and after scheduling is finished, we will modify
+     the insn.
+
+     Special care must be taken whenever there is more than one jump
+     in flight.  */
+
+  first_jump = first_jump_index (clock_var);
+  if (first_jump != -1)
+    {
+      int first_cycle = get_jump_cycle (first_jump);
+      rtx first_cond = get_jump_cond (first_jump);
+      int second_cycle = 0;
+
+      if (first_jump > 0)
+       second_cycle = get_jump_cycle (first_jump - 1);
+
+      for (insnp = ready; insnp < e_ready; insnp++)
+       {
+         rtx insn = *insnp;
+         int icode = recog_memoized (insn);
+         bool is_asm = (icode < 0
+                        && (GET_CODE (PATTERN (insn)) == ASM_INPUT
+                            || asm_noperands (PATTERN (insn)) >= 0));
+         int this_cycles;
+         enum attr_type type;
+
+         gcc_assert (!is_asm);
+         if (icode < 0)
+           continue;
+         this_cycles = get_attr_cycles (insn);
+         type = get_attr_type (insn);
+         /* Treat branches specially; there is also a hazard if two jumps
+            end at the same cycle.  */
+         if (type == TYPE_BRANCH || type == TYPE_CALL)
+           this_cycles++;
+         if (clock_var + this_cycles <= first_cycle)
+           continue;
+         if ((first_jump > 0 && clock_var + this_cycles > second_cycle)
+             || !predicate_insn (insn, first_cond, false))
+           {
+             memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx));
+             *ready = insn;
+             n_ready--;
+             ready++;
+           }
+       }
+    }
+
+  return n_ready;
+}
+
+/* Implement the TARGET_SCHED_REORDER hook.  We save the current clock
+   for later and clear the register access information for the new
+   cycle.  We also move asm statements out of the way if they would be
+   scheduled in a delay slot.  */
+
+static int
+c6x_sched_reorder (FILE *dump ATTRIBUTE_UNUSED,
+                  int sched_verbose ATTRIBUTE_UNUSED,
+                  rtx *ready ATTRIBUTE_UNUSED,
+                  int *pn_ready ATTRIBUTE_UNUSED, int clock_var)
+{
+  ss.curr_sched_clock = clock_var;
+  ss.issued_this_cycle = 0;
+  memset (ss.reg_n_accesses, 0, sizeof ss.reg_n_accesses);
+  memset (ss.reg_n_xaccesses, 0, sizeof ss.reg_n_xaccesses);
+
+  if (ready == NULL)
+    return 0;
+
+  return c6x_sched_reorder_1 (ready, pn_ready, clock_var);
+}
+
+/* Implement the TARGET_SCHED_REORDER2 hook.  We use this to record the clock
+   cycle for every insn.  */
+
+static int
+c6x_sched_reorder2 (FILE *dump ATTRIBUTE_UNUSED,
+                   int sched_verbose ATTRIBUTE_UNUSED,
+                   rtx *ready ATTRIBUTE_UNUSED,
+                   int *pn_ready ATTRIBUTE_UNUSED, int clock_var)
+{
+  /* FIXME: the assembler rejects labels inside an execute packet.
+     This can occur if prologue insns are scheduled in parallel with
+     others, so we avoid this here.  Also make sure that nothing is
+     scheduled in parallel with a TYPE_ATOMIC insn or after a jump.  */
+  if (RTX_FRAME_RELATED_P (ss.last_scheduled_insn)
+      || JUMP_P (ss.last_scheduled_insn)
+      || (recog_memoized (ss.last_scheduled_insn) >= 0
+         && get_attr_type (ss.last_scheduled_insn) == TYPE_ATOMIC))
+    {
+      int n_ready = *pn_ready;
+      rtx *e_ready = ready + n_ready;
+      rtx *insnp;
+
+      for (insnp = ready; insnp < e_ready; insnp++)
+       {
+         rtx insn = *insnp;
+         if (!shadow_p (insn))
+           {
+             memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx));
+             *ready = insn;
+             n_ready--;
+             ready++;
+           }
+       }
+      return n_ready;
+    }
+
+  return c6x_sched_reorder_1 (ready, pn_ready, clock_var);
+}
+
+/* Subroutine of maybe_clobber_cond, called through note_stores.  */
+
+static void
+clobber_cond_1 (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data1)
+{
+  rtx *cond = (rtx *)data1;
+  if (*cond != NULL_RTX && reg_overlap_mentioned_p (x, *cond))
+    *cond = NULL_RTX;
+}
+
+/* Examine INSN, and if it destroys the conditions have recorded for
+   any of the jumps in flight, clear that condition so that we don't
+   predicate any more insns.  CLOCK_VAR helps us limit the search to
+   only those jumps which are still in flight.  */
+
+static void
+maybe_clobber_cond (rtx insn, int clock_var)
+{
+  int n, idx;
+  idx = ss.jump_cycle_index;
+  for (n = 0; n < 12; n++, idx++)
+    {
+      rtx cond, link;
+      int cycle;
+
+      if (idx >= 12)
+       idx -= 12;
+      cycle = ss.jump_cycles[idx];
+      if (cycle <= clock_var)
+       return;
+
+      cond = ss.jump_cond[idx];
+      if (cond == NULL_RTX)
+       continue;
+
+      if (CALL_P (insn))
+       {
+         ss.jump_cond[idx] = NULL_RTX;
+         continue;
+       }
+
+      note_stores (PATTERN (insn), clobber_cond_1, ss.jump_cond + idx);
+      for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+       if (REG_NOTE_KIND (link) == REG_INC)
+         clobber_cond_1 (XEXP (link, 0), NULL_RTX, ss.jump_cond + idx);
+    }
+}
+
+/* Implement the TARGET_SCHED_VARIABLE_ISSUE hook.  We are about to
+   issue INSN.  Return the number of insns left on the ready queue
+   that can be issued this cycle.
+   We use this hook to record clock cycles and reservations for every insn.  */
+
+static int
+c6x_variable_issue (FILE *dump ATTRIBUTE_UNUSED,
+                   int sched_verbose ATTRIBUTE_UNUSED,
+                   rtx insn, int can_issue_more ATTRIBUTE_UNUSED)
+{
+  ss.last_scheduled_insn = insn;
+  if (GET_CODE (PATTERN (insn)) != USE && GET_CODE (PATTERN (insn)) != CLOBBER)
+    ss.issued_this_cycle++;
+  if (insn_info)
+    {
+      int curr_clock = ss.curr_sched_clock;
+      int uid = INSN_UID (insn);
+      int icode = recog_memoized (insn);
+      rtx first_cond;
+      int first, first_cycle;
+
+      insn_set_clock (insn, curr_clock);
+      INSN_INFO_ENTRY (uid).ebb_start
+       = curr_clock == 0 && ss.issued_this_cycle == 1;
+
+      first = first_jump_index (ss.curr_sched_clock);
+      if (first == -1)
+       {
+         first_cycle = 0;
+         first_cond = NULL_RTX;
+       }
+      else
+       {
+         first_cycle = get_jump_cycle (first);
+         first_cond = get_jump_cond (first);
+       }
+      if (icode >= 0
+         && first_cycle > curr_clock
+         && first_cond != NULL_RTX
+         && (curr_clock + get_attr_cycles (insn) > first_cycle
+             || get_attr_type (insn) == TYPE_BRANCH
+             || get_attr_type (insn) == TYPE_CALL))
+       INSN_INFO_ENTRY (uid).new_cond = first_cond;
+
+      maybe_clobber_cond (insn, curr_clock);
+
+      if (icode >= 0)
+       {
+         int i, cycles;
+
+         c6x_registers_update (insn);
+         memcpy (ss.reg_n_accesses, ss.tmp_reg_n_accesses,
+                 sizeof ss.reg_n_accesses);
+         memcpy (ss.reg_n_xaccesses, ss.tmp_reg_n_accesses,
+                 sizeof ss.reg_n_xaccesses);
+
+         cycles = get_attr_cycles (insn);
+         if (ss.delays_finished_at < ss.curr_sched_clock + cycles)
+           ss.delays_finished_at = ss.curr_sched_clock + cycles;
+         if (get_attr_type (insn) == TYPE_BRANCH
+             || get_attr_type (insn) == TYPE_CALL)
+           {
+             rtx opposite = condjump_opposite_condition (insn);
+             record_jump (ss.curr_sched_clock + cycles, opposite);
+           }
+
+         /* Mark the cycles in which the destination registers are written.
+            This is used for calculating stalls when using cross units.  */
+         extract_insn (insn);
+         /* Cross-path stalls don't apply to results of load insns.  */
+         if (get_attr_type (insn) == TYPE_LOAD
+             || get_attr_type (insn) == TYPE_LOADN
+             || get_attr_type (insn) == TYPE_LOAD_SHADOW)
+           cycles--;
+         for (i = 0; i < recog_data.n_operands; i++)
+           {
+             rtx op = recog_data.operand[i];
+             if (MEM_P (op))
+               {
+                 rtx addr = XEXP (op, 0);
+                 if (GET_RTX_CLASS (GET_CODE (addr)) == RTX_AUTOINC)
+                   c6x_mark_reg_written (XEXP (addr, 0),
+                                         insn_uid_get_clock (uid) + 1);
+               }
+             if (recog_data.operand_type[i] != OP_IN
+                 && REG_P (op))
+               {
+                 c6x_mark_reg_written (op,
+                                       insn_uid_get_clock (uid) + cycles);
+               }
+           }
+       }
+    }
+  return can_issue_more;
+}
+
+/* Implement the TARGET_SCHED_ADJUST_COST hook.  We need special handling for
+   anti- and output dependencies.  */
+
+static int
+c6x_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
+{
+  enum attr_type insn_type = TYPE_UNKNOWN, dep_insn_type = TYPE_UNKNOWN;
+  int dep_insn_code_number, insn_code_number;
+  int shadow_bonus = 0;
+  enum reg_note kind;
+  dep_insn_code_number = recog_memoized (dep_insn);
+  insn_code_number = recog_memoized (insn);
+
+  if (dep_insn_code_number >= 0)
+    dep_insn_type = get_attr_type (dep_insn);
+
+  if (insn_code_number >= 0)
+    insn_type = get_attr_type (insn);
+
+  kind = REG_NOTE_KIND (link);
+  if (kind == 0)
+    {
+      /* If we have a dependency on a load, and it's not for the result of
+        the load, it must be for an autoincrement.  Reduce the cost in that
+        case.  */
+      if (dep_insn_type == TYPE_LOAD)
+       {
+         rtx set = PATTERN (dep_insn);
+         if (GET_CODE (set) == COND_EXEC)
+           set = COND_EXEC_CODE (set);
+         if (GET_CODE (set) == UNSPEC)
+           cost = 1;
+         else
+           {
+             gcc_assert (GET_CODE (set) == SET);
+             if (!reg_overlap_mentioned_p (SET_DEST (set), PATTERN (insn)))
+               cost = 1;
+           }
+       }
+    }
+
+  /* A jump shadow needs to have its latency decreased by one.  Conceptually,
+     it occurs in between two cycles, but we schedule it at the end of the
+     first cycle.  */
+  if (shadow_type_p (insn_type))
+    shadow_bonus = 1;
+
+  /* Anti and output dependencies usually have zero cost, but we want
+     to insert a stall after a jump, and after certain floating point
+     insns that take more than one cycle to read their inputs.  In the
+     future, we should try to find a better algorithm for scheduling
+     jumps.  */
+  if (kind != 0)
+    {
+      /* We can get anti-dependencies against shadow insns.  Treat these
+        like output dependencies, so that the insn is entirely finished
+        before the branch takes place.  */
+      if (kind == REG_DEP_ANTI && insn_type == TYPE_SHADOW)
+       kind = REG_DEP_OUTPUT;
+      switch (dep_insn_type)
+       {
+       case TYPE_CALLP:
+         return 1;
+       case TYPE_BRANCH:
+       case TYPE_CALL:
+         if (get_attr_has_shadow (dep_insn) == HAS_SHADOW_Y)
+           /* This is a real_jump/real_call insn.  These don't have
+              outputs, and ensuring the validity of scheduling things
+              in the delay slot is the job of
+              c6x_sched_reorder_1.  */
+           return 0;
+         /* Unsplit calls can happen - e.g. for divide insns.  */
+         return 6;
+       case TYPE_LOAD:
+       case TYPE_LOADN:
+       case TYPE_INTDP:
+         if (kind == REG_DEP_OUTPUT)
+           return 5 - shadow_bonus;
+         return 0;
+       case TYPE_MPY4:
+       case TYPE_FP4:
+         if (kind == REG_DEP_OUTPUT)
+           return 4 - shadow_bonus;
+         return 0;
+       case TYPE_MPY2:
+         if (kind == REG_DEP_OUTPUT)
+           return 2 - shadow_bonus;
+         return 0;
+       case TYPE_CMPDP:
+         if (kind == REG_DEP_OUTPUT)
+           return 2 - shadow_bonus;
+         return 2;
+       case TYPE_ADDDP:
+       case TYPE_MPYSPDP:
+         if (kind == REG_DEP_OUTPUT)
+           return 7 - shadow_bonus;
+         return 2;
+       case TYPE_MPYSP2DP:
+         if (kind == REG_DEP_OUTPUT)
+           return 5 - shadow_bonus;
+         return 2;
+       case TYPE_MPYI:
+         if (kind == REG_DEP_OUTPUT)
+           return 9 - shadow_bonus;
+         return 4;
+       case TYPE_MPYID:
+       case TYPE_MPYDP:
+         if (kind == REG_DEP_OUTPUT)
+           return 10 - shadow_bonus;
+         return 4;
+
+       default:
+         if (insn_type == TYPE_SPKERNEL)
+           return 0;
+         if (kind == REG_DEP_OUTPUT)
+           return 1 - shadow_bonus;
+
+         return 0;
+       }
+    }
+
+  return cost - shadow_bonus;
+}
+\f
+/* Create a SEQUENCE rtx to replace the instructions in SLOT, of which there
+   are N_FILLED.  REAL_FIRST identifies the slot if the insn that appears
+   first in the original stream.  */
+
+static void
+gen_one_bundle (rtx *slot, int n_filled, int real_first)
+{
+  rtx bundle;
+  rtx t;
+  int i;
+
+  bundle = gen_rtx_SEQUENCE (VOIDmode, gen_rtvec_v (n_filled, slot));
+  bundle = make_insn_raw (bundle);
+  BLOCK_FOR_INSN (bundle) = BLOCK_FOR_INSN (slot[0]);
+  INSN_LOCATOR (bundle) = INSN_LOCATOR (slot[0]);
+  PREV_INSN (bundle) = PREV_INSN (slot[real_first]);
+
+  t = NULL_RTX;
+
+  for (i = 0; i < n_filled; i++)
+    {
+      rtx insn = slot[i];
+      remove_insn (insn);
+      PREV_INSN (insn) = t ? t : PREV_INSN (bundle);
+      if (t != NULL_RTX)
+       NEXT_INSN (t) = insn;
+      t = insn;
+      if (i > 0)
+       INSN_LOCATOR (slot[i]) = INSN_LOCATOR (bundle);
+    }
+
+  NEXT_INSN (bundle) = NEXT_INSN (PREV_INSN (bundle));
+  NEXT_INSN (t) = NEXT_INSN (bundle);
+  NEXT_INSN (PREV_INSN (bundle)) = bundle;
+  PREV_INSN (NEXT_INSN (bundle)) = bundle;
+}
+
+/* Move all parallel instructions into SEQUENCEs, so that no subsequent passes
+   try to insert labels in the middle.  */
+
+static void
+c6x_gen_bundles (void)
+{
+  basic_block bb;
+  rtx insn, next, last_call;
+
+  FOR_EACH_BB (bb)
+    {
+      rtx insn, next;
+      /* The machine is eight insns wide.  We can have up to six shadow
+        insns, plus an extra slot for merging the jump shadow.  */
+      rtx slot[15];
+      int n_filled = 0;
+      int first_slot = 0;
+
+      for (insn = BB_HEAD (bb);; insn = next)
+       {
+         int at_end;
+         rtx delete_this = NULL_RTX;
+
+         if (NONDEBUG_INSN_P (insn))
+           {
+             /* Put calls at the start of the sequence.  */
+             if (CALL_P (insn))
+               {
+                 first_slot++;
+                 if (n_filled)
+                   {
+                     memmove (&slot[1], &slot[0],
+                              n_filled * sizeof (slot[0]));
+                   }
+                 if (!shadow_p (insn))
+                   {
+                     PUT_MODE (insn, TImode);
+                     if (n_filled)
+                       PUT_MODE (slot[1], VOIDmode);
+                   }
+                 n_filled++;
+                 slot[0] = insn;
+               }
+             else
+               {
+                 slot[n_filled++] = insn;
+               }
+           }
+
+         next = NEXT_INSN (insn);
+         while (next && insn != BB_END (bb)
+                && !(NONDEBUG_INSN_P (next)
+                     && GET_CODE (PATTERN (next)) != USE
+                     && GET_CODE (PATTERN (next)) != CLOBBER))
+           {
+             insn = next;
+             next = NEXT_INSN (insn);
+           }
+
+         at_end = insn == BB_END (bb);
+         if (delete_this == NULL_RTX
+             && (at_end || (GET_MODE (next) == TImode
+                            && !(shadow_p (next) && CALL_P (next)))))
+           {
+             if (n_filled >= 2)
+               gen_one_bundle (slot, n_filled, first_slot);
+
+             n_filled = 0;
+             first_slot = 0;
+           }
+         if (at_end)
+           break;
+       }
+    }
+  /* Bundling, and emitting nops, can separate
+     NOTE_INSN_CALL_ARG_LOCATION from the corresponding calls.  Fix
+     that up here.  */
+  last_call = NULL_RTX;
+  for (insn = get_insns (); insn; insn = next)
+    {
+      next = NEXT_INSN (insn);
+      if (CALL_P (insn)
+         || (INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE
+             && CALL_P (XVECEXP (PATTERN (insn), 0, 0))))
+       last_call = insn;
+      if (!NOTE_P (insn) || NOTE_KIND (insn) != NOTE_INSN_CALL_ARG_LOCATION)
+       continue;
+      if (NEXT_INSN (last_call) == insn)
+       continue;
+      NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn);
+      PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn);
+      PREV_INSN (insn) = last_call;
+      NEXT_INSN (insn) = NEXT_INSN (last_call);
+      PREV_INSN (NEXT_INSN (insn)) = insn;
+      NEXT_INSN (PREV_INSN (insn)) = insn;
+      last_call = insn;
+    }
+}
+
+/* Emit a NOP instruction for CYCLES cycles after insn AFTER.  Return it.  */
+
+static rtx
+emit_nop_after (int cycles, rtx after)
+{
+  rtx insn;
+
+  /* mpydp has 9 delay slots, and we may schedule a stall for a cross-path
+     operation.  We don't need the extra NOP since in this case, the hardware
+     will automatically insert the required stall.  */
+  if (cycles == 10)
+    cycles--;
+
+  gcc_assert (cycles < 10);
+
+  insn = emit_insn_after (gen_nop_count (GEN_INT (cycles)), after);
+  PUT_MODE (insn, TImode);
+
+  return insn;
+}
+
+/* Determine whether INSN is a call that needs to have a return label
+   placed.  */
+
+static bool
+returning_call_p (rtx insn)
+{
+  if (CALL_P (insn))
+    return (!SIBLING_CALL_P (insn)
+           && get_attr_type (insn) != TYPE_CALLP
+           && get_attr_type (insn) != TYPE_SHADOW);
+  if (recog_memoized (insn) < 0)
+    return false;
+  if (get_attr_type (insn) == TYPE_CALL)
+    return true;
+  return false;
+}
+
+/* Determine whether INSN's pattern can be converted to use callp.  */
+static bool
+can_use_callp (rtx insn)
+{
+  int icode = recog_memoized (insn);
+  if (!TARGET_INSNS_64PLUS
+      || icode < 0
+      || GET_CODE (PATTERN (insn)) == COND_EXEC)
+    return false;
+
+  return ((icode == CODE_FOR_real_call
+          || icode == CODE_FOR_call_internal
+          || icode == CODE_FOR_call_value_internal)
+         && get_attr_dest_regfile (insn) == DEST_REGFILE_ANY);
+}
+
+/* Convert the pattern of INSN, which must be a CALL_INSN, into a callp.  */
+static void
+convert_to_callp (rtx insn)
+{
+  rtx lab;
+  extract_insn (insn);
+  if (GET_CODE (PATTERN (insn)) == SET)
+    {
+      rtx dest = recog_data.operand[0];
+      lab = recog_data.operand[1];
+      PATTERN (insn) = gen_callp_value (dest, lab);
+      INSN_CODE (insn) = CODE_FOR_callp_value;
+    }
+  else
+    {
+      lab = recog_data.operand[0];
+      PATTERN (insn) = gen_callp (lab);
+      INSN_CODE (insn) = CODE_FOR_callp;
+    }
+}
+
+/* Scan forwards from INSN until we find the next insn that has mode TImode
+   (indicating it starts a new cycle), and occurs in cycle CLOCK.
+   Return it if we find such an insn, NULL_RTX otherwise.  */
+static rtx
+find_next_cycle_insn (rtx insn, int clock)
+{
+  rtx t = insn;
+  if (GET_MODE (t) == TImode)
+    t = next_real_insn (t);
+  while (t && GET_MODE (t) != TImode)
+    t = next_real_insn (t);
+
+  if (t && insn_get_clock (t) == clock)
+    return t;
+  return NULL_RTX;
+}
+
+/* If COND_INSN has a COND_EXEC condition, wrap the same condition
+   around PAT.  Return PAT either unchanged or modified in this
+   way.  */
+static rtx
+duplicate_cond (rtx pat, rtx cond_insn)
+{
+  rtx cond_pat = PATTERN (cond_insn);
+  if (GET_CODE (cond_pat) == COND_EXEC)
+    pat = gen_rtx_COND_EXEC (VOIDmode, copy_rtx (COND_EXEC_TEST (cond_pat)),
+                            pat);
+  return pat;
+}
+
+/* Walk forward from INSN to find the last insn that issues in the same clock
+   cycle.  */
+static rtx
+find_last_same_clock (rtx insn)
+{
+  rtx retval = insn;
+  rtx t = next_real_insn (insn);
+
+  while (t && GET_MODE (t) != TImode)
+    {
+      if (!DEBUG_INSN_P (t) && recog_memoized (t) >= 0)
+       retval = t;
+      t = next_real_insn (t);
+    }
+  return retval;
+}
+
+/* For every call insn in the function, emit code to load the return
+   address.  For each call we create a return label and store it in
+   CALL_LABELS.  If are not scheduling, we emit the labels here,
+   otherwise the caller will do it later.
+   This function is called after final insn scheduling, but before creating
+   the SEQUENCEs that represent execute packets.  */
+
+static void
+reorg_split_calls (rtx *call_labels)
+{
+  unsigned int reservation_mask = 0;
+  rtx insn = get_insns ();
+  gcc_assert (GET_CODE (insn) == NOTE);
+  insn = next_real_insn (insn);
+  while (insn)
+    {
+      int uid;
+      rtx next = next_real_insn (insn);
+
+      if (DEBUG_INSN_P (insn))
+       goto done;
+
+      if (GET_MODE (insn) == TImode)
+       reservation_mask = 0;
+      uid = INSN_UID (insn);
+      if (c6x_flag_schedule_insns2 && recog_memoized (insn) >= 0)
+       reservation_mask |= 1 << INSN_INFO_ENTRY (uid).reservation;
+
+      if (returning_call_p (insn))
+       {
+         rtx label = gen_label_rtx ();
+         rtx labelref = gen_rtx_LABEL_REF (Pmode, label);
+         rtx reg = gen_rtx_REG (SImode, RETURN_ADDR_REGNO);
+
+         LABEL_NUSES (label) = 2;
+         if (!c6x_flag_schedule_insns2)
+           {
+             if (can_use_callp (insn))
+               convert_to_callp (insn);
+             else
+               {
+                 rtx t;
+                 rtx slot[4];
+                 emit_label_after (label, insn);
+
+                 /* Bundle the call and its delay slots into a single
+                    SEQUENCE.  While these do not issue in parallel
+                    we need to group them into a single EH region.  */
+                 slot[0] = insn;
+                 PUT_MODE (insn, TImode);
+                 if (TARGET_INSNS_64)
+                   {
+                     t = gen_addkpc (reg, labelref, GEN_INT (4));
+                     slot[1] = emit_insn_after (duplicate_cond (t, insn),
+                                                insn);
+                     PUT_MODE (slot[1], TImode);
+                     gen_one_bundle (slot, 2, 0);
+                   }
+                 else
+                   {
+                     slot[3] = emit_insn_after (gen_nop_count (GEN_INT (3)),
+                                                insn);
+                     PUT_MODE (slot[3], TImode);
+                     t = gen_movsi_lo_sum (reg, reg, labelref);
+                     slot[2] = emit_insn_after (duplicate_cond (t, insn),
+                                                 insn);
+                     PUT_MODE (slot[2], TImode);
+                     t = gen_movsi_high (reg, labelref);
+                     slot[1] = emit_insn_after (duplicate_cond (t, insn),
+                                                insn);
+                     PUT_MODE (slot[1], TImode);
+                     gen_one_bundle (slot, 4, 0);
+                   }
+               }
+           }
+         else
+           {
+             /* If we scheduled, we reserved the .S2 unit for one or two
+                cycles after the call.  Emit the insns in these slots,
+                unless it's possible to create a CALLP insn.
+                Note that this works because the dependencies ensure that
+                no insn setting/using B3 is scheduled in the delay slots of
+                a call.  */
+             int this_clock = insn_get_clock (insn);
+             rtx last_same_clock;
+             rtx after1;
+
+             call_labels[INSN_UID (insn)] = label;
+
+             last_same_clock = find_last_same_clock (insn);
+
+             if (can_use_callp (insn))
+               {
+                 /* Find the first insn of the next execute packet.  If it
+                    is outside the branch delay slots of this call, we may
+                    use a CALLP insn.  */
+                 rtx next_cycle_start = next_nonnote_nondebug_insn (last_same_clock);
+
+                 if (CALL_P (next_cycle_start)
+                     && (insn_get_clock (next_cycle_start) == this_clock + 5))
+                   {
+                     convert_to_callp (next_cycle_start);
+                     insn_set_clock (next_cycle_start, this_clock);
+                     if (GET_MODE (insn) == TImode)
+                       {
+                         rtx new_cycle_first = NEXT_INSN (insn);
+                         while (!NONDEBUG_INSN_P (new_cycle_first)
+                                || GET_CODE (PATTERN (new_cycle_first)) == USE
+                                || GET_CODE (PATTERN (new_cycle_first)) == CLOBBER)
+                           new_cycle_first = NEXT_INSN (new_cycle_first);
+                         PUT_MODE (new_cycle_first, TImode);
+                         if (new_cycle_first != next_cycle_start)
+                           PUT_MODE (next_cycle_start, VOIDmode);
+                         INSN_INFO_ENTRY (INSN_UID (new_cycle_first)).ebb_start
+                           = INSN_INFO_ENTRY (INSN_UID (insn)).ebb_start;
+                       }
+                     else
+                       PUT_MODE (next_cycle_start, VOIDmode);
+                     delete_insn (insn);
+                     goto done;
+                   }
+               }
+             after1 = find_next_cycle_insn (last_same_clock, this_clock + 1);
+             if (after1 == NULL_RTX)
+               after1 = last_same_clock;
+             else
+               after1 = find_last_same_clock (after1);
+             if (TARGET_INSNS_64)
+               {
+                 rtx x1 = gen_addkpc (reg, labelref, const0_rtx);
+                 x1 = emit_insn_after (duplicate_cond (x1, insn), after1);
+                 insn_set_clock (x1, this_clock + 1);
+                 INSN_INFO_ENTRY (INSN_UID (x1)).reservation = RESERVATION_S2;
+                 if (after1 == last_same_clock)
+                   PUT_MODE (x1, TImode);
+               }
+             else
+               {
+                 rtx x1, x2;
+                 rtx after2 = find_next_cycle_insn (after1, this_clock + 2);
+                 if (after2 == NULL_RTX)
+                   after2 = after1;
+                 x2 = gen_movsi_lo_sum (reg, reg, labelref);
+                 x2 = emit_insn_after (duplicate_cond (x2, insn), after2);
+                 x1 = gen_movsi_high (reg, labelref);
+                 x1 = emit_insn_after (duplicate_cond (x1, insn), after1);
+                 insn_set_clock (x1, this_clock + 1);
+                 insn_set_clock (x2, this_clock + 2);
+                 INSN_INFO_ENTRY (INSN_UID (x1)).reservation = RESERVATION_S2;
+                 INSN_INFO_ENTRY (INSN_UID (x2)).reservation = RESERVATION_S2;
+                 if (after1 == last_same_clock)
+                   PUT_MODE (x1, TImode);
+                 if (after1 == after2)
+                   PUT_MODE (x2, TImode);
+               }
+           }
+       }
+    done:
+      insn = next;
+    }
+}
+
+/* Called as part of c6x_reorg.  This function emits multi-cycle NOP
+   insns as required for correctness.  CALL_LABELS is the array that
+   holds the return labels for call insns; we emit these here if
+   scheduling was run earlier.  */
+
+static void
+reorg_emit_nops (rtx *call_labels)
+{
+  bool first;
+  rtx prev, last_call;
+  int prev_clock, earliest_bb_end;
+  int prev_implicit_nops;
+  rtx insn = get_insns ();
+
+  /* We look at one insn (or bundle inside a sequence) in each iteration, storing
+     its issue time in PREV_CLOCK for the next iteration.  If there is a gap in
+     clocks, we must insert a NOP.
+     EARLIEST_BB_END tracks in which cycle all insns that have been issued in the
+     current basic block will finish.  We must not allow the next basic block to
+     begin before this cycle.
+     PREV_IMPLICIT_NOPS tells us whether we've seen an insn that implicitly contains
+     a multi-cycle nop.  The code is scheduled such that subsequent insns will
+     show the cycle gap, but we needn't insert a real NOP instruction.  */
+  insn = next_real_insn (insn);
+  last_call = prev = NULL_RTX;
+  prev_clock = -1;
+  earliest_bb_end = 0;
+  prev_implicit_nops = 0;
+  first = true;
+  while (insn)
+    {
+      int this_clock = -1;
+      rtx next;
+      int max_cycles = 0;
+
+      next = next_real_insn (insn);
+
+      if (DEBUG_INSN_P (insn)
+         || GET_CODE (PATTERN (insn)) == USE
+         || GET_CODE (PATTERN (insn)) == CLOBBER
+         || shadow_or_blockage_p (insn)
+         || (JUMP_P (insn)
+             && (GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
+                 || GET_CODE (PATTERN (insn)) == ADDR_VEC)))
+       goto next_insn;
+
+      if (!c6x_flag_schedule_insns2)
+       /* No scheduling; ensure that no parallel issue happens.  */
+       PUT_MODE (insn, TImode);
+      else
+       {
+         int cycles;
+
+         this_clock = insn_get_clock (insn);
+         if (this_clock != prev_clock)
+           {
+             PUT_MODE (insn, TImode);
+
+             if (!first)
+               {
+                 cycles = this_clock - prev_clock;
+
+                 cycles -= prev_implicit_nops;
+                 if (cycles > 1)
+                   {
+                     rtx nop = emit_nop_after (cycles - 1, prev);
+                     insn_set_clock (nop, prev_clock + prev_implicit_nops + 1);
+                   }
+               }
+             prev_clock = this_clock;
+
+             if (last_call
+                 && insn_get_clock (last_call) + 6 <= this_clock)
+               {
+                 emit_label_before (call_labels[INSN_UID (last_call)], insn);
+                 last_call = NULL_RTX;
+               }
+             prev_implicit_nops = 0;
+           }
+       }
+
+      /* Examine how many cycles the current insn takes, and adjust
+        LAST_CALL, EARLIEST_BB_END and PREV_IMPLICIT_NOPS.  */
+      if (recog_memoized (insn) >= 0
+         /* If not scheduling, we've emitted NOPs after calls already.  */
+         && (c6x_flag_schedule_insns2 || !returning_call_p (insn)))
+       {
+         max_cycles = get_attr_cycles (insn);
+         if (get_attr_type (insn) == TYPE_CALLP)
+           prev_implicit_nops = 5;
+       }
+      else
+       max_cycles = 1;
+      if (returning_call_p (insn))
+       last_call = insn;
+
+      if (c6x_flag_schedule_insns2)
+       {
+         gcc_assert (this_clock >= 0);
+         if (earliest_bb_end < this_clock + max_cycles)
+           earliest_bb_end = this_clock + max_cycles;
+       }
+      else if (max_cycles > 1)
+       emit_nop_after (max_cycles - 1, insn);
+
+      prev = insn;
+      first = false;
+
+    next_insn:
+      if (c6x_flag_schedule_insns2
+         && (next == NULL_RTX
+             || (GET_MODE (next) == TImode
+                 && INSN_INFO_ENTRY (INSN_UID (next)).ebb_start))
+         && earliest_bb_end > 0)
+       {
+         int cycles = earliest_bb_end - prev_clock;
+         if (cycles > 1)
+           {
+             prev = emit_nop_after (cycles - 1, prev);
+             insn_set_clock (prev, prev_clock + prev_implicit_nops + 1);
+           }
+         earliest_bb_end = 0;
+         prev_clock = -1;
+         first = true;
+
+         if (last_call)
+           emit_label_after (call_labels[INSN_UID (last_call)], prev);
+         last_call = NULL_RTX;
+       }
+      insn = next;
+    }
+}
+
+/* If possible, split INSN, which we know is either a jump or a call, into a real
+   insn and its shadow.  */
+static void
+split_delayed_branch (rtx insn)
+{
+  int code = recog_memoized (insn);
+  rtx i1, newpat;
+  rtx pat = PATTERN (insn);
+
+  if (GET_CODE (pat) == COND_EXEC)
+    pat = COND_EXEC_CODE (pat);
+
+  if (CALL_P (insn))
+    {
+      rtx src = pat, dest = NULL_RTX;
+      rtx callee;
+      if (GET_CODE (pat) == SET)
+       {
+         dest = SET_DEST (pat);
+         src = SET_SRC (pat);
+       }
+      callee = XEXP (XEXP (src, 0), 0);
+      if (SIBLING_CALL_P (insn))
+       {
+         if (REG_P (callee))
+           newpat = gen_indirect_sibcall_shadow ();
+         else
+           newpat = gen_sibcall_shadow (callee);
+         pat = gen_real_jump (callee);
+       }
+      else if (dest != NULL_RTX)
+       {
+         if (REG_P (callee))
+           newpat = gen_indirect_call_value_shadow (dest);
+         else
+           newpat = gen_call_value_shadow (dest, callee);
+         pat = gen_real_call (callee);
+       }
+      else
+       {
+         if (REG_P (callee))
+           newpat = gen_indirect_call_shadow ();
+         else
+           newpat = gen_call_shadow (callee);
+         pat = gen_real_call (callee);
+       }
+      pat = duplicate_cond (pat, insn);
+      newpat = duplicate_cond (newpat, insn);
+    }
+  else
+    {
+      rtx src, op;
+      if (GET_CODE (pat) == PARALLEL
+         && GET_CODE (XVECEXP (pat, 0, 0)) == RETURN)
+       {
+         newpat = gen_return_shadow ();
+         pat = gen_real_ret (XEXP (XVECEXP (pat, 0, 1), 0));
+         newpat = duplicate_cond (newpat, insn);
+       }
+      else
+       switch (code)
+         {
+         case CODE_FOR_br_true:
+         case CODE_FOR_br_false:
+           src = SET_SRC (pat);
+           op = XEXP (src, code == CODE_FOR_br_true ? 1 : 2);
+           newpat = gen_condjump_shadow (op);
+           pat = gen_real_jump (op);
+           if (code == CODE_FOR_br_true)
+             pat = gen_rtx_COND_EXEC (VOIDmode, XEXP (src, 0), pat);
+           else
+             pat = gen_rtx_COND_EXEC (VOIDmode,
+                                      reversed_comparison (XEXP (src, 0),
+                                                           VOIDmode),
+                                      pat);
+           break;
+
+         case CODE_FOR_jump:
+           op = SET_SRC (pat);
+           newpat = gen_jump_shadow (op);
+           break;
+
+         case CODE_FOR_indirect_jump:
+           newpat = gen_indirect_jump_shadow ();
+           break;
+
+         case CODE_FOR_return_internal:
+           newpat = gen_return_shadow ();
+           pat = gen_real_ret (XEXP (XVECEXP (pat, 0, 1), 0));
+           break;
+
+         default:
+           return;
+         }
+    }
+  i1 = emit_insn_before (pat, insn);
+  PATTERN (insn) = newpat;
+  INSN_CODE (insn) = -1;
+  record_delay_slot_pair (i1, insn, 5);
+}
+
+/* Split every insn (i.e. jumps and calls) which can have delay slots into
+   two parts: the first one is scheduled normally and emits the instruction,
+   while the second one is a shadow insn which shows the side effect taking
+   place. The second one is placed in the right cycle by the scheduler, but
+   not emitted as an assembly instruction.  */
+
+static void
+split_delayed_insns (void)
+{
+  rtx insn;
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    {
+      if (JUMP_P (insn) || CALL_P (insn))
+       split_delayed_branch (insn);
+    }
+}
+
+/* For every insn that has an entry in the new_conditions vector, give it
+   the appropriate predicate.  */
+static void
+conditionalize_after_sched (void)
+{
+  basic_block bb;
+  rtx insn;
+  FOR_EACH_BB (bb)
+    FOR_BB_INSNS (bb, insn)
+      {
+       unsigned uid = INSN_UID (insn);
+       rtx cond;
+       if (!NONDEBUG_INSN_P (insn) || uid >= INSN_INFO_LENGTH)
+         continue;
+       cond = INSN_INFO_ENTRY (uid).new_cond;
+       if (cond == NULL_RTX)
+         continue;
+       if (dump_file)
+         fprintf (dump_file, "Conditionalizing insn %d\n", uid);
+       predicate_insn (insn, cond, true);
+      }
+}
+
+/* Implement the TARGET_MACHINE_DEPENDENT_REORG pass.  We split call insns here
+   into a sequence that loads the return register and performs the call,
+   and emit the return label.
+   If scheduling after reload is requested, it happens here.  */
+
+static void
+c6x_reorg (void)
+{
+  basic_block bb;
+  rtx *call_labels;
+  bool do_selsched = (c6x_flag_schedule_insns2 && flag_selective_scheduling2
+                     && !maybe_skip_selective_scheduling ());
+
+  /* We are freeing block_for_insn in the toplev to keep compatibility
+     with old MDEP_REORGS that are not CFG based.  Recompute it now.  */
+  compute_bb_for_insn ();
+
+  df_clear_flags (DF_LR_RUN_DCE);
+
+  /* If optimizing, we'll have split before scheduling.  */
+  if (optimize == 0)
+    split_all_insns ();
+
+  if (c6x_flag_schedule_insns2)
+    {
+      int sz = get_max_uid () * 3 / 2 + 1;
+
+      insn_info = VEC_alloc (c6x_sched_insn_info, heap, sz);
+
+      /* Make sure the real-jump insns we create are not deleted.  */
+      sched_no_dce = true;
+
+      split_delayed_insns ();
+      timevar_push (TV_SCHED2);
+      if (do_selsched)
+       run_selective_scheduling ();
+      else
+       schedule_ebbs ();
+      conditionalize_after_sched ();
+      timevar_pop (TV_SCHED2);
+
+      free_delay_pairs ();
+      sched_no_dce = false;
+    }
+
+  call_labels = XCNEWVEC (rtx, get_max_uid () + 1);
+
+  reorg_split_calls (call_labels);
+
+  if (c6x_flag_schedule_insns2)
+    {
+      FOR_EACH_BB (bb)
+       if ((bb->flags & BB_DISABLE_SCHEDULE) == 0)
+         assign_reservations (BB_HEAD (bb), BB_END (bb));
+    }
+
+  if (c6x_flag_var_tracking)
+    {
+      timevar_push (TV_VAR_TRACKING);
+      variable_tracking_main ();
+      timevar_pop (TV_VAR_TRACKING);
+    }
+
+  reorg_emit_nops (call_labels);
+
+  /* Post-process the schedule to move parallel insns into SEQUENCEs.  */
+  if (c6x_flag_schedule_insns2)
+    {
+      free_delay_pairs ();
+      c6x_gen_bundles ();
+    }
+
+  df_finish_pass (false);
+}
+
+/* Called when a function has been assembled.  It should perform all the
+   tasks of ASM_DECLARE_FUNCTION_SIZE in elfos.h, plus target-specific
+   tasks.
+   We free the reservation (and other scheduling) information here now that
+   all insns have been output.  */
+void
+c6x_function_end (FILE *file, const char *fname)
+{
+  c6x_output_fn_unwind (file);
+
+  if (insn_info)
+    VEC_free (c6x_sched_insn_info, heap, insn_info);
+  insn_info = NULL;
+
+  if (!flag_inhibit_size_directive)
+    ASM_OUTPUT_MEASURED_SIZE (file, fname);
+}
+\f
+/* Determine whether X is a shift with code CODE and an integer amount
+   AMOUNT.  */
+static bool
+shift_p (rtx x, enum rtx_code code, int amount)
+{
+  return (GET_CODE (x) == code && GET_CODE (XEXP (x, 1)) == CONST_INT
+         && INTVAL (XEXP (x, 1)) == amount);
+}
+
+/* Compute a (partial) cost for rtx X.  Return true if the complete
+   cost has been computed, and false if subexpressions should be
+   scanned.  In either case, *TOTAL contains the cost result.  */
+
+static bool
+c6x_rtx_costs (rtx x, int code, int outer_code, int *total, bool speed)
+{
+  int cost2 = COSTS_N_INSNS (1);
+  rtx op0, op1;
+
+  switch (code)
+    {
+    case CONST_INT:
+      if (outer_code == SET || outer_code == PLUS)
+        *total = satisfies_constraint_IsB (x) ? 0 : cost2;
+      else if (outer_code == AND || outer_code == IOR || outer_code == XOR
+              || outer_code == MINUS)
+       *total = satisfies_constraint_Is5 (x) ? 0 : cost2;
+      else if (GET_RTX_CLASS (outer_code) == RTX_COMPARE
+              || GET_RTX_CLASS (outer_code) == RTX_COMM_COMPARE)
+       *total = satisfies_constraint_Iu4 (x) ? 0 : cost2;
+      else if (outer_code == ASHIFT || outer_code == ASHIFTRT
+              || outer_code == LSHIFTRT)
+       *total = satisfies_constraint_Iu5 (x) ? 0 : cost2;
+      else
+       *total = cost2;
+      return true;
+
+    case CONST:
+    case LABEL_REF:
+    case SYMBOL_REF:
+    case CONST_DOUBLE:
+      *total = COSTS_N_INSNS (2);
+      return true;
+
+    case TRUNCATE:
+      /* Recognize a mult_highpart operation.  */
+      if ((GET_MODE (x) == HImode || GET_MODE (x) == SImode)
+         && GET_CODE (XEXP (x, 0)) == LSHIFTRT
+         && GET_MODE (XEXP (x, 0)) == GET_MODE_2XWIDER_MODE (GET_MODE (x))
+         && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
+         && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+         && INTVAL (XEXP (XEXP (x, 0), 1)) == GET_MODE_BITSIZE (GET_MODE (x)))
+       {
+         rtx mul = XEXP (XEXP (x, 0), 0);
+         rtx op0 = XEXP (mul, 0);
+         rtx op1 = XEXP (mul, 1);
+         enum rtx_code code0 = GET_CODE (op0);
+         enum rtx_code code1 = GET_CODE (op1);
+
+         if ((code0 == code1
+              && (code0 == SIGN_EXTEND || code0 == ZERO_EXTEND))
+             || (GET_MODE (x) == HImode
+                 && code0 == ZERO_EXTEND && code1 == SIGN_EXTEND))
+           {
+             if (GET_MODE (x) == HImode)
+               *total = COSTS_N_INSNS (2);
+             else
+               *total = COSTS_N_INSNS (12);
+             *total += rtx_cost (XEXP (op0, 0), code0, speed);
+             *total += rtx_cost (XEXP (op1, 0), code1, speed);
+             return true;
+           }
+       }
+      return false;
+
+    case ASHIFT:
+    case ASHIFTRT:
+    case LSHIFTRT:
+      if (GET_MODE (x) == DImode)
+       *total = COSTS_N_INSNS (CONSTANT_P (XEXP (x, 1)) ? 4 : 15);
+      else
+       *total = COSTS_N_INSNS (1);
+      return false;
+
+    case PLUS:
+    case MINUS:
+      *total = COSTS_N_INSNS (1);
+      op0 = code == PLUS ? XEXP (x, 0) : XEXP (x, 1);
+      op1 = code == PLUS ? XEXP (x, 1) : XEXP (x, 0);
+      if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD
+         && INTEGRAL_MODE_P (GET_MODE (x))
+         && GET_CODE (op0) == MULT
+         && GET_CODE (XEXP (op0, 1)) == CONST_INT
+         && (INTVAL (XEXP (op0, 1)) == 2
+             || INTVAL (XEXP (op0, 1)) == 4
+             || (code == PLUS && INTVAL (XEXP (op0, 1)) == 8)))
+       {
+         *total += rtx_cost (XEXP (op0, 0), ASHIFT, speed);
+         *total += rtx_cost (op1, (enum rtx_code)code, speed);
+         return true;
+       }
+      return false;
+
+    case MULT:
+      op0 = XEXP (x, 0);
+      op1 = XEXP (x, 1);
+      if (GET_MODE (x) == DFmode)
+       {
+         if (TARGET_FP)
+           *total = COSTS_N_INSNS (speed ? 10 : 1);
+         else
+           *total = COSTS_N_INSNS (speed ? 200 : 4);
+       }
+      else if (GET_MODE (x) == SFmode)
+       {
+         if (TARGET_FP)
+           *total = COSTS_N_INSNS (speed ? 4 : 1);
+         else
+           *total = COSTS_N_INSNS (speed ? 100 : 4);
+       }
+      else if (GET_MODE (x) == DImode)
+       {
+         if (TARGET_MPY32
+             && GET_CODE (op0) == GET_CODE (op1)
+             && (GET_CODE (op0) == ZERO_EXTEND
+                 || GET_CODE (op0) == SIGN_EXTEND))
+           {
+             *total = COSTS_N_INSNS (speed ? 2 : 1);
+             op0 = XEXP (op0, 0);
+             op1 = XEXP (op1, 0);
+           }
+         else
+           /* Maybe improve this laster.  */
+           *total = COSTS_N_INSNS (20);
+       }
+      else if (GET_MODE (x) == SImode)
+       {
+         if (((GET_CODE (op0) == ZERO_EXTEND
+               || GET_CODE (op0) == SIGN_EXTEND
+               || shift_p (op0, LSHIFTRT, 16))
+              && (GET_CODE (op1) == SIGN_EXTEND
+                  || GET_CODE (op1) == ZERO_EXTEND
+                  || scst5_operand (op1, SImode)
+                  || shift_p (op1, ASHIFTRT, 16)
+                  || shift_p (op1, LSHIFTRT, 16)))
+             || (shift_p (op0, ASHIFTRT, 16)
+                 && (GET_CODE (op1) == SIGN_EXTEND
+                     || shift_p (op1, ASHIFTRT, 16))))
+           {
+             *total = COSTS_N_INSNS (speed ? 2 : 1);
+             op0 = XEXP (op0, 0);
+             if (scst5_operand (op1, SImode))
+               op1 = NULL_RTX;
+             else
+               op1 = XEXP (op1, 0);
+           }
+         else if (!speed)
+           *total = COSTS_N_INSNS (1);
+         else if (TARGET_MPY32)
+           *total = COSTS_N_INSNS (4);
+         else
+           *total = COSTS_N_INSNS (6);
+       }
+      else if (GET_MODE (x) == HImode)
+       *total = COSTS_N_INSNS (speed ? 2 : 1);
+
+      if (GET_CODE (op0) != REG
+         && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
+       *total += rtx_cost (op0, MULT, speed);
+      if (op1 && GET_CODE (op1) != REG
+         && (GET_CODE (op1) != SUBREG || GET_CODE (SUBREG_REG (op1)) != REG))
+       *total += rtx_cost (op1, MULT, speed);
+      return true;
+
+    case UDIV:
+    case DIV:
+      /* This is a bit random; assuming on average there'll be 16 leading
+        zeros.  FIXME: estimate better for constant dividends.  */
+      *total = COSTS_N_INSNS (6 + 3 * 16);
+      return false;
+
+    case IF_THEN_ELSE:
+      /* Recognize the cmp_and/ior patterns.  */
+      op0 = XEXP (x, 0);
+      if ((GET_CODE (op0) == EQ || GET_CODE (op0) == NE)
+         && REG_P (XEXP (op0, 0))
+         && XEXP (op0, 1) == const0_rtx
+         && rtx_equal_p (XEXP (x, 1), XEXP (op0, 0)))
+       {
+         *total = rtx_cost (XEXP (x, 1), (enum rtx_code)outer_code, speed);
+         return false;
+       }
+      return false;
+
+    default:
+      return false;
+    }
+}
+
+/* Implements target hook vector_mode_supported_p.  */
+
+static bool
+c6x_vector_mode_supported_p (enum machine_mode mode)
+{
+  switch (mode)
+    {
+    case V2HImode:
+    case V4QImode:
+    case V2SImode:
+    case V4HImode:
+    case V8QImode:
+      return true;
+    default:
+      return false;
+    }
+}
+
+/* Implements TARGET_VECTORIZE_PREFERRED_SIMD_MODE.  */
+static enum machine_mode
+c6x_preferred_simd_mode (enum machine_mode mode)
+{
+  switch (mode)
+    {
+    case HImode:
+      return V2HImode;
+    case QImode:
+      return V4QImode;
+
+    default:
+      return word_mode;
+    }
+}
+
+/* Implement TARGET_SCALAR_MODE_SUPPORTED_P.  */
+
+static bool
+c6x_scalar_mode_supported_p (enum machine_mode mode)
+{
+  if (ALL_FIXED_POINT_MODE_P (mode)
+      && GET_MODE_PRECISION (mode) <= 2 * BITS_PER_WORD)
+    return true;
+
+  return default_scalar_mode_supported_p (mode);
+}
+
+/* Output a reference from a function exception table to the type_info
+   object X.  Output these via a special assembly directive.  */
+
+static bool
+c6x_output_ttype (rtx x)
+{
+  /* Use special relocations for symbol references.  */
+  if (GET_CODE (x) != CONST_INT)
+    fputs ("\t.ehtype\t", asm_out_file);
+  else
+    fputs ("\t.word\t", asm_out_file);
+  output_addr_const (asm_out_file, x);
+  fputc ('\n', asm_out_file);
+
+  return TRUE;
+}
+
+/* Modify the return address of the current function.  */
+
+void
+c6x_set_return_address (rtx source, rtx scratch)
+{
+  struct c6x_frame frame;
+  rtx addr;
+  HOST_WIDE_INT offset;
+
+  c6x_compute_frame_layout (&frame);
+  if (! c6x_save_reg (RETURN_ADDR_REGNO))
+    emit_move_insn (gen_rtx_REG (Pmode, RETURN_ADDR_REGNO), source);
+  else
+    {
+
+      if (frame_pointer_needed)
+       {
+         addr = hard_frame_pointer_rtx;
+         offset = frame.b3_offset;
+       }
+      else
+       {
+         addr = stack_pointer_rtx;
+         offset = frame.to_allocate - frame.b3_offset;
+       }
+
+      /* TODO: Use base+offset loads where possible.  */
+      if (offset)
+       {
+         HOST_WIDE_INT low = trunc_int_for_mode (offset, HImode);
+
+         emit_insn (gen_movsi_high (scratch, GEN_INT (low)));
+         if (low != offset)
+           emit_insn (gen_movsi_lo_sum (scratch, scratch, GEN_INT(offset)));
+         emit_insn (gen_addsi3 (scratch, addr, scratch));
+         addr = scratch;
+       }
+
+      emit_move_insn (gen_frame_mem (Pmode, addr), source);
+    }
+}
+
+/* We save pairs of registers using a DImode store.  Describe the component
+   registers for DWARF generation code.  */
+
+static rtx
+c6x_dwarf_register_span (rtx rtl)
+{
+    unsigned regno;
+    unsigned real_regno;
+    int nregs;
+    int i;
+    rtx p;
+
+    regno = REGNO (rtl);
+    nregs = HARD_REGNO_NREGS (regno, GET_MODE (rtl));
+    if (nregs == 1)
+      return  NULL_RTX;
+
+    p = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc(nregs));
+    for (i = 0; i < nregs; i++)
+      {
+       if (TARGET_BIG_ENDIAN)
+         real_regno = regno + nregs - (i + 1);
+       else
+         real_regno = regno + i;
+
+       XVECEXP (p, 0, i) = gen_rtx_REG (SImode, real_regno);
+      }
+
+    return p;
+}
+\f
+/* Codes for all the C6X builtins.  */
+enum c6x_builtins
+{
+  C6X_BUILTIN_SADD,
+  C6X_BUILTIN_SSUB,
+  C6X_BUILTIN_ADD2,
+  C6X_BUILTIN_SUB2,
+  C6X_BUILTIN_ADD4,
+  C6X_BUILTIN_SUB4,
+  C6X_BUILTIN_SADD2,
+  C6X_BUILTIN_SSUB2,
+  C6X_BUILTIN_SADDU4,
+
+  C6X_BUILTIN_SMPY,
+  C6X_BUILTIN_SMPYH,
+  C6X_BUILTIN_SMPYHL,
+  C6X_BUILTIN_SMPYLH,
+  C6X_BUILTIN_MPY2,
+  C6X_BUILTIN_SMPY2,
+
+  C6X_BUILTIN_CLRR,
+  C6X_BUILTIN_EXTR,
+  C6X_BUILTIN_EXTRU,
+
+  C6X_BUILTIN_SSHL,
+  C6X_BUILTIN_SUBC,
+  C6X_BUILTIN_ABS,
+  C6X_BUILTIN_ABS2,
+  C6X_BUILTIN_AVG2,
+  C6X_BUILTIN_AVGU4,
+
+  C6X_BUILTIN_MAX
+};
+
+
+static GTY(()) tree c6x_builtin_decls[C6X_BUILTIN_MAX];
+
+/* Return the C6X builtin for CODE.  */
+static tree
+c6x_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
+{
+  if (code >= C6X_BUILTIN_MAX)
+    return error_mark_node;
+
+  return c6x_builtin_decls[code];
+}
+
+#define def_builtin(NAME, TYPE, CODE)                                  \
+do {                                                                   \
+  tree bdecl;                                                          \
+  bdecl = add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD,   \
+                               NULL, NULL_TREE);                       \
+  c6x_builtin_decls[CODE] = bdecl;                                     \
+} while (0)
+
+/* Set up all builtin functions for this target.  */
+static void
+c6x_init_builtins (void)
+{
+  tree V4QI_type_node = build_vector_type (unsigned_intQI_type_node, 4);
+  tree V2HI_type_node = build_vector_type (intHI_type_node, 2);
+  tree V2SI_type_node = build_vector_type (intSI_type_node, 2);
+  tree int_ftype_int
+    = build_function_type_list (integer_type_node, integer_type_node,
+                               NULL_TREE);
+  tree int_ftype_int_int
+    = build_function_type_list (integer_type_node, integer_type_node,
+                               integer_type_node, NULL_TREE);
+  tree v2hi_ftype_v2hi
+    = build_function_type_list (V2HI_type_node, V2HI_type_node, NULL_TREE);
+  tree v4qi_ftype_v4qi_v4qi
+    = build_function_type_list (V4QI_type_node, V4QI_type_node,
+                               V4QI_type_node, NULL_TREE);
+  tree v2hi_ftype_v2hi_v2hi
+    = build_function_type_list (V2HI_type_node, V2HI_type_node,
+                               V2HI_type_node, NULL_TREE);
+  tree v2si_ftype_v2hi_v2hi
+    = build_function_type_list (V2SI_type_node, V2HI_type_node,
+                               V2HI_type_node, NULL_TREE);
+  
+  def_builtin ("__builtin_c6x_sadd", int_ftype_int_int,
+              C6X_BUILTIN_SADD);
+  def_builtin ("__builtin_c6x_ssub", int_ftype_int_int,
+              C6X_BUILTIN_SSUB);
+  def_builtin ("__builtin_c6x_add2", v2hi_ftype_v2hi_v2hi,
+              C6X_BUILTIN_ADD2);
+  def_builtin ("__builtin_c6x_sub2", v2hi_ftype_v2hi_v2hi,
+              C6X_BUILTIN_SUB2);
+  def_builtin ("__builtin_c6x_add4", v4qi_ftype_v4qi_v4qi,
+              C6X_BUILTIN_ADD4);
+  def_builtin ("__builtin_c6x_sub4", v4qi_ftype_v4qi_v4qi,
+              C6X_BUILTIN_SUB4);
+  def_builtin ("__builtin_c6x_mpy2", v2si_ftype_v2hi_v2hi,
+              C6X_BUILTIN_MPY2);
+  def_builtin ("__builtin_c6x_sadd2", v2hi_ftype_v2hi_v2hi,
+              C6X_BUILTIN_SADD2);
+  def_builtin ("__builtin_c6x_ssub2", v2hi_ftype_v2hi_v2hi,
+              C6X_BUILTIN_SSUB2);
+  def_builtin ("__builtin_c6x_saddu4", v4qi_ftype_v4qi_v4qi,
+              C6X_BUILTIN_SADDU4);
+  def_builtin ("__builtin_c6x_smpy2", v2si_ftype_v2hi_v2hi,
+              C6X_BUILTIN_SMPY2);
+
+  def_builtin ("__builtin_c6x_smpy", int_ftype_int_int,
+              C6X_BUILTIN_SMPY);
+  def_builtin ("__builtin_c6x_smpyh", int_ftype_int_int,
+              C6X_BUILTIN_SMPYH);
+  def_builtin ("__builtin_c6x_smpyhl", int_ftype_int_int,
+              C6X_BUILTIN_SMPYHL);
+  def_builtin ("__builtin_c6x_smpylh", int_ftype_int_int,
+              C6X_BUILTIN_SMPYLH);
+
+  def_builtin ("__builtin_c6x_sshl", int_ftype_int_int,
+              C6X_BUILTIN_SSHL);
+  def_builtin ("__builtin_c6x_subc", int_ftype_int_int,
+              C6X_BUILTIN_SUBC);
+
+  def_builtin ("__builtin_c6x_avg2", v2hi_ftype_v2hi_v2hi,
+              C6X_BUILTIN_AVG2);
+  def_builtin ("__builtin_c6x_avgu4", v4qi_ftype_v4qi_v4qi,
+              C6X_BUILTIN_AVGU4);
+
+  def_builtin ("__builtin_c6x_clrr", int_ftype_int_int,
+              C6X_BUILTIN_CLRR);
+  def_builtin ("__builtin_c6x_extr", int_ftype_int_int,
+              C6X_BUILTIN_EXTR);
+  def_builtin ("__builtin_c6x_extru", int_ftype_int_int,
+              C6X_BUILTIN_EXTRU);
+
+  def_builtin ("__builtin_c6x_abs", int_ftype_int, C6X_BUILTIN_ABS);
+  def_builtin ("__builtin_c6x_abs2", v2hi_ftype_v2hi, C6X_BUILTIN_ABS2);
+}
+
+
+struct builtin_description
+{
+  const enum insn_code icode;
+  const char *const name;
+  const enum c6x_builtins code;
+};
+
+static const struct builtin_description bdesc_2arg[] =
+{
+  { CODE_FOR_saddsi3, "__builtin_c6x_sadd", C6X_BUILTIN_SADD },
+  { CODE_FOR_ssubsi3, "__builtin_c6x_ssub", C6X_BUILTIN_SSUB },
+  { CODE_FOR_addv2hi3, "__builtin_c6x_add2", C6X_BUILTIN_ADD2 },
+  { CODE_FOR_subv2hi3, "__builtin_c6x_sub2", C6X_BUILTIN_SUB2 },
+  { CODE_FOR_addv4qi3, "__builtin_c6x_add4", C6X_BUILTIN_ADD4 },
+  { CODE_FOR_subv4qi3, "__builtin_c6x_sub4", C6X_BUILTIN_SUB4 },
+  { CODE_FOR_ss_addv2hi3, "__builtin_c6x_sadd2", C6X_BUILTIN_SADD2 },
+  { CODE_FOR_ss_subv2hi3, "__builtin_c6x_ssub2", C6X_BUILTIN_SSUB2 },
+  { CODE_FOR_us_addv4qi3, "__builtin_c6x_saddu4", C6X_BUILTIN_SADDU4 },
+
+  { CODE_FOR_subcsi3, "__builtin_c6x_subc", C6X_BUILTIN_SUBC },
+  { CODE_FOR_ss_ashlsi3, "__builtin_c6x_sshl", C6X_BUILTIN_SSHL },
+
+  { CODE_FOR_avgv2hi3, "__builtin_c6x_avg2", C6X_BUILTIN_AVG2 },
+  { CODE_FOR_uavgv4qi3, "__builtin_c6x_avgu4", C6X_BUILTIN_AVGU4 },
+
+  { CODE_FOR_mulhqsq3, "__builtin_c6x_smpy", C6X_BUILTIN_SMPY },
+  { CODE_FOR_mulhqsq3_hh, "__builtin_c6x_smpyh", C6X_BUILTIN_SMPYH },
+  { CODE_FOR_mulhqsq3_lh, "__builtin_c6x_smpylh", C6X_BUILTIN_SMPYLH },
+  { CODE_FOR_mulhqsq3_hl, "__builtin_c6x_smpyhl", C6X_BUILTIN_SMPYHL },
+
+  { CODE_FOR_mulv2hqv2sq3, "__builtin_c6x_smpy2", C6X_BUILTIN_SMPY2 },
+
+  { CODE_FOR_clrr, "__builtin_c6x_clrr", C6X_BUILTIN_CLRR },
+  { CODE_FOR_extr, "__builtin_c6x_extr", C6X_BUILTIN_EXTR },
+  { CODE_FOR_extru, "__builtin_c6x_extru", C6X_BUILTIN_EXTRU }
+};
+
+static const struct builtin_description bdesc_1arg[] =
+{
+  { CODE_FOR_ssabssi2, "__builtin_c6x_abs", C6X_BUILTIN_ABS },
+  { CODE_FOR_ssabsv2hi2, "__builtin_c6x_abs2", C6X_BUILTIN_ABS2 }
+};
+
+/* Errors in the source file can cause expand_expr to return const0_rtx
+   where we expect a vector.  To avoid crashing, use one of the vector
+   clear instructions.  */
+static rtx
+safe_vector_operand (rtx x, enum machine_mode mode)
+{
+  if (x != const0_rtx)
+    return x;
+  x = gen_reg_rtx (SImode);
+
+  emit_insn (gen_movsi (x, CONST0_RTX (SImode)));
+  return gen_lowpart (mode, x);
+}
+
+/* Subroutine of c6x_expand_builtin to take care of binop insns.  MACFLAG is -1
+   if this is a normal binary op, or one of the MACFLAG_xxx constants.  */
+
+static rtx
+c6x_expand_binop_builtin (enum insn_code icode, tree exp, rtx target,
+                         bool match_op)
+{
+  int offs = match_op ? 1 : 0;
+  rtx pat;
+  tree arg0 = CALL_EXPR_ARG (exp, 0);
+  tree arg1 = CALL_EXPR_ARG (exp, 1);
+  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+  enum machine_mode op0mode = GET_MODE (op0);
+  enum machine_mode op1mode = GET_MODE (op1);
+  enum machine_mode tmode = insn_data[icode].operand[0].mode;
+  enum machine_mode mode0 = insn_data[icode].operand[1 + offs].mode;
+  enum machine_mode mode1 = insn_data[icode].operand[2 + offs].mode;
+  rtx ret = target;
+
+  if (VECTOR_MODE_P (mode0))
+    op0 = safe_vector_operand (op0, mode0);
+  if (VECTOR_MODE_P (mode1))
+    op1 = safe_vector_operand (op1, mode1);
+
+  if (! target
+      || GET_MODE (target) != tmode
+      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+    {
+      if (tmode == SQmode || tmode == V2SQmode)
+       {
+         ret = gen_reg_rtx (tmode == SQmode ? SImode : V2SImode);
+         target = gen_lowpart (tmode, ret);
+       }
+      else
+       target = gen_reg_rtx (tmode);
+    }
+
+  if ((op0mode == V2HImode || op0mode == SImode || op0mode == VOIDmode)
+      && (mode0 == V2HQmode || mode0 == HQmode || mode0 == SQmode))
+    {
+      op0mode = mode0;
+      op0 = gen_lowpart (mode0, op0);
+    }
+  if ((op1mode == V2HImode || op1mode == SImode || op1mode == VOIDmode)
+      && (mode1 == V2HQmode || mode1 == HQmode || mode1 == SQmode))
+    {
+      op1mode = mode1;
+      op1 = gen_lowpart (mode1, op1);
+    }
+  /* In case the insn wants input operands in modes different from
+     the result, abort.  */
+  gcc_assert ((op0mode == mode0 || op0mode == VOIDmode)
+             && (op1mode == mode1 || op1mode == VOIDmode));
+
+  if (! (*insn_data[icode].operand[1 + offs].predicate) (op0, mode0))
+    op0 = copy_to_mode_reg (mode0, op0);
+  if (! (*insn_data[icode].operand[2 + offs].predicate) (op1, mode1))
+    op1 = copy_to_mode_reg (mode1, op1);
+
+  if (match_op)
+    pat = GEN_FCN (icode) (target, target, op0, op1);
+  else
+    pat = GEN_FCN (icode) (target, op0, op1);
+
+  if (! pat)
+    return 0;
+
+  emit_insn (pat);
+
+  return ret;
+}
+
+/* Subroutine of c6x_expand_builtin to take care of unop insns.  */
+
+static rtx
+c6x_expand_unop_builtin (enum insn_code icode, tree exp,
+                         rtx target)
+{
+  rtx pat;
+  tree arg0 = CALL_EXPR_ARG (exp, 0);
+  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+  enum machine_mode op0mode = GET_MODE (op0);
+  enum machine_mode tmode = insn_data[icode].operand[0].mode;
+  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
+
+  if (! target
+      || GET_MODE (target) != tmode
+      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+    target = gen_reg_rtx (tmode);
+
+  if (VECTOR_MODE_P (mode0))
+    op0 = safe_vector_operand (op0, mode0);
+
+  if (op0mode == SImode && mode0 == HImode)
+    {
+      op0mode = HImode;
+      op0 = gen_lowpart (HImode, op0);
+    }
+  gcc_assert (op0mode == mode0 || op0mode == VOIDmode);
+
+  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
+    op0 = copy_to_mode_reg (mode0, op0);
+
+  pat = GEN_FCN (icode) (target, op0);
+  if (! pat)
+    return 0;
+  emit_insn (pat);
+  return target;
+}
+
+/* Expand an expression EXP that calls a built-in function,
+   with result going to TARGET if that's convenient
+   (and in mode MODE if that's convenient).
+   SUBTARGET may be used as the target for computing one of EXP's operands.
+   IGNORE is nonzero if the value is to be ignored.  */
+
+static rtx
+c6x_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
+                    rtx subtarget ATTRIBUTE_UNUSED,
+                    enum machine_mode mode ATTRIBUTE_UNUSED,
+                    int ignore ATTRIBUTE_UNUSED)
+{
+  size_t i;
+  const struct builtin_description *d;
+  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
+
+  for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
+    if (d->code == fcode)
+      return c6x_expand_binop_builtin (d->icode, exp, target,
+                                      fcode == C6X_BUILTIN_CLRR);
+
+  for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
+    if (d->code == fcode)
+      return c6x_expand_unop_builtin (d->icode, exp, target);
+
+  gcc_unreachable ();
+}
+\f
+/* Target Structure.  */
+
+/* Initialize the GCC target structure.  */
+#undef TARGET_FUNCTION_ARG
+#define TARGET_FUNCTION_ARG c6x_function_arg
+#undef TARGET_FUNCTION_ARG_ADVANCE
+#define TARGET_FUNCTION_ARG_ADVANCE c6x_function_arg_advance
+#undef TARGET_FUNCTION_ARG_BOUNDARY
+#define TARGET_FUNCTION_ARG_BOUNDARY c6x_function_arg_boundary
+#undef TARGET_FUNCTION_ARG_ROUND_BOUNDARY
+#define TARGET_FUNCTION_ARG_ROUND_BOUNDARY \
+  c6x_function_arg_round_boundary
+#undef TARGET_FUNCTION_VALUE_REGNO_P
+#define TARGET_FUNCTION_VALUE_REGNO_P c6x_function_value_regno_p
+#undef TARGET_FUNCTION_VALUE
+#define TARGET_FUNCTION_VALUE c6x_function_value
+#undef TARGET_LIBCALL_VALUE
+#define TARGET_LIBCALL_VALUE c6x_libcall_value
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY c6x_return_in_memory
+#undef TARGET_RETURN_IN_MSB
+#define TARGET_RETURN_IN_MSB c6x_return_in_msb
+#undef TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE c6x_pass_by_reference
+#undef TARGET_CALLEE_COPIES
+#define TARGET_CALLEE_COPIES c6x_callee_copies
+#undef TARGET_STRUCT_VALUE_RTX
+#define TARGET_STRUCT_VALUE_RTX c6x_struct_value_rtx
+#undef TARGET_FUNCTION_OK_FOR_SIBCALL
+#define TARGET_FUNCTION_OK_FOR_SIBCALL c6x_function_ok_for_sibcall
+
+#undef TARGET_ASM_OUTPUT_MI_THUNK
+#define TARGET_ASM_OUTPUT_MI_THUNK c6x_output_mi_thunk
+#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
+#define TARGET_ASM_CAN_OUTPUT_MI_THUNK c6x_can_output_mi_thunk
+
+#undef TARGET_BUILD_BUILTIN_VA_LIST
+#define TARGET_BUILD_BUILTIN_VA_LIST c6x_build_builtin_va_list
+
+#undef TARGET_ASM_TRAMPOLINE_TEMPLATE
+#define TARGET_ASM_TRAMPOLINE_TEMPLATE c6x_asm_trampoline_template
+#undef TARGET_TRAMPOLINE_INIT
+#define TARGET_TRAMPOLINE_INIT c6x_initialize_trampoline
+
+#undef TARGET_LEGITIMATE_CONSTANT_P
+#define TARGET_LEGITIMATE_CONSTANT_P c6x_legitimate_constant_p
+#undef TARGET_LEGITIMATE_ADDRESS_P
+#define TARGET_LEGITIMATE_ADDRESS_P c6x_legitimate_address_p
+
+#undef TARGET_IN_SMALL_DATA_P
+#define TARGET_IN_SMALL_DATA_P c6x_in_small_data_p
+#undef TARGET_ASM_SELECT_RTX_SECTION
+#define TARGET_ASM_SELECT_RTX_SECTION  c6x_select_rtx_section
+#undef TARGET_ASM_SELECT_SECTION
+#define TARGET_ASM_SELECT_SECTION  c6x_elf_select_section
+#undef TARGET_ASM_UNIQUE_SECTION
+#define TARGET_ASM_UNIQUE_SECTION  c6x_elf_unique_section
+#undef TARGET_SECTION_TYPE_FLAGS
+#define TARGET_SECTION_TYPE_FLAGS  c6x_section_type_flags
+#undef TARGET_HAVE_SRODATA_SECTION
+#define TARGET_HAVE_SRODATA_SECTION true
+#undef TARGET_ASM_MERGEABLE_RODATA_PREFIX
+#define TARGET_ASM_MERGEABLE_RODATA_PREFIX ".const"
+
+#undef TARGET_OPTION_OVERRIDE
+#define TARGET_OPTION_OVERRIDE c6x_option_override
+#undef TARGET_CONDITIONAL_REGISTER_USAGE
+#define TARGET_CONDITIONAL_REGISTER_USAGE c6x_conditional_register_usage
+
+#undef TARGET_INIT_LIBFUNCS
+#define TARGET_INIT_LIBFUNCS c6x_init_libfuncs
+#undef TARGET_LIBFUNC_GNU_PREFIX
+#define TARGET_LIBFUNC_GNU_PREFIX true
+
+#undef TARGET_SCALAR_MODE_SUPPORTED_P
+#define TARGET_SCALAR_MODE_SUPPORTED_P c6x_scalar_mode_supported_p
+#undef TARGET_VECTOR_MODE_SUPPORTED_P
+#define TARGET_VECTOR_MODE_SUPPORTED_P c6x_vector_mode_supported_p
+#undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE
+#define TARGET_VECTORIZE_PREFERRED_SIMD_MODE c6x_preferred_simd_mode
+
+#undef TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS c6x_rtx_costs
+
+#undef TARGET_SCHED_INIT
+#define TARGET_SCHED_INIT c6x_sched_init
+#undef TARGET_SCHED_SET_SCHED_FLAGS
+#define TARGET_SCHED_SET_SCHED_FLAGS c6x_set_sched_flags
+#undef TARGET_SCHED_ADJUST_COST
+#define TARGET_SCHED_ADJUST_COST c6x_adjust_cost
+#undef TARGET_SCHED_ISSUE_RATE
+#define TARGET_SCHED_ISSUE_RATE c6x_issue_rate
+#undef TARGET_SCHED_VARIABLE_ISSUE
+#define TARGET_SCHED_VARIABLE_ISSUE c6x_variable_issue
+#undef TARGET_SCHED_REORDER
+#define TARGET_SCHED_REORDER c6x_sched_reorder
+#undef TARGET_SCHED_REORDER2
+#define TARGET_SCHED_REORDER2 c6x_sched_reorder2
+#undef TARGET_SCHED_EXPOSED_PIPELINE
+#define TARGET_SCHED_EXPOSED_PIPELINE true
+
+#undef TARGET_SCHED_ALLOC_SCHED_CONTEXT
+#define TARGET_SCHED_ALLOC_SCHED_CONTEXT c6x_alloc_sched_context
+#undef TARGET_SCHED_INIT_SCHED_CONTEXT
+#define TARGET_SCHED_INIT_SCHED_CONTEXT c6x_init_sched_context
+#undef TARGET_SCHED_SET_SCHED_CONTEXT
+#define TARGET_SCHED_SET_SCHED_CONTEXT c6x_set_sched_context
+#undef TARGET_SCHED_FREE_SCHED_CONTEXT
+#define TARGET_SCHED_FREE_SCHED_CONTEXT c6x_free_sched_context
+
+#undef TARGET_CAN_ELIMINATE
+#define TARGET_CAN_ELIMINATE c6x_can_eliminate
+
+#undef TARGET_PREFERRED_RENAME_CLASS
+#define TARGET_PREFERRED_RENAME_CLASS c6x_preferred_rename_class
+
+#undef TARGET_MACHINE_DEPENDENT_REORG
+#define TARGET_MACHINE_DEPENDENT_REORG c6x_reorg
+
+#undef TARGET_ASM_FILE_START
+#define TARGET_ASM_FILE_START c6x_file_start
+
+#undef  TARGET_PRINT_OPERAND
+#define TARGET_PRINT_OPERAND c6x_print_operand
+#undef  TARGET_PRINT_OPERAND_ADDRESS
+#define TARGET_PRINT_OPERAND_ADDRESS c6x_print_operand_address
+#undef  TARGET_PRINT_OPERAND_PUNCT_VALID_P
+#define TARGET_PRINT_OPERAND_PUNCT_VALID_P c6x_print_operand_punct_valid_p
+
+/* C6x unwinding tables use a different format for the typeinfo tables.  */
+#undef TARGET_ASM_TTYPE
+#define TARGET_ASM_TTYPE c6x_output_ttype
+
+#undef TARGET_DWARF_REGISTER_SPAN
+#define TARGET_DWARF_REGISTER_SPAN c6x_dwarf_register_span
+
+#undef TARGET_INIT_BUILTINS
+#define TARGET_INIT_BUILTINS c6x_init_builtins
+#undef TARGET_EXPAND_BUILTIN
+#define TARGET_EXPAND_BUILTIN c6x_expand_builtin
+#undef  TARGET_BUILTIN_DECL
+#define TARGET_BUILTIN_DECL c6x_builtin_decl
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+
+#include "gt-c6x.h"
diff --git a/gcc/config/c6x/c6x.h b/gcc/config/c6x/c6x.h
new file mode 100644 (file)
index 0000000..5d34d59
--- /dev/null
@@ -0,0 +1,617 @@
+/* Target Definitions for TI C6X.
+   Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+   Contributed by Andrew Jenner <andrew@codesourcery.com>
+   Contributed by Bernd Schmidt <bernds@codesourcery.com>
+
+   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/>.  */
+
+#ifndef GCC_C6X_H
+#define GCC_C6X_H
+
+/* Feature bit definitions that enable specific insns.  */
+#define C6X_INSNS_C62X         1
+#define C6X_INSNS_C64X         2
+#define C6X_INSNS_C64XP                4
+#define C6X_INSNS_C67X         8
+#define C6X_INSNS_C67XP                16
+#define C6X_INSNS_C674X                32
+#define C6X_INSNS_ATOMIC       64
+#define C6X_INSNS_ALL_CPU_BITS 127
+
+#define C6X_DEFAULT_INSN_MASK                                          \
+  (C6X_INSNS_C62X | C6X_INSNS_C64X | C6X_INSNS_C64XP)
+
+/* A mask of allowed insn types, as defined above.  */
+extern unsigned long c6x_insn_mask;
+
+/* Value of -march= */
+extern c6x_cpu_t c6x_arch;
+#define C6X_DEFAULT_ARCH C6X_CPU_C64XP
+
+/* True if the target has C64x instructions.  */
+#define TARGET_INSNS_64                ((c6x_insn_mask & C6X_INSNS_C64X) != 0)
+/* True if the target has C64x+ instructions.  */
+#define TARGET_INSNS_64PLUS    ((c6x_insn_mask & C6X_INSNS_C64XP) != 0)
+/* True if the target has C67x instructions.  */
+#define TARGET_INSNS_67                ((c6x_insn_mask & C6X_INSNS_C67X) != 0)
+/* True if the target has C67x+ instructions.  */
+#define TARGET_INSNS_67PLUS    ((c6x_insn_mask & C6X_INSNS_C67XP) != 0)
+
+/* True if the target supports doubleword loads.  */
+#define TARGET_LDDW            (TARGET_INSNS_64 || TARGET_INSNS_67)
+/* True if the target supports doubleword loads.  */
+#define TARGET_STDW            TARGET_INSNS_64
+/* True if the target supports the MPY32 family of instructions.  */
+#define TARGET_MPY32           TARGET_INSNS_64PLUS
+/* True if the target has floating point hardware.  */
+#define TARGET_FP              TARGET_INSNS_67
+/* True if the target has C67x+ floating point extensions.  */
+#define TARGET_FP_EXT          TARGET_INSNS_67PLUS
+
+#define TARGET_DEFAULT 0
+
+/* Run-time Target.  */
+
+#define TARGET_CPU_CPP_BUILTINS()              \
+  do                                           \
+    {                                          \
+      builtin_assert ("machine=tic6x");                \
+      builtin_assert ("cpu=tic6x");            \
+      builtin_define ("__TMS320C6X__");                \
+      builtin_define ("_TMS320C6X");           \
+                                               \
+      if (TARGET_DSBT)                         \
+       builtin_define ("__DSBT__");            \
+                                               \
+      if (TARGET_BIG_ENDIAN)                   \
+       builtin_define ("_BIG_ENDIAN");         \
+      else                                     \
+       builtin_define ("_LITTLE_ENDIAN");      \
+                                               \
+      switch (c6x_arch)                                \
+       {                                       \
+       case C6X_CPU_C62X:                      \
+         builtin_define ("_TMS320C6200");      \
+         break;                                \
+                                               \
+       case C6X_CPU_C64XP:                     \
+         builtin_define ("_TMS320C6400_PLUS"); \
+         /* ... fall through ... */            \
+       case C6X_CPU_C64X:                      \
+         builtin_define ("_TMS320C6400");      \
+         break;                                \
+                                               \
+       case C6X_CPU_C67XP:                     \
+         builtin_define ("_TMS320C6700_PLUS"); \
+         /* ... fall through ... */            \
+       case C6X_CPU_C67X:                      \
+         builtin_define ("_TMS320C6700");      \
+         break;                                \
+                                               \
+       case C6X_CPU_C674X:                     \
+         builtin_define ("_TMS320C6740");      \
+         builtin_define ("_TMS320C6700_PLUS"); \
+         builtin_define ("_TMS320C6700");      \
+         builtin_define ("_TMS320C6400_PLUS"); \
+         builtin_define ("_TMS320C6400");      \
+         break;                                \
+       }                                       \
+    } while (0)
+
+#define OPTION_DEFAULT_SPECS \
+  {"arch", "%{!march=*:-march=%(VALUE)}" }
+
+/* Storage Layout.  */
+
+#define BITS_BIG_ENDIAN 0
+#define BYTES_BIG_ENDIAN (TARGET_BIG_ENDIAN != 0)
+#define WORDS_BIG_ENDIAN (TARGET_BIG_ENDIAN != 0)
+
+#define REG_WORDS_BIG_ENDIAN 0
+
+#define UNITS_PER_WORD 4
+#define PARM_BOUNDARY 8
+#define STACK_BOUNDARY 64
+#define FUNCTION_BOUNDARY 32
+#define BIGGEST_ALIGNMENT 64
+#define STRICT_ALIGNMENT 1
+
+/* The ABI requires static arrays must be at least 8 byte aligned.
+   Really only externally visible arrays must be aligned this way, as
+   only those are directly visible from another compilation unit.  But
+   we don't have that information available here.  */
+#define DATA_ALIGNMENT(TYPE, ALIGN)                                    \
+  (((ALIGN) < BITS_PER_UNIT * 8 && TREE_CODE (TYPE) == ARRAY_TYPE)     \
+   ? BITS_PER_UNIT * 8 : (ALIGN))
+
+/* Type Layout.  */
+
+#define DEFAULT_SIGNED_CHAR 1
+
+#undef SIZE_TYPE
+#define SIZE_TYPE "unsigned int"
+#undef PTRDIFF_TYPE
+#define PTRDIFF_TYPE "int"
+
+/* Registers.  */
+
+#define FIRST_PSEUDO_REGISTER 67
+#define FIXED_REGISTERS                                        \
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    \
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    \
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,    \
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    \
+    1, 1, 1}
+#define CALL_USED_REGISTERS                            \
+  { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,    \
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,    \
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1,    \
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,    \
+    1, 1, 1}
+
+/* This lists call-used non-predicate registers first, followed by call-used
+   registers, followed by predicate registers.  We want to avoid allocating
+   the predicate registers for other uses as much as possible.  */
+#define REG_ALLOC_ORDER                                                        \
+  {                                                                    \
+    REG_A0, REG_A3, REG_A4, REG_A5, REG_A6, REG_A7, REG_A8, REG_A9,    \
+    REG_A16, REG_A17, REG_A18, REG_A19, REG_A20, REG_A21, REG_A22, REG_A23, \
+    REG_A24, REG_A25, REG_A26, REG_A27, REG_A28, REG_A29, REG_A30, REG_A31, \
+    REG_B4, REG_B5, REG_B6, REG_B7, REG_B8, REG_B9, REG_B16,   \
+    REG_B17, REG_B18, REG_B19, REG_B20, REG_B21, REG_B22, REG_B23, REG_B24, \
+    REG_B25, REG_B26, REG_B27, REG_B28, REG_B29, REG_B30, REG_B31,     \
+    REG_A10, REG_A11, REG_A12, REG_A13, REG_A14, REG_A15,              \
+    REG_B3, REG_B10, REG_B11, REG_B12, REG_B13, REG_B14, REG_B15,      \
+    REG_A1, REG_A2, REG_B0, REG_B1, REG_B2, REG_ILC                    \
+  }
+
+#define HARD_REGNO_NREGS(regno, mode)          \
+  ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)  \
+   / UNITS_PER_WORD)
+
+#define HARD_REGNO_MODE_OK(reg, mode) (GET_MODE_SIZE (mode) <= UNITS_PER_WORD \
+                                      ? 1 : ((reg) & 1) == 0)
+
+#define MODES_TIEABLE_P(mode1, mode2)         \
+  ((mode1) == (mode2) ||                      \
+   (GET_MODE_SIZE (mode1) <= UNITS_PER_WORD && \
+    GET_MODE_SIZE (mode2) <= UNITS_PER_WORD))
+
+
+/* Register Classes.  */
+
+enum reg_class
+  {
+    NO_REGS,
+    PREDICATE_A_REGS,
+    PREDICATE_B_REGS,
+    PREDICATE_REGS,
+    PICREG,
+    SPREG,
+    CALL_USED_B_REGS,
+    NONPREDICATE_A_REGS,
+    NONPREDICATE_B_REGS,
+    NONPREDICATE_REGS,
+    A_REGS,
+    B_REGS,
+    GENERAL_REGS,
+    ALL_REGS,
+    LIM_REG_CLASSES
+  };
+
+#define N_REG_CLASSES (int) LIM_REG_CLASSES
+
+#define REG_CLASS_NAMES {        \
+    "NO_REGS",                   \
+    "PREDICATE_A_REGS",                  \
+    "PREDICATE_B_REGS",                  \
+    "PREDICATE_REGS",            \
+    "PICREG",                    \
+    "SPREG",                     \
+    "CALL_USED_B_REGS",                  \
+    "NONPREDICATE_A_REGS",       \
+    "NONPREDICATE_B_REGS",       \
+    "NONPREDICATE_REGS",         \
+    "A_REGS",                    \
+    "B_REGS",                    \
+    "GENERAL_REGS",              \
+    "ALL_REGS" }
+
+#define REG_CLASS_CONTENTS                     \
+{                                              \
+  /* NO_REGS.  */                              \
+  { 0x00000000, 0x00000000, 0 },               \
+  /* PREDICATE_A_REGS.  */                     \
+  { 0x00000006, 0x00000000, 0 },               \
+  /* PREDICATE_B_REGS.  */                     \
+  { 0x00000000, 0x00000007, 0 },               \
+  /* PREDICATE_REGS.  */                       \
+  { 0x00000006, 0x00000007, 0 },               \
+  /* PICREG.  */                               \
+  { 0x00000000, 0x00004000, 0 },               \
+  /* SPREG.  */                                        \
+  { 0x00000000, 0x00008000, 0 },               \
+  /* CALL_USED_B_REGS.  */                     \
+  { 0x00000000, 0xFFFF03FF, 0 },               \
+  /* NONPREDICATE_A_REGS.  */                  \
+  { 0xFFFFFFF9, 0x00000000, 0 },               \
+  /* NONPREDICATE_B_REGS.  */                  \
+  { 0x00000000, 0xFFFFFFF8, 0 },               \
+  /* NONPREDICATE_REGS.  */                    \
+  { 0xFFFFFFF9, 0xFFFFFFF8, 0 },               \
+  /* A_REGS.  */                               \
+  { 0xFFFFFFFF, 0x00000000, 3 },               \
+  /* B_REGS.  */                               \
+  { 0x00000000, 0xFFFFFFFF, 3 },               \
+  /* GENERAL_REGS.  */                         \
+  { 0xFFFFFFFF, 0xFFFFFFFF, 3 },               \
+  /* ALL_REGS.  */                             \
+  { 0xFFFFFFFF, 0xFFFFFFFF, 7 },               \
+}
+
+#define A_REGNO_P(N) ((N) <= REG_A31)
+#define B_REGNO_P(N) ((N) >= REG_B0 && (N) <= REG_B31)
+
+#define A_REG_P(X) (REG_P (X) && A_REGNO_P (REGNO (X)))
+#define CROSS_OPERANDS(X0,X1) \
+  (A_REG_P (X0) == A_REG_P (X1) ? CROSS_N : CROSS_Y)
+
+#define REGNO_REG_CLASS(reg) \
+    ((reg) >= REG_A1 && (reg) <= REG_A2 ? PREDICATE_A_REGS     \
+     : (reg) == REG_A0 && TARGET_INSNS_64 ? PREDICATE_A_REGS   \
+     : (reg) >= REG_B0 && (reg) <= REG_B2 ? PREDICATE_B_REGS   \
+     : A_REGNO_P (reg) ? NONPREDICATE_A_REGS                   \
+     : call_used_regs[reg] ? CALL_USED_B_REGS : B_REGS)
+
+#define BASE_REG_CLASS ALL_REGS
+#define INDEX_REG_CLASS ALL_REGS
+
+#define REGNO_OK_FOR_BASE_STRICT_P(X)                          \
+  ((X) < FIRST_PSEUDO_REGISTER                                 \
+   || (reg_renumber[X] >= 0 && reg_renumber[X] < FIRST_PSEUDO_REGISTER))
+#define REGNO_OK_FOR_BASE_NONSTRICT_P(X) 1
+
+#define REGNO_OK_FOR_INDEX_STRICT_P(X)                         \
+  ((X) < FIRST_PSEUDO_REGISTER                                 \
+   || (reg_renumber[X] >= 0 && reg_renumber[X] < FIRST_PSEUDO_REGISTER))
+#define REGNO_OK_FOR_INDEX_NONSTRICT_P(X) 1
+
+#ifdef REG_OK_STRICT
+#define REGNO_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_STRICT_P (X)
+#define REGNO_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_STRICT_P (X)
+#else
+#define REGNO_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_NONSTRICT_P (X)
+#define REGNO_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_NONSTRICT_P (X)
+#endif
+
+#define CLASS_MAX_NREGS(class, mode) \
+  ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+
+#define REGNO_OK_FOR_INDIRECT_JUMP_P(REGNO, MODE) B_REGNO_P (REGNO)
+
+/* Stack and Calling.  */
+
+/* SP points to 4 bytes below the first word of the frame.  */
+#define STACK_POINTER_OFFSET 4
+/* Likewise for AP (which is the incoming stack pointer).  */
+#define FIRST_PARM_OFFSET(fundecl) 4
+#define STARTING_FRAME_OFFSET 0
+#define FRAME_GROWS_DOWNWARD 1
+#define STACK_GROWS_DOWNWARD
+
+#define STACK_POINTER_REGNUM REG_B15
+#define HARD_FRAME_POINTER_REGNUM REG_A15
+/* These two always get eliminated in favour of the stack pointer
+   or the hard frame pointer.  */
+#define FRAME_POINTER_REGNUM REG_FRAME
+#define ARG_POINTER_REGNUM REG_ARGP
+
+#define PIC_OFFSET_TABLE_REGNUM REG_B14
+
+/* We keep the stack pointer constant rather than using push/pop
+   instructions.  */
+#define ACCUMULATE_OUTGOING_ARGS 1
+
+/* Before the prologue, the return address is in the B3 register.  */
+#define RETURN_ADDR_REGNO REG_B3
+#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, RETURN_ADDR_REGNO)
+
+#define RETURN_ADDR_RTX(COUNT, FRAME) c6x_return_addr_rtx (COUNT)
+
+#define INCOMING_FRAME_SP_OFFSET 0
+#define ARG_POINTER_CFA_OFFSET(fundecl) 0
+
+#define STATIC_CHAIN_REGNUM REG_A2
+
+struct c6x_args {
+  /* Number of arguments to pass in registers.  */
+  int nregs;
+  /* Number of arguments passed in registers so far.  */
+  int count;
+};
+
+#define CUMULATIVE_ARGS struct c6x_args
+
+#define INIT_CUMULATIVE_ARGS(cum, fntype, libname, fndecl, n_named_args) \
+  c6x_init_cumulative_args (&cum, fntype, libname, n_named_args)
+
+#define BLOCK_REG_PADDING(MODE, TYPE, FIRST) \
+  (c6x_block_reg_pad_upward (MODE, TYPE, FIRST) ? upward : downward)
+
+#define FUNCTION_ARG_REGNO_P(r) \
+    (((r) >= REG_A4 && (r) <= REG_A13) || ((r) >= REG_B4 && (r) <= REG_B13))
+
+#define DEFAULT_PCC_STRUCT_RETURN 0
+
+#define FUNCTION_PROFILER(file, labelno) \
+  fatal_error ("profiling is not yet implemented for this architecture")
+
+
+/* Trampolines.  */
+#define TRAMPOLINE_SIZE 32
+#define TRAMPOLINE_ALIGNMENT 256
+\f
+#define ELIMINABLE_REGS                                        \
+{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM},          \
+ { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM},     \
+ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM},                \
+ { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}   \
+
+/* Define the offset between two registers, one to be eliminated, and the other
+   its replacement, at the start of a routine.  */
+
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
+  ((OFFSET) = c6x_initial_elimination_offset ((FROM), (TO)))
+\f
+/* Addressing Modes.  */
+
+#define CONSTANT_ADDRESS_P(x) (CONSTANT_P(x) && GET_CODE(x) != CONST_DOUBLE)
+#define MAX_REGS_PER_ADDRESS 2
+
+#define HAVE_PRE_DECREMENT 1
+#define HAVE_POST_DECREMENT 1
+#define HAVE_PRE_INCREMENT 1
+#define HAVE_POST_INCREMENT 1
+
+/* Register forms are available, but due to scaling we currently don't
+   support them.  */
+#define HAVE_PRE_MODIFY_DISP 1
+#define HAVE_POST_MODIFY_DISP 1
+
+#define LEGITIMATE_PIC_OPERAND_P(X) \
+  (!symbolic_operand (X, SImode))
+\f
+struct GTY(()) machine_function
+{
+  /* True if we expanded a sibling call.  */
+  int contains_sibcall;
+};
+\f
+/* Costs.  */
+#define NO_FUNCTION_CSE 1
+
+#define SLOW_BYTE_ACCESS 0
+
+#define BRANCH_COST(speed_p, predictable_p) 6
+
+\f
+/* Model costs for the vectorizer.  */
+
+/* Cost of conditional branch.  */
+#ifndef TARG_COND_BRANCH_COST
+#define TARG_COND_BRANCH_COST        6
+#endif
+
+/* Cost of any scalar operation, excluding load and store.  */
+#ifndef TARG_SCALAR_STMT_COST
+#define TARG_SCALAR_STMT_COST        1
+#endif
+
+/* Cost of scalar load. */
+#undef TARG_SCALAR_LOAD_COST
+#define TARG_SCALAR_LOAD_COST        2 /* load + rotate */
+
+/* Cost of scalar store.  */
+#undef TARG_SCALAR_STORE_COST
+#define TARG_SCALAR_STORE_COST       10
+
+/* Cost of any vector operation, excluding load, store,
+   or vector to scalar operation.  */
+#undef TARG_VEC_STMT_COST
+#define TARG_VEC_STMT_COST           1
+
+/* Cost of vector to scalar operation.  */
+#undef TARG_VEC_TO_SCALAR_COST
+#define TARG_VEC_TO_SCALAR_COST      1
+
+/* Cost of scalar to vector operation.  */
+#undef TARG_SCALAR_TO_VEC_COST
+#define TARG_SCALAR_TO_VEC_COST      1
+
+/* Cost of aligned vector load.  */
+#undef TARG_VEC_LOAD_COST
+#define TARG_VEC_LOAD_COST           1
+
+/* Cost of misaligned vector load.  */
+#undef TARG_VEC_UNALIGNED_LOAD_COST
+#define TARG_VEC_UNALIGNED_LOAD_COST 2
+
+/* Cost of vector store.  */
+#undef TARG_VEC_STORE_COST
+#define TARG_VEC_STORE_COST          1
+
+/* Cost of vector permutation.  */
+#ifndef TARG_VEC_PERMUTE_COST
+#define TARG_VEC_PERMUTE_COST        1
+#endif
+
+/* Exception handling.  */
+#define TARGET_EXTRA_CFI_SECTION(unwind) ((unwind) ? ".c6xabi.exidx" : NULL)
+/* ttype entries (the only interesting data references used) are
+   sb-relative got-indirect (aka .ehtype).  */
+#define ASM_PREFERRED_EH_DATA_FORMAT(code, data) \
+  (((code) == 0 && (data) == 1) ? (DW_EH_PE_datarel | DW_EH_PE_indirect) \
+                               : DW_EH_PE_absptr)
+
+/* This should be the same as the definition in elfos.h, plus the call
+   to output special unwinding directives.  */
+#undef ASM_DECLARE_FUNCTION_NAME
+#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL)            \
+  do                                                           \
+    {                                                          \
+      c6x_output_file_unwind (FILE);                           \
+      ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "function");      \
+      ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL));           \
+      ASM_OUTPUT_LABEL (FILE, NAME);                           \
+    }                                                          \
+  while (0)
+
+/* This should be the same as the definition in elfos.h, plus the call
+   to output special unwinding directives.  */
+#undef ASM_DECLARE_FUNCTION_SIZE
+#define ASM_DECLARE_FUNCTION_SIZE(STREAM, NAME, DECL) \
+  c6x_function_end (STREAM, NAME)
+
+/* Arbitrarily choose A4/A5.  */
+#define EH_RETURN_DATA_REGNO(N) (((N) < 2) ? (N) + 4 : INVALID_REGNUM)
+
+/* The register that holds the return address in exception handlers.  */
+#define C6X_EH_STACKADJ_REGNUM  3
+#define EH_RETURN_STACKADJ_RTX  gen_rtx_REG (SImode, C6X_EH_STACKADJ_REGNUM)
+
+
+/* Assembler Format.  */
+
+#define DWARF2_ASM_LINE_DEBUG_INFO 1
+
+#undef ASM_APP_ON
+#define ASM_APP_ON "\t; #APP \n"
+#undef ASM_APP_OFF
+#define ASM_APP_OFF "\t; #NO_APP \n"
+
+#define ASM_OUTPUT_COMMON(stream, name, size, rounded)
+#define ASM_OUTPUT_LOCAL(stream, name, size, rounded)
+
+#define GLOBAL_ASM_OP "\t.global\t"
+
+#define REGISTER_NAMES                                         \
+  {                                                            \
+    "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",            \
+    "A8", "A9", "A10", "A11", "A12", "A13", "A14", "A15",      \
+    "A16", "A17", "A18", "A19", "A20", "A21", "A22", "A23",    \
+    "A24", "A25", "A26", "A27", "A28", "A29", "A30", "A31",     \
+    "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7",             \
+    "B8", "B9", "B10", "B11", "B12", "B13", "B14", "B15",       \
+    "B16", "B17", "B18", "B19", "B20", "B21", "B22", "B23",     \
+    "B24", "B25", "B26", "B27", "B28", "B29", "B30", "B31",    \
+    "FP", "ARGP", "ILC" }
+
+#define DBX_REGISTER_NUMBER(N) (dbx_register_map[(N)])
+
+extern int const dbx_register_map[FIRST_PSEUDO_REGISTER];
+
+#define FINAL_PRESCAN_INSN c6x_final_prescan_insn
+
+#define TEXT_SECTION_ASM_OP ".text;"
+#define DATA_SECTION_ASM_OP ".data;"
+
+#define ASM_OUTPUT_ALIGN(stream, power)                            \
+  do                                                       \
+    {                                                      \
+      if (power)                                           \
+        fprintf ((stream), "\t.align\t%d\n", power);       \
+    }                                                       \
+  while (0)
+
+#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE)           \
+do { char __buf[256];                                  \
+     fprintf (FILE, "\t.long\t");                              \
+     ASM_GENERATE_INTERNAL_LABEL (__buf, "L", VALUE);  \
+     assemble_name (FILE, __buf);                      \
+     fputc ('\n', FILE);                               \
+   } while (0)
+
+/* Determine whether to place EXP (an expression or a decl) should be
+   placed into one of the small data sections.  */
+#define PLACE_IN_SDATA_P(EXP) \
+  (c6x_sdata_mode == C6X_SDATA_NONE ? false    \
+   : c6x_sdata_mode == C6X_SDATA_ALL ? true    \
+   : !AGGREGATE_TYPE_P (TREE_TYPE (EXP)))
+
+#define SCOMMON_ASM_OP "\t.scomm\t"
+
+#undef  ASM_OUTPUT_ALIGNED_DECL_COMMON
+#define ASM_OUTPUT_ALIGNED_DECL_COMMON(FILE, DECL, NAME, SIZE, ALIGN)  \
+  do                                                                   \
+    {                                                                  \
+      if (DECL != NULL && PLACE_IN_SDATA_P (DECL))                     \
+       fprintf ((FILE), "%s", SCOMMON_ASM_OP);                         \
+      else                                                             \
+       fprintf ((FILE), "%s", COMMON_ASM_OP);                          \
+      assemble_name ((FILE), (NAME));                                  \
+      fprintf ((FILE), ",%u,%u\n", (int)(SIZE), (ALIGN) / BITS_PER_UNIT);\
+    }                                                                  \
+  while (0)
+
+/* This says how to output assembler code to declare an
+   uninitialized internal linkage data object.  */
+
+#undef  ASM_OUTPUT_ALIGNED_DECL_LOCAL
+#define ASM_OUTPUT_ALIGNED_DECL_LOCAL(FILE, DECL, NAME, SIZE, ALIGN)   \
+do {                                                                   \
+  if (PLACE_IN_SDATA_P (DECL))                                         \
+    switch_to_section (sbss_section);                                  \
+  else                                                                 \
+    switch_to_section (bss_section);                                   \
+  ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object");                    \
+  if (!flag_inhibit_size_directive)                                    \
+    ASM_OUTPUT_SIZE_DIRECTIVE (FILE, NAME, SIZE);                      \
+  ASM_OUTPUT_ALIGN ((FILE), exact_log2((ALIGN) / BITS_PER_UNIT));      \
+  ASM_OUTPUT_LABEL(FILE, NAME);                                                \
+  ASM_OUTPUT_SKIP((FILE), (SIZE) ? (SIZE) : 1);                                \
+} while (0)
+
+#define CASE_VECTOR_PC_RELATIVE flag_pic
+#define JUMP_TABLES_IN_TEXT_SECTION flag_pic
+
+#define ADDR_VEC_ALIGN(VEC) (JUMP_TABLES_IN_TEXT_SECTION ? 5 : 2)
+
+/* This is how to output an element of a case-vector that is relative.  */
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
+  do { char buf[100];                                  \
+       fputs ("\t.long ", FILE);                       \
+       ASM_GENERATE_INTERNAL_LABEL (buf, "L", VALUE);  \
+       assemble_name (FILE, buf);                      \
+       putc ('-', FILE);                               \
+       ASM_GENERATE_INTERNAL_LABEL (buf, "L", REL);    \
+       assemble_name (FILE, buf);                      \
+       putc ('\n', FILE);                              \
+     } while (0)
+
+/* Misc.  */
+
+#define CASE_VECTOR_MODE SImode
+#define MOVE_MAX 4
+#define MOVE_RATIO(SPEED) 4
+#define TRULY_NOOP_TRUNCATION(outprec, inprec) 1
+#define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) ((VALUE) = 32, 1)
+#define Pmode SImode
+#define FUNCTION_MODE QImode
+
+extern int c6x_initial_flag_pic;
+
+#endif /* GCC_C6X_H */
diff --git a/gcc/config/c6x/c6x.md b/gcc/config/c6x/c6x.md
new file mode 100644 (file)
index 0000000..7935a81
--- /dev/null
@@ -0,0 +1,3004 @@
+;; Machine description for TI C6X.
+;; Copyright (C) 2010, 2011 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"))
+
+(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)))
+
+(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_w1,c6x_2,c6x_w2,c6x_m1,c6x_m2,c6x_t1,c6x_t2,c6x_branch")
+(automata_option "ndfa")
+
+(define_cpu_unit "d1,l1,s1" "c6x_1")
+(define_cpu_unit "x1" "c6x_1")
+(define_cpu_unit "l1w,s1w" "c6x_w1")
+(define_cpu_unit "m1" "c6x_m1")
+(define_cpu_unit "m1w" "c6x_m1")
+(define_cpu_unit "t1" "c6x_t1")
+(define_cpu_unit "d2,l2,s2" "c6x_2")
+(define_cpu_unit "x2" "c6x_2")
+(define_cpu_unit "l2w,s2w" "c6x_w2")
+(define_cpu_unit "m2" "c6x_m2")
+(define_cpu_unit "m2w" "c6x_m2")
+(define_cpu_unit "t2" "c6x_t2")
+
+;; 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 "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;
+  enum 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;
+  enum 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;
+  REAL_VALUE_TYPE value;
+
+  gcc_assert (GET_CODE (operands[1]) == CONST_DOUBLE);
+
+  REAL_VALUE_FROM_CONST_DOUBLE (value, operands[1]);
+  REAL_VALUE_TO_TARGET_SINGLE (value, 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 "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 "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 "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 (memory_operand (operands[0], <MODE>mode))
+    {
+      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 (VOIDmode, 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;
+  }"
+)
+
+;; -------------------------------------------------------------------------
+;; Delayed-branch real jumps and shadows
+;; -------------------------------------------------------------------------
+
+(define_insn "real_jump"
+  [(unspec [(match_operand 0 "c6x_jump_operand" "a,b,s") (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")])
+
+(define_insn "indirect_jump_shadow"
+  [(set (pc) (unspec [(pc)] 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:SI (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")
diff --git a/gcc/config/c6x/c6x.opt b/gcc/config/c6x/c6x.opt
new file mode 100644 (file)
index 0000000..14ad81b
--- /dev/null
@@ -0,0 +1,67 @@
+; Option definitions for TI C6X.
+; Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+; 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/>.
+
+HeaderInclude
+config/c6x/c6x-opts.h
+
+SourceInclude
+config/c6x/c6x-opts.h
+
+mbig-endian
+Target Report RejectNegative Mask(BIG_ENDIAN)
+Use big-endian byte order
+
+mlittle-endian
+Target Report RejectNegative InverseMask(BIG_ENDIAN, LITTLE_ENDIAN)
+Use little-endian byte order
+
+msim
+Target RejectNegative
+Use simulator runtime
+
+msdata=
+Target RejectNegative Enum(c6x_sdata) Joined Var(c6x_sdata_mode) Init(C6X_SDATA_DEFAULT)
+Select method for sdata handling
+
+Enum
+Name(c6x_sdata) Type(enum c6x_sdata)
+Valid arguments for the -msdata= option
+
+EnumValue
+Enum(c6x_sdata) String(none) Value(C6X_SDATA_NONE)
+
+EnumValue
+Enum(c6x_sdata) String(default) Value(C6X_SDATA_DEFAULT)
+
+EnumValue
+Enum(c6x_sdata) String(all) Value(C6X_SDATA_ALL)
+
+mdsbt
+Target Mask(DSBT)
+Compile for the DSBT shared library ABI
+
+mlong-calls
+Target Report Mask(LONG_CALLS)
+Avoid generating pc-relative calls; use indirection
+
+march=
+Target RejectNegative Joined Enum(c6x_isa) Var(c6x_arch_option)
+Specify the name of the target architecture
diff --git a/gcc/config/c6x/c6x_intrinsics.h b/gcc/config/c6x/c6x_intrinsics.h
new file mode 100644 (file)
index 0000000..2ae7dd5
--- /dev/null
@@ -0,0 +1,194 @@
+/* Intrinsics for TI C6X.
+
+   Copyright (C) 2011 Free Software Foundation, Inc.
+   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.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _GCC_C6X_INTRINSICS_H
+#define _GCC_C6X_INTRINSICS_H
+
+#if !defined(__TMS320C6X__)
+# error "c6x_intrinsics.h is only supported for C6X targets"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+/* Define vector types.  */
+typedef uint8_t __uv4qi __attribute__((vector_size (4)));
+typedef int16_t __v2hi __attribute__((vector_size (4)));
+typedef int32_t __v2si __attribute__((vector_size (8)));
+
+__extension__ static __inline int __attribute__ ((__always_inline__))
+_abs (int src)
+{
+  return __builtin_c6x_abs (src);
+}
+
+__extension__ static __inline int __attribute__ ((__always_inline__))
+_abs2 (int src)
+{
+  return (int)__builtin_c6x_abs2 ((__v2hi)src);
+}
+
+__extension__ static __inline int __attribute__ ((__always_inline__))
+_sadd (int src1, int src2)
+{
+  return __builtin_c6x_sadd (src1, src2);
+}
+
+__extension__ static __inline int __attribute__ ((__always_inline__))
+_ssub (int src1, int src2)
+{
+  return __builtin_c6x_ssub (src1, src2);
+}
+
+__extension__ static __inline int __attribute__ ((__always_inline__))
+_add2 (int src1, int src2)
+{
+  return (int)__builtin_c6x_add2 ((__v2hi)src1, (__v2hi)src2);
+}
+
+__extension__ static __inline int __attribute__ ((__always_inline__))
+_sub2 (int src1, int src2)
+{
+  return (int)__builtin_c6x_sub2 ((__v2hi)src1, (__v2hi)src2);
+}
+
+__extension__ static __inline int __attribute__ ((__always_inline__))
+_add4 (int src1, int src2)
+{
+  return (int)__builtin_c6x_add4 ((__uv4qi)src1, (__uv4qi)src2);
+}
+
+__extension__ static __inline int __attribute__ ((__always_inline__))
+_sub4 (int src1, int src2)
+{
+  return (int)__builtin_c6x_sub4 ((__uv4qi)src1, (__uv4qi)src2);
+}
+
+__extension__ static __inline int __attribute__ ((__always_inline__))
+_sadd2 (int src1, int src2)
+{
+  return (int)__builtin_c6x_sadd2 ((__v2hi)src1, (__v2hi)src2);
+}
+
+__extension__ static __inline int __attribute__ ((__always_inline__))
+_ssub2 (int src1, int src2)
+{
+  return (int)__builtin_c6x_ssub2 ((__v2hi)src1, (__v2hi)src2);
+}
+
+__extension__ static __inline int __attribute__ ((__always_inline__))
+_saddu4 (int src1, int src2)
+{
+  return (int)__builtin_c6x_saddu4 ((__uv4qi)src1, (__uv4qi)src2);
+}
+
+__extension__ static __inline int __attribute__ ((__always_inline__))
+_smpy (int src1, int src2)
+{
+  return __builtin_c6x_smpy (src1, src2);
+}
+
+__extension__ static __inline int __attribute__ ((__always_inline__))
+_smpylh (int src1, int src2)
+{
+  return __builtin_c6x_smpylh (src1, src2);
+}
+
+__extension__ static __inline int __attribute__ ((__always_inline__))
+_smpyhl (int src1, int src2)
+{
+  return __builtin_c6x_smpyhl (src1, src2);
+}
+
+__extension__ static __inline int __attribute__ ((__always_inline__))
+_smpyh (int src1, int src2)
+{
+  return __builtin_c6x_smpyh (src1, src2);
+}
+
+__extension__ static __inline long long __attribute__ ((__always_inline__))
+_smpy2ll (int src1, int src2)
+{
+  return (long long)__builtin_c6x_smpy2 ((__v2hi)src1, (__v2hi)src2);
+}
+
+__extension__ static __inline long long __attribute__ ((__always_inline__))
+_mpy2ll (int src1, int src2)
+{
+  return (long long)__builtin_c6x_mpy2 ((__v2hi)src1, (__v2hi)src2);
+}
+
+__extension__ static __inline int __attribute__ ((__always_inline__))
+_extr (int src1, int src2)
+{
+  return __builtin_c6x_extr (src1, src2);
+}
+
+__extension__ static __inline int __attribute__ ((__always_inline__))
+_extru (int src1, int src2)
+{
+  return __builtin_c6x_extru (src1, src2);
+}
+
+__extension__ static __inline int __attribute__ ((__always_inline__))
+_clrr (int src1, int src2)
+{
+  return __builtin_c6x_clrr (src1, src2);
+}
+
+__extension__ static __inline int __attribute__ ((__always_inline__))
+_avg2 (int src1, int src2)
+{
+  return (int)__builtin_c6x_avg2 ((__v2hi)src1, (__v2hi)src2);
+}
+
+__extension__ static __inline int __attribute__ ((__always_inline__))
+_avgu4 (int src1, int src2)
+{
+  return (int)__builtin_c6x_avgu4 ((__uv4qi)src1, (__uv4qi)src2);
+}
+
+__extension__ static __inline int __attribute__ ((__always_inline__))
+_sshl (int src1, int src2)
+{
+  return __builtin_c6x_sshl (src1, src2);
+}
+
+__extension__ static __inline int __attribute__ ((__always_inline__))
+_subc (int src1, int src2)
+{
+  return __builtin_c6x_subc (src1, src2);
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/gcc/config/c6x/constraints.md b/gcc/config/c6x/constraints.md
new file mode 100644 (file)
index 0000000..1a6710b
--- /dev/null
@@ -0,0 +1,174 @@
+;; Constraint definitions for TI C6X.
+;; Copyright (C) 2010, 2011 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/>.
+
+(define_register_constraint "a" "A_REGS"
+  "Register file A (A0--A31).")
+
+(define_register_constraint "b" "B_REGS"
+  "Register file B (B0--B31).")
+
+(define_register_constraint "A" "PREDICATE_A_REGS"
+  "Predicate registers in register file A (A0--A2 on C64X and higher,
+   A1 and A2 otherwise).")
+
+(define_register_constraint "B" "PREDICATE_B_REGS"
+  "Predicate registers in register file B (B0--B2).")
+
+(define_register_constraint "C" "CALL_USED_B_REGS"
+  "A call-used register in register file B (B0--B9, B16--B31).")
+
+(define_register_constraint "Da" "NONPREDICATE_A_REGS"
+  "Register file A, excluding predicate registers (A3--A31, plus A0 if
+not C64X or higher).")
+
+(define_register_constraint "Db" "NONPREDICATE_B_REGS"
+  "Register file B, excluding predicate registers (B3--B31).")
+
+(define_register_constraint "Z" "PICREG"
+  "Register B14 (aka DP).")
+
+(define_register_constraint "z" "SPREG"
+  "Register B15 (aka SP).")
+
+(define_constraint "Iu4"
+  "Integer constant in the range 0 @dots{} 15, aka ucst4."
+  (and (match_code "const_int")
+       (match_test "ival >= 0 && ival <= 15")))
+
+(define_constraint "Iu5"
+  "Integer constant in the range 0 @dots{} 31, aka ucst5."
+  (and (match_code "const_int")
+       (match_test "ival >= 0 && ival <= 31")))
+
+(define_constraint "In5"
+  "Integer constant in the range @minus{}31 @dots{} 0, negation of ucst5."
+  (and (match_code "const_int")
+       (match_test "ival >= -31 && ival <= 0")))
+
+(define_constraint "Is5"
+  "Integer constant in the range @minus{}16 @dots{} 15, aka scst5."
+  (and (match_code "const_int")
+       (match_test "ival >= -16 && ival <= 15")))
+
+(define_constraint "I5x"
+  "Integer constant that can be the operand of an ADDA or a SUBA insn."
+  (and (match_code "const_int")
+       (match_test "(ival >= -31 && ival <= 31)
+                   || ((ival & 1) == 0 && ival >= -62 && ival <= 62)
+                   || ((ival & 3) == 0 && ival >= -124 && ival <= 124)
+                   || ((TARGET_INSNS_64 || TARGET_INSNS_67)
+                       && (ival & 7) == 0 && ival > 0 && ival <= 248)")))
+
+(define_constraint "Iux"
+  "Integer constant that can be the operand of a long ADDA or a SUBA insn,
+   i.e. one involving B14 or B15 as source operand."
+  (and (match_code "const_int")
+       (and (match_test "TARGET_INSNS_64PLUS")
+           (match_test "ival >= 0
+                        && (ival < 32768
+                            || ((ival & 1) == 0 && ival < 65536)
+                            || ((ival & 3) == 0 && ival < 131072))"))))
+
+(define_constraint "IuB"
+  "Integer constant in the range 0 @dots{} 65535, aka ucst16."
+  (and (match_code "const_int")
+       (match_test "ival >= 0 && ival <= 65535")))
+
+(define_constraint "IsB"
+  "Integer constant in the range @minus{}32768 @dots{} 32767."
+  (and (match_code "const_int")
+       (match_test "ival >= -32768 && ival <= 32767")))
+
+(define_constraint "IsC"
+  "Integer constant in the range @math{-2^{20}} @dots{} @math{2^{20} - 1}."
+  (and (match_code "const_int")
+       (match_test "ival >= -0x100000 && ival <= 0xfffff")))
+
+(define_constraint "JA"
+  "@internal
+   Integer constant in the range 0 @dots{} 31, corresponding to an A register
+   number."
+  (and (match_code "const_int")
+       (match_test "ival >= 0 && ival < 32")))
+
+(define_constraint "JB"
+  "@internal
+   Integer constant in the range 32 @dots{} 63, corresponding to a B register
+   number."
+  (and (match_code "const_int")
+       (match_test "ival >= 32 && ival < 64")))
+
+(define_constraint "Jc"
+  "Integer constant that is a valid mask for the clr instruction"
+  (and (match_code "const_int")
+       (match_test "c6x_valid_mask_p (ival)")))
+
+(define_constraint "Js"
+  "Integer constant that is a valid mask for the set instruction"
+  (and (match_code "const_int")
+       (match_test "c6x_valid_mask_p (~ival)")))
+
+(define_memory_constraint "Q"
+  "Memory location with A base register."
+  (and (match_code "mem")
+       (match_test "c6x_mem_operand (op, A_REGS, false)")))
+
+(define_memory_constraint "R"
+  "Memory location with B base register."
+  (and (match_code "mem")
+       (match_test "c6x_mem_operand (op, B_REGS, false)")))
+
+(define_memory_constraint "T"
+  "@internal
+   Memory location with B base register, but not using a long offset."
+  (and (match_code "mem")
+       (match_test "c6x_mem_operand (op, B_REGS, true)")))
+
+(define_constraint "S0"
+  "@internal
+   On C64x+ targets, a GP-relative small data reference"
+  (and (match_test "TARGET_INSNS_64PLUS")
+       (match_operand 0 "sdata_symbolic_operand")))
+
+(define_constraint "S1"
+  "@internal
+   Any kind of @code{SYMBOL_REF}, for use in a call address."
+  (and (match_code "symbol_ref")
+       (match_operand 0 "c6x_call_operand")))
+
+(define_constraint "S2"
+  "@internal
+   Any SYMBOL_REF or LABEL_REF."
+  (ior (match_code "symbol_ref") (match_code "label_ref")))
+
+(define_constraint "Si"
+  "@internal
+   Any immediate value, unless it matches the S0 constraint."
+  (and (match_operand 0 "immediate_operand")
+       (match_test "!satisfies_constraint_S0 (op)")))
+
+(define_memory_constraint "W"
+  "@internal
+   A memory operand with an address that can't be used in an unaligned access."
+  (and (match_code "mem")
+       (match_test "!c6x_legitimate_address_p_1 (GET_MODE (op), XEXP (op, 0),
+                                                reload_completed, true)")))
diff --git a/gcc/config/c6x/crti.s b/gcc/config/c6x/crti.s
new file mode 100644 (file)
index 0000000..8fe35c1
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright 2010, 2011  Free Software Foundation, Inc.
+   Contributed by Bernd Schmidt <bernds@codesourcery.com>.
+
+This file 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.
+
+This file 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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+/*
+ * This file just supplies function prologues for the .init and .fini
+ * sections.  It is linked in before crtbegin.o.
+ */
+
+       .section .init
+       .globl  _init
+       .type   _init,@function
+_init:
+       add     .l2     -8, B15, B15
+       stw     .d2t2   B3,*+B15(4)
+       .section .fini
+       .globl  _fini
+       .type   _fini,@function
+_fini:
+       add     .l2     -8, B15, B15
+       stw     .d2t2   B3,*+B15(4)
diff --git a/gcc/config/c6x/crtn.s b/gcc/config/c6x/crtn.s
new file mode 100644 (file)
index 0000000..5900a4b
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright 2010, 2011  Free Software Foundation, Inc.
+   Contributed by Bernd Schmidt <bernds@codesourcery.com>.
+
+This file 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.
+
+This file 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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+/*
+ * This file supplies function epilogues for the .init and .fini sections.
+ * It is linked in after all other files.
+ */
+
+       .section .init
+       ldw .d2t2       *+B15(4), B3
+       add .d2         B15, 8, B15
+       nop             3
+       ret .s2         B3
+       nop             5
+
+       .section .fini
+       ldw .d2t2       *+B15(4), B3
+       add .d2         B15, 8, B15
+       nop             3
+       ret .s2         B3
+       nop             5
+
diff --git a/gcc/config/c6x/elf-common.h b/gcc/config/c6x/elf-common.h
new file mode 100644 (file)
index 0000000..50a3c3a
--- /dev/null
@@ -0,0 +1,37 @@
+/* ELF definitions for TI C6X
+   Copyright (C) 2010 Free Software Foundation, Inc.
+   Contributed by Andrew Jenner <andrew@codesourcery.com>
+   Contributed by Bernd Schmidt <bernds@codesourcery.com>
+
+   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/>.  */
+
+/* Controlling the Compilation Driver.  */
+#define ENDIAN_LINK_SPEC "%{mbig-endian:-EB} %{mlittle-endian:-EL} "
+
+#undef ASM_SPEC
+#define ASM_SPEC "%{march=*:-march=%*} %{mbig-endian:-mbig-endian} \
+ %{mdsbt:-mdsbt %{!fPIC:-mpid=near} %{fPIC:-mpid=far -mpic} %{fpic:-mpic}} \
+ %{!mdsbt:%{fpic:-mpic -mpid=near} %{fPIC:-mpic -mpid=far}}"
+
+#undef DATA_SECTION_ASM_OP
+#define DATA_SECTION_ASM_OP "\t.section\t\".fardata\",\"aw\""
+#undef READONLY_DATA_SECTION_ASM_OP
+#define READONLY_DATA_SECTION_ASM_OP "\t.section\t\".const\",\"a\",@progbits"
+#define BSS_SECTION_ASM_OP "\t.section\t\".far\",\"aw\",@nobits"
+#define SDATA_SECTION_ASM_OP "\t.section\t\".neardata\",\"aw\""
+#define SBSS_SECTION_ASM_OP "\t.section\t\".bss\",\"aw\",@nobits"
+#define TARGET_LIBGCC_SDATA_SECTION ".neardata"
diff --git a/gcc/config/c6x/elf.h b/gcc/config/c6x/elf.h
new file mode 100644 (file)
index 0000000..d89ed43
--- /dev/null
@@ -0,0 +1,35 @@
+/* ELF definitions for TI C6X
+   Copyright (C) 2010 Free Software Foundation, Inc.
+   Contributed by Andrew Jenner <andrew@codesourcery.com>
+   Contributed by Bernd Schmidt <bernds@codesourcery.com>
+
+   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/>.  */
+
+/* crt0.o should come from the linker script, but for compatibility,
+   we mention it here for -msim.  */
+#undef  STARTFILE_SPEC
+#define STARTFILE_SPEC "%{msim:crt0%O%s} crti%O%s crtbegin%O%s"
+
+#undef  ENDFILE_SPEC
+#define ENDFILE_SPEC   "crtend%O%s crtn%O%s"
+
+#undef  LIB_SPEC
+#define LIB_SPEC "%{msim:--start-group -lc -lsim --end-group;" \
+       ":-lc}"
+
+#undef LINK_SPEC
+#define LINK_SPEC ENDIAN_LINK_SPEC
diff --git a/gcc/config/c6x/eqd.c b/gcc/config/c6x/eqd.c
new file mode 100644 (file)
index 0000000..c19f886
--- /dev/null
@@ -0,0 +1,47 @@
+/* Software floating-point emulation.
+   Return 1 iff a == b, 0 otherwise.
+   Copyright (C) 1997,1999,2006,2007,2011 Free Software Foundation, Inc.
+   Contributed by Richard Henderson (rth@cygnus.com) and
+                 Jakub Jelinek (jj@ultra.linux.cz).
+
+   This file is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file into
+   combinations with other programs, and to distribute those
+   combinations without any restriction coming from the use of this
+   file.  (The Lesser General Public License restrictions do apply in
+   other respects; for example, they cover modification of the file,
+   and distribution when not linked into a combine executable.)
+
+   This file 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with GCC; see the file COPYING.LIB.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "config/soft-fp/soft-fp.h"
+#include "config/soft-fp/double.h"
+
+CMPtype __c6xabi_eqd(DFtype a, DFtype b)
+{
+  FP_DECL_EX;
+  FP_DECL_D(A); FP_DECL_D(B);
+  CMPtype r;
+
+  FP_UNPACK_RAW_D(A, a);
+  FP_UNPACK_RAW_D(B, b);
+  FP_CMP_EQ_D(r, A, B);
+  if (r && (FP_ISSIGNAN_D(A) || FP_ISSIGNAN_D(B)))
+    FP_SET_EXCEPTION(FP_EX_INVALID);
+  FP_HANDLE_EXCEPTIONS;
+
+  return !r;
+}
diff --git a/gcc/config/c6x/eqf.c b/gcc/config/c6x/eqf.c
new file mode 100644 (file)
index 0000000..c87c92b
--- /dev/null
@@ -0,0 +1,47 @@
+/* Software floating-point emulation.
+   Return 1 iff a == b, 0 otherwise.
+   Copyright (C) 1997,1999,2006,2007,2011 Free Software Foundation, Inc.
+   Contributed by Richard Henderson (rth@cygnus.com) and
+                 Jakub Jelinek (jj@ultra.linux.cz).
+
+   This file is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file into
+   combinations with other programs, and to distribute those
+   combinations without any restriction coming from the use of this
+   file.  (The Lesser General Public License restrictions do apply in
+   other respects; for example, they cover modification of the file,
+   and distribution when not linked into a combine executable.)
+
+   This file 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with GCC; see the file COPYING.LIB.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "config/soft-fp/soft-fp.h"
+#include "config/soft-fp/single.h"
+
+CMPtype __c6xabi_eqf(SFtype a, SFtype b)
+{
+  FP_DECL_EX;
+  FP_DECL_S(A); FP_DECL_S(B);
+  CMPtype r;
+
+  FP_UNPACK_RAW_S(A, a);
+  FP_UNPACK_RAW_S(B, b);
+  FP_CMP_EQ_S(r, A, B);
+  if (r && (FP_ISSIGNAN_S(A) || FP_ISSIGNAN_S(B)))
+    FP_SET_EXCEPTION(FP_EX_INVALID);
+  FP_HANDLE_EXCEPTIONS;
+
+  return !r;
+}
diff --git a/gcc/config/c6x/ged.c b/gcc/config/c6x/ged.c
new file mode 100644 (file)
index 0000000..30590b2
--- /dev/null
@@ -0,0 +1,47 @@
+/* Software floating-point emulation.
+   Return 1 iff a >= b, 0 otherwise.
+   Copyright (C) 1997,1999,2006,2007,2011 Free Software Foundation, Inc.
+   Contributed by Richard Henderson (rth@cygnus.com) and
+                 Jakub Jelinek (jj@ultra.linux.cz).
+
+   This file is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file into
+   combinations with other programs, and to distribute those
+   combinations without any restriction coming from the use of this
+   file.  (The Lesser General Public License restrictions do apply in
+   other respects; for example, they cover modification of the file,
+   and distribution when not linked into a combine executable.)
+
+   This file 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with GCC; see the file COPYING.LIB.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "config/soft-fp/soft-fp.h"
+#include "config/soft-fp/double.h"
+
+CMPtype __c6xabi_ged(DFtype a, DFtype b)
+{
+  FP_DECL_EX;
+  FP_DECL_D(A); FP_DECL_D(B);
+  CMPtype r;
+
+  FP_UNPACK_RAW_D(A, a);
+  FP_UNPACK_RAW_D(B, b);
+  FP_CMP_D(r, A, B, -2);
+  if (r == -2 && (FP_ISSIGNAN_D(A) || FP_ISSIGNAN_D(B)))
+    FP_SET_EXCEPTION(FP_EX_INVALID);
+  FP_HANDLE_EXCEPTIONS;
+
+  return r >= 0;
+}
diff --git a/gcc/config/c6x/gef.c b/gcc/config/c6x/gef.c
new file mode 100644 (file)
index 0000000..0a22b13
--- /dev/null
@@ -0,0 +1,47 @@
+/* Software floating-point emulation.
+   Return 1 iff a >= b, 0 otherwise.
+   Copyright (C) 1997,1999,2006,2007 Free Software Foundation, Inc.
+   Contributed by Richard Henderson (rth@cygnus.com) and
+                 Jakub Jelinek (jj@ultra.linux.cz).
+
+   This file is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file into
+   combinations with other programs, and to distribute those
+   combinations without any restriction coming from the use of this
+   file.  (The Lesser General Public License restrictions do apply in
+   other respects; for example, they cover modification of the file,
+   and distribution when not linked into a combine executable.)
+
+   This file 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with GCC; see the file COPYING.LIB.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "config/soft-fp/soft-fp.h"
+#include "config/soft-fp/single.h"
+
+CMPtype __c6xabi_gef(SFtype a, SFtype b)
+{
+  FP_DECL_EX;
+  FP_DECL_S(A); FP_DECL_S(B);
+  CMPtype r;
+
+  FP_UNPACK_RAW_S(A, a);
+  FP_UNPACK_RAW_S(B, b);
+  FP_CMP_S(r, A, B, -2);
+  if (r == -2 && (FP_ISSIGNAN_S(A) || FP_ISSIGNAN_S(B)))
+    FP_SET_EXCEPTION(FP_EX_INVALID);
+  FP_HANDLE_EXCEPTIONS;
+
+  return r >= 0;
+}
diff --git a/gcc/config/c6x/genmult.sh b/gcc/config/c6x/genmult.sh
new file mode 100644 (file)
index 0000000..993c826
--- /dev/null
@@ -0,0 +1,33 @@
+#! /bin/sh
+# Generate c6x-mult.md from c6x-mult.md.in
+# The input file is passed as an argument.
+
+# Copyright 2011 Free Software Foundation, Inc.
+
+#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/>.
+
+echo ";; -*- buffer-read-only: t -*-"
+echo ";; Generated automatically from c6x-mult.md.in by genmult.sh"
+
+sed -e "s,_VARIANT_,,g" -e "s,_SET_,set,g" -e "s,_.BRK_,,g" \
+    -e "s,_A_,a,g" -e "s,_B_,b,g" -e "s,_DESTOPERAND_,register_operand,g" \
+    -e "s,_MOD._,,g" -e "s,:_M,:,g" < $1
+
+sed -e "s,_VARIANT_,_real,g" -e "s,_SET_,unspec,g" -e "s,_OBRK_,[,g" \
+    -e "s,_CBRK_,] UNSPEC_REAL_MULT,g" -e "s,_A_,JA,g" -e "s,_B_,JB,g" \
+    -e "s,_DESTOPERAND_,const_int_operand,g" -e "s,_MODk_,k,g" \
+    -e "s,_MODK_,K,g" -e 's,:_MV..[IQ],:SI,g' -e "s,:_MSQ,:SI,g"  < $1
diff --git a/gcc/config/c6x/genopt.sh b/gcc/config/c6x/genopt.sh
new file mode 100644 (file)
index 0000000..5f323c9
--- /dev/null
@@ -0,0 +1,59 @@
+#!/bin/sh
+# Generate c6x-tables.opt from the lists in *.def.
+# Copyright (C) 2011 Free Software Foundation, Inc.
+#
+# 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/>.
+
+cat <<EOF
+; -*- buffer-read-only: t -*-
+; Generated automatically by genopt.sh from c6x-isas.def.
+;
+; Copyright (C) 2011 Free Software Foundation, Inc.
+;
+; 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/>.
+
+Enum
+Name(c6x_isa) Type(int)
+Known C6X ISAs (for use with the -march= option):
+
+EOF
+
+awk -F'[(,     ]+' 'BEGIN {
+    value = 0
+}
+/^C6X_ISA/ {
+    name = $2
+    gsub("\"", "", name)
+    print "EnumValue"
+    print "Enum(c6x_isa) String(" name ") Value(" value ")"
+    print ""
+    value++
+}' $1/c6x-isas.def
diff --git a/gcc/config/c6x/gensched.sh b/gcc/config/c6x/gensched.sh
new file mode 100644 (file)
index 0000000..61ea70d
--- /dev/null
@@ -0,0 +1,44 @@
+#! /bin/sh
+# Generate c6x-sched.md from c6x-sched.md.in
+# The input file is passed as an argument.
+
+# Copyright 2010, 2011 Free Software Foundation, Inc.
+
+#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/>.
+
+echo ";; -*- buffer-read-only: t -*-"
+echo ";; Generated automatically from c6x-sched.md.in by gensched.sh"
+
+for cross in n y; do
+    for side in 1 2; do
+       tside=$side
+       case $side in
+           1) rf="a"; otherside=2 ;;
+           2) rf="b"; otherside=1 ;;
+       esac
+       case $cross in
+           y) cunit="+x$side"; tside=$otherside;;
+           n) cunit="";;
+       esac
+       echo
+       echo ";; Definitions for side $side, cross $cross"
+       echo
+       sed -e "s,_CROSS_,$cross,g" -e "s,_CUNIT_,$cunit,g" \
+           -e "s,_N_,$side,g" -e "s,_RF_,$rf,g" -e "s,_NX_,$tside,g" \
+           < $1
+    done
+done
diff --git a/gcc/config/c6x/gtd.c b/gcc/config/c6x/gtd.c
new file mode 100644 (file)
index 0000000..042192b
--- /dev/null
@@ -0,0 +1,47 @@
+/* Software floating-point emulation.
+   Return 1 iff a > b, 0 otherwise.
+   Copyright (C) 1997,1999,2006,2007,2011 Free Software Foundation, Inc.
+   Contributed by Richard Henderson (rth@cygnus.com) and
+                 Jakub Jelinek (jj@ultra.linux.cz).
+
+   This file is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file into
+   combinations with other programs, and to distribute those
+   combinations without any restriction coming from the use of this
+   file.  (The Lesser General Public License restrictions do apply in
+   other respects; for example, they cover modification of the file,
+   and distribution when not linked into a combine executable.)
+
+   This file 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with GCC; see the file COPYING.LIB.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "config/soft-fp/soft-fp.h"
+#include "config/soft-fp/double.h"
+
+CMPtype __c6xabi_gtd(DFtype a, DFtype b)
+{
+  FP_DECL_EX;
+  FP_DECL_D(A); FP_DECL_D(B);
+  CMPtype r;
+
+  FP_UNPACK_RAW_D(A, a);
+  FP_UNPACK_RAW_D(B, b);
+  FP_CMP_D(r, A, B, -2);
+  if (r == -2 && (FP_ISSIGNAN_D(A) || FP_ISSIGNAN_D(B)))
+    FP_SET_EXCEPTION(FP_EX_INVALID);
+  FP_HANDLE_EXCEPTIONS;
+
+  return r > 0;
+}
diff --git a/gcc/config/c6x/gtf.c b/gcc/config/c6x/gtf.c
new file mode 100644 (file)
index 0000000..0d0e10a
--- /dev/null
@@ -0,0 +1,47 @@
+/* Software floating-point emulation.
+   Return 1 iff a > b, 0 otherwise.
+   Copyright (C) 1997,1999,2006,2007,2011 Free Software Foundation, Inc.
+   Contributed by Richard Henderson (rth@cygnus.com) and
+                 Jakub Jelinek (jj@ultra.linux.cz).
+
+   This file is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file into
+   combinations with other programs, and to distribute those
+   combinations without any restriction coming from the use of this
+   file.  (The Lesser General Public License restrictions do apply in
+   other respects; for example, they cover modification of the file,
+   and distribution when not linked into a combine executable.)
+
+   This file 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with GCC; see the file COPYING.LIB.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "config/soft-fp/soft-fp.h"
+#include "config/soft-fp/single.h"
+
+CMPtype __c6xabi_gtf(SFtype a, SFtype b)
+{
+  FP_DECL_EX;
+  FP_DECL_S(A); FP_DECL_S(B);
+  CMPtype r;
+
+  FP_UNPACK_RAW_S(A, a);
+  FP_UNPACK_RAW_S(B, b);
+  FP_CMP_S(r, A, B, -2);
+  if (r == -2 && (FP_ISSIGNAN_S(A) || FP_ISSIGNAN_S(B)))
+    FP_SET_EXCEPTION(FP_EX_INVALID);
+  FP_HANDLE_EXCEPTIONS;
+
+  return r > 0;
+}
diff --git a/gcc/config/c6x/led.c b/gcc/config/c6x/led.c
new file mode 100644 (file)
index 0000000..b97f3d1
--- /dev/null
@@ -0,0 +1,47 @@
+/* Software floating-point emulation.
+   Return 1 iff a <= b, 0 otherwise.
+   Copyright (C) 1997,1999,2006,2007,2011 Free Software Foundation, Inc.
+   Contributed by Richard Henderson (rth@cygnus.com) and
+                 Jakub Jelinek (jj@ultra.linux.cz).
+
+   This file is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file into
+   combinations with other programs, and to distribute those
+   combinations without any restriction coming from the use of this
+   file.  (The Lesser General Public License restrictions do apply in
+   other respects; for example, they cover modification of the file,
+   and distribution when not linked into a combine executable.)
+
+   This file 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with GCC; see the file COPYING.LIB.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "config/soft-fp/soft-fp.h"
+#include "config/soft-fp/double.h"
+
+CMPtype __c6xabi_led(DFtype a, DFtype b)
+{
+  FP_DECL_EX;
+  FP_DECL_D(A); FP_DECL_D(B);
+  CMPtype r;
+
+  FP_UNPACK_RAW_D(A, a);
+  FP_UNPACK_RAW_D(B, b);
+  FP_CMP_D(r, A, B, 2);
+  if (r == 2 && (FP_ISSIGNAN_D(A) || FP_ISSIGNAN_D(B)))
+    FP_SET_EXCEPTION(FP_EX_INVALID);
+  FP_HANDLE_EXCEPTIONS;
+
+  return r <= 0;
+}
diff --git a/gcc/config/c6x/lef.c b/gcc/config/c6x/lef.c
new file mode 100644 (file)
index 0000000..d234a18
--- /dev/null
@@ -0,0 +1,47 @@
+/* Software floating-point emulation.
+   Return 1 iff a <= b, 0 otherwise.
+   Copyright (C) 1997,1999,2006,2007,2011 Free Software Foundation, Inc.
+   Contributed by Richard Henderson (rth@cygnus.com) and
+                 Jakub Jelinek (jj@ultra.linux.cz).
+
+   This file is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file into
+   combinations with other programs, and to distribute those
+   combinations without any restriction coming from the use of this
+   file.  (The Lesser General Public License restrictions do apply in
+   other respects; for example, they cover modification of the file,
+   and distribution when not linked into a combine executable.)
+
+   This file 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with GCC; see the file COPYING.LIB.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "config/soft-fp/soft-fp.h"
+#include "config/soft-fp/single.h"
+
+CMPtype __c6xabi_lef(SFtype a, SFtype b)
+{
+  FP_DECL_EX;
+  FP_DECL_S(A); FP_DECL_S(B);
+  CMPtype r;
+
+  FP_UNPACK_RAW_S(A, a);
+  FP_UNPACK_RAW_S(B, b);
+  FP_CMP_S(r, A, B, 2);
+  if (r == 2 && (FP_ISSIGNAN_S(A) || FP_ISSIGNAN_S(B)))
+    FP_SET_EXCEPTION(FP_EX_INVALID);
+  FP_HANDLE_EXCEPTIONS;
+
+  return r <= 0;
+}
diff --git a/gcc/config/c6x/lib1funcs.asm b/gcc/config/c6x/lib1funcs.asm
new file mode 100644 (file)
index 0000000..5bf3447
--- /dev/null
@@ -0,0 +1,438 @@
+/* Copyright 2010, 2011  Free Software Foundation, Inc.
+   Contributed by Bernd Schmidt <bernds@codesourcery.com>.
+
+This file 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.
+
+This file 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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+       ;; ABI considerations for the divide functions
+       ;; The following registers are call-used:
+       ;; __c6xabi_divi A0,A1,A2,A4,A6,B0,B1,B2,B4,B5
+       ;; __c6xabi_divu A0,A1,A2,A4,A6,B0,B1,B2,B4
+       ;; __c6xabi_remi A1,A2,A4,A5,A6,B0,B1,B2,B4
+       ;; __c6xabi_remu A1,A4,A5,A7,B0,B1,B2,B4
+       ;;
+       ;; In our implementation, divu and remu are leaf functions,
+       ;; while both divi and remi call into divu.
+       ;; A0 is not clobbered by any of the functions.
+       ;; divu does not clobber B2 either, which is taken advantage of
+       ;; in remi.
+       ;; divi uses B5 to hold the original return address during
+       ;; the call to divu.
+       ;; remi uses B2 and A5 to hold the input values during the
+       ;; call to divu.  It stores B3 in on the stack.
+
+#ifdef L_divsi3
+.text
+.align 2
+.global __c6xabi_divi
+.hidden __c6xabi_divi
+.type __c6xabi_divi, STT_FUNC
+
+__c6xabi_divi:
+       call .s2        __c6xabi_divu
+||     mv .d2          B3, B5
+||     cmpgt .l1       0, A4, A1
+||     cmpgt .l2       0, B4, B1
+
+       [A1] neg .l1    A4, A4
+||     [B1] neg .l2    B4, B4
+||     xor .s1x        A1, B1, A1
+
+#ifdef _TMS320C6400
+       [A1] addkpc .s2 1f, B3, 4
+#else
+       [A1] mvkl .s2   1f, B3
+       [A1] mvkh .s2   1f, B3
+       nop             2
+#endif
+1:
+       neg .l1         A4, A4
+||     mv .l2          B3,B5
+||     ret .s2         B5
+       nop             5
+#endif
+
+#if defined L_modsi3 || defined L_divmodsi4
+.align 2
+#ifdef L_modsi3
+#define MOD_OUTPUT_REG A4
+.global __c6xabi_remi
+.hidden __c6xabi_remi
+.type __c6xabi_remi, STT_FUNC
+#else
+#define MOD_OUTPUT_REG A5
+.global __c6xabi_divremi
+.hidden __c6xabi_divremi
+.type __c6xabi_divremi, STT_FUNC
+__c6xabi_divremi:
+#endif
+
+__c6xabi_remi:
+       stw .d2t2       B3, *B15--[2]
+||     cmpgt .l1       0, A4, A1
+||     cmpgt .l2       0, B4, B2
+||     mv .s1          A4, A5
+||     call .s2        __c6xabi_divu
+
+       [A1] neg .l1    A4, A4
+||     [B2] neg .l2    B4, B4
+||     xor .s2x        B2, A1, B0
+||     mv .d2          B4, B2
+
+#ifdef _TMS320C6400
+       [B0] addkpc .s2 1f, B3, 1
+       [!B0] addkpc .s2 2f, B3, 1
+       nop             2
+#else
+       [B0] mvkl .s2   1f,B3
+       [!B0] mvkl .s2  2f,B3
+
+       [B0] mvkh .s2   1f,B3
+       [!B0] mvkh .s2  2f,B3
+#endif
+1:
+       neg .l1         A4, A4
+2:
+       ldw .d2t2       *++B15[2], B3
+
+#ifdef _TMS320C6400_PLUS
+       mpy32 .m1x      A4, B2, A6
+       nop             3
+       ret .s2         B3
+       sub .l1         A5, A6, MOD_OUTPUT_REG
+       nop             4
+#else
+       mpyu .m1x       A4, B2, A1
+       nop             1
+       mpylhu .m1x     A4, B2, A6
+||     mpylhu .m2x     B2, A4, B2
+       nop             1
+       add .l1x        A6, B2, A6
+||     ret .s2         B3
+       shl .s1         A6, 16, A6
+       add .d1         A6, A1, A6
+       sub .l1         A5, A6, MOD_OUTPUT_REG
+       nop             2
+#endif
+
+#endif
+
+#if defined L_udivsi3 || defined L_udivmodsi4
+.align 2
+#ifdef L_udivsi3
+.global __c6xabi_divu
+.hidden __c6xabi_divu
+.type __c6xabi_divu, STT_FUNC
+__c6xabi_divu:
+#else
+.global __c6xabi_divremu
+.hidden __c6xabi_divremu
+.type __c6xabi_divremu, STT_FUNC
+__c6xabi_divremu:
+#endif
+       ;; We use a series of up to 31 subc instructions.  First, we find
+       ;; out how many leading zero bits there are in the divisor.  This
+       ;; gives us both a shift count for aligning (shifting) the divisor
+       ;; to the, and the number of times we have to execute subc.
+
+       ;; At the end, we have both the remainder and most of the quotient
+       ;; in A4.  The top bit of the quotient is computed first and is
+       ;; placed in A2.
+
+       ;; Return immediately if the dividend is zero.  Setting B4 to 1
+       ;; is a trick to allow us to leave the following insns in the jump
+       ;; delay slot without affecting the result.
+       mv      .s2x    A4, B1
+
+#ifndef _TMS320C6400
+[!b1]  mvk     .s2     1, B4
+#endif
+[b1]   lmbd    .l2     1, B4, B1
+||[!b1] b      .s2     B3      ; RETURN A
+#ifdef _TMS320C6400
+||[!b1] mvk    .d2     1, B4
+#endif
+#ifdef L_udivmodsi4
+||[!b1] zero   .s1     A5
+#endif
+       mv      .l1x    B1, A6
+||     shl     .s2     B4, B1, B4
+
+       ;; The loop performs a maximum of 28 steps, so we do the
+       ;; first 3 here.
+       cmpltu  .l1x    A4, B4, A2
+[!A2]  sub     .l1x    A4, B4, A4
+||     shru    .s2     B4, 1, B4
+||     xor     .s1     1, A2, A2
+
+       shl     .s1     A2, 31, A2
+|| [b1]        subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+[b1]   subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+
+       ;; RETURN A may happen here (note: must happen before the next branch)
+0:
+       cmpgt   .l2     B1, 7, B0
+|| [b1]        subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+[b1]   subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+|| [b0] b      .s1     0b
+[b1]   subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+[b1]   subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+[b1]   subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+[b1]   subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+[b1]   subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+       ;; loop backwards branch happens here
+
+       ret     .s2     B3
+||     mvk     .s1     32, A1
+       sub     .l1     A1, A6, A6
+#ifdef L_udivmodsi4
+||     extu    .s1     A4, A6, A5
+#endif
+       shl     .s1     A4, A6, A4
+       shru    .s1     A4, 1, A4
+||     sub     .l1     A6, 1, A6
+       or      .l1     A2, A4, A4
+       shru    .s1     A4, A6, A4
+       nop
+
+#endif
+
+#ifdef L_umodsi3
+.align 2
+.global __c6xabi_remu
+.hidden __c6xabi_remu
+.type __c6xabi_remu, STT_FUNC
+__c6xabi_remu:
+       ;; The ABI seems designed to prevent these functions calling each other,
+       ;; so we duplicate most of the divsi3 code here.
+       mv      .s2x    A4, B1
+#ifndef _TMS320C6400
+[!b1]  mvk     .s2     1, B4
+#endif
+       lmbd    .l2     1, B4, B1
+||[!b1] b      .s2     B3      ; RETURN A
+#ifdef _TMS320C6400
+||[!b1] mvk    .d2     1, B4
+#endif
+
+       mv      .l1x    B1, A7
+||     shl     .s2     B4, B1, B4
+
+       cmpltu  .l1x    A4, B4, A1
+[!a1]  sub     .l1x    A4, B4, A4
+       shru    .s2     B4, 1, B4
+
+0:
+       cmpgt   .l2     B1, 7, B0
+|| [b1]        subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+       ;; RETURN A may happen here (note: must happen before the next branch)
+[b1]   subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+|| [b0] b      .s1     0b
+[b1]   subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+[b1]   subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+[b1]   subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+[b1]   subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+[b1]   subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+       ;; loop backwards branch happens here
+
+       ret     .s2     B3
+[b1]   subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+[b1]   subc    .l1x    A4,B4,A4
+
+       extu    .s1     A4, A7, A4
+       nop     2
+#endif
+
+#if defined L_strasgi_64plus && defined _TMS320C6400_PLUS
+
+.align 2
+.global __c6xabi_strasgi_64plus
+.hidden __c6xabi_strasgi_64plus
+.type __c6xabi_strasgi_64plus, STT_FUNC
+__c6xabi_strasgi_64plus:
+       shru    .s2x    a6, 2, b31
+||     mv      .s1     a4, a30
+||     mv      .d2     b4, b30
+
+       add     .s2     -4, b31, b31
+
+       sploopd         1
+||     mvc     .s2     b31, ilc
+       ldw     .d2t2   *b30++, b31
+       nop     4
+       mv      .s1x    b31,a31
+       spkernel        6, 0
+||     stw     .d1t1   a31, *a30++
+
+       ret     .s2     b3
+       nop 5
+#endif
+
+#ifdef L_strasgi
+.global __c6xabi_strasgi
+.type __c6xabi_strasgi, STT_FUNC
+__c6xabi_strasgi:
+       ;; This is essentially memcpy, with alignment known to be at least
+       ;; 4, and the size a multiple of 4 greater than or equal to 28.
+       ldw     .d2t1   *B4++, A0
+||     mvk     .s2     16, B1
+       ldw     .d2t1   *B4++, A1
+||     mvk     .s2     20, B2
+||     sub     .d1     A6, 24, A6
+       ldw     .d2t1   *B4++, A5
+       ldw     .d2t1   *B4++, A7
+||     mv      .l2x    A6, B7
+       ldw     .d2t1   *B4++, A8
+       ldw     .d2t1   *B4++, A9
+||     mv      .s2x    A0, B5
+||     cmpltu  .l2     B2, B7, B0
+
+0:
+       stw     .d1t2   B5, *A4++
+||[b0] ldw     .d2t1   *B4++, A0
+||     mv      .s2x    A1, B5
+||     mv      .l2     B7, B6
+
+[b0]   sub     .d2     B6, 24, B7
+||[b0] b       .s2     0b
+||     cmpltu  .l2     B1, B6, B0
+
+[b0]   ldw     .d2t1   *B4++, A1
+||     stw     .d1t2   B5, *A4++
+||     mv      .s2x    A5, B5
+||     cmpltu  .l2     12, B6, B0
+
+[b0]   ldw     .d2t1   *B4++, A5
+||     stw     .d1t2   B5, *A4++
+||     mv      .s2x    A7, B5
+||     cmpltu  .l2     8, B6, B0
+
+[b0]   ldw     .d2t1   *B4++, A7
+||     stw     .d1t2   B5, *A4++
+||     mv      .s2x    A8, B5
+||     cmpltu  .l2     4, B6, B0
+
+[b0]   ldw     .d2t1   *B4++, A8
+||     stw     .d1t2   B5, *A4++
+||     mv      .s2x    A9, B5
+||     cmpltu  .l2     0, B6, B0
+
+[b0]   ldw     .d2t1   *B4++, A9
+||     stw     .d1t2   B5, *A4++
+||     mv      .s2x    A0, B5
+||     cmpltu  .l2     B2, B7, B0
+
+       ;; loop back branch happens here
+
+       cmpltu  .l2     B1, B6, B0
+||     ret     .s2     b3
+
+[b0]   stw     .d1t1   A1, *A4++
+||     cmpltu  .l2     12, B6, B0
+[b0]   stw     .d1t1   A5, *A4++
+||     cmpltu  .l2     8, B6, B0
+[b0]   stw     .d1t1   A7, *A4++
+||     cmpltu  .l2     4, B6, B0
+[b0]   stw     .d1t1   A8, *A4++
+||     cmpltu  .l2     0, B6, B0
+[b0]   stw     .d1t1   A9, *A4++
+
+       ;; return happens here
+
+#endif
+
+#ifdef _TMS320C6400_PLUS
+#ifdef L_push_rts
+.align 2
+.global __c6xabi_push_rts
+.hidden __c6xabi_push_rts
+.type __c6xabi_push_rts, STT_FUNC
+__c6xabi_push_rts:
+       stw .d2t2       B14, *B15--[2]
+       stdw .d2t1      A15:A14, *B15--
+||     b .s2x          A3
+       stdw .d2t2      B13:B12, *B15--
+       stdw .d2t1      A13:A12, *B15--
+       stdw .d2t2      B11:B10, *B15--
+       stdw .d2t1      A11:A10, *B15--
+       stdw .d2t2      B3:B2, *B15--
+#endif
+
+#ifdef L_pop_rts
+.align 2
+.global __c6xabi_pop_rts
+.hidden __c6xabi_pop_rts
+.type __c6xabi_pop_rts, STT_FUNC
+__c6xabi_pop_rts:
+       lddw .d2t2      *++B15, B3:B2
+       lddw .d2t1      *++B15, A11:A10
+       lddw .d2t2      *++B15, B11:B10
+       lddw .d2t1      *++B15, A13:A12
+       lddw .d2t2      *++B15, B13:B12
+       lddw .d2t1      *++B15, A15:A14
+||     b .s2           B3
+       ldw .d2t2       *++B15[2], B14
+       nop             4
+#endif
+
+#ifdef L_call_stub
+.align 2
+.global __c6xabi_call_stub
+.type __c6xabi_call_stub, STT_FUNC
+__c6xabi_call_stub:
+       stw .d2t1       A2, *B15--[2]
+       stdw .d2t1      A7:A6, *B15--
+||     call .s2        B31
+       stdw .d2t1      A1:A0, *B15--
+       stdw .d2t2      B7:B6, *B15--
+       stdw .d2t2      B5:B4, *B15--
+       stdw .d2t2      B1:B0, *B15--
+       stdw .d2t2      B3:B2, *B15--
+||     addkpc .s2      1f, B3, 0
+1:
+       lddw .d2t2      *++B15, B3:B2
+       lddw .d2t2      *++B15, B1:B0
+       lddw .d2t2      *++B15, B5:B4
+       lddw .d2t2      *++B15, B7:B6
+       lddw .d2t1      *++B15, A1:A0
+       lddw .d2t1      *++B15, A7:A6
+||     b .s2           B3
+       ldw .d2t1       *++B15[2], A2
+       nop             4
+#endif
+
+#endif
+
diff --git a/gcc/config/c6x/libgcc-c6xeabi.ver b/gcc/config/c6x/libgcc-c6xeabi.ver
new file mode 100644 (file)
index 0000000..6bce556
--- /dev/null
@@ -0,0 +1,103 @@
+# Copyright (C) 2011 Free Software Foundation, Inc.
+#
+# 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/>.
+
+GCC_4.7.0 {
+  __c6xabi_strasgi
+  __c6xabi_call_stub
+  __c6xabi_mpyll
+  __c6xabi_negll
+  __c6xabi_llshru
+  __c6xabi_llshl
+  __c6xabi_llshr
+  __c6xabi_fixfu
+  __c6xabi_fixdu
+  __c6xabi_fixflli
+  __c6xabi_fixdlli
+  __c6xabi_fixfull
+  __c6xabi_fixdull
+  __c6xabi_fltllif
+  __c6xabi_fltllid
+  __c6xabi_fltullf
+  __c6xabi_fltulld
+  __c6xabi_divlli
+  __c6xabi_remlli
+  __c6xabi_divull
+  __c6xabi_remull
+  __c6xabi_divremull
+  __c6xabi_gef
+  __c6xabi_gtf
+  __c6xabi_lef
+  __c6xabi_ltf
+  __c6xabi_eqf
+  __c6xabi_ged
+  __c6xabi_gtd
+  __c6xabi_led
+  __c6xabi_ltd
+  __c6xabi_eqd
+  __c6xabi_addf
+  __c6xabi_divf
+  __c6xabi_neqf
+  __c6xabi_cmpf
+  __c6xabi_mpyf
+  __c6xabi_negf
+  __c6xabi_subf
+  __c6xabi_unordf
+  __c6xabi_fixfi
+  __c6xabi_fltif
+  __c6xabi_fltuf
+  __c6xabi_addd
+  __c6xabi_divd
+  __c6xabi_neqd
+  __c6xabi_cmpd
+  __c6xabi_mpyd
+  __c6xabi_negd
+  __c6xabi_subd
+  __c6xabi_unordd
+  __c6xabi_fixdi
+  __c6xabi_fltid
+  __c6xabi_fltud
+  __c6xabi_cvtfd
+  __c6xabi_cvtdf
+  __c6xabi_mulcf
+  __c6xabi_mulcd
+  __c6xabi_divcf
+  __c6xabi_divcd
+
+  __gnu_ltsf2
+  __gnu_ltdf2
+  __gnu_gesf2
+  __gnu_gedf2
+  __gnu_gtsf2
+  __gnu_gtdf2
+  __gnu_eqsf2
+  __gnu_eqdf2
+
+  # Exception-Handling
+  _Unwind_Complete
+  _Unwind_VRS_Get
+  _Unwind_VRS_Set
+  _Unwind_VRS_Pop
+  __c6xabi_unwind_cpp_pr0
+  __c6xabi_unwind_cpp_pr1
+  __c6xabi_unwind_cpp_pr2
+  __c6xabi_unwind_cpp_pr3
+  __c6xabi_unwind_cpp_pr4
+  # The libstdc++ exception-handling personality routine uses this 
+  # GNU-specific entry point.
+  __gnu_unwind_frame
+}
diff --git a/gcc/config/c6x/ltd.c b/gcc/config/c6x/ltd.c
new file mode 100644 (file)
index 0000000..5518583
--- /dev/null
@@ -0,0 +1,47 @@
+/* Software floating-point emulation.
+   Return 1 iff a < b, 0 otherwise.
+   Copyright (C) 1997,1999,2006,2007,2011 Free Software Foundation, Inc.
+   Contributed by Richard Henderson (rth@cygnus.com) and
+                 Jakub Jelinek (jj@ultra.linux.cz).
+
+   This file is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file into
+   combinations with other programs, and to distribute those
+   combinations without any restriction coming from the use of this
+   file.  (The Lesser General Public License restrictions do apply in
+   other respects; for example, they cover modification of the file,
+   and distribution when not linked into a combine executable.)
+
+   This file 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with GCC; see the file COPYING.LIB.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "config/soft-fp/soft-fp.h"
+#include "config/soft-fp/double.h"
+
+CMPtype __c6xabi_ltd(DFtype a, DFtype b)
+{
+  FP_DECL_EX;
+  FP_DECL_D(A); FP_DECL_D(B);
+  CMPtype r;
+
+  FP_UNPACK_RAW_D(A, a);
+  FP_UNPACK_RAW_D(B, b);
+  FP_CMP_D(r, A, B, 2);
+  if (r == 2 && (FP_ISSIGNAN_D(A) || FP_ISSIGNAN_D(B)))
+    FP_SET_EXCEPTION(FP_EX_INVALID);
+  FP_HANDLE_EXCEPTIONS;
+
+  return r < 0;
+}
diff --git a/gcc/config/c6x/ltf.c b/gcc/config/c6x/ltf.c
new file mode 100644 (file)
index 0000000..7ffe9f8
--- /dev/null
@@ -0,0 +1,47 @@
+/* Software floating-point emulation.
+   Return 1 iff a < b, 0 otherwise.
+   Copyright (C) 1997,1999,2006,2007,2011 Free Software Foundation, Inc.
+   Contributed by Richard Henderson (rth@cygnus.com) and
+                 Jakub Jelinek (jj@ultra.linux.cz).
+
+   This file is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file into
+   combinations with other programs, and to distribute those
+   combinations without any restriction coming from the use of this
+   file.  (The Lesser General Public License restrictions do apply in
+   other respects; for example, they cover modification of the file,
+   and distribution when not linked into a combine executable.)
+
+   This file 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with GCC; see the file COPYING.LIB.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "config/soft-fp/soft-fp.h"
+#include "config/soft-fp/single.h"
+
+CMPtype __c6xabi_ltf(SFtype a, SFtype b)
+{
+  FP_DECL_EX;
+  FP_DECL_S(A); FP_DECL_S(B);
+  CMPtype r;
+
+  FP_UNPACK_RAW_S(A, a);
+  FP_UNPACK_RAW_S(B, b);
+  FP_CMP_S(r, A, B, 2);
+  if (r == 2 && (FP_ISSIGNAN_S(A) || FP_ISSIGNAN_S(B)))
+    FP_SET_EXCEPTION(FP_EX_INVALID);
+  FP_HANDLE_EXCEPTIONS;
+
+  return r < 0;
+}
diff --git a/gcc/config/c6x/predicates.md b/gcc/config/c6x/predicates.md
new file mode 100644 (file)
index 0000000..c4ccf54
--- /dev/null
@@ -0,0 +1,226 @@
+/* Predicates for TI C6X
+   Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+   Contributed by Andrew Jenner <andrew@codesourcery.com>
+   Contributed by Bernd Schmidt <bernds@codesourcery.com>
+
+   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/>.  */
+
+(define_predicate "reg_or_const_int_operand"
+  (ior (match_operand 0 "register_operand")
+       (match_operand 0 "const_int_operand")))
+
+(define_predicate "const_vector_operand"
+  (match_code "const_vector"))
+
+(define_predicate "scst5_operand"
+  (and (match_operand 0 "const_int_operand")
+       (match_test "satisfies_constraint_Is5 (op)")))
+
+(define_predicate "reg_or_ucst4_operand"
+  (ior (match_operand 0 "register_operand")
+       (and (match_operand 0 "const_int_operand")
+           (match_test "satisfies_constraint_Iu4 (op)"))))
+
+(define_predicate "reg_or_scst5_operand"
+  (ior (match_operand 0 "register_operand")
+       (match_operand 0 "scst5_operand")))
+
+(define_predicate "reg_or_ucst5_operand"
+  (ior (match_operand 0 "register_operand")
+       (and (match_operand 0 "const_int_operand")
+           (match_test "satisfies_constraint_Iu5 (op)"))))
+
+(define_predicate "addsi_operand"
+  (ior (match_operand 0 "register_operand")
+       (and (match_operand 0 "const_int_operand")
+           (match_test "satisfies_constraint_IsB (op)"))))
+
+(define_predicate "andsi_operand"
+  (ior (match_operand 0 "reg_or_scst5_operand")
+       (and (match_operand 0 "const_int_operand")
+           (match_test "satisfies_constraint_Jc (op)"))))
+
+(define_predicate "iorsi_operand"
+  (ior (match_operand 0 "reg_or_scst5_operand")
+       (and (match_operand 0 "const_int_operand")
+           (match_test "satisfies_constraint_Js (op)"))))
+
+(define_predicate "insv_operand"
+  (and (match_operand 0 "const_int_operand")
+       (match_test "INTVAL (op) == 0 || INTVAL (op) == -1")))
+
+(define_predicate "c6x_jump_operand"
+  (match_code "label_ref,symbol_ref,reg"))
+
+(define_predicate "c6x_call_operand"
+  (ior (match_code "symbol_ref,reg")
+       (and (match_code "subreg")
+            (match_test "GET_CODE (XEXP (op, 0)) == REG")))
+{
+  /* The linker transforms jumps to undefined weak symbols in a way that
+     is incompatible with our code generation.  */
+  return (GET_CODE (op) != SYMBOL_REF
+         || (!SYMBOL_REF_WEAK (op)
+             && !c6x_long_call_p (op)));
+})
+
+;; Returns 1 if OP is a symbolic operand, i.e. a symbol_ref or a label_ref,
+;; possibly with an offset.
+(define_predicate "symbolic_operand"
+  (ior (match_code "symbol_ref,label_ref")
+       (and (match_code "const")
+           (match_test "GET_CODE (XEXP (op,0)) == PLUS
+                        && (GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
+                            || GET_CODE (XEXP (XEXP (op, 0), 0)) == LABEL_REF)
+                        && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT"))))
+
+(define_predicate "const_int_or_symbolic_operand"
+  (ior (match_operand 0 "symbolic_operand")
+       (match_operand 0 "const_int_operand")))
+
+;; Return nonzero iff OP is one of the integer constants 2, 4 or 8.
+(define_predicate "adda_scale_operand"
+  (and (match_code "const_int")
+       (match_test "INTVAL (op) == 2 || INTVAL (op) == 4
+                   || ((TARGET_INSNS_64 || TARGET_INSNS_67)
+                       && INTVAL (op) == 8)")))
+
+;; Return nonzero iff OP is one of the integer constants 2 or 4.
+(define_predicate "suba_scale_operand"
+  (and (match_code "const_int")
+       (match_test "INTVAL (op) == 2 || INTVAL (op) == 4")))
+
+;; True if this operator is valid for predication.
+(define_predicate "predicate_operator"
+  (match_code "eq,ne"))
+
+(define_predicate "c6x_comparison_operator"
+  (match_code "eq,ltu,gtu,lt,gt"))
+
+(define_predicate "non_c6x_comparison_operator"
+  (match_code "ne,leu,geu,le,ge"))
+
+;; FP Comparisons handled by c6x_expand_compare.
+(define_predicate "c6x_fp_comparison_operator"
+  (ior (match_code "eq,lt,gt,le,ge")
+       (and (match_test "TARGET_FP")
+           (match_code "ltgt,uneq,unlt,ungt,unle,unge,ordered,unordered"))))
+
+(define_predicate "c6x_any_comparison_operand"
+  (match_code "eq,lt,gt,le,ge,ltu,gtu")
+{
+  rtx op0 = XEXP (op, 0);
+  rtx op1 = XEXP (op, 1);
+  if (ltugtu_operator (op, SImode)
+      && register_operand (op0, SImode)
+      && ((TARGET_INSNS_64 && reg_or_ucst5_operand (op1, SImode))
+         || (!TARGET_INSNS_64 && reg_or_ucst4_operand (op1, SImode))))
+    return true;
+  if (eqltgt_operator (op, SImode)
+      && register_operand (op0, SImode)
+      && reg_or_scst5_operand (op1, SImode))
+    return true;
+  if (!TARGET_FP)
+    return false;
+  if (!eqltgt_operator (op, SFmode) && !eqltgt_operator (op, DFmode))
+    return false;
+  if (register_operand (op0, GET_MODE (op))
+      && register_operand (op1, GET_MODE (op)))
+    return true;
+  return false;
+})
+
+(define_predicate "ltugtu_operator"
+  (match_code "ltu,gtu"))
+
+(define_predicate "eqltgt_operator"
+  (match_code "eq,lt,gt"))
+
+(define_predicate "eqne_operator"
+  (match_code "eq,ne"))
+
+(define_predicate "predicate_register"
+  (and (match_code "reg")
+       (ior (match_test "REGNO_REG_CLASS (REGNO (op)) == PREDICATE_A_REGS")
+           (match_test "REGNO_REG_CLASS (REGNO (op)) == PREDICATE_B_REGS"))))
+
+;; Allow const_ints for things like the real_mult patterns.
+(define_predicate "a_register"
+  (ior (and (match_code "reg")
+           (match_test "A_REGNO_P (REGNO (op))"))
+       (and (match_code "const_int")
+           (match_test "A_REGNO_P (INTVAL (op))"))))
+
+(define_predicate "b_register"
+  (ior (and (match_code "reg")
+           (match_test "B_REGNO_P (REGNO (op))"))
+       (and (match_code "const_int")
+           (match_test "B_REGNO_P (INTVAL (op))"))))
+
+(define_predicate "pic_register_operand"
+  (and (match_code "reg")
+       (match_test "op == pic_offset_table_rtx")))
+
+;; True if OP refers to a symbol in the sdata section.
+(define_predicate "sdata_symbolic_operand"
+  (match_code "symbol_ref,const")
+{
+  HOST_WIDE_INT offset = 0, size = 0;
+  tree t;
+
+  switch (GET_CODE (op))
+    {
+    case CONST:
+      op = XEXP (op, 0);
+      if (GET_CODE (op) != PLUS
+         || GET_CODE (XEXP (op, 0)) != SYMBOL_REF
+         || GET_CODE (XEXP (op, 1)) != CONST_INT)
+       return false;
+      offset = INTVAL (XEXP (op, 1));
+      op = XEXP (op, 0);
+      /* FALLTHRU */
+
+    case SYMBOL_REF:
+      /* For shared libraries, only allow symbols we know are local.
+         For executables, the linker knows to create copy relocs if
+        necessary so we can use DP-relative addressing for all small
+        objects.  */
+      if ((c6x_initial_flag_pic && !SYMBOL_REF_LOCAL_P (op))
+         || !SYMBOL_REF_SMALL_P (op))
+       return false;
+
+     /* Note that in addition to DECLs, we can get various forms
+       of constants here.  */
+      t = SYMBOL_REF_DECL (op);
+      if (DECL_P (t))
+        t = DECL_SIZE_UNIT (t);
+      else
+       t = TYPE_SIZE_UNIT (TREE_TYPE (t));
+      if (t && host_integerp (t, 0))
+       {
+         size = tree_low_cst (t, 0);
+         if (size < 0)
+           size = 0;
+       }
+
+      /* Don't allow addressing outside the object.  */
+      return (offset >= 0 && offset <= size);
+
+    default:
+      gcc_unreachable ();
+    }
+})
diff --git a/gcc/config/c6x/sfp-machine.h b/gcc/config/c6x/sfp-machine.h
new file mode 100644 (file)
index 0000000..2c90e58
--- /dev/null
@@ -0,0 +1,120 @@
+/* Soft-FP definitions for TI C6X.
+   Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+
+   This files is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file into
+   combinations with other programs, and to distribute those
+   combinations without any restriction coming from the use of this
+   file.  (The Lesser General Public License restrictions do apply in
+   other respects; for example, they cover modification of the file,
+   and distribution when not linked into a combine executable.)
+
+   This file 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with GCC; see the file COPYING.LIB.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#define _FP_W_TYPE_SIZE                32
+#define _FP_W_TYPE             unsigned long
+#define _FP_WS_TYPE            signed long
+#define _FP_I_TYPE             long
+
+#define _FP_MUL_MEAT_S(R,X,Y)                          \
+  _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_D(R,X,Y)                          \
+  _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_Q(R,X,Y)                          \
+  _FP_MUL_MEAT_4_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm)
+
+#define _FP_DIV_MEAT_S(R,X,Y)  _FP_DIV_MEAT_1_loop(S,R,X,Y)
+#define _FP_DIV_MEAT_D(R,X,Y)  _FP_DIV_MEAT_2_udiv(D,R,X,Y)
+#define _FP_DIV_MEAT_Q(R,X,Y)  _FP_DIV_MEAT_4_udiv(Q,R,X,Y)
+
+#define _FP_NANFRAC_H          ((_FP_QNANBIT_H << 1) - 1)
+#define _FP_NANFRAC_S          ((_FP_QNANBIT_S << 1) - 1)
+#define _FP_NANFRAC_D          ((_FP_QNANBIT_D << 1) - 1), -1
+#define _FP_NANFRAC_Q          ((_FP_QNANBIT_Q << 1) - 1), -1, -1, -1
+#define _FP_NANSIGN_H          0
+#define _FP_NANSIGN_S          0
+#define _FP_NANSIGN_D          0
+#define _FP_NANSIGN_Q          0
+
+#define _FP_KEEPNANFRACP 1
+
+/* Someone please check this.  */
+#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP)                     \
+  do {                                                         \
+    if ((_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs)         \
+       && !(_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs))     \
+      {                                                                \
+       R##_s = Y##_s;                                          \
+       _FP_FRAC_COPY_##wc(R,Y);                                \
+      }                                                                \
+    else                                                       \
+      {                                                                \
+       R##_s = X##_s;                                          \
+       _FP_FRAC_COPY_##wc(R,X);                                \
+      }                                                                \
+    R##_c = FP_CLS_NAN;                                                \
+  } while (0)
+
+#define        __LITTLE_ENDIAN 1234
+#define        __BIG_ENDIAN    4321
+
+#if defined _BIG_ENDIAN
+# define __BYTE_ORDER __BIG_ENDIAN
+#else
+# define __BYTE_ORDER __LITTLE_ENDIAN
+#endif
+
+
+/* Define ALIASNAME as a strong alias for NAME.  */
+# define strong_alias(name, aliasname) _strong_alias(name, aliasname)
+# define _strong_alias(name, aliasname) \
+  extern __typeof (name) aliasname __attribute__ ((alias (#name)));
+
+/* Rename helper functions to the names specified in the C6000 ELF ABI.  */
+#define __fixdfsi     __c6xabi_fixdi
+#define __fixsfsi     __c6xabi_fixfi
+#define __floatsidf   __c6xabi_fltid
+#define __floatunsidf __c6xabi_fltud
+#define __floatsisf   __c6xabi_fltif
+#define __floatunsisf __c6xabi_fltuf
+#define __truncdfsf2  __c6xabi_cvtdf
+#define __extendsfdf2 __c6xabi_cvtfd
+#define __adddf3      __c6xabi_addd
+#define __subdf3      __c6xabi_subd
+#define __muldf3      __c6xabi_mpyd
+#define __divdf3      __c6xabi_divd
+#define __negdf2      __c6xabi_negd
+#define __absdf2      __c6xabi_absd
+#define __addsf3      __c6xabi_addf
+#define __subsf3      __c6xabi_subf
+#define __mulsf3      __c6xabi_mpyf
+#define __divsf3      __c6xabi_divf
+#define __negsf2      __c6xabi_negf
+#define __abssf2      __c6xabi_absf
+#define __lesf2       __c6xabi_cmpf
+#define __ledf2       __c6xabi_cmpd
+#define __ltsf2       __gnu_ltsf2
+#define __ltdf2       __gnu_ltdf2
+#define __gesf2       __gnu_gesf2
+#define __gedf2       __gnu_gedf2
+#define __gtsf2       __gnu_gtsf2
+#define __gtdf2       __gnu_gtdf2
+#define __eqsf2       __gnu_eqsf2
+#define __eqdf2       __gnu_eqdf2
+#define __nesf2       __c6xabi_neqf
+#define __nedf2       __c6xabi_neqd
+#define __unordsf2    __c6xabi_unordf
+#define __unorddf2    __c6xabi_unordd
diff --git a/gcc/config/c6x/sync.md b/gcc/config/c6x/sync.md
new file mode 100644 (file)
index 0000000..05ab02a
--- /dev/null
@@ -0,0 +1,270 @@
+;; GCC machine description for C6X synchronization instructions.
+;; Copyright (C) 2011 Free Software Foundation, Inc.
+;;
+;; 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/>.
+
+;; C64X+ has atomic instructions, but they are not atomic on all
+;; devices and have other problems.  We use normal loads and stores,
+;; and place them in overlapping branch shadows to ensure interrupts
+;; are disabled during the sequence, which guarantees atomicity on all
+;; single-core systems.
+
+(define_code_iterator FETCHOP [plus minus ior xor and])
+(define_code_attr fetchop_name
+  [(plus "add") (minus "sub") (ior "ior") (xor "xor") (and "and")])
+(define_code_attr fetchop_pred
+  [(plus "reg_or_scst5_operand") (minus "register_operand")
+   (ior "reg_or_scst5_operand") (xor "reg_or_scst5_operand")
+   (and "reg_or_scst5_operand")])
+(define_code_attr fetchop_constr
+  [(plus "bIs5") (minus "b") (ior "bIs5") (xor "bIs5") (and "bIs5")])
+(define_code_attr fetchop_opcode
+  [(plus "add") (minus "sub") (ior "or") (xor "xor") (and "and")])
+(define_code_attr fetchop_inops02
+  [(plus "%2, %0") (minus "%0, %2") (ior "%2, %0") (xor "%2, %0")
+   (and "%2, %0")])
+(define_code_attr fetchop_inops21
+  [(plus "%1, %2") (minus "%2, %1") (ior "%1, %2") (xor "%1, %2")
+   (and "%1, %2")])
+
+(define_expand "sync_compare_and_swapsi"
+  [(parallel
+     [(set (match_operand:SI 0 "register_operand" "")
+          (match_operand:SI 1 "memory_operand" ""))
+      (set (match_dup 1)
+          (unspec_volatile:SI
+            [(match_operand:SI 2 "register_operand" "")
+             (match_operand:SI 3 "register_operand" "")]
+            UNSPECV_CAS))
+      (clobber (match_scratch:SI 4 ""))])]
+  ""
+{
+})
+
+(define_expand "sync_<fetchop_name>si"
+  [(parallel
+    [(set (match_operand:SI 0 "memory_operand" "")
+         (unspec:SI
+          [(FETCHOP:SI (match_dup 0)
+                       (match_operand:SI 1 "<fetchop_pred>" ""))]
+          UNSPEC_ATOMIC))
+     (clobber (match_scratch:SI 2 ""))])]
+  ""
+{
+})
+
+(define_expand "sync_old_<fetchop_name>si"
+  [(parallel
+    [(set (match_operand:SI 0 "register_operand" "")
+         (match_operand:SI 1 "memory_operand" ""))
+     (set (match_dup 1)
+         (unspec:SI
+          [(FETCHOP:SI (match_dup 1)
+                       (match_operand:SI 2 "<fetchop_pred>" ""))]
+          UNSPEC_ATOMIC))
+     (clobber (match_scratch:SI 3 ""))])]
+  ""
+{
+})
+
+(define_expand "sync_new_<fetchop_name>si"
+  [(parallel
+    [(set (match_operand:SI 0 "register_operand" "")
+         (FETCHOP:SI (match_operand:SI 1 "memory_operand" "")
+                     (match_operand:SI 2 "<fetchop_pred>" "")))
+     (set (match_dup 1)
+         (unspec:SI [(FETCHOP:SI (match_dup 1) (match_dup 2))]
+                    UNSPEC_ATOMIC))
+     (clobber (match_scratch:SI 3 ""))])]
+  ""
+{
+})
+
+(define_expand "sync_nandsi"
+  [(parallel
+    [(set (match_operand:SI 0 "memory_operand" "")
+         (unspec:SI
+          [(not:SI (and:SI (match_dup 0)
+                           (match_operand:SI 1 "reg_or_scst5_operand" "")))]
+          UNSPEC_ATOMIC))
+     (clobber (match_scratch:SI 2 ""))])]
+  ""
+{
+})
+
+(define_expand "sync_old_nandsi"
+  [(parallel
+    [(set (match_operand:SI 0 "register_operand" "")
+         (match_operand:SI 1 "memory_operand" ""))
+     (set (match_dup 1)
+         (unspec:SI
+          [(not:SI (and:SI (match_dup 1)
+                   (match_operand:SI 2 "reg_or_scst5_operand" "")))]
+          UNSPEC_ATOMIC))
+     (clobber (match_scratch:SI 3 ""))])]
+  ""
+{
+})
+
+(define_expand "sync_new_nandsi"
+  [(parallel
+    [(set (match_operand:SI 0 "register_operand" "")
+         (not:SI (and:SI (match_operand:SI 1 "memory_operand" "")
+                         (match_operand:SI 2 "reg_or_scst5_operand" ""))))
+     (set (match_dup 1)
+         (unspec:SI [(not:SI (and:SI (match_dup 1) (match_dup 2)))]
+                    UNSPEC_ATOMIC))
+     (clobber (match_scratch:SI 3 ""))])]
+  ""
+{
+})
+
+(define_insn "*sync_compare_and_swapsi"
+  [(set (match_operand:SI 0 "register_operand" "=&b")
+       (match_operand:SI 1 "memory_operand" "+m"))
+   (set (match_dup 1)
+       (unspec_volatile:SI
+         [(match_operand:SI 2 "register_operand" "B")
+          (match_operand:SI 3 "register_operand" "b")]
+         UNSPECV_CAS))
+   (clobber (match_scratch:SI 4 "=&B"))]
+  ""
+  "0: b .s2 1f ; 0\n\\
+   || ldw .d%U1t%U0 %1, %0\n\\
+   nop 4\n\\
+|| b .s2 2f ; 1\n\\
+   cmpeq .l2 %0, %2, %2 ; 5\n\\
+1: [%2] stw .d%U1t%U3 %3, %1 ; 6\n\\
+2:"
+  [(set_attr "type" "atomic")])
+
+(define_insn "sync_<fetchop_name>si_insn"
+  [(set (match_operand:SI 0 "memory_operand" "+m")
+       (unspec:SI
+         [(FETCHOP:SI (match_dup 0)
+            (match_operand:SI 1 "<fetchop_pred>" "<fetchop_constr>"))]
+         UNSPEC_ATOMIC))
+   (clobber (match_scratch:SI 2 "=&B"))]
+  ""
+  "0: b .s2 1f ; 0\n\\
+|| ldw .d%U0t%U2 %0, %2\n\\
+   nop 4\n\\
+|| b .s2 2f ; 1\n\\
+   <fetchop_opcode> .l2 <fetchop_inops21>, %2 ; 5\n\\
+1: stw .d%U0t%U2 %2, %0 ; 6\n\\
+2:"
+  [(set_attr "type" "atomic")])
+
+(define_insn "sync_old_<fetchop_name>si_insn"
+  [(set (match_operand:SI 0 "register_operand" "=&b")
+       (match_operand:SI 1 "memory_operand" "+m"))
+   (set (match_dup 1)
+       (unspec:SI
+         [(FETCHOP:SI (match_dup 1)
+            (match_operand:SI 2 "<fetchop_pred>" "<fetchop_constr>"))]
+         UNSPEC_ATOMIC))
+   (clobber (match_scratch:SI 3 "=&B"))]
+  ""
+  "0: b .s2 1f ; 0\n\\
+|| ldw .d%U1t%U0 %1, %0\n\\
+   nop 4\n\\
+|| b .s2 2f ; 1\n\\
+   <fetchop_opcode> .l2 <fetchop_inops02>, %3 ; 5\n\\
+1: stw .d%U1t%U3 %3, %1 ; 6\n\\
+2:"
+  [(set_attr "type" "atomic")])
+
+(define_insn "sync_new_<fetchop_name>si_insn"
+  [(set (match_operand:SI 0 "register_operand" "=&b")
+       (FETCHOP:SI (match_operand:SI 1 "memory_operand" "+m")
+          (match_operand:SI 2 "<fetchop_pred>" "<fetchop_constr>")))
+   (set (match_dup 1)
+       (unspec:SI
+         [(FETCHOP:SI (match_dup 1)
+                      (match_dup 2))]
+         UNSPEC_ATOMIC))
+   (clobber (match_scratch:SI 3 "=&B"))]
+  ""
+  "0: b .s2 1f ; 0\n\\
+|| ldw .d%U1t%U0 %1, %0\n\\
+   nop 4\n\\
+|| b .s2 2f ; 1\n\\
+   <fetchop_opcode> .l2 <fetchop_inops02>, %0 ; 5\n\\
+1: stw .d%U1t%U0 %0, %1 ; 6\n\\
+2:"
+  [(set_attr "type" "atomic")])
+
+(define_insn "sync_nandsi_insn"
+  [(set (match_operand:SI 0 "memory_operand" "+m")
+       (unspec:SI
+         [(not:SI (and:SI (match_dup 0)
+                          (match_operand:SI 1 "reg_or_scst5_operand" "bIs5")))]
+         UNSPEC_ATOMIC))
+   (clobber (match_scratch:SI 2 "=&B"))]
+  ""
+  "0: b .s2 1f ; 0\n\\
+|| ldw .d%U0t%U2 %0, %2\n\\
+   nop 1\n\\
+   nop 3\n\\
+|| b .s2 2f ; 2\n\\
+   and .l2 %1, %2, %2 ; 5\n\\
+1: not .l2 %2, %2 ; 6\n\\
+   stw .d%U0t%U2 %2, %0 ; 7\n\\
+2:"
+  [(set_attr "type" "atomic")])
+
+(define_insn "sync_old_nandsi_insn"
+  [(set (match_operand:SI 0 "register_operand" "=&b")
+       (match_operand:SI 1 "memory_operand" "+m"))
+   (set (match_dup 1)
+       (unspec:SI
+         [(not:SI (and:SI (match_dup 1)
+                          (match_operand:SI 2 "reg_or_scst5_operand" "bIs5")))]
+         UNSPEC_ATOMIC))
+   (clobber (match_scratch:SI 3 "=&B"))]
+  ""
+  "0: b .s2 1f ; 0\n\\
+|| ldw .d%U1t%U0 %1, %0\n\\
+   nop 1\n\\
+   nop 3\n\\
+|| b .s2 2f ; 2\n\\
+   and .l2 %2, %0, %3 ; 5\n\\
+1: not .l2 %3, %3 ; 6\n\\
+   stw .d%U1t%U3 %3, %1 ; 7\n\\
+2:"
+  [(set_attr "type" "atomic")])
+
+(define_insn "sync_new_nandsi_insn"
+  [(set (match_operand:SI 0 "register_operand" "=&b")
+       (not:SI (and:SI (match_operand:SI 1 "memory_operand" "+m")
+                       (match_operand:SI 2 "reg_or_scst5_operand" "bIs5"))))
+   (set (match_dup 1)
+       (unspec:SI
+         [(not:SI (and:SI (match_dup 1) (match_dup 2)))]
+         UNSPEC_ATOMIC))
+   (clobber (match_scratch:SI 3 "=&B"))]
+  ""
+  "0: b .s2 1f ; 0\n\\
+|| ldw .d%U1t%U0 %1, %0\n\\
+   nop 1\n\\
+   nop 3\n\\
+|| b .s2 2f ; 2\n\\
+   and .l2 %2, %0, %0 ; 5\n\\
+1: not .l2 %0, %0 ; 6\n\\
+   stw .d%U1t%U0 %0, %1 ; 7\n\\
+2:"
+  [(set_attr "type" "atomic")])
diff --git a/gcc/config/c6x/t-c6x b/gcc/config/c6x/t-c6x
new file mode 100644 (file)
index 0000000..6a7ced7
--- /dev/null
@@ -0,0 +1,43 @@
+# Target Makefile Fragment for TI C6X.
+# Copyright (C) 2010, 2011
+# Free Software Foundation, Inc.
+# 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/>.
+
+MD_INCLUDES=   $(srcdir)/config/c6x/constraints.md \
+               $(srcdir)/config/c6x/predicates.md \
+               $(srcdir)/config/c6x/c6x-mult.md \
+               $(srcdir)/config/c6x/c6x-sched.md
+
+s-config s-conditions s-flags s-codes s-constants s-emit s-recog s-preds \
+       s-opinit s-extract s-peep s-attr s-attrtab s-output: $(MD_INCLUDES)
+
+$(srcdir)/config/c6x/c6x-sched.md: $(srcdir)/config/c6x/gensched.sh \
+  $(srcdir)/config/c6x/c6x-sched.md.in
+       $(SHELL) $(srcdir)/config/c6x/gensched.sh \
+       $(srcdir)/config/c6x/c6x-sched.md.in > $@
+
+$(srcdir)/config/c6x/c6x-mult.md: $(srcdir)/config/c6x/genmult.sh \
+  $(srcdir)/config/c6x/c6x-mult.md.in
+       $(SHELL) $(srcdir)/config/c6x/genmult.sh \
+       $(srcdir)/config/c6x/c6x-mult.md.in > $@
+
+$(srcdir)/config/c6x/c6x-tables.opt: $(srcdir)/config/c6x/genopt.sh \
+  $(srcdir)/config/c6x/c6x-isas.def
+       $(SHELL) $(srcdir)/config/c6x/genopt.sh $(srcdir)/config/c6x > \
+               $(srcdir)/config/c6x/c6x-tables.opt
diff --git a/gcc/config/c6x/t-c6x-elf b/gcc/config/c6x/t-c6x-elf
new file mode 100644 (file)
index 0000000..ed28642
--- /dev/null
@@ -0,0 +1,66 @@
+# Target Makefile Fragment for TI C6X using ELF.
+# Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+# 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/>.
+
+LIB1ASMSRC = c6x/lib1funcs.asm
+LIB1ASMFUNCS = _divsi3 _udivsi3 _umodsi3 _modsi3 _udivmodsi4 _divmodsi4
+LIB1ASMFUNCS += _strasgi _strasgi_64plus _clzsi2 _clzdi2 _clz
+LIB1ASMFUNCS += _push_rts _pop_rts _call_stub
+
+LIB2FUNCS_EXCLUDE = _cmpdi2 _ucmpdi2 _gcc_bcmp _eprintf _clzsi _clzdi
+
+LIB2FUNCS_EXTRA = $(srcdir)/config/c6x/gef.c \
+                  $(srcdir)/config/c6x/gtf.c \
+                  $(srcdir)/config/c6x/lef.c \
+                  $(srcdir)/config/c6x/ltf.c \
+                  $(srcdir)/config/c6x/eqf.c \
+                  $(srcdir)/config/c6x/ged.c \
+                  $(srcdir)/config/c6x/gtd.c \
+                  $(srcdir)/config/c6x/led.c \
+                  $(srcdir)/config/c6x/ltd.c \
+                  $(srcdir)/config/c6x/eqd.c
+
+# Use this variant for fully testing all CPU types
+#MULTILIB_OPTIONS     = mbig-endian march=c674x/march=c64x/march=c67x/march=c67x+/march=c62x
+#MULTILIB_DIRNAMES    = be c674x c64x c67x c67x+ c62x
+
+MULTILIB_OPTIONS     = mbig-endian march=c674x
+MULTILIB_DIRNAMES    = be c674x
+MULTILIB_EXCEPTIONS  =
+MULTILIB_MATCHES     =
+
+# Assemble startup files.
+$(T)crti.o: $(srcdir)/config/c6x/crti.s $(GCC_PASSES)
+       $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \
+       -c -o $(T)crti.o $(CRTSTUFF_T_CFLAGS) -x assembler-with-cpp \
+       $(srcdir)/config/c6x/crti.s
+
+$(T)crtn.o: $(srcdir)/config/c6x/crtn.s $(GCC_PASSES)
+       $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \
+       -c -o $(T)crtn.o $(CRTSTUFF_T_CFLAGS) -x assembler-with-cpp \
+       $(srcdir)/config/c6x/crtn.s
+
+EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crtbeginS.o crtendS.o crti.o crtn.o
+
+# Avoid failures when the user's GOT becomes too large.
+CRTSTUFF_T_CFLAGS = -msdata=none
+CRTSTUFF_T_CFLAGS_S = -msdata=none
+TARGET_LIBGCC2_CFLAGS = -msdata=none
+
+SHLIB_MAPFILES += $(srcdir)/config/c6x/libgcc-c6xeabi.ver
diff --git a/gcc/config/c6x/t-c6x-softfp b/gcc/config/c6x/t-c6x-softfp
new file mode 100644 (file)
index 0000000..5df90eb
--- /dev/null
@@ -0,0 +1,9 @@
+softfp_float_modes := sf df
+softfp_int_modes := si di
+softfp_extensions := sfdf
+softfp_truncations := dfsf
+softfp_machine_header := c6x/sfp-machine.h
+softfp_exclude_libgcc2 := y
+
+# softfp seems to be missing a whole bunch of prototypes.
+TARGET_LIBGCC2_CFLAGS += -Wno-missing-prototypes
diff --git a/gcc/config/c6x/t-c6x-uclinux b/gcc/config/c6x/t-c6x-uclinux
new file mode 100644 (file)
index 0000000..fdc447a
--- /dev/null
@@ -0,0 +1,7 @@
+MULTILIB_OSDIRNAMES    = march.c674x=!c674x
+MULTILIB_OSDIRNAMES   += mbig-endian=!be
+MULTILIB_OSDIRNAMES   += mbig-endian/march.c674x=!be/c674x
+
+CRTSTUFF_T_CFLAGS = -fPIC -msdata=none
+CRTSTUFF_T_CFLAGS_S = -fPIC -msdata=none
+TARGET_LIBGCC2_CFLAGS = -fPIC -msdata=none
diff --git a/gcc/config/c6x/uclinux-elf.h b/gcc/config/c6x/uclinux-elf.h
new file mode 100644 (file)
index 0000000..f770e7e
--- /dev/null
@@ -0,0 +1,64 @@
+/* Definitions for TI C6X running ucLinux using ELF
+   Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+   Contributed by Andrew Jenner <andrew@codesourcery.com>
+   Contributed by Bernd Schmidt <bernds@codesourcery.com>
+
+   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/>.  */
+
+#undef TARGET_OS_CPP_BUILTINS
+#define TARGET_OS_CPP_BUILTINS()               \
+  do                                           \
+    {                                          \
+      builtin_define ("__uClinux__");          \
+      builtin_define_std ("linux");             \
+      builtin_define_std ("unix");              \
+      builtin_assert ("system=linux");          \
+      builtin_assert ("system=unix");           \
+      builtin_assert ("system=posix");          \
+    }                                          \
+  while (false)
+
+#undef  STARTFILE_SPEC
+#define STARTFILE_SPEC \
+  "%{!shared:crt1%O%s} crti%O%s %{shared|pie:crtbeginS.o%s;:crtbegin.o%s}"
+
+#define UCLIBC_DYNAMIC_LINKER "/lib/ld-uClibc.so.0"
+
+#undef LINK_SPEC
+#define LINK_SPEC ENDIAN_LINK_SPEC \
+  "%{shared} %{fpie|fPIE:-pie} \
+  %{!shared: %{!static: \
+   %{rdynamic:-export-dynamic} \
+   %{!dynamic-linker:-dynamic-linker " UCLIBC_DYNAMIC_LINKER "}} \
+   %{static}}"
+
+#undef DRIVER_SELF_SPECS
+#define DRIVER_SELF_SPECS "%{!mno-dsbt:-mdsbt}"
+
+/* Clear the instruction cache from `beg' to `end'.  This makes an
+   inline system call to SYS_cacheflush.  */
+#undef CLEAR_INSN_CACHE
+#define CLEAR_INSN_CACHE(BEG, END)                                     \
+{                                                                      \
+  register unsigned long _beg __asm ("A4") = (unsigned long) (BEG);    \
+  register unsigned long _end __asm ("B4") = (unsigned long) (END);    \
+  register unsigned long _scno __asm ("B0") = 244;                     \
+  __asm __volatile ("swe               ; sys_cache_sync"               \
+                   : "=a" (_beg)                                       \
+                   : "0" (_beg), "b" (_end), "b" (_scno));     \
+}
+
index 4096879a1c7168c925e0def8cc7edc4804e4d6c1..939f6dea1dd80ff4a7df08c67c2bfc1e5092424b 100644 (file)
@@ -806,8 +806,8 @@ Tobias Schl@"uter for work on GNU Fortran.
 
 @item
 Bernd Schmidt for various code generation improvements and major
-work in the reload pass as well a serving as release manager for
-GCC 2.95.3.
+work in the reload pass, serving as release manager for
+GCC 2.95.3, and work on the Blackfin and C6X ports.
 
 @item
 Peter Schmid for constant testing of libstdc++---especially application
index e97e789a752efd3d1aa963d8b5a2f3480db8a6b3..7cbd68ea9060195de621a2964d1cf379320caa88 100644 (file)
@@ -7975,6 +7975,7 @@ instructions, but allow the compiler to schedule those calls.
 * RX Built-in Functions::
 * SPARC VIS Built-in Functions::
 * SPU Built-in Functions::
+* TI C6X Built-in Functions::
 @end menu
 
 @node Alpha Built-in Functions
@@ -12793,6 +12794,45 @@ specification is supported. Internally, GCC uses built-in functions to
 implement the required functionality, but these are not supported and
 are subject to change without notice.
 
+@node TI C6X Built-in Functions
+@subsection TI C6X Built-in Functions
+
+GCC provides intrinsics to access certain instructions of the TI C6X
+processors.  These intrinsics, listed below, are available after
+inclusion of the @code{c6x_intrinsics.h} header file.  They map directly
+to C6X instructions.
+
+@smallexample
+
+int _sadd (int, int)
+int _ssub (int, int)
+int _sadd2 (int, int)
+int _ssub2 (int, int)
+long long _mpy2 (int, int)
+long long _smpy2 (int, int)
+int _add4 (int, int)
+int _sub4 (int, int)
+int _saddu4 (int, int)
+
+int _smpy (int, int)
+int _smpyh (int, int)
+int _smpyhl (int, int)
+int _smpylh (int, int)
+
+int _sshl (int, int)
+int _subc (int, int)
+
+int _avg2 (int, int)
+int _avgu4 (int, int)
+
+int _clrr (int, int)
+int _extr (int, int)
+int _extru (int, int)
+int _abs (int)
+int _abs2 (int)
+
+@end smallexample
+
 @node Target Format Checks
 @section Format Checks Specific to Particular Target Machines
 
index 9834728f838433418a6b9a5fa0f71587ed15ec18..811bf3d7ccd6f3b3278c710b9811d3cdf13b0505 100644 (file)
@@ -3071,6 +3071,8 @@ information are.
 @item
 @uref{#sparcv9-x-solaris2,,sparcv9-*-solaris2*}
 @item
+@uref{#c6x-x-x,,c6x-*-*}
+@item
 @uref{#x-x-vxworks,,*-*-vxworks*}
 @item
 @uref{#x86-64-x-x,,x86_64-*-*, amd64-*-*}
@@ -4379,6 +4381,13 @@ and @option{-xildoff} turns off the incremental linker.
 
 This is a synonym for @samp{sparc64-*-solaris2*}.
 
+@html
+<hr />
+@end html
+@heading @anchor{c6x-x-x}c6x-*-*
+
+The C6X family of processors. This port requires binutils-2.22 or newer.
+
 @html
 <hr />
 @end html
index 39c805b04d3f51bef1aa3259109b1a2cbbad5fa6..7541e3a92f3c49945b2bb600919fc8ea62ac18f4 100644 (file)
@@ -496,6 +496,10 @@ Objective-C and Objective-C++ Dialects}.
 -mfast-fp -minline-plt -mmulticore  -mcorea  -mcoreb  -msdram @gol
 -micplb}
 
+@emph{C6X Options}
+@gccoptlist{-mbig-endian  -mlittle-endian -march=@var{cpu} @gol
+-msim -msdata=@var{sdata-type}}
+
 @emph{CRIS Options}
 @gccoptlist{-mcpu=@var{cpu}  -march=@var{cpu}  -mtune=@var{cpu} @gol
 -mmax-stack-frame=@var{n}  -melinux-stacksize=@var{n} @gol
@@ -10091,6 +10095,7 @@ platform.
 * ARM Options::
 * AVR Options::
 * Blackfin Options::
+* C6X Options::
 * CRIS Options::
 * Darwin Options::
 * DEC Alpha Options::
@@ -10755,6 +10760,54 @@ anomaly workarounds.  For Linux targets, the default is to assume ICPLBs
 are enabled; for standalone applications the default is off.
 @end table
 
+@node C6X Options
+@subsection C6X Options
+@cindex C6X Options
+
+@table @gcctabopt
+@item -march=@var{name}
+@opindex march
+This specifies the name of the target architecture.  GCC uses this
+name to determine what kind of instructions it can emit when generating
+assembly code.  Permissible names are: @samp{c62x},
+@samp{c64x}, @samp{c64x+}, @samp{c67x}, @samp{c67x+}, @samp{c674x}.
+
+@item -mbig-endian
+@opindex mbig-endian
+Generate code for a big endian target.
+
+@item -mlittle-endian
+@opindex mlittle-endian
+Generate code for a little endian target.  This is the default.
+
+@item -msim
+@opindex msim
+Choose startup files and linker script suitable for the simulator.
+
+@item -msdata=default
+@opindex msdata=default
+Put small global and static data in the @samp{.neardata} section,
+which is pointed to by register @code{B14}.  Put small uninitialized
+global and static data in the @samp{.bss} section, which is adjacent
+to the @samp{.neardata} section.  Put small read-only data into the
+@samp{.rodata} section.  The corresponding sections used for large
+pieces of data are @samp{.fardata}, @samp{.far} and @samp{.const}.
+
+@item -msdata=all
+@opindex msdata=all
+Put all data, not just small objets, into the sections reserved for
+small data, and use addressing relative to the @code{B14} register to
+access them.
+
+@item -msdata=none
+@opindex msdata=none
+Make no use of the sections reserved for small data, and use absolute
+addresses to access all data.  Put all initialized global and static
+data in the @samp{.fardata} section, and all uninitialized data in the
+@samp{.far} section.  Put all constant data into the @samp{.const}
+section.
+@end table
+
 @node CRIS Options
 @subsection CRIS Options
 @cindex CRIS Options
index abe51f80727b9792f9fc89f59badd329798c8c55..23047ca45aa9fcc6406ed25195553d306cf980a0 100644 (file)
@@ -3304,6 +3304,89 @@ The constant 0.
 
 @end table
 
+@item TI C6X family---@file{config/c6x/constraints.md}
+@table @code
+@item a
+Register file A (A0--A31).
+
+@item b
+Register file B (B0--B31).
+
+@item A
+Predicate registers in register file A (A0--A2 on C64X and
+higher, A1 and A2 otherwise).
+
+@item B
+Predicate registers in register file B (B0--B2).
+
+@item C
+A call-used register in register file B (B0--B9, B16--B31).
+
+@item Da
+Register file A, excluding predicate registers (A3--A31,
+plus A0 if not C64X or higher).
+
+@item Db
+Register file B, excluding predicate registers (B3--B31).
+
+@item Iu4
+Integer constant in the range 0 @dots{} 15.
+
+@item Iu5
+Integer constant in the range 0 @dots{} 31.
+
+@item In5
+Integer constant in the range @minus{}31 @dots{} 0.
+
+@item Is5
+Integer constant in the range @minus{}16 @dots{} 15.
+
+@item I5x
+Integer constant that can be the operand of an ADDA or a SUBA insn.
+
+@item IuB
+Integer constant in the range 0 @dots{} 65535.
+
+@item IsB
+Integer constant in the range @minus{}32768 @dots{} 32767.
+
+@item IsC
+Integer constant in the range @math{-2^{20}} @dots{} @math{2^{20} - 1}.
+
+@item Jc
+Integer constant that is a valid mask for the clr instruction.
+
+@item Js
+Integer constant that is a valid mask for the set instruction.
+
+@item Q
+Memory location with A base register.
+
+@item R
+Memory location with B base register.
+
+@ifset INTERNALS
+@item S0
+On C64x+ targets, a GP-relative small data reference.
+
+@item S1
+Any kind of @code{SYMBOL_REF}, for use in a call address.
+
+@item Si
+Any kind of immediate operand, unless it matches the S0 constraint.
+
+@item T
+Memory location with B base register, but not using a long offset.
+
+@item W
+A memory operand with an address that can't be used in an unaligned access.
+
+@end ifset
+@item Z
+Register B14 (aka DP).
+
+@end table
+
 @item Xtensa---@file{config/xtensa/constraints.md}
 @table @code
 @item a
index cd4c40ff32ad5a526bfa1d2f1118bc61f7cccc28..82ced170887259a0bfbbe4fcaa6ecebee629e7ec 100644 (file)
@@ -1389,6 +1389,36 @@ UDItype __umulsidi3 (USItype, USItype);
   } while (0)
 #endif /* __vax__ */
 
+#ifdef _TMS320C6X
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  do                                                                   \
+    {                                                                  \
+      UDItype __ll;                                                    \
+      __asm__ ("addu .l1 %1, %2, %0"                                   \
+              : "=a" (__ll) : "a" (al), "a" (bl));                     \
+      (sl) = (USItype)__ll;                                            \
+      (sh) = ((USItype)(__ll >> 32)) + (ah) + (bh);                    \
+    }                                                                  \
+  while (0)
+
+#ifdef _TMS320C6400_PLUS
+#define __umulsidi3(u,v) ((UDItype)(USItype)u*(USItype)v)
+#define umul_ppmm(w1, w0, u, v)                                                \
+  do {                                                                 \
+    UDItype __x = (UDItype) (USItype) (u) * (USItype) (v);             \
+    (w1) = (USItype) (__x >> 32);                                      \
+    (w0) = (USItype) (__x);                                            \
+  } while (0)
+#endif  /* _TMS320C6400_PLUS */
+
+#define count_leading_zeros(count, x)  ((count) = __builtin_clz (x))
+#ifdef _TMS320C6400
+#define count_trailing_zeros(count, x) ((count) = __builtin_ctz (x))
+#endif
+#define UMUL_TIME 4
+#define UDIV_TIME 40
+#endif /* _TMS320C6X */
+
 #if defined (__xtensa__) && W_TYPE_SIZE == 32
 /* This code is not Xtensa-configuration-specific, so rely on the compiler
    to expand builtin functions depending on what configuration features
index 49fed6ef5c1fbebc78139e030380088fcd339e78..885724a4d8422abcca9d98d1a6cc0bb4fa0f82e6 100644 (file)
@@ -1,3 +1,8 @@
+2011-07-15  Bernd Schmidt  <bernds@codesourcery.com>
+
+       * config.host: Handle tic6x-*-*.
+       * config/c6x/c6x-abi.h: New file.
+
 2011-07-13  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
 
        * config/i386/crtprec.c: New file.
index 63c4dcc34abc3687d2b116bb5ce1889032f26d33..293d462b89f82a5ef97f00a05e9197f9fd543cb6 100644 (file)
@@ -146,6 +146,9 @@ sh[123456789lbe]*-*-*)
 v850*-*-*)
        cpu_type=v850
        ;;
+tic6x-*-*)
+       cpu_type=c6x
+       ;;
 esac
 
 # Common parts for widely ported systems.
@@ -662,6 +665,9 @@ sparc64-*-netbsd*)
        ;;
 spu-*-elf*)
        ;;
+tic6x-*-*)
+       tmake_file="${tmake_file} t-gnu-prefix"
+       ;;
 v850*-*-*)
        ;;
 vax-*-linux*)
diff --git a/libgcc/config/c6x/c6x-abi.h b/libgcc/config/c6x/c6x-abi.h
new file mode 100644 (file)
index 0000000..e4de070
--- /dev/null
@@ -0,0 +1,109 @@
+/* Header file for C6X ABI versions of libgcc functions.
+   Copyright (C) 2011
+   Free Software Foundation, Inc.
+   Contributed by Bernd Schmidt <bernds@codesourcery.com>
+
+   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.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   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/>.  */
+
+/* Make __c6xabi_AEABI_NAME an alias for __GCC_NAME.  */
+#define RENAME_LIBRARY(GCC_NAME, AEABI_NAME)                   \
+  __asm__ (".globl\t__c6xabi_" #AEABI_NAME "\n"                \
+          ".set\t__c6xabi_" #AEABI_NAME                        \
+          ", __gnu_" #GCC_NAME "\n");
+
+/* Rename helper functions to the names specified in the C6000 ELF ABI.  */
+#ifdef L_divsi3
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (divsi3, divi)
+#endif
+#ifdef L_divdi3
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (divdi3, divlli)
+#endif
+#ifdef L_udivsi3
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (udivsi3, divu)
+#endif
+#ifdef L_udivdi3
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (udivdi3, divull)
+#endif
+#ifdef L_udivmoddi4
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (udivmoddi4, divremull)
+#endif
+#ifdef L_modsi3
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (modsi3, remi)
+#endif
+#ifdef L_moddi3
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (moddi3, remlli)
+#endif
+#ifdef L_umodsi3
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (umodsi3, remu)
+#endif
+#ifdef L_umoddi3
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (umoddi3, remull)
+#endif
+#ifdef L_negdi2
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (negdi2, negll)
+#endif
+#ifdef L_muldi3
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (muldi3, mpyll)
+#endif
+#ifdef L_ashrdi3
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (ashrdi3, llshr)
+#endif
+#ifdef L_lshrdi3
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (lshrdi3, llshru)
+#endif
+#ifdef L_ashldi3
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (ashldi3, llshl)
+#endif
+
+/* The following are excluded from softfp due to softfp_exclude_libgcc2,
+   so we rename them here rather than in sfp-machine.h.  */
+#ifdef L_fixdfdi
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixdfdi, fixdlli)
+#endif
+#ifdef L_fixunsdfsi
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixunsdfsi, fixdu)
+#endif
+#ifdef L_fixunsdfdi
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixunsdfdi, fixdull)
+#endif
+#ifdef L_fixsfdi
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixsfdi, fixflli)
+#endif
+#ifdef L_fixunssfsi
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixunssfsi, fixfu)
+#endif
+#ifdef L_fixunssfdi
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixunssfdi, fixfull)
+#endif
+#ifdef L_floatdidf
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatdidf, fltllid)
+#endif
+#ifdef L_floatundidf
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatundidf, fltulld)
+#endif
+#ifdef L_floatdisf
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatdisf, fltllif)
+#endif
+#ifdef L_floatundisf
+#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatundisf, fltullf)
+#endif
+
+#define LIBGCC2_GNU_PREFIX