From bdcee4712ec20209d14aeb2d0487de41be1ad424 Mon Sep 17 00:00:00 2001 From: Chen Liqin Date: Tue, 10 Oct 2006 07:50:29 +0000 Subject: [PATCH] * Add new port for score. From-SVN: r117597 --- ChangeLog | 4 + gcc/config.gcc | 8 + gcc/config/score/crti.asm | 85 ++ gcc/config/score/crtn.asm | 47 ++ gcc/config/score/elf.h | 101 +++ gcc/config/score/mac.md | 181 +++++ gcc/config/score/misc.md | 108 +++ gcc/config/score/mul-div.S | 224 ++++++ gcc/config/score/predicates.md | 63 ++ gcc/config/score/score-conv.h | 82 ++ gcc/config/score/score-mdaux.c | 738 ++++++++++++++++++ gcc/config/score/score-mdaux.h | 113 +++ gcc/config/score/score-modes.def | 26 + gcc/config/score/score-protos.h | 92 +++ gcc/config/score/score-version.h | 21 + gcc/config/score/score.c | 1071 +++++++++++++++++++++++++ gcc/config/score/score.h | 909 ++++++++++++++++++++++ gcc/config/score/score.md | 1253 ++++++++++++++++++++++++++++++ gcc/config/score/score.opt | 53 ++ gcc/config/score/score7.md | 46 ++ gcc/config/score/t-score-elf | 44 ++ gcc/configure | 2 +- 22 files changed, 5270 insertions(+), 1 deletion(-) create mode 100644 gcc/config/score/crti.asm create mode 100644 gcc/config/score/crtn.asm create mode 100644 gcc/config/score/elf.h create mode 100644 gcc/config/score/mac.md create mode 100644 gcc/config/score/misc.md create mode 100644 gcc/config/score/mul-div.S create mode 100644 gcc/config/score/predicates.md create mode 100644 gcc/config/score/score-conv.h create mode 100644 gcc/config/score/score-mdaux.c create mode 100644 gcc/config/score/score-mdaux.h create mode 100644 gcc/config/score/score-modes.def create mode 100644 gcc/config/score/score-protos.h create mode 100644 gcc/config/score/score-version.h create mode 100644 gcc/config/score/score.c create mode 100644 gcc/config/score/score.h create mode 100644 gcc/config/score/score.md create mode 100644 gcc/config/score/score.opt create mode 100644 gcc/config/score/score7.md create mode 100644 gcc/config/score/t-score-elf diff --git a/ChangeLog b/ChangeLog index 06424fa5a29..f59e369ff93 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2006-10-10 Chen Liqin + + * MAINTAINERS: Add self as score port maintainer. + 2006-10-04 Brooks Moses * MAINTAINERS (Write After Approval): Add myself. diff --git a/gcc/config.gcc b/gcc/config.gcc index 6068a28f8a8..b6de3e775ae 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -309,6 +309,9 @@ powerpc*-*-*) rs6000*-*-*) need_64bit_hwint=yes ;; +score*-*-*) + cpu_type=score + ;; sparc64*-*-*) cpu_type=sparc need_64bit_hwint=yes @@ -1932,6 +1935,11 @@ s390x-ibm-tpf*) thread_file='tpf' extra_options="${extra_options} s390/tpf.opt" ;; +score-*-elf) + tm_file="dbxelf.h elfos.h score/elf.h score/score.h" + tmake_file=score/t-score-elf + extra_objs="score-mdaux.o" + ;; sh-*-elf* | sh[12346l]*-*-elf* | sh*-*-kaos* | \ sh-*-symbianelf* | sh[12346l]*-*-symbianelf* | \ sh-*-linux* | sh[346lbe]*-*-linux* | \ 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 +#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 +#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 + + diff --git a/gcc/configure b/gcc/configure index ff7e9c811c7..37788e92cb4 100755 --- a/gcc/configure +++ b/gcc/configure @@ -15619,7 +15619,7 @@ esac case "$target" in i?86*-*-* | mips*-*-* | alpha*-*-* | powerpc*-*-* | sparc*-*-* | m68*-*-* \ | x86_64*-*-* | hppa*-*-* | arm*-*-* | strongarm*-*-* | xscale*-*-* \ - | xstormy16*-*-* | cris-*-* | xtensa-*-* | bfin-*-*) + | xstormy16*-*-* | cris-*-* | xtensa-*-* | bfin-*-* | score*-*-*) insn="nop" ;; ia64*-*-* | s390*-*-*)