aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/gcc/config/c6x
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.9/gcc/config/c6x')
-rw-r--r--gcc-4.9/gcc/config/c6x/c6x-isas.def37
-rw-r--r--gcc-4.9/gcc/config/c6x/c6x-modes.def24
-rw-r--r--gcc-4.9/gcc/config/c6x/c6x-mult.md844
-rw-r--r--gcc-4.9/gcc/config/c6x/c6x-mult.md.in421
-rw-r--r--gcc-4.9/gcc/config/c6x/c6x-opts.h35
-rw-r--r--gcc-4.9/gcc/config/c6x/c6x-protos.h65
-rw-r--r--gcc-4.9/gcc/config/c6x/c6x-sched.md934
-rw-r--r--gcc-4.9/gcc/config/c6x/c6x-sched.md.in230
-rw-r--r--gcc-4.9/gcc/config/c6x/c6x-tables.opt43
-rw-r--r--gcc-4.9/gcc/config/c6x/c6x.c6846
-rw-r--r--gcc-4.9/gcc/config/c6x/c6x.h618
-rw-r--r--gcc-4.9/gcc/config/c6x/c6x.md3136
-rw-r--r--gcc-4.9/gcc/config/c6x/c6x.opt67
-rw-r--r--gcc-4.9/gcc/config/c6x/c6x_intrinsics.h194
-rw-r--r--gcc-4.9/gcc/config/c6x/constraints.md174
-rw-r--r--gcc-4.9/gcc/config/c6x/elf-common.h37
-rw-r--r--gcc-4.9/gcc/config/c6x/elf.h35
-rw-r--r--gcc-4.9/gcc/config/c6x/genmult.sh33
-rw-r--r--gcc-4.9/gcc/config/c6x/genopt.sh59
-rw-r--r--gcc-4.9/gcc/config/c6x/gensched.sh44
-rw-r--r--gcc-4.9/gcc/config/c6x/predicates.md226
-rw-r--r--gcc-4.9/gcc/config/c6x/sync.md270
-rw-r--r--gcc-4.9/gcc/config/c6x/t-c6x42
-rw-r--r--gcc-4.9/gcc/config/c6x/t-c6x-elf30
-rw-r--r--gcc-4.9/gcc/config/c6x/t-c6x-uclinux3
-rw-r--r--gcc-4.9/gcc/config/c6x/uclinux-elf.h63
26 files changed, 14510 insertions, 0 deletions
diff --git a/gcc-4.9/gcc/config/c6x/c6x-isas.def b/gcc-4.9/gcc/config/c6x/c6x-isas.def
new file mode 100644
index 000000000..1447a5d14
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/c6x-isas.def
@@ -0,0 +1,37 @@
+/* C6X ISA names.
+ Copyright (C) 2011-2014 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-4.9/gcc/config/c6x/c6x-modes.def b/gcc-4.9/gcc/config/c6x/c6x-modes.def
new file mode 100644
index 000000000..a438e2808
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/c6x-modes.def
@@ -0,0 +1,24 @@
+/* Definitions of target machine for GNU compiler, for TI C6x.
+ Copyright (C) 2010-2014 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-4.9/gcc/config/c6x/c6x-mult.md b/gcc-4.9/gcc/config/c6x/c6x-mult.md
new file mode 100644
index 000000000..d8e262652
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/c6x-mult.md
@@ -0,0 +1,844 @@
+;; -*- 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-2014 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 "op_pattern" "sxs")
+ (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 "op_pattern" "ssx")
+ (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-2014 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 "op_pattern" "sxs")
+ (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 "op_pattern" "ssx")
+ (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-4.9/gcc/config/c6x/c6x-mult.md.in b/gcc-4.9/gcc/config/c6x/c6x-mult.md.in
new file mode 100644
index 000000000..f09c7c085
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/c6x-mult.md.in
@@ -0,0 +1,421 @@
+;; 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-2014 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 "op_pattern" "sxs")
+ (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 "op_pattern" "ssx")
+ (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-4.9/gcc/config/c6x/c6x-opts.h b/gcc-4.9/gcc/config/c6x/c6x-opts.h
new file mode 100644
index 000000000..6bc3fe846
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/c6x-opts.h
@@ -0,0 +1,35 @@
+/* Definitions for option handling for TI C6X.
+ Copyright (C) 2011-2014 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-4.9/gcc/config/c6x/c6x-protos.h b/gcc-4.9/gcc/config/c6x/c6x-protos.h
new file mode 100644
index 000000000..e360ebff8
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/c6x-protos.h
@@ -0,0 +1,65 @@
+/* Prototypes for exported functions defined in c6x.c.
+ Copyright (C) 2010-2014 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-4.9/gcc/config/c6x/c6x-sched.md b/gcc-4.9/gcc/config/c6x/c6x-sched.md
new file mode 100644
index 000000000..d85c1a9b9
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/c6x-sched.md
@@ -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-2014 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"))))
+ "(fps1+s1,nothing*2,s1w)|(fpl1+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"))))
+ "(adddps1+(s1)*2,nothing*3,s1w*2)|(adddpl1+(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-2014 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"))))
+ "(fps2+s2,nothing*2,s2w)|(fpl2+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"))))
+ "(adddps2+(s2)*2,nothing*3,s2w*2)|(adddpl2+(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-2014 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"))))
+ "(fps1+s1+x1,nothing*2,s1w)|(fpl1+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"))))
+ "(adddps1+(s1+x1)*2,nothing*3,s1w*2)|(adddpl1+(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-2014 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"))))
+ "(fps2+s2+x2,nothing*2,s2w)|(fpl2+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"))))
+ "(adddps2+(s2+x2)*2,nothing*3,s2w*2)|(adddpl2+(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-4.9/gcc/config/c6x/c6x-sched.md.in b/gcc-4.9/gcc/config/c6x/c6x-sched.md.in
new file mode 100644
index 000000000..2a98dddac
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/c6x-sched.md.in
@@ -0,0 +1,230 @@
+;; Scheduling description for TI C6X.
+;; Copyright (C) 2010-2014 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_"))))
+ "(fps_N_+s_N__CUNIT_,nothing*2,s_N_w)|(fpl_N_+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_"))))
+ "(adddps_N_+(s_N__CUNIT_)*2,nothing*3,s_N_w*2)|(adddpl_N_+(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-4.9/gcc/config/c6x/c6x-tables.opt b/gcc-4.9/gcc/config/c6x/c6x-tables.opt
new file mode 100644
index 000000000..a4eb62fab
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/c6x-tables.opt
@@ -0,0 +1,43 @@
+; -*- buffer-read-only: t -*-
+; Generated automatically by genopt.sh from c6x-isas.def.
+;
+; Copyright (C) 2011-2014 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-4.9/gcc/config/c6x/c6x.c b/gcc-4.9/gcc/config/c6x/c6x.c
new file mode 100644
index 000000000..9ba10df73
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/c6x.c
@@ -0,0 +1,6846 @@
+/* Target Code for TI C6X
+ Copyright (C) 2010-2014 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 "stor-layout.h"
+#include "varasm.h"
+#include "calls.h"
+#include "stringpool.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 "function.h"
+#include "diagnostic-core.h"
+#include "cgraph.h"
+#include "langhooks.h"
+#include "target.h"
+#include "target-def.h"
+#include "sel-sched.h"
+#include "debug.h"
+#include "opts.h"
+#include "hw-doloop.h"
+#include "regrename.h"
+#include "dumpfile.h"
+#include "gimple-expr.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;
+
+/* 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;
+
+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;
+ /* The scheduler state after the insn, transformed into a mask of UNIT_QID
+ bits rather than storing the state. Meaningful only for the last
+ insn in a cycle. */
+ unsigned int unit_mask;
+} c6x_sched_insn_info;
+
+
+/* Record a c6x_sched_insn_info structure for every insn in the function. */
+static vec<c6x_sched_insn_info> insn_info;
+
+#define INSN_INFO_LENGTH (insn_info).length ()
+#define INSN_INFO_ENTRY(N) (insn_info[(N)])
+
+static bool done_cfi_sections;
+
+#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)
+
+/* The DFA names of the units. */
+static const char *const c6x_unit_names[] =
+{
+ "d1", "l1", "s1", "m1", "fps1", "fpl1", "adddps1", "adddpl1",
+ "d2", "l2", "s2", "m2", "fps2", "fpl2", "adddps2", "adddpl2"
+};
+
+/* The DFA unit number for each unit in c6x_unit_names[]. */
+static int c6x_unit_codes[ARRAY_SIZE (c6x_unit_names)];
+
+/* Unit query IDs. */
+#define UNIT_QID_D1 0
+#define UNIT_QID_L1 1
+#define UNIT_QID_S1 2
+#define UNIT_QID_M1 3
+#define UNIT_QID_FPS1 4
+#define UNIT_QID_FPL1 5
+#define UNIT_QID_ADDDPS1 6
+#define UNIT_QID_ADDDPL1 7
+#define UNIT_QID_SIDE_OFFSET 8
+
+#define RESERVATION_S1 2
+#define RESERVATION_S2 10
+
+/* An enum for the unit requirements we count in the UNIT_REQS table. */
+enum unitreqs
+{
+ UNIT_REQ_D,
+ UNIT_REQ_L,
+ UNIT_REQ_S,
+ UNIT_REQ_M,
+ UNIT_REQ_DL,
+ UNIT_REQ_DS,
+ UNIT_REQ_LS,
+ UNIT_REQ_DLS,
+ UNIT_REQ_T,
+ UNIT_REQ_X,
+ UNIT_REQ_MAX
+};
+
+/* A table used to count unit requirements. Used when computing minimum
+ iteration intervals. */
+typedef int unit_req_table[2][UNIT_REQ_MAX];
+static unit_req_table unit_reqs;
+
+/* Register map for debugging. */
+unsigned 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. */
+};
+
+/* 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)
+{
+ unsigned i;
+
+ 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;
+
+ for (i = 0; i < ARRAY_SIZE (c6x_unit_names); i++)
+ c6x_unit_codes[i] = get_cpu_unit_code (c6x_unit_names[i]);
+
+ 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);
+ }
+}
+
+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 (dwarf2out_do_frame ())
+ {
+ if (flag_unwind_tables || flag_exceptions)
+ {
+ if (write_symbols == DWARF2_DEBUG
+ || write_symbols == VMS_AND_DWARF2_DEBUG)
+ asm_fprintf (f, "\t.cfi_sections .debug_frame, .c6xabi.exidx\n");
+ else
+ asm_fprintf (f, "\t.cfi_sections .c6xabi.exidx\n");
+ }
+ else
+ asm_fprintf (f, "\t.cfi_sections .debug_frame\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);
+}
+
+
+/* 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);
+}
+
+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 (Pmode, tramp, TRAMPOLINE_SIZE),
+ Pmode);
+#endif
+}
+
+/* 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 (Pmode, 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);
+ }
+}
+
+/* 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;
+}
+
+/* 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;
+}
+
+/* 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.exists ())
+ {
+ 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.exists ())
+ {
+ 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);
+ }
+ }
+}
+
+/* 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;
+}
+
+/* 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;
+}
+
+/* Implements FINAL_PRESCAN_INSN. */
+void
+c6x_final_prescan_insn (rtx insn, rtx *opvec ATTRIBUTE_UNUSED,
+ int noperands ATTRIBUTE_UNUSED)
+{
+ c6x_current_insn = insn;
+}
+
+/* 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 || !crtl->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)
+ || !crtl->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
+ && !crtl->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);
+}
+
+/* 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;
+}
+
+/* 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))
+ {
+ unsigned int sched_mask, reserved;
+ rtx within, last;
+ int pass;
+ int rsrv[2];
+ int rsrv_count[2][4];
+ int i;
+
+ if (GET_MODE (insn) != TImode)
+ continue;
+
+ reserved = 0;
+ last = NULL_RTX;
+ /* Find the last insn in the packet. It has a state recorded for it,
+ which we can use to determine the units we should be using. */
+ for (within = insn;
+ (within != NEXT_INSN (end)
+ && (within == insn || GET_MODE (within) != TImode));
+ within = NEXT_INSN (within))
+ {
+ int icode;
+ if (!NONDEBUG_INSN_P (within))
+ continue;
+ icode = recog_memoized (within);
+ if (icode < 0)
+ continue;
+ if (shadow_p (within))
+ continue;
+ if (INSN_INFO_ENTRY (INSN_UID (within)).reservation != 0)
+ reserved |= 1 << INSN_INFO_ENTRY (INSN_UID (within)).reservation;
+ last = within;
+ }
+ if (last == NULL_RTX)
+ continue;
+
+ sched_mask = INSN_INFO_ENTRY (INSN_UID (last)).unit_mask;
+ sched_mask &= ~reserved;
+
+ memset (rsrv_count, 0, sizeof rsrv_count);
+ rsrv[0] = rsrv[1] = ~0;
+ for (i = 0; i < 8; i++)
+ {
+ int side = i / 4;
+ int unit = i & 3;
+ unsigned unit_bit = 1 << (unit + side * UNIT_QID_SIDE_OFFSET);
+ /* Clear the bits which we expect to reserve in the following loop,
+ leaving the ones set which aren't present in the scheduler's
+ state and shouldn't be reserved. */
+ if (sched_mask & unit_bit)
+ rsrv[i / 4] &= ~(1 << unit);
+ }
+
+ /* 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 uid = INSN_UID (within);
+ int this_rsrv, side;
+ int icode;
+ enum attr_units units;
+ enum attr_type type;
+ int j;
+
+ if (!NONDEBUG_INSN_P (within))
+ continue;
+ icode = recog_memoized (within);
+ if (icode < 0)
+ continue;
+ if (INSN_INFO_ENTRY (uid).reservation != 0)
+ continue;
+ units = get_attr_units (within);
+ type = get_attr_type (within);
+ this_rsrv = get_reservation_flags (units);
+ if (this_rsrv == 0)
+ continue;
+ side = get_insn_side (within, units);
+
+ /* Certain floating point instructions are treated specially. If
+ an insn can choose between units it can reserve, and its
+ reservation spans more than one cycle, the reservation contains
+ special markers in the first cycle to help us reconstruct what
+ the automaton chose. */
+ if ((type == TYPE_ADDDP || type == TYPE_FP4)
+ && units == UNITS_LS)
+ {
+ int test1_code = ((type == TYPE_FP4 ? UNIT_QID_FPL1 : UNIT_QID_ADDDPL1)
+ + side * UNIT_QID_SIDE_OFFSET);
+ int test2_code = ((type == TYPE_FP4 ? UNIT_QID_FPS1 : UNIT_QID_ADDDPS1)
+ + side * UNIT_QID_SIDE_OFFSET);
+ if ((sched_mask & (1 << test1_code)) != 0)
+ {
+ this_rsrv = RESERVATION_FLAG_L;
+ sched_mask &= ~(1 << test1_code);
+ }
+ else if ((sched_mask & (1 << test2_code)) != 0)
+ {
+ this_rsrv = RESERVATION_FLAG_S;
+ sched_mask &= ~(1 << test2_code);
+ }
+ }
+
+ if ((this_rsrv & (this_rsrv - 1)) == 0)
+ {
+ int t = exact_log2 (this_rsrv) + side * UNIT_QID_SIDE_OFFSET;
+ rsrv[side] |= this_rsrv;
+ INSN_INFO_ENTRY (uid).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 (uid).reservation
+ = best + side * UNIT_QID_SIDE_OFFSET;
+ }
+ }
+ }
+}
+
+/* Return a factor by which to weight unit imbalances for a reservation
+ R. */
+static int
+unit_req_factor (enum unitreqs r)
+{
+ switch (r)
+ {
+ case UNIT_REQ_D:
+ case UNIT_REQ_L:
+ case UNIT_REQ_S:
+ case UNIT_REQ_M:
+ case UNIT_REQ_X:
+ case UNIT_REQ_T:
+ return 1;
+ case UNIT_REQ_DL:
+ case UNIT_REQ_LS:
+ case UNIT_REQ_DS:
+ return 2;
+ case UNIT_REQ_DLS:
+ return 3;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Examine INSN, and store in REQ1/SIDE1 and REQ2/SIDE2 the unit
+ requirements. Returns zero if INSN can't be handled, otherwise
+ either one or two to show how many of the two pairs are in use.
+ REQ1 is always used, it holds what is normally thought of as the
+ instructions reservation, e.g. UNIT_REQ_DL. REQ2 is used to either
+ describe a cross path, or for loads/stores, the T unit. */
+static int
+get_unit_reqs (rtx insn, int *req1, int *side1, int *req2, int *side2)
+{
+ enum attr_units units;
+ enum attr_cross cross;
+ int side, req;
+
+ if (!NONDEBUG_INSN_P (insn) || recog_memoized (insn) < 0)
+ return 0;
+ units = get_attr_units (insn);
+ if (units == UNITS_UNKNOWN)
+ return 0;
+ side = get_insn_side (insn, units);
+ cross = get_attr_cross (insn);
+
+ req = (units == UNITS_D ? UNIT_REQ_D
+ : units == UNITS_D_ADDR ? UNIT_REQ_D
+ : units == UNITS_DL ? UNIT_REQ_DL
+ : units == UNITS_DS ? UNIT_REQ_DS
+ : units == UNITS_L ? UNIT_REQ_L
+ : units == UNITS_LS ? UNIT_REQ_LS
+ : units == UNITS_S ? UNIT_REQ_S
+ : units == UNITS_M ? UNIT_REQ_M
+ : units == UNITS_DLS ? UNIT_REQ_DLS
+ : -1);
+ gcc_assert (req != -1);
+ *req1 = req;
+ *side1 = side;
+ if (units == UNITS_D_ADDR)
+ {
+ *req2 = UNIT_REQ_T;
+ *side2 = side ^ (cross == CROSS_Y ? 1 : 0);
+ return 2;
+ }
+ else if (cross == CROSS_Y)
+ {
+ *req2 = UNIT_REQ_X;
+ *side2 = side;
+ return 2;
+ }
+ return 1;
+}
+
+/* Walk the insns between and including HEAD and TAIL, and mark the
+ resource requirements in the unit_reqs table. */
+static void
+count_unit_reqs (unit_req_table reqs, rtx head, rtx tail)
+{
+ rtx insn;
+
+ memset (reqs, 0, sizeof (unit_req_table));
+
+ for (insn = head; insn != NEXT_INSN (tail); insn = NEXT_INSN (insn))
+ {
+ int side1, side2, req1, req2;
+
+ switch (get_unit_reqs (insn, &req1, &side1, &req2, &side2))
+ {
+ case 2:
+ reqs[side2][req2]++;
+ /* fall through */
+ case 1:
+ reqs[side1][req1]++;
+ break;
+ }
+ }
+}
+
+/* Update the table REQS by merging more specific unit reservations into
+ more general ones, i.e. counting (for example) UNIT_REQ_D also in
+ UNIT_REQ_DL, DS, and DLS. */
+static void
+merge_unit_reqs (unit_req_table reqs)
+{
+ int side;
+ for (side = 0; side < 2; side++)
+ {
+ int d = reqs[side][UNIT_REQ_D];
+ int l = reqs[side][UNIT_REQ_L];
+ int s = reqs[side][UNIT_REQ_S];
+ int dl = reqs[side][UNIT_REQ_DL];
+ int ls = reqs[side][UNIT_REQ_LS];
+ int ds = reqs[side][UNIT_REQ_DS];
+
+ reqs[side][UNIT_REQ_DL] += d;
+ reqs[side][UNIT_REQ_DL] += l;
+ reqs[side][UNIT_REQ_DS] += d;
+ reqs[side][UNIT_REQ_DS] += s;
+ reqs[side][UNIT_REQ_LS] += l;
+ reqs[side][UNIT_REQ_LS] += s;
+ reqs[side][UNIT_REQ_DLS] += ds + dl + ls + d + l + s;
+ }
+}
+
+/* Examine the table REQS and return a measure of unit imbalance by comparing
+ the two sides of the machine. If, for example, D1 is used twice and D2
+ used not at all, the return value should be 1 in the absence of other
+ imbalances. */
+static int
+unit_req_imbalance (unit_req_table reqs)
+{
+ int val = 0;
+ int i;
+
+ for (i = 0; i < UNIT_REQ_MAX; i++)
+ {
+ int factor = unit_req_factor ((enum unitreqs) i);
+ int diff = abs (reqs[0][i] - reqs[1][i]);
+ val += (diff + factor - 1) / factor / 2;
+ }
+ return val;
+}
+
+/* Return the resource-constrained minimum iteration interval given the
+ data in the REQS table. This must have been processed with
+ merge_unit_reqs already. */
+static int
+res_mii (unit_req_table reqs)
+{
+ int side, req;
+ int worst = 1;
+ for (side = 0; side < 2; side++)
+ for (req = 0; req < UNIT_REQ_MAX; req++)
+ {
+ int factor = unit_req_factor ((enum unitreqs) req);
+ worst = MAX ((reqs[side][UNIT_REQ_D] + factor - 1) / factor, worst);
+ }
+
+ return worst;
+}
+
+/* Examine INSN, and store in PMASK1 and PMASK2 bitmasks that represent
+ the operands that are involved in the (up to) two reservations, as
+ found by get_unit_reqs. Return true if we did this successfully, false
+ if we couldn't identify what to do with INSN. */
+static bool
+get_unit_operand_masks (rtx insn, unsigned int *pmask1, unsigned int *pmask2)
+{
+ enum attr_op_pattern op_pat;
+
+ if (recog_memoized (insn) < 0)
+ return 0;
+ if (GET_CODE (PATTERN (insn)) == COND_EXEC)
+ return false;
+ extract_insn (insn);
+ op_pat = get_attr_op_pattern (insn);
+ if (op_pat == OP_PATTERN_DT)
+ {
+ gcc_assert (recog_data.n_operands == 2);
+ *pmask1 = 1 << 0;
+ *pmask2 = 1 << 1;
+ return true;
+ }
+ else if (op_pat == OP_PATTERN_TD)
+ {
+ gcc_assert (recog_data.n_operands == 2);
+ *pmask1 = 1 << 1;
+ *pmask2 = 1 << 0;
+ return true;
+ }
+ else if (op_pat == OP_PATTERN_SXS)
+ {
+ gcc_assert (recog_data.n_operands == 3);
+ *pmask1 = (1 << 0) | (1 << 2);
+ *pmask2 = 1 << 1;
+ return true;
+ }
+ else if (op_pat == OP_PATTERN_SX)
+ {
+ gcc_assert (recog_data.n_operands == 2);
+ *pmask1 = 1 << 0;
+ *pmask2 = 1 << 1;
+ return true;
+ }
+ else if (op_pat == OP_PATTERN_SSX)
+ {
+ gcc_assert (recog_data.n_operands == 3);
+ *pmask1 = (1 << 0) | (1 << 1);
+ *pmask2 = 1 << 2;
+ return true;
+ }
+ return false;
+}
+
+/* Try to replace a register in INSN, which has corresponding rename info
+ from regrename_analyze in INFO. OP_MASK and ORIG_SIDE provide information
+ about the operands that must be renamed and the side they are on.
+ REQS is the table of unit reservations in the loop between HEAD and TAIL.
+ We recompute this information locally after our transformation, and keep
+ it only if we managed to improve the balance. */
+static void
+try_rename_operands (rtx head, rtx tail, unit_req_table reqs, rtx insn,
+ insn_rr_info *info, unsigned int op_mask, int orig_side)
+{
+ enum reg_class super_class = orig_side == 0 ? B_REGS : A_REGS;
+ HARD_REG_SET unavailable;
+ du_head_p this_head;
+ struct du_chain *chain;
+ int i;
+ unsigned tmp_mask;
+ int best_reg, old_reg;
+ vec<du_head_p> involved_chains = vNULL;
+ unit_req_table new_reqs;
+
+ for (i = 0, tmp_mask = op_mask; tmp_mask; i++)
+ {
+ du_head_p op_chain;
+ if ((tmp_mask & (1 << i)) == 0)
+ continue;
+ if (info->op_info[i].n_chains != 1)
+ goto out_fail;
+ op_chain = regrename_chain_from_id (info->op_info[i].heads[0]->id);
+ involved_chains.safe_push (op_chain);
+ tmp_mask &= ~(1 << i);
+ }
+
+ if (involved_chains.length () > 1)
+ goto out_fail;
+
+ this_head = involved_chains[0];
+ if (this_head->cannot_rename)
+ goto out_fail;
+
+ for (chain = this_head->first; chain; chain = chain->next_use)
+ {
+ unsigned int mask1, mask2, mask_changed;
+ int count, side1, side2, req1, req2;
+ insn_rr_info *this_rr = &insn_rr[INSN_UID (chain->insn)];
+
+ count = get_unit_reqs (chain->insn, &req1, &side1, &req2, &side2);
+
+ if (count == 0)
+ goto out_fail;
+
+ if (!get_unit_operand_masks (chain->insn, &mask1, &mask2))
+ goto out_fail;
+
+ extract_insn (chain->insn);
+
+ mask_changed = 0;
+ for (i = 0; i < recog_data.n_operands; i++)
+ {
+ int j;
+ int n_this_op = this_rr->op_info[i].n_chains;
+ for (j = 0; j < n_this_op; j++)
+ {
+ du_head_p other = this_rr->op_info[i].heads[j];
+ if (regrename_chain_from_id (other->id) == this_head)
+ break;
+ }
+ if (j == n_this_op)
+ continue;
+
+ if (n_this_op != 1)
+ goto out_fail;
+ mask_changed |= 1 << i;
+ }
+ gcc_assert (mask_changed != 0);
+ if (mask_changed != mask1 && mask_changed != mask2)
+ goto out_fail;
+ }
+
+ /* If we get here, we can do the renaming. */
+ COMPL_HARD_REG_SET (unavailable, reg_class_contents[(int) super_class]);
+
+ old_reg = this_head->regno;
+ best_reg = find_best_rename_reg (this_head, super_class, &unavailable, old_reg);
+
+ regrename_do_replace (this_head, best_reg);
+
+ count_unit_reqs (new_reqs, head, PREV_INSN (tail));
+ merge_unit_reqs (new_reqs);
+ if (dump_file)
+ {
+ fprintf (dump_file, "reshuffle for insn %d, op_mask %x, "
+ "original side %d, new reg %d\n",
+ INSN_UID (insn), op_mask, orig_side, best_reg);
+ fprintf (dump_file, " imbalance %d -> %d\n",
+ unit_req_imbalance (reqs), unit_req_imbalance (new_reqs));
+ }
+ if (unit_req_imbalance (new_reqs) > unit_req_imbalance (reqs))
+ regrename_do_replace (this_head, old_reg);
+ else
+ memcpy (reqs, new_reqs, sizeof (unit_req_table));
+
+ out_fail:
+ involved_chains.release ();
+}
+
+/* Find insns in LOOP which would, if shifted to the other side
+ of the machine, reduce an imbalance in the unit reservations. */
+static void
+reshuffle_units (basic_block loop)
+{
+ rtx head = BB_HEAD (loop);
+ rtx tail = BB_END (loop);
+ rtx insn;
+ unit_req_table reqs;
+ edge e;
+ edge_iterator ei;
+ bitmap_head bbs;
+
+ count_unit_reqs (reqs, head, PREV_INSN (tail));
+ merge_unit_reqs (reqs);
+
+ regrename_init (true);
+
+ bitmap_initialize (&bbs, &bitmap_default_obstack);
+
+ FOR_EACH_EDGE (e, ei, loop->preds)
+ bitmap_set_bit (&bbs, e->src->index);
+
+ bitmap_set_bit (&bbs, loop->index);
+ regrename_analyze (&bbs);
+
+ for (insn = head; insn != NEXT_INSN (tail); insn = NEXT_INSN (insn))
+ {
+ enum attr_units units;
+ int count, side1, side2, req1, req2;
+ unsigned int mask1, mask2;
+ insn_rr_info *info;
+
+ if (!NONDEBUG_INSN_P (insn))
+ continue;
+
+ count = get_unit_reqs (insn, &req1, &side1, &req2, &side2);
+
+ if (count == 0)
+ continue;
+
+ if (!get_unit_operand_masks (insn, &mask1, &mask2))
+ continue;
+
+ info = &insn_rr[INSN_UID (insn)];
+ if (info->op_info == NULL)
+ continue;
+
+ if (reqs[side1][req1] > 1
+ && reqs[side1][req1] > 2 * reqs[side1 ^ 1][req1])
+ {
+ try_rename_operands (head, tail, reqs, insn, info, mask1, side1);
+ }
+
+ units = get_attr_units (insn);
+ if (units == UNITS_D_ADDR)
+ {
+ gcc_assert (count == 2);
+ if (reqs[side2][req2] > 1
+ && reqs[side2][req2] > 2 * reqs[side2 ^ 1][req2])
+ {
+ try_rename_operands (head, tail, reqs, insn, info, mask2, side2);
+ }
+ }
+ }
+ regrename_finish ();
+}
+
+/* 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;
+ /* The last issued insn that isn't a shadow of another. */
+ rtx last_scheduled_iter0;
+
+ /* The following variable value is DFA state before issuing the
+ first insn in the current clock cycle. We do not use this member
+ of the structure directly; we copy the data in and out of
+ prev_cycle_state. */
+ state_t prev_cycle_state_ctx;
+
+ 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;
+
+/* The following variable value is DFA state before issuing the first insn
+ in the current clock cycle. This is used in c6x_variable_issue for
+ comparison with the state after issuing the last insn in a cycle. */
+static state_t prev_cycle_state;
+
+/* 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;
+
+/* The highest insn uid after delayed insns were split, but before loop bodies
+ were copied by the modulo scheduling code. */
+static int sploop_max_uid_iter0;
+
+/* 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)
+ insn_info.safe_grow (uid * 5 / 4 + 10);
+
+ INSN_INFO_ENTRY (uid).clock = cycle;
+ INSN_INFO_ENTRY (uid).new_cond = NULL;
+ INSN_INFO_ENTRY (uid).reservation = 0;
+ 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->last_scheduled_iter0 = 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;
+
+ sc->prev_cycle_state_ctx = xmalloc (dfa_state_size);
+
+ 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);
+
+ state_reset (sc->prev_cycle_state_ctx);
+}
+
+/* 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;
+ sc->prev_cycle_state_ctx = xmalloc (dfa_state_size);
+ memcpy (sc->prev_cycle_state_ctx, prev_cycle_state, dfa_state_size);
+ }
+}
+
+/* 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;
+ memcpy (prev_cycle_state, sc->prev_cycle_state_ctx, dfa_state_size);
+}
+
+/* Clear data in _SC. */
+static void
+c6x_clear_sched_context (void *_sc)
+{
+ c6x_sched_context_t sc = (c6x_sched_context_t) _sc;
+ gcc_assert (_sc != NULL);
+
+ free (sc->prev_cycle_state_ctx);
+}
+
+/* Free _SC. */
+static void
+c6x_free_sched_context (void *_sc)
+{
+ free (_sc);
+}
+
+/* True if we are currently performing a preliminary scheduling
+ pass before modulo scheduling; we can't allow the scheduler to
+ modify instruction patterns using packetization assumptions,
+ since there will be another scheduling pass later if modulo
+ scheduling fails. */
+static bool in_hwloop;
+
+/* 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 | DO_PREDICATION;
+ }
+ if (in_hwloop)
+ *flags |= DONT_BREAK_DEPENDENCIES;
+
+ spec_info->mask = 0;
+}
+
+/* Implement the TARGET_SCHED_ISSUE_RATE hook. */
+
+static int
+c6x_issue_rate (void)
+{
+ return 8;
+}
+
+/* Used together with the collapse_ndfa option, this ensures that we reach a
+ deterministic automaton state before trying to advance a cycle.
+ With collapse_ndfa, genautomata creates advance cycle arcs only for
+ such deterministic states. */
+
+static rtx
+c6x_sched_dfa_pre_cycle_insn (void)
+{
+ return const0_rtx;
+}
+
+/* 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)
+{
+ if (prev_cycle_state == NULL)
+ {
+ prev_cycle_state = xmalloc (dfa_state_size);
+ }
+ init_sched_state (&ss);
+ state_reset (prev_cycle_state);
+}
+
+/* We are about to being issuing INSN. Return nonzero if we cannot
+ issue it on given cycle CLOCK and return zero if we should not sort
+ the ready queue on the next clock start.
+ For C6X, we use this function just to copy the previous DFA state
+ for comparison purposes. */
+
+static int
+c6x_dfa_new_cycle (FILE *dump ATTRIBUTE_UNUSED, int verbose ATTRIBUTE_UNUSED,
+ rtx insn ATTRIBUTE_UNUSED, int last_clock ATTRIBUTE_UNUSED,
+ int clock ATTRIBUTE_UNUSED, int *sort_p ATTRIBUTE_UNUSED)
+{
+ if (clock != last_clock)
+ memcpy (prev_cycle_state, curr_state, dfa_state_size);
+ return 0;
+}
+
+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 == CODE_FOR_sploop
+ || (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)
+ || (ss.issued_this_cycle > 0 && icode == CODE_FOR_sploop))
+ {
+ 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, rsrv_cycles;
+ enum attr_type type;
+
+ gcc_assert (!is_asm);
+ if (icode < 0)
+ continue;
+ this_cycles = get_attr_cycles (insn);
+ rsrv_cycles = get_attr_reserve_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)
+ || clock_var + rsrv_cycles > first_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 (INSN_UID (insn) < sploop_max_uid_iter0 && !JUMP_P (insn))
+ ss.last_scheduled_iter0 = insn;
+ if (GET_CODE (PATTERN (insn)) != USE && GET_CODE (PATTERN (insn)) != CLOBBER)
+ ss.issued_this_cycle++;
+ if (insn_info.exists ())
+ {
+ state_t st_after = alloca (dfa_state_size);
+ int curr_clock = ss.curr_sched_clock;
+ int uid = INSN_UID (insn);
+ int icode = recog_memoized (insn);
+ rtx first_cond;
+ int first, first_cycle;
+ unsigned int mask;
+ int i;
+
+ 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;
+
+ memcpy (st_after, curr_state, dfa_state_size);
+ state_transition (st_after, const0_rtx);
+
+ mask = 0;
+ for (i = 0; i < 2 * UNIT_QID_SIDE_OFFSET; i++)
+ if (cpu_unit_reservation_p (st_after, c6x_unit_codes[i])
+ && !cpu_unit_reservation_p (prev_cycle_state, c6x_unit_codes[i]))
+ mask |= 1 << i;
+ INSN_INFO_ENTRY (uid).unit_mask = mask;
+
+ 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;
+}
+
+/* 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_LOCATION (bundle) = INSN_LOCATION (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_LOCATION (slot[i]) = INSN_LOCATION (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_FN (bb, cfun)
+ {
+ 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 (NOTE_P (insn));
+ 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 the shadow insn corresponding to this call, we may
+ use a CALLP insn. */
+ rtx shadow = next_nonnote_nondebug_insn (last_same_clock);
+
+ if (CALL_P (shadow)
+ && insn_get_clock (shadow) == this_clock + 5)
+ {
+ convert_to_callp (shadow);
+ insn_set_clock (shadow, this_clock);
+ INSN_INFO_ENTRY (INSN_UID (shadow)).reservation
+ = RESERVATION_S2;
+ INSN_INFO_ENTRY (INSN_UID (shadow)).unit_mask
+ = INSN_INFO_ENTRY (INSN_UID (last_same_clock)).unit_mask;
+ 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 != shadow)
+ PUT_MODE (shadow, VOIDmode);
+ INSN_INFO_ENTRY (INSN_UID (new_cycle_first)).ebb_start
+ = INSN_INFO_ENTRY (INSN_UID (insn)).ebb_start;
+ }
+ else
+ PUT_MODE (shadow, 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
+ INSN_INFO_ENTRY (INSN_UID (x1)).unit_mask
+ = INSN_INFO_ENTRY (INSN_UID (after1)).unit_mask;
+ }
+ 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);
+ else
+ INSN_INFO_ENTRY (INSN_UID (x1)).unit_mask
+ = INSN_INFO_ENTRY (INSN_UID (after1)).unit_mask;
+ if (after1 == after2)
+ PUT_MODE (x2, TImode);
+ else
+ INSN_INFO_ENTRY (INSN_UID (x2)).unit_mask
+ = INSN_INFO_ENTRY (INSN_UID (after2)).unit_mask;
+ }
+ }
+ }
+ 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_TABLE_DATA_P (insn))
+ 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, 0);
+}
+
+/* If INSN is a multi-cycle insn that should be handled properly in
+ modulo-scheduling, split it into a real insn and a shadow.
+ Return true if we made a change.
+
+ It is valid for us to fail to split an insn; the caller has to deal
+ with the possibility. Currently we handle loads and most mpy2 and
+ mpy4 insns. */
+static bool
+split_delayed_nonbranch (rtx insn)
+{
+ int code = recog_memoized (insn);
+ enum attr_type type;
+ rtx i1, newpat, src, dest;
+ rtx pat = PATTERN (insn);
+ rtvec rtv;
+ int delay;
+
+ if (GET_CODE (pat) == COND_EXEC)
+ pat = COND_EXEC_CODE (pat);
+
+ if (code < 0 || GET_CODE (pat) != SET)
+ return false;
+ src = SET_SRC (pat);
+ dest = SET_DEST (pat);
+ if (!REG_P (dest))
+ return false;
+
+ type = get_attr_type (insn);
+ if (code >= 0
+ && (type == TYPE_LOAD
+ || type == TYPE_LOADN))
+ {
+ if (!MEM_P (src)
+ && (GET_CODE (src) != ZERO_EXTEND
+ || !MEM_P (XEXP (src, 0))))
+ return false;
+
+ if (GET_MODE_SIZE (GET_MODE (dest)) > 4
+ && (GET_MODE_SIZE (GET_MODE (dest)) != 8 || !TARGET_LDDW))
+ return false;
+
+ rtv = gen_rtvec (2, GEN_INT (REGNO (SET_DEST (pat))),
+ SET_SRC (pat));
+ newpat = gen_load_shadow (SET_DEST (pat));
+ pat = gen_rtx_UNSPEC (VOIDmode, rtv, UNSPEC_REAL_LOAD);
+ delay = 4;
+ }
+ else if (code >= 0
+ && (type == TYPE_MPY2
+ || type == TYPE_MPY4))
+ {
+ /* We don't handle floating point multiplies yet. */
+ if (GET_MODE (dest) == SFmode)
+ return false;
+
+ rtv = gen_rtvec (2, GEN_INT (REGNO (SET_DEST (pat))),
+ SET_SRC (pat));
+ newpat = gen_mult_shadow (SET_DEST (pat));
+ pat = gen_rtx_UNSPEC (VOIDmode, rtv, UNSPEC_REAL_MULT);
+ delay = type == TYPE_MPY2 ? 1 : 3;
+ }
+ else
+ return false;
+
+ pat = duplicate_cond (pat, insn);
+ newpat = duplicate_cond (newpat, insn);
+ i1 = emit_insn_before (pat, insn);
+ PATTERN (insn) = newpat;
+ INSN_CODE (insn) = -1;
+ recog_memoized (insn);
+ recog_memoized (i1);
+ record_delay_slot_pair (i1, insn, delay, 0);
+ return true;
+}
+
+/* Examine if INSN is the result of splitting a load into a real load and a
+ shadow, and if so, undo the transformation. */
+static void
+undo_split_delayed_nonbranch (rtx insn)
+{
+ int icode = recog_memoized (insn);
+ enum attr_type type;
+ rtx prev_pat, insn_pat, prev;
+
+ if (icode < 0)
+ return;
+ type = get_attr_type (insn);
+ if (type != TYPE_LOAD_SHADOW && type != TYPE_MULT_SHADOW)
+ return;
+ prev = PREV_INSN (insn);
+ prev_pat = PATTERN (prev);
+ insn_pat = PATTERN (insn);
+ if (GET_CODE (prev_pat) == COND_EXEC)
+ {
+ prev_pat = COND_EXEC_CODE (prev_pat);
+ insn_pat = COND_EXEC_CODE (insn_pat);
+ }
+
+ gcc_assert (GET_CODE (prev_pat) == UNSPEC
+ && ((XINT (prev_pat, 1) == UNSPEC_REAL_LOAD
+ && type == TYPE_LOAD_SHADOW)
+ || (XINT (prev_pat, 1) == UNSPEC_REAL_MULT
+ && type == TYPE_MULT_SHADOW)));
+ insn_pat = gen_rtx_SET (VOIDmode, SET_DEST (insn_pat),
+ XVECEXP (prev_pat, 0, 1));
+ insn_pat = duplicate_cond (insn_pat, prev);
+ PATTERN (insn) = insn_pat;
+ INSN_CODE (insn) = -1;
+ delete_insn (prev);
+}
+
+/* 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_FN (bb, cfun)
+ 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);
+ }
+}
+
+/* A callback for the hw-doloop pass. This function examines INSN; if
+ it is a loop_end pattern we recognize, return the reg rtx for the
+ loop counter. Otherwise, return NULL_RTX. */
+
+static rtx
+hwloop_pattern_reg (rtx insn)
+{
+ rtx pat, reg;
+
+ if (!JUMP_P (insn) || recog_memoized (insn) != CODE_FOR_loop_end)
+ return NULL_RTX;
+
+ pat = PATTERN (insn);
+ reg = SET_DEST (XVECEXP (pat, 0, 1));
+ if (!REG_P (reg))
+ return NULL_RTX;
+ return reg;
+}
+
+/* Return the number of cycles taken by BB, as computed by scheduling,
+ including the latencies of all insns with delay slots. IGNORE is
+ an insn we should ignore in the calculation, usually the final
+ branch. */
+static int
+bb_earliest_end_cycle (basic_block bb, rtx ignore)
+{
+ int earliest = 0;
+ rtx insn;
+
+ FOR_BB_INSNS (bb, insn)
+ {
+ int cycles, this_clock;
+
+ if (LABEL_P (insn) || NOTE_P (insn) || DEBUG_INSN_P (insn)
+ || GET_CODE (PATTERN (insn)) == USE
+ || GET_CODE (PATTERN (insn)) == CLOBBER
+ || insn == ignore)
+ continue;
+
+ this_clock = insn_get_clock (insn);
+ cycles = get_attr_cycles (insn);
+
+ if (earliest < this_clock + cycles)
+ earliest = this_clock + cycles;
+ }
+ return earliest;
+}
+
+/* Examine the insns in BB and remove all which have a uid greater or
+ equal to MAX_UID. */
+static void
+filter_insns_above (basic_block bb, int max_uid)
+{
+ rtx insn, next;
+ bool prev_ti = false;
+ int prev_cycle = -1;
+
+ FOR_BB_INSNS_SAFE (bb, insn, next)
+ {
+ int this_cycle;
+ if (!NONDEBUG_INSN_P (insn))
+ continue;
+ if (insn == BB_END (bb))
+ return;
+ this_cycle = insn_get_clock (insn);
+ if (prev_ti && this_cycle == prev_cycle)
+ {
+ gcc_assert (GET_MODE (insn) != TImode);
+ PUT_MODE (insn, TImode);
+ }
+ prev_ti = false;
+ if (INSN_UID (insn) >= max_uid)
+ {
+ if (GET_MODE (insn) == TImode)
+ {
+ prev_ti = true;
+ prev_cycle = this_cycle;
+ }
+ delete_insn (insn);
+ }
+ }
+}
+
+/* Implement TARGET_ASM_EMIT_EXCEPT_PERSONALITY. */
+
+static void
+c6x_asm_emit_except_personality (rtx personality)
+{
+ fputs ("\t.personality\t", asm_out_file);
+ output_addr_const (asm_out_file, personality);
+ fputc ('\n', asm_out_file);
+}
+
+/* Use a special assembly directive rather than a regular setion for
+ unwind table data. */
+
+static void
+c6x_asm_init_sections (void)
+{
+ exception_section = get_unnamed_section (0, output_section_asm_op,
+ "\t.handlerdata");
+}
+
+/* A callback for the hw-doloop pass. Called to optimize LOOP in a
+ machine-specific fashion; returns true if successful and false if
+ the hwloop_fail function should be called. */
+
+static bool
+hwloop_optimize (hwloop_info loop)
+{
+ basic_block entry_bb, bb;
+ rtx seq, insn, prev, entry_after, end_packet;
+ rtx head_insn, tail_insn, new_insns, last_insn;
+ int loop_earliest;
+ int n_execute_packets;
+ edge entry_edge;
+ unsigned ix;
+ int max_uid_before, delayed_splits;
+ int i, sp_ii, min_ii, max_ii, max_parallel, n_insns, n_real_insns, stages;
+ rtx *orig_vec;
+ rtx *copies;
+ rtx **insn_copies;
+
+ if (!c6x_flag_modulo_sched || !c6x_flag_schedule_insns2
+ || !TARGET_INSNS_64PLUS)
+ return false;
+
+ if (loop->iter_reg_used || loop->depth > 1)
+ return false;
+ if (loop->has_call || loop->has_asm)
+ return false;
+
+ if (loop->head != loop->tail)
+ return false;
+
+ gcc_assert (loop->incoming_dest == loop->head);
+
+ entry_edge = NULL;
+ FOR_EACH_VEC_SAFE_ELT (loop->incoming, i, entry_edge)
+ if (entry_edge->flags & EDGE_FALLTHRU)
+ break;
+ if (entry_edge == NULL)
+ return false;
+
+ reshuffle_units (loop->head);
+
+ in_hwloop = true;
+ schedule_ebbs_init ();
+ schedule_ebb (BB_HEAD (loop->tail), loop->loop_end, true);
+ schedule_ebbs_finish ();
+ in_hwloop = false;
+
+ bb = loop->head;
+ loop_earliest = bb_earliest_end_cycle (bb, loop->loop_end) + 1;
+
+ max_uid_before = get_max_uid ();
+
+ /* Split all multi-cycle operations, such as loads. For normal
+ scheduling, we only do this for branches, as the generated code
+ would otherwise not be interrupt-safe. When using sploop, it is
+ safe and beneficial to split them. If any multi-cycle operations
+ remain after splitting (because we don't handle them yet), we
+ cannot pipeline the loop. */
+ delayed_splits = 0;
+ FOR_BB_INSNS (bb, insn)
+ {
+ if (NONDEBUG_INSN_P (insn))
+ {
+ recog_memoized (insn);
+ if (split_delayed_nonbranch (insn))
+ delayed_splits++;
+ else if (INSN_CODE (insn) >= 0
+ && get_attr_cycles (insn) > 1)
+ goto undo_splits;
+ }
+ }
+
+ /* Count the number of insns as well as the number real insns, and save
+ the original sequence of insns in case we must restore it later. */
+ n_insns = n_real_insns = 0;
+ FOR_BB_INSNS (bb, insn)
+ {
+ n_insns++;
+ if (NONDEBUG_INSN_P (insn) && insn != loop->loop_end)
+ n_real_insns++;
+ }
+ orig_vec = XNEWVEC (rtx, n_insns);
+ n_insns = 0;
+ FOR_BB_INSNS (bb, insn)
+ orig_vec[n_insns++] = insn;
+
+ /* Count the unit reservations, and compute a minimum II from that
+ table. */
+ count_unit_reqs (unit_reqs, loop->start_label,
+ PREV_INSN (loop->loop_end));
+ merge_unit_reqs (unit_reqs);
+
+ min_ii = res_mii (unit_reqs);
+ max_ii = loop_earliest < 15 ? loop_earliest : 14;
+
+ /* Make copies of the loop body, up to a maximum number of stages we want
+ to handle. */
+ max_parallel = loop_earliest / min_ii + 1;
+
+ copies = XCNEWVEC (rtx, (max_parallel + 1) * n_real_insns);
+ insn_copies = XNEWVEC (rtx *, max_parallel + 1);
+ for (i = 0; i < max_parallel + 1; i++)
+ insn_copies[i] = copies + i * n_real_insns;
+
+ head_insn = next_nonnote_nondebug_insn (loop->start_label);
+ tail_insn = prev_real_insn (BB_END (bb));
+
+ i = 0;
+ FOR_BB_INSNS (bb, insn)
+ if (NONDEBUG_INSN_P (insn) && insn != loop->loop_end)
+ insn_copies[0][i++] = insn;
+
+ sploop_max_uid_iter0 = get_max_uid ();
+
+ /* Generate the copies of the loop body, and save them in the
+ INSN_COPIES array. */
+ start_sequence ();
+ for (i = 0; i < max_parallel; i++)
+ {
+ int j;
+ rtx this_iter;
+
+ this_iter = duplicate_insn_chain (head_insn, tail_insn);
+ j = 0;
+ while (this_iter)
+ {
+ rtx prev_stage_insn = insn_copies[i][j];
+ gcc_assert (INSN_CODE (this_iter) == INSN_CODE (prev_stage_insn));
+
+ if (INSN_CODE (this_iter) >= 0
+ && (get_attr_type (this_iter) == TYPE_LOAD_SHADOW
+ || get_attr_type (this_iter) == TYPE_MULT_SHADOW))
+ {
+ rtx prev = PREV_INSN (this_iter);
+ record_delay_slot_pair (prev, this_iter,
+ get_attr_cycles (prev) - 1, 0);
+ }
+ else
+ record_delay_slot_pair (prev_stage_insn, this_iter, i, 1);
+
+ insn_copies[i + 1][j] = this_iter;
+ j++;
+ this_iter = next_nonnote_nondebug_insn (this_iter);
+ }
+ }
+ new_insns = get_insns ();
+ last_insn = insn_copies[max_parallel][n_real_insns - 1];
+ end_sequence ();
+ emit_insn_before (new_insns, BB_END (bb));
+
+ /* Try to schedule the loop using varying initiation intervals,
+ starting with the smallest possible and incrementing it
+ on failure. */
+ for (sp_ii = min_ii; sp_ii <= max_ii; sp_ii++)
+ {
+ basic_block tmp_bb;
+ if (dump_file)
+ fprintf (dump_file, "Trying to schedule for II %d\n", sp_ii);
+
+ df_clear_flags (DF_LR_RUN_DCE);
+
+ schedule_ebbs_init ();
+ set_modulo_params (sp_ii, max_parallel, n_real_insns,
+ sploop_max_uid_iter0);
+ tmp_bb = schedule_ebb (BB_HEAD (bb), last_insn, true);
+ schedule_ebbs_finish ();
+
+ if (tmp_bb)
+ {
+ if (dump_file)
+ fprintf (dump_file, "Found schedule with II %d\n", sp_ii);
+ break;
+ }
+ }
+
+ discard_delay_pairs_above (max_uid_before);
+
+ if (sp_ii > max_ii)
+ goto restore_loop;
+
+ stages = insn_get_clock (ss.last_scheduled_iter0) / sp_ii + 1;
+
+ if (stages == 1 && sp_ii > 5)
+ goto restore_loop;
+
+ /* At this point, we know we've been successful, unless we find later that
+ there are too many execute packets for the loop buffer to hold. */
+
+ /* Assign reservations to the instructions in the loop. We must find
+ the stage that contains the full loop kernel, and transfer the
+ reservations of the instructions contained in it to the corresponding
+ instructions from iteration 0, which are the only ones we'll keep. */
+ assign_reservations (BB_HEAD (bb), ss.last_scheduled_insn);
+ PREV_INSN (BB_END (bb)) = ss.last_scheduled_iter0;
+ NEXT_INSN (ss.last_scheduled_iter0) = BB_END (bb);
+ filter_insns_above (bb, sploop_max_uid_iter0);
+
+ for (i = 0; i < n_real_insns; i++)
+ {
+ rtx insn = insn_copies[0][i];
+ int uid = INSN_UID (insn);
+ int stage = insn_uid_get_clock (uid) / sp_ii;
+
+ if (stage + 1 < stages)
+ {
+ int copy_uid;
+ stage = stages - stage - 1;
+ copy_uid = INSN_UID (insn_copies[stage][i]);
+ INSN_INFO_ENTRY (uid).reservation
+ = INSN_INFO_ENTRY (copy_uid).reservation;
+ }
+ }
+ if (stages == 1)
+ stages++;
+
+ /* Compute the number of execute packets the pipelined form of the loop will
+ require. */
+ prev = NULL_RTX;
+ n_execute_packets = 0;
+ for (insn = loop->start_label; insn != loop->loop_end; insn = NEXT_INSN (insn))
+ {
+ if (NONDEBUG_INSN_P (insn) && GET_MODE (insn) == TImode
+ && !shadow_p (insn))
+ {
+ n_execute_packets++;
+ if (prev && insn_get_clock (prev) + 1 != insn_get_clock (insn))
+ /* We need an extra NOP instruction. */
+ n_execute_packets++;
+
+ prev = insn;
+ }
+ }
+
+ end_packet = ss.last_scheduled_iter0;
+ while (!NONDEBUG_INSN_P (end_packet) || GET_MODE (end_packet) != TImode)
+ end_packet = PREV_INSN (end_packet);
+
+ /* The earliest cycle in which we can emit the SPKERNEL instruction. */
+ loop_earliest = (stages - 1) * sp_ii;
+ if (loop_earliest > insn_get_clock (end_packet))
+ {
+ n_execute_packets++;
+ end_packet = loop->loop_end;
+ }
+ else
+ loop_earliest = insn_get_clock (end_packet);
+
+ if (n_execute_packets > 14)
+ goto restore_loop;
+
+ /* Generate the spkernel instruction, and place it at the appropriate
+ spot. */
+ PUT_MODE (end_packet, VOIDmode);
+
+ insn = gen_spkernel (GEN_INT (stages - 1),
+ const0_rtx, JUMP_LABEL (loop->loop_end));
+ insn = emit_jump_insn_before (insn, end_packet);
+ JUMP_LABEL (insn) = JUMP_LABEL (loop->loop_end);
+ insn_set_clock (insn, loop_earliest);
+ PUT_MODE (insn, TImode);
+ INSN_INFO_ENTRY (INSN_UID (insn)).ebb_start = false;
+ delete_insn (loop->loop_end);
+
+ /* Place the mvc and sploop instructions before the loop. */
+ entry_bb = entry_edge->src;
+
+ start_sequence ();
+
+ insn = emit_insn (gen_mvilc (loop->iter_reg));
+ insn = emit_insn (gen_sploop (GEN_INT (sp_ii)));
+
+ seq = get_insns ();
+
+ if (!single_succ_p (entry_bb) || vec_safe_length (loop->incoming) > 1)
+ {
+ basic_block new_bb;
+ edge e;
+ edge_iterator ei;
+
+ emit_insn_before (seq, BB_HEAD (loop->head));
+ seq = emit_label_before (gen_label_rtx (), seq);
+
+ new_bb = create_basic_block (seq, insn, entry_bb);
+ FOR_EACH_EDGE (e, ei, loop->incoming)
+ {
+ if (!(e->flags & EDGE_FALLTHRU))
+ redirect_edge_and_branch_force (e, new_bb);
+ else
+ redirect_edge_succ (e, new_bb);
+ }
+ make_edge (new_bb, loop->head, 0);
+ }
+ else
+ {
+ entry_after = BB_END (entry_bb);
+ while (DEBUG_INSN_P (entry_after)
+ || (NOTE_P (entry_after)
+ && NOTE_KIND (entry_after) != NOTE_INSN_BASIC_BLOCK))
+ entry_after = PREV_INSN (entry_after);
+ emit_insn_after (seq, entry_after);
+ }
+
+ end_sequence ();
+
+ /* Make sure we don't try to schedule this loop again. */
+ for (ix = 0; loop->blocks.iterate (ix, &bb); ix++)
+ bb->flags |= BB_DISABLE_SCHEDULE;
+
+ return true;
+
+ restore_loop:
+ if (dump_file)
+ fprintf (dump_file, "Unable to pipeline loop.\n");
+
+ for (i = 1; i < n_insns; i++)
+ {
+ NEXT_INSN (orig_vec[i - 1]) = orig_vec[i];
+ PREV_INSN (orig_vec[i]) = orig_vec[i - 1];
+ }
+ PREV_INSN (orig_vec[0]) = PREV_INSN (BB_HEAD (bb));
+ NEXT_INSN (PREV_INSN (BB_HEAD (bb))) = orig_vec[0];
+ NEXT_INSN (orig_vec[n_insns - 1]) = NEXT_INSN (BB_END (bb));
+ PREV_INSN (NEXT_INSN (BB_END (bb))) = orig_vec[n_insns - 1];
+ BB_HEAD (bb) = orig_vec[0];
+ BB_END (bb) = orig_vec[n_insns - 1];
+ undo_splits:
+ free_delay_pairs ();
+ FOR_BB_INSNS (bb, insn)
+ if (NONDEBUG_INSN_P (insn))
+ undo_split_delayed_nonbranch (insn);
+ return false;
+}
+
+/* A callback for the hw-doloop pass. Called when a loop we have discovered
+ turns out not to be optimizable; we have to split the doloop_end pattern
+ into a subtract and a test. */
+static void
+hwloop_fail (hwloop_info loop)
+{
+ rtx insn, test, testreg;
+
+ if (dump_file)
+ fprintf (dump_file, "splitting doloop insn %d\n",
+ INSN_UID (loop->loop_end));
+ insn = gen_addsi3 (loop->iter_reg, loop->iter_reg, constm1_rtx);
+ /* See if we can emit the add at the head of the loop rather than at the
+ end. */
+ if (loop->head == NULL
+ || loop->iter_reg_used_outside
+ || loop->iter_reg_used
+ || TEST_HARD_REG_BIT (loop->regs_set_in_loop, REGNO (loop->iter_reg))
+ || loop->incoming_dest != loop->head
+ || EDGE_COUNT (loop->head->preds) != 2)
+ emit_insn_before (insn, loop->loop_end);
+ else
+ {
+ rtx t = loop->start_label;
+ while (!NOTE_P (t) || NOTE_KIND (t) != NOTE_INSN_BASIC_BLOCK)
+ t = NEXT_INSN (t);
+ emit_insn_after (insn, t);
+ }
+
+ testreg = SET_DEST (XVECEXP (PATTERN (loop->loop_end), 0, 2));
+ if (GET_CODE (testreg) == SCRATCH)
+ testreg = loop->iter_reg;
+ else
+ emit_insn_before (gen_movsi (testreg, loop->iter_reg), loop->loop_end);
+
+ test = gen_rtx_NE (VOIDmode, testreg, const0_rtx);
+ insn = emit_jump_insn_before (gen_cbranchsi4 (test, testreg, const0_rtx,
+ loop->start_label),
+ loop->loop_end);
+
+ JUMP_LABEL (insn) = loop->start_label;
+ LABEL_NUSES (loop->start_label)++;
+ delete_insn (loop->loop_end);
+}
+
+static struct hw_doloop_hooks c6x_doloop_hooks =
+{
+ hwloop_pattern_reg,
+ hwloop_optimize,
+ hwloop_fail
+};
+
+/* Run the hw-doloop pass to modulo-schedule hardware loops, or split the
+ doloop_end patterns where such optimizations are impossible. */
+static void
+c6x_hwloops (void)
+{
+ if (optimize)
+ reorg_loops (true, &c6x_doloop_hooks);
+}
+
+/* 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);
+ df_note_add_problem ();
+
+ /* If optimizing, we'll have split before scheduling. */
+ if (optimize == 0)
+ split_all_insns ();
+
+ df_analyze ();
+
+ if (c6x_flag_schedule_insns2)
+ {
+ int sz = get_max_uid () * 3 / 2 + 1;
+
+ insn_info.create (sz);
+ }
+
+ /* Make sure the real-jump insns we create are not deleted. When modulo-
+ scheduling, situations where a reg is only stored in a loop can also
+ cause dead code when doing the initial unrolling. */
+ sched_no_dce = true;
+
+ c6x_hwloops ();
+
+ if (c6x_flag_schedule_insns2)
+ {
+ 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_FN (bb, cfun)
+ 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);
+
+ insn_info.release ();
+
+ if (!flag_inhibit_size_directive)
+ ASM_OUTPUT_MEASURED_SIZE (file, fname);
+}
+
+/* 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 opno, 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, 0, speed);
+ *total += rtx_cost (XEXP (op1, 0), code1, 0, 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, 0, speed);
+ *total += rtx_cost (op1, (enum rtx_code) code, 1, 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, 0, speed);
+ if (op1 && GET_CODE (op1) != REG
+ && (GET_CODE (op1) != SUBREG || GET_CODE (SUBREG_REG (op1)) != REG))
+ *total += rtx_cost (op1, MULT, 1, 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,
+ opno, 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;
+}
+
+/* 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 ();
+}
+
+/* Target unwind frame info is generated from dwarf CFI directives, so
+ always output dwarf2 unwind info. */
+
+static enum unwind_info_type
+c6x_debug_unwind_info (void)
+{
+ if (flag_unwind_tables || flag_exceptions)
+ return UI_DWARF2;
+
+ return default_debug_unwind_info ();
+}
+
+/* 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_DFA_NEW_CYCLE
+#define TARGET_SCHED_DFA_NEW_CYCLE c6x_dfa_new_cycle
+#undef TARGET_SCHED_DFA_PRE_CYCLE_INSN
+#define TARGET_SCHED_DFA_PRE_CYCLE_INSN c6x_sched_dfa_pre_cycle_insn
+#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_CLEAR_SCHED_CONTEXT
+#define TARGET_SCHED_CLEAR_SCHED_CONTEXT c6x_clear_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
+
+/* The C6x ABI follows the ARM EABI exception handling rules. */
+#undef TARGET_ARM_EABI_UNWINDER
+#define TARGET_ARM_EABI_UNWINDER true
+
+#undef TARGET_ASM_EMIT_EXCEPT_PERSONALITY
+#define TARGET_ASM_EMIT_EXCEPT_PERSONALITY c6x_asm_emit_except_personality
+
+#undef TARGET_ASM_INIT_SECTIONS
+#define TARGET_ASM_INIT_SECTIONS c6x_asm_init_sections
+
+#undef TARGET_DEBUG_UNWIND_INFO
+#define TARGET_DEBUG_UNWIND_INFO c6x_debug_unwind_info
+
+#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-4.9/gcc/config/c6x/c6x.h b/gcc-4.9/gcc/config/c6x/c6x.h
new file mode 100644
index 000000000..e0a60a971
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/c6x.h
@@ -0,0 +1,618 @@
+/* Target Definitions for TI C6X.
+ Copyright (C) 2010-2014 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_ABI_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 DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (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
+
+#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)))
+
+/* 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))
+
+struct GTY(()) machine_function
+{
+ /* True if we expanded a sibling call. */
+ int contains_sibcall;
+};
+
+/* Costs. */
+#define NO_FUNCTION_CSE 1
+
+#define SLOW_BYTE_ACCESS 0
+
+#define BRANCH_COST(speed_p, predictable_p) 6
+
+
+/* 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
+
+/* 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 unsigned 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
+
+#define CPU_UNITS_QUERY 1
+
+extern int c6x_initial_flag_pic;
+
+#endif /* GCC_C6X_H */
diff --git a/gcc-4.9/gcc/config/c6x/c6x.md b/gcc-4.9/gcc/config/c6x/c6x.md
new file mode 100644
index 000000000..53032b1f0
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/c6x.md
@@ -0,0 +1,3136 @@
+;; Machine description for TI C6X.
+;; Copyright (C) 2010-2014 Free Software Foundation, Inc.
+;; Contributed by Andrew Jenner <andrew@codesourcery.com>
+;; Contributed by Bernd Schmidt <bernds@codesourcery.com>
+;; Contributed by CodeSourcery.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>.
+
+
+;; Register names
+
+(define_constants
+ [(REG_A0 0)
+ (REG_A1 1)
+ (REG_A2 2)
+ (REG_A3 3)
+ (REG_A4 4)
+ (REG_A5 5)
+ (REG_A6 6)
+ (REG_A7 7)
+ (REG_A8 8)
+ (REG_A9 9)
+ (REG_A10 10)
+ (REG_A11 11)
+ (REG_A12 12)
+ (REG_A13 13)
+ (REG_A14 14)
+ (REG_A15 15)
+ (REG_A16 16)
+ (REG_A17 17)
+ (REG_A18 18)
+ (REG_A19 19)
+ (REG_A20 20)
+ (REG_A21 21)
+ (REG_A22 22)
+ (REG_A23 23)
+ (REG_A24 24)
+ (REG_A25 25)
+ (REG_A26 26)
+ (REG_A27 27)
+ (REG_A28 28)
+ (REG_A29 29)
+ (REG_A30 30)
+ (REG_A31 31)
+ (REG_B0 32)
+ (REG_B1 33)
+ (REG_B2 34)
+ (REG_B3 35)
+ (REG_B4 36)
+ (REG_B5 37)
+ (REG_B6 38)
+ (REG_B7 39)
+ (REG_B8 40)
+ (REG_B9 41)
+ (REG_B10 42)
+ (REG_B11 43)
+ (REG_B12 44)
+ (REG_B13 45)
+ (REG_B14 46)
+ (REG_SP 47)
+ (REG_B15 47)
+ (REG_B16 48)
+ (REG_B17 49)
+ (REG_B18 50)
+ (REG_B19 51)
+ (REG_B20 52)
+ (REG_B21 53)
+ (REG_B22 54)
+ (REG_B23 55)
+ (REG_B24 56)
+ (REG_B25 57)
+ (REG_B26 58)
+ (REG_B27 59)
+ (REG_B28 60)
+ (REG_B29 61)
+ (REG_B30 62)
+ (REG_B31 63)
+ (REG_FRAME 64)
+ (REG_ARGP 65)
+ (REG_ILC 66)])
+
+(define_c_enum "unspec" [
+ UNSPEC_NOP
+ UNSPEC_RCP
+ UNSPEC_MISALIGNED_ACCESS
+ UNSPEC_ADDKPC
+ UNSPEC_SETUP_DSBT
+ UNSPEC_LOAD_GOT
+ UNSPEC_LOAD_SDATA
+ UNSPEC_BITREV
+ UNSPEC_GOTOFF
+ UNSPEC_MVILC
+ UNSPEC_REAL_JUMP
+ UNSPEC_REAL_LOAD
+ UNSPEC_REAL_MULT
+ UNSPEC_JUMP_SHADOW
+ UNSPEC_LOAD_SHADOW
+ UNSPEC_MULT_SHADOW
+ UNSPEC_EPILOGUE_BARRIER
+ UNSPEC_ATOMIC
+ UNSPEC_CLR
+ UNSPEC_EXT
+ UNSPEC_EXTU
+ UNSPEC_SUBC
+ UNSPEC_AVG
+])
+
+(define_c_enum "unspecv" [
+ UNSPECV_BLOCKAGE
+ UNSPECV_SPLOOP
+ UNSPECV_SPKERNEL
+ UNSPECV_EH_RETURN
+ UNSPECV_CAS
+])
+
+;; -------------------------------------------------------------------------
+;; Instruction attributes
+;; -------------------------------------------------------------------------
+
+(define_attr "cpu"
+ "c62x,c64x,c64xp,c67x,c67xp,c674x"
+ (const (symbol_ref "(enum attr_cpu)c6x_arch")))
+
+;; Define a type for each insn which is used in the scheduling description.
+;; These correspond to the types defined in chapter 4 of the C674x manual.
+(define_attr "type"
+ "unknown,single,mpy2,store,storen,mpy4,load,loadn,branch,call,callp,dp2,fp4,
+ intdp,cmpdp,adddp,mpy,mpyi,mpyid,mpydp,mpyspdp,mpysp2dp,spkernel,sploop,
+ mvilc,blockage,shadow,load_shadow,mult_shadow,atomic"
+ (const_string "single"))
+
+;; The register file used by an instruction's destination register.
+;; The function destreg_file computes this; instructions can override the
+;; attribute if they aren't a single_set.
+(define_attr "dest_regfile"
+ "unknown,any,a,b"
+ (cond [(eq_attr "type" "single,load,mpy2,mpy4,dp2,fp4,intdp,cmpdp,adddp,mpy,mpyi,mpyid,mpydp,mpyspdp,mpysp2dp")
+ (cond [(match_operand 0 "a_register" "") (const_string "a")
+ (match_operand 0 "b_register" "") (const_string "b")]
+ (const_string "unknown"))
+ (eq_attr "type" "store")
+ (cond [(match_operand 1 "a_register" "") (const_string "a")
+ (match_operand 1 "b_register" "") (const_string "b")]
+ (const_string "unknown"))]
+ (const_string "unknown")))
+
+(define_attr "addr_regfile"
+ "unknown,a,b"
+ (const_string "unknown"))
+
+(define_attr "cross"
+ "n,y"
+ (const_string "n"))
+
+;; This describes the relationship between operands and register files.
+;; For example, "sxs" means that operands 0 and 2 determine the side of
+;; the machine, and operand 1 can optionally use the cross path. "dt" and
+;; "td" are used to describe loads and stores.
+;; Used for register renaming in loops for improving modulo scheduling.
+(define_attr "op_pattern"
+ "unknown,dt,td,sx,sxs,ssx"
+ (cond [(eq_attr "type" "load") (const_string "td")
+ (eq_attr "type" "store") (const_string "dt")]
+ (const_string "unknown")))
+
+(define_attr "has_shadow"
+ "n,y"
+ (const_string "n"))
+
+;; The number of cycles the instruction takes to finish. Any cycles above
+;; the first are delay slots.
+(define_attr "cycles" ""
+ (cond [(eq_attr "type" "branch,call") (const_int 6)
+ (eq_attr "type" "load,loadn") (const_int 5)
+ (eq_attr "type" "dp2") (const_int 2)
+ (eq_attr "type" "mpy2") (const_int 2)
+ (eq_attr "type" "mpy4") (const_int 4)
+ (eq_attr "type" "fp4") (const_int 4)
+ (eq_attr "type" "mvilc") (const_int 4)
+ (eq_attr "type" "cmpdp") (const_int 2)
+ (eq_attr "type" "intdp") (const_int 5)
+ (eq_attr "type" "adddp") (const_int 7)
+ (eq_attr "type" "mpydp") (const_int 10)
+ (eq_attr "type" "mpyi") (const_int 9)
+ (eq_attr "type" "mpyid") (const_int 10)
+ (eq_attr "type" "mpyspdp") (const_int 7)
+ (eq_attr "type" "mpysp2dp") (const_int 5)]
+ (const_int 1)))
+
+;; The number of cycles during which the instruction reserves functional
+;; units.
+(define_attr "reserve_cycles" ""
+ (cond [(eq_attr "type" "cmpdp") (const_int 2)
+ (eq_attr "type" "adddp") (const_int 2)
+ (eq_attr "type" "mpydp") (const_int 4)
+ (eq_attr "type" "mpyi") (const_int 4)
+ (eq_attr "type" "mpyid") (const_int 4)
+ (eq_attr "type" "mpyspdp") (const_int 2)]
+ (const_int 1)))
+
+(define_attr "predicable" "no,yes"
+ (const_string "yes"))
+
+(define_attr "enabled" "no,yes"
+ (const_string "yes"))
+
+;; Specify which units can be used by a given instruction. Normally,
+;; dest_regfile is used to select between the two halves of the machine.
+;; D_ADDR is for load/store instructions; they use the D unit and use
+;; addr_regfile to choose between D1 and D2.
+
+(define_attr "units62"
+ "unknown,d,d_addr,l,m,s,dl,ds,dls,ls"
+ (const_string "unknown"))
+
+(define_attr "units64"
+ "unknown,d,d_addr,l,m,s,dl,ds,dls,ls"
+ (const_string "unknown"))
+
+(define_attr "units64p"
+ "unknown,d,d_addr,l,m,s,dl,ds,dls,ls"
+ (attr "units64"))
+
+(define_attr "units67"
+ "unknown,d,d_addr,l,m,s,dl,ds,dls,ls"
+ (attr "units62"))
+
+(define_attr "units67p"
+ "unknown,d,d_addr,l,m,s,dl,ds,dls,ls"
+ (attr "units67"))
+
+(define_attr "units674"
+ "unknown,d,d_addr,l,m,s,dl,ds,dls,ls"
+ (attr "units64"))
+
+(define_attr "units"
+ "unknown,d,d_addr,l,m,s,dl,ds,dls,ls"
+ (cond [(eq_attr "cpu" "c62x")
+ (attr "units62")
+ (eq_attr "cpu" "c67x")
+ (attr "units67")
+ (eq_attr "cpu" "c67xp")
+ (attr "units67p")
+ (eq_attr "cpu" "c64x")
+ (attr "units64")
+ (eq_attr "cpu" "c64xp")
+ (attr "units64p")
+ (eq_attr "cpu" "c674x")
+ (attr "units674")
+ ]
+ (const_string "unknown")))
+
+(define_automaton "c6x_1,c6x_2,c6x_m1,c6x_m2,c6x_t1,c6x_t2,c6x_branch")
+(automata_option "no-comb-vect")
+(automata_option "ndfa")
+(automata_option "collapse-ndfa")
+
+(define_query_cpu_unit "d1,l1,s1" "c6x_1")
+(define_cpu_unit "x1" "c6x_1")
+(define_cpu_unit "l1w,s1w" "c6x_1")
+(define_query_cpu_unit "m1" "c6x_m1")
+(define_cpu_unit "m1w" "c6x_m1")
+(define_cpu_unit "t1" "c6x_t1")
+(define_query_cpu_unit "d2,l2,s2" "c6x_2")
+(define_cpu_unit "x2" "c6x_2")
+(define_cpu_unit "l2w,s2w" "c6x_2")
+(define_query_cpu_unit "m2" "c6x_m2")
+(define_cpu_unit "m2w" "c6x_m2")
+(define_cpu_unit "t2" "c6x_t2")
+;; A special set of units used to identify specific reservations, rather than
+;; just units.
+(define_query_cpu_unit "fps1,fpl1,adddps1,adddpl1" "c6x_1")
+(define_query_cpu_unit "fps2,fpl2,adddps2,adddpl2" "c6x_2")
+
+;; There can be up to two branches in one cycle (on the .s1 and .s2
+;; units), but some instructions must not be scheduled in parallel
+;; with a branch. We model this by reserving either br0 or br1 for a
+;; normal branch, and both of them for an insn such as callp.
+;; Another constraint is that two branches may only execute in parallel
+;; if one uses an offset, and the other a register. We can distinguish
+;; these by the dest_regfile attribute; it is "any" iff the branch uses
+;; an offset. br0 is reserved for these, while br1 is reserved for
+;; branches using a register.
+(define_cpu_unit "br0,br1" "c6x_branch")
+
+(include "c6x-sched.md")
+
+;; Some reservations which aren't generated from c6x-sched.md.in
+
+(define_insn_reservation "branch_s1any" 6
+ (and (eq_attr "type" "branch")
+ (and (eq_attr "cross" "n")
+ (and (eq_attr "units" "s")
+ (eq_attr "dest_regfile" "any"))))
+ "s1+s1w+br0")
+
+;; For calls, we also reserve the units needed in the following cycles
+;; to load the return address. There are two options; using addkpc or
+;; mvkh/mvkl. The code in c6x_reorg knows whether to use one of these
+;; or whether to use callp. The actual insns are emitted only after
+;; the final scheduling pass is complete.
+;; We always reserve S2 for PC-relative call insns, since that allows
+;; us to turn them into callp insns later on.
+(define_insn_reservation "call_addkpc_s1any" 6
+ (and (eq_attr "type" "call")
+ (and (ne (symbol_ref "TARGET_INSNS_64") (const_int 0))
+ (and (eq_attr "cross" "n")
+ (and (eq_attr "units" "s")
+ (eq_attr "dest_regfile" "any")))))
+ "s2+s2w+br0,s2+s2w+br0+br1")
+
+(define_insn_reservation "call_mvk_s1any" 6
+ (and (eq_attr "type" "call")
+ (and (eq (symbol_ref "TARGET_INSNS_64") (const_int 0))
+ (and (eq_attr "cross" "n")
+ (and (eq_attr "units" "s")
+ (eq_attr "dest_regfile" "any")))))
+ "s2+s2w+br0,s2+s2w,s2+s2w")
+
+(define_reservation "all" "s1+s2+d1+d2+l1+l2+m1+m2")
+
+(define_insn_reservation "callp_s1" 1
+ (and (eq_attr "type" "callp") (eq_attr "dest_regfile" "a"))
+ "s1+s1w,all*5")
+
+(define_insn_reservation "callp_s2" 1
+ (and (eq_attr "type" "callp") (eq_attr "dest_regfile" "b"))
+ "s2+s2w,all*5")
+
+;; Constraints
+
+(include "constraints.md")
+
+;; Predicates
+
+(include "predicates.md")
+
+;; General predication pattern.
+
+(define_cond_exec
+ [(match_operator 0 "eqne_operator"
+ [(match_operand 1 "predicate_register" "AB")
+ (const_int 0)])]
+ ""
+ "")
+
+;; -------------------------------------------------------------------------
+;; NOP instruction
+;; -------------------------------------------------------------------------
+
+(define_insn "nop"
+ [(const_int 0)]
+ ""
+ "nop")
+
+(define_insn "nop_count"
+ [(unspec [(match_operand 0 "const_int_operand" "n")] UNSPEC_NOP)]
+ ""
+ "%|%.\\tnop\\t%0")
+
+;; -------------------------------------------------------------------------
+;; Move instructions
+;; -------------------------------------------------------------------------
+
+(define_mode_iterator QIHIM [QI HI])
+(define_mode_iterator SIDIM [SI DI])
+(define_mode_iterator SIDIVM [SI DI V2HI V4QI])
+(define_mode_iterator VEC4M [V2HI V4QI])
+(define_mode_iterator VEC8M [V2SI V4HI V8QI])
+(define_mode_iterator SISFVM [SI SF V2HI V4QI])
+(define_mode_iterator DIDFM [DI DF])
+(define_mode_iterator DIDFVM [DI DF V2SI V4HI V8QI])
+(define_mode_iterator SFDFM [SF DF])
+(define_mode_iterator M32 [QI HI SI SF V2HI V4QI])
+
+;; The C6X LO_SUM and HIGH are backwards - HIGH sets the low bits, and
+;; LO_SUM adds in the high bits. Fortunately these are opaque operations
+;; so this does not matter.
+(define_insn "movsi_lo_sum"
+ [(set (match_operand:SI 0 "register_operand" "=ab")
+ (lo_sum:SI (match_operand:SI 1 "register_operand" "0")
+ (match_operand:SI 2 "const_int_or_symbolic_operand" "i")))]
+ "reload_completed"
+ "%|%.\\tmvkh\\t%$\\t%2, %0"
+ [(set_attr "units" "s")])
+
+(define_insn "movsi_high"
+ [(set (match_operand:SI 0 "register_operand" "=ab")
+ (high:SI (match_operand:SI 1 "const_int_or_symbolic_operand" "i")))]
+ "reload_completed"
+ "%|%.\\tmvkl\\t%$\\t%1, %0"
+ [(set_attr "units" "s")])
+
+(define_insn "movsi_gotoff_lo_sum"
+ [(set (match_operand:SI 0 "register_operand" "=ab")
+ (lo_sum:SI (match_operand:SI 1 "register_operand" "0")
+ (unspec:SI [(match_operand:SI 2 "symbolic_operand" "S2")]
+ UNSPEC_GOTOFF)))]
+ "flag_pic == 2"
+ "%|%.\\tmvkh\\t%$\\t$dpr_got%2, %0"
+ [(set_attr "units" "s")])
+
+(define_insn "movsi_gotoff_high"
+ [(set (match_operand:SI 0 "register_operand" "=ab")
+ (high:SI (unspec:SI [(match_operand:SI 1 "symbolic_operand" "S2")]
+ UNSPEC_GOTOFF)))]
+ "flag_pic == 2"
+ "%|%.\\tmvkl\\t%$\\t$dpr_got%1, %0"
+ [(set_attr "units" "s")])
+
+;; Normally we'd represent this as a normal load insn, but we can't currently
+;; represent the addressing mode.
+(define_insn "load_got_gotoff"
+ [(set (match_operand:SI 0 "register_operand" "=a,b")
+ (unspec:SI [(match_operand:SI 1 "register_operand" "Z,Z")
+ (match_operand:SI 2 "register_operand" "b,b")]
+ UNSPEC_GOTOFF))]
+ "flag_pic == 2"
+ "%|%.\\tldw\\t%$\\t*+%1[%2], %0"
+ [(set_attr "type" "load")
+ (set_attr "units" "d_addr")
+ (set_attr "op_pattern" "unknown")
+ (set_attr "dest_regfile" "a,b")
+ (set_attr "addr_regfile" "b")])
+
+(define_insn "*movstricthi_high"
+ [(set (match_operand:SI 0 "register_operand" "+ab")
+ (ior:SI (and:SI (match_dup 0) (const_int 65535))
+ (ashift:SI (match_operand:SI 1 "const_int_operand" "IuB")
+ (const_int 16))))]
+ "reload_completed"
+ "%|%.\\tmvklh\\t%$\\t%1, %0"
+ [(set_attr "units" "s")])
+
+;; Break up SImode loads of immediate operands.
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "const_int_operand" ""))]
+ "reload_completed
+ && !satisfies_constraint_IsB (operands[1])"
+ [(set (match_dup 0) (match_dup 2))
+ (set (match_dup 0) (ior:SI (and:SI (match_dup 0) (const_int 65535))
+ (ashift:SI (match_dup 3) (const_int 16))))]
+{
+ HOST_WIDE_INT val = INTVAL (operands[1]);
+ operands[2] = GEN_INT (trunc_int_for_mode (val, HImode));
+ operands[3] = GEN_INT ((val >> 16) & 65535);
+})
+
+(define_split
+ [(set (match_operand:VEC4M 0 "register_operand" "")
+ (match_operand:VEC4M 1 "const_vector_operand" ""))]
+ "reload_completed"
+ [(set (match_dup 2) (match_dup 3))]
+{
+ unsigned HOST_WIDE_INT mask, val;
+ 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 "op_pattern" "unknown")
+ (set_attr "predicable" "no")])
+
+;; Move instruction patterns
+
+(define_mode_attr LDST_SUFFIX [(QI "b") (HI "h")
+ (SI "w") (SF "w") (V2HI "w") (V4QI "w")
+ (DI "dw") (V2SI "dw") (V4HI "dw") (V8QI "dw")])
+
+(define_insn "mov<mode>_insn"
+ [(set (match_operand:QIHIM 0 "nonimmediate_operand"
+ "=a,b, a, b, ab, ab,a,?a, b,?b, Q, R, R, Q")
+ (match_operand:QIHIM 1 "general_operand"
+ "a,b,?b,?a,Is5,IsB,Q, R, R, Q, a,?a, b,?b"))]
+ "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) == REG"
+ "@
+ %|%.\\tmv\\t%$\\t%1, %0
+ %|%.\\tmv\\t%$\\t%1, %0
+ %|%.\\tmv\\t%$\\t%1, %0
+ %|%.\\tmv\\t%$\\t%1, %0
+ %|%.\\tmvk\\t%$\\t%1, %0
+ %|%.\\tmvk\\t%$\\t%1, %0
+ %|%.\\tld<LDST_SUFFIX>\\t%$\\t%1, %0
+ %|%.\\tld<LDST_SUFFIX>\\t%$\\t%1, %0
+ %|%.\\tld<LDST_SUFFIX>\\t%$\\t%1, %0
+ %|%.\\tld<LDST_SUFFIX>\\t%$\\t%1, %0
+ %|%.\\tst<LDST_SUFFIX>\\t%$\\t%1, %0
+ %|%.\\tst<LDST_SUFFIX>\\t%$\\t%1, %0
+ %|%.\\tst<LDST_SUFFIX>\\t%$\\t%1, %0
+ %|%.\\tst<LDST_SUFFIX>\\t%$\\t%1, %0"
+ [(set_attr "type" "*,*,*,*,*,*,load,load,load,load,store,store,store,store")
+ (set_attr "units62" "dls,dls,ls,ls,s,s,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr")
+ (set_attr "units64" "dls,dls,ls,ls,dl,s,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr")
+ (set_attr "op_pattern" "sx,sx,sx,sx,*,*,*,*,*,*,*,*,*,*")
+ (set_attr "addr_regfile" "*,*,*,*,*,*,a,b,b,a,a,b,b,a")
+ (set_attr "dest_regfile" "*,*,*,*,*,*,a,a,b,b,a,a,b,b")
+ (set_attr "cross" "n,n,y,y,n,n,n,y,n,y,n,y,n,y")])
+
+(define_insn "mov<mode>_insn"
+ [(set (match_operand:SISFVM 0 "nonimmediate_operand"
+ "=a,b, a, b, ab, ab,a,b,ab,a,?a, b,?b, Q, R, R, Q")
+ (match_operand:SISFVM 1 "general_operand"
+ "a,b,?b,?a,Is5,IsB,S0,S0,Si,Q, R, R, Q, a,?a, b,?b"))]
+ "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) == REG
+ || (GET_CODE (operands[1]) == SUBREG && REG_P (SUBREG_REG (operands[1]))))"
+ "@
+ %|%.\\tmv\\t%$\\t%1, %0
+ %|%.\\tmv\\t%$\\t%1, %0
+ %|%.\\tmv\\t%$\\t%1, %0
+ %|%.\\tmv\\t%$\\t%1, %0
+ %|%.\\tmvk\\t%$\\t%1, %0
+ %|%.\\tmvk\\t%$\\t%1, %0
+ %|%.\\tadda%D1\\t%$\\tB14, %1, %0
+ %|%.\\tadda%D1\\t%$\\tB14, %1, %0
+ #
+ %|%.\\tldw\\t%$\\t%1, %0
+ %|%.\\tldw\\t%$\\t%1, %0
+ %|%.\\tldw\\t%$\\t%1, %0
+ %|%.\\tldw\\t%$\\t%1, %0
+ %|%.\\tstw\\t%$\\t%1, %0
+ %|%.\\tstw\\t%$\\t%1, %0
+ %|%.\\tstw\\t%$\\t%1, %0
+ %|%.\\tstw\\t%$\\t%1, %0"
+ [(set_attr "type" "*,*,*,*,*,*,*,*,*,load,load,load,load,store,store,store,store")
+ (set_attr "units62" "dls,dls,ls,ls,s,s,d,d,*,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr")
+ (set_attr "units64" "dls,dls,ls,ls,dl,s,d,d,*,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr")
+ (set_attr "op_pattern" "sx,sx,sx,sx,*,*,*,*,*,*,*,*,*,*,*,*,*")
+ (set_attr "addr_regfile" "*,*,*,*,*,*,*,*,*,a,b,b,a,a,b,b,a")
+ (set_attr "dest_regfile" "*,*,*,*,*,*,*,*,*,a,a,b,b,a,a,b,b")
+ (set_attr "cross" "n,n,y,y,n,n,y,n,*,n,y,n,y,n,y,n,y")
+ (set_attr "predicable" "yes,yes,yes,yes,yes,yes,no,no,yes,yes,yes,yes,yes,yes,yes,yes,yes")])
+
+(define_insn "*mov<mode>_insn"
+ [(set (match_operand:DIDFVM 0 "nonimmediate_operand"
+ "=a,b, a, b,ab,a,?a, b,?b, Q, R, R, Q")
+ (match_operand:DIDFVM 1 "general_operand"
+ "a,b,?b,?a,iF,Q, R, R, Q, a,?a, b,?b"))]
+ "(!MEM_P (operands[0]) || REG_P (operands[1])
+ || (GET_CODE (operands[1]) == SUBREG && REG_P (SUBREG_REG (operands[1]))))"
+{
+ if (MEM_P (operands[1]) && TARGET_LDDW)
+ return "%|%.\\tlddw\\t%$\\t%1, %0";
+ if (MEM_P (operands[0]) && TARGET_STDW)
+ return "%|%.\\tstdw\\t%$\\t%1, %0";
+ if (TARGET_INSNS_64PLUS && REG_P (operands[0]) && REG_P (operands[1])
+ && A_REGNO_P (REGNO (operands[0])) == A_REGNO_P (REGNO (operands[1])))
+ return "%|%.\\tdmv\\t%$\\t%P1, %p1, %0";
+ return "#";
+}
+ [(set_attr "units" "s,s,*,*,*,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr")
+ (set_attr "addr_regfile" "*,*,*,*,*,a,b,b,a,a,b,b,a")
+ (set_attr "dest_regfile" "*,*,*,*,*,a,a,b,b,a,a,b,b")
+ (set_attr "type" "*,*,*,*,*,load,load,load,load,store,store,store,store")
+ (set_attr "cross" "n,n,y,y,*,n,y,n,y,n,y,n,y")])
+
+(define_split
+ [(set (match_operand:DIDFVM 0 "nonimmediate_operand" "")
+ (match_operand:DIDFVM 1 "general_operand" ""))]
+ "reload_completed
+ && !((MEM_P (operands[0]) && TARGET_STDW)
+ || (MEM_P (operands[1]) && TARGET_LDDW))
+ && !const_vector_operand (operands[1], <MODE>mode)
+ && !(TARGET_INSNS_64PLUS && REG_P (operands[0]) && REG_P (operands[1])
+ && A_REGNO_P (REGNO (operands[0])) == A_REGNO_P (REGNO (operands[1])))"
+ [(set (match_dup 2) (match_dup 3))
+ (set (match_dup 4) (match_dup 5))]
+{
+ rtx lo_half[2], hi_half[2];
+ split_di (operands, 2, lo_half, hi_half);
+
+ /* We can't have overlap for a register-register move, but if
+ memory is involved, we have to make sure we don't clobber the
+ address. */
+ if (reg_overlap_mentioned_p (lo_half[0], hi_half[1]))
+ {
+ operands[2] = hi_half[0];
+ operands[3] = hi_half[1];
+ operands[4] = lo_half[0];
+ operands[5] = lo_half[1];
+ }
+ else
+ {
+ operands[2] = lo_half[0];
+ operands[3] = lo_half[1];
+ operands[4] = hi_half[0];
+ operands[5] = hi_half[1];
+ }
+})
+
+(define_insn "real_load<mode>"
+ [(unspec [(match_operand 0 "const_int_operand" "JA,JA,JB,JB")
+ (match_operand:M32 1 "memory_operand" "Q,R,R,Q")]
+ UNSPEC_REAL_LOAD)]
+ ""
+ "%|%.\\tld<LDST_SUFFIX>\\t%$\\t%1, %k0"
+ [(set_attr "type" "load")
+ (set_attr "units" "d_addr")
+ (set_attr "addr_regfile" "a,b,b,a")
+ (set_attr "dest_regfile" "a,a,b,b")
+ (set_attr "cross" "n,y,n,y")])
+
+(define_insn "real_load<mode>"
+ [(unspec [(match_operand 0 "const_int_operand" "JA,JA,JB,JB")
+ (match_operand:DIDFVM 1 "memory_operand" "Q,R,R,Q")]
+ UNSPEC_REAL_LOAD)]
+ "TARGET_LDDW"
+ "%|%.\\tlddw\\t%$\\t%1, %K0"
+ [(set_attr "type" "load")
+ (set_attr "units" "d_addr")
+ (set_attr "addr_regfile" "a,b,b,a")
+ (set_attr "dest_regfile" "a,a,b,b")
+ (set_attr "cross" "n,y,n,y")])
+
+(define_insn "load_shadow"
+ [(set (match_operand 0 "register_operand" "=ab")
+ (unspec [(pc)] UNSPEC_LOAD_SHADOW))]
+ ""
+ ";; load to %0 occurs"
+ [(set_attr "type" "load_shadow")])
+
+(define_insn "mult_shadow"
+ [(set (match_operand 0 "register_operand" "=ab")
+ (unspec [(pc)] UNSPEC_MULT_SHADOW))]
+ ""
+ ";; multiplication occurs and stores to %0"
+ [(set_attr "type" "mult_shadow")])
+
+
+(define_mode_iterator MOV [QI HI SI SF DI DF V2HI V4QI V2SI V4HI V8QI])
+
+(define_expand "mov<mode>"
+ [(set (match_operand:MOV 0 "nonimmediate_operand" "")
+ (match_operand:MOV 1 "general_operand" ""))]
+ ""
+{
+ if (expand_move (operands, <MODE>mode))
+ DONE;
+})
+
+(define_expand "movmisalign<mode>"
+ [(set (match_operand:SIDIVM 0 "nonimmediate_operand" "")
+ (unspec:SIDIVM [(match_operand:SIDIVM 1 "nonimmediate_operand" "")]
+ UNSPEC_MISALIGNED_ACCESS))]
+ "TARGET_INSNS_64"
+{
+ if (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;
+ }"
+)
+
+;; -------------------------------------------------------------------------
+;; Doloop
+;; -------------------------------------------------------------------------
+
+; operand 0 is the loop count pseudo register
+; operand 1 is the label to jump to at the top of the loop
+(define_expand "doloop_end"
+ [(parallel [(set (pc) (if_then_else
+ (ne (match_operand:SI 0 "" "")
+ (const_int 1))
+ (label_ref (match_operand 1 "" ""))
+ (pc)))
+ (set (match_dup 0)
+ (plus:SI (match_dup 0)
+ (const_int -1)))
+ (clobber (match_dup 2))])] ; match_scratch
+ "TARGET_INSNS_64PLUS && optimize"
+{
+ /* The loop optimizer doesn't check the predicates... */
+ if (GET_MODE (operands[0]) != SImode)
+ FAIL;
+ operands[2] = gen_rtx_SCRATCH (SImode);
+})
+
+(define_insn "mvilc"
+ [(set (reg:SI REG_ILC)
+ (unspec [(match_operand:SI 0 "register_operand" "a,b")] UNSPEC_MVILC))]
+ "TARGET_INSNS_64PLUS"
+ "%|%.\\tmvc\\t%$\\t%0, ILC"
+ [(set_attr "predicable" "no")
+ (set_attr "cross" "y,n")
+ (set_attr "units" "s")
+ (set_attr "dest_regfile" "b")
+ (set_attr "type" "mvilc")])
+
+(define_insn "sploop"
+ [(unspec_volatile [(match_operand:SI 0 "const_int_operand" "i")
+ (reg:SI REG_ILC)]
+ UNSPECV_SPLOOP)]
+ "TARGET_INSNS_64PLUS"
+ "%|%.\\tsploop\t%0"
+ [(set_attr "predicable" "no")
+ (set_attr "type" "sploop")])
+
+(define_insn "spkernel"
+ [(set (pc)
+ (if_then_else
+ (ne (unspec_volatile:SI
+ [(match_operand:SI 0 "const_int_operand" "i")
+ (match_operand:SI 1 "const_int_operand" "i")]
+ UNSPECV_SPKERNEL)
+ (const_int 1))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))]
+ "TARGET_INSNS_64PLUS"
+ "%|%.\\tspkernel\t%0, %1"
+ [(set_attr "predicable" "no")
+ (set_attr "type" "spkernel")])
+
+(define_insn "loop_end"
+ [(set (pc)
+ (if_then_else (ne (match_operand:SI 3 "nonimmediate_operand" "0,0,0,*r")
+ (const_int 1))
+ (label_ref (match_operand 1 "" ""))
+ (pc)))
+ (set (match_operand:SI 0 "nonimmediate_operand" "=AB,*r,m,m")
+ (plus:SI (match_dup 3)
+ (const_int -1)))
+ (clobber (match_scratch:SI 2 "=X,&AB,&AB,&AB"))]
+ "TARGET_INSNS_64PLUS && optimize"
+ "#"
+ [(set_attr "type" "spkernel")])
+
+(define_split
+ [(set (pc)
+ (if_then_else (ne (match_operand:SI 3 "nonimmediate_operand" "")
+ (const_int 1))
+ (label_ref (match_operand 1 "" ""))
+ (pc)))
+ (set (match_operand:SI 0 "memory_operand" "")
+ (plus:SI (match_dup 3)
+ (const_int -1)))
+ (clobber (match_scratch 2))]
+ ""
+ [(set (match_dup 2) (plus:SI (match_dup 3) (const_int -1)))
+ (set (match_dup 0) (match_dup 2))
+ (set (pc)
+ (if_then_else (ne (match_dup 2) (const_int 0))
+ (label_ref (match_dup 1))
+ (pc)))]
+{
+ if (!REG_P (operands[3]))
+ {
+ emit_move_insn (operands[2], operands[3]);
+ operands[3] = operands[2];
+ }
+})
+
+;; -------------------------------------------------------------------------
+;; Delayed-branch real jumps and shadows
+;; -------------------------------------------------------------------------
+
+(define_insn "real_jump"
+ [(unspec [(match_operand 0 "c6x_jump_operand" "a,b,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")])
+
+;; computed_jump_p returns true if it finds a constant; so use one in the
+;; unspec.
+(define_insn "indirect_jump_shadow"
+ [(set (pc) (unspec [(const_int 1)] UNSPEC_JUMP_SHADOW))]
+ ""
+ ";; indirect jump occurs"
+ [(set_attr "type" "shadow")])
+
+;; Operand 0 may be a PARALLEL which isn't handled by output_operand, so
+;; we don't try to print it.
+(define_insn "indirect_call_value_shadow"
+ [(set (match_operand 0 "" "")
+ (call (unspec [(pc)] UNSPEC_JUMP_SHADOW)
+ (const_int 0)))]
+ ""
+ ";; indirect call occurs, with return value"
+ [(set_attr "type" "shadow")])
+
+(define_insn "indirect_sibcall_shadow"
+ [(call (unspec [(pc)] UNSPEC_JUMP_SHADOW)
+ (const_int 0))]
+ "SIBLING_CALL_P (insn)"
+ ";; indirect sibcall occurs"
+ [(set_attr "type" "shadow")])
+
+(define_insn "indirect_call_shadow"
+ [(call (unspec [(pc)] UNSPEC_JUMP_SHADOW)
+ (const_int 0))]
+ ""
+ ";; indirect call occurs"
+ [(set_attr "type" "shadow")])
+
+(define_insn "call_value_shadow"
+ [(set (match_operand 0 "" "")
+ (call (unspec [(match_operand 1 "" "")] UNSPEC_JUMP_SHADOW)
+ (const_int 0)))]
+ ""
+ ";; call to %1 occurs, with return value"
+ [(set_attr "type" "shadow")])
+
+(define_insn "call_shadow"
+ [(call (unspec [(match_operand 0 "" "")] UNSPEC_JUMP_SHADOW)
+ (const_int 0))]
+ "!SIBLING_CALL_P (insn)"
+ ";; call to %0 occurs"
+ [(set_attr "type" "shadow")])
+
+(define_insn "sibcall_shadow"
+ [(call (unspec [(match_operand 0 "" "")] UNSPEC_JUMP_SHADOW)
+ (const_int 0))]
+ "SIBLING_CALL_P (insn)"
+ ";; sibcall to %0 occurs"
+ [(set_attr "type" "shadow")])
+
+(define_insn "jump_shadow"
+ [(set (pc) (unspec [(match_operand 0 "" "")] UNSPEC_JUMP_SHADOW))]
+ ""
+ ";; jump to %0 occurs"
+ [(set_attr "type" "shadow")])
+
+(define_insn "condjump_shadow"
+ [(set (pc)
+ (if_then_else (eq (unspec [(const_int 0)] UNSPEC_JUMP_SHADOW)
+ (const_int 0))
+ (match_operand 0 "" "")
+ (pc)))]
+ ""
+ ";; condjump to %0 occurs"
+ [(set_attr "type" "shadow")])
+
+(define_insn "return_shadow"
+ [(unspec [(const_int 0)] UNSPEC_JUMP_SHADOW)
+ (return)]
+ ""
+ ";; return occurs"
+ [(set_attr "type" "shadow")])
+
+;; -------------------------------------------------------------------------
+;; Add instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "addsi3"
+ [(set (match_operand:SI 0 "register_operand"
+ "=a ,b , a, b, a, b, a, b, ab, a, b, a, b,ab")
+ (plus:SI (match_operand:SI 1 "register_operand"
+ "%a ,b , a, b, b, a, b, a, 0, a, b, z, z,0")
+ (match_operand:SI 2 "addsi_operand"
+ "aIs5,bIs5,?b,?a,?a,?b,?aIs5,?bIs5,I5x,I5x,I5x,Iux,Iux,IsB")))]
+ ""
+{
+ if (CONSTANT_P (operands[2]))
+ {
+ HOST_WIDE_INT val = INTVAL (operands[2]);
+
+ if (c6x_get_unit_specifier (insn) == 'd')
+ {
+ bool issp = (TARGET_INSNS_64PLUS
+ && operands[1] == stack_pointer_rtx
+ && GET_CODE (PATTERN (insn)) != COND_EXEC);
+
+ if (get_attr_cross (insn) == CROSS_N)
+ {
+ if (satisfies_constraint_Iu5 (operands[2]))
+ return "%|%.\\tadd\\t%$\\t%1, %2, %0";
+ else if (satisfies_constraint_In5 (operands[2]))
+ return "%|%.\\tsub\\t%$\\t%1, %n2, %0";
+ }
+
+ if (issp && val > 0 && val < 32768)
+ {
+ return "%|%.\\taddab\\t%$\\t%1, %2, %0";
+ }
+ if ((val & 1) == 0 && ((val >= -62 && val <= 62)
+ || (issp && val > 0 && val < 65536)))
+ {
+ if (val < 0)
+ return "%|%.\\tsubah\\t%$\\t%1, %r2, %0";
+ else
+ return "%|%.\\taddah\\t%$\\t%1, %r2, %0";
+ }
+ else if ((val & 3) == 0 && ((val >= -124 && val <= 124)
+ || (issp && val > 0 && val < 131072)))
+ {
+ if (val < 0)
+ return "%|%.\\tsubaw\\t%$\\t%1, %R2, %0";
+ else
+ return "%|%.\\taddaw\\t%$\\t%1, %R2, %0";
+ }
+ else if ((val & 7) == 0 && val > 0 && val <= 248)
+ {
+ rtx xop[3];
+ xop[0] = operands[0];
+ xop[1] = operands[1];
+ xop[2] = GEN_INT (val >> 3);
+ output_asm_insn ("%|%.\\taddad\\t%$\\t%1, %2, %0", xop);
+ return "";
+ }
+ }
+ else
+ {
+ if (satisfies_constraint_Is5 (operands[2]))
+ return "%|%.\\tadd\\t%$\\t%2, %1, %0";
+ }
+ gcc_assert (rtx_equal_p (operands[0], operands[1]));
+ return "%|%.\\taddk\\t%$\\t%2, %0";
+ }
+ if (which_alternative == 4 || which_alternative == 5)
+ return "%|%.\\tadd\\t%$\\t%2, %1, %0";
+ else
+ return "%|%.\\tadd\\t%$\\t%1, %2, %0";
+}
+ [(set_attr "units62" "dls,dls,ls,ls,ls,ls,ls,ls,s,d,d,*,*,s")
+ (set_attr "units67" "dls,dls,ls,ls,ls,ls,ls,ls,ds,d,d,*,*,s")
+ (set_attr "units64" "dls,dls,dls,dls,dls,dls,ls,ls,ds,d,d,d,d,s")
+ (set_attr "cross" "n,n,y,y,y,y,y,y,n,n,n,y,n,n")
+ (set_attr "predicable" "yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,no,no,yes")])
+
+(define_insn "subsi3"
+ [(set (match_operand:SI 0 "register_operand" "=a,b,a,b,a,b")
+ (minus:SI (match_operand:SI 1 "reg_or_scst5_operand" "a,b,aIs5,bIs5,bIs5,aIs5")
+ (match_operand:SI 2 "register_operand" "a,b,a,b,?a,?b")))]
+ ""
+ "%|%.\\tsub\\t%$\\t%1, %2, %0"
+ [(set_attr "units62" "dls,dls,ls,ls,l,l")
+ (set_attr "units64" "dls,dls,ls,ls,ls,ls")
+ (set_attr "cross" "n,n,n,n,y,y")])
+
+(define_insn "*addshiftsi"
+ [(set (match_operand:SI 0 "register_operand" "=a,b")
+ (plus:SI (mult:SI (match_operand:SI 2 "register_operand" "a,b")
+ (match_operand:SI 3 "adda_scale_operand" "n,n"))
+ (match_operand:SI 1 "register_operand" "a,b")))]
+ ""
+ "%|%.\\tadda%d3\\t%$\\t%1, %2, %0"
+ [(set_attr "units" "d")])
+
+(define_insn "*subshiftsi"
+ [(set (match_operand:SI 0 "register_operand" "=a,b")
+ (minus:SI (match_operand:SI 1 "register_operand" "a,b")
+ (mult:SI (match_operand:SI 2 "register_operand" "a,b")
+ (match_operand:SI 3 "suba_scale_operand" "n,n"))))]
+ ""
+ "%|%.\\tsuba%d3\\t%$\\t%1, %2, %0"
+ [(set_attr "units" "d")])
+
+(define_insn "addsidi3_widen"
+ [(set (match_operand:DI 0 "register_operand" "=a,b,a,b")
+ (plus:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%a,b,a,b"))
+ (zero_extend:DI (match_operand:SI 2 "register_operand" "a,b,?b,?a"))))]
+ ""
+ "%|%.\\taddu\\t%$\\t%1, %2, %0"
+ [(set_attr "units" "l")
+ (set_attr "cross" "n,n,y,y")])
+
+(define_expand "adddi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "register_operand" "")))]
+ ""
+{
+ rtx tmp;
+ rtx lo_half[3], hi_half[3];
+ split_di (operands + 1, 2, lo_half + 1, hi_half + 1);
+ if (reg_overlap_mentioned_p (operands[0], hi_half[1])
+ || reg_overlap_mentioned_p (operands[0], hi_half[2]))
+ tmp = gen_reg_rtx (DImode);
+ else
+ tmp = operands[0];
+ split_di (&tmp, 1, lo_half, hi_half);
+ emit_insn (gen_addsidi3_widen (tmp, lo_half[1], lo_half[2]));
+ emit_insn (gen_addsi3 (hi_half[0], copy_rtx (hi_half[0]), hi_half[1]));
+ emit_insn (gen_addsi3 (copy_rtx (hi_half[0]),
+ copy_rtx (hi_half[0]), hi_half[2]));
+ if (tmp != operands[0])
+ emit_move_insn (operands[0], tmp);
+ DONE;
+})
+
+(define_insn "addsf3"
+ [(set (match_operand:SF 0 "register_operand" "=a,b,a,b")
+ (plus:SF (match_operand:SF 1 "register_operand" "%a,b,a,b")
+ (match_operand:SF 2 "register_operand" "a,b,?b,?a")))]
+ "TARGET_FP"
+ "%|%.\\taddsp\\t%$\\t%1, %2, %0"
+ [(set_attr "type" "fp4")
+ (set_attr "units67" "l")
+ (set_attr "units67p" "ls")
+ (set_attr "units674" "ls")
+ (set_attr "cross" "n,n,y,y")])
+
+(define_insn "adddf3"
+ [(set (match_operand:DF 0 "register_operand" "=a,b,a,b")
+ (plus:DF (match_operand:DF 1 "register_operand" "%a,b,a,b")
+ (match_operand:DF 2 "register_operand" "a,b,?b,?a")))]
+ "TARGET_FP"
+ "%|%.\\tadddp\\t%$\\t%1, %2, %0"
+ [(set_attr "type" "adddp")
+ (set_attr "units67" "l")
+ (set_attr "units67p" "ls")
+ (set_attr "units674" "ls")
+ (set_attr "cross" "n,n,y,y")])
+
+(define_insn "subsf3"
+ [(set (match_operand:SF 0 "register_operand" "=a,b, a, b, a, b")
+ (minus:SF (match_operand:SF 1 "register_operand" "a,b, b, a, a, b")
+ (match_operand:SF 2 "register_operand" "a,b,?a,?b,?b,?a")))]
+ "TARGET_FP"
+ "%|%.\\tsubsp\\t%$\\t%1, %2, %0"
+ [(set_attr "type" "fp4")
+ (set_attr "units67" "l")
+ (set_attr "units67p" "ls")
+ (set_attr "units674" "ls")
+ (set_attr "cross" "n,n,y,y,y,y")])
+
+(define_insn "subdf3"
+ [(set (match_operand:DF 0 "register_operand" "=a,b, a, b, a, b")
+ (minus:DF (match_operand:DF 1 "register_operand" "a,b, b, a, a, b")
+ (match_operand:DF 2 "register_operand" "a,b,?a,?b,?b,?a")))]
+ "TARGET_FP"
+ "%|%.\\tsubdp\\t%$\\t%1, %2, %0"
+ [(set_attr "type" "adddp")
+ (set_attr "units67" "l")
+ (set_attr "units67p" "ls")
+ (set_attr "units674" "ls")
+ (set_attr "cross" "n,n,y,y,y,y")])
+
+;; -------------------------------------------------------------------------
+;; Logical instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "andsi3"
+ [(set (match_operand:SI 0 "register_operand" "=a,b,a,b,a,b")
+ (and:SI (match_operand:SI 1 "register_operand" "%a,b,b,a,a,b")
+ (match_operand:SI 2 "andsi_operand" "aIs5,bIs5,?aIs5,?bIs5,aJc,bJc")))]
+ ""
+{
+ if (which_alternative < 4)
+ return "%|%.\\tand\\t%$\\t%2, %1, %0";
+ else
+ return "%|%.\\tclr\\t%$\\t%1, %f2, %F2, %0";
+}
+ [(set_attr "units62" "ls,ls,ls,ls,s,s")
+ (set_attr "units64" "dls,dls,dls,dls,s,s")
+ (set_attr "cross" "n,n,y,y,n,n")])
+
+(define_insn "iorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=a,b,a,b,a,b")
+ (ior:SI (match_operand:SI 1 "register_operand" "%a,b,b,a,a,b")
+ (match_operand:SI 2 "iorsi_operand" "aIs5,bIs5,?aIs5,?bIs5,aJs,bJs")))]
+ ""
+{
+ if (which_alternative < 4)
+ return "%|%.\\tor\\t%$\\t%2, %1, %0";
+ else
+ return "%|%.\\tset\\t%$\\t%1, %s2, %S2, %0";
+}
+ [(set_attr "units62" "ls,ls,ls,ls,s,s")
+ (set_attr "units64" "dls,dls,dls,dls,s,s")
+ (set_attr "cross" "n,n,y,y,n,n")])
+
+(define_insn "xorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+ (xor:SI (match_operand:SI 1 "register_operand" "%a,b,b,a")
+ (match_operand:SI 2 "reg_or_scst5_operand" "aIs5,bIs5,?aIs5,?bIs5")))]
+ ""
+ "%|%.\\txor\\t%$\\t%2, %1, %0"
+ [(set_attr "units62" "ls")
+ (set_attr "units64" "dls")
+ (set_attr "cross" "n,n,y,y")])
+
+;; -------------------------------------------------------------------------
+;; Conversions
+;; -------------------------------------------------------------------------
+
+(define_insn "extendsfdf2"
+ [(set (match_operand:DF 0 "register_operand" "=a,b,a,b")
+ (float_extend:DF (match_operand:SF 1 "register_operand" "a,b,?b,?a")))]
+ "TARGET_FP"
+ "%|%.\\tspdp\\t%$\\t%1,%0"
+ [(set_attr "type" "dp2")
+ (set_attr "units" "s")
+ (set_attr "cross" "n,n,y,y")])
+
+(define_insn "truncdfsf2"
+ [(set (match_operand:SF 0 "register_operand" "=a,b")
+ (float_truncate:SF (match_operand:DF 1 "register_operand" "a,b")))]
+ "TARGET_FP"
+ "%|%.\\tdpsp\\t%$\\t%1,%0"
+ [(set_attr "type" "fp4")
+ (set_attr "units" "l")
+ (set_attr "cross" "n")])
+
+;;;; Convert between signed integer types and floating point.
+(define_insn "floatsisf2"
+ [(set (match_operand:SF 0 "register_operand" "=a,b,a,b")
+ (float:SF (match_operand:SI 1 "register_operand" "a,b,?b,?a")))]
+ "TARGET_FP"
+ "%|%.\\tintsp\\t%$\\t%1,%0"
+ [(set_attr "type" "fp4")
+ (set_attr "units" "l")
+ (set_attr "cross" "n,n,y,y")])
+
+(define_insn "floatunssisf2"
+ [(set (match_operand:SF 0 "register_operand" "=a,b,a,b")
+ (unsigned_float:SF (match_operand:SI 1 "register_operand" "a,b,?b,?a")))]
+ "TARGET_FP"
+ "%|%.\\tintspu\\t%$\\t%1,%0"
+ [(set_attr "type" "fp4")
+ (set_attr "units" "l")
+ (set_attr "cross" "n,n,y,y")])
+
+(define_insn "floatsidf2"
+ [(set (match_operand:DF 0 "register_operand" "=a,b,a,b")
+ (float:DF (match_operand:SI 1 "register_operand" "a,b,?b,?a")))]
+ "TARGET_FP"
+ "%|%.\\tintdp\\t%$\\t%1,%0"
+ [(set_attr "type" "intdp")
+ (set_attr "units" "l")
+ (set_attr "cross" "n,n,y,y")])
+
+(define_insn "floatunssidf2"
+ [(set (match_operand:DF 0 "register_operand" "=a,b,a,b")
+ (unsigned_float:DF (match_operand:SI 1 "register_operand" "a,b,?b,?a")))]
+ "TARGET_FP"
+ "%|%.\\tintdpu\\t%$\\t%1,%0"
+ [(set_attr "type" "intdp")
+ (set_attr "units" "l")
+ (set_attr "cross" "n,n,y,y")])
+
+(define_insn "fix_truncsfsi2"
+ [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+ (fix:SI (match_operand:SF 1 "register_operand" "a,b,?b,?a")))]
+ "TARGET_FP"
+ "%|%.\\tsptrunc\\t%$\\t%1,%0"
+ [(set_attr "type" "fp4")
+ (set_attr "units" "l")
+ (set_attr "cross" "n,n,y,y")])
+
+(define_insn "fix_truncdfsi2"
+ [(set (match_operand:SI 0 "register_operand" "=a,b")
+ (fix:SI (match_operand:DF 1 "register_operand" "a,b")))]
+ "TARGET_FP"
+ "%|%.\\tdptrunc\\t%$\\t%1,%0"
+ [(set_attr "type" "fp4")
+ (set_attr "units" "l")
+ (set_attr "cross" "n")])
+
+;; -------------------------------------------------------------------------
+;; Saturating arithmetic
+;; -------------------------------------------------------------------------
+
+(define_insn "saddsi3"
+ [(set (match_operand:SI 0 "register_operand" "=a,b,a,b,a,b,a,b")
+ (ss_plus:SI (match_operand:SI 1 "register_operand" "a,b,?b,?a,a,b,?b,?a")
+ (match_operand:SI 2 "reg_or_const_int_operand" "a,b,a,b,aIs5,bIs5,aIs5,bIs5")))]
+ ""
+ "%|%.\\tsadd\\t%$\\t%2, %1, %0"
+ [(set_attr "units" "ls,ls,ls,ls,l,l,l,l")
+ (set_attr "cross" "n,n,y,y,n,n,y,y")])
+
+(define_insn "ssubsi3"
+ [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+ (ss_minus:SI (match_operand:SI 1 "reg_or_scst5_operand" "aIs5,bIs5,?bIs5,?aIs5")
+ (match_operand:SI 2 "register_operand" "a,b,a,b")))]
+ ""
+ "%|%.\\tssub\\t%$\\t%1, %2, %0"
+ [(set_attr "units" "l")
+ (set_attr "cross" "n,n,y,y")])
+
+(define_insn "subcsi3"
+ [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+ (unspec:SI
+ [(match_operand:SI 1 "register_operand" "a,b,a,b")
+ (match_operand:SI 2 "register_operand" "a,b,?b,?a")]
+ UNSPEC_SUBC))]
+ ""
+ "%|%.\\tsubc\\t%$\\t%1, %2, %0"
+ [(set_attr "units" "l")
+ (set_attr "cross" "n,n,y,y")])
+
+;; -------------------------------------------------------------------------
+;; Call instructions
+;; -------------------------------------------------------------------------
+
+(define_expand "call"
+ [(match_operand 0 "" "")]
+ ""
+{
+ c6x_expand_call (NULL_RTX, operands[0], false);
+ DONE;
+})
+
+(define_expand "call_value"
+ [(match_operand 0 "" "")
+ (match_operand 1 "" "")]
+ ""
+{
+ c6x_expand_call (operands[0], operands[1], false);
+ DONE;
+})
+
+(define_expand "sibcall"
+ [(match_operand 0 "" "")]
+ ""
+{
+ c6x_expand_call (NULL_RTX, operands[0], true);
+ cfun->machine->contains_sibcall = true;
+ DONE;
+})
+
+(define_expand "sibcall_value"
+ [(match_operand 0 "" "")
+ (match_operand 1 "" "")]
+ ""
+{
+ c6x_expand_call (operands[0], operands[1], true);
+ cfun->machine->contains_sibcall = true;
+ DONE;
+})
+
+(define_insn "call_internal"
+ [(call (mem (match_operand:SI 0 "c6x_call_operand" "S1,a,b"))
+ (const_int 0))]
+ "!SIBLING_CALL_P (insn)"
+ "%|%.\\tcall\\t%$\\t%0"
+ [(set_attr "type" "call")
+ (set_attr "predicable" "no")
+ (set_attr "units" "s")
+ (set_attr "dest_regfile" "any,b,b")
+ (set_attr "cross" "n,y,n")])
+
+(define_insn "call_value_internal"
+ [(set (match_operand 0 "" "")
+ (call (mem (match_operand:SI 1 "c6x_call_operand" "S1,a,b"))
+ (const_int 0)))]
+ ""
+ "%|%.\\tcall\\t%$\\t%1"
+ [(set_attr "type" "call")
+ (set_attr "predicable" "no")
+ (set_attr "units" "s")
+ (set_attr "dest_regfile" "any,b,b")
+ (set_attr "cross" "n,y,n")])
+
+(define_insn "sibcall_internal"
+ [(call (mem (match_operand:SI 0 "c6x_call_operand" "S1,C"))
+ (const_int 0))]
+ "SIBLING_CALL_P (insn)"
+ "%|%.\\tb\\t%$\\t%0"
+ [(set_attr "type" "branch")
+ (set_attr "predicable" "no")
+ (set_attr "units" "s")
+ (set_attr "dest_regfile" "any,b")])
+
+(define_insn "callp"
+ [(call (mem (match_operand:SI 0 "c6x_call_operand" "S1"))
+ (const_int 0))
+ (unspec [(const_int 6)] UNSPEC_NOP)]
+ "!SIBLING_CALL_P (insn)"
+ "%|%.\\tcallp\\t%$\\t%0, B3"
+ [(set_attr "type" "callp")
+ (set_attr "predicable" "no")
+ (set_attr "units" "s")
+ (set_attr "dest_regfile" "b")
+ (set_attr "cross" "n")])
+
+(define_insn "callp_value"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (call (mem (match_operand:SI 1 "c6x_call_operand" "S1"))
+ (const_int 0)))
+ (unspec [(const_int 6)] UNSPEC_NOP)]
+ "!SIBLING_CALL_P (insn)"
+ "%|%.\\tcallp\\t%$\\t%1, B3"
+ [(set_attr "type" "callp")
+ (set_attr "predicable" "no")
+ (set_attr "units" "s")
+ (set_attr "dest_regfile" "b")
+ (set_attr "cross" "n")])
+
+(define_insn "return_internal"
+ [(return)
+ (use (match_operand:SI 0 "register_operand" "b"))]
+ "reload_completed"
+ "%|%.\\tret\\t%$\\t%0"
+ [(set_attr "type" "branch")
+ (set_attr "units" "s")
+ (set_attr "dest_regfile" "b")])
+
+(define_insn "addkpc"
+ [(set (match_operand:SI 0 "register_operand" "=b")
+ (unspec:SI [(match_operand 1 "" "")] UNSPEC_ADDKPC))
+ (unspec [(match_operand 2 "const_int_operand" "n")] UNSPEC_NOP)]
+ "TARGET_INSNS_64"
+ "%|%.\\taddkpc\\t%$\\t%l1, %0, %2"
+ [(set_attr "units" "s")
+ (set_attr "dest_regfile" "b")])
+
+;; -------------------------------------------------------------------------
+;; Unary operations
+;; -------------------------------------------------------------------------
+
+(define_insn "negsi2"
+ [(set (match_operand:SI 0 "register_operand" "=a, a, b, b")
+ (neg:SI (match_operand:SI 1 "register_operand" "a,?b, b,?a")))]
+ ""
+ "%|%.\\tneg\\t%$\\t%1, %0"
+ [(set_attr "units" "ls")
+ (set_attr "cross" "n,y,n,y")])
+
+(define_insn "one_cmplsi2"
+ [(set (match_operand:SI 0 "register_operand" "=a, a, b, b")
+ (not:SI (match_operand:SI 1 "register_operand" "a,?b, b,?a")))]
+ ""
+ "%|%.\\tnot\\t%$\\t%1, %0"
+ [(set_attr "units" "ls")
+ (set_attr "cross" "n,y,n,y")])
+
+(define_insn "clrsbsi2"
+ [(set (match_operand:SI 0 "register_operand" "=a, a, b, b")
+ (clrsb:SI (match_operand:SI 1 "register_operand" "a,?b, b,?a")))]
+ ""
+ "%|%.\\tnorm\\t%$\\t%1, %0"
+ [(set_attr "units" "l")
+ (set_attr "cross" "n,y,n,y")])
+
+(define_insn "clzsi2"
+ [(set (match_operand:SI 0 "register_operand" "=a, a, b, b")
+ (clz:SI (match_operand:SI 1 "register_operand" "a,?b, b,?a")))]
+ ""
+ "%|%.\\tlmbd\\t%$\\t1, %1, %0"
+ [(set_attr "units" "l")
+ (set_attr "cross" "n,y,n,y")])
+
+;; bitrevsi2 is defined in c6x-mult.md.in.
+
+(define_expand "ctzsi2"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (ctz:SI (match_operand:SI 1 "register_operand" "")))]
+ "TARGET_INSNS_64"
+{
+ rtx tmpreg = gen_reg_rtx (SImode);
+ emit_insn (gen_bitrevsi2 (tmpreg, operands[1]));
+ emit_insn (gen_clzsi2 (operands[0], tmpreg));
+ DONE;
+})
+
+(define_expand "ctzdi2"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (ctz:DI (match_operand:DI 1 "register_operand" "")))]
+ "TARGET_INSNS_64"
+{
+ rtx tmpreg = gen_reg_rtx (DImode);
+ rtx out;
+ emit_insn (gen_bitrevsi2 (gen_highpart (SImode, tmpreg),
+ gen_lowpart (SImode, operands[1])));
+ emit_insn (gen_bitrevsi2 (gen_lowpart (SImode, tmpreg),
+ gen_highpart (SImode, operands[1])));
+ out = expand_unop (DImode, clz_optab, tmpreg, operands[0], 1);
+ if (!rtx_equal_p (out, operands[0]))
+ emit_move_insn (operands[0], out);
+ DONE;
+})
+
+(define_insn "ssabssi2"
+ [(set (match_operand:SI 0 "register_operand" "=a, a, b, b")
+ (ss_abs:SI (match_operand:SI 1 "register_operand" "a,?b, b,?a")))]
+ ""
+ "%|%.\\tabs\\t%$\\t%1, %0"
+ [(set_attr "units" "l")
+ (set_attr "cross" "n,y,n,y")])
+
+;; -------------------------------------------------------------------------
+;; Shift instructions
+;; -------------------------------------------------------------------------
+
+(define_code_iterator any_shift [ss_ashift ashift ashiftrt lshiftrt])
+(define_code_iterator any_rshift [ashiftrt lshiftrt])
+(define_code_attr shift_code [(ss_ashift "ss_ashl") (ashift "ashl")
+ (ashiftrt "ashr") (lshiftrt "lshr")])
+(define_code_attr shift_insn [(ss_ashift "sshl") (ashift "shl")
+ (ashiftrt "shr") (lshiftrt "shru")])
+
+(define_insn "<shift_code>si3"
+ [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+ (any_shift:SI (match_operand:SI 1 "register_operand" "a,b,?b,?a")
+ (match_operand:SI 2 "reg_or_ucst5_operand" "aIu5,bIu5,aIu5,bIu5")))]
+ ""
+ "%|%.\\t<shift_insn>\\t%$\\t%1, %2, %0"
+ [(set_attr "units" "s")
+ (set_attr "cross" "n,n,y,y")])
+
+;; See c6x-mult.md.in for the rotlsi3 pattern.
+
+(define_insn "rotrdi3_16"
+ [(set (match_operand:DI 0 "register_operand" "=a,b")
+ (rotatert:DI (match_operand:DI 1 "register_operand" "a,b")
+ (const_int 16)))]
+ "TARGET_INSNS_64PLUS"
+ "%|%.\\tdpackx2\\t%$\\t%P1, %p1, %0"
+ [(set_attr "units" "l")
+ (set_attr "cross" "n")])
+
+(define_insn "shlmbsi3"
+ [(set (match_operand:SI 0 "register_operand" "=a,b,a,b")
+ (ior:SI (ashift:SI (match_operand:SI 1 "register_operand" "a,b,?b,?a")
+ (const_int 8))
+ (lshiftrt:SI (match_operand:SI 2 "register_operand" "a,b,a,b")
+ (const_int 24))))]
+ "TARGET_INSNS_64"
+ "%|%.\\tshlmb\\t%$\\t%2, %1, %0"
+ [(set_attr "units" "ls")
+ (set_attr "cross" "n,n,y,y")])
+
+(define_expand "ashldi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (ashift:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")))]
+ "TARGET_INSNS_64"
+{
+ if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) == 8)
+ {
+ rtx lo0, lo1, hi0, hi1, tmp;
+ lo0 = gen_lowpart (SImode, operands[0]);
+ hi0 = gen_highpart (SImode, operands[0]);
+ lo1 = gen_lowpart (SImode, operands[1]);
+ hi1 = gen_highpart (SImode, operands[1]);
+ if (reg_overlap_mentioned_p (hi0, lo1))
+ tmp = gen_reg_rtx (SImode);
+ else
+ tmp = hi0;
+ emit_insn (gen_shlmbsi3 (tmp, hi1, lo1));
+ emit_insn (gen_ashlsi3 (lo0, lo1, operands[2]));
+ if (tmp != hi0)
+ emit_move_insn (hi0, tmp);
+ DONE;
+ }
+ FAIL;
+})
+
+(define_expand "rotrdi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (rotatert:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")))]
+ "TARGET_INSNS_64PLUS"
+{
+ if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) == 16)
+ {
+ emit_insn (gen_rotrdi3_16 (operands[0], operands[1]));
+ DONE;
+ }
+ FAIL;
+})
+
+(define_insn "bswapv2hi2"
+ [(set (match_operand:V2HI 0 "register_operand" "=a,b,a,b")
+ (bswap:V2HI (match_operand:V2HI 1 "register_operand" "a,b,?b,?a")))]
+ "TARGET_INSNS_64"
+ "%|%.\\tswap4\\t%$\\t%1, %0"
+ [(set_attr "units" "l")
+ (set_attr "cross" "n,n,y,y")])
+
+(define_expand "bswapsi2"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (bswap:SI (match_operand:SI 1 "register_operand" "")))]
+ "TARGET_INSNS_64"
+{
+ rtx tmpreg = gen_reg_rtx (SImode);
+ rtx tmpv2 = gen_lowpart (V2HImode, tmpreg);
+ rtx op0v2 = gen_lowpart (V2HImode, operands[0]);
+ emit_insn (gen_rotlsi3 (tmpreg, operands[1], GEN_INT (16)));
+ emit_insn (gen_bswapv2hi2 (op0v2, tmpv2));
+ DONE;
+})
+
+;; -------------------------------------------------------------------------
+;; Division
+;; -------------------------------------------------------------------------
+
+(define_insn "divsi3_insn"
+ [(set (reg:SI REG_A4) (div:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+ (clobber (reg:SI REG_A0))
+ (clobber (reg:SI REG_A1))
+ (clobber (reg:SI REG_A2))
+ (clobber (reg:SI REG_A6))
+ (clobber (reg:SI REG_B0))
+ (clobber (reg:SI REG_B1))
+ (clobber (reg:SI REG_B2))
+ (clobber (reg:SI REG_B3))
+ (clobber (reg:SI REG_B4))
+ (clobber (reg:SI REG_B5))
+ (clobber (reg:SI REG_B30))
+ (clobber (reg:SI REG_B31))]
+ ""
+ "%|%.\\tcall\\t%$\\t__c6xabi_divi"
+ [(set_attr "type" "call")
+ (set_attr "dest_regfile" "any")
+ (set_attr "units" "s")
+ (set_attr "cross" "n")])
+
+(define_insn "divsi3_insn_indcall"
+ [(set (reg:SI REG_A4) (div:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+ (use (match_operand:SI 0 "register_operand" "b"))
+ (clobber (reg:SI REG_A0))
+ (clobber (reg:SI REG_A1))
+ (clobber (reg:SI REG_A2))
+ (clobber (reg:SI REG_A6))
+ (clobber (reg:SI REG_B0))
+ (clobber (reg:SI REG_B1))
+ (clobber (reg:SI REG_B2))
+ (clobber (reg:SI REG_B3))
+ (clobber (reg:SI REG_B4))
+ (clobber (reg:SI REG_B5))
+ (clobber (reg:SI REG_B30))
+ (clobber (reg:SI REG_B31))]
+ ""
+ "%|%.\\tcall\\t%$\\t%0"
+ [(set_attr "type" "call")
+ (set_attr "dest_regfile" "any")
+ (set_attr "units" "s")
+ (set_attr "cross" "n")])
+
+(define_insn "udivsi3_insn"
+ [(set (reg:SI REG_A4) (udiv:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+ (clobber (reg:SI REG_A0))
+ (clobber (reg:SI REG_A1))
+ (clobber (reg:SI REG_A2))
+ (clobber (reg:SI REG_A6))
+ (clobber (reg:SI REG_B0))
+ (clobber (reg:SI REG_B1))
+ (clobber (reg:SI REG_B2))
+ (clobber (reg:SI REG_B3))
+ (clobber (reg:SI REG_B4))
+ (clobber (reg:SI REG_B30))
+ (clobber (reg:SI REG_B31))]
+ ""
+ "%|%.\\tcall\\t%$\\t__c6xabi_divu"
+ [(set_attr "type" "call")
+ (set_attr "dest_regfile" "any")
+ (set_attr "units" "s")
+ (set_attr "cross" "n")])
+
+(define_insn "udivsi3_insn_indcall"
+ [(set (reg:SI REG_A4) (udiv:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+ (use (match_operand:SI 0 "register_operand" "b"))
+ (clobber (reg:SI REG_A0))
+ (clobber (reg:SI REG_A1))
+ (clobber (reg:SI REG_A2))
+ (clobber (reg:SI REG_A6))
+ (clobber (reg:SI REG_B0))
+ (clobber (reg:SI REG_B1))
+ (clobber (reg:SI REG_B2))
+ (clobber (reg:SI REG_B3))
+ (clobber (reg:SI REG_B4))
+ (clobber (reg:SI REG_B30))
+ (clobber (reg:SI REG_B31))]
+ ""
+ "%|%.\\tcall\\t%$\\t%0"
+ [(set_attr "type" "call")
+ (set_attr "dest_regfile" "any")
+ (set_attr "units" "s")
+ (set_attr "cross" "n")])
+
+(define_insn "modsi3_insn"
+ [(set (reg:SI REG_A4) (mod:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+ (clobber (reg:SI REG_A1))
+ (clobber (reg:SI REG_A2))
+ (clobber (reg:SI REG_A5))
+ (clobber (reg:SI REG_A6))
+ (clobber (reg:SI REG_B0))
+ (clobber (reg:SI REG_B1))
+ (clobber (reg:SI REG_B2))
+ (clobber (reg:SI REG_B3))
+ (clobber (reg:SI REG_B4))
+ (clobber (reg:SI REG_B30))
+ (clobber (reg:SI REG_B31))]
+ ""
+ "%|%.\\tcall\\t%$\\t__c6xabi_remi"
+ [(set_attr "type" "call")
+ (set_attr "dest_regfile" "any")
+ (set_attr "units" "s")
+ (set_attr "cross" "n")])
+
+(define_insn "modsi3_insn_indcall"
+ [(set (reg:SI REG_A4) (mod:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+ (use (match_operand:SI 0 "register_operand" "b"))
+ (clobber (reg:SI REG_A1))
+ (clobber (reg:SI REG_A2))
+ (clobber (reg:SI REG_A5))
+ (clobber (reg:SI REG_A6))
+ (clobber (reg:SI REG_B0))
+ (clobber (reg:SI REG_B1))
+ (clobber (reg:SI REG_B2))
+ (clobber (reg:SI REG_B3))
+ (clobber (reg:SI REG_B4))
+ (clobber (reg:SI REG_B30))
+ (clobber (reg:SI REG_B31))]
+ ""
+ "%|%.\\tcall\\t%$\\t%0"
+ [(set_attr "type" "call")
+ (set_attr "dest_regfile" "any")
+ (set_attr "units" "s")
+ (set_attr "cross" "n")])
+
+(define_insn "divmodsi4_insn"
+ [(set (reg:SI REG_A4) (div:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+ (set (reg:SI REG_A5) (mod:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+ (clobber (reg:SI REG_A1))
+ (clobber (reg:SI REG_A2))
+ (clobber (reg:SI REG_A6))
+ (clobber (reg:SI REG_B0))
+ (clobber (reg:SI REG_B1))
+ (clobber (reg:SI REG_B2))
+ (clobber (reg:SI REG_B3))
+ (clobber (reg:SI REG_B4))
+ (clobber (reg:SI REG_B30))
+ (clobber (reg:SI REG_B31))]
+ ""
+ "%|%.\\tcall\\t%$\\t__c6xabi_divremi"
+ [(set_attr "type" "call")
+ (set_attr "dest_regfile" "any")
+ (set_attr "units" "s")
+ (set_attr "cross" "n")])
+
+(define_insn "divmodsi4_insn_indcall"
+ [(set (reg:SI REG_A4) (div:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+ (set (reg:SI REG_A5) (mod:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+ (use (match_operand:SI 0 "register_operand" "b"))
+ (clobber (reg:SI REG_A1))
+ (clobber (reg:SI REG_A2))
+ (clobber (reg:SI REG_A5))
+ (clobber (reg:SI REG_A6))
+ (clobber (reg:SI REG_B0))
+ (clobber (reg:SI REG_B1))
+ (clobber (reg:SI REG_B2))
+ (clobber (reg:SI REG_B3))
+ (clobber (reg:SI REG_B4))
+ (clobber (reg:SI REG_B30))
+ (clobber (reg:SI REG_B31))]
+ ""
+ "%|%.\\tcall\\t%$\\t%0"
+ [(set_attr "type" "call")
+ (set_attr "dest_regfile" "any")
+ (set_attr "units" "s")
+ (set_attr "cross" "n")])
+
+(define_insn "umodsi3_insn"
+ [(set (reg:SI REG_A4) (umod:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+ (clobber (reg:SI REG_A1))
+ (clobber (reg:SI REG_A5))
+ (clobber (reg:SI REG_A7))
+ (clobber (reg:SI REG_B0))
+ (clobber (reg:SI REG_B1))
+ (clobber (reg:SI REG_B2))
+ (clobber (reg:SI REG_B3))
+ (clobber (reg:SI REG_B4))
+ (clobber (reg:SI REG_B30))
+ (clobber (reg:SI REG_B31))]
+ ""
+ "%|%.\\tcall\\t%$\\t__c6xabi_remu"
+ [(set_attr "type" "call")
+ (set_attr "dest_regfile" "any")
+ (set_attr "units" "s")
+ (set_attr "cross" "n")])
+
+(define_insn "umodsi3_insn_indcall"
+ [(set (reg:SI REG_A4) (umod:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+ (use (match_operand:SI 0 "register_operand" "b"))
+ (clobber (reg:SI REG_A1))
+ (clobber (reg:SI REG_A5))
+ (clobber (reg:SI REG_A7))
+ (clobber (reg:SI REG_B0))
+ (clobber (reg:SI REG_B1))
+ (clobber (reg:SI REG_B2))
+ (clobber (reg:SI REG_B3))
+ (clobber (reg:SI REG_B4))
+ (clobber (reg:SI REG_B30))
+ (clobber (reg:SI REG_B31))]
+ ""
+ "%|%.\\tcall\\t%$\\t%0"
+ [(set_attr "type" "call")
+ (set_attr "dest_regfile" "any")
+ (set_attr "units" "s")
+ (set_attr "cross" "n")])
+
+(define_insn "udivmodsi4_insn"
+ [(set (reg:SI REG_A4) (udiv:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+ (set (reg:SI REG_A5) (umod:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+ (clobber (reg:SI REG_A0))
+ (clobber (reg:SI REG_A1))
+ (clobber (reg:SI REG_A2))
+ (clobber (reg:SI REG_A6))
+ (clobber (reg:SI REG_B0))
+ (clobber (reg:SI REG_B1))
+ (clobber (reg:SI REG_B2))
+ (clobber (reg:SI REG_B3))
+ (clobber (reg:SI REG_B4))
+ (clobber (reg:SI REG_B30))
+ (clobber (reg:SI REG_B31))]
+ ""
+ "%|%.\\tcall\\t%$\\t__c6xabi_divremu"
+ [(set_attr "type" "call")
+ (set_attr "dest_regfile" "any")
+ (set_attr "units" "s")
+ (set_attr "cross" "n")])
+
+(define_insn "udivmodsi4_insn_indcall"
+ [(set (reg:SI REG_A4) (udiv:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+ (set (reg:SI REG_A5) (umod:SI (reg:SI REG_A4) (reg:SI REG_B4)))
+ (use (match_operand:SI 0 "register_operand" "b"))
+ (clobber (reg:SI REG_A0))
+ (clobber (reg:SI REG_A1))
+ (clobber (reg:SI REG_A2))
+ (clobber (reg:SI REG_A6))
+ (clobber (reg:SI REG_B0))
+ (clobber (reg:SI REG_B1))
+ (clobber (reg:SI REG_B2))
+ (clobber (reg:SI REG_B3))
+ (clobber (reg:SI REG_B4))
+ (clobber (reg:SI REG_B30))
+ (clobber (reg:SI REG_B31))]
+ ""
+ "%|%.\\tcall\\t%$\\t%0"
+ [(set_attr "type" "call")
+ (set_attr "dest_regfile" "any")
+ (set_attr "units" "s")
+ (set_attr "cross" "n")])
+
+(define_insn_and_split "divmodsi4"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (div:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))
+ (set (match_operand:SI 3 "register_operand" "")
+ (mod:SI (match_dup 1) (match_dup 2)))
+ (clobber (reg:SI REG_A0))
+ (clobber (reg:SI REG_A1))
+ (clobber (reg:SI REG_A2))
+ (clobber (reg:SI REG_A4))
+ (clobber (reg:SI REG_A5))
+ (clobber (reg:SI REG_A6))
+ (clobber (reg:SI REG_B0))
+ (clobber (reg:SI REG_B1))
+ (clobber (reg:SI REG_B2))
+ (clobber (reg:SI REG_B3))
+ (clobber (reg:SI REG_B4))
+ (clobber (reg:SI REG_B5))
+ (clobber (reg:SI REG_B30))
+ (clobber (reg:SI REG_B31))]
+ ""
+ "#"
+ ""
+ [(const_int 0)]
+{
+ rtx reg = NULL_RTX;
+
+ if (TARGET_LONG_CALLS)
+ {
+ if (reload_completed)
+ reg = gen_rtx_REG (SImode, REG_A6);
+ else
+ reg = gen_reg_rtx (SImode);
+ }
+ emit_move_insn (gen_rtx_REG (SImode, REG_A4), operands[1]);
+ emit_move_insn (gen_rtx_REG (SImode, REG_B4), operands[2]);
+ if (find_reg_note (curr_insn, REG_UNUSED, operands[3]))
+ {
+ if (TARGET_LONG_CALLS)
+ {
+ emit_move_insn (reg, optab_libfunc (sdiv_optab, SImode));
+ emit_insn (gen_divsi3_insn_indcall (reg));
+ }
+ else
+ emit_insn (gen_divsi3_insn ());
+ emit_move_insn (operands[0], gen_rtx_REG (SImode, REG_A4));
+ }
+ else if (find_reg_note (curr_insn, REG_UNUSED, operands[0]))
+ {
+ if (TARGET_LONG_CALLS)
+ {
+ emit_move_insn (reg, optab_libfunc (smod_optab, SImode));
+ emit_insn (gen_modsi3_insn_indcall (reg));
+ }
+ else
+ emit_insn (gen_modsi3_insn ());
+ emit_move_insn (operands[3], gen_rtx_REG (SImode, REG_A4));
+ }
+ else
+ {
+ if (TARGET_LONG_CALLS)
+ {
+ emit_move_insn (reg, optab_libfunc (sdivmod_optab, SImode));
+ emit_insn (gen_divmodsi4_insn_indcall (reg));
+ }
+ else
+ emit_insn (gen_divmodsi4_insn ());
+ emit_move_insn (operands[0], gen_rtx_REG (SImode, REG_A4));
+ emit_move_insn (operands[3], gen_rtx_REG (SImode, REG_A5));
+ }
+ DONE;
+})
+
+(define_insn_and_split "udivmodsi4"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (udiv:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))
+ (set (match_operand:SI 3 "register_operand" "")
+ (umod:SI (match_dup 1) (match_dup 2)))
+ (clobber (reg:SI REG_A0))
+ (clobber (reg:SI REG_A1))
+ (clobber (reg:SI REG_A2))
+ (clobber (reg:SI REG_A4))
+ (clobber (reg:SI REG_A5))
+ (clobber (reg:SI REG_A6))
+ (clobber (reg:SI REG_A7))
+ (clobber (reg:SI REG_B0))
+ (clobber (reg:SI REG_B1))
+ (clobber (reg:SI REG_B2))
+ (clobber (reg:SI REG_B3))
+ (clobber (reg:SI REG_B4))
+ (clobber (reg:SI REG_B30))
+ (clobber (reg:SI REG_B31))]
+ ""
+ "#"
+ ""
+ [(const_int 0)]
+{
+ rtx reg = NULL_RTX;
+
+ if (TARGET_LONG_CALLS)
+ {
+ if (reload_completed)
+ reg = gen_rtx_REG (SImode, REG_A6);
+ else
+ reg = gen_reg_rtx (SImode);
+ }
+
+ emit_move_insn (gen_rtx_REG (SImode, REG_A4), operands[1]);
+ emit_move_insn (gen_rtx_REG (SImode, REG_B4), operands[2]);
+ if (find_reg_note (curr_insn, REG_UNUSED, operands[3]))
+ {
+ if (TARGET_LONG_CALLS)
+ {
+ emit_move_insn (reg, optab_libfunc (udiv_optab, SImode));
+ emit_insn (gen_udivsi3_insn_indcall (reg));
+ }
+ else
+ emit_insn (gen_udivsi3_insn ());
+ emit_move_insn (operands[0], gen_rtx_REG (SImode, REG_A4));
+ }
+ else if (find_reg_note (curr_insn, REG_UNUSED, operands[0]))
+ {
+ if (TARGET_LONG_CALLS)
+ {
+ emit_move_insn (reg, optab_libfunc (umod_optab, SImode));
+ emit_insn (gen_umodsi3_insn_indcall (reg));
+ }
+ else
+ emit_insn (gen_umodsi3_insn ());
+ emit_move_insn (operands[3], gen_rtx_REG (SImode, REG_A4));
+ }
+ else
+ {
+ if (TARGET_LONG_CALLS)
+ {
+ emit_move_insn (reg, optab_libfunc (udivmod_optab, SImode));
+ emit_insn (gen_udivmodsi4_insn_indcall (reg));
+ }
+ else
+ emit_insn (gen_udivmodsi4_insn ());
+ emit_move_insn (operands[0], gen_rtx_REG (SImode, REG_A4));
+ emit_move_insn (operands[3], gen_rtx_REG (SImode, REG_A5));
+ }
+ DONE;
+})
+
+;; -------------------------------------------------------------------------
+;; Multiplication
+;; See c6x-mult.md.in for define_insn patterns.
+;; -------------------------------------------------------------------------
+
+(define_expand "mulhisi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" ""))
+ (sign_extend:SI (match_operand:HI 2 "reg_or_scst5_operand" ""))))]
+ ""
+{
+ if (CONSTANT_P (operands[2]))
+ {
+ emit_insn (gen_mulhisi3_const (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+})
+
+(define_expand "usmulhisi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" ""))
+ (sign_extend:SI (match_operand:HI 2 "reg_or_scst5_operand" ""))))]
+ ""
+{
+ if (CONSTANT_P (operands[2]))
+ {
+ emit_insn (gen_usmulhisi3_const (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+})
+
+(define_expand "mulsi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (mult:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))]
+ ""
+{
+ if (!TARGET_MPY32)
+ {
+ rtx lo1 = gen_lowpart (HImode, operands[1]);
+ rtx lo2 = gen_lowpart (HImode, operands[2]);
+ /* (N * AH + AL) * (N * BH + BL)
+ = N*(AH * BL + BH * AL) + AL*BL */
+ rtx tmp1 = gen_reg_rtx (SImode);
+ rtx tmp2 = gen_reg_rtx (SImode);
+ rtx tmp3 = gen_reg_rtx (SImode);
+ emit_insn (gen_umulhisi3 (tmp1, lo1, lo2));
+ emit_insn (gen_umulhisi3_lh (tmp2, lo1, operands[2]));
+ emit_insn (gen_umulhisi3_hl (tmp3, operands[1], lo2));
+ emit_insn (gen_addsi3 (tmp2, tmp2, tmp3));
+ emit_insn (gen_ashlsi3 (tmp2, tmp2, GEN_INT (16)));
+ emit_insn (gen_addsi3 (operands[0], tmp1, tmp2));
+ DONE;
+ }
+})
+
+;; -------------------------------------------------------------------------
+;; Floating point multiplication
+;; -------------------------------------------------------------------------
+
+(define_insn "mulsf3"
+ [(set (match_operand:SF 0 "register_operand" "=a,b,a,b")
+ (mult:SF (match_operand:SF 1 "register_operand" "%a,b,?a,?b")
+ (match_operand:SF 2 "register_operand" "a,b,b,a")))]
+ "TARGET_FP"
+ "%|%.\\tmpysp\\t%$\\t%1, %2, %0"
+ [(set_attr "type" "mpy4")
+ (set_attr "units" "m")
+ (set_attr "cross" "n,n,y,y")])
+
+(define_insn "muldf3"
+ [(set (match_operand:DF 0 "register_operand" "=a,b")
+ (mult:DF (match_operand:DF 1 "register_operand" "%a,b")
+ (match_operand:DF 2 "register_operand" "a,b")))]
+ "TARGET_FP"
+ "%|%.\\tmpydp\\t%$\\t%1, %2, %0"
+ [(set_attr "type" "mpydp")
+ (set_attr "units" "m")
+ (set_attr "cross" "n")])
+
+;; Note that mpyspdp and mpysp2dp are available on C67x, despite what the
+;; manual says.
+(define_insn "*muldf_ext1"
+ [(set (match_operand:DF 0 "register_operand" "=a,b,a,b")
+ (mult:DF (float_extend:DF (match_operand:SF 1 "register_operand" "a,b,a,b"))
+ (match_operand:DF 2 "register_operand" "a,b,?b,?a")))]
+ "TARGET_FP_EXT"
+ "%|%.\\tmpyspdp\\t%$\\t%1, %2, %0"
+ [(set_attr "type" "mpyspdp")
+ (set_attr "units" "m")
+ (set_attr "cross" "n,n,y,y")])
+
+(define_insn "*muldf_ext2"
+ [(set (match_operand:DF 0 "register_operand" "=a,b,a,b")
+ (mult:DF (float_extend:DF (match_operand:SF 1 "register_operand" "%a,b,a,b"))
+ (float_extend:DF (match_operand:SF 2 "register_operand" "a,b,?b,?a"))))]
+ "TARGET_FP_EXT"
+ "%|%.\\tmpysp2dp\\t%$\\t%1, %2, %0"
+ [(set_attr "type" "mpysp2dp")
+ (set_attr "units" "m")
+ (set_attr "cross" "n,n,y,y")])
+
+;; -------------------------------------------------------------------------
+;; Floating point division
+;; -------------------------------------------------------------------------
+
+(define_insn "rcpsf2"
+ [(set (match_operand:SF 0 "register_operand" "=a,b,a,b")
+ (unspec:SF [(match_operand:SF 1 "register_operand" "a,b,?b,?a")]
+ UNSPEC_RCP))]
+ "TARGET_FP"
+ "%|%.\\trcpsp\\t%$\\t%1, %0"
+ [(set_attr "units" "s")
+ (set_attr "cross" "n,n,y,y")])
+
+(define_insn "rcpdf2"
+ [(set (match_operand:DF 0 "register_operand" "=a,b")
+ (unspec:DF [(match_operand:DF 1 "register_operand" "a,b")]
+ UNSPEC_RCP))]
+ "TARGET_FP"
+ "%|%.\\trcpdp\\t%$\\t%1, %0"
+ [(set_attr "type" "dp2")
+ (set_attr "units" "s")
+ (set_attr "cross" "n")])
+
+(define_expand "divsf3"
+ [(set (match_dup 4)
+ (unspec:SF [(match_operand:SF 2 "register_operand" "")]
+ UNSPEC_RCP))
+ (set (match_dup 5) (mult:SF (match_dup 2) (match_dup 4)))
+ (set (match_dup 6) (minus:SF (match_dup 3) (match_dup 5)))
+ (set (match_dup 4) (mult:SF (match_dup 4) (match_dup 6)))
+ (set (match_dup 5) (mult:SF (match_dup 2) (match_dup 4)))
+ (set (match_dup 6) (minus:SF (match_dup 3) (match_dup 5)))
+ (set (match_dup 4) (mult:SF (match_dup 4) (match_dup 6)))
+ (set (match_operand:SF 0 "register_operand" "")
+ (mult:SF (match_operand:SF 1 "register_operand")
+ (match_dup 4)))]
+ "TARGET_FP && flag_reciprocal_math"
+{
+ operands[3] = force_reg (SFmode,
+ CONST_DOUBLE_FROM_REAL_VALUE (dconst2, SFmode));
+ operands[4] = gen_reg_rtx (SFmode);
+ operands[5] = gen_reg_rtx (SFmode);
+ operands[6] = gen_reg_rtx (SFmode);
+})
+
+(define_expand "divdf3"
+ [(set (match_dup 4)
+ (unspec:DF [(match_operand:DF 2 "register_operand" "")]
+ UNSPEC_RCP))
+ (set (match_dup 5) (mult:DF (match_dup 2) (match_dup 4)))
+ (set (match_dup 6) (minus:DF (match_dup 3) (match_dup 5)))
+ (set (match_dup 4) (mult:DF (match_dup 4) (match_dup 6)))
+ (set (match_dup 5) (mult:DF (match_dup 2) (match_dup 4)))
+ (set (match_dup 6) (minus:DF (match_dup 3) (match_dup 5)))
+ (set (match_dup 4) (mult:DF (match_dup 4) (match_dup 6)))
+ (set (match_dup 5) (mult:DF (match_dup 2) (match_dup 4)))
+ (set (match_dup 6) (minus:DF (match_dup 3) (match_dup 5)))
+ (set (match_dup 4) (mult:DF (match_dup 4) (match_dup 6)))
+ (set (match_operand:DF 0 "register_operand" "")
+ (mult:DF (match_operand:DF 1 "register_operand")
+ (match_dup 4)))]
+ "TARGET_FP && flag_reciprocal_math"
+{
+ operands[3] = force_reg (DFmode,
+ CONST_DOUBLE_FROM_REAL_VALUE (dconst2, DFmode));
+ operands[4] = gen_reg_rtx (DFmode);
+ operands[5] = gen_reg_rtx (DFmode);
+ operands[6] = gen_reg_rtx (DFmode);
+})
+
+;; -------------------------------------------------------------------------
+;; Block moves
+;; -------------------------------------------------------------------------
+
+(define_expand "movmemsi"
+ [(use (match_operand:BLK 0 "memory_operand" ""))
+ (use (match_operand:BLK 1 "memory_operand" ""))
+ (use (match_operand:SI 2 "nonmemory_operand" ""))
+ (use (match_operand:SI 3 "const_int_operand" ""))
+ (use (match_operand:SI 4 "const_int_operand" ""))
+ (use (match_operand:SI 5 "const_int_operand" ""))]
+ ""
+{
+ if (c6x_expand_movmem (operands[0], operands[1], operands[2], operands[3],
+ operands[4], operands[5]))
+ DONE;
+ else
+ FAIL;
+})
+
+;; -------------------------------------------------------------------------
+;; Prologue and epilogue.
+;; -------------------------------------------------------------------------
+
+;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
+;; all of memory. This blocks insns from being moved across this point.
+
+(define_insn "blockage"
+ [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)]
+ ""
+ ""
+ [(set_attr "type" "blockage")])
+
+(define_insn "push_rts"
+ [(set (mem:SI (reg:SI REG_SP)) (reg:SI REG_B14))
+ (set (mem:DI (plus:SI (reg:SI REG_SP) (const_int -8))) (reg:DI REG_A14))
+ (set (mem:DI (plus:SI (reg:SI REG_SP) (const_int -16))) (reg:DI REG_B12))
+ (set (mem:DI (plus:SI (reg:SI REG_SP) (const_int -24))) (reg:DI REG_A12))
+ (set (mem:DI (plus:SI (reg:SI REG_SP) (const_int -32))) (reg:DI REG_B10))
+ (set (mem:DI (plus:SI (reg:SI REG_SP) (const_int -40))) (reg:DI REG_A10))
+ (set (mem:DI (plus:SI (reg:SI REG_SP) (const_int -48))) (reg:DI REG_B2))
+ (set (reg:SI REG_SP) (plus:SI (reg:SI REG_SP) (const_int -56)))
+ (unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)
+ (clobber (reg:SI REG_A3))]
+ "TARGET_INSNS_64PLUS"
+ "%|%.\\tcallp\\t%$\\t__c6xabi_push_rts, a3"
+ [(set_attr "type" "callp")
+ (set_attr "dest_regfile" "a")
+ (set_attr "units" "s")
+ (set_attr "cross" "n")])
+
+(define_insn "pop_rts"
+ [(set (reg:SI REG_B14) (mem:SI (plus:SI (reg:SI REG_SP) (const_int 56))))
+ (set (reg:DI REG_A14) (mem:DI (plus:SI (reg:SI REG_SP) (const_int 48))))
+ (set (reg:DI REG_B12) (mem:DI (plus:SI (reg:SI REG_SP) (const_int 40))))
+ (set (reg:DI REG_A12) (mem:DI (plus:SI (reg:SI REG_SP) (const_int 32))))
+ (set (reg:DI REG_B10) (mem:DI (plus:SI (reg:SI REG_SP) (const_int 24))))
+ (set (reg:DI REG_A10) (mem:DI (plus:SI (reg:SI REG_SP) (const_int 16))))
+ (set (reg:DI REG_B2) (mem:DI (plus:SI (reg:SI REG_SP) (const_int 8))))
+ (set (reg:SI REG_SP) (plus:SI (reg:SI REG_SP) (const_int 56)))
+ (clobber (reg:SI REG_A3))
+ (return)]
+ "TARGET_INSNS_64PLUS"
+ "%|%.\\tretp\\t%$\\t__c6xabi_pop_rts, a3"
+ [(set_attr "type" "callp")
+ (set_attr "dest_regfile" "a")
+ (set_attr "units" "s")
+ (set_attr "cross" "n")])
+
+(define_expand "prologue"
+ [(const_int 1)]
+ ""
+ "c6x_expand_prologue (); DONE;")
+
+(define_expand "epilogue"
+ [(const_int 1)]
+ ""
+ "c6x_expand_epilogue (false); DONE;")
+
+(define_expand "sibcall_epilogue"
+ [(return)]
+ ""
+{
+ c6x_expand_epilogue (true);
+ DONE;
+})
+
+(define_insn "setup_dsbt"
+ [(set (match_operand:SI 0 "pic_register_operand" "+Z")
+ (unspec:SI [(match_dup 0)
+ (match_operand:SI 1 "symbolic_operand" "")]
+ UNSPEC_SETUP_DSBT))]
+ "TARGET_DSBT"
+ "%|%.\\tldw\\t%$\\t*+%0($DSBT_index%1), %0"
+ [(set_attr "type" "load")
+ (set_attr "units" "d_addr")
+ (set_attr "dest_regfile" "b")
+ (set_attr "addr_regfile" "b")])
+
+
+;; A dummy use/set to prevent prologue and epiloge overlapping.
+;; This can be caused by sched-ebb in the presence of multiple
+;; exit sequences, and causes the unwinding table generation to explode.
+(define_insn "epilogue_barrier"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (unspec:SI [(match_operand:SI 1 "register_operand" "")]
+ UNSPEC_EPILOGUE_BARRIER))]
+ ""
+ ""
+ [(set_attr "type" "blockage")])
+
+;; -------------------------------------------------------------------------
+;; Vector insns
+;; -------------------------------------------------------------------------
+
+(define_code_iterator logical [and ior xor])
+(define_code_attr logical_insn [(and "and") (ior "ior") (xor "xor")])
+(define_code_attr logical_opcode [(and "and") (ior "or") (xor "xor")])
+(define_code_iterator plusminus [plus minus])
+(define_code_attr plusminus_insn [(plus "add") (minus "sub")])
+(define_code_iterator ss_plusminus [ss_plus ss_minus])
+(define_code_attr ss_plusminus_insn [(ss_plus "add") (ss_minus "sub")])
+
+;; Vector logical insns
+
+(define_insn "<logical_insn><mode>3"
+ [(set (match_operand:VEC4M 0 "register_operand" "=a,b,a,b")
+ (logical:VEC4M (match_operand:VEC4M 1 "register_operand" "a,b,a,b")
+ (match_operand:VEC4M 2 "register_operand" "a,b,?b,?a")))]
+ ""
+ "%|%.\\t<logical_opcode>\\t%$\\t%1, %2, %0"
+ [(set_attr "units62" "ls")
+ (set_attr "units64" "dls")
+ (set_attr "cross" "n,n,y,y")])
+
+;; Vector add/subtract
+
+(define_insn "<plusminus_insn>v2hi3"
+ [(set (match_operand:V2HI 0 "register_operand" "=a,b,a,b")
+ (plusminus:V2HI (match_operand:V2HI 1 "register_operand" "a,b,a,b")
+ (match_operand:V2HI 2 "register_operand" "a,b,?b,?a")))]
+ ""
+ "%|%.\\t<plusminus_insn>2\\t%$\\t%1, %2, %0"
+ [(set_attr "units62" "l")
+ (set_attr "units64" "dls")
+ (set_attr "cross" "n,n,y,y")])
+
+(define_insn "<plusminus_insn>v4qi3"
+ [(set (match_operand:V4QI 0 "register_operand" "=a,b,a,b")
+ (plusminus:V4QI (match_operand:V4QI 1 "register_operand" "a,b,a,b")
+ (match_operand:V4QI 2 "register_operand" "a,b,?b,?a")))]
+ "TARGET_INSNS_64"
+ "%|%.\\t<plusminus_insn>4\\t%$\\t%1, %2, %0"
+ [(set_attr "units" "l")
+ (set_attr "cross" "n,n,y,y")])
+
+(define_insn "ss_addv2hi3"
+ [(set (match_operand:V2HI 0 "register_operand" "=a,b,a,b")
+ (ss_plus:V2HI (match_operand:V2HI 1 "register_operand" "a,b,a,b")
+ (match_operand:V2HI 2 "register_operand" "a,b,?b,?a")))]
+ "TARGET_INSNS_64"
+ "%|%.\\tsadd2\\t%$\\t%1, %2, %0"
+ [(set_attr "units" "s")
+ (set_attr "cross" "n,n,y,y")])
+
+(define_insn "ss_subv2hi3"
+ [(set (match_operand:V2HI 0 "register_operand" "=a,b,a,b")
+ (ss_minus:V2HI (match_operand:V2HI 1 "register_operand" "a,b,a,b")
+ (match_operand:V2HI 2 "register_operand" "a,b,?b,?a")))]
+ "TARGET_INSNS_64"
+ "%|%.\\tssub2\\t%$\\t%1, %2, %0"
+ [(set_attr "units" "l")
+ (set_attr "cross" "n,n,y,y")])
+
+(define_insn "us_addv4qi3"
+ [(set (match_operand:V4QI 0 "register_operand" "=a,b,a,b")
+ (ss_plus:V4QI (match_operand:V4QI 1 "register_operand" "a,b,a,b")
+ (match_operand:V4QI 2 "register_operand" "a,b,?b,?a")))]
+ "TARGET_INSNS_64"
+ "%|%.\\tsaddu4\\t%$\\t%1, %2, %0"
+ [(set_attr "units" "s")
+ (set_attr "cross" "n,n,y,y")])
+
+;; Vector/scalar min/max
+
+(define_mode_iterator SMINMAX [HI V2HI])
+(define_mode_iterator UMINMAX [QI V4QI])
+
+(define_insn "smax<mode>3"
+ [(set (match_operand:SMINMAX 0 "register_operand" "=a,b,a,b")
+ (smax:SMINMAX (match_operand:SMINMAX 1 "register_operand" "a,b,a,b")
+ (match_operand:SMINMAX 2 "register_operand" "a,b,?b,?a")))]
+ "TARGET_INSNS_64"
+ "%|%.\\tmax2\\t%$\\t%1, %2, %0"
+ [(set_attr "units64" "l")
+ (set_attr "units64p" "ls")
+ (set_attr "cross" "n,n,y,y")])
+
+(define_insn "smin<mode>3"
+ [(set (match_operand:SMINMAX 0 "register_operand" "=a,b,a,b")
+ (smin:SMINMAX (match_operand:SMINMAX 1 "register_operand" "a,b,a,b")
+ (match_operand:SMINMAX 2 "register_operand" "a,b,?b,?a")))]
+ "TARGET_INSNS_64"
+ "%|%.\\tmin2\\t%$\\t%1, %2, %0"
+ [(set_attr "units64" "l")
+ (set_attr "units64p" "ls")
+ (set_attr "cross" "n,n,y,y")])
+
+(define_insn "umax<mode>3"
+ [(set (match_operand:UMINMAX 0 "register_operand" "=a,b,a,b")
+ (umax:UMINMAX (match_operand:UMINMAX 1 "register_operand" "a,b,a,b")
+ (match_operand:UMINMAX 2 "register_operand" "a,b,?b,?a")))]
+ "TARGET_INSNS_64"
+ "%|%.\\tmaxu4\\t%$\\t%1, %2, %0"
+ [(set_attr "units" "l")
+ (set_attr "cross" "n,n,y,y")])
+
+(define_insn "umin<mode>3"
+ [(set (match_operand:UMINMAX 0 "register_operand" "=a,b,a,b")
+ (umin:UMINMAX (match_operand:UMINMAX 1 "register_operand" "a,b,a,b")
+ (match_operand:UMINMAX 2 "register_operand" "a,b,?b,?a")))]
+ "TARGET_INSNS_64"
+ "%|%.\\tminu4\\t%$\\t%1, %2, %0"
+ [(set_attr "units" "l")
+ (set_attr "cross" "n,n,y,y")])
+
+;; Vector shifts
+
+(define_insn "<shift_code>v2hi3"
+ [(set (match_operand:V2HI 0 "register_operand" "=a,b,a,b")
+ (any_rshift:V2HI (match_operand:V2HI 1 "register_operand" "a,b,?b,?a")
+ (match_operand:SI 2 "reg_or_ucst5_operand" "aIu5,bIu5,aIu5,bIu5")))]
+ "TARGET_INSNS_64"
+ "%|%.\\t<shift_insn>2\\t%$\\t%1, %2, %0"
+ [(set_attr "units" "s")
+ (set_attr "cross" "n,n,y,y")])
+
+;; See c6x-mult.md.in for avg2/avgu4
+
+;; Widening vector multiply and dot product.
+;; See c6x-mult.md.in for the define_insn patterns
+
+(define_expand "sdot_prodv2hi"
+ [(match_operand:SI 0 "register_operand" "")
+ (match_operand:V2HI 1 "register_operand" "")
+ (match_operand:V2HI 2 "register_operand" "")
+ (match_operand:SI 3 "register_operand" "")]
+ "TARGET_INSNS_64"
+{
+ rtx t = gen_reg_rtx (SImode);
+ emit_insn (gen_dotv2hi (t, operands[1], operands[2]));
+ emit_insn (gen_addsi3 (operands[0], operands[3], t));
+ DONE;
+})
+
+;; Unary vector operations
+
+(define_insn "ssabsv2hi2"
+ [(set (match_operand:V2HI 0 "register_operand" "=a, a, b, b")
+ (ss_abs:V2HI (match_operand:V2HI 1 "register_operand" "a,?b, b,?a")))]
+ "TARGET_INSNS_64"
+ "%|%.\\tabs2\\t%$\\t%1, %0"
+ [(set_attr "units" "l")
+ (set_attr "cross" "n,y,n,y")])
+
+;; Pack insns
+
+(define_insn "*packv2hi_insv"
+ [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+a,b,a,b,ab")
+ (const_int 16)
+ (const_int 16))
+ (match_operand:SI 1 "nonmemory_operand" "a,b,?b,?a,n"))]
+ "TARGET_INSNS_64"
+ "@
+ %|%.\\tpack2\\t%$\\t%1, %0, %0
+ %|%.\\tpack2\\t%$\\t%1, %0, %0
+ %|%.\\tpack2\\t%$\\t%1, %0, %0
+ %|%.\\tpack2\\t%$\\t%1, %0, %0
+ %|%.\\tmvklh\\t%$\\t%1, %0"
+ [(set_attr "units" "ls")
+ (set_attr "cross" "n,n,y,y,n")])
+
+(define_insn "movstricthi"
+ [(set (strict_low_part (match_operand:HI 0 "register_operand" "+a,b,a,b"))
+ (match_operand:HI 1 "register_operand" "a,b,?b,?a"))]
+ "TARGET_INSNS_64"
+ "%|%.\\tpackhl2\\t%$\\t%0, %1, %0"
+ [(set_attr "units" "ls")
+ (set_attr "cross" "n,n,y,y")])
+
+(include "c6x-mult.md")
+(include "sync.md")
diff --git a/gcc-4.9/gcc/config/c6x/c6x.opt b/gcc-4.9/gcc/config/c6x/c6x.opt
new file mode 100644
index 000000000..1a96f6086
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/c6x.opt
@@ -0,0 +1,67 @@
+; Option definitions for TI C6X.
+; Copyright (C) 2010-2014 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-4.9/gcc/config/c6x/c6x_intrinsics.h b/gcc-4.9/gcc/config/c6x/c6x_intrinsics.h
new file mode 100644
index 000000000..ce0436ca7
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/c6x_intrinsics.h
@@ -0,0 +1,194 @@
+/* Intrinsics for TI C6X.
+
+ Copyright (C) 2011-2014 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-4.9/gcc/config/c6x/constraints.md b/gcc-4.9/gcc/config/c6x/constraints.md
new file mode 100644
index 000000000..e2721d9a7
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/constraints.md
@@ -0,0 +1,174 @@
+;; Constraint definitions for TI C6X.
+;; Copyright (C) 2010-2014 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-4.9/gcc/config/c6x/elf-common.h b/gcc-4.9/gcc/config/c6x/elf-common.h
new file mode 100644
index 000000000..8eef1b82e
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/elf-common.h
@@ -0,0 +1,37 @@
+/* ELF definitions for TI C6X
+ Copyright (C) 2010-2014 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-4.9/gcc/config/c6x/elf.h b/gcc-4.9/gcc/config/c6x/elf.h
new file mode 100644
index 000000000..a4189f6ae
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/elf.h
@@ -0,0 +1,35 @@
+/* ELF definitions for TI C6X
+ Copyright (C) 2010-2014 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-4.9/gcc/config/c6x/genmult.sh b/gcc-4.9/gcc/config/c6x/genmult.sh
new file mode 100644
index 000000000..dd8a086f4
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/genmult.sh
@@ -0,0 +1,33 @@
+#! /bin/sh
+# Generate c6x-mult.md from c6x-mult.md.in
+# The input file is passed as an argument.
+
+# Copyright (C) 2011-2014 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-4.9/gcc/config/c6x/genopt.sh b/gcc-4.9/gcc/config/c6x/genopt.sh
new file mode 100644
index 000000000..406823a7b
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/genopt.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+# Generate c6x-tables.opt from the lists in *.def.
+# Copyright (C) 2011-2014 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-2014 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-4.9/gcc/config/c6x/gensched.sh b/gcc-4.9/gcc/config/c6x/gensched.sh
new file mode 100644
index 000000000..4d389cc03
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/gensched.sh
@@ -0,0 +1,44 @@
+#! /bin/sh
+# Generate c6x-sched.md from c6x-sched.md.in
+# The input file is passed as an argument.
+
+# Copyright (C) 2010-2014 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-4.9/gcc/config/c6x/predicates.md b/gcc-4.9/gcc/config/c6x/predicates.md
new file mode 100644
index 000000000..464d27689
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/predicates.md
@@ -0,0 +1,226 @@
+/* Predicates for TI C6X
+ Copyright (C) 2010-2014 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 && tree_fits_shwi_p (t))
+ {
+ size = tree_to_shwi (t);
+ if (size < 0)
+ size = 0;
+ }
+
+ /* Don't allow addressing outside the object. */
+ return (offset >= 0 && offset <= size);
+
+ default:
+ gcc_unreachable ();
+ }
+})
diff --git a/gcc-4.9/gcc/config/c6x/sync.md b/gcc-4.9/gcc/config/c6x/sync.md
new file mode 100644
index 000000000..fff6c4394
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/sync.md
@@ -0,0 +1,270 @@
+;; GCC machine description for C6X synchronization instructions.
+;; Copyright (C) 2011-2014 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-4.9/gcc/config/c6x/t-c6x b/gcc-4.9/gcc/config/c6x/t-c6x
new file mode 100644
index 000000000..4cde36ce8
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/t-c6x
@@ -0,0 +1,42 @@
+# Target Makefile Fragment for TI C6X.
+# Copyright (C) 2010-2014 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-4.9/gcc/config/c6x/t-c6x-elf b/gcc-4.9/gcc/config/c6x/t-c6x-elf
new file mode 100644
index 000000000..8d7276be4
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/t-c6x-elf
@@ -0,0 +1,30 @@
+# Target Makefile Fragment for TI C6X using ELF.
+# Copyright (C) 2010-2014 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/>.
+
+EXTRA_HEADERS += $(srcdir)/ginclude/unwind-arm-common.h
+
+# 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 =
diff --git a/gcc-4.9/gcc/config/c6x/t-c6x-uclinux b/gcc-4.9/gcc/config/c6x/t-c6x-uclinux
new file mode 100644
index 000000000..e4b93908f
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/t-c6x-uclinux
@@ -0,0 +1,3 @@
+MULTILIB_OSDIRNAMES = march.c674x=!c674x
+MULTILIB_OSDIRNAMES += mbig-endian=!be
+MULTILIB_OSDIRNAMES += mbig-endian/march.c674x=!be/c674x
diff --git a/gcc-4.9/gcc/config/c6x/uclinux-elf.h b/gcc-4.9/gcc/config/c6x/uclinux-elf.h
new file mode 100644
index 000000000..3f3964ba7
--- /dev/null
+++ b/gcc-4.9/gcc/config/c6x/uclinux-elf.h
@@ -0,0 +1,63 @@
+/* Definitions for TI C6X running ucLinux using ELF
+ Copyright (C) 2010-2014 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)); \
+}