summaryrefslogtreecommitdiffstats
path: root/gcc/config
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/score/crti.asm85
-rw-r--r--gcc/config/score/crtn.asm47
-rw-r--r--gcc/config/score/elf.h101
-rw-r--r--gcc/config/score/mac.md181
-rw-r--r--gcc/config/score/misc.md108
-rw-r--r--gcc/config/score/mul-div.S224
-rw-r--r--gcc/config/score/predicates.md63
-rw-r--r--gcc/config/score/score-conv.h82
-rw-r--r--gcc/config/score/score-mdaux.c738
-rw-r--r--gcc/config/score/score-mdaux.h113
-rw-r--r--gcc/config/score/score-modes.def26
-rw-r--r--gcc/config/score/score-protos.h92
-rw-r--r--gcc/config/score/score-version.h21
-rw-r--r--gcc/config/score/score.c1071
-rw-r--r--gcc/config/score/score.h909
-rw-r--r--gcc/config/score/score.md1253
-rw-r--r--gcc/config/score/score.opt53
-rw-r--r--gcc/config/score/score7.md46
-rw-r--r--gcc/config/score/t-score-elf44
19 files changed, 5257 insertions, 0 deletions
diff --git a/gcc/config/score/crti.asm b/gcc/config/score/crti.asm
new file mode 100644
index 00000000000..65ffb159919
--- /dev/null
+++ b/gcc/config/score/crti.asm
@@ -0,0 +1,85 @@
+# crti.asm for Sunplus S+CORE
+#
+# Copyright (C) 2005 Free Software Foundation, Inc.
+#
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any
+# later version.
+#
+# In addition to the permissions in the GNU General Public License, the
+# Free Software Foundation gives you unlimited permission to link the
+# compiled version of this file with other programs, and to distribute
+# those programs without any restriction coming from the use of this
+# file. (The General Public License restrictions do apply in other
+# respects; for example, they cover modification of the file, and
+# distribution when not linked into another program.)
+#
+# This file is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING. If not, write to the Free
+# Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception, if you link this library with files
+# compiled with GCC to produce an executable, this does not cause
+# the resulting executable to be covered by the GNU General Public License.
+# This exception does not however invalidate any other reasons why
+# the executable file might be covered by the GNU General Public License.
+#
+
+# This file makes a stack frame for the contents of the .init and
+# .fini sections.
+
+.section .init,"ax", @progbits
+ .weak _start
+ .ent _start
+ .frame r0, 0, r3, 0
+ .mask 0x00000000, 0
+_start:
+ la r28, _gp
+ la r8, __bss_start
+ la r9, __bss_end__
+ sub! r9, r8
+ srli! r9, 2
+ addi r9, -1
+ mtsr r9, sr0
+ li r9, 0
+1:
+ sw r9, [r8]+, 4
+ bcnz 1b
+ la r0, _stack
+ jl _init
+ la r4, _end
+ jl _init_argv
+ jl exit
+ .end _start
+
+ .weak _init_argv
+ .ent
+ .frame r0, 0, r3, 0
+ .mask 0x00000000, 0
+_init_argv:
+ ldiu! r4, 0
+ ldiu! r5, 0
+ j main
+ .end _init_argv
+
+ .globl _init
+ .type _init, %function
+_init:
+ addi r0, -32
+ sw r3, [r0, 20]
+
+ .section .fini, "ax", @progbits
+ .globl _fini
+ .type _fini, %function
+_fini:
+ addi r0, -32
+ sw r3, [r0, 20]
+
+
diff --git a/gcc/config/score/crtn.asm b/gcc/config/score/crtn.asm
new file mode 100644
index 00000000000..97039fa24df
--- /dev/null
+++ b/gcc/config/score/crtn.asm
@@ -0,0 +1,47 @@
+# crtn.asm for Sunplus S+CORE
+
+# Copyright (C) 2005 Free Software Foundation, Inc.
+#
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any
+# later version.
+#
+# In addition to the permissions in the GNU General Public License, the
+# Free Software Foundation gives you unlimited permission to link the
+# compiled version of this file with other programs, and to distribute
+# those programs without any restriction coming from the use of this
+# file. (The General Public License restrictions do apply in other
+# respects; for example, they cover modification of the file, and
+# distribution when not linked into another program.)
+#
+# This file is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING. If not, write to the Free
+# Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception, if you link this library with files
+# compiled with GCC to produce an executable, this does not cause
+# the resulting executable to be covered by the GNU General Public License.
+# This exception does not however invalidate any other reasons why
+# the executable file might be covered by the GNU General Public License.
+#
+
+# This file makes sure that the .init and .fini sections do in
+# fact return.
+
+.section .init, "ax", @progbits
+ lw r3, [r0, 20]
+ addi r0, 32
+ br r3
+
+.section .fini, "ax", @progbits
+ lw r3, [r0, 20]
+ addi r0, 32
+ br r3
+
diff --git a/gcc/config/score/elf.h b/gcc/config/score/elf.h
new file mode 100644
index 00000000000..8c8b5dc80eb
--- /dev/null
+++ b/gcc/config/score/elf.h
@@ -0,0 +1,101 @@
+/* elf.h for Sunplus S+CORE processor
+ Copyright (C) 2005 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 2, 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 COPYING. If not, write to
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+#define OBJECT_FORMAT_ELF
+
+/* Biggest alignment supported by the object file format of this machine. */
+#undef MAX_OFILE_ALIGNMENT
+#define MAX_OFILE_ALIGNMENT (32768 * 8)
+
+/* Switch into a generic section. */
+#undef TARGET_ASM_NAMED_SECTION
+#define TARGET_ASM_NAMED_SECTION default_elf_asm_named_section
+
+/* The following macro defines the format used to output the second
+ operand of the .type assembler directive. */
+#define TYPE_OPERAND_FMT "@%s"
+
+#undef TYPE_ASM_OP
+#define TYPE_ASM_OP "\t.type\t"
+
+#undef SIZE_ASM_OP
+#define SIZE_ASM_OP "\t.size\t"
+
+/* A c expression whose value is a string containing the
+ assembler operation to identify the following data as
+ uninitialized global data. */
+#ifndef BSS_SECTION_ASM_OP
+#define BSS_SECTION_ASM_OP "\t.section\t.bss"
+#endif
+
+#ifndef ASM_OUTPUT_ALIGNED_BSS
+#define ASM_OUTPUT_ALIGNED_BSS asm_output_aligned_bss
+#endif
+
+#define ASM_OUTPUT_DEF(FILE, LABEL1, LABEL2) \
+ do { \
+ fputc ('\t', FILE); \
+ assemble_name (FILE, LABEL1); \
+ fputs (" = ", FILE); \
+ assemble_name (FILE, LABEL2); \
+ fputc ('\n', FILE); \
+ } while (0)
+
+
+/* This is how we tell the assembler that a symbol is weak. */
+#undef ASM_WEAKEN_LABEL
+#define ASM_WEAKEN_LABEL(FILE, NAME) ASM_OUTPUT_WEAK_ALIAS (FILE, NAME, 0)
+
+#define ASM_OUTPUT_WEAK_ALIAS(FILE, NAME, VALUE) \
+ do { \
+ fputs ("\t.weak\t", FILE); \
+ assemble_name (FILE, NAME); \
+ if (VALUE) \
+ { \
+ fputc (' ', FILE); \
+ assemble_name (FILE, VALUE); \
+ } \
+ fputc ('\n', FILE); \
+ } while (0)
+
+#define MAKE_DECL_ONE_ONLY(DECL) (DECL_WEAK (DECL) = 1)
+
+/* On elf, we *do* have support for the .init and .fini sections, and we
+ can put stuff in there to be executed before and after `main'. We let
+ crtstuff.c and other files know this by defining the following symbols.
+ The definitions say how to change sections to the .init and .fini
+ sections. This is the same for all known elf assemblers. */
+#undef INIT_SECTION_ASM_OP
+#define INIT_SECTION_ASM_OP "\t.section\t.init"
+#undef FINI_SECTION_ASM_OP
+#define FINI_SECTION_ASM_OP "\t.section\t.fini"
+
+/* Don't set the target flags, this is done by the linker script */
+#undef LIB_SPEC
+#define LIB_SPEC ""
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "crti%O%s crtbegin%O%s"
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC "crtend%O%s crtn%O%s"
+
+/* We support #pragma. */
+#define HANDLE_SYSV_PRAGMA 1
diff --git a/gcc/config/score/mac.md b/gcc/config/score/mac.md
new file mode 100644
index 00000000000..ca7889d4185
--- /dev/null
+++ b/gcc/config/score/mac.md
@@ -0,0 +1,181 @@
+;; Machine description for Sunplus S+CORE
+;; Copyright (C) 2005
+;; Free Software Foundation, Inc.
+;; Contributed by Sunnorth.
+
+;; 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 2, 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 COPYING. If not, write to
+;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
+
+;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
+
+(define_insn "smaxsi3"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (smax:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "d")))]
+ "TARGET_MAC"
+ "max %0, %1, %2"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")])
+
+(define_insn "sminsi3"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (smin:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "d")))]
+ "TARGET_MAC"
+ "min %0, %1, %2"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")])
+
+(define_insn "abssi2"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (abs:SI (match_operand:SI 1 "register_operand" "d")))]
+ "TARGET_MAC"
+ "abs %0, %1"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")])
+
+(define_insn "clzsi2"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (clz:SI (match_operand:SI 1 "register_operand" "d")))]
+ "TARGET_MAC"
+ "clz %0, %1"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")])
+
+(define_insn "sffs"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (unspec:SI [(match_operand:SI 1 "register_operand" "d")] SFFS))]
+ "TARGET_MAC"
+ "bitrev %0, %1, r0\;clz %0, %0\;addi %0, 0x1"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")])
+
+(define_expand "ffssi2"
+ [(set (match_operand:SI 0 "register_operand")
+ (ffs:SI (match_operand:SI 1 "register_operand")))]
+ "TARGET_MAC"
+{
+ emit_insn (gen_sffs (operands[0], operands[1]));
+ emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (CC_NZmode, CC_REGNUM),
+ gen_rtx_COMPARE (CC_NZmode, operands[0],
+ GEN_INT (33))));
+ emit_insn (gen_movsicc_internal (operands[0],
+ gen_rtx_fmt_ee (EQ, VOIDmode, operands[0], GEN_INT (33)),
+ GEN_INT (0),
+ operands[0]));
+ DONE;
+})
+
+(define_peephole2
+ [(set (match_operand:SI 0 "loreg_operand" "")
+ (match_operand:SI 1 "register_operand" ""))
+ (set (match_operand:SI 2 "hireg_operand" "")
+ (match_operand:SI 3 "register_operand" ""))]
+ "TARGET_MAC"
+ [(parallel
+ [(set (match_dup 0) (match_dup 1))
+ (set (match_dup 2) (match_dup 3))])])
+
+(define_peephole2
+ [(set (match_operand:SI 0 "hireg_operand" "")
+ (match_operand:SI 1 "register_operand" ""))
+ (set (match_operand:SI 2 "loreg_operand" "")
+ (match_operand:SI 3 "register_operand" ""))]
+ "TARGET_MAC"
+ [(parallel
+ [(set (match_dup 2) (match_dup 3))
+ (set (match_dup 0) (match_dup 1))])])
+
+(define_insn "movtohilo"
+ [(parallel
+ [(set (match_operand:SI 0 "loreg_operand" "=l")
+ (match_operand:SI 1 "register_operand" "d"))
+ (set (match_operand:SI 2 "hireg_operand" "=h")
+ (match_operand:SI 3 "register_operand" "d"))])]
+ "TARGET_MAC"
+ "mtcehl %3, %1"
+ [(set_attr "type" "fce")
+ (set_attr "mode" "SI")])
+
+(define_insn "mulsi3addsi"
+ [(set (match_operand:SI 0 "register_operand" "=l,l,d")
+ (plus:SI (mult:SI (match_operand:SI 2 "register_operand" "d,d,d")
+ (match_operand:SI 3 "register_operand" "d,d,d"))
+ (match_operand:SI 1 "register_operand" "0,d,l")))
+ (clobber (reg:SI HI_REGNUM))]
+ "TARGET_MAC"
+ "@
+ mad %2, %3
+ mtcel%S1 %1\;mad %2, %3
+ mad %2, %3\;mfcel%S0 %0"
+ [(set_attr "mode" "SI")])
+
+(define_insn "mulsi3subsi"
+ [(set (match_operand:SI 0 "register_operand" "=l,l,d")
+ (minus:SI (match_operand:SI 1 "register_operand" "0,d,l")
+ (mult:SI (match_operand:SI 2 "register_operand" "d,d,d")
+ (match_operand:SI 3 "register_operand" "d,d,d"))))
+ (clobber (reg:SI HI_REGNUM))]
+ "TARGET_MAC"
+ "@
+ msb %2, %3
+ mtcel%S1 %1\;msb %2, %3
+ msb %2, %3\;mfcel%S0 %0"
+ [(set_attr "mode" "SI")])
+
+(define_insn "mulsidi3adddi"
+ [(set (match_operand:DI 0 "register_operand" "=x")
+ (plus:DI (mult:DI
+ (sign_extend:DI (match_operand:SI 2 "register_operand" "%d"))
+ (sign_extend:DI (match_operand:SI 3 "register_operand" "d")))
+ (match_operand:DI 1 "register_operand" "0")))]
+ "TARGET_MAC"
+ "mad %2, %3"
+ [(set_attr "mode" "DI")])
+
+(define_insn "umulsidi3adddi"
+ [(set (match_operand:DI 0 "register_operand" "=x")
+ (plus:DI (mult:DI
+ (zero_extend:DI (match_operand:SI 2 "register_operand" "%d"))
+ (zero_extend:DI (match_operand:SI 3 "register_operand" "d")))
+ (match_operand:DI 1 "register_operand" "0")))]
+ "TARGET_MAC"
+ "madu %2, %3"
+ [(set_attr "mode" "DI")])
+
+(define_insn "mulsidi3subdi"
+ [(set (match_operand:DI 0 "register_operand" "=x")
+ (minus:DI
+ (match_operand:DI 1 "register_operand" "0")
+ (mult:DI
+ (sign_extend:DI (match_operand:SI 2 "register_operand" "%d"))
+ (sign_extend:DI (match_operand:SI 3 "register_operand" "d")))))]
+ "TARGET_MAC"
+ "msb %2, %3"
+ [(set_attr "mode" "DI")])
+
+(define_insn "umulsidi3subdi"
+ [(set (match_operand:DI 0 "register_operand" "=x")
+ (minus:DI
+ (match_operand:DI 1 "register_operand" "0")
+ (mult:DI (zero_extend:DI
+ (match_operand:SI 2 "register_operand" "%d"))
+ (zero_extend:DI
+ (match_operand:SI 3 "register_operand" "d")))))]
+ "TARGET_MAC"
+ "msbu %2, %3"
+ [(set_attr "mode" "DI")])
diff --git a/gcc/config/score/misc.md b/gcc/config/score/misc.md
new file mode 100644
index 00000000000..d19c53538a6
--- /dev/null
+++ b/gcc/config/score/misc.md
@@ -0,0 +1,108 @@
+;; Machine description for Sunplus S+CORE
+;; Copyright (C) 2005
+;; Free Software Foundation, Inc.
+;; Contributed by Sunnorth.
+
+;; 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 2, 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 COPYING. If not, write to
+;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
+
+;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
+
+(define_insn "pushsi"
+ [(set (match_operand:SI 0 "push_operand" "=<")
+ (match_operand:SI 1 "register_operand" "d"))]
+ ""
+ "push! %1, [r0]"
+ [(set_attr "type" "store")
+ (set_attr "mode" "SI")])
+
+(define_insn "popsi"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (match_operand:SI 1 "pop_operand" ">"))]
+ ""
+ "pop! %0, [r0]"
+ [(set_attr "type" "store")
+ (set_attr "mode" "SI")])
+
+(define_peephole2
+ [(set (match_operand:SI 0 "g32reg_operand" "")
+ (match_operand:SI 1 "loreg_operand" ""))
+ (set (match_operand:SI 2 "g32reg_operand" "")
+ (match_operand:SI 3 "hireg_operand" ""))]
+ ""
+ [(parallel
+ [(set (match_dup 0) (match_dup 1))
+ (set (match_dup 2) (match_dup 3))])])
+
+(define_peephole2
+ [(set (match_operand:SI 0 "g32reg_operand" "")
+ (match_operand:SI 1 "hireg_operand" ""))
+ (set (match_operand:SI 2 "g32reg_operand" "")
+ (match_operand:SI 3 "loreg_operand" ""))]
+ ""
+ [(parallel
+ [(set (match_dup 2) (match_dup 3))
+ (set (match_dup 0) (match_dup 1))])])
+
+(define_insn "movhilo"
+ [(parallel
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (match_operand:SI 1 "loreg_operand" ""))
+ (set (match_operand:SI 2 "register_operand" "=d")
+ (match_operand:SI 3 "hireg_operand" ""))])]
+ ""
+ "mfcehl %2, %0"
+ [(set_attr "type" "fce")
+ (set_attr "mode" "SI")])
+
+(define_expand "movsicc"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (if_then_else:SI (match_operator 1 "comparison_operator"
+ [(reg:CC CC_REGNUM) (const_int 0)])
+ (match_operand:SI 2 "register_operand" "")
+ (match_operand:SI 3 "register_operand" "")))]
+ ""
+{
+ mdx_movsicc (operands);
+})
+
+(define_insn "movsicc_internal"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (if_then_else:SI (match_operator 1 "comparison_operator"
+ [(reg:CC CC_REGNUM) (const_int 0)])
+ (match_operand:SI 2 "register_operand" "d")
+ (match_operand:SI 3 "register_operand" "0")))]
+ ""
+ "mv%C1 %0, %2"
+ [(set_attr "type" "cndmv")
+ (set_attr "mode" "SI")])
+
+(define_insn "zero_extract_bittst"
+ [(set (reg:CC_NZ CC_REGNUM)
+ (compare:CC_NZ (unspec:SI
+ [(match_operand:SI 0 "register_operand" "*e,d")
+ (match_operand:SI 1 "const_bi_operand" "")]
+ BITTST)
+ (const_int 0)))]
+ ""
+ "@
+ bittst! %0, %c1
+ bittst.c %0, %c1"
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
diff --git a/gcc/config/score/mul-div.S b/gcc/config/score/mul-div.S
new file mode 100644
index 00000000000..37a2406b20a
--- /dev/null
+++ b/gcc/config/score/mul-div.S
@@ -0,0 +1,224 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+ Contributed by Sunnorth
+
+ 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 2, 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 COPYING. If not, write to
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+#define ra r3
+#define a0 r4
+#define a1 r5
+#define a2 r6
+#define a3 r7
+#define v0 r23
+
+#define t0 r8
+#define t1 r9
+#define t2 r10
+#define t3 r11
+
+#define t4 r22
+
+#if defined(__scorebe__)
+#define LIBGCC1_BIG_ENDIAN
+#define out_H v0
+#define out_L v1
+#define in0_H a0
+#define in0_L a1
+#define in1_H a2
+#define in1_L a3
+#elif defined(__scorele__)
+#define out_H v1
+#define out_L v0
+#define in0_H a1
+#define in0_L a0
+#define in1_H a3
+#define in1_L a2
+#else
+#err "must specify S+core endian!"
+#endif
+
+#if !defined(L_mulsi3) && !defined(L_divsi3)
+ .text
+ .global _flush_cache
+_flush_cache:
+ srli r9, r5, 4
+ mv r8, r4
+ mtsr r9, sr0
+1:
+ cache 0xe, [r8, 0] # write back invalid dcache
+ addi r8, 16
+ bcnz 1b
+ mfcr r8, cr4
+ bittst! r8, 0x3 # if LDM is enable, write back LDM
+ beq! 6f
+ ldi r10, 0
+ cache 0xc, [r10, 0]
+6:
+ bittst! r8, 0x2 # if LIM is enable, refill it
+ beq! 7f
+ cache 0x4, [r10, 0]
+7:
+ #nop!
+ #nop!
+ #nop!
+ #nop!
+ #nop!
+ mv r8, r4
+ mtsr r9, sr0
+2:
+ cache 0x2, [r8, 0] # invalid unlock icache
+ #nop!
+ #nop!
+ #nop!
+ #nop!
+ #nop!
+ addi r8, 16
+ bcnz 2b
+ br r3
+#endif
+
+/* FUNCTION
+ (U) INT32 v0 = __mulsi3 ((U) INT32 a0, (U) INT32 a1);
+ REGISTERS:
+ use t0
+ modify a0
+ a1 -> become 0
+ NOTE:
+ this seems to give better performance to just rotate and add. */
+
+#ifdef L_mulsi3
+ .text
+ .global __umulsi3
+ .global __mulsi3
+ /* signed multiplication (32x32) */
+ .ent __mulsi3
+__umulsi3:
+__mulsi3:
+ li t1, 0
+__mulsi3_loop:
+ andri.c t0, a1, 1 /* t0 = multiplier[0] */
+ srli a1, a1, 1 /* a1 /= 2 */
+ beq __mulsi3_loop2 /* skip if (t0 == 0) */
+ add t1, t1, a0 /* add multiplicand */
+__mulsi3_loop2:
+ slli a0, a0, 1 /* multiplicand mul 2 */
+ cmpi.c a1, 0
+ bne __mulsi3_loop
+ mv r4, t1
+ br ra
+ .end __mulsi3
+#endif /* L_mulsi3 */
+
+
+/* FUNCTION
+ UINT32 (v0) = __udivsi3 (UINT32 (a0), UINT32 (a1));
+ INT32 (v0) = __divsi3 (INT32 (a0), INT32 (a1));
+ UINT32 (v0) = __umodsi3 (UINT32 (a0), UINT32 (a1));
+ INT32 (v0) = __modsi3 (INT32 (a0), INT32 (a1));
+ DESCRIPTION
+ performs 32-bit division/modulo.
+ REGISTERS
+ used t0 bit-index
+ t1
+ modify a0 becomes remainer */
+#ifdef L_divsi3
+ .text
+ .global __udivsi3
+ .global __umodsi3
+ .global __divsi3
+ .global __modsi3
+
+ /* unsigned division */
+ .ent __udivsi3
+__udivsi3:
+ li t4, 0
+ cmpi.c a1, 0
+ beq __uds_exit
+ li t0, 1
+ blt __uds_ok
+__uds_normalize:
+ cmp.c a0, a1
+ bcc __uds_ok
+ slli a1, a1, 1
+ slli t0, t0, 1
+ cmpi.c a1, 0
+ bge __uds_normalize
+__uds_ok:
+__uds_loop2:
+ cmp.c a0, a1
+ bcc __uds_loop3
+ sub a0, a0, a1
+ or t4, t4, t0
+__uds_loop3:
+ srli t0, t0, 1
+ srli a1, a1, 1
+ cmpi.c t0, 0
+ bne __uds_loop2
+__uds_exit:
+ mv a1, a0
+ mv r4, t4
+ br ra
+ .end __udivsi3
+
+ /* unsigned modulus */
+ .ent __umodsi3
+__umodsi3:
+ mv t3, ra
+ jl __udivsi3
+ mv r4, a1
+ br t3
+ .end __umodsi3
+
+ /* abs and div */
+ .ent __orgsi3
+__orgsi3:
+ cmpi.c a0, 0
+ bge __orgsi3_a0p
+ neg a0, a0
+__orgsi3_a0p:
+ cmpi.c a1, 0
+ bge __udivsi3
+ neg a1, a1
+ b __udivsi3 /* goto udivsi3 */
+ .end __orgsi3
+
+ /* signed division */
+ .ent __divsi3
+__divsi3:
+ mv t3, ra
+ xor t2, a0, a1
+ jl __orgsi3
+__divsi3_adjust:
+ cmpi.c t2, 0
+ bge __divsi3_exit
+ neg r4, r4
+__divsi3_exit:
+ br t3
+ .end __divsi3
+
+ /* signed modulus */
+ .ent __modsi3
+__modsi3:
+ mv t3, ra
+ mv t2, a0
+ jl __orgsi3
+ mv r4, a1
+ b __divsi3_adjust
+ .end __modsi3
+
+#endif /* L_divsi3 */
+
diff --git a/gcc/config/score/predicates.md b/gcc/config/score/predicates.md
new file mode 100644
index 00000000000..f1633ec4b2e
--- /dev/null
+++ b/gcc/config/score/predicates.md
@@ -0,0 +1,63 @@
+;; Predicate definitions for Sunplus S+CORE.
+;; Copyright (C) 2005 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 2, 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 COPYING. If not, write to
+;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
+
+(define_predicate "arith_operand"
+ (ior (match_code "const_int")
+ (match_operand 0 "register_operand")))
+
+(define_predicate "const_call_insn_operand"
+ (match_code "const,symbol_ref,label_ref")
+{
+ enum score_symbol_type symbol_type;
+
+ return (mda_symbolic_constant_p (op, &symbol_type)
+ && (symbol_type == SYMBOL_GENERAL));
+})
+
+(define_predicate "call_insn_operand"
+ (ior (match_operand 0 "const_call_insn_operand")
+ (match_operand 0 "register_operand")))
+
+(define_predicate "const_bi_operand"
+ (and (match_code "const_int")
+ (match_test "CONST_OK_FOR_LETTER_P (INTVAL (op), 'J')")))
+
+(define_predicate "pindex_off_operand"
+ (and (match_code "const_int")
+ (match_test "CONST_OK_FOR_LETTER_P (INTVAL (op), 'P')")))
+
+(define_predicate "hireg_operand"
+ (and (match_code "reg")
+ (match_test "REGNO (op) == HI_REGNUM")))
+
+(define_predicate "loreg_operand"
+ (and (match_code "reg")
+ (match_test "REGNO (op) == LO_REGNUM")))
+
+(define_predicate "g32reg_operand"
+ (and (match_code "reg")
+ (match_test "GP_REG_P (REGNO (op))")))
+
+(define_predicate "branch_n_operator"
+ (match_code "lt,ge"))
+
+(define_predicate "branch_nz_operator"
+ (match_code "eq,ne,lt,ge"))
+
diff --git a/gcc/config/score/score-conv.h b/gcc/config/score/score-conv.h
new file mode 100644
index 00000000000..72730d89b83
--- /dev/null
+++ b/gcc/config/score/score-conv.h
@@ -0,0 +1,82 @@
+/* score-conv.h for Sunplus S+CORE processor
+ Copyright (C) 2005 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 2, 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 COPYING. If not, write to
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+#ifndef SCORE_CONV_0601
+#define SCORE_CONV_0601
+
+extern int target_flags;
+
+#define GP_REG_FIRST 0U
+#define GP_REG_LAST 31U
+#define GP_REG_NUM (GP_REG_LAST - GP_REG_FIRST + 1U)
+#define GP_DBX_FIRST 0U
+
+#define CE_REG_FIRST 48U
+#define CE_REG_LAST 49U
+#define CE_REG_NUM (CE_REG_LAST - CE_REG_FIRST + 1U)
+
+#define ARG_REG_FIRST 4U
+#define ARG_REG_LAST 7U
+#define ARG_REG_NUM (ARG_REG_LAST - ARG_REG_FIRST + 1U)
+
+#define REG_CONTAIN(REGNO, FIRST, NUM) \
+ ((unsigned int)((int) (REGNO) - (FIRST)) < (NUM))
+
+#define GP_REG_P(REGNO) REG_CONTAIN (REGNO, GP_REG_FIRST, GP_REG_NUM)
+
+#define G16_REG_P(REGNO) REG_CONTAIN (REGNO, GP_REG_FIRST, 16)
+
+#define CE_REG_P(REGNO) REG_CONTAIN (REGNO, CE_REG_FIRST, CE_REG_NUM)
+
+#define UIMM_IN_RANGE(V, W) ((V) >= 0 && (V) < ((HOST_WIDE_INT)1 << (W)))
+
+#define SIMM_IN_RANGE(V, W) \
+ ((V) >= (-1 * ((HOST_WIDE_INT) 1 << ((W) - 1))) \
+ && (V) < (1 * ((HOST_WIDE_INT) 1 << ((W) - 1))))
+
+#define IMM_IN_RANGE(V, W, S) \
+ ((S) ? SIMM_IN_RANGE (V, W) : UIMM_IN_RANGE (V, W))
+
+#define SCORE_STACK_ALIGN(LOC) (((LOC) + 3) & ~3)
+
+#define SCORE_MAX_FIRST_STACK_STEP (0x3ff0)
+
+#define SCORE_SDATA_MAX score_sdata_max ()
+
+#define DEFAULT_SDATA_MAX 8
+
+#define CONST_HIGH_PART(VALUE) \
+ (((VALUE) + 0x8000) & ~(unsigned HOST_WIDE_INT) 0xffff)
+
+#define CONST_LOW_PART(VALUE) ((VALUE) - CONST_HIGH_PART (VALUE))
+
+#define PROLOGUE_TEMP_REGNUM (GP_REG_FIRST + 8)
+
+#define EPILOGUE_TEMP_REGNUM (GP_REG_FIRST + 8)
+
+enum score_symbol_type
+{
+ SYMBOL_GENERAL,
+ SYMBOL_SMALL_DATA /* The symbol refers to something in a small data section. */
+};
+
+int score_sdata_max (void);
+
+#endif
diff --git a/gcc/config/score/score-mdaux.c b/gcc/config/score/score-mdaux.c
new file mode 100644
index 00000000000..6f72fb6a465
--- /dev/null
+++ b/gcc/config/score/score-mdaux.c
@@ -0,0 +1,738 @@
+/* score-mdaux.c for Sunplus S+CORE processor
+ Copyright (C) 2005 Free Software Foundation, Inc.
+ Contributed by Sunnorth
+
+ 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 2, 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 COPYING. If not, write to
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include <signal.h>
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "real.h"
+#include "insn-config.h"
+#include "conditions.h"
+#include "insn-attr.h"
+#include "recog.h"
+#include "toplev.h"
+#include "output.h"
+#include "tree.h"
+#include "function.h"
+#include "expr.h"
+#include "optabs.h"
+#include "flags.h"
+#include "reload.h"
+#include "tm_p.h"
+#include "ggc.h"
+#include "gstab.h"
+#include "hashtab.h"
+#include "debug.h"
+#include "target.h"
+#include "target-def.h"
+#include "integrate.h"
+#include "langhooks.h"
+#include "cfglayout.h"
+#include "score-mdaux.h"
+
+#define BITSET_P(VALUE, BIT) (((VALUE) & (1L << (BIT))) != 0)
+#define INS_BUF_SZ 100
+
+/* Define the information needed to generate branch insns. This is
+ stored from the compare operation. */
+rtx cmp_op0, cmp_op1;
+
+static char ins[INS_BUF_SZ + 8];
+
+/* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points
+ to the same object as SYMBOL. */
+static int
+score_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset)
+{
+ if (GET_CODE (symbol) != SYMBOL_REF)
+ return 0;
+
+ if (CONSTANT_POOL_ADDRESS_P (symbol)
+ && offset >= 0
+ && offset < (int)GET_MODE_SIZE (get_pool_mode (symbol)))
+ return 1;
+
+ if (SYMBOL_REF_DECL (symbol) != 0
+ && offset >= 0
+ && offset < int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol))))
+ return 1;
+
+ return 0;
+}
+
+/* Split X into a base and a constant offset, storing them in *BASE
+ and *OFFSET respectively. */
+static void
+score_split_const (rtx x, rtx *base, HOST_WIDE_INT *offset)
+{
+ *offset = 0;
+
+ if (GET_CODE (x) == CONST)
+ x = XEXP (x, 0);
+
+ if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
+ {
+ *offset += INTVAL (XEXP (x, 1));
+ x = XEXP (x, 0);
+ }
+
+ *base = x;
+}
+
+/* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */
+static enum
+score_symbol_type score_classify_symbol (rtx x)
+{
+ if (GET_CODE (x) == LABEL_REF)
+ return SYMBOL_GENERAL;
+
+ if (GET_CODE (x) != SYMBOL_REF)
+ gcc_unreachable ();
+
+ if (CONSTANT_POOL_ADDRESS_P(x))
+ {
+ if (GET_MODE_SIZE (get_pool_mode (x)) <= SCORE_SDATA_MAX)
+ return SYMBOL_SMALL_DATA;
+ return SYMBOL_GENERAL;
+ }
+ if (SYMBOL_REF_SMALL_P (x))
+ return SYMBOL_SMALL_DATA;
+ return SYMBOL_GENERAL;
+}
+
+/* Return true if the current function must save REGNO. */
+static int
+score_save_reg_p (unsigned int regno)
+{
+ /* Check call-saved registers. */
+ if (regs_ever_live[regno] && !call_used_regs[regno])
+ return 1;
+
+ /* We need to save the old frame pointer before setting up a new one. */
+ if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
+ return 1;
+
+ /* We need to save the incoming return address if it is ever clobbered
+ within the function. */
+ if (regno == RA_REGNUM && regs_ever_live[regno])
+ return 1;
+
+ return 0;
+}
+
+/* Return one word of double-word value OP, taking into account the fixed
+ endianness of certain registers. HIGH_P is true to select the high part,
+ false to select the low part. */
+static rtx
+subw (rtx op, int high_p)
+{
+ unsigned int byte;
+ enum machine_mode mode = GET_MODE (op);
+
+ if (mode == VOIDmode)
+ mode = DImode;
+
+ byte = (TARGET_LITTLE_ENDIAN ? high_p : !high_p) ? UNITS_PER_WORD : 0;
+
+ if (GET_CODE (op) == REG && REGNO (op) == HI_REGNUM)
+ return gen_rtx_REG (SImode, high_p ? HI_REGNUM : LO_REGNUM);
+
+ if (GET_CODE (op) == MEM)
+ return adjust_address (op, SImode, byte);
+
+ return simplify_gen_subreg (SImode, op, mode, byte);
+}
+
+struct score_frame_info *
+mda_cached_frame (void)
+{
+ static struct score_frame_info _frame_info;
+ return &_frame_info;
+}
+
+/* Return the bytes needed to compute the frame pointer from the current
+ stack pointer. SIZE is the size (in bytes) of the local variables. */
+struct score_frame_info *
+mda_compute_frame_size (HOST_WIDE_INT size)
+{
+ unsigned int regno;
+ struct score_frame_info *f = mda_cached_frame ();
+
+ memset (f, 0, sizeof (struct score_frame_info));
+ f->gp_reg_size = 0;
+ f->mask = 0;
+ f->var_size = SCORE_STACK_ALIGN (size);
+ f->args_size = current_function_outgoing_args_size;
+ f->cprestore_size = SCORE_STACK_ALIGN (STARTING_FRAME_OFFSET) - f->args_size;
+ if (f->var_size == 0 && current_function_is_leaf)
+ f->args_size = f->cprestore_size = 0;
+
+ if (f->args_size == 0 && current_function_calls_alloca)
+ f->args_size = UNITS_PER_WORD;
+
+ f->total_size = f->var_size + f->args_size;
+ for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
+ {
+ if (score_save_reg_p (regno))
+ {
+ f->gp_reg_size += GET_MODE_SIZE (SImode);
+ f->mask |= 1 << (regno - GP_REG_FIRST);
+ }
+ }
+
+ if (current_function_calls_eh_return)
+ {
+ unsigned int i;
+ for (i = 0; ; ++i)
+ {
+ regno = EH_RETURN_DATA_REGNO (i);
+ if (regno == INVALID_REGNUM)
+ break;
+ f->gp_reg_size += GET_MODE_SIZE (SImode);
+ f->mask |= 1 << (regno - GP_REG_FIRST);
+ }
+ }
+
+ f->total_size += SCORE_STACK_ALIGN (f->gp_reg_size);
+ f->num_gp = f->gp_reg_size / UNITS_PER_WORD;
+
+ if (f->mask)
+ {
+ HOST_WIDE_INT offset;
+ offset = (f->args_size + f->cprestore_size + f->var_size
+ + f->gp_reg_size - GET_MODE_SIZE (SImode));
+ f->gp_sp_offset = offset;
+ }
+ else
+ {
+ f->gp_sp_offset = 0;
+ }
+
+ if ((f->total_size == f->gp_reg_size) && flag_pic)
+ f->total_size += 8;
+
+ return f;
+}
+
+/* Generate the prologue instructions for entry into a S+core function. */
+void
+mdx_prologue (void)
+{
+#define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
+
+ struct score_frame_info *f = mda_compute_frame_size (get_frame_size ());
+ HOST_WIDE_INT size;
+ int regno;
+
+ size = f->total_size - f->gp_reg_size;
+
+ if (flag_pic)
+ emit_insn (gen_cpload ());
+
+ for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--)
+ {
+ if (BITSET_P (f->mask, regno - GP_REG_FIRST))
+ {
+ rtx mem = gen_rtx_MEM (SImode,
+ gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
+ rtx reg = gen_rtx_REG (SImode, regno);
+ if (!current_function_calls_eh_return)
+ MEM_READONLY_P (mem) = 1;
+ EMIT_PL (emit_insn (gen_pushsi (mem, reg)));
+ }
+ }
+
+ if (size > 0)
+ {
+ rtx insn;
+
+ if (CONST_OK_FOR_LETTER_P (-size, 'L'))
+ EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx,
+ stack_pointer_rtx,
+ GEN_INT (-size))));
+ else
+ {
+ EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode, PROLOGUE_TEMP_REGNUM),
+ GEN_INT (size)));
+ EMIT_PL (emit_insn
+ (gen_sub3_insn (stack_pointer_rtx,
+ stack_pointer_rtx,
+ gen_rtx_REG (Pmode,
+ PROLOGUE_TEMP_REGNUM))));
+ }
+ insn = get_last_insn ();
+ REG_NOTES (insn) =
+ alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+ gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+ plus_constant (stack_pointer_rtx,
+ -size)),
+ REG_NOTES (insn));
+ }
+
+ if (frame_pointer_needed)
+ EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
+
+ if (flag_pic)
+ emit_insn (gen_cprestore (GEN_INT (size + 4)));
+
+#undef EMIT_PL
+}
+
+/* Generate the epilogue instructions in a S+core function. */
+void
+mdx_epilogue (int sibcall_p)
+{
+ struct score_frame_info *f = mda_compute_frame_size (get_frame_size ());
+ HOST_WIDE_INT size;
+ int regno;
+ rtx base;
+
+ size = f->total_size - f->gp_reg_size;
+
+ if (!frame_pointer_needed)
+ base = stack_pointer_rtx;
+ else
+ base = hard_frame_pointer_rtx;
+
+ if (size)
+ {
+ if (CONST_OK_FOR_LETTER_P (size, 'L'))
+ emit_insn (gen_add3_insn (base, base, GEN_INT (size)));
+ else
+ {
+ emit_move_insn (gen_rtx_REG (Pmode, EPILOGUE_TEMP_REGNUM),
+ GEN_INT (size));
+ emit_insn (gen_add3_insn (base, base,
+ gen_rtx_REG (Pmode,
+ EPILOGUE_TEMP_REGNUM)));
+ }
+ }
+
+ if (base != stack_pointer_rtx)
+ emit_move_insn (stack_pointer_rtx, base);
+
+ if (current_function_calls_eh_return)
+ emit_insn (gen_add3_insn (stack_pointer_rtx,
+ stack_pointer_rtx,
+ EH_RETURN_STACKADJ_RTX));
+
+ for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++)
+ {
+ if (BITSET_P (f->mask, regno - GP_REG_FIRST))
+ {
+ rtx mem = gen_rtx_MEM (SImode,
+ gen_rtx_POST_INC (SImode, stack_pointer_rtx));
+ rtx reg = gen_rtx_REG (SImode, regno);
+
+ if (!current_function_calls_eh_return)
+ MEM_READONLY_P (mem) = 1;
+
+ emit_insn (gen_popsi (reg, mem));
+ }
+ }
+
+ if (!sibcall_p)
+ emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, RA_REGNUM)));
+}
+
+/* Return true if X is a valid base register for the given mode.
+ Allow only hard registers if STRICT. */
+int
+mda_valid_base_register_p (rtx x, int strict)
+{
+ if (!strict && GET_CODE (x) == SUBREG)
+ x = SUBREG_REG (x);
+
+ return (GET_CODE (x) == REG
+ && score_regno_mode_ok_for_base_p (REGNO (x), strict));
+}
+
+/* Return true if X is a valid address for machine mode MODE. If it is,
+ fill in INFO appropriately. STRICT is true if we should only accept
+ hard base registers. */
+int
+mda_classify_address (struct score_address_info *info,
+ enum machine_mode mode, rtx x, int strict)
+{
+ info->code = GET_CODE (x);
+
+ switch (info->code)
+ {
+ case REG:
+ case SUBREG:
+ info->type = ADD_REG;
+ info->reg = x;
+ info->offset = const0_rtx;
+ return mda_valid_base_register_p (info->reg, strict);
+ case PLUS:
+ info->type = ADD_REG;
+ info->reg = XEXP (x, 0);
+ info->offset = XEXP (x, 1);
+ return (mda_valid_base_register_p (info->reg, strict)
+ && GET_CODE (info->offset) == CONST_INT
+ && CONST_OK_FOR_LETTER_P (INTVAL (info->offset), 'O'));
+ case PRE_DEC:
+ case POST_DEC:
+ case PRE_INC:
+ case POST_INC:
+ if (TARGET_NOPINDEX || GET_MODE_SIZE (mode) > GET_MODE_SIZE (SImode))
+ return false;
+ info->type = ADD_REG;
+ info->reg = XEXP (x, 0);
+ info->offset = GEN_INT (GET_MODE_SIZE (mode));
+ return mda_valid_base_register_p (info->reg, strict);
+ case CONST_INT:
+ info->type = ADD_CONST_INT;
+ return CONST_OK_FOR_LETTER_P (INTVAL (x), 'O');
+ case CONST:
+ case LABEL_REF:
+ case SYMBOL_REF:
+ info->type = ADD_SYMBOLIC;
+ return (mda_symbolic_constant_p (x, &info->symbol_type)
+ && (info->symbol_type == SYMBOL_GENERAL
+ || info->symbol_type == SYMBOL_SMALL_DATA));
+ default:
+ return 0;
+ }
+}
+
+void
+mda_gen_cmp (enum machine_mode mode)
+{
+ emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
+ gen_rtx_COMPARE (mode, cmp_op0, cmp_op1)));
+}
+
+/* Return true if X is a symbolic constant that can be calculated in
+ the same way as a bare symbol. If it is, store the type of the
+ symbol in *SYMBOL_TYPE. */
+int
+mda_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type)
+{
+ HOST_WIDE_INT offset;
+
+ score_split_const (x, &x, &offset);
+ if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
+ *symbol_type = score_classify_symbol (x);
+ else
+ return 0;
+
+ if (offset == 0)
+ return 1;
+
+ /* if offset > 15bit, must reload */
+ if (!CONST_OK_FOR_LETTER_P (offset, 'O'))
+ return 0;
+
+ switch (*symbol_type)
+ {
+ case SYMBOL_GENERAL:
+ return 1;
+ case SYMBOL_SMALL_DATA:
+ return score_offset_within_object_p (x, offset);
+ }
+ gcc_unreachable ();
+}
+
+void
+mdx_movsicc (rtx *ops)
+{
+ enum machine_mode mode = CCmode;
+
+ if (GET_CODE (ops[1]) == EQ || GET_CODE (ops[1]) == NE)
+ mode = CC_NZmode;
+
+ emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
+ gen_rtx_COMPARE (mode, cmp_op0, cmp_op1)));
+}
+
+/* Call and sibcall pattern all need call this function. */
+void
+mdx_call (rtx *ops, bool sib)
+{
+ rtx addr = XEXP (ops[0], 0);
+ if (!call_insn_operand (addr, VOIDmode))
+ {
+ rtx oaddr = addr;
+ addr = gen_reg_rtx (Pmode);
+ gen_move_insn (addr, oaddr);
+ }
+
+ if (sib)
+ emit_call_insn (gen_sibcall_internal (addr, ops[1]));
+ else
+ emit_call_insn (gen_call_internal (addr, ops[1]));
+}
+
+/* Call value and sibcall value pattern all need call this function. */
+void
+mdx_call_value (rtx *ops, bool sib)
+{
+ rtx result = ops[0];
+ rtx addr = XEXP (ops[1], 0);
+ rtx arg = ops[2];
+
+ if (!call_insn_operand (addr, VOIDmode))
+ {
+ rtx oaddr = addr;
+ addr = gen_reg_rtx (Pmode);
+ gen_move_insn (addr, oaddr);
+ }
+
+ if (sib)
+ emit_call_insn (gen_sibcall_value_internal (result, addr, arg));
+ else
+ emit_call_insn (gen_call_value_internal (result, addr, arg));
+}
+
+/* Machine Split */
+void
+mds_movdi (rtx *ops)
+{
+ rtx dst = ops[0];
+ rtx src = ops[1];
+ rtx dst0 = subw (dst, 0);
+ rtx dst1 = subw (dst, 1);
+ rtx src0 = subw (src, 0);
+ rtx src1 = subw (src, 1);
+
+ if (GET_CODE (dst0) == REG && reg_overlap_mentioned_p (dst0, src))
+ {
+ emit_move_insn (dst1, src1);
+ emit_move_insn (dst0, src0);
+ }
+ else
+ {
+ emit_move_insn (dst0, src0);
+ emit_move_insn (dst1, src1);
+ }
+}
+
+void
+mds_zero_extract_andi (rtx *ops)
+{
+ if (INTVAL (ops[1]) == 1 && const_bi_operand (ops[2], SImode))
+ emit_insn (gen_zero_extract_bittst (ops[0], ops[2]));
+ else
+ {
+ unsigned HOST_WIDE_INT mask;
+ mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U));
+ mask = mask << INTVAL (ops[2]);
+ emit_insn (gen_andsi3_cmp (ops[0], gen_int_mode (mask, SImode)));
+ }
+}
+
+/* Check addr could be present as PRE/POST mode. */
+static bool
+mda_pindex_mem (rtx addr)
+{
+ if (GET_CODE (addr) == MEM)
+ {
+ switch (GET_CODE (XEXP (addr, 0)))
+ {
+ case PRE_DEC:
+ case POST_DEC:
+ case PRE_INC:
+ case POST_INC:
+ return true;
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+/* Output asm code for ld/sw insn. */
+static int
+pr_addr_post (rtx *ops, int idata, int iaddr, char *ip, enum mda_mem_unit unit)
+{
+ struct score_address_info ai;
+
+ gcc_assert (GET_CODE (ops[idata]) == REG);
+ gcc_assert (mda_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true));
+
+ if (!mda_pindex_mem (ops[iaddr])
+ && ai.type == ADD_REG
+ && GET_CODE (ai.offset) == CONST_INT
+ && G16_REG_P (REGNO (ops[idata]))
+ && G16_REG_P (REGNO (ai.reg)))
+ {
+ if (INTVAL (ai.offset) == 0)
+ {
+ ops[iaddr] = ai.reg;
+ return snprintf (ip, INS_BUF_SZ,
+ "! %%%d, [%%%d]", idata, iaddr);
+ }
+ if (REGNO (ai.reg) == HARD_FRAME_POINTER_REGNUM)
+ {
+ HOST_WIDE_INT offset = INTVAL (ai.offset);
+ if (MDA_ALIGN_UNIT (offset, unit)
+ && CONST_OK_FOR_LETTER_P (offset >> unit, 'J'))
+ {
+ ops[iaddr] = ai.offset;
+ return snprintf (ip, INS_BUF_SZ,
+ "p! %%%d, %%c%d", idata, iaddr);
+ }
+ }
+ }
+ return snprintf (ip, INS_BUF_SZ, " %%%d, %%a%d", idata, iaddr);
+}
+
+/* Output asm insn for load. */
+const char *
+mdp_linsn (rtx *ops, enum mda_mem_unit unit, bool sign)
+{
+ const char *pre_ins[] =
+ {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
+ char *ip;
+
+ strcpy (ins, pre_ins[(sign ? 4 : 0) + unit]);
+ ip = ins + strlen (ins);
+
+ if ((!sign && unit != MDA_HWORD)
+ || (sign && unit != MDA_BYTE))
+ pr_addr_post (ops, 0, 1, ip, unit);
+ else
+ snprintf (ip, INS_BUF_SZ, " %%0, %%a1");
+
+ return ins;
+}
+
+/* Output asm insn for store. */
+const char *
+mdp_sinsn (rtx *ops, enum mda_mem_unit unit)
+{
+ const char *pre_ins[] = {"sb", "sh", "sw"};
+ char *ip;
+
+ strcpy (ins, pre_ins[unit]);
+ ip = ins + strlen (ins);
+ pr_addr_post (ops, 1, 0, ip, unit);
+ return ins;
+}
+
+/* Output asm insn for load immediate. */
+const char *
+mdp_limm (rtx *ops)
+{
+ gcc_assert (GET_CODE (ops[0]) == REG);
+
+ if (G16_REG_P (REGNO (ops[0]))
+ && CONST_OK_FOR_LETTER_P (INTVAL (ops[1]), 'I'))
+ return "ldiu! %0, %c1";
+ else if (CONST_OK_FOR_LETTER_P (INTVAL (ops[1]), 'L'))
+ return "ldi %0, %c1";
+ else if (EXTRA_CONSTRAINT (ops[1], 'Q'))
+ return "ldis %0, %U1";
+ else
+ return "li %0, %D1";
+}
+
+/* Output asm insn for move. */
+const char *
+mdp_move (rtx *ops)
+{
+ gcc_assert (GET_CODE (ops[0]) == REG);
+ gcc_assert (GET_CODE (ops[1]) == REG);
+
+ if (G16_REG_P (REGNO (ops[0])))
+ {
+ if (G16_REG_P (REGNO (ops[1])))
+ return "mv! %0, %1";
+ else
+ return "mlfh! %0, %1";
+ }
+ else if (G16_REG_P (REGNO (ops[1])))
+ return "mhfl! %0, %1";
+ else
+ return "mv %0, %1";
+}
+
+/* Score support add/sub with exponent immediate insn,
+ use to judge imm condition. */
+static unsigned int
+num_bits1 (unsigned HOST_WIDE_INT v)
+{
+ int i, n = 0;
+
+ for (i = 0; i < BITS_PER_WORD; i++)
+ n += BITSET_P (v, i) ? 1 : 0;
+ return n;
+}
+
+/* Generate add insn, insn will affect condition flag. Optimize used. */
+const char *
+mdp_add_imm_ucc (rtx *ops)
+{
+ HOST_WIDE_INT v = INTVAL (ops[2]);
+
+ gcc_assert (GET_CODE (ops[2]) == CONST_INT);
+ gcc_assert (REGNO (ops[0]) == REGNO (ops[1]));
+
+ if (G16_REG_P (REGNO (ops[0])))
+ {
+ if (v > 0 && num_bits1 (v) == 1 && IMM_IN_RANGE (ffs (v) - 1, 4, 0))
+ {
+ ops[2] = GEN_INT (ffs (v) - 1);
+ return "addei! %0, %c2";
+ }
+
+ if (v < 0 && num_bits1 (-v) == 1 && IMM_IN_RANGE (ffs (-v) - 1, 4, 0))
+ {
+ ops[2] = GEN_INT (ffs (-v) - 1);
+ return "subei! %0, %c2";
+ }
+ }
+ return "addi.c %0, %c2";
+}
+
+/* Output arith insn, insn will update condition flag. */
+const char *
+mdp_select (rtx *ops, const char *inst_pre, bool commu, const char *let)
+{
+ gcc_assert (GET_CODE (ops[0]) == REG);
+ gcc_assert (GET_CODE (ops[1]) == REG);
+
+ if (G16_REG_P (REGNO (ops[0]))
+ && (GET_CODE (ops[2]) == REG ? G16_REG_P (REGNO (ops[2])) : 1)
+ && REGNO (ops[0]) == REGNO (ops[1]))
+ {
+ snprintf (ins, INS_BUF_SZ, "%s! %%0, %%%s2", inst_pre, let);
+ return ins;
+ }
+
+ if (commu && G16_REG_P (REGNO (ops[0]))
+ && G16_REG_P (REGNO (ops[1]))
+ && REGNO (ops[0]) == REGNO (ops[2]))
+ {
+ gcc_assert (GET_CODE (ops[2]) == REG);
+ snprintf (ins, INS_BUF_SZ, "%s! %%0, %%%s1", inst_pre, let);
+ return ins;
+ }
+
+ snprintf (ins, INS_BUF_SZ, "%s.c %%0, %%1, %%%s2", inst_pre, let);
+ return ins;
+}
+
diff --git a/gcc/config/score/score-mdaux.h b/gcc/config/score/score-mdaux.h
new file mode 100644
index 00000000000..965174996b0
--- /dev/null
+++ b/gcc/config/score/score-mdaux.h
@@ -0,0 +1,113 @@
+/* score-mdaux.h for Sunplus S+CORE processor
+ Copyright (C) 2005 Free Software Foundation, Inc.
+ Contributed by Sunnorth
+
+ 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 2, 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 COPYING. If not, write to
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+#ifndef SCORE_MDAUX_0621
+#define SCORE_MDAUX_0621
+
+/* Machine Auxiliary Functions. */
+enum score_address_type
+{
+ ADD_REG,
+ ADD_CONST_INT,
+ ADD_SYMBOLIC
+};
+#ifdef RTX_CODE
+struct score_address_info
+{
+ enum score_address_type type;
+ rtx reg;
+ rtx offset;
+ enum rtx_code code;
+ enum score_symbol_type symbol_type;
+};
+#endif
+
+struct score_frame_info
+{
+ HOST_WIDE_INT total_size; /* bytes that the entire frame takes up */
+ HOST_WIDE_INT var_size; /* bytes that variables take up */
+ HOST_WIDE_INT args_size; /* bytes that outgoing arguments take up */
+ HOST_WIDE_INT gp_reg_size; /* bytes needed to store gp regs */
+ HOST_WIDE_INT gp_sp_offset; /* offset from new sp to store gp registers */
+ HOST_WIDE_INT cprestore_size; /* # bytes that the .cprestore slot takes up */
+ unsigned int mask; /* mask of saved gp registers */
+ int num_gp; /* number of gp registers saved */
+};
+
+typedef void (*score_save_restore_fn) (rtx, rtx);
+
+int mda_valid_base_register_p (rtx x, int strict);
+
+#ifdef RTX_CODE
+int mda_classify_address (struct score_address_info *info,
+ enum machine_mode mode, rtx x, int strict);
+
+struct score_frame_info *mda_compute_frame_size (HOST_WIDE_INT size);
+
+struct score_frame_info *mda_cached_frame (void);
+
+void mda_gen_cmp (enum machine_mode mode);
+#endif
+
+int mda_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type);
+
+bool mda_pindex_mem (rtx addr);
+
+int mda_bp (void);
+
+/* Machine Expand. */
+void mdx_prologue (void);
+
+void mdx_epilogue (int sibcall_p);
+
+void mdx_movsicc (rtx *ops);
+
+void mdx_call (rtx *ops, bool sibcall);
+
+void mdx_call_value (rtx *ops, bool sibcall);
+
+/* Machine Split. */
+void mds_movdi (rtx *ops);
+
+void mds_addsi (rtx *ops);
+
+void mds_zero_extract_andi (rtx *ops);
+
+/* Machine Print. */
+enum mda_mem_unit {MDA_BYTE = 0, MDA_HWORD = 1, MDA_WORD = 2};
+
+#define MDA_ALIGN_UNIT(V, UNIT) !(V & ((1 << UNIT) - 1))
+
+const char * mdp_linsn (rtx *ops, enum mda_mem_unit unit, bool sign);
+
+const char * mdp_sinsn (rtx *ops, enum mda_mem_unit unit);
+
+const char * mdp_add_imm_ucc (rtx *ops);
+
+const char * mdp_select (rtx *ops, const char *inst_pre,
+ bool comu, const char *let);
+
+const char * mdp_limm (rtx *ops);
+
+const char * mdp_move (rtx *ops);
+
+#endif
+
diff --git a/gcc/config/score/score-modes.def b/gcc/config/score/score-modes.def
new file mode 100644
index 00000000000..2f076f5b8e6
--- /dev/null
+++ b/gcc/config/score/score-modes.def
@@ -0,0 +1,26 @@
+/* score-modes.def for Sunplus S+CORE processor
+ Copyright (C) 2005 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 2, 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 COPYING. If not, write to
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* CC_NZmode should be used if the N (sign) and Z (zero) flag is set correctly.
+ CC_Nmode should be used if only the N flag is set correctly. */
+
+CC_MODE (CC_NZ);
+CC_MODE (CC_N);
+
diff --git a/gcc/config/score/score-protos.h b/gcc/config/score/score-protos.h
new file mode 100644
index 00000000000..bbe444e91d1
--- /dev/null
+++ b/gcc/config/score/score-protos.h
@@ -0,0 +1,92 @@
+/* score-protos.h for Sunplus S+CORE processor
+ Copyright (C) 2005 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 2, 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 COPYING. If not, write to
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+#ifndef __SCORE_PROTOS_H__
+#define __SCORE_PROTOS_H__
+
+extern enum reg_class score_char_to_class[];
+
+void score_override_options (void);
+
+void score_init_expanders (void);
+
+int score_hard_regno_mode_ok (unsigned int, enum machine_mode);
+
+int score_reg_class (int regno);
+
+enum reg_class score_preferred_reload_class (rtx x, enum reg_class class);
+
+enum reg_class score_secondary_reload_class (enum reg_class class,
+ enum machine_mode mode, rtx x);
+
+int score_const_ok_for_letter_p (int value, char c);
+
+int score_extra_constraint (rtx op, char c);
+
+rtx score_return_addr (int count, rtx frame);
+
+HOST_WIDE_INT score_initial_elimination_offset (int from, int to);
+
+rtx score_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
+ tree type, int named);
+
+int score_arg_partial_nregs (const CUMULATIVE_ARGS *cum,
+ enum machine_mode mode, tree type, int named);
+
+void score_init_cumulative_args (CUMULATIVE_ARGS *cum,
+ tree fntype, rtx libname);
+
+void score_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+ tree type, int named);
+
+rtx score_function_value (tree valtype, tree func, enum machine_mode mode);
+
+rtx score_va_arg (tree va_list, tree type);
+
+void score_initialize_trampoline (rtx ADDR, rtx FUNC, rtx CHAIN);
+
+int score_address_p (enum machine_mode mode, rtx x, int strict);
+
+int score_legitimize_address (rtx *xloc);
+
+int score_regno_mode_ok_for_base_p (int regno, int strict);
+
+int score_register_move_cost (enum machine_mode mode, enum reg_class to,
+ enum reg_class from);
+
+void score_declare_object (FILE *stream, const char *name,
+ const char *directive, const char *fmt, ...);
+
+void score_declare_object_name (FILE *stream, const char *name, tree decl);
+
+int score_output_external (FILE *file, tree decl, const char *name);
+
+void score_print_operand (FILE *file, rtx op, int letter);
+
+void score_print_operand_address (FILE *file, rtx addr);
+
+#ifdef RTX_CODE
+enum machine_mode score_select_cc_mode (enum rtx_code op, rtx x, rtx y);
+#endif
+
+#include "score-mdaux.h"
+
+#endif /* __SCORE_PROTOS_H__ */
+
diff --git a/gcc/config/score/score-version.h b/gcc/config/score/score-version.h
new file mode 100644
index 00000000000..2eeaf2f0d99
--- /dev/null
+++ b/gcc/config/score/score-version.h
@@ -0,0 +1,21 @@
+/* score-version.h for Sunplus S+CORE processor
+ Copyright (C) 2005 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 2, 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 COPYING. If not, write to
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+#define SCORE_GCC_VERSION "1.1"
diff --git a/gcc/config/score/score.c b/gcc/config/score/score.c
new file mode 100644
index 00000000000..458de7922e2
--- /dev/null
+++ b/gcc/config/score/score.c
@@ -0,0 +1,1071 @@
+/* Output routines for Sunplus S+CORE processor
+ Copyright (C) 2005 Free Software Foundation, Inc.
+ Contributed by Sunnorth.
+
+ 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 2, 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 COPYING. If not, write to
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include <signal.h>
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "real.h"
+#include "insn-config.h"
+#include "conditions.h"
+#include "insn-attr.h"
+#include "recog.h"
+#include "toplev.h"
+#include "output.h"
+#include "tree.h"
+#include "function.h"
+#include "expr.h"
+#include "optabs.h"
+#include "flags.h"
+#include "reload.h"
+#include "tm_p.h"
+#include "ggc.h"
+#include "gstab.h"
+#include "hashtab.h"
+#include "debug.h"
+#include "target.h"
+#include "target-def.h"
+#include "integrate.h"
+#include "langhooks.h"
+#include "cfglayout.h"
+#include "score-mdaux.h"
+
+#define GR_REG_CLASS_P(C) ((C) == G16_REGS || (C) == G32_REGS)
+#define SP_REG_CLASS_P(C) \
+ ((C) == CN_REG || (C) == LC_REG || (C) == SC_REG || (C) == SP_REGS)
+#define CP_REG_CLASS_P(C) \
+ ((C) == CP1_REGS || (C) == CP2_REGS || (C) == CP3_REGS || (C) == CPA_REGS)
+#define CE_REG_CLASS_P(C) \
+ ((C) == HI_REG || (C) == LO_REG || (C) == CE_REGS)
+
+static int score_arg_partial_bytes (const CUMULATIVE_ARGS *cum,
+ enum machine_mode mode,
+ tree type, int named);
+
+#undef TARGET_ASM_FILE_START
+#define TARGET_ASM_FILE_START th_asm_file_start
+
+#undef TARGET_ASM_FILE_END
+#define TARGET_ASM_FILE_END th_asm_file_end
+
+#undef TARGET_ASM_FUNCTION_PROLOGUE
+#define TARGET_ASM_FUNCTION_PROLOGUE th_function_prologue
+
+#undef TARGET_ASM_FUNCTION_EPILOGUE
+#define TARGET_ASM_FUNCTION_EPILOGUE th_function_epilogue
+
+#undef TARGET_SCHED_ISSUE_RATE
+#define TARGET_SCHED_ISSUE_RATE th_issue_rate
+
+#undef TARGET_ASM_SELECT_RTX_SECTION
+#define TARGET_ASM_SELECT_RTX_SECTION th_select_rtx_section
+
+#undef TARGET_IN_SMALL_DATA_P
+#define TARGET_IN_SMALL_DATA_P th_in_small_data_p
+
+#undef TARGET_FUNCTION_OK_FOR_SIBCALL
+#define TARGET_FUNCTION_OK_FOR_SIBCALL th_function_ok_for_sibcall
+
+#undef TARGET_STRICT_ARGUMENT_NAMING
+#define TARGET_STRICT_ARGUMENT_NAMING th_strict_argument_naming
+
+#undef TARGET_ASM_OUTPUT_MI_THUNK
+#define TARGET_ASM_OUTPUT_MI_THUNK th_output_mi_thunk
+
+#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
+#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true
+
+#undef TARGET_PROMOTE_FUNCTION_ARGS
+#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
+
+#undef TARGET_PROMOTE_FUNCTION_RETURN
+#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
+
+#undef TARGET_PROMOTE_PROTOTYPES
+#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
+
+#undef TARGET_MUST_PASS_IN_STACK
+#define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
+
+#undef TARGET_ARG_PARTIAL_BYTES
+#define TARGET_ARG_PARTIAL_BYTES score_arg_partial_bytes
+
+#undef TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE score_pass_by_reference
+
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY score_return_in_memory
+
+/* Implement TARGET_RETURN_IN_MEMORY. In S+core,
+ small structures are returned in a register.
+ Objects with varying size must still be returned in memory. */
+static bool
+score_return_in_memory (tree type, tree fndecl ATTRIBUTE_UNUSED)
+{
+ return ((TYPE_MODE (type) == BLKmode)
+ || (int_size_in_bytes (type) > 2 * UNITS_PER_WORD)
+ || (int_size_in_bytes (type) == -1));
+}
+
+/* Return nonzero when an argument must be passed by reference. */
+static bool
+score_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
+ enum machine_mode mode, tree type,
+ bool named ATTRIBUTE_UNUSED)
+{
+ /* If we have a variable-sized parameter, we have no choice. */
+ return targetm.calls.must_pass_in_stack (mode, type);
+}
+
+/* Return a legitimate address for REG + OFFSET. */
+static rtx
+score_add_offset (rtx temp, rtx reg, HOST_WIDE_INT offset)
+{
+ if (!CONST_OK_FOR_LETTER_P (offset, 'O'))
+ {
+ reg = expand_simple_binop (GET_MODE (reg), PLUS,
+ gen_int_mode (offset & 0xffffc000,
+ GET_MODE (reg)),
+ reg, NULL, 0, OPTAB_WIDEN);
+ offset &= 0x3fff;
+ }
+
+ return plus_constant (reg, offset);
+}
+
+/* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text
+ in order to avoid duplicating too much logic from elsewhere. */
+static void
+th_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
+ HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
+ tree function)
+{
+ rtx this, temp1, temp2, insn, fnaddr;
+
+ /* Pretend to be a post-reload pass while generating rtl. */
+ no_new_pseudos = 1;
+ reload_completed = 1;
+ reset_block_changes ();
+
+ /* We need two temporary registers in some cases. */
+ temp1 = gen_rtx_REG (Pmode, 8);
+ temp2 = gen_rtx_REG (Pmode, 9);
+
+ /* Find out which register contains the "this" pointer. */
+ if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
+ this = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1);
+ else
+ this = gen_rtx_REG (Pmode, ARG_REG_FIRST);
+
+ /* Add DELTA to THIS. */
+ if (delta != 0)
+ {
+ rtx offset = GEN_INT (delta);
+ if (!CONST_OK_FOR_LETTER_P (delta, 'L'))
+ {
+ emit_move_insn (temp1, offset);
+ offset = temp1;
+ }
+ emit_insn (gen_add3_insn (this, this, offset));
+ }
+
+ /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */
+ if (vcall_offset != 0)
+ {
+ rtx addr;
+
+ /* Set TEMP1 to *THIS. */
+ emit_move_insn (temp1, gen_rtx_MEM (Pmode, this));
+
+ /* Set ADDR to a legitimate address for *THIS + VCALL_OFFSET. */
+ addr = score_add_offset (temp2, temp1, vcall_offset);
+
+ /* Load the offset and add it to THIS. */
+ emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr));
+ emit_insn (gen_add3_insn (this, this, temp1));
+ }
+
+ /* Jump to the target function. */
+ fnaddr = XEXP (DECL_RTL (function), 0);
+ insn = emit_call_insn (gen_sibcall_internal (fnaddr, const0_rtx));
+ SIBLING_CALL_P (insn) = 1;
+
+ /* Run just enough of rest_of_compilation. This sequence was
+ "borrowed" from alpha.c. */
+ insn = get_insns ();
+ insn_locators_initialize ();
+ split_all_insns_noflow ();
+ shorten_branches (insn);
+ final_start_function (insn, file, 1);
+ final (insn, file, 1);
+ final_end_function ();
+
+ /* Clean up the vars set above. Note that final_end_function resets
+ the global pointer for us. */
+ reload_completed = 0;
+ no_new_pseudos = 0;
+}
+
+/* Implement TARGET_STRICT_ARGUMENT_NAMING. */
+static bool
+th_strict_argument_naming (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED)
+{
+ return true;
+}
+
+/* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
+static bool
+th_function_ok_for_sibcall (ATTRIBUTE_UNUSED tree decl,
+ ATTRIBUTE_UNUSED tree exp)
+{
+ return true;
+}
+
+struct score_arg_info
+{
+ /* The argument's size, in bytes. */
+ unsigned int num_bytes;
+
+ /* The number of words passed in registers, rounded up. */
+ unsigned int reg_words;
+
+ /* The offset of the first register from GP_ARG_FIRST or FP_ARG_FIRST,
+ or ARG_REG_NUM if the argument is passed entirely on the stack. */
+ unsigned int reg_offset;
+
+ /* The number of words that must be passed on the stack, rounded up. */
+ unsigned int stack_words;
+
+ /* The offset from the start of the stack overflow area of the argument's
+ first stack word. Only meaningful when STACK_WORDS is nonzero. */
+ unsigned int stack_offset;
+};
+
+/* Fill INFO with information about a single argument. CUM is the
+ cumulative state for earlier arguments. MODE is the mode of this
+ argument and TYPE is its type (if known). NAMED is true if this
+ is a named (fixed) argument rather than a variable one. */
+static void
+classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
+ tree type, int named, struct score_arg_info *info)
+{
+ int even_reg_p;
+ unsigned int num_words, max_regs;
+
+ even_reg_p = 0;
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ || GET_MODE_CLASS (mode) == MODE_FLOAT)
+ even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD);
+ else
+ if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named)
+ even_reg_p = 1;
+
+ if (TARGET_MUST_PASS_IN_STACK (mode, type))
+ info->reg_offset = ARG_REG_NUM;
+ else
+ {
+ info->reg_offset = cum->num_gprs;
+ if (even_reg_p)
+ info->reg_offset += info->reg_offset & 1;
+ }
+
+ if (mode == BLKmode)
+ info->num_bytes = int_size_in_bytes (type);
+ else
+ info->num_bytes = GET_MODE_SIZE (mode);
+
+ num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+ max_regs = ARG_REG_NUM - info->reg_offset;
+
+ /* Partition the argument between registers and stack. */
+ info->reg_words = MIN (num_words, max_regs);
+ info->stack_words = num_words - info->reg_words;
+
+ /* The alignment applied to registers is also applied to stack arguments. */
+ if (info->stack_words)
+ {
+ info->stack_offset = cum->stack_words;
+ if (even_reg_p)
+ info->stack_offset += info->stack_offset & 1;
+ }
+}
+
+/* Set up the stack and frame (if desired) for the function. */
+static void
+th_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
+{
+ const char *fnname;
+ struct score_frame_info *f = mda_cached_frame ();
+ HOST_WIDE_INT tsize = f->total_size;
+
+ fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
+ if (!flag_inhibit_size_directive)
+ {
+ fputs ("\t.ent\t", file);
+ assemble_name (file, fnname);
+ fputs ("\n", file);
+ }
+ assemble_name (file, fnname);
+ fputs (":\n", file);
+
+ if (!flag_inhibit_size_directive)
+ {
+ fprintf (file,
+ "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t"
+ "# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d"
+ ", args= " HOST_WIDE_INT_PRINT_DEC
+ ", gp= " HOST_WIDE_INT_PRINT_DEC "\n",
+ (reg_names[(frame_pointer_needed)
+ ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
+ tsize,
+ reg_names[RA_REGNUM],
+ current_function_is_leaf ? 1 : 0,
+ f->var_size,
+ f->num_gp,
+ f->args_size,
+ f->cprestore_size);
+
+ fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n",
+ f->mask,
+ (f->gp_sp_offset - f->total_size));
+ }
+}
+
+/* Do any necessary cleanup after a function to restore stack, frame,
+ and regs. */
+static void
+th_function_epilogue (FILE *file,
+ HOST_WIDE_INT size ATTRIBUTE_UNUSED)
+{
+ if (!flag_inhibit_size_directive)
+ {
+ const char *fnname;
+ fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
+ fputs ("\t.end\t", file);
+ assemble_name (file, fnname);
+ fputs ("\n", file);
+ }
+}
+
+/* Implement TARGET_SCHED_ISSUE_RATE. */
+static int
+th_issue_rate (void)
+{
+ return 1;
+}
+
+/* Returns true if X contains a SYMBOL_REF. */
+static bool
+symbolic_expression_p (rtx x)
+{
+ if (GET_CODE (x) == SYMBOL_REF)
+ return true;
+
+ if (GET_CODE (x) == CONST)
+ return symbolic_expression_p (XEXP (x, 0));
+
+ if (UNARY_P (x))
+ return symbolic_expression_p (XEXP (x, 0));
+
+ if (ARITHMETIC_P (x))
+ return (symbolic_expression_p (XEXP (x, 0))
+ || symbolic_expression_p (XEXP (x, 1)));
+
+ return false;
+}
+
+/* Choose the section to use for the constant rtx expression X that has
+ mode MODE. */
+static section *
+th_select_rtx_section (enum machine_mode mode, rtx x,
+ unsigned HOST_WIDE_INT align)
+{
+ if (GET_MODE_SIZE (mode) <= SCORE_SDATA_MAX)
+ return get_named_section (0, ".sdata", 0);
+ else if (flag_pic && symbolic_expression_p (x))
+ return get_named_section (0, ".data.rel.ro", 3);
+ else
+ return mergeable_constant_section (mode, align, 0);
+}
+
+/* Implement TARGET_IN_SMALL_DATA_P. */
+static bool
+th_in_small_data_p (tree decl)
+{
+ HOST_WIDE_INT size;
+
+ if (TREE_CODE (decl) == STRING_CST
+ || TREE_CODE (decl) == FUNCTION_DECL)
+ return false;
+
+ if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
+ {
+ const char *name;
+ name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
+ if (strcmp (name, ".sdata") != 0
+ && strcmp (name, ".sbss") != 0)
+ return true;
+ if (!DECL_EXTERNAL (decl))
+ return false;
+ }
+ size = int_size_in_bytes (TREE_TYPE (decl));
+ return (size > 0 && size <= SCORE_SDATA_MAX);
+}
+
+/* Implement TARGET_ASM_FILE_START. */
+static void
+th_asm_file_start (void)
+{
+ default_file_start ();
+ fprintf (asm_out_file, ASM_COMMENT_START
+ "GCC for S+core %s \n", SCORE_GCC_VERSION);
+
+ if (flag_pic)
+ fprintf (asm_out_file, "\t.set pic\n");
+}
+
+/* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
+ .externs for any small-data variables that turned out to be external. */
+struct extern_list *extern_head = 0;
+
+static void
+th_asm_file_end (void)
+{
+ tree name_tree;
+ struct extern_list *p;
+ if (extern_head)
+ {
+ fputs ("\n", asm_out_file);
+ for (p = extern_head; p != 0; p = p->next)
+ {
+ name_tree = get_identifier (p->name);
+ if (!TREE_ASM_WRITTEN (name_tree)
+ && TREE_SYMBOL_REFERENCED (name_tree))
+ {
+ TREE_ASM_WRITTEN (name_tree) = 1;
+ fputs ("\t.extern\t", asm_out_file);
+ assemble_name (asm_out_file, p->name);
+ fprintf (asm_out_file, ", %d\n", p->size);
+ }
+ }
+ }
+}
+
+static unsigned int sdata_max;
+
+int
+score_sdata_max (void)
+{
+ return sdata_max;
+}
+
+/* default 0 = NO_REGS */
+enum reg_class score_char_to_class[256];
+
+/* Implement OVERRIDE_OPTIONS macro. */
+void
+score_override_options (void)
+{
+ if (!flag_pic)
+ sdata_max = g_switch_set ? g_switch_value : DEFAULT_SDATA_MAX;
+ else
+ {
+ sdata_max = 0;
+ if (g_switch_set)
+ warning (0, "-fPIC and -G are incompatible");
+ }
+
+ score_char_to_class['d'] = G32_REGS;
+ score_char_to_class['e'] = G16_REGS;
+ score_char_to_class['t'] = T32_REGS;
+
+ score_char_to_class['h'] = HI_REG;
+ score_char_to_class['l'] = LO_REG;
+ score_char_to_class['x'] = CE_REGS;
+
+ score_char_to_class['q'] = CN_REG;
+ score_char_to_class['y'] = LC_REG;
+ score_char_to_class['z'] = SC_REG;
+ score_char_to_class['a'] = SP_REGS;
+
+ score_char_to_class['c'] = CR_REGS;
+
+ score_char_to_class['b'] = CP1_REGS;
+ score_char_to_class['f'] = CP2_REGS;
+ score_char_to_class['i'] = CP3_REGS;
+ score_char_to_class['j'] = CPA_REGS;
+}
+
+/* Implement REGNO_REG_CLASS macro. */
+int
+score_reg_class (int regno)
+{
+ int c;
+ gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
+
+ if (regno == FRAME_POINTER_REGNUM
+ || regno == ARG_POINTER_REGNUM)
+ return ALL_REGS;
+
+ for (c = 0 ; c < N_REG_CLASSES ; c++)
+ if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
+ return c;
+
+ return NO_REGS;
+}
+
+/* Implement PREFERRED_RELOAD_CLASS macro. */
+enum reg_class
+score_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class class)
+{
+ if (reg_class_subset_p (G32_REGS, class))
+ class = G32_REGS;
+ if (reg_class_subset_p (G16_REGS, class))
+ class = G16_REGS;
+ return class;
+}
+
+/* Implement SECONDARY_INPUT_RELOAD_CLASS
+ and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
+enum reg_class
+score_secondary_reload_class (enum reg_class class,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ rtx x)
+{
+ int regno = -1;
+ if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG)
+ regno = true_regnum (x);
+
+ if (!GR_REG_CLASS_P (class))
+ return GP_REG_P (regno) ? NO_REGS : G32_REGS;
+ return NO_REGS;
+}
+
+/* Implement CONST_OK_FOR_LETTER_P macro. */
+/* imm constraints
+ I IMM8 (i15-2-form)
+ J IMM5 (i15_1-form)
+ K IMM16 (i-form)
+ L IMM16s (i-form)
+ M IMM14 (ri-form)
+ N IMM14s (ri-form)
+ O IMM15s (ri-form)
+ P IMM12s (rix-form) / IMM10s(cop-form) << 2 */
+int
+score_const_ok_for_letter_p (int value, char c)
+{
+ switch (c)
+ {
+ case 'I': return IMM_IN_RANGE (value, 8, 0);
+ case 'J': return IMM_IN_RANGE (value, 5, 0);
+ case 'K': return IMM_IN_RANGE (value, 16, 0);
+ case 'L': return IMM_IN_RANGE (value, 16, 1);
+ case 'M': return IMM_IN_RANGE (value, 14, 0);
+ case 'N': return IMM_IN_RANGE (value, 14, 1);
+ case 'O': return IMM_IN_RANGE (value, 15, 1);
+ case 'P': return IMM_IN_RANGE (value, 12, 1);
+ default : return 0;
+ }
+}
+
+/* Implement EXTRA_CONSTRAINT macro. */
+/* Q const_hi imm
+ Z symbol_ref */
+int
+score_extra_constraint (rtx op, char c)
+{
+ switch (c)
+ {
+ case 'Q':
+ return (GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffff) == 0);
+ case 'Z':
+ return GET_CODE (op) == SYMBOL_REF;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Return truth value on whether or not a given hard register
+ can support a given mode. */
+int
+score_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
+{
+ int size = GET_MODE_SIZE (mode);
+ enum mode_class class = GET_MODE_CLASS (mode);
+
+ if (class == MODE_CC)
+ return regno == CC_REGNUM;
+ else if (regno == FRAME_POINTER_REGNUM
+ || regno == ARG_POINTER_REGNUM)
+ return class == MODE_INT;
+ else if (GP_REG_P (regno))
+ /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1) */
+ return !(regno & 1) || (size <= UNITS_PER_WORD);
+ else if (CE_REG_P (regno))
+ return (class == MODE_INT
+ && ((size <= UNITS_PER_WORD)
+ || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
+ else
+ return (class == MODE_INT) && (size <= UNITS_PER_WORD);
+}
+
+/* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
+ pointer or argument pointer. TO is either the stack pointer or
+ hard frame pointer. */
+HOST_WIDE_INT
+score_initial_elimination_offset (int from,
+ int to ATTRIBUTE_UNUSED)
+{
+ struct score_frame_info *f = mda_compute_frame_size (get_frame_size ());
+ switch (from)
+ {
+ case ARG_POINTER_REGNUM:
+ return f->total_size;
+ case FRAME_POINTER_REGNUM:
+ return 0;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Argument support functions. */
+
+/* Initialize CUMULATIVE_ARGS for a function. */
+void
+score_init_cumulative_args (CUMULATIVE_ARGS *cum,
+ tree fntype ATTRIBUTE_UNUSED,
+ rtx libname ATTRIBUTE_UNUSED)
+{
+ memset (cum, 0, sizeof (CUMULATIVE_ARGS));
+}
+
+/* Implement FUNCTION_ARG_ADVANCE macro. */
+void
+score_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+ tree type, int named)
+{
+ struct score_arg_info info;
+ classify_arg (cum, mode, type, named, &info);
+ cum->num_gprs = info.reg_offset + info.reg_words;
+ if (info.stack_words > 0)
+ cum->stack_words = info.stack_offset + info.stack_words;
+ cum->arg_number++;
+}
+
+/* Implement TARGET_ARG_PARTIAL_BYTES macro. */
+static int
+score_arg_partial_bytes (const CUMULATIVE_ARGS *cum,
+ enum machine_mode mode, tree type, int named)
+{
+ struct score_arg_info info;
+ classify_arg (cum, mode, type, named, &info);
+ return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
+}
+
+/* Implement FUNCTION_ARG macro. */
+rtx
+score_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
+ tree type, int named)
+{
+ struct score_arg_info info;
+
+ if (mode == VOIDmode || !named)
+ return 0;
+
+ classify_arg (cum, mode, type, named, &info);
+
+ if (info.reg_offset == ARG_REG_NUM)
+ return 0;
+
+ if (!info.stack_words)
+ return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
+ else
+ {
+ rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
+ unsigned int i, part_offset = 0;
+ for (i = 0; i < info.reg_words; i++)
+ {
+ rtx reg;
+ reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
+ XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
+ GEN_INT (part_offset));
+ part_offset += UNITS_PER_WORD;
+ }
+ return ret;
+ }
+}
+
+/* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
+ VALTYPE is the return type and MODE is VOIDmode. For libcalls,
+ VALTYPE is null and MODE is the mode of the return value. */
+rtx
+score_function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
+ enum machine_mode mode)
+{
+ if (valtype)
+ {
+ int unsignedp;
+ mode = TYPE_MODE (valtype);
+ unsignedp = TYPE_UNSIGNED (valtype);
+ mode = promote_mode (valtype, mode, &unsignedp, 1);
+ }
+ return gen_rtx_REG (mode, RT_REGNUM);
+}
+
+/* Implement INITIALIZE_TRAMPOLINE macro. */
+void
+score_initialize_trampoline (rtx ADDR, rtx FUNC, rtx CHAIN)
+{
+#define FFCACHE "_flush_cache"
+#define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
+
+ unsigned int tramp[TRAMPOLINE_INSNS] = {
+ 0x8103bc56, /* mv r8, r3 */
+ 0x9000bc05, /* bl 0x0x8 */
+ 0xc1238000 | (CODE_SIZE - 8), /* lw r9, &func */
+ 0xc0038000
+ | (STATIC_CHAIN_REGNUM << 21)
+ | (CODE_SIZE - 4), /* lw static chain reg, &chain */
+ 0x8068bc56, /* mv r3, r8 */
+ 0x8009bc08, /* br r9 */
+ 0x0,
+ 0x0,
+ };
+ rtx pfunc, pchain;
+ int i;
+
+ for (i = 0; i < TRAMPOLINE_INSNS; i++)
+ emit_move_insn (gen_rtx_MEM (ptr_mode, plus_constant (ADDR, i << 2)),
+ GEN_INT (tramp[i]));
+
+ pfunc = plus_constant (ADDR, CODE_SIZE);
+ pchain = plus_constant (ADDR, CODE_SIZE + GET_MODE_SIZE (ptr_mode));
+
+ emit_move_insn (gen_rtx_MEM (ptr_mode, pfunc), FUNC);
+ emit_move_insn (gen_rtx_MEM (ptr_mode, pchain), CHAIN);
+ emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE),
+ 0, VOIDmode, 2,
+ ADDR, Pmode,
+ GEN_INT (TRAMPOLINE_SIZE), SImode);
+#undef FFCACHE
+#undef CODE_SIZE
+}
+
+/* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
+int
+score_regno_mode_ok_for_base_p (int regno, int strict)
+{
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ {
+ if (!strict)
+ return 1;
+ regno = reg_renumber[regno];
+ }
+ if (regno == ARG_POINTER_REGNUM
+ || regno == FRAME_POINTER_REGNUM)
+ return 1;
+ return GP_REG_P (regno);
+}
+
+/* Implement GO_IF_LEGITIMATE_ADDRESS macro. */
+int
+score_address_p (enum machine_mode mode, rtx x, int strict)
+{
+ struct score_address_info addr;
+
+ return mda_classify_address (&addr, mode, x, strict);
+}
+
+/* Copy VALUE to a register and return that register. If new psuedos
+ are allowed, copy it into a new register, otherwise use DEST. */
+static rtx
+score_force_temporary (rtx dest, rtx value)
+{
+ if (!no_new_pseudos)
+ return force_reg (Pmode, value);
+ else
+ {
+ emit_move_insn (copy_rtx (dest), value);
+ return dest;
+ }
+}
+
+/* Return a LO_SUM expression for ADDR. TEMP is as for score_force_temporary
+ and is used to load the high part into a register. */
+static rtx
+score_split_symbol (rtx temp, rtx addr)
+{
+ rtx high = score_force_temporary (temp,
+ gen_rtx_HIGH (Pmode, copy_rtx (addr)));
+ return gen_rtx_LO_SUM (Pmode, high, addr);
+}
+
+/* This function is used to implement LEGITIMIZE_ADDRESS. If *XLOC can
+ be legitimized in a way that the generic machinery might not expect,
+ put the new address in *XLOC and return true. */
+int
+score_legitimize_address (rtx *xloc)
+{
+ enum score_symbol_type symbol_type;
+
+ if (mda_symbolic_constant_p (*xloc, &symbol_type)
+ && symbol_type == SYMBOL_GENERAL)
+ {
+ *xloc = score_split_symbol (0, *xloc);
+ return 1;
+ }
+
+ if (GET_CODE (*xloc) == PLUS
+ && GET_CODE (XEXP (*xloc, 1)) == CONST_INT)
+ {
+ rtx reg = XEXP (*xloc, 0);
+ if (!mda_valid_base_register_p (reg, 0))
+ reg = copy_to_mode_reg (Pmode, reg);
+ *xloc = score_add_offset (NULL, reg, INTVAL (XEXP (*xloc, 1)));
+ return 1;
+ }
+ return 0;
+}
+
+/* Return a number assessing the cost of moving a register in class
+ FROM to class TO. */
+int
+score_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
+ enum reg_class from, enum reg_class to)
+{
+ if (GR_REG_CLASS_P (from))
+ {
+ if (GR_REG_CLASS_P (to))
+ return 2;
+ else if (SP_REG_CLASS_P (to))
+ return 4;
+ else if (CP_REG_CLASS_P (to))
+ return 5;
+ else if (CE_REG_CLASS_P (to))
+ return 6;
+ }
+ if (GR_REG_CLASS_P (to))
+ {
+ if (GR_REG_CLASS_P (from))
+ return 2;
+ else if (SP_REG_CLASS_P (from))
+ return 4;
+ else if (CP_REG_CLASS_P (from))
+ return 5;
+ else if (CE_REG_CLASS_P (from))
+ return 6;
+ }
+ return 12;
+}
+
+/* Implement ASM_OUTPUT_EXTERNAL macro. */
+int
+score_output_external (FILE *file ATTRIBUTE_UNUSED,
+ tree decl, const char *name)
+{
+ register struct extern_list *p;
+
+ if (th_in_small_data_p (decl))
+ {
+ p = (struct extern_list *) ggc_alloc (sizeof (struct extern_list));
+ p->next = extern_head;
+ p->name = name;
+ p->size = int_size_in_bytes (TREE_TYPE (decl));
+ extern_head = p;
+ }
+ return 0;
+}
+
+/* Output format asm string. */
+void
+score_declare_object (FILE *stream, const char *name,
+ const char *directive, const char *fmt, ...)
+{
+ va_list ap;
+ fputs (directive, stream);
+ assemble_name (stream, name);
+ va_start (ap, fmt);
+ vfprintf (stream, fmt, ap);
+ va_end (ap);
+}
+
+/* Implement RETURN_ADDR_RTX. Note, we do not support moving
+ back to a previous frame. */
+rtx
+score_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
+{
+ if (count != 0)
+ return const0_rtx;
+ return get_hard_reg_initial_val (Pmode, RA_REGNUM);
+}
+
+/* Implement PRINT_OPERAND macro. */
+/* Score-specific operand codes:
+ '[' print .set nor1 directive
+ ']' print .set r1 directive
+
+ 'U' print hi part of a CONST_INT rtx
+ 'D' print first part of const double
+ 'S' selectively print '!' if operand is 15bit instrucion accessable
+ 'V' print "v!" if operand is 15bit instruction accessable, or
+ "lfh!"
+
+ 'L' low part of DImode reg operand
+ 'H' high part of DImode reg operand
+
+ 'C' print part of opcode for a branch condition. */
+void
+score_print_operand (FILE *file, rtx op, int c)
+{
+ enum rtx_code code = -1;
+ if (!PRINT_OPERAND_PUNCT_VALID_P (c))
+ code = GET_CODE (op);
+
+ if (c == '[')
+ {
+ fprintf (file, ".set r1\n");
+ }
+ else if (c == ']')
+ {
+ fprintf (file, "\n\t.set nor1");
+ }
+ else if (c == 'U')
+ {
+ gcc_assert (code == CONST_INT);
+ fprintf (file, HOST_WIDE_INT_PRINT_HEX,
+ (unsigned HOST_WIDE_INT) INTVAL (op) >> 16);
+ }
+ else if (c == 'D')
+ {
+ if (GET_CODE (op) == CONST_DOUBLE)
+ fprintf (file, HOST_WIDE_INT_PRINT_HEX,
+ TARGET_LITTLE_ENDIAN
+ ? CONST_DOUBLE_LOW (op) : CONST_DOUBLE_HIGH (op));
+ else
+ output_addr_const (file, op);
+ }
+ else if (c == 'S')
+ {
+ gcc_assert (code == REG);
+ if (G16_REG_P (REGNO (op)))
+ fprintf (file, "!");
+ }
+ else if (c == 'V')
+ {
+ gcc_assert (code == REG);
+ fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
+ }
+ else if (code == REG)
+ {
+ int regnum = REGNO (op);
+ if ((c == 'H' && !WORDS_BIG_ENDIAN)
+ || (c == 'L' && WORDS_BIG_ENDIAN))
+ regnum ++;
+ fprintf (file, "%s", reg_names[regnum]);
+ }
+ else if (c == 'C')
+ {
+ switch (code)
+ {
+ case EQ: fputs ("eq", file); break;
+ case NE: fputs ("ne", file); break;
+ case GT: fputs ("gt", file); break;
+ case GE: fputs ("ge", file); break;
+ case LT: fputs ("lt", file); break;
+ case LE: fputs ("le", file); break;
+ case GTU: fputs ("gtu", file); break;
+ case GEU: fputs ("cs", file); break;
+ case LTU: fputs ("cc", file); break;
+ case LEU: fputs ("leu", file); break;
+ default:
+ output_operand_lossage ("invalid operand for code: '%c'", code);
+ }
+ }
+ else
+ {
+ switch (code)
+ {
+ case MEM:
+ score_print_operand_address (file, op);
+ break;
+ default:
+ output_addr_const (file, op);
+ }
+ }
+}
+
+/* Implement PRINT_OPERAND_ADDRESS macro. */
+void
+score_print_operand_address (FILE *file, rtx x)
+{
+ struct score_address_info addr;
+ enum rtx_code code = GET_CODE (x);
+ enum machine_mode mode = GET_MODE (x);
+
+ if (code == MEM)
+ x = XEXP (x, 0);
+
+ if (mda_classify_address (&addr, mode, x, true))
+ {
+ switch (addr.type)
+ {
+ case ADD_REG:
+ {
+ switch (addr.code)
+ {
+ case PRE_DEC:
+ fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
+ INTVAL (addr.offset));
+ break;
+ case POST_DEC:
+ fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
+ INTVAL (addr.offset));
+ break;
+ case PRE_INC:
+ fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
+ INTVAL (addr.offset));
+ break;
+ case POST_INC:
+ fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
+ INTVAL (addr.offset));
+ break;
+ default:
+ fprintf (file, "[%s,%ld]", reg_names[REGNO (addr.reg)],
+ INTVAL (addr.offset));
+ break;
+ }
+ }
+ return;
+ case ADD_CONST_INT:
+ case ADD_SYMBOLIC:
+ output_addr_const (file, x);
+ return;
+ }
+ }
+ print_rtl (stderr, x);
+ gcc_unreachable ();
+}
+
+struct gcc_target targetm = TARGET_INITIALIZER;
diff --git a/gcc/config/score/score.h b/gcc/config/score/score.h
new file mode 100644
index 00000000000..01fe9b57df8
--- /dev/null
+++ b/gcc/config/score/score.h
@@ -0,0 +1,909 @@
+/* score.h for Sunplus S+CORE processor
+ Copyright (C) 2005 Free Software Foundation, Inc.
+ Contributed by Sunnorth.
+
+ 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 2, 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 COPYING. If not, write to
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+#include "score-conv.h"
+#include "score-version.h"
+
+/* Define the information needed to generate branch insns. This is
+ stored from the compare operation. */
+extern GTY(()) rtx cmp_op0;
+extern GTY(()) rtx cmp_op1;
+
+/* Controlling the Compilation Driver. */
+#define SWITCH_TAKES_ARG(CHAR) \
+ (DEFAULT_SWITCH_TAKES_ARG (CHAR) || (CHAR) == 'G')
+
+/* CC1_SPEC is the set of arguments to pass to the compiler proper. */
+#undef CC1_SPEC
+#define CC1_SPEC "%{!mel:-meb}"
+
+#undef ASM_SPEC
+#define ASM_SPEC \
+ "%{!mel:-EB} %{mel:-EL} %{mSCORE5U:-SCORE5U} %{mSCORE7:-SCORE7} %{G*}"
+
+#undef LINK_SPEC
+#define LINK_SPEC "%{!mel:-EB} %{mel:-EL} %{G*}"
+
+/* Run-time Target Specification. */
+#define TARGET_CPU_CPP_BUILTINS() \
+ do { \
+ builtin_define ("SUNPLUS"); \
+ builtin_define ("__SCORE__"); \
+ builtin_define ("__score__"); \
+ if (TARGET_LITTLE_ENDIAN) \
+ builtin_define ("__scorele__"); \
+ else \
+ builtin_define ("__scorebe__"); \
+ if (TARGET_SCORE5U) \
+ builtin_define ("__score5u__"); \
+ } while (0)
+
+
+#define TARGET_DEFAULT MASK_SCORE7
+
+#define TARGET_VERSION \
+ fprintf (stderr, "Sunplus S+CORE %s", SCORE_GCC_VERSION);
+
+#define OVERRIDE_OPTIONS score_override_options ()
+
+/* Show we can debug even without a frame pointer. */
+#define CAN_DEBUG_WITHOUT_FP
+
+/* Target machine storage layout. */
+#define BITS_BIG_ENDIAN 0
+#define BYTES_BIG_ENDIAN (TARGET_LITTLE_ENDIAN == 0)
+#define WORDS_BIG_ENDIAN (TARGET_LITTLE_ENDIAN == 0)
+
+/* Define this to set the endianness to use in libgcc2.c, which can
+ not depend on target_flags. */
+#if defined(__scorele__)
+#define LIBGCC2_WORDS_BIG_ENDIAN 0
+#else
+#define LIBGCC2_WORDS_BIG_ENDIAN 1
+#endif
+
+/* Width of a word, in units (bytes). */
+#define UNITS_PER_WORD 4
+
+/* Define this macro if it is advisable to hold scalars in registers
+ in a wider mode than that declared by the program. In such cases,
+ the value is constrained to be within the bounds of the declared
+ type, but kept valid in the wider mode. The signedness of the
+ extension may differ from that of the type. */
+#define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE) \
+ if (GET_MODE_CLASS (MODE) == MODE_INT \
+ && GET_MODE_SIZE (MODE) < UNITS_PER_WORD) \
+ (MODE) = SImode;
+
+/* Allocation boundary (in *bits*) for storing arguments in argument list. */
+#define PARM_BOUNDARY BITS_PER_WORD
+#define STACK_BOUNDARY 64
+
+/* Allocation boundary (in *bits*) for the code of a function. */
+#define FUNCTION_BOUNDARY BITS_PER_WORD
+
+/* There is no point aligning anything to a rounder boundary than this. */
+#define BIGGEST_ALIGNMENT LONG_DOUBLE_TYPE_SIZE
+
+/* If defined, a C expression to compute the alignment for a static
+ variable. TYPE is the data type, and ALIGN is the alignment that
+ the object would ordinarily have. The value of this macro is used
+ instead of that alignment to align the object.
+
+ If this macro is not defined, then ALIGN is used.
+
+ One use of this macro is to increase alignment of medium-size
+ data to make it all fit in fewer cache lines. Another is to
+ cause character arrays to be word-aligned so that `strcpy' calls
+ that copy constants to character arrays can be done inline. */
+#define DATA_ALIGNMENT(TYPE, ALIGN) \
+ ((((ALIGN) < BITS_PER_WORD) \
+ && (TREE_CODE (TYPE) == ARRAY_TYPE \
+ || TREE_CODE (TYPE) == UNION_TYPE \
+ || TREE_CODE (TYPE) == RECORD_TYPE)) ? BITS_PER_WORD : (ALIGN))
+
+/* Alignment of field after `int : 0' in a structure. */
+#define EMPTY_FIELD_BOUNDARY 32
+
+/* All accesses must be aligned. */
+#define STRICT_ALIGNMENT 1
+
+/* Score requires that structure alignment is affected by bitfields. */
+#define PCC_BITFIELD_TYPE_MATTERS 1
+
+/* long double is not a fixed mode, but the idea is that, if we
+ support long double, we also want a 128-bit integer type. */
+#define MAX_FIXED_MODE_SIZE LONG_DOUBLE_TYPE_SIZE
+
+#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT
+
+/* Layout of Data Type. */
+/* Set the sizes of the core types. */
+#define INT_TYPE_SIZE 32
+#define SHORT_TYPE_SIZE 16
+#define LONG_TYPE_SIZE 32
+#define LONG_LONG_TYPE_SIZE 64
+#define CHAR_TYPE_SIZE 8
+#define FLOAT_TYPE_SIZE 32
+#define DOUBLE_TYPE_SIZE 64
+#define LONG_DOUBLE_TYPE_SIZE 64
+
+/* Define this as 1 if `char' should by default be signed; else as 0. */
+#undef DEFAULT_SIGNED_CHAR
+#define DEFAULT_SIGNED_CHAR 1
+
+/* Default definitions for size_t and ptrdiff_t. */
+#define SIZE_TYPE "unsigned int"
+
+/* Register Usage
+
+ S+core have:
+ - 32 integer registers
+ - 16 control registers (cond)
+ - 16 special registers (ceh/cel/cnt/lcr/scr/arg/fp)
+ - 32 coprocessors 1 registers
+ - 32 coprocessors 2 registers
+ - 32 coprocessors 3 registers. */
+#define FIRST_PSEUDO_REGISTER 160
+
+/* By default, fix the kernel registers (r30 and r31), the global
+ pointer (r28) and the stack pointer (r0). This can change
+ depending on the command-line options.
+
+ Regarding coprocessor registers: without evidence to the contrary,
+ it's best to assume that each coprocessor register has a unique
+ use. This can be overridden, in, e.g., override_options() or
+ CONDITIONAL_REGISTER_USAGE should the assumption be inappropriate
+ for a particular target. */
+
+/* Control Registers, use mfcr/mtcr insn
+ 32 cr0 PSR
+ 33 cr1 Condition
+ 34 cr2 ECR
+ 35 cr3 EXCPVec
+ 36 cr4 CCR
+ 37 cr5 EPC
+ 38 cr6 EMA
+ 39 cr7 TLBLock
+ 40 cr8 TLBPT
+ 41 cr8 PEADDR
+ 42 cr10 TLBRPT
+ 43 cr11 PEVN
+ 44 cr12 PECTX
+ 45 cr13
+ 46 cr14
+ 47 cr15
+
+ Custom Engine Register, use mfce/mtce
+ 48 CEH CEH
+ 49 CEL CEL
+
+ Special-Purpose Register, use mfsr/mtsr
+ 50 sr0 CNT
+ 51 sr1 LCR
+ 52 sr2 SCR
+
+ 53 ARG_POINTER_REGNUM
+ 54 FRAME_POINTER_REGNUM
+ but Control register have 32 registers, cr16-cr31. */
+#define FIXED_REGISTERS \
+{ \
+ /* General Purpose Registers */ \
+ 1, 1, 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, 0, 1, 1, \
+ /* Control Regisers */ \
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
+ /* CEH/ CEL/ CNT/ LCR/ SCR / ARG_POINTER_REGNUM/ FRAME_POINTER_REGNUM */\
+ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
+ /* CP 1 Registers */ \
+ 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, 1, 1, 1, 1, 1, 1, \
+ /* CP 2 Registers */ \
+ 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, 1, 1, 1, 1, 1, 1, \
+ /* CP 3 Registers*/ \
+ 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, 1, 1, 1, 1, 1, 1, \
+}
+
+#define CALL_USED_REGISTERS \
+{ \
+ /* General purpose register */ \
+ 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
+ /* Control Regisers */ \
+ 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, 1, 1, 1, 1, 1, 1, \
+ /* CP 1 Registers */ \
+ 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, 1, 1, 1, 1, 1, 1, \
+ /* CP 2 Registers */ \
+ 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, 1, 1, 1, 1, 1, 1, \
+ /* CP 3 Registers */ \
+ 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, 1, 1, 1, 1, 1, 1, \
+}
+
+#define REG_ALLOC_ORDER \
+{ 0, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, \
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 2, 3, \
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, \
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, \
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, \
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, \
+ 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, \
+ 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, \
+ 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, \
+ 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159 }
+
+#define HARD_REGNO_NREGS(REGNO, MODE) \
+ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+
+/* Return true if REGNO is suitable for holding a quantity of type MODE. */
+#define HARD_REGNO_MODE_OK(REGNO, MODE) score_hard_regno_mode_ok (REGNO, MODE)
+
+/* Value is 1 if it is a good idea to tie two pseudo registers
+ when one has mode MODE1 and one has mode MODE2.
+ If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2,
+ for any hard reg, then this must be 0 for correct output. */
+#define MODES_TIEABLE_P(MODE1, MODE2) \
+ ((GET_MODE_CLASS (MODE1) == MODE_FLOAT \
+ || GET_MODE_CLASS (MODE1) == MODE_COMPLEX_FLOAT) \
+ == (GET_MODE_CLASS (MODE2) == MODE_FLOAT \
+ || GET_MODE_CLASS (MODE2) == MODE_COMPLEX_FLOAT))
+
+/* Register Classes. */
+/* Define the classes of registers for register constraints in the
+ machine description. Also define ranges of constants. */
+enum reg_class
+{
+ NO_REGS,
+ G16_REGS, /* r0 ~ r15 */
+ G32_REGS, /* r0 ~ r31 */
+ T32_REGS, /* r8 ~ r11 | r22 ~ r27 */
+
+ HI_REG, /* hi */
+ LO_REG, /* lo */
+ CE_REGS, /* hi + lo */
+
+ CN_REG, /* cnt */
+ LC_REG, /* lcb */
+ SC_REG, /* scb */
+ SP_REGS, /* cnt + lcb + scb */
+
+ CR_REGS, /* cr0 - cr15 */
+
+ CP1_REGS, /* cp1 */
+ CP2_REGS, /* cp2 */
+ CP3_REGS, /* cp3 */
+ CPA_REGS, /* cp1 + cp2 + cp3 */
+
+ ALL_REGS,
+ LIM_REG_CLASSES
+};
+
+#define N_REG_CLASSES ((int) LIM_REG_CLASSES)
+
+#define GENERAL_REGS G32_REGS
+
+/* Give names of register classes as strings for dump file. */
+#define REG_CLASS_NAMES \
+{ \
+ "NO_REGS", \
+ "G16_REGS", \
+ "G32_REGS", \
+ "T32_REGS", \
+ \
+ "HI_REG", \
+ "LO_REG", \
+ "CE_REGS", \
+ \
+ "CN_REG", \
+ "LC_REG", \
+ "SC_REG", \
+ "SP_REGS", \
+ \
+ "CR_REGS", \
+ \
+ "CP1_REGS", \
+ "CP2_REGS", \
+ "CP3_REGS", \
+ "CPA_REGS", \
+ \
+ "ALL_REGS", \
+}
+
+/* Define which registers fit in which classes. */
+#define REG_CLASS_CONTENTS \
+{ \
+ /* NO_REGS/G16/G32/T32 */ \
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, \
+ { 0x0000ffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, \
+ { 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, \
+ { 0x0fc00f00, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, \
+ /* HI/LO/CE */ \
+ { 0x00000000, 0x00010000, 0x00000000, 0x00000000, 0x00000000}, \
+ { 0x00000000, 0x00020000, 0x00000000, 0x00000000, 0x00000000}, \
+ { 0x00000000, 0x00030000, 0x00000000, 0x00000000, 0x00000000}, \
+ /* CN/LC/SC/SP/CR */ \
+ { 0x00000000, 0x00040000, 0x00000000, 0x00000000, 0x00000000}, \
+ { 0x00000000, 0x00080000, 0x00000000, 0x00000000, 0x00000000}, \
+ { 0x00000000, 0x00100000, 0x00000000, 0x00000000, 0x00000000}, \
+ { 0x00000000, 0x001c0000, 0x00000000, 0x00000000, 0x00000000}, \
+ { 0x00000000, 0x0000ffff, 0x00000000, 0x00000000, 0x00000000}, \
+ /* CP1/CP2/CP3/CPA */ \
+ { 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000}, \
+ { 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000}, \
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff}, \
+ { 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff}, \
+ /* ALL_REGS */ \
+ { 0xffffffff, 0x001fffff, 0xffffffff, 0xffffffff, 0xffffffff}, \
+}
+
+/* A C expression whose value is a register class containing hard
+ register REGNO. In general there is more that one such class;
+ choose a class which is "minimal", meaning that no smaller class
+ also contains the register. */
+#define REGNO_REG_CLASS(REGNO) score_reg_class (REGNO)
+
+/* A macro whose definition is the name of the class to which a
+ valid base register must belong. A base register is one used in
+ an address which is the register value plus a displacement. */
+#define BASE_REG_CLASS G16_REGS
+
+/* The class value for index registers. */
+#define INDEX_REG_CLASS NO_REGS
+
+#define REG_CLASS_FROM_LETTER(C) score_char_to_class[(unsigned char) (C)]
+
+/* Addressing modes, and classification of registers for them. */
+#define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) \
+ score_regno_mode_ok_for_base_p (REGNO, 1)
+
+#define REGNO_OK_FOR_INDEX_P(NUM) 0
+
+#define PREFERRED_RELOAD_CLASS(X, CLASS) \
+ score_preferred_reload_class (X, CLASS)
+
+/* If we need to load shorts byte-at-a-time, then we need a scratch. */
+#define SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, X) \
+ score_secondary_reload_class (CLASS, MODE, X)
+
+/* Return the register class of a scratch register needed to copy IN into
+ or out of a register in CLASS in MODE. If it can be done directly,
+ NO_REGS is returned. */
+#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS, MODE, X) \
+ score_secondary_reload_class (CLASS, MODE, X)
+
+/* Return the maximum number of consecutive registers
+ needed to represent mode MODE in a register of class CLASS. */
+#define CLASS_MAX_NREGS(CLASS, MODE) \
+ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+
+#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
+ (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) \
+ ? reg_classes_intersect_p (HI_REG, (CLASS)) : 0)
+
+/* The letters I, J, K, L, M, N, O, and P in a register constraint
+ string can be used to stand for particular ranges of immediate
+ operands. This macro defines what the ranges are. C is the
+ letter, and VALUE is a constant value. Return 1 if VALUE is
+ in the range specified by C. */
+#define CONST_OK_FOR_LETTER_P(VALUE, C) score_const_ok_for_letter_p (VALUE, C)
+
+/* Similar, but for floating constants, and defining letters G and H.
+ Here VALUE is the CONST_DOUBLE rtx itself. */
+
+#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \
+ ((C) == 'G' && (VALUE) == CONST0_RTX (GET_MODE (VALUE)))
+
+/* Letters in the range `Q' through `U' may be defined in a
+ machine-dependent fashion to stand for arbitrary operand types.
+ The machine description macro `EXTRA_CONSTRAINT' is passed the
+ operand as its first argument and the constraint letter as its
+ second operand. */
+#define EXTRA_CONSTRAINT(VALUE, C) score_extra_constraint (VALUE, C)
+
+/* Basic Stack Layout. */
+/* Stack layout; function entry, exit and calling. */
+#define STACK_GROWS_DOWNWARD
+
+#define STACK_PUSH_CODE PRE_DEC
+#define STACK_POP_CODE POST_INC
+
+/* The offset of the first local variable from the beginning of the frame.
+ See compute_frame_size for details about the frame layout. */
+#define STARTING_FRAME_OFFSET current_function_outgoing_args_size
+
+/* The argument pointer always points to the first argument. */
+#define FIRST_PARM_OFFSET(FUNDECL) 0
+
+/* A C expression whose value is RTL representing the value of the return
+ address for the frame COUNT steps up from the current frame. */
+#define RETURN_ADDR_RTX(count, frame) score_return_addr (count, frame)
+
+/* Pick up the return address upon entry to a procedure. */
+#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (VOIDmode, RA_REGNUM)
+
+/* Exception handling Support. */
+/* Use r0 to r3 to pass exception handling information. */
+#define EH_RETURN_DATA_REGNO(N) \
+ ((N) < 4 ? (N) + ARG_REG_FIRST : INVALID_REGNUM)
+
+/* The register that holds the return address in exception handlers. */
+#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, EH_REGNUM)
+
+/* Registers That Address the Stack Frame. */
+/* Register to use for pushing function arguments. */
+#define STACK_POINTER_REGNUM SP_REGNUM
+
+/* These two registers don't really exist: they get eliminated to either
+ the stack or hard frame pointer. */
+#define FRAME_POINTER_REGNUM 53
+
+/* we use r2 as the frame pointer. */
+#define HARD_FRAME_POINTER_REGNUM FP_REGNUM
+
+#define ARG_POINTER_REGNUM 54
+
+/* Register in which static-chain is passed to a function. */
+#define STATIC_CHAIN_REGNUM 23
+
+/* Elimination Frame Pointer and Arg Pointer */
+/* Value should be nonzero if functions must have frame pointers.
+ Zero means the frame pointer need not be set up (and parms
+ may be accessed via the stack pointer) in functions that seem suitable.
+ This is computed in `reload', in reload1.c. */
+#define FRAME_POINTER_REQUIRED current_function_calls_alloca
+
+#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}}
+
+/* We can always eliminate to the hard frame pointer. We can eliminate
+ to the stack pointer unless a frame pointer is needed. */
+#define CAN_ELIMINATE(FROM, TO) \
+ (((TO) == HARD_FRAME_POINTER_REGNUM) \
+ || ((TO) == STACK_POINTER_REGNUM \
+ && !frame_pointer_needed))
+
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
+ (OFFSET) = score_initial_elimination_offset ((FROM), (TO))
+
+/* Passing Function Arguments on the Stack. */
+/* Allocate stack space for arguments at the beginning of each function. */
+#define ACCUMULATE_OUTGOING_ARGS 1
+
+/* reserve stack space for all argument registers. */
+#define REG_PARM_STACK_SPACE(FNDECL) UNITS_PER_WORD
+
+/* Define this if it is the responsibility of the caller to
+ allocate the area reserved for arguments passed in registers.
+ If `ACCUMULATE_OUTGOING_ARGS' is also defined, the only effect
+ of this macro is to determine whether the space is included in
+ `current_function_outgoing_args_size'. */
+#define OUTGOING_REG_PARM_STACK_SPACE
+
+#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, STACK_SIZE) 0
+
+/* Passing Arguments in Registers */
+/* Determine where to put an argument to a function.
+ Value is zero to push the argument on the stack,
+ or a hard register in which to store the argument.
+
+ MODE is the argument's machine mode.
+ TYPE is the data type of the argument (as a tree).
+ This is null for libcalls where that information may
+ not be available.
+ CUM is a variable of type CUMULATIVE_ARGS which gives info about
+ the preceding args and about the function being called.
+ NAMED is nonzero if this argument is a named parameter
+ (otherwise it is an extra parameter matching an ellipsis). */
+#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
+ score_function_arg (&CUM, MODE, TYPE, NAMED)
+
+/* A C type for declaring a variable that is used as the first argument of
+ `FUNCTION_ARG' and other related values. For some target machines, the
+ type `int' suffices and can hold the number of bytes of argument so far. */
+typedef struct score_args
+{
+ unsigned int arg_number; /* how many arguments have been seen */
+ unsigned int num_gprs; /* number of gprs in use */
+ unsigned int stack_words; /* number of words in stack */
+} score_args_t;
+
+#define CUMULATIVE_ARGS score_args_t
+
+/* Initialize a variable CUM of type CUMULATIVE_ARGS
+ for a call to a function whose data type is FNTYPE.
+ For a library call, FNTYPE is 0. */
+#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT, n_named_args) \
+ score_init_cumulative_args (&CUM, FNTYPE, LIBNAME)
+
+/* Update the data in CUM to advance over an argument
+ of mode MODE and data type TYPE.
+ (TYPE is null for libcalls where that information may not be available.) */
+#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
+ score_function_arg_advance (&CUM, MODE, TYPE, NAMED)
+
+/* 1 if N is a possible register number for function argument passing.
+ We have no FP argument registers when soft-float. When FP registers
+ are 32 bits, we can't directly reference the odd numbered ones. */
+#define FUNCTION_ARG_REGNO_P(REGNO) \
+ REG_CONTAIN (REGNO, ARG_REG_FIRST, ARG_REG_NUM)
+
+/* How Scalar Function Values Are Returned. */
+#define FUNCTION_VALUE(VALTYPE, FUNC) \
+ score_function_value ((VALTYPE), (FUNC), VOIDmode)
+
+#define LIBCALL_VALUE(MODE) score_function_value (NULL_TREE, NULL, (MODE))
+
+/* 1 if N is a possible register number for a function value. */
+#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == (ARG_REG_FIRST))
+
+#define PIC_FUNCTION_ADDR_REGNUM (GP_REG_FIRST + 25)
+
+/* How Large Values Are Returned. */
+#define STRUCT_VALUE 0
+
+/* Function Entry and Exit */
+/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function,
+ the stack pointer does not matter. The value is tested only in
+ functions that have frame pointers.
+ No definition is equivalent to always zero. */
+#define EXIT_IGNORE_STACK 1
+
+/* Generating Code for Profiling */
+/* Output assembler code to FILE to increment profiler label # LABELNO
+ for profiling a function entry. */
+#define FUNCTION_PROFILER(FILE, LABELNO) \
+{ \
+ fprintf (FILE, " .set r1 \n"); \
+ fprintf (FILE, " mv r%d,r%d \n", AT_REGNUM, RA_REGNUM); \
+ fprintf (FILE, " subi r%d, %d \n", STACK_POINTER_REGNUM, 8); \
+ fprintf (FILE, " jl _mcount \n"); \
+ fprintf (FILE, " .set nor1 \n"); \
+}
+
+/* Trampolines for Nested Functions. */
+#define TRAMPOLINE_INSNS 8
+
+/* A C expression for the size in bytes of the trampoline, as an integer. */
+#define TRAMPOLINE_SIZE \
+ (TRAMPOLINE_INSNS * GET_MODE_SIZE (SImode) + GET_MODE_SIZE (ptr_mode) * 2)
+
+/* A C statement to initialize the variable parts of a trampoline.
+ ADDR is an RTX for the address of the trampoline; FNADDR is an
+ RTX for the address of the nested function; STATIC_CHAIN is an
+ RTX for the static chain value that should be passed to the
+ function when it is called. */
+
+#define INITIALIZE_TRAMPOLINE(ADDR, FUNC, CHAIN) \
+ score_initialize_trampoline (ADDR, FUNC, CHAIN)
+
+#define HAVE_PRE_INCREMENT 1
+#define HAVE_PRE_DECREMENT 1
+#define HAVE_POST_INCREMENT 1
+#define HAVE_POST_DECREMENT 1
+#define HAVE_PRE_MODIFY_DISP 0
+#define HAVE_POST_MODIFY_DISP 0
+#define HAVE_PRE_MODIFY_REG 0
+#define HAVE_POST_MODIFY_REG 0
+
+/* Recognize any constant value that is a valid address. */
+#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X)
+
+/* Maximum number of registers that can appear in a valid memory address. */
+#define MAX_REGS_PER_ADDRESS 1
+
+#ifdef REG_OK_STRICT
+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL) \
+ if (score_address_p (MODE, X, 1)) \
+ goto LABEL;
+#else
+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL) \
+ if (score_address_p (MODE, X, 0)) \
+ goto LABEL;
+#endif
+
+/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
+ and check its validity for a certain class.
+ We have two alternate definitions for each of them.
+ The usual definition accepts all pseudo regs; the other rejects them all.
+ The symbol REG_OK_STRICT causes the latter definition to be used.
+
+ Most source files want to accept pseudo regs in the hope that
+ they will get allocated to the class that the insn wants them to be in.
+ Some source files that are used after register allocation
+ need to be strict. */
+#ifndef REG_OK_STRICT
+#define REG_MODE_OK_FOR_BASE_P(X, MODE) \
+ score_regno_mode_ok_for_base_p (REGNO (X), 0)
+#else
+#define REG_MODE_OK_FOR_BASE_P(X, MODE) \
+ score_regno_mode_ok_for_base_p (REGNO (X), 1)
+#endif
+
+#define REG_OK_FOR_INDEX_P(X) 0
+
+#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \
+ do { \
+ if (score_legitimize_address (&(X))) \
+ goto WIN; \
+ } while (0)
+
+/* Go to LABEL if ADDR (a legitimate address expression)
+ has an effect that depends on the machine mode it is used for. */
+#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) {}
+
+#define LEGITIMATE_CONSTANT_P(X) 1
+
+/* Describing Relative Costs of Operations */
+/* Compute extra cost of moving data between one register class and another. */
+#define REGISTER_MOVE_COST(MODE, FROM, TO) \
+ score_register_move_cost (MODE, FROM, TO)
+
+/* Moves to and from memory are quite expensive */
+#define MEMORY_MOVE_COST(MODE, CLASS, TO_P) \
+ (4 + memory_move_secondary_cost ((MODE), (CLASS), (TO_P)))
+
+/* Try to generate sequences that don't involve branches. */
+#define BRANCH_COST 2
+
+/* Nonzero if access to memory by bytes is slow and undesirable. */
+#define SLOW_BYTE_ACCESS 1
+
+/* Define this macro if it is as good or better to call a constant
+ function address than to call an address kept in a register. */
+#define NO_FUNCTION_CSE 1
+
+/* Dividing the Output into Sections (Texts, Data, ...). */
+/* Define the strings to put out for each section in the object file. */
+#define TEXT_SECTION_ASM_OP "\t.text"
+#define DATA_SECTION_ASM_OP "\t.data"
+#define SDATA_SECTION_ASM_OP "\t.sdata"
+
+#undef READONLY_DATA_SECTION_ASM_OP
+#define READONLY_DATA_SECTION_ASM_OP "\t.rdata"
+
+/* The Overall Framework of an Assembler File */
+/* How to start an assembler comment.
+ The leading space is important. */
+#define ASM_COMMENT_START "#"
+
+/* Output to assembler file text saying following lines
+ may contain character constants, extra white space, comments, etc. */
+#define ASM_APP_ON "#APP\n\t.set volatile\n"
+
+/* Output to assembler file text saying following lines
+ no longer contain unusual constructs. */
+#define ASM_APP_OFF "#NO_APP\n\t.set optimize\n"
+
+/* Output of Uninitialized Variables. */
+/* This says how to define a global common symbol. */
+#define ASM_OUTPUT_ALIGNED_DECL_COMMON(STREAM, DECL, NAME, SIZE, ALIGN) \
+ score_declare_object (STREAM, NAME, "\n\t.comm\t", \
+ ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", \
+ SIZE, ALIGN / BITS_PER_UNIT);
+
+/* This says how to define a local common symbol (i.e., not visible to
+ linker). */
+#undef ASM_OUTPUT_ALIGNED_LOCAL
+#define ASM_OUTPUT_ALIGNED_LOCAL(STREAM, NAME, SIZE, ALIGN) \
+ score_declare_object (STREAM, NAME, "\n\t.lcomm\t", \
+ ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", \
+ SIZE, ALIGN / BITS_PER_UNIT);
+
+/* Globalizing directive for a label. */
+#define GLOBAL_ASM_OP "\t.globl\t"
+
+/* Output and Generation of Labels */
+/* This is how to declare a function name. The actual work of
+ emitting the label is moved to function_prologue, so that we can
+ get the line number correctly emitted before the .ent directive,
+ and after any .file directives. Define as empty so that the function
+ is not declared before the .ent directive elsewhere. */
+#undef ASM_DECLARE_FUNCTION_NAME
+#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL)
+
+#undef ASM_DECLARE_OBJECT_NAME
+#define ASM_DECLARE_OBJECT_NAME(STREAM, NAME, DECL) \
+ score_declare_object (STREAM, NAME, "", ":\n", 0)
+
+/* This says how to output an external. It would be possible not to
+ output anything and let undefined symbol become external. However
+ the assembler uses length information on externals to allocate in
+ data/sdata bss/sbss, thereby saving exec time. */
+#define ASM_OUTPUT_EXTERNAL(STREAM, DECL, NAME) \
+ score_output_external (STREAM, DECL, NAME)
+
+/* This handles the magic '..CURRENT_FUNCTION' symbol, which means
+ 'the start of the function that this code is output in'. */
+#define ASM_OUTPUT_LABELREF(STREAM, NAME) \
+ fprintf ((STREAM), "%s", (NAME))
+
+/* Local compiler-generated symbols must have a prefix that the assembler
+ understands. */
+#define LOCAL_LABEL_PREFIX "."
+
+#undef ASM_GENERATE_INTERNAL_LABEL
+#define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM) \
+ sprintf ((LABEL), "*%s%s%ld", (LOCAL_LABEL_PREFIX), (PREFIX), (long) (NUM))
+
+/* Output of Assembler Instructions. */
+#define REGISTER_NAMES \
+{ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", \
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", \
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", \
+ \
+ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \
+ "cr8", "cr9", "cr10", "cr11", "cr12", "cr13", "cr14", "cr15", \
+ \
+ "ceh", "cel", "sr0", "sr1", "sr2", "_arg", "_frame", "", \
+ "cr24", "cr25", "cr26", "cr27", "cr28", "cr29", "cr30", "cr31", \
+ \
+ "c1r0", "c1r1", "c1r2", "c1r3", "c1r4", "c1r5", "c1r6", "c1r7", \
+ "c1r8", "c1r9", "c1r10", "c1r11", "c1r12", "c1r13", "c1r14", "c1r15", \
+ "c1r16", "c1r17", "c1r18", "c1r19", "c1r20", "c1r21", "c1r22", "c1r23",\
+ "c1r24", "c1r25", "c1r26", "c1r27", "c1r28", "c1r29", "c1r30", "c1r31",\
+ \
+ "c2r0", "c2r1", "c2r2", "c2r3", "c2r4", "c2r5", "c2r6", "c2r7", \
+ "c2r8", "c2r9", "c2r10", "c2r11", "c2r12", "c2r13", "c2r14", "c2r15", \
+ "c2r16", "c2r17", "c2r18", "c2r19", "c2r20", "c2r21", "c2r22", "c2r23",\
+ "c2r24", "c2r25", "c2r26", "c2r27", "c2r28", "c2r29", "c2r30", "c2r31",\
+ \
+ "c3r0", "c3r1", "c3r2", "c3r3", "c3r4", "c3r5", "c3r6", "c3r7", \
+ "c3r8", "c3r9", "c3r10", "c3r11", "c3r12", "c3r13", "c3r14", "c3r15", \
+ "c3r16", "c3r17", "c3r18", "c3r19", "c3r20", "c3r21", "c3r22", "c3r23",\
+ "c3r24", "c3r25", "c3r26", "c3r27", "c3r28", "c3r29", "c3r30", "c3r31",\
+}
+
+/* Print operand X (an rtx) in assembler syntax to file FILE. */
+#define PRINT_OPERAND(STREAM, X, CODE) score_print_operand (STREAM, X, CODE)
+
+/* A C expression which evaluates to true if CODE is a valid
+ punctuation character for use in the `PRINT_OPERAND' macro. */
+#define PRINT_OPERAND_PUNCT_VALID_P(C) ((C) == '[' || (C) == ']')
+
+/* Print a memory address as an operand to reference that memory location. */
+#define PRINT_OPERAND_ADDRESS(STREAM, X) \
+ score_print_operand_address (STREAM, X)
+
+/* By default on the S+core, external symbols do not have an underscore
+ prepended. */
+#define USER_LABEL_PREFIX ""
+
+/* This is how to output an insn to push a register on the stack. */
+#define ASM_OUTPUT_REG_PUSH(STREAM, REGNO) \
+ do { \
+ fprintf (STREAM, "\tpush! %s,[%s]\n", \
+ reg_names[REGNO], \
+ reg_names[STACK_POINTER_REGNUM]); \
+ } while (0)
+
+/* This is how to output an insn to pop a register from the stack. */
+#define ASM_OUTPUT_REG_POP(STREAM, REGNO) \
+ do { \
+ fprintf (STREAM, "\tpop! %s,[%s]\n", \
+ reg_names[REGNO], \
+ reg_names[STACK_POINTER_REGNUM]); \
+ } while (0)
+
+/* Output of Dispatch Tables. */
+/* This is how to output an element of a case-vector. We can make the
+ entries PC-relative in GP-relative when .gp(d)word is supported. */
+#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM, BODY, VALUE, REL) \
+ do { \
+ if (flag_pic) \
+ fprintf (STREAM, "\t.gpword %sL%d\n", LOCAL_LABEL_PREFIX, VALUE); \
+ else \
+ fprintf (STREAM, "\t.word %sL%d\n", LOCAL_LABEL_PREFIX, VALUE); \
+ } while (0)
+
+/* This is how to output an element of a case-vector that is absolute. */
+#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE) \
+ fprintf (STREAM, "\t.word %sL%d\n", LOCAL_LABEL_PREFIX, VALUE)
+
+/* Assembler Commands for Exception Regions */
+/* Since the S+core is encoded in the least-significant bit
+ of the address, mask it off return addresses for purposes of
+ finding exception handling regions. */
+#define MASK_RETURN_ADDR constm1_rtx
+
+/* Assembler Commands for Alignment */
+/* This is how to output an assembler line to advance the location
+ counter by SIZE bytes. */
+#undef ASM_OUTPUT_SKIP
+#define ASM_OUTPUT_SKIP(STREAM, SIZE) \
+ fprintf (STREAM, "\t.space\t"HOST_WIDE_INT_PRINT_UNSIGNED"\n", (SIZE))
+
+/* This is how to output an assembler line
+ that says to advance the location counter
+ to a multiple of 2**LOG bytes. */
+#define ASM_OUTPUT_ALIGN(STREAM, LOG) \
+ fprintf (STREAM, "\t.align\t%d\n", (LOG))
+
+/* Macros Affecting All Debugging Formats. */
+#ifndef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
+#endif
+
+/* Specific Options for DBX Output. */
+#define DBX_DEBUGGING_INFO 1
+
+/* By default, turn on GDB extensions. */
+#define DEFAULT_GDB_EXTENSIONS 1
+
+#define DBX_CONTIN_LENGTH 0
+
+/* File Names in DBX Format. */
+#define DWARF2_DEBUGGING_INFO 1
+
+/* The DWARF 2 CFA column which tracks the return address. */
+#define DWARF_FRAME_RETURN_COLUMN 3
+
+/* Specify the machine mode that this machine uses
+ for the index in the tablejump instruction. */
+#define CASE_VECTOR_MODE SImode
+
+/* Define if operations between registers always perform the operation
+ on the full register even if a narrower mode is specified. */
+#define WORD_REGISTER_OPERATIONS
+
+/* All references are zero extended. */
+#define LOAD_EXTEND_OP(MODE) ZERO_EXTEND
+
+/* Define if loading short immediate values into registers sign extends. */
+#define SHORT_IMMEDIATES_SIGN_EXTEND
+
+/* Max number of bytes we can move from memory to memory
+ in one reasonably fast instruction. */
+#define MOVE_MAX 4
+
+/* Define this to be nonzero if shift instructions ignore all but the low-order
+ few bits. */
+#define SHIFT_COUNT_TRUNCATED 1
+
+/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits
+ is done just by pretending it is already truncated. */
+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
+
+/* Specify the machine mode that pointers have.
+ After generation of rtl, the compiler makes no further distinction
+ between pointers and any other objects of this machine mode. */
+#define Pmode SImode
+
+/* Give call MEMs SImode since it is the "most permissive" mode
+ for 32-bit targets. */
+#define FUNCTION_MODE Pmode
+
+struct extern_list GTY ((chain_next ("%h.next")))
+{
+ struct extern_list *next; /* next external */
+ const char *name; /* name of the external */
+ int size; /* size in bytes */
+};
+
+extern GTY (()) struct extern_list *extern_head ;
diff --git a/gcc/config/score/score.md b/gcc/config/score/score.md
new file mode 100644
index 00000000000..bc3d99f7126
--- /dev/null
+++ b/gcc/config/score/score.md
@@ -0,0 +1,1253 @@
+;; Machine description for Sunplus S+CORE
+;; Copyright (C) 2005
+;; Free Software Foundation, Inc.
+;; Contributed by Sunnorth.
+
+;; 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 2, 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 COPYING. If not, write to
+;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
+
+;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
+
+; branch conditional branch
+; jump unconditional jump
+; call unconditional call
+; load load instruction(s)
+; store store instruction(s)
+; cmp integer compare
+; arith integer arithmetic instruction
+; move data movement within same register set
+; const load constant
+; nop no operation
+; mul integer multiply
+; div integer divide
+; cndmv conditional moves
+; fce transfer from hi/lo registers
+; tce transfer to hi/lo registers
+; fsr transfer from special registers
+; tsr transfer to special registers
+; pseudo pseudo instruction
+
+(define_constants
+ [(CC_REGNUM 33)
+ (T_REGNUM 34)
+ (RA_REGNUM 3)
+ (SP_REGNUM 0)
+ (AT_REGNUM 1)
+ (FP_REGNUM 2)
+ (RT_REGNUM 4)
+ (GP_REGNUM 28)
+ (EH_REGNUM 29)
+ (HI_REGNUM 48)
+ (LO_REGNUM 49)
+ (CN_REGNUM 50)
+ (LC_REGNUM 51)
+ (SC_REGNUM 52)])
+
+(define_constants
+ [(BITTST 0)
+ (LOAD_ADD 1)
+ (STORE_ADD 2)
+
+ (SCB 3)
+ (SCW 4)
+ (SCE 5)
+ (SCLC 6)
+
+ (LCB 7)
+ (LCW 8)
+ (LCE 9)
+
+ (SFFS 10)])
+
+(define_attr "type"
+ "unknown,branch,jump,call,load,store,cmp,arith,move,const,nop,mul,div,cndmv,fce,tce,fsr,tsr,fcr,tcr,pseudo"
+ (const_string "unknown"))
+
+(define_attr "mode" "unknown,none,QI,HI,SI,DI"
+ (const_string "unknown"))
+
+(define_attr "up_c" "yes,no"
+ (const_string "no"))
+
+(include "score7.md")
+(include "predicates.md")
+(include "misc.md")
+(include "mac.md")
+
+(define_insn "movqi"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,d,*x,d,*a")
+ (match_operand:QI 1 "general_operand" "i,d,m,d,*x,d,*a,d"))]
+ ""
+{
+ switch (which_alternative)
+ {
+ case 0: return mdp_limm (operands);
+ case 1: return mdp_move (operands);
+ case 2: return mdp_linsn (operands, MDA_BYTE, false);
+ case 3: return mdp_sinsn (operands, MDA_BYTE);
+ case 4: return TARGET_MAC ? \"mf%1%S0 %0\" : \"mf%1 %0\";
+ case 5: return TARGET_MAC ? \"mt%0%S1 %1\" : \"mt%0 %1\";
+ case 6: return \"mfsr %0, %1\";
+ case 7: return \"mtsr %1, %0\";
+ default: gcc_unreachable ();
+ }
+}
+ [(set_attr "type" "arith,move,load,store,fce,tce,fsr,tsr")
+ (set_attr "mode" "QI")])
+
+(define_insn "movhi"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,m,d,*x,d,*a")
+ (match_operand:HI 1 "general_operand" "i,d,m,d,*x,d,*a,d"))]
+ ""
+{
+ switch(which_alternative)
+ {
+ case 0: return mdp_limm (operands);
+ case 1: return mdp_move (operands);
+ case 2: return mdp_linsn (operands, MDA_HWORD, false);
+ case 3: return mdp_sinsn (operands, MDA_HWORD);
+ case 4: return TARGET_MAC ? \"mf%1%S0 %0\" : \"mf%1 %0\";
+ case 5: return TARGET_MAC ? \"mt%0%S1 %1\" : \"mt%0 %1\";
+ case 6: return \"mfsr %0, %1\";
+ case 7: return \"mtsr %1, %0\";
+ default: gcc_unreachable ();
+ }
+}
+ [(set_attr "type" "arith,move,load,store,fce,tce,fsr,tsr")
+ (set_attr "mode" "HI")])
+
+(define_insn "movsi"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,m,d,*x,d,*a,d,c")
+ (match_operand:SI 1 "general_operand" "i,d,m,d,*x,d,*a,d,c,d"))]
+ ""
+{
+ switch (which_alternative)
+ {
+ case 0:
+ if (GET_CODE (operands[1]) != CONST_INT)
+ return \"la %0, %1\";
+ else
+ return mdp_limm (operands);
+ case 1: return mdp_move (operands);
+ case 2: return mdp_linsn (operands, MDA_WORD, false);
+ case 3: return mdp_sinsn (operands, MDA_WORD);
+ case 4: return TARGET_MAC ? \"mf%1%S0 %0\" : \"mf%1 %0\";
+ case 5: return TARGET_MAC ? \"mt%0%S1 %1\" : \"mt%0 %1\";
+ case 6: return \"mfsr %0, %1\";
+ case 7: return \"mtsr %1, %0\";
+ case 8: return \"mfcr %0, %1\";
+ case 9: return \"mtcr %1, %0\";
+ default: gcc_unreachable ();
+ }
+}
+ [(set_attr "type" "arith,move,load,store,fce,tce,fsr,tsr,fcr,tcr")
+ (set_attr "mode" "SI")])
+
+(define_insn_and_split "movdi"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,m,d,*x")
+ (match_operand:DI 1 "general_operand" "i,d,m,d,*x,d"))]
+ ""
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+{
+ mds_movdi (operands);
+ DONE;
+})
+
+(define_insn "addsi3"
+ [(set (match_operand:SI 0 "register_operand" "=d,d,d")
+ (plus:SI (match_operand:SI 1 "register_operand" "0,d,%d")
+ (match_operand:SI 2 "arith_operand" "L,N,d")))]
+ ""
+ "@
+ addi %0, %c2
+ addri %0, %1, %c2
+ add %0, %1, %2"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")])
+
+(define_insn "*addsi3_cmp"
+ [(set (reg:CC_NZ CC_REGNUM)
+ (compare:CC_NZ (plus:SI (match_operand:SI 0 "register_operand" "d,d,d")
+ (match_operand:SI 1 "arith_operand" "N,L,d"))
+ (const_int 0)))]
+ ""
+ "@
+ %[ addri.c r1, %0, %c1 %]
+ %[ m%V0 r1, %0\;addi.c r1, %2 %]
+ %[ add.c r1, %0, %1 %]"
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "addsi3_ucc"
+ [(set (reg:CC_NZ CC_REGNUM)
+ (compare:CC_NZ (plus:SI (match_operand:SI 1 "register_operand" "0,d,d")
+ (match_operand:SI 2 "arith_operand" "L,N,d"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=d,d,d")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ ""
+{
+ switch (which_alternative)
+ {
+ case 0: return mdp_add_imm_ucc (operands);
+ case 1: return \"addri.c %0, %1, %c2\";
+ case 2: return mdp_select (operands, "add", true, "");
+ default: gcc_unreachable ();
+ }
+}
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "adddi3"
+ [(set (match_operand:DI 0 "register_operand" "=*e,d")
+ (plus:DI (match_operand:DI 1 "register_operand" "*0,d")
+ (match_operand:DI 2 "register_operand" "*e,d")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "@
+ add! %L0, %L2\;addc! %H0, %H2
+ add.c %L0, %L1, %L2\;addc %H0, %H1, %H2"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "DI")])
+
+(define_insn "subsi3"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (minus:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "d")))]
+ ""
+ "sub %0, %1, %2"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")])
+
+(define_insn "*subsi3_cmp"
+ [(set (reg:CC_NZ CC_REGNUM)
+ (compare:CC_NZ (minus:SI (match_operand:SI 0 "register_operand" "d")
+ (match_operand:SI 1 "register_operand" "d"))
+ (const_int 0)))]
+ ""
+ "%[ sub.c r1, %0, %1 %]"
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_peephole2
+ [(set (match_operand:SI 0 "g32reg_operand" "")
+ (minus:SI (match_operand:SI 1 "g32reg_operand" "")
+ (match_operand:SI 2 "g32reg_operand" "")))
+ (set (reg:CC CC_REGNUM)
+ (compare:CC (match_dup 1) (match_dup 2)))]
+ ""
+ [(parallel
+ [(set (reg:CC CC_REGNUM)
+ (compare:CC (match_dup 1) (match_dup 2)))
+ (set (match_dup 0)
+ (minus:SI (match_dup 1) (match_dup 2)))])])
+
+(define_insn "subsi3_ucc_pcmp"
+ [(parallel
+ [(set (reg:CC CC_REGNUM)
+ (compare:CC (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "d")))
+ (set (match_operand:SI 0 "register_operand" "=d")
+ (minus:SI (match_dup 1) (match_dup 2)))])]
+ ""
+{
+ return mdp_select (operands, "sub", false, "");
+}
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "subsi3_ucc"
+ [(set (reg:CC_NZ CC_REGNUM)
+ (compare:CC_NZ (minus:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "d"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=d")
+ (minus:SI (match_dup 1) (match_dup 2)))]
+ ""
+{
+ return mdp_select (operands, "sub", false, "");
+}
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "subdi3"
+ [(set (match_operand:DI 0 "register_operand" "=*e,d")
+ (minus:DI (match_operand:DI 1 "register_operand" "*0,d")
+ (match_operand:DI 2 "register_operand" "*e,d")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "@
+ sub! %L0, %L2\;subc %H0, %H1, %H2
+ sub.c %L0, %L1, %L2\;subc %H0, %H1, %H2"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "DI")])
+
+(define_insn "andsi3"
+ [(set (match_operand:SI 0 "register_operand" "=d,d,d,d")
+ (and:SI (match_operand:SI 1 "register_operand" "0,0,d,d")
+ (match_operand:SI 2 "arith_operand" "K,Q,M,d")))]
+ ""
+ "@
+ andi %0, %c2
+ andis %0, %U2
+ andri %0, %1, %c2
+ and %0, %1, %2"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")])
+
+(define_insn "andsi3_cmp"
+ [(set (reg:CC_NZ CC_REGNUM)
+ (compare:CC_NZ (and:SI (match_operand:SI 0 "register_operand" "d,d,d,d")
+ (match_operand:SI 1 "arith_operand" "M,K,Q,d"))
+ (const_int 0)))]
+ ""
+ "@
+ %[ andri.c r1, %0, %c1 %]
+ %[ m%V0 r1, %0\;andi.c r1, %c1 %]
+ %[ m%V0 r1, %0\;andis.c r1, %U1 %]
+ %[ and.c r1, %0, %1 %]"
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "andsi3_ucc"
+ [(set (reg:CC_NZ CC_REGNUM)
+ (compare:CC_NZ (and:SI
+ (match_operand:SI 1 "register_operand" "0,0,d,d")
+ (match_operand:SI 2 "arith_operand" "K,Q,M,d"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=d,d,d,d")
+ (and:SI (match_dup 1) (match_dup 2)))]
+ ""
+{
+ switch (which_alternative)
+ {
+ case 0: return \"andi.c %0, %c2\";
+ case 1: return \"andis.c %0, %U2\";
+ case 2: return \"andri.c %0, %1, %c2\";
+ case 3: return mdp_select (operands, "and", true, "");
+ default: gcc_unreachable ();
+ }
+}
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn_and_split "*zero_extract_andi"
+ [(set (reg:CC_NZ CC_REGNUM)
+ (compare:CC_NZ (zero_extract:SI
+ (match_operand:SI 0 "register_operand" "d")
+ (match_operand:SI 1 "const_bi_operand" "")
+ (match_operand:SI 2 "const_bi_operand" ""))
+ (const_int 0)))]
+ ""
+ "#"
+ ""
+ [(const_int 1)]
+{
+ mds_zero_extract_andi (operands);
+ DONE;
+})
+
+(define_insn "iorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=d,d,d,d")
+ (ior:SI (match_operand:SI 1 "register_operand" "0,0,d,d")
+ (match_operand:SI 2 "arith_operand" "K,Q,M,d")))]
+ ""
+ "@
+ ori %0, %c2
+ oris %0, %U2
+ orri %0, %1, %c2
+ or %0, %1, %2"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")])
+
+(define_insn "iorsi3_ucc"
+ [(set (reg:CC_NZ CC_REGNUM)
+ (compare:CC_NZ (ior:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "d"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=d")
+ (ior:SI (match_dup 1) (match_dup 2)))]
+ ""
+{
+ return mdp_select (operands, "or", true, "");
+}
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "iorsi3_cmp"
+ [(set (reg:CC_NZ CC_REGNUM)
+ (compare:CC_NZ (ior:SI (match_operand:SI 0 "register_operand" "d")
+ (match_operand:SI 1 "register_operand" "d"))
+ (const_int 0)))]
+ ""
+ "%[ or.c r1, %0, %1 %]"
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "xorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (xor:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "d")))]
+ ""
+ "xor %0, %1, %2"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")])
+
+(define_insn "xorsi3_ucc"
+ [(set (reg:CC_NZ CC_REGNUM)
+ (compare:CC_NZ (xor:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "d"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=d")
+ (xor:SI (match_dup 1) (match_dup 2)))]
+ ""
+{
+ return mdp_select (operands, "xor", true, "");
+}
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "xorsi3_cmp"
+ [(set (reg:CC_NZ CC_REGNUM)
+ (compare:CC_NZ (xor:SI (match_operand:SI 0 "register_operand" "d")
+ (match_operand:SI 1 "register_operand" "d"))
+ (const_int 0)))]
+ ""
+ "%[ xor.c r1, %0, %1 %]"
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "=d,d")
+ (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "d,m")))]
+ ""
+{
+ switch (which_alternative)
+ {
+ case 0: return \"extsb %0, %1\";
+ case 1: return mdp_linsn (operands, MDA_BYTE, true);
+ default: gcc_unreachable ();
+ }
+}
+ [(set_attr "type" "arith,load")
+ (set_attr "mode" "SI")])
+
+(define_insn "extendqisi2_cmp"
+ [(set (reg:CC_N CC_REGNUM)
+ (compare:CC_N (ashiftrt:SI
+ (ashift:SI (match_operand:SI 0 "register_operand" "d")
+ (const_int 24))
+ (const_int 24))
+ (const_int 0)))]
+ ""
+ "%[ extsb.c r1, %0 %]"
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "extendqisi2_ucc"
+ [(set (reg:CC_N CC_REGNUM)
+ (compare:CC_N (ashiftrt:SI
+ (ashift:SI (match_operand:SI 1 "register_operand" "d")
+ (const_int 24))
+ (const_int 24))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=d")
+ (sign_extend:SI (match_operand:QI 2 "register_operand" "0")))]
+ ""
+ "extsb.c %0, %1"
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "zero_extendqisi2"
+ [(set (match_operand:SI 0 "register_operand""=d,d")
+ (zero_extend:SI (match_operand:QI 1 "register_operand" "d,m")))]
+ ""
+{
+ switch (which_alternative)
+ {
+ case 0: return \"extzb %0, %1\";
+ case 1: return mdp_linsn (operands, MDA_BYTE, false);
+ default: gcc_unreachable ();
+ }
+}
+ [(set_attr "type" "arith, load")
+ (set_attr "mode" "SI")])
+
+(define_insn "extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "=d,d")
+ (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "d,m")))]
+ ""
+{
+ switch (which_alternative)
+ {
+ case 0: return \"extsh %0, %1\";
+ case 1: return mdp_linsn (operands, MDA_HWORD, true);
+ default: gcc_unreachable ();
+ }
+}
+ [(set_attr "type" "arith, load")
+ (set_attr "mode" "SI")])
+
+(define_insn "extendhisi2_cmp"
+ [(set (reg:CC_N CC_REGNUM)
+ (compare:CC_N (ashiftrt:SI
+ (ashift:SI (match_operand:SI 0 "register_operand" "d")
+ (const_int 16))
+ (const_int 16))
+ (const_int 0)))]
+ ""
+ "%[ extsh.c r1, %0 %]"
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "extendhisi2_ucc"
+ [(set (reg:CC_N CC_REGNUM)
+ (compare:CC_N (ashiftrt:SI
+ (ashift:SI (match_operand:SI 1 "register_operand" "d")
+ (const_int 16))
+ (const_int 16))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=d")
+ (sign_extend:SI (match_operand:HI 2 "register_operand" "0")))]
+ ""
+ "extsh.c %0, %1"
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "zero_extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "=d,d")
+ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "d,m")))]
+ ""
+{
+ switch (which_alternative)
+ {
+ case 0: return \"extzh %0, %1\";
+ case 1: return mdp_linsn (operands, MDA_HWORD, false);
+ default: gcc_unreachable ();
+ }
+ }
+ [(set_attr "type" "arith, load")
+ (set_attr "mode" "SI")])
+
+(define_insn "mulsi3"
+ [(set (match_operand:SI 0 "register_operand" "=l")
+ (mult:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "d")))
+ (clobber (reg:SI HI_REGNUM))]
+ "!TARGET_SCORE5U"
+ "mul %1, %2"
+ [(set_attr "type" "mul")
+ (set_attr "mode" "SI")])
+
+(define_insn "mulsidi3"
+ [(set (match_operand:DI 0 "register_operand" "=x")
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "d"))
+ (sign_extend:DI
+ (match_operand:SI 2 "register_operand" "d"))))]
+ "!TARGET_SCORE5U"
+ "mul %1, %2"
+ [(set_attr "type" "mul")
+ (set_attr "mode" "DI")])
+
+(define_insn "umulsidi3"
+ [(set (match_operand:DI 0 "register_operand" "=x")
+ (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "d"))
+ (zero_extend:DI
+ (match_operand:SI 2 "register_operand" "d"))))]
+ "!TARGET_SCORE5U"
+ "mulu %1, %2"
+ [(set_attr "type" "mul")
+ (set_attr "mode" "DI")])
+
+(define_insn "divmodsi4"
+ [(set (match_operand:SI 0 "register_operand" "=l")
+ (div:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "d")))
+ (set (match_operand:SI 3 "register_operand" "=h")
+ (mod:SI (match_dup 1) (match_dup 2)))]
+ "!TARGET_SCORE5U"
+ "div %1, %2"
+ [(set_attr "type" "div")
+ (set_attr "mode" "SI")])
+
+(define_insn "udivmodsi4"
+ [(set (match_operand:SI 0 "register_operand" "=l")
+ (udiv:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "d")))
+ (set (match_operand:SI 3 "register_operand" "=h")
+ (umod:SI (match_dup 1) (match_dup 2)))]
+ "!TARGET_SCORE5U"
+ "divu %1, %2"
+ [(set_attr "type" "div")
+ (set_attr "mode" "SI")])
+
+(define_insn "ashlsi3"
+ [(set (match_operand:SI 0 "register_operand" "=d,d")
+ (ashift:SI (match_operand:SI 1 "register_operand" "d,d")
+ (match_operand:SI 2 "arith_operand" "J,d")))]
+ ""
+ "@
+ slli %0, %1, %c2
+ sll %0, %1, %2"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")])
+
+(define_insn "ashlsi3_ucc"
+ [(set (reg:CC_NZ CC_REGNUM)
+ (compare:CC_NZ (ashift:SI
+ (match_operand:SI 1 "register_operand" "d,d")
+ (match_operand:SI 2 "arith_operand" "J,d"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=d,d")
+ (ashift:SI (match_dup 1) (match_dup 2)))]
+ ""
+{
+ switch (which_alternative)
+ {
+ case 0: return mdp_select (operands, "slli", false, "c");
+ case 1: return mdp_select (operands, "sll", false, "");
+ default: gcc_unreachable ();
+ }
+}
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "ashlsi3_cmp"
+ [(set (reg:CC_NZ CC_REGNUM)
+ (compare:CC_NZ (ashift:SI
+ (match_operand:SI 0 "register_operand" "d,d")
+ (match_operand:SI 1 "arith_operand" "J,d"))
+ (const_int 0)))]
+ ""
+ "@
+ %[ slli.c r1, %0, %c1 %]
+ %[ sll.c r1, %0, %1 %]"
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "ashrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=d,d")
+ (ashiftrt:SI (match_operand:SI 1 "register_operand" "d,d")
+ (match_operand:SI 2 "arith_operand" "J,d")))]
+ ""
+ "@
+ srai %0, %1, %c2
+ sra %0, %1, %2"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")])
+
+(define_insn "ashrsi3_ucc"
+ [(set (reg:CC_NZ CC_REGNUM)
+ (compare:CC_NZ (ashiftrt:SI
+ (match_operand:SI 1 "register_operand" "d,d")
+ (match_operand:SI 2 "arith_operand" "J,d"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=d,d")
+ (ashiftrt:SI (match_dup 1) (match_dup 2)))]
+ ""
+{
+ switch (which_alternative)
+ {
+ case 0: return \"srai.c %0, %1, %c2\";
+ case 1: return mdp_select (operands, "sra", false, "");
+ default: gcc_unreachable ();
+ }
+}
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "ashrsi3_cmp"
+ [(set (reg:CC_NZ CC_REGNUM)
+ (compare:CC_NZ (ashiftrt:SI
+ (match_operand:SI 0 "register_operand" "d,d")
+ (match_operand:SI 1 "arith_operand" "J,d"))
+ (const_int 0)))]
+ ""
+ "@
+ %[ srai.c r1, %0, %c1 %]
+ %[ sra.c r1, %0, %1 %]"
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "ashrsi3_ucc_n"
+ [(set (reg:CC_N CC_REGNUM)
+ (compare:CC_N (ashiftrt:SI
+ (match_operand:SI 1 "register_operand" "d,d")
+ (match_operand:SI 2 "arith_operand" "J,d"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=d,d")
+ (ashiftrt:SI (match_dup 1) (match_dup 2)))]
+ ""
+{
+ switch (which_alternative)
+ {
+ case 0: return \"srai.c %0, %1, %c2\";
+ case 1: return mdp_select (operands, "sra", false, "");
+ default: gcc_unreachable ();
+ }
+}
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "ashrsi3_cmp_n"
+ [(set (reg:CC_N CC_REGNUM)
+ (compare:CC_N (ashiftrt:SI
+ (match_operand:SI 0 "register_operand" "d,d")
+ (match_operand:SI 1 "arith_operand" "J,d"))
+ (const_int 0)))]
+ ""
+ "@
+ %[ srai.c r1, %0, %c1 %]
+ %[ sra.c r1, %0, %1 %]"
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "lshrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=d,d")
+ (lshiftrt:SI (match_operand:SI 1 "register_operand" "d,d")
+ (match_operand:SI 2 "arith_operand" "J,d")))]
+ ""
+ "@
+ srli %0, %1, %c2
+ srl %0, %1, %2"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")])
+
+(define_insn "lshrsi3_ucc"
+ [(set (reg:CC_NZ CC_REGNUM)
+ (compare:CC_NZ (lshiftrt:SI
+ (match_operand:SI 1 "register_operand" "d,d")
+ (match_operand:SI 2 "arith_operand" "J,d"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=d,d")
+ (lshiftrt:SI (match_dup 1) (match_dup 2)))]
+ ""
+{
+ switch (which_alternative)
+ {
+ case 0: return mdp_select (operands, "srli", false, "c");
+ case 1: return mdp_select (operands, "srl", false, "");
+ default: gcc_unreachable ();
+ }
+}
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "lshrsi3_cmp"
+ [(set (reg:CC_NZ CC_REGNUM)
+ (compare:CC_NZ (lshiftrt:SI
+ (match_operand:SI 0 "register_operand" "d,d")
+ (match_operand:SI 1 "arith_operand" "J,d"))
+ (const_int 0)))]
+ ""
+ "@
+ %[ srli.c r1, %0, %c1 %]
+ %[ srl.c r1, %0, %1 %]"
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "negsi2"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (neg:SI (match_operand:SI 1 "register_operand" "d")))]
+ ""
+ "neg %0, %1"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")])
+
+(define_insn "negsi2_ucc"
+ [(set (reg:CC CC_REGNUM)
+ (compare:CC (neg:SI (match_operand:SI 1 "register_operand" "*e,d"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=*e,d")
+ (neg:SI (match_dup 1)))]
+ ""
+ "@
+ neg! %0, %1
+ neg.c %0, %1"
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "one_cmplsi2"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (not:SI (match_operand:SI 1 "register_operand" "d")))]
+ ""
+ "not %0, %1"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")])
+
+(define_insn "one_cmplsi2_ucc"
+ [(set (reg:CC_NZ CC_REGNUM)
+ (compare:CC_NZ (not:SI (match_operand:SI 1 "register_operand" "*e,d"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=*e,d")
+ (not:SI (match_dup 1)))]
+ ""
+ "@
+ not! %0, %1
+ not.c %0, %1"
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "one_cmplsi2_cmp"
+ [(set (reg:CC_NZ CC_REGNUM)
+ (compare:CC_NZ (not:SI (match_operand:SI 0 "register_operand" "*e,d"))
+ (const_int 0)))]
+ ""
+ "@
+ %[ not! r1, %0 %]
+ %[ not.c r1, %0 %]"
+ [(set_attr "type" "arith")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "rotlsi3"
+ [(set (match_operand:SI 0 "register_operand" "=d,d")
+ (rotate:SI (match_operand:SI 1 "register_operand" "d,d")
+ (match_operand:SI 2 "arith_operand" "J,d")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "@
+ roli.c %0, %1, %c2
+ rol.c %0, %1, %2"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")])
+
+(define_insn "rotrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=d,d")
+ (rotatert:SI (match_operand:SI 1 "register_operand" "d,d")
+ (match_operand:SI 2 "arith_operand" "J,d")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "@
+ rori.c %0, %1, %c2
+ ror.c %0, %1, %2"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")])
+
+(define_expand "cmpsi"
+ [(match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "arith_operand" "")]
+ ""
+{
+ cmp_op0 = operands[0];
+ cmp_op1 = operands[1];
+ DONE;
+})
+
+(define_insn "cmpsi_nz"
+ [(set (reg:CC_NZ CC_REGNUM)
+ (compare:CC_NZ (match_operand:SI 0 "register_operand" "d,*e,d")
+ (match_operand:SI 1 "arith_operand" "L,*e,d")))]
+ ""
+ "@
+ cmpi.c %0, %c1
+ cmp! %0, %1
+ cmp.c %0, %1"
+ [(set_attr "type" "cmp")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "cmpsi_n"
+ [(set (reg:CC_N CC_REGNUM)
+ (compare:CC_N (match_operand:SI 0 "register_operand" "d,*e,d")
+ (match_operand:SI 1 "arith_operand" "L,*e,d")))]
+ ""
+ "@
+ cmpi.c %0, %c1
+ cmp! %0, %1
+ cmp.c %0, %1"
+ [(set_attr "type" "cmp")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_insn "cmpsi_cc"
+ [(set (reg:CC CC_REGNUM)
+ (compare:CC (match_operand:SI 0 "register_operand" "d,*e,d")
+ (match_operand:SI 1 "arith_operand" "L,*e,d")))]
+ ""
+ "@
+ cmpi.c %0, %c1
+ cmp! %0, %1
+ cmp.c %0, %1"
+ [(set_attr "type" "cmp")
+ (set_attr "up_c" "yes")
+ (set_attr "mode" "SI")])
+
+(define_expand "beq"
+ [(set (pc)
+ (if_then_else (eq (reg:CC CC_REGNUM) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ mda_gen_cmp (CCmode);
+})
+
+(define_expand "bne"
+ [(set (pc)
+ (if_then_else (ne (reg:CC CC_REGNUM) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ mda_gen_cmp (CCmode);
+})
+
+(define_expand "bgt"
+ [(set (pc)
+ (if_then_else (gt (reg:CC CC_REGNUM) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ mda_gen_cmp (CCmode);
+})
+
+(define_expand "ble"
+ [(set (pc)
+ (if_then_else (le (reg:CC CC_REGNUM) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ mda_gen_cmp (CCmode);
+})
+
+(define_expand "bge"
+ [(set (pc)
+ (if_then_else (ge (reg:CC CC_REGNUM) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ mda_gen_cmp (CCmode);
+})
+
+(define_expand "blt"
+ [(set (pc)
+ (if_then_else (lt (reg:CC CC_REGNUM) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ mda_gen_cmp (CCmode);
+})
+
+(define_expand "bgtu"
+ [(set (pc)
+ (if_then_else (gtu (reg:CC CC_REGNUM) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ mda_gen_cmp (CCmode);
+})
+
+(define_expand "bleu"
+ [(set (pc)
+ (if_then_else (leu (reg:CC CC_REGNUM) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ mda_gen_cmp (CCmode);
+})
+
+(define_expand "bgeu"
+ [(set (pc)
+ (if_then_else (geu (reg:CC CC_REGNUM) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ mda_gen_cmp (CCmode);
+})
+
+(define_expand "bltu"
+ [(set (pc)
+ (if_then_else (ltu (reg:CC CC_REGNUM) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ mda_gen_cmp (CCmode);
+})
+
+(define_insn "branch_n"
+ [(set (pc)
+ (if_then_else
+ (match_operator 0 "branch_n_operator"
+ [(reg:CC_N CC_REGNUM)
+ (const_int 0)])
+ (label_ref (match_operand 1 "" ""))
+ (pc)))]
+ ""
+ "b%C0 %1"
+ [(set_attr "type" "branch")])
+
+(define_insn "branch_nz"
+ [(set (pc)
+ (if_then_else
+ (match_operator 0 "branch_nz_operator"
+ [(reg:CC_NZ CC_REGNUM)
+ (const_int 0)])
+ (label_ref (match_operand 1 "" ""))
+ (pc)))]
+ ""
+ "b%C0 %1"
+ [(set_attr "type" "branch")])
+
+(define_insn "branch_cc"
+ [(set (pc)
+ (if_then_else
+ (match_operator 0 "comparison_operator"
+ [(reg:CC CC_REGNUM)
+ (const_int 0)])
+ (label_ref (match_operand 1 "" ""))
+ (pc)))]
+ ""
+ "b%C0 %1"
+ [(set_attr "type" "branch")])
+
+(define_insn "jump"
+ [(set (pc)
+ (label_ref (match_operand 0 "" "")))]
+ ""
+{
+ if (!flag_pic)
+ return \"j %0\";
+ else
+ return \"b %0\";
+}
+ [(set_attr "type" "jump")])
+
+(define_expand "sibcall"
+ [(parallel [(call (match_operand 0 "" "")
+ (match_operand 1 "" ""))
+ (use (match_operand 2 "" ""))])]
+ ""
+{
+ mdx_call (operands, true);
+ DONE;
+})
+
+(define_insn "sibcall_internal"
+ [(call (mem:SI (match_operand:SI 0 "call_insn_operand" "t,Z"))
+ (match_operand 1 "" ""))
+ (clobber (reg:SI RT_REGNUM))]
+ "SIBLING_CALL_P (insn) && !flag_pic"
+ "@
+ br%S0 %0
+ j %0"
+ [(set_attr "type" "call")])
+
+(define_expand "sibcall_value"
+ [(parallel [(set (match_operand 0 "" "")
+ (call (match_operand 1 "" "") (match_operand 2 "" "")))
+ (use (match_operand 3 "" ""))])]
+ ""
+{
+ mdx_call_value (operands, true);
+ DONE;
+})
+
+(define_insn "sibcall_value_internal"
+ [(set (match_operand 0 "register_operand" "=d,d")
+ (call (mem:SI (match_operand:SI 1 "call_insn_operand" "t,Z"))
+ (match_operand 2 "" "")))
+ (clobber (reg:SI RT_REGNUM))]
+ "SIBLING_CALL_P(insn) && !flag_pic"
+ "@
+ br%S1 %1
+ j %1"
+ [(set_attr "type" "call")])
+
+(define_expand "call"
+ [(parallel [(call (match_operand 0 "" "") (match_operand 1 "" ""))
+ (use (match_operand 2 "" ""))])]
+ ""
+{
+ mdx_call (operands, false);
+ DONE;
+})
+
+(define_insn "call_internal"
+ [(call (mem:SI (match_operand:SI 0 "call_insn_operand" "d,Z"))
+ (match_operand 1 "" ""))
+ (clobber (reg:SI RA_REGNUM))]
+ ""
+{
+ if (!flag_pic)
+ switch (which_alternative)
+ {
+ case 0: return \"brl%S0 %0\";
+ case 1: return \"jl %0\";
+ default: gcc_unreachable ();
+ }
+ else
+ return \"la r29, %0\;brl r29\";
+}
+ [(set_attr "type" "call")])
+
+(define_expand "call_value"
+ [(parallel [(set (match_operand 0 "" "")
+ (call (match_operand 1 "" "") (match_operand 2 "" "")))
+ (use (match_operand 3 "" ""))])]
+ ""
+{
+ mdx_call_value (operands, false);
+ DONE;
+})
+
+(define_insn "call_value_internal"
+ [(set (match_operand 0 "register_operand" "=d,d")
+ (call (mem:SI (match_operand:SI 1 "call_insn_operand" "d,Z"))
+ (match_operand 2 "" "")))
+ (clobber (reg:SI RA_REGNUM))]
+ ""
+{
+ if (!flag_pic)
+ switch (which_alternative)
+ {
+ case 0: return \"brl%S1 %1\";
+ case 1: return \"jl %1\";
+ default: gcc_unreachable ();
+ }
+ else
+ return \"la r29, %1\;brl r29\";
+}
+ [(set_attr "type" "call")])
+
+(define_expand "indirect_jump"
+ [(set (pc) (match_operand 0 "register_operand" "d"))]
+ ""
+{
+ rtx dest;
+ dest = operands[0];
+ if (GET_CODE (dest) != REG
+ || GET_MODE (dest) != Pmode)
+ operands[0] = copy_to_mode_reg (Pmode, dest);
+
+ emit_jump_insn (gen_indirect_jump_internal1 (operands[0]));
+ DONE;
+})
+
+(define_insn "indirect_jump_internal1"
+ [(set (pc) (match_operand:SI 0 "register_operand" "d"))]
+ ""
+ "br%S0 %0"
+ [(set_attr "type" "jump")])
+
+(define_expand "tablejump"
+ [(set (pc)
+ (match_operand 0 "register_operand" "d"))
+ (use (label_ref (match_operand 1 "" "")))]
+ ""
+{
+ if (GET_MODE (operands[0]) != ptr_mode)
+ gcc_unreachable ();
+ emit_jump_insn (gen_tablejump_internal1 (operands[0], operands[1]));
+ DONE;
+})
+
+(define_insn "tablejump_internal1"
+ [(set (pc)
+ (match_operand:SI 0 "register_operand" "d"))
+ (use (label_ref (match_operand 1 "" "")))]
+ ""
+ "*
+ if (flag_pic)
+ return \"mv! r29, %0\;.cpadd r29\;br%S0 r29\";
+ else
+ return \"br%S0 %0\";
+ "
+ [(set_attr "type" "jump")])
+
+(define_expand "prologue"
+ [(const_int 1)]
+ ""
+{
+ mdx_prologue ();
+ DONE;
+})
+
+(define_expand "epilogue"
+ [(const_int 2)]
+ ""
+{
+ mdx_epilogue (false);
+ DONE;
+})
+
+(define_expand "sibcall_epilogue"
+ [(const_int 2)]
+ ""
+{
+ mdx_epilogue (true);
+ DONE;
+})
+
+(define_insn "return_internal"
+ [(return)
+ (use (match_operand 0 "pmode_register_operand" "d"))]
+ ""
+ "br%S0 %0")
+
+(define_insn "nop"
+ [(const_int 0)]
+ ""
+ "#nop!"
+)
+
+(define_insn "cpload"
+ [(unspec:SI [(const_int 1)] 1)]
+ "flag_pic"
+ ".cpload r29"
+)
+
+(define_insn "cprestore"
+ [(unspec:SI [(match_operand:SI 0 "" "")] 2)]
+ "flag_pic"
+ ".cprestore %0"
+)
diff --git a/gcc/config/score/score.opt b/gcc/config/score/score.opt
new file mode 100644
index 00000000000..2b9f03e480c
--- /dev/null
+++ b/gcc/config/score/score.opt
@@ -0,0 +1,53 @@
+; Options for the Sunnorth port of the compiler.
+
+; Copyright (C) 2005 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 2, 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 COPYING. If not, write to the Free
+; Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+; 02110-1301, USA.
+
+meb
+Target RejectNegative Report InverseMask(LITTLE_ENDIAN)
+Generate big-endian code
+
+mel
+Target RejectNegative Report Mask(LITTLE_ENDIAN)
+Generate little-endian code
+
+mnpi
+Target RejectNegative Report Mask(NOPINDEX)
+Do not use pre/post index
+
+mnuls
+Target RejectNegative Report Mask(NOUNALIGNED)
+Do not use unaligned load/store
+
+mmac
+Target RejectNegative Report Mask(MAC)
+Enable mac instruction
+
+mSCORE5
+Target RejectNegative Report Mask(SCORE5)
+Support SCORE 5 ISA
+
+mSCORE5U
+Target RejectNegative Report Mask(SCORE5U)
+Support SCORE 5U ISA
+
+mSCORE7
+Target RejectNegative Report Mask(SCORE7)
+Support SCORE 7 ISA
+
diff --git a/gcc/config/score/score7.md b/gcc/config/score/score7.md
new file mode 100644
index 00000000000..f04054ea5fa
--- /dev/null
+++ b/gcc/config/score/score7.md
@@ -0,0 +1,46 @@
+;; Machine description for Sunplus S+CORE
+;; Sunplus S+CORE 7 Pipeline Description
+;; Copyright (C) 2005
+;; Free Software Foundation, Inc.
+;; Contributed by Sunnorth.
+
+;; 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 2, 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 COPYING. If not, write to
+;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
+
+(define_automaton "score")
+
+(define_cpu_unit "core" "score")
+
+(define_insn_reservation "memory" 3
+ (eq_attr "type" "load")
+ "core")
+
+(define_insn_reservation "mul" 3
+ (eq_attr "type" "mul,div")
+ "core")
+
+(define_insn_reservation "fce" 1
+ (eq_attr "type" "fce")
+ "core")
+
+(define_insn_reservation "tsr" 1
+ (eq_attr "type" "tsr,fsr")
+ "core")
+
+(define_insn_reservation "up_c" 1
+ (eq_attr "up_c" "yes")
+ "core")
diff --git a/gcc/config/score/t-score-elf b/gcc/config/score/t-score-elf
new file mode 100644
index 00000000000..66424dddebd
--- /dev/null
+++ b/gcc/config/score/t-score-elf
@@ -0,0 +1,44 @@
+# Additional Backend Files
+score-mdaux.o: $(srcdir)/config/score/score-mdaux.c $(CONFIG_H) $(SYSTEM_H) \
+ coretypes.h $(TM_H) $(RTL_H) output.h flags.h $(TREE_H) \
+ expr.h toplev.h $(TM_P_H)
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+ $(srcdir)/config/score/score-mdaux.c
+
+# Assemble startup files.
+$(T)crti.o: $(srcdir)/config/score/crti.asm $(GCC_PASSES)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \
+ -c -o $(T)crti.o -x assembler-with-cpp $(srcdir)/config/score/crti.asm
+
+$(T)crtn.o: $(srcdir)/config/score/crtn.asm $(GCC_PASSES)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \
+ -c -o $(T)crtn.o -x assembler-with-cpp $(srcdir)/config/score/crtn.asm
+
+LIB1ASMSRC = score/mul-div.S
+
+LIB1ASMFUNCS = _mulsi3 _divsi3 _flush_cache
+
+FPBIT = fp-bit.c
+DPBIT = dp-bit.c
+
+# If any special flags are necessary when building libgcc2 put them here.
+TARGET_LIBGCC2_CFLAGS = -g
+
+fp-bit.c: $(srcdir)/config/fp-bit.c
+ echo '#define FLOAT' > fp-bit.c
+ cat $(srcdir)/config/fp-bit.c >> fp-bit.c
+
+dp-bit.c: $(srcdir)/config/fp-bit.c
+ cat $(srcdir)/config/fp-bit.c > dp-bit.c
+
+# We must build libgcc2.a with -G 0, in case the user wants to link
+# without the $gp register.
+TARGET_LIBGCC2_CFLAGS = -G 0
+
+MULTILIB_OPTIONS = mel mSCORE7
+EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crti.o crtn.o
+
+LIBGCC = stmp-multilib
+INSTALL_LIBGCC = install-multilib
+
+
OpenPOWER on IntegriCloud