]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
C-SKY port: Backend implementation
authorJojo <jijie_rong@c-sky.com>
Fri, 17 Aug 2018 19:03:27 +0000 (19:03 +0000)
committerSandra Loosemore <sandra@gcc.gnu.org>
Fri, 17 Aug 2018 19:03:27 +0000 (15:03 -0400)
2018-08-17  Jojo  <jijie_rong@c-sky.com>
    Huibin Wang  <huibin_wang@c-sky.com>
    Sandra Loosemore  <sandra@codesourcery.com>
    Chung-Lin Tang  <cltang@codesourcery.com>

C-SKY port: Backend implementation

gcc/
* config/csky/*: New.
* common/config/csky/*: New.

Co-Authored-By: Chung-Lin Tang <cltang@codesourcery.com>
Co-Authored-By: Huibin Wang <huibin_wang@c-sky.com>
Co-Authored-By: Sandra Loosemore <sandra@codesourcery.com>
From-SVN: r263628

28 files changed:
gcc/ChangeLog
gcc/common/config/csky/csky-common.c [new file with mode: 0644]
gcc/config/csky/constraints.md [new file with mode: 0644]
gcc/config/csky/csky-elf.h [new file with mode: 0644]
gcc/config/csky/csky-linux-elf.h [new file with mode: 0644]
gcc/config/csky/csky-protos.h [new file with mode: 0644]
gcc/config/csky/csky.c [new file with mode: 0644]
gcc/config/csky/csky.h [new file with mode: 0644]
gcc/config/csky/csky.md [new file with mode: 0644]
gcc/config/csky/csky.opt [new file with mode: 0644]
gcc/config/csky/csky_cores.def [new file with mode: 0644]
gcc/config/csky/csky_genopt.sh [new file with mode: 0644]
gcc/config/csky/csky_insn_dsp.md [new file with mode: 0644]
gcc/config/csky/csky_insn_fpu.md [new file with mode: 0644]
gcc/config/csky/csky_isa.def [new file with mode: 0644]
gcc/config/csky/csky_isa.h [new file with mode: 0644]
gcc/config/csky/csky_opts.h [new file with mode: 0644]
gcc/config/csky/csky_pipeline_ck801.md [new file with mode: 0644]
gcc/config/csky/csky_pipeline_ck802.md [new file with mode: 0644]
gcc/config/csky/csky_pipeline_ck803.md [new file with mode: 0644]
gcc/config/csky/csky_pipeline_ck810.md [new file with mode: 0644]
gcc/config/csky/csky_tables.opt [new file with mode: 0644]
gcc/config/csky/predicates.md [new file with mode: 0644]
gcc/config/csky/print-sysroot-suffix.sh [new file with mode: 0644]
gcc/config/csky/t-csky [new file with mode: 0644]
gcc/config/csky/t-csky-elf [new file with mode: 0644]
gcc/config/csky/t-csky-linux [new file with mode: 0644]
gcc/config/csky/t-sysroot-suffix [new file with mode: 0644]

index b1367f752b2180ee1523636795b359b20f03b892..7b8ce71836315ddbefb1504f35e938a552a0244f 100644 (file)
@@ -1,3 +1,13 @@
+2018-08-17  Jojo  <jijie_rong@c-sky.com>
+           Huibin Wang  <huibin_wang@c-sky.com>
+           Sandra Loosemore  <sandra@codesourcery.com>
+           Chung-Lin Tang  <cltang@codesourcery.com>
+
+       C-SKY port: Backend implementation
+
+       * config/csky/*: New.
+       * common/config/csky/*: New.
+
 2018-08-17  Jojo  <jijie_rong@c-sky.com>
            Huibin Wang  <huibin_wang@c-sky.com>
            Sandra Loosemore  <sandra@codesourcery.com>
diff --git a/gcc/common/config/csky/csky-common.c b/gcc/common/config/csky/csky-common.c
new file mode 100644 (file)
index 0000000..39095bf
--- /dev/null
@@ -0,0 +1,42 @@
+/* Common hooks for CSKY.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   Contributed by C-SKY Microsystems and Mentor Graphics.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "common/common-target.h"
+#include "common/common-target-def.h"
+
+/* Set default optimization options.  */
+static const struct default_options csky_option_optimization_table[] =
+  {
+    /* Enable section anchors by default at -O1 or higher.  */
+    { OPT_LEVELS_1_PLUS, OPT_fsection_anchors, NULL, 1 },
+    { OPT_LEVELS_NONE, 0, NULL, 0 }
+  };
+
+#undef  TARGET_DEFAULT_TARGET_FLAGS
+#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
+
+#undef  TARGET_OPTION_OPTIMIZATION_TABLE
+#define TARGET_OPTION_OPTIMIZATION_TABLE csky_option_optimization_table
+
+struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER;
diff --git a/gcc/config/csky/constraints.md b/gcc/config/csky/constraints.md
new file mode 100644 (file)
index 0000000..e08f7f8
--- /dev/null
@@ -0,0 +1,174 @@
+;; Constraints for C-SKY.
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+;; Contributed by C-SKY Microsystems and Mentor Graphics.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.  */
+
+;; Register constraints.
+
+(define_register_constraint "a" "MINI_REGS" "r0 - r7")
+(define_register_constraint "b" "LOW_REGS"  "r0 - r15")
+(define_register_constraint "c" "C_REGS" "C register")
+(define_register_constraint "y" "HILO_REGS" "HI and LO registers")
+(define_register_constraint "l" "LO_REGS" "LO register")
+(define_register_constraint "h" "HI_REGS" "HI register")
+(define_register_constraint "v" "V_REGS" "vector registers")
+(define_register_constraint "z" "SP_REGS" "SP register")
+
+
+;; Memory and misc constraints.
+
+(define_memory_constraint "Q"
+  "Memory operands with base register, index register and short displacement for FPUV2"
+  (match_test "csky_valid_fpuv2_mem_operand (op)"))
+
+(define_constraint "R"
+  "Memory operands whose address is a label_ref"
+  (and (match_code "mem")
+       (match_test "GET_CODE (XEXP (op, 0)) == LABEL_REF")))
+
+(define_constraint "S"
+  "Symbol reference with optional offset"
+  (match_test "csky_symbolic_address_p (op)"))
+
+
+;; Constant integer constraints.
+
+(define_constraint "I"
+  "Constant in range [0, 65535]"
+  (and (match_code "const_int")
+       (match_test "CSKY_CONST_OK_FOR_I (ival)")))
+
+(define_constraint "J"
+  "Constant in range [1, 32]"
+  (and (match_code "const_int")
+       (match_test "CSKY_CONST_OK_FOR_J (ival)")))
+
+(define_constraint "K"
+  "Constant in range [0, 31]"
+  (and (match_code "const_int")
+       (match_test "CSKY_CONST_OK_FOR_K (ival)")))
+
+(define_constraint "L"
+  "Constant in range [1, 8]"
+  (and (match_code "const_int")
+       (match_test "CSKY_CONST_OK_FOR_L (ival)")))
+
+(define_constraint "M"
+  "Constant in range [1, 4096]"
+  (and (match_code "const_int")
+       (match_test "CSKY_CONST_OK_FOR_M (ival)")))
+
+(define_constraint "N"
+  "Constant in range [1, 256]"
+  (and (match_code "const_int")
+       (match_test "CSKY_CONST_OK_FOR_N (ival)")))
+
+(define_constraint "O"
+  "Constant in range [0, 4095]"
+  (and (match_code "const_int")
+       (match_test "CSKY_CONST_OK_FOR_O (ival)")))
+
+(define_constraint "P"
+  "Constant in range [4, 508] that is divisible by 4"
+  (and (match_code "const_int")
+       (match_test "CSKY_CONST_OK_FOR_P (ival)")))
+
+(define_constraint "T"
+  "Constant in range [-256, -1]"
+  (and (match_code "const_int")
+       (match_test "CSKY_CONST_OK_FOR_T (ival)")))
+
+(define_constraint "Ua"
+  "Constant 0"
+  (and (match_code "const_int")
+       (match_test "ival == 0")))
+
+(define_constraint "Ub"
+  "Unsigned int that is an exact power of 2"
+  (and (match_code "const_int")
+       (match_test "CSKY_CONST_OK_FOR_Ub (ival)")))
+
+(define_constraint "Uc"
+  "Unsigned int X such that X+1 is an exact power of 2"
+  (and (match_code "const_int")
+       (match_test "CSKY_CONST_OK_FOR_Uc (ival)")))
+
+(define_constraint "Ud"
+  "64-bit int whose high/low words separately satisfy I, Ub, or Uc"
+  (and (match_code "const_int")
+       (match_test "CSKY_CONST_OK_FOR_Ud (ival)")))
+
+(define_constraint "Ug"
+  "Constant in range [-508, -4] that is divisible by 4"
+  (and (match_code "const_int")
+       (match_test "CSKY_CONST_OK_FOR_Ug (ival)")))
+
+(define_constraint "Uh"
+  "Constant in range [-31, 0]"
+  (and (match_code "const_int")
+       (match_test "CSKY_CONST_OK_FOR_Uh (ival)")))
+
+(define_constraint "Uj"
+  "Constant in range [4, 1024] that is divisible by 4"
+  (and (match_code "const_int")
+       (match_test "CSKY_CONST_OK_FOR_Uj (ival)")))
+
+(define_constraint "Uk"
+  "Constant in range [1, 65536]"
+  (and (match_code "const_int")
+       (match_test "CSKY_CONST_OK_FOR_Uk (ival)")))
+
+(define_constraint "Ul"
+  "Constant in range [-1024, -4] that is divisible by 4"
+  (and (match_code "const_int")
+       (match_test "CSKY_CONST_OK_FOR_Ul (ival)")))
+
+(define_constraint "Um"
+  "Constant in range [-4096, -1]"
+  (and (match_code "const_int")
+       (match_test "CSKY_CONST_OK_FOR_Um (ival)")))
+
+(define_constraint "Un"
+  "Constant whose low 16 bits are all zeros"
+  (and (match_code "const_int")
+       (match_test "CSKY_CONST_OK_FOR_MOVIH (ival)")))
+
+(define_constraint "Uo"
+  "Constant that can be synthesized with an extra instruction"
+  (and (match_code "const_int")
+       (match_test "csky_inlinable_constant (ival)")))
+
+(define_constraint "Up"
+  "Constant in range [0, 255]"
+  (and (match_code "const_int")
+       (match_test "CSKY_CONST_OK_FOR_N (ival + 1)")))
+
+(define_constraint "Uq"
+  "Constant in range [0, 1020] that is divisible by 4"
+  (and (match_code "const_int")
+       (match_test "CSKY_CONST_OK_FOR_Uj (ival + 4)")))
+
+(define_constraint "Ur"
+  "Constant in range [-1020, -4] that is divisible by 4"
+  (and (match_code "const_int")
+       (match_test "CSKY_CONST_OK_FOR_Uj (-ival + 4)")))
+
+(define_constraint "Us"
+  "Constant in range [-8, -1]"
+  (and (match_code "const_int")
+       (match_test "CSKY_CONST_OK_FOR_US (ival)")))
diff --git a/gcc/config/csky/csky-elf.h b/gcc/config/csky/csky-elf.h
new file mode 100644 (file)
index 0000000..822caed
--- /dev/null
@@ -0,0 +1,81 @@
+/* Declarations for bare-metal C-SKY targets.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   Contributed by C-SKY Microsystems and Mentor Graphics.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+
+/******************************************************************
+ *              Run-time Target Specification                    *
+ ******************************************************************/
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC \
+  "crt0.o%s crti.o%s crtbegin.o%s"
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC "crtend.o%s crtn.o%s"
+
+#undef CC1_SPEC
+#define CC1_SPEC                \
+  "%{EB:-EB}                    \
+   %{EL:-EL}                    \
+   %{fpic|fPIC:-DPIC}           \
+   %{march=ck803s:-march=ck803}         \
+  "
+
+#undef ASM_SPEC
+#define ASM_SPEC               \
+  "%{mbig-endian:-mbig-endian} \
+  %{EB:-EB}                    \
+  %{EL:-EL}                    \
+  %{fpic|fPIC:-pic}            \
+  %{mcpu=*:-mcpu=%*}           \
+  %{march=*:-march=%*}         \
+  %{mhard-float:-mhard-float}  \
+  %{melrw:-melrw}              \
+  %{mno-elrw:-mno-elrw}                \
+  %{mistack:-mistack}          \
+  %{mno-istack:-mno-istack}    \
+  %{mmp:-mmp}                  \
+  %{mcp:-mcp}                  \
+  %{mcache:-mcache}            \
+  %{msecurity|mmac:-msecurity} \
+  %{mtrust:-mtrust}            \
+  %{mdsp:-mdsp}                        \
+  %{medsp:-medsp}              \
+  %{mvdsp:-mvdsp}              \
+  "
+
+#undef LINK_SPEC
+#define LINK_SPEC     \
+"%{mbig-endian:-EB}   \
+ %{EB:-EB}           \
+ %{EL:-EL} -X"
+
+#undef LIB_SPEC
+#define LIB_SPEC \
+  "%{pthread:-lpthread} -lc %{mccrt:-lcc-rt}"
+/* FIXME add this to LIB_SPEC when need */
+/*   %{!shared:%{profile:-lc_p}%{!profile:-lc}}" */
+
+
+#define CPLUSPLUS_CPP_SPEC "-D_GNU_SOURCE %(cpp)"
+
+/* Disable features only for Linux toolchains. */
+#undef TARGET_POSIX_IO
+#define TARGET_CSKY_LINUX 0
diff --git a/gcc/config/csky/csky-linux-elf.h b/gcc/config/csky/csky-linux-elf.h
new file mode 100644 (file)
index 0000000..19a553c
--- /dev/null
@@ -0,0 +1,132 @@
+/* Declarations for C-SKY targets running Linux.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   Contributed by C-SKY Microsystems and Mentor Graphics.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+/******************************************************************
+ *              Run-time Target Specification                    *
+ ******************************************************************/
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC                                                       \
+  "%{!shared: %{pie:Scrt1.o%s;:crt1.o%s}}                                    \
+  crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s}"
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC \
+  "%{shared|pie:crtendS.o%s;:crtend.o%s} crtn.o%s"
+
+#undef CC1_SPEC
+#define CC1_SPEC  \
+  "%{EB:-EB}     \
+   %{EL:-EL}     \
+  "
+
+#undef ASM_SPEC
+#define ASM_SPEC               \
+  "%{mbig-endian:-mbig-endian} \
+  %{EB:-EB}                    \
+  %{EL:-EL}                    \
+  %{fpic|fPIC:-pic}            \
+  %{mcpu=*:-mcpu=%*}           \
+  %{march=*:-march=%*}         \
+  %{mhard-float:-mhard-float}  \
+  %{melrw:-melrw}              \
+  %{mno-elrw:-mno-elrw}                \
+  %{mistack:-mistack}          \
+  %{mno-istack:-mno-istack}    \
+  %{mmp:-mmp}                  \
+  %{mcp:-mcp}                  \
+  %{mcache:-mcache}            \
+  %{msecurity|mmac:-msecurity} \
+  %{mtrust:-mtrust}            \
+  %{mdsp:-mdsp}                        \
+  %{medsp:-medsp}              \
+  %{mvdsp:-mvdsp}              \
+  "
+
+#define LINUX_DYNAMIC_LINKER  "/lib/ld.so.1"
+
+#define LINUX_TARGET_LINK_SPEC "%{h*} %{version:-v}            \
+   %{b}                                                                \
+   %{static:-Bstatic}                                          \
+   %{shared:-shared}                                           \
+   %{symbolic:-Bsymbolic}                                      \
+   %{!static:                                                  \
+     %{rdynamic:-export-dynamic}                               \
+     %{!shared:-dynamic-linker " LINUX_DYNAMIC_LINKER "}}      \
+   -X                                                          \
+   %{mbig-endian:-EB} %{mlittle-endian:-EL}                    \
+   %{EB:-EB} %{EL:-EL}"
+
+
+#undef LINK_SPEC
+#define LINK_SPEC LINUX_TARGET_LINK_SPEC
+
+
+#undef LIB_SPEC
+#define LIB_SPEC \
+  "%{pthread:-lpthread} -lc %{mccrt:-lcc-rt}"
+/* FIXME add this to LIB_SPEC when need */
+/*   %{!shared:%{profile:-lc_p}%{!profile:-lc}}" */
+
+#define TARGET_OS_CPP_BUILTINS()           \
+  do                                       \
+    {                                      \
+      GNU_USER_TARGET_OS_CPP_BUILTINS ();   \
+    }                                      \
+  while (0)
+
+/* In crtstuff.c to control section in where code resides.
+   We have to write it as asm code.  */
+#ifdef __PIC__
+#define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC)  \
+  asm (SECTION_OP "\n"                             \
+       "\tgrs\tr3, .Lgetpc_"#FUNC"\n\t"                    \
+       ".Lgetpc_"#FUNC":\n\t"                      \
+       "\tlrw\tr2,\t.Lgetpc_"#FUNC"@GOTPC\n\t"     \
+       "\taddu\tr3, r2\n\t"                        \
+       "\tlrw\tr2, "#FUNC"@GOTOFF\n\t"             \
+       "\taddu\tr2, r3\n\t"                        \
+       "\tjsr\tr2\n\t");                           \
+  FORCE_CODE_SECTION_ALIGN                         \
+  asm (TEXT_SECTION_ASM_OP);
+#endif
+
+#undef CPP_SPEC
+#define CPP_SPEC "%{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}"
+
+#undef FUNCTION_PROFILER
+#define SAVE_LR            \
+  "push\tlr"
+#define FUNCTION_PROFILER(file, labelno)               \
+  fprintf (file, "\t%s\n\tjbsr\t_mcount\n", SAVE_LR);
+#define NO_PROFILE_COUNTERS 1
+
+/* Enable features only for Linux toolchains.  */
+#define TARGET_CSKY_LINUX 1
+
+/* Clear the instruction cache from `BEG' to `END'.  */
+#define CLEAR_INSN_CACHE(BEG, END)                     \
+  cacheflush (BEG, END-BEG, 3)
+
+/* For __clear_cache in libgcc2.c.  The declaration is copied from
+   <sys/cachectl.h>.  */
+#ifdef IN_LIBGCC2
+extern int cacheflush (void *__addr, const int __nbytes, const int __op);
+#endif
diff --git a/gcc/config/csky/csky-protos.h b/gcc/config/csky/csky-protos.h
new file mode 100644 (file)
index 0000000..c10267a
--- /dev/null
@@ -0,0 +1,71 @@
+/* Prototype declarations for the C-SKY back end.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   Contributed by C-SKY Microsystems and Mentor Graphics.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_CSKY_PROTOS_H
+#define GCC_CSKY_PROTOS_H
+
+extern bool csky_simple_addr_operand_p (rtx);
+extern bool csky_symbolic_address_p (rtx);
+extern bool csky_legitimate_pic_operand_p (rtx);
+
+extern void csky_cpu_cpp_builtins (cpp_reader *);
+
+extern bool csky_inlinable_constant (HOST_WIDE_INT value);
+extern bool csky_shifted_imm8_constant (unsigned HOST_WIDE_INT,
+                                       unsigned int *, unsigned int *);
+extern bool csky_valid_fpuv2_mem_operand (rtx);
+
+extern bool csky_minipool_load_p (rtx_insn *);
+extern const char *csky_output_move (rtx insn, rtx *, machine_mode);
+extern const char *csky_output_movedouble (rtx *, machine_mode);
+extern const char *csky_output_ck801_move (rtx, rtx *, machine_mode);
+extern const char *csky_output_ck801_movedouble (rtx *, machine_mode);
+extern char *csky_output_call (rtx *, int);
+extern const char *csky_output_casesi (rtx *);
+
+extern bool csky_split_and (rtx *);
+extern bool csky_split_ior (rtx *);
+extern bool csky_split_xor (rtx *);
+
+#ifdef RTX_CODE
+extern bool csky_emit_compare (enum rtx_code, rtx, rtx);
+extern bool csky_emit_compare_float (enum rtx_code, rtx, rtx);
+#endif /* RTX_CODE */
+
+extern rtx csky_return_addr (int, rtx);
+extern void csky_init_expanders (void);
+extern HOST_WIDE_INT csky_initial_elimination_offset (int, int);
+extern void csky_expand_prologue (void);
+extern void csky_expand_epilogue (void);
+extern const char *csky_output_return_instruction (void);
+extern void csky_set_eh_return_address (rtx, rtx);
+
+extern bool csky_symbol_mentioned_p (rtx);
+extern bool csky_label_mentioned_p (rtx);
+extern rtx csky_legitimize_pic_address (rtx, rtx, bool);
+
+extern bool csky_tls_referenced_p (rtx);
+extern rtx csky_legitimize_tls_address (rtx, rtx);
+
+extern int csky_compute_pushpop_length (rtx *);
+
+extern int csky_default_branch_cost (bool, bool);
+extern bool csky_default_logical_op_non_short_circuit (void);
+#endif /* GCC_CSKY_PROTOS_H */
diff --git a/gcc/config/csky/csky.c b/gcc/config/csky/csky.c
new file mode 100644 (file)
index 0000000..a9e196b
--- /dev/null
@@ -0,0 +1,6795 @@
+/* GCC backend functions for C-SKY targets.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   Contributed by C-SKY Microsystems and Mentor Graphics.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#define IN_TARGET_CODE 1
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "memmodel.h"
+#include "backend.h"
+#include "target.h"
+#include "rtl.h"
+#include "tree.h"
+#include "cfghooks.h"
+#include "df.h"
+#include "tm_p.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "optabs.h"
+#include "regs.h"
+#include "emit-rtl.h"
+#include "recog.h"
+#include "cgraph.h"
+#include "c-family/c-common.h"
+#include "cpplib.h"
+#include "diagnostic-core.h"
+#include "alias.h"
+#include "fold-const.h"
+#include "stor-layout.h"
+#include "calls.h"
+#include "varasm.h"
+#include "output.h"
+#include "insn-attr.h"
+#include "flags.h"
+#include "reload.h"
+#include "explow.h"
+#include "expr.h"
+#include "cfgrtl.h"
+#include "sched-int.h"
+#include "common/common-target.h"
+#include "langhooks.h"
+#include "intl.h"
+#include "libfuncs.h"
+#include "params.h"
+#include "opts.h"
+#include "dumpfile.h"
+#include "target-globals.h"
+#include "builtins.h"
+#include "tm-constrs.h"
+#include "rtl-iter.h"
+#include "pass_manager.h"
+#include "tree-pass.h"
+#include "context.h"
+
+/* This file should be included last.  */
+#include "target-def.h"
+
+/* Stack and register size macros.  */
+
+#define CSKY_NUM_WORDS(SIZE) \
+  (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+#define CSKY_NUM_REGS(MODE) \
+  CSKY_NUM_WORDS (GET_MODE_SIZE (MODE))
+#define CSKY_STACK_ALIGN(SIZE) \
+  (CSKY_NUM_WORDS (SIZE) * UNITS_PER_WORD)
+
+/* Offsets and range macros.  */
+
+#define CSKY_LD16_MAX_OFFSET(MODE)             \
+  (31 * GET_MODE_SIZE (MODE))
+#define CSKY_LD32_MAX_OFFSET(MODE) \
+  (4095 * GET_MODE_SIZE (MODE))
+#define CSKY_LD16_OFFSET_MASK(MODE) \
+  (CSKY_LD16_MAX_OFFSET (MODE) + GET_MODE_SIZE (MODE) - 1)
+
+#define CSKY_ADDI16_MAX_IMM          256
+#define CSKY_SUBI16_MAX_IMM          256
+
+#define CSKY_CONSTPOOL_LABEL_PREFIX   "LCP"
+
+/* Array of the smallest class containing reg number REGNO, indexed by
+   REGNO.  Used by REGNO_REG_CLASS.  */
+enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER] =
+{
+  /* Registers r0-r7.  */
+  MINI_REGS,    MINI_REGS,     MINI_REGS,     MINI_REGS,
+  MINI_REGS,    MINI_REGS,     MINI_REGS,     MINI_REGS,
+  /* Registers r8-r15.  */
+  LOW_REGS,     LOW_REGS,      LOW_REGS,      LOW_REGS,
+  LOW_REGS,     LOW_REGS,      SP_REGS,       LOW_REGS,
+  /* Registers r16-r31.  */
+  GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
+  GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
+  GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
+  GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
+  /* Reserved.  */
+  RESERVE_REGS,
+  /* CC,HI,LO registers.  */
+  C_REGS,      HI_REGS,             LO_REGS,
+  /* Reserved.  */
+  RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+  RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+  RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+  RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+  /* Vec registers.  */
+  V_REGS,      V_REGS,       V_REGS,       V_REGS,
+  V_REGS,      V_REGS,       V_REGS,       V_REGS,
+  V_REGS,      V_REGS,       V_REGS,       V_REGS,
+  V_REGS,      V_REGS,       V_REGS,       V_REGS,
+  /* Reserved.  */
+  RESERVE_REGS, RESERVE_REGS,
+  /* Register epc.  */
+  OTHER_REGS
+};
+
+/* Arrays that map GCC register numbers to debugger register numbers,
+   '-1' means that is INVALID_REGNUM.
+   TODO: which rules according to here ?  */
+const int csky_dbx_regno[FIRST_PSEUDO_REGISTER] =
+{
+  0,  1,  2,  3,  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,
+  -1, -1, 36, 37, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, 56, 57, 58, 59,
+  60, 61, 62, 63, 64, 65, 66, 67,
+  68, 69, 70, 71, -1, -1, 72
+};
+
+/* Table of machine attributes.  */
+static tree csky_handle_fndecl_attribute (tree *, tree, tree, int, bool *);
+static tree csky_handle_isr_attribute (tree *, tree, tree, int, bool *);
+static const struct attribute_spec csky_attribute_table[] =
+{
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req,
+       affects_type_identity, handler, exclude } */
+  { "naked",    0, 0, true,  false, false, false, csky_handle_fndecl_attribute, NULL },
+  /* Interrupt Service Routines have special prologue and epilogue requirements.  */
+  { "interrupt", 0, 1, false, false, false, false, csky_handle_isr_attribute,   NULL },
+  { "isr",      0, 1, false, false, false, false, csky_handle_isr_attribute,    NULL },
+  { NULL,       0, 0, false, false, false, false, NULL,                         NULL }
+};
+
+/* A C structure for machine-specific, per-function data.
+   This is added to the cfun structure.  */
+typedef struct GTY(()) machine_function
+{
+  /* Records if LR has to be saved for far jumps.  */
+  int far_jump_used;
+  /* Records the type of the current function.  */
+  unsigned long func_type;
+  /* Record if the function has a variable argument list.  */
+  int uses_anonymous_args;
+
+  /* Stack frame layout information.  If frame_init_p is true,
+     these fields have been initialized and don't need to be
+     recomputed.  */
+  unsigned int reg_mask;       /* non-volatile reg saves */
+  int arg_size;                        /* stdarg spills (bytes) */
+  int reg_size;                        /* non-volatile reg saves (bytes) */
+  int local_size;              /* locals */
+  int outbound_size;           /* arg overflow on calls out */
+  int frame_size;              /* total static size of stack frame */
+  int local_offset;
+  int reg_offset;
+  int arg_offset;
+  int frame_init_p;
+
+} machine_function;
+
+/* These macros are for the func_type values above.  */
+#define CSKY_FT_TYPE_MASK   ((1 << 3) - 1)
+#define CSKY_FT_UNKNOWN            0               /* Type not been determined */
+#define CSKY_FT_NORMAL     1               /* Normal function */
+#define CSKY_FT_ISR        4               /* Interrupt service routine */
+#define CSKY_FT_FIQ        5               /* Fast interrupt service routine */
+#define CSKY_FT_EXCEPTION   6              /* Exception handler */
+#define CSKY_FT_INTERRUPT   (1 << 2)       /* overlap CSKY_FT_ISR */
+#define CSKY_FT_NAKED      (1 << 3)        /* No prologue and epilogue */
+#define CSKY_FUNCTION_TYPE(t)        ((t) & CSKY_FT_TYPE_MASK)
+#define CSKY_FUNCTION_IS_INTERRUPT(t) ((t) & CSKY_FT_INTERRUPT)
+#define CSKY_FUNCTION_IS_NAKED(t)     ((t) & CSKY_FT_NAKED)
+
+struct csky_processors
+{
+  const char *const name;
+  enum csky_processor_type core;
+  const char *arch;
+  enum csky_base_architecture base_arch;
+  enum csky_isa_feature isa_bits[CSKY_ISA_FEATURE_GET (max)];
+};
+
+static struct csky_processors all_cores[] =
+{
+#undef CSKY_CORE
+#define CSKY_CORE(NAME, CORE, X, ARCH, ISA)  \
+  {NAME, TARGET_CPU_##CORE, #ARCH, CSKY_BASE_ARCH_##ARCH, \
+  {ISA CSKY_ISA_FEATURE_GET (none)}},
+#include "csky_cores.def"
+#undef CSKY_CORE
+  {NULL, TARGET_CPU_csky_none, NULL, CSKY_BASE_ARCH_NONE, \
+  {CSKY_ISA_FEATURE_GET (none)}}
+};
+
+static struct csky_processors all_architectures[] =
+{
+#undef CSKY_ARCH
+#define CSKY_ARCH(NAME, CORE, ARCH, ISA)     \
+  {NAME, TARGET_CPU_##CORE, #ARCH, CSKY_BASE_ARCH_##ARCH,  \
+  {ISA CSKY_ISA_FEATURE_GET (none)}},
+#include "csky_cores.def"
+#undef CSKY_ARCH
+  {NULL, TARGET_CPU_csky_none, NULL, CSKY_BASE_ARCH_NONE, \
+  {CSKY_ISA_FEATURE_GET (none)}}
+};
+
+struct csky_fpu_desc
+{
+  const char *name;
+  enum csky_isa_feature isa_bits[CSKY_ISA_FEATURE_GET (max)];
+};
+
+static const struct csky_fpu_desc all_fpus[] =
+{
+#undef CSKY_FPU
+#define CSKY_FPU(NAME, CNAME, ISA) \
+  {NAME, {ISA CSKY_ISA_FEATURE_GET (none)}},
+#include "csky_cores.def"
+#undef CSKY_FPU
+};
+
+/* Active target architecture.  */
+struct csky_build_target
+{
+  /* Name of the target CPU, if known, or NULL if the target CPU was not
+     specified by the user (and inferred from the -march option).  */
+  const char *core_name;
+  /* Name of the target ARCH.  NULL if there is a selected CPU.  */
+  const char *arch_name;
+  /* Preprocessor substring (never NULL).  */
+  const char *arch_pp_name;
+  /* CPU identifier for the core we're compiling for (architecturally).  */
+  enum csky_processor_type arch_core;
+  /* The base architecture value.  */
+  enum csky_base_architecture base_arch;
+  /* Bitmap encapsulating the isa_bits for the target environment.  */
+  sbitmap isa;
+};
+
+struct csky_build_target csky_active_target;
+
+/* The following are used in the .md file as equivalents to bits.  */
+int csky_arch_isa_features[CSKY_ISA_FEATURE_GET (max)] = {0};
+
+/* The highest CSKY architecture version supported by the target.  */
+enum csky_base_architecture csky_base_arch = CSKY_TARGET_ARCH_GET (NONE);
+
+/* Forward definitions of types.  */
+typedef struct minipool_node   Mnode;
+typedef struct minipool_fixup  Mfix;
+
+static GTY(()) int tls_labelno;
+
+
+/* Maximum constant offset that can be added/subtracted from SP in a
+   single instruction.  For ck801, this is for addsp/subsp, otherwise
+   it is the range of addi/subi.  */
+#define CSKY_MAX_SP_ADJUST \
+  (CSKY_TARGET_ARCH (CK801) ? 508 : 4096)
+
+
+/* Implement TARGET_CPU_CPP_BUILTINS.  */
+
+#define builtin_define(MACRO) cpp_define (pfile, MACRO)
+
+void
+csky_cpu_cpp_builtins (cpp_reader *pfile)
+{
+  const char *arch_name = csky_active_target.arch_pp_name;
+  char *pp_name = (char *) alloca (1 + strlen (arch_name) + 4);
+  sprintf (pp_name, "__%s__", arch_name);
+  builtin_define (pp_name);
+
+  builtin_define ("__csky__=2");
+  builtin_define ("__CSKY__=2");
+  builtin_define ("__ckcore__=2");
+  builtin_define ("__CKCORE__=2");
+
+  builtin_define ("__CSKYABIV2__");
+  builtin_define ("__cskyabiv2__");
+  builtin_define ("__CSKYABI__=2");
+  builtin_define ("__cskyabi__=2");
+
+  if (TARGET_BIG_ENDIAN)
+    {
+      builtin_define ("__ckcoreBE__");
+      builtin_define ("__cskyBE__");
+      builtin_define ("__cskybe__");
+      builtin_define ("__CSKYBE__");
+    }
+  else
+    {
+      builtin_define ("__ckcoreLE__");
+      builtin_define ("__cskyLE__");
+      builtin_define ("__cskyle__");
+      builtin_define ("__CSKYLE__");
+    }
+
+  if (TARGET_HARD_FLOAT)
+    {
+      builtin_define ("__csky_hard_float__");
+      builtin_define ("__CSKY_HARD_FLOAT__");
+    }
+  else
+    {
+      builtin_define ("__csky_soft_float__");
+      builtin_define ("__CSKY_SOFT_FLOAT__");
+    }
+
+  if (CSKY_ISA_FEATURE (fpv2_sf))
+    {
+      builtin_define ("__csky_fpuv2__");
+      builtin_define ("__CSKY_FPUV2__");
+    }
+
+  if (TARGET_ELRW)
+    {
+      builtin_define ("__csky_elrw__");
+      builtin_define ("__CSKY_ELRW__");
+    }
+  if (TARGET_ISTACK)
+    {
+      builtin_define ("__csky_istack__");
+      builtin_define ("__CSKY_ISTACK__");
+    }
+  if (TARGET_MP)
+    {
+      builtin_define ("__csky_mp__");
+      builtin_define ("__CSKY_MP__");
+    }
+  if (TARGET_CP)
+    {
+      builtin_define ("__csky_cp__");
+      builtin_define ("__CSKY_CP__");
+    }
+  if (TARGET_CACHE)
+    {
+      builtin_define ("__csky_cache__");
+      builtin_define ("__CSKY_CACHE__");
+    }
+  if (TARGET_SECURITY)
+    {
+      builtin_define ("__csky_security__");
+      builtin_define ("__CSKY_SECURITY__");
+    }
+  if (TARGET_TRUST)
+    {
+      builtin_define ("__csky_trust__");
+      builtin_define ("__CSKY_TRUST__");
+    }
+  if (TARGET_DSP)
+    {
+      builtin_define ("__csky_dsp__");
+      builtin_define ("__CSKY_DSP__");
+    }
+  if (TARGET_EDSP)
+    {
+      builtin_define ("__csky_edsp__");
+      builtin_define ("__CSKY_EDSP__");
+    }
+  if (TARGET_VDSP)
+    {
+      builtin_define ("__csky_vdsp__");
+      builtin_define ("__CSKY_VDSP__");
+    }
+}
+
+
+/******************************************************************
+ *                        Storage Layout                         *
+ ******************************************************************/
+
+
+#undef TARGET_PROMOTE_FUNCTION_MODE
+#define TARGET_PROMOTE_FUNCTION_MODE \
+  default_promote_function_mode_always_promote
+
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT csky_constant_alignment
+
+
+/******************************************************************
+ *             Stack Layout and Calling Conventions              *
+ ******************************************************************/
+
+#undef TARGET_CAN_ELIMINATE
+#define TARGET_CAN_ELIMINATE csky_can_eliminate
+
+#undef TARGET_FUNCTION_ARG
+#define TARGET_FUNCTION_ARG csky_function_arg
+
+#undef TARGET_FUNCTION_ARG_ADVANCE
+#define TARGET_FUNCTION_ARG_ADVANCE csky_function_arg_advance
+
+#undef TARGET_FUNCTION_VALUE
+#define TARGET_FUNCTION_VALUE csky_function_value
+
+#undef TARGET_LIBCALL_VALUE
+#define TARGET_LIBCALL_VALUE csky_libcall_value
+
+#undef TARGET_FUNCTION_VALUE_REGNO_P
+#define TARGET_FUNCTION_VALUE_REGNO_P csky_function_value_regno_p
+
+#undef TARGET_SPLIT_COMPLEX_ARG
+#define TARGET_SPLIT_COMPLEX_ARG hook_bool_const_tree_true
+
+#undef TARGET_PROMOTE_PROTOTYPES
+#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_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 csky_arg_partial_bytes
+
+#undef TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE hook_pass_by_reference_must_pass_in_stack
+
+#undef TARGET_ASM_OUTPUT_MI_THUNK
+#define TARGET_ASM_OUTPUT_MI_THUNK csky_output_mi_thunk
+
+#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
+#define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
+  hook_bool_const_tree_hwi_hwi_const_tree_true
+
+#undef TARGET_ASM_FUNCTION_PROLOGUE
+#define TARGET_ASM_FUNCTION_PROLOGUE csky_output_function_prologue
+
+#undef TARGET_ASM_FUNCTION_EPILOGUE
+#define TARGET_ASM_FUNCTION_EPILOGUE csky_output_function_epilogue
+
+#undef TARGET_WARN_FUNC_RETURN
+#define TARGET_WARN_FUNC_RETURN csky_warn_func_return
+
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY csky_return_in_memory
+
+
+/******************************************************************
+ *               Implementing the Varargs Macros                 *
+ ******************************************************************/
+
+
+#undef TARGET_SETUP_INCOMING_VARARGS
+#define TARGET_SETUP_INCOMING_VARARGS csky_setup_incoming_varargs
+
+
+/******************************************************************
+ *              Implicit Calls to Library Routines               *
+ ******************************************************************/
+
+
+#undef TARGET_INIT_LIBFUNCS
+#define TARGET_INIT_LIBFUNCS csky_init_libfuncs
+
+
+/******************************************************************
+ *    Dividing the Output into Sections (Texts, Data, . . . )    *
+ ******************************************************************/
+
+
+#undef TARGET_HAVE_TLS
+#define TARGET_HAVE_TLS TARGET_CSKY_LINUX
+
+
+/******************************************************************
+ *        Defining target-specific uses of __attribute__         *
+ ******************************************************************/
+
+
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE csky_attribute_table
+
+#undef TARGET_OPTION_OVERRIDE
+#define TARGET_OPTION_OVERRIDE csky_option_override
+
+
+/* Implement the BRANCH_COST target macro.  */
+
+int
+csky_default_branch_cost (bool speed_p ATTRIBUTE_UNUSED,
+                         bool predictable_p ATTRIBUTE_UNUSED)
+{
+  return csky_branch_cost;
+}
+
+bool
+csky_default_logical_op_non_short_circuit (void)
+{
+  return BRANCH_COST (optimize_function_for_speed_p (cfun), false) >= 2;
+}
+
+/******************************************************************
+ *                        Register Usage                         *
+ ******************************************************************/
+
+#undef TARGET_HARD_REGNO_NREGS
+#define TARGET_HARD_REGNO_NREGS csky_hard_regno_nregs
+
+#undef TARGET_HARD_REGNO_MODE_OK
+#define TARGET_HARD_REGNO_MODE_OK csky_hard_regno_mode_ok
+
+#undef TARGET_MODES_TIEABLE_P
+#define TARGET_MODES_TIEABLE_P csky_modes_tieable_p
+
+#undef TARGET_CAN_CHANGE_MODE_CLASS
+#define TARGET_CAN_CHANGE_MODE_CLASS csky_can_change_mode_class
+
+#undef TARGET_CONDITIONAL_REGISTER_USAGE
+#define TARGET_CONDITIONAL_REGISTER_USAGE csky_conditional_register_usage
+
+#undef TARGET_CLASS_LIKELY_SPILLED_P
+#define TARGET_CLASS_LIKELY_SPILLED_P csky_class_likely_spilled_p
+
+#undef TARGET_PREFERRED_RELOAD_CLASS
+#define TARGET_PREFERRED_RELOAD_CLASS csky_preferred_reload_class
+
+#undef TARGET_CLASS_MAX_NREGS
+#define TARGET_CLASS_MAX_NREGS csky_class_max_nregs
+
+#undef TARGET_SECONDARY_RELOAD
+#define TARGET_SECONDARY_RELOAD         csky_secondary_reload
+
+#undef TARGET_SPILL_CLASS
+#define TARGET_SPILL_CLASS csky_spill_class
+
+
+/******************************************************************
+ *                       Addressing Modes                        *
+ ******************************************************************/
+
+
+#undef TARGET_CANNOT_FORCE_CONST_MEM
+#define TARGET_CANNOT_FORCE_CONST_MEM csky_cannot_force_const_mem
+
+#undef TARGET_LEGITIMATE_CONSTANT_P
+#define TARGET_LEGITIMATE_CONSTANT_P csky_legitimate_constant_p
+
+#undef TARGET_LEGITIMIZE_ADDRESS
+#define TARGET_LEGITIMIZE_ADDRESS csky_legitimize_address
+
+#undef TARGET_LEGITIMATE_ADDRESS_P
+#define TARGET_LEGITIMATE_ADDRESS_P csky_legitimate_address_p
+
+
+/******************************************************************
+ *                            Others                             *
+ ******************************************************************/
+
+
+#undef TARGET_CANNOT_COPY_INSN_P
+#define TARGET_CANNOT_COPY_INSN_P csky_cannot_copy_insn_p
+
+
+/******************************************************************
+ *                     Assembler Format                          *
+ ******************************************************************/
+
+
+#undef TARGET_PRINT_OPERAND
+#define TARGET_PRINT_OPERAND csky_print_operand
+
+#undef TARGET_PRINT_OPERAND_ADDRESS
+#define TARGET_PRINT_OPERAND_ADDRESS csky_print_operand_address
+
+#undef TARGET_ASM_UNALIGNED_HI_OP
+#define TARGET_ASM_UNALIGNED_HI_OP "\t.short\t"
+
+#undef TARGET_ASM_UNALIGNED_SI_OP
+#define TARGET_ASM_UNALIGNED_SI_OP "\t.long\t"
+
+#undef TARGET_DWARF_REGISTER_SPAN
+#define TARGET_DWARF_REGISTER_SPAN csky_dwarf_register_span
+
+
+/******************************************************************
+ *                   Miscellaneous Parameters                    *
+ ******************************************************************/
+
+
+#undef TARGET_MACHINE_DEPENDENT_REORG
+#define TARGET_MACHINE_DEPENDENT_REORG csky_reorg
+
+#undef TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS
+#define TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS csky_allocate_stack_slots_for_args
+
+#undef TARGET_HAVE_SPECULATION_SAFE_VALUE
+#define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed
+
+
+/******************************************************************
+ *               Trampolines for Nested Functions                *
+ ******************************************************************/
+
+
+#undef TARGET_ASM_TRAMPOLINE_TEMPLATE
+#define TARGET_ASM_TRAMPOLINE_TEMPLATE csky_asm_trampoline_template
+#undef TARGET_TRAMPOLINE_INIT
+#define TARGET_TRAMPOLINE_INIT         csky_trampoline_init
+
+/* The low bit is ignored by jsr and jmp instructions so is safe to use.  */
+#undef TARGET_CUSTOM_FUNCTION_DESCRIPTORS
+#define TARGET_CUSTOM_FUNCTION_DESCRIPTORS 1
+
+/******************************************************************
+ *           Describing Relative Costs of Operations             *
+ ******************************************************************/
+
+
+#undef TARGET_REGISTER_MOVE_COST
+#define TARGET_REGISTER_MOVE_COST csky_register_move_cost
+
+#undef TARGET_MEMORY_MOVE_COST
+#define TARGET_MEMORY_MOVE_COST          csky_memory_move_cost
+
+#undef TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS         csky_rtx_costs
+
+#undef TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST      csky_address_cost
+
+
+/******************************************************************
+ *                       Anchor address                          *
+ ******************************************************************/
+
+
+/* FIXME: the max offset is related to mode size, the following is
+   defined according to SImode. How to deal with HImode and
+   QImode, and should the min offset be defined?  */
+#undef TARGET_MAX_ANCHOR_OFFSET
+#define TARGET_MAX_ANCHOR_OFFSET \
+  ((TARGET_MINI_REGISTERS && optimize_size) ? 127 : 4095)
+
+
+/******************************************************************
+ *                    Condition Code Status                      *
+ ******************************************************************/
+
+
+#undef TARGET_FIXED_CONDITION_CODE_REGS
+#define TARGET_FIXED_CONDITION_CODE_REGS csky_fixed_condition_code_regs
+
+
+/******************************************************************
+ *          Adjusting the Instruction Scheduler                  *
+ ******************************************************************/
+
+
+#undef TARGET_SCHED_ISSUE_RATE
+#define TARGET_SCHED_ISSUE_RATE csky_sched_issue_rate
+
+#undef TARGET_SCHED_ADJUST_COST
+#define         TARGET_SCHED_ADJUST_COST csky_sched_adjust_cost
+
+
+/* The declaration of functions.  */
+static void push_csky_minipool_fix (rtx_insn *, HOST_WIDE_INT, rtx *,
+                                   machine_mode, rtx);
+static void csky_print_operand (FILE *stream, rtx x, int code);
+
+
+/* Define a table to map ISR attribute arguments onto function type
+   modifiers.  */
+
+typedef struct
+{
+  const char *const arg;
+  const unsigned long return_value;
+} isr_attribute_entry;
+
+static const isr_attribute_entry isr_attribute_map[] =
+{
+  {"irq", CSKY_FT_ISR },
+  {"IRQ", CSKY_FT_ISR },
+  {"fiq", CSKY_FT_FIQ },
+  {"FIQ", CSKY_FT_FIQ },
+  {NULL, CSKY_FT_NORMAL }
+};
+
+
+/* Return the function type of the current function, if it has not been
+   determined, return CSKY_FT_UNKNOWN.  */
+
+static unsigned long
+get_csky_isr_type (tree argument)
+{
+  const isr_attribute_entry *ptr;
+  const char *arg;
+
+  /* if argument is NULL, set default value ISR.  */
+  if (argument == NULL_TREE)
+    return CSKY_FT_ISR;
+
+  if (TREE_VALUE (argument) == NULL_TREE
+     || TREE_CODE (TREE_VALUE (argument)) != STRING_CST)
+    return CSKY_FT_UNKNOWN;
+
+  arg = TREE_STRING_POINTER (TREE_VALUE (argument));
+
+  for (ptr = isr_attribute_map; ptr->arg != NULL; ptr++)
+    if (strcmp (arg, ptr->arg) == 0)
+      return ptr->return_value;
+
+  return CSKY_FT_UNKNOWN;
+}
+
+/* Classify cfun as a normal function or some sort of interrupt
+   handler, and set the corresponding bits in cfun->machine->func_type.  */
+
+static unsigned long
+get_csky_current_func_type (void)
+{
+  if (CSKY_FUNCTION_TYPE (cfun->machine->func_type) == CSKY_FT_UNKNOWN)
+    {
+      unsigned long type = CSKY_FT_UNKNOWN;
+      tree a;
+      tree attr;
+
+      gcc_assert (TREE_CODE (current_function_decl) == FUNCTION_DECL);
+
+      attr = DECL_ATTRIBUTES (current_function_decl);
+      a = lookup_attribute ("naked", attr);
+      if (a != NULL_TREE)
+       type |= CSKY_FT_NAKED;
+      a = lookup_attribute ("isr", attr);
+      if (a == NULL_TREE)
+       a = lookup_attribute ("interrupt", attr);
+      if (a == NULL_TREE)
+       type |= CSKY_FT_NORMAL;
+      else
+       type |= get_csky_isr_type (TREE_VALUE (a));
+
+      cfun->machine->func_type = type;
+    }
+
+  return cfun->machine->func_type;
+}
+
+/* These typedefs are located at the start of this file, so that
+   they can be used in the prototypes there.  This comment is to
+   remind readers of that fact so that the following structures
+   can be understood more easily.
+
+     typedef struct minipool_node    Mnode;
+     typedef struct minipool_fixup   Mfix;  */
+
+struct minipool_node
+{
+  /* Doubly linked chain of entries.  */
+  Mnode *next;
+  Mnode *prev;
+  /* The maximum offset into the code that this entry can be placed.  While
+     pushing fixes for forward references, all entries are sorted in order
+     of increasing max_address.  */
+  HOST_WIDE_INT max_address;
+  /* Similarly for an entry inserted for a backwards ref.  */
+  HOST_WIDE_INT min_address;
+  /* The number of fixes referencing this entry.  This can become zero
+     if we "unpush" an entry.  In this case we ignore the entry when we
+     come to emit the code.  */
+  int refcount;
+  /* The offset from the start of the minipool.  */
+  HOST_WIDE_INT offset;
+  /* The value in table.  */
+  rtx value;
+  /* The mode of value.  */
+  machine_mode mode;
+  /* The size of the value.  */
+  int fix_size;
+};
+
+struct minipool_fixup
+{
+  Mfix *next;
+  rtx_insn *insn;
+  HOST_WIDE_INT address;
+  rtx *loc;
+  machine_mode mode;
+  int fix_size;
+  rtx value;
+  Mnode *minipool;
+  HOST_WIDE_INT forwards;
+  HOST_WIDE_INT backwards;
+};
+
+static Mnode *minipool_vector_head;
+static Mnode *minipool_vector_tail;
+static rtx  minipool_vector_label;
+static HOST_WIDE_INT constpool_label_no = 0;
+
+/* Obstack for minipool constant handling.  */
+static struct obstack minipool_obstack;
+static char *minipool_startobj;
+/* The linked list of all minipool fixes required for this function.  */
+Mfix *minipool_fix_head;
+Mfix *minipool_fix_tail;
+/* The fix entry for the current minipool, once it has been placed.  */
+Mfix *minipool_barrier;
+
+/* Allow GC scanning of the minipool obstack.  */
+static void
+csky_add_gc_roots (void)
+{
+  gcc_obstack_init (&minipool_obstack);
+  minipool_startobj = (char *) obstack_alloc (&minipool_obstack, 0);
+}
+
+/* Implement TARGET_CONSTANT_ALIGNMENT.
+   Make strings word-aligned so strcpy from constants will be faster.  */
+static HOST_WIDE_INT
+csky_constant_alignment (const_tree exp, HOST_WIDE_INT align)
+{
+  if (TREE_CODE (exp) == STRING_CST
+      && !optimize_size
+      && align < BITS_PER_WORD)
+    return BITS_PER_WORD;
+  return align;
+}
+
+/* Record that there is a natural barrier in the insn stream at
+   ADDRESS.  */
+
+static void
+push_csky_minipool_barrier (rtx_insn *insn, HOST_WIDE_INT address)
+{
+  Mfix *fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (*fix));
+
+  fix->insn = insn;
+  fix->address = address;
+
+  fix->next = NULL;
+  if (minipool_fix_head != NULL)
+    minipool_fix_tail->next = fix;
+  else
+    minipool_fix_head = fix;
+
+  minipool_fix_tail = fix;
+}
+
+/* Compute the size of a vector jump table.  */
+
+static HOST_WIDE_INT
+get_csky_jump_table_size (rtx insn)
+{
+  /* ADDR_VECs only take room if read-only data does into the text
+     section.  */
+  if (JUMP_TABLES_IN_TEXT_SECTION || readonly_data_section == text_section)
+    {
+      rtx body = PATTERN (insn);
+      int elt = GET_CODE (body) == ADDR_DIFF_VEC ? 1 : 0;
+      HOST_WIDE_INT size;
+      HOST_WIDE_INT modesize;
+
+      modesize = GET_MODE_SIZE (GET_MODE (body));
+      size = modesize * XVECLEN (body, elt);
+      switch (modesize)
+       {
+       case 1:
+         /* Round up size  of TBB table to a halfword boundary.  */
+         size = (size + 1) & ~(HOST_WIDE_INT)1;
+         break;
+       case 2:
+         /* No padding necessary for TBH.  */
+         break;
+       case 4:
+         break;
+       default:
+         gcc_unreachable ();
+       }
+      return size;
+    }
+
+  return 0;
+}
+
+
+/* Scan INSN and note any of its operands that need fixing.
+   If DO_PUSHES is false we do not actually push any of the fixups
+   needed.  The function returns TRUE if any fixups were needed/pushed.  */
+
+static bool
+note_csky_invalid_constants (rtx_insn *insn, HOST_WIDE_INT address,
+                            int do_pushes)
+{
+  bool result = false;
+  int opno;
+
+  extract_constrain_insn (insn);
+
+  if (recog_data.n_alternatives == 0)
+    return false;
+
+  /* Fill in recog_op_alt with information about the constraints of
+     this insn.  */
+  preprocess_constraints (insn);
+
+  const operand_alternative *op_alt = which_op_alt ();
+  for (opno = 0; opno < recog_data.n_operands; opno++)
+    {
+      /* Things we need to fix can only occur in inputs.  */
+      if (recog_data.operand_type[opno] != OP_IN)
+       continue;
+
+      /* If this alternative is a memory reference, then any mention
+        of constants in this alternative is really to fool reload
+        into allowing us to accept one there.  We need to fix them up
+        now so that we output the right code.  */
+      if (op_alt[opno].memory_ok)
+       {
+         rtx op = recog_data.operand[opno];
+
+         if (CONSTANT_P (op))
+           {
+             if (do_pushes)
+               push_csky_minipool_fix (insn, address,
+                                       recog_data.operand_loc[opno],
+                                       recog_data.operand_mode[opno], op);
+             result = true;
+           }
+       }
+    }
+
+  return result;
+}
+
+
+/* Add a constant to the minipool for a forward reference.  Returns the
+   node added or NULL if the constant will not fit in this pool.  */
+
+static Mnode *
+add_csky_minipool_forward_ref (Mfix *fix)
+{
+  /* If set, max_mp is the first pool_entry that has a lower
+     constraint than the one we are trying to add.  */
+  Mnode *max_mp = NULL;
+  HOST_WIDE_INT max_address = fix->address + fix->forwards;
+  Mnode *mp;
+
+  /* If the minipool starts before the end of FIX->INSN then this FIX
+     can not be placed into the current pool.  Furthermore, adding the
+     new constant pool entry may cause the pool to start FIX_SIZE bytes
+     earlier.  */
+  if (minipool_vector_head
+      && (fix->address + get_attr_length (fix->insn)
+         >= minipool_vector_head->max_address - fix->fix_size))
+    return NULL;
+
+  /* Scan the pool to see if a constant with the same value has
+     already been added.  While we are doing this, also note the
+     location where we must insert the constant if it doesn't already
+     exist.  */
+  for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
+    {
+      if (GET_CODE (fix->value) == GET_CODE (mp->value)
+         && fix->mode == mp->mode
+         && (GET_CODE (fix->value) != CODE_LABEL
+             || (CODE_LABEL_NUMBER (fix->value)
+                 == CODE_LABEL_NUMBER (mp->value)))
+         && rtx_equal_p (fix->value, mp->value))
+       {
+         /* More than one fix references this entry.  */
+         mp->refcount++;
+         return mp;
+       }
+
+      /* Note the insertion point if necessary.  */
+      if (max_mp == NULL && mp->max_address > max_address)
+       max_mp = mp;
+    }
+
+  /* The value is not currently in the minipool, so we need to create
+     a new entry for it.  If MAX_MP is NULL, the entry will be put on
+     the end of the list since the placement is less constrained than
+     any existing entry.  Otherwise, we insert the new fix before
+     MAX_MP and, if necessary, adjust the constraints on the other
+     entries.  */
+  mp = XNEW (Mnode);
+  mp->fix_size = fix->fix_size;
+  mp->mode = fix->mode;
+  mp->value = fix->value;
+  mp->refcount = 1;
+  /* Not yet required for a backwards ref.  */
+  mp->min_address = -65536;
+
+  if (max_mp == NULL)
+    {
+      mp->max_address = max_address;
+      mp->next = NULL;
+      mp->prev = minipool_vector_tail;
+
+      if (mp->prev == NULL)
+       {
+         minipool_vector_head = mp;
+         minipool_vector_label
+           = gen_csky_constpool_label (gen_rtx_CONST_INT (VOIDmode,
+                                                          constpool_label_no++));
+       }
+      else
+       mp->prev->next = mp;
+
+      minipool_vector_tail = mp;
+    }
+  else
+    {
+      if (max_address > max_mp->max_address - mp->fix_size)
+       mp->max_address = max_mp->max_address - mp->fix_size;
+      else
+       mp->max_address = max_address;
+
+      mp->next = max_mp;
+      mp->prev = max_mp->prev;
+      max_mp->prev = mp;
+      if (mp->prev != NULL)
+       mp->prev->next = mp;
+      else
+       minipool_vector_head = mp;
+    }
+
+  /* Save the new entry.  */
+  max_mp = mp;
+
+  /* Scan over the preceding entries and adjust their addresses as
+     required.  */
+  while (mp->prev != NULL
+        && mp->prev->max_address > mp->max_address - mp->prev->fix_size)
+    {
+      mp->prev->max_address = mp->max_address - mp->prev->fix_size;
+      mp = mp->prev;
+    }
+
+  return max_mp;
+}
+
+
+/* Return the cost of forcibly inserting a barrier after INSN.  */
+
+static int
+get_csky_barrier_cost (rtx_insn *insn)
+{
+  /* Basing the location of the pool on the loop depth is preferable,
+     but at the moment, the basic block information seems to be
+     corrupt by this stage of the compilation.  */
+  int base_cost = 50;
+  rtx next = next_nonnote_insn (insn);
+
+  if (next != NULL && GET_CODE (next) == CODE_LABEL)
+    base_cost -= 20;
+
+  switch (GET_CODE (insn))
+    {
+    case CODE_LABEL:
+      /* It will always be better to place the table before the label, rather
+     than after it.  */
+      return 50;
+
+    case INSN:
+    case CALL_INSN:
+      return base_cost;
+
+    case JUMP_INSN:
+      return base_cost - 10;
+
+    default:
+      return base_cost + 10;
+    }
+}
+
+
+/* Find the best place in the insn stream in the range
+   (FIX->address,MAX_ADDRESS) to forcibly insert a minipool barrier.
+   Create the barrier by inserting a jump and add a new fix entry for
+   it.  */
+static Mfix *
+create_csky_fix_barrier (Mfix *fix, Mfix *fix_next,
+                        HOST_WIDE_INT max_address)
+{
+  rtx_barrier *barrier;
+  rtx_insn *from = (fix ? fix->insn : get_insns ());
+  /* The instruction after which we will insert the jump.  */
+  rtx_insn *selected = NULL;
+  int selected_cost;
+  /* The address at which the jump instruction will be placed.  */
+  HOST_WIDE_INT selected_address = 0;
+  Mfix *new_fix;
+  HOST_WIDE_INT count = (fix ? fix->address : 0);
+  HOST_WIDE_INT max_count = max_address;
+  rtx_code_label *label = gen_label_rtx ();
+
+  selected_cost = get_csky_barrier_cost (from);
+
+  while (from && count < max_count)
+    {
+      int new_cost;
+      rtx_jump_table_data *table;
+
+      /* Count the length of this insn.  */
+      count += get_attr_length (from);
+
+      /* If there is a jump table, add its length.  */
+      if (tablejump_p (from, NULL, &table))
+       {
+         count += get_csky_jump_table_size (table);
+
+         /* Jump tables aren't in a basic block, so base the cost on
+            the dispatch insn.  If we select this location, we will
+            still put the pool after the table.  */
+         new_cost = get_csky_barrier_cost (from);
+
+         if (count < max_count
+             && (!selected || new_cost <= selected_cost))
+           {
+             selected = table;
+             selected_cost = new_cost;
+             selected_address = count;
+           }
+
+         /* Continue after the dispatch table.  */
+         from = NEXT_INSN (table);
+         continue;
+       }
+
+      new_cost = get_csky_barrier_cost (from);
+
+      if (count < max_count
+         && (!selected || new_cost <= selected_cost))
+       {
+         selected = from;
+         selected_cost = new_cost;
+         selected_address = count;
+       }
+
+      from = NEXT_INSN (from);
+    }
+
+  /* Make sure that we found a place to insert the jump.  */
+  gcc_assert (selected);
+
+  /* Create a new JUMP_INSN that branches around a barrier.  */
+  from = emit_jump_insn_after (gen_jump (label), selected);
+  JUMP_LABEL (from) = label;
+  barrier = emit_barrier_after (from);
+  emit_label_after (label, barrier);
+
+  /* Create a minipool barrier entry for the new barrier.  */
+  new_fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* new_fix));
+  new_fix->insn = barrier;
+  new_fix->address = selected_address;
+  if (fix)
+    {
+      new_fix->next = fix->next;
+      fix->next = new_fix;
+    }
+  else
+    new_fix->next = fix_next;
+
+  return new_fix;
+}
+
+
+/* Print a symbolic form of the constant X to the dump file F.
+   This is used for dump output for -mconstpool in the target-dependent
+   reorg pass.  */
+
+static void
+print_csky_value (FILE *f, rtx x)
+{
+  switch (GET_CODE (x))
+    {
+    case CONST_INT:
+      fprintf (f, HOST_WIDE_INT_PRINT_HEX, INTVAL (x));
+      return;
+
+    case CONST_DOUBLE:
+      fprintf (f, "<0x%lx,0x%lx>", (long)XWINT (x, 2), (long)XWINT (x, 3));
+      return;
+
+    case CONST_VECTOR:
+      {
+       int i;
+
+       fprintf (f, "<");
+       for (i = 0; i < CONST_VECTOR_NUNITS (x); i++)
+         {
+           fprintf (f, HOST_WIDE_INT_PRINT_HEX,
+                    INTVAL (CONST_VECTOR_ELT (x, i)));
+           if (i < (CONST_VECTOR_NUNITS (x) - 1))
+             fputc (',', f);
+         }
+       fprintf (f, ">");
+      }
+      return;
+
+    case CONST_STRING:
+      fprintf (f, "\"%s\"", XSTR (x, 0));
+      return;
+
+    case SYMBOL_REF:
+      fprintf (f, "`%s'", XSTR (x, 0));
+      return;
+
+    case LABEL_REF:
+      fprintf (f, "L%d", INSN_UID (XEXP (x, 0)));
+      return;
+
+    case CONST:
+      print_csky_value (f, XEXP (x, 0));
+      return;
+
+    case PLUS:
+      print_csky_value (f, XEXP (x, 0));
+      fprintf (f, "+");
+      print_csky_value (f, XEXP (x, 1));
+      return;
+
+    case PC:
+      fprintf (f, "pc");
+      return;
+
+    default:
+      fprintf (f, "????");
+      return;
+    }
+}
+
+
+/* Record INSN, which will need fixing up to load a value from the
+   minipool.  ADDRESS is the offset of the insn since the start of the
+   function; LOC is a pointer to the part of the insn which requires
+   fixing; VALUE is the constant that must be loaded, which is of type
+   MODE.  */
+
+static void
+push_csky_minipool_fix (rtx_insn *insn, HOST_WIDE_INT address, rtx *loc,
+                       machine_mode mode, rtx value)
+{
+  #define CSKY_ELRW16_RANGE  1400
+  #define CSKY_LRW16_RANGE   700
+  #define CSKY_CONSTANT_POOL_RANGE (TARGET_ELRW ? CSKY_ELRW16_RANGE \
+                                               : CSKY_LRW16_RANGE)
+
+  /* Fixes less than a word need padding out to a word boundary.  */
+  #define CSKY_MINIPOOL_FIX_SIZE(mode) \
+    (GET_MODE_SIZE ((mode)) >= 4 ? GET_MODE_SIZE ((mode)) : 4)
+
+  Mfix *fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (*fix));
+
+  fix->insn = insn;
+  fix->address = address;
+  fix->loc = loc;
+  fix->mode = mode;
+  fix->fix_size = CSKY_MINIPOOL_FIX_SIZE (mode);
+  fix->value = value;
+  fix->forwards = CSKY_CONSTANT_POOL_RANGE;
+  fix->backwards = 0;
+  fix->minipool = NULL;
+
+  /* If an insn doesn't have a range defined for it, then it isn't
+     expecting to be reworked by this code.  Better to stop now than
+     to generate duff assembly code.  */
+  gcc_assert (fix->forwards || fix->backwards);
+
+  if (dump_file)
+    {
+      fprintf (dump_file,
+              ";; %smode fixup for i%d; addr %lu, range (%ld,%ld): ",
+              GET_MODE_NAME (mode),
+              INSN_UID (insn), (unsigned long) address,
+              -1 * (long)fix->backwards, (long)fix->forwards);
+      print_csky_value (dump_file, fix->value);
+      fprintf (dump_file, "\n");
+    }
+
+  /* Add it to the chain of fixes.  */
+  fix->next = NULL;
+
+  if (minipool_fix_head != NULL)
+    minipool_fix_tail->next = fix;
+  else
+    minipool_fix_head = fix;
+
+  minipool_fix_tail = fix;
+}
+
+
+/* Fill in the offsets for minipool entries.  */
+
+static void
+assign_csky_minipool_offsets (Mfix *barrier)
+{
+  HOST_WIDE_INT offset = 0;
+  Mnode *mp;
+
+  minipool_barrier = barrier;
+
+  for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
+    {
+      mp->offset = offset;
+
+      if (mp->refcount > 0)
+       offset += mp->fix_size;
+    }
+}
+
+
+/* Output the literal table.  */
+
+static HOST_WIDE_INT
+dump_csky_minipool (rtx_insn *scan)
+{
+  Mnode *mp;
+  Mnode *nmp;
+  HOST_WIDE_INT pool_length = 0;
+
+  if (dump_file)
+    fprintf (dump_file,
+            ";; Emitting minipool after insn %u;\
+             address %ld; align %d (bytes)\n",
+            INSN_UID (scan), (unsigned long) minipool_barrier->address, 4);
+
+  scan = emit_insn_after (gen_align_4 (), scan);
+  scan = emit_insn_after (minipool_vector_label, scan);
+
+  for (mp = minipool_vector_head; mp != NULL; mp = nmp)
+    {
+      if (mp->refcount > 0)
+       {
+         if (dump_file)
+           {
+             fprintf (dump_file, ";;  Offset %u, min %ld, max %ld ",
+                      (unsigned) mp->offset, (unsigned long) mp->min_address,
+                      (unsigned long) mp->max_address);
+             print_csky_value (dump_file, mp->value);
+             fputc ('\n', dump_file);
+           }
+
+         switch (mp->fix_size)
+           {
+           case 4:
+             scan = emit_insn_after (gen_consttable_4 (mp->value), scan);
+             pool_length += 4;
+             break;
+           case 8:
+             scan = emit_insn_after (gen_consttable_8 (mp->value), scan);
+             pool_length += 8;
+             break;
+           default:
+             gcc_unreachable ();
+           }
+       }
+
+      nmp = mp->next;
+      free (mp);
+    }
+
+  minipool_vector_head = minipool_vector_tail = NULL;
+  scan = emit_barrier_after (scan);
+
+  return pool_length;
+}
+
+/* Return true if INSN is a minipool load or instruction that will be
+   converted to one.  It is assumed that INSN has type attribute "load".  */
+
+bool
+csky_minipool_load_p (rtx_insn *insn)
+{
+  rtx op1, addr;
+
+  extract_insn_cached (insn);
+
+  op1 = recog_data.operand[1];
+
+  /* This is a constant that has not yet been turned into
+     a minipool load.  */
+  if (CONSTANT_P (op1))
+    return true;
+
+  /* Constant pool loads are label_refs.  */
+  if (GET_CODE (op1) == ZERO_EXTEND || GET_CODE (op1) == SIGN_EXTEND)
+    op1 = XEXP (op1, 0);
+  if (GET_CODE (op1) != MEM)
+    return false;
+  addr = XEXP (op1, 0);
+  if (GET_CODE (addr) == PLUS && CONST_INT_P (XEXP (addr, 1)))
+    addr = XEXP (addr, 0);
+  return GET_CODE (addr) == LABEL_REF;
+}
+
+
+/* Compute the attribute "length" of push or pop insn, according to
+   the registers it uses.  */
+
+int
+csky_compute_pushpop_length (rtx *operands)
+{
+  rtx parallel_op = operands[2];
+  /* Initialize to elements number of PARALLEL.  */
+  unsigned indx = XVECLEN (parallel_op, 0) - 1;
+  unsigned first_indx = 0;
+  unsigned regno = REGNO (operands[1]);
+
+  if (regno > CSKY_LR_REGNUM)
+    return 4;
+
+  /* Check each register in the list.  */
+  for (; indx > first_indx; indx--)
+    {
+      regno = REGNO (XEXP (XVECEXP (parallel_op, 0, indx), 0));
+      /* If a register number higher than 15 is included, a 32-bit insn
+        is used.  */
+      if (regno > CSKY_LR_REGNUM)
+       return 4;
+    }
+
+  return 2;
+}
+
+/* Emit constant pools for -mconstpool.  */
+static void
+csky_emit_constant_pools (void)
+{
+    rtx_insn *insn;
+    HOST_WIDE_INT address = 0;
+    Mfix *fix;
+
+    minipool_fix_head = minipool_fix_tail = NULL;
+
+    /* The first insn must always be a note, or the code below won't
+       scan it properly.  */
+    insn = get_insns ();
+    gcc_assert (NOTE_P (insn));
+
+    /* Scan the insns and record the operands that need fixing.  */
+    for (insn = next_nonnote_insn (insn); insn;
+        insn = next_nonnote_insn (insn))
+      {
+       if (BARRIER_P (insn))
+         push_csky_minipool_barrier (insn, address);
+       else if (INSN_P (insn))
+         {
+           rtx_jump_table_data *table;
+
+           note_csky_invalid_constants (insn, address, true);
+           address += get_attr_length (insn);
+
+           /* If the insn is a vector jump, add the size of the table
+            and skip the table.  */
+           if (tablejump_p (insn, NULL, &table))
+             {
+               address += get_csky_jump_table_size (table);
+               insn = table;
+             }
+         }
+      }
+
+    fix = minipool_fix_head;
+
+    /* Now scan the fixups and perform the required changes.  */
+    while (fix)
+      {
+       Mfix *ftmp;
+       Mfix *last_added_fix;
+       Mfix *last_barrier = NULL;
+       Mfix *this_fix;
+       Mnode *mp;
+       bool has_pending_const = false;
+
+       /* Check if there is any pending constant not processed.  */
+       for (mp = minipool_vector_head; mp; mp = mp->next)
+         if (mp->refcount > 0)
+           {
+             has_pending_const = true;
+             break;
+           }
+
+       /* If no pending constant, skip over barrier insns.  */
+       if (has_pending_const == false)
+         {
+           while (fix && BARRIER_P (fix->insn))
+             fix = fix->next;
+           if (fix == NULL)
+             break;
+         }
+
+       last_added_fix = NULL;
+
+       for (ftmp = fix; ftmp; ftmp = ftmp->next)
+         {
+           if (BARRIER_P (ftmp->insn))
+             {
+               if (minipool_vector_head
+                   && ftmp->address >= minipool_vector_head->max_address)
+                 break;
+
+               last_barrier = ftmp;
+             }
+           else
+             {
+               ftmp->minipool = add_csky_minipool_forward_ref (ftmp);
+               if (ftmp->minipool == NULL)
+                 break;
+             }
+           last_added_fix = ftmp;  /* Keep track of the last fix added.  */
+         }
+
+       /* If the last added fix is a barrier, dump minipool after it.  */
+       if (last_added_fix && BARRIER_P (last_added_fix->insn))
+         ftmp = last_barrier;
+       else
+         {
+           /* ftmp is first fix that we can't fit into this pool.
+              Insert a new barrier in the code somewhere between the previous
+              fix and this one, and arrange to jump around it.  */
+           HOST_WIDE_INT max_address;
+
+           /* The last item on the list of fixes must be a barrier, so
+              we can never run off the end of the list of fixes without
+              last_barrier being set.  */
+           gcc_assert (ftmp);
+
+           /* Check that there isn't another fix that is in range that
+              we couldn't fit into this pool because the pool was
+              already too large: we need to put the pool before such an
+              instruction.  The pool itself may come just after the
+              fix because create_csky_fix_barrier also allows space for a
+              jump instruction.  */
+           max_address = minipool_vector_head->max_address;
+           if (ftmp->address < max_address)
+             max_address = ftmp->address + 1;
+           last_barrier = create_csky_fix_barrier (last_added_fix, ftmp,
+                                                   max_address);
+         }
+
+       assign_csky_minipool_offsets (last_barrier);
+
+       /* Scan over the fixes we have identified for this pool, fixing them
+          up and adding the constants to the pool itself.  */
+       for (this_fix = fix; this_fix && ftmp != this_fix;
+            this_fix = this_fix->next)
+         {
+           if (GET_CODE (this_fix->insn) != BARRIER)
+             {
+               rtx addr
+                 = plus_constant (Pmode,
+                                  gen_rtx_LABEL_REF (VOIDmode,
+                                                     minipool_vector_label),
+                                  this_fix->minipool->offset);
+               rtx insn_body = PATTERN (this_fix->insn);
+               rtx src = XEXP (insn_body, 1);
+               *this_fix->loc = gen_rtx_MEM (this_fix->mode, addr);
+               if (GET_CODE (this_fix->value) == SYMBOL_REF)
+                 emit_insn_after (gen_rtx_UNSPEC_VOLATILE (VOIDmode,
+                                                           gen_rtvec (1, src),
+                                                           VUNSPEC_SYMBOL_REF),
+                                  this_fix->insn);
+             }
+         }
+       dump_csky_minipool (last_barrier->insn);
+       fix = ftmp;
+       if (fix->next == NULL)
+         break;
+      }
+
+    /* Free the minipool memory.  */
+    obstack_free (&minipool_obstack, minipool_startobj);
+}
+
+
+/* Implement TARGET_MACHINE_DEPENDENT_REORG.  This handles
+   -mconstpool output.  */
+
+static void
+csky_reorg (void)
+{
+  if (TARGET_CONSTANT_POOL)
+    csky_emit_constant_pools ();
+}
+
+
+/* Check to see if the current function contains a branch insn with the
+   far jump attribute set.  Such a function uses the LR register.  */
+
+static bool
+csky_far_jump_used_p (void)
+{
+  rtx_insn *insn;
+  if (cfun->machine->far_jump_used)
+    return true;
+
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    if (GET_CODE (insn) == JUMP_INSN
+       /* Ignore tablejump patterns.  */
+       && GET_CODE (PATTERN (insn)) != ADDR_VEC
+       && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC
+       && get_attr_far_jump (insn) == FAR_JUMP_YES)
+      {
+       cfun->machine->far_jump_used = 1;
+       return true;
+      }
+  return false;
+}
+
+
+/* Return the mask of registers used by the current function.  Set
+   COUNT to the number of registers used.  */
+
+static unsigned int
+get_csky_live_regs (int *count)
+{
+  int reg;
+  unsigned int live_regs_mask = 0;
+
+  *count = 0;
+  for (reg = 0; reg < CSKY_NGPR_REGS; reg++)
+    {
+      bool save = false;
+
+      /* Ignore unsupported registers.  */
+      if (CSKY_TARGET_ARCH (CK801) && reg > 8 && reg < 13)
+       continue;
+      if ((CSKY_TARGET_ARCH (CK801)
+          || CSKY_TARGET_ARCH (CK802)
+          || CSKY_TARGET_ARCH (CK803))
+         && reg > 15)
+       break;
+
+      /* Caller-saved registers marked as used.  */
+      if (df_regs_ever_live_p (reg) && !call_really_used_regs[reg])
+       save = true;
+
+      /* Frame pointer marked used.  */
+      else if (frame_pointer_needed && reg == FRAME_POINTER_REGNUM)
+       save = true;
+
+      /* This is required for CK801/802 where FP is a fixed reg, otherwise
+        we end up with no FP value available to the DWARF-2 unwinder.  */
+      else if (crtl->calls_eh_return && reg == FRAME_POINTER_REGNUM)
+       save = true;
+
+      /* CK801/802 also need special handling for LR because it's clobbered
+        by far jumps.  */
+      else if ((CSKY_TARGET_ARCH (CK801) || CSKY_TARGET_ARCH (CK802))
+              && reg == CSKY_LR_REGNUM
+              && (!crtl->is_leaf || csky_far_jump_used_p ()))
+       save = true;
+
+      /* Register is used for EH data return.  */
+      else if (crtl->calls_eh_return
+              && reg >= CSKY_FIRST_EH_RETDATA_REGNUM
+              && reg <= CSKY_LAST_EH_RETDATA_REGNUM)
+       save = true;
+
+      /* We need a temporary reg to hold the offset for adjusting the SP
+        for a large stack frame.  */
+      if (reg == CSKY_STACKADJUST_REGNUM
+         && cfun->machine->reg_offset > CSKY_MAX_SP_ADJUST * 2)
+       save = true;
+
+      /* Add reg to the mask.  */
+      if (save)
+       {
+         (*count)++;
+         live_regs_mask |= (1 << reg);
+       }
+    }
+  return live_regs_mask;
+}
+
+/* Compute the stack frame layout, storing sizes of the various pieces
+   in cfun->machine.
+
+   Stack frames constructed in the prologue look like:
+                       ... caller's frame ...
+       incoming SP ->  caller's outbound argument overflow
+                       argument spill
+       optional FP ->  register save
+                       local variables
+                       alloca() space
+       adjusted SP ->  outbound argument overflow
+
+   with SP/FP pointing at the base (low address) of the respective area,
+   and each area aligned to a word boundary.  */
+
+static void
+csky_layout_stack_frame (void)
+{
+  machine_function *infp = cfun->machine;
+  int reg_count;
+
+  if (infp->frame_init_p)
+    return;
+
+  /* Get sizes of local variables & outbound arguments.  */
+  infp->outbound_size = CSKY_STACK_ALIGN (crtl->outgoing_args_size);
+  infp->local_offset = infp->outbound_size;
+  infp->local_size = CSKY_STACK_ALIGN (get_frame_size ());
+  infp->reg_offset = infp->local_offset + infp->local_size;
+
+  /* Now compute size of argument spill + saved regs.  These do not
+     need explicit alignment since they are already word-sized.  */
+  infp->reg_mask = get_csky_live_regs (&reg_count);
+  infp->reg_size = reg_count * UNITS_PER_WORD;
+  infp->arg_offset = infp->reg_offset + infp->reg_size;
+  infp->arg_size = crtl->args.pretend_args_size;
+  infp->frame_size = infp->arg_offset + infp->arg_size;
+  infp->frame_init_p = reload_completed;
+}
+
+/* Implement TARGET_CAN_ELIMINATE.  */
+static bool
+csky_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
+{
+  if (to == STACK_POINTER_REGNUM)
+    return !frame_pointer_needed;
+  return true;
+}
+
+/* Worker function for INITIAL_ELIMINATION_OFFSET macro.
+   Define the offset between two registers, one to be eliminated, and
+   the other its replacement, at the start of a routine.  */
+
+HOST_WIDE_INT
+csky_initial_elimination_offset (int from, int to)
+{
+  int offset;
+
+  csky_layout_stack_frame ();
+
+  /* Set OFFSET to the offset to the initial stack pointer.  */
+  switch (from)
+    {
+    case FRAME_POINTER_REGNUM:
+      offset = cfun->machine->reg_offset;
+      break;
+
+    case ARG_POINTER_REGNUM:
+      offset = cfun->machine->arg_offset;
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  /* If we are asked for the offset to the frame pointer instead,
+     then subtract the difference between the frame pointer and stack
+     pointer.  */
+  if (to == FRAME_POINTER_REGNUM)
+    offset -= cfun->machine->reg_offset;
+  return offset;
+}
+
+
+/* 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).  */
+static rtx
+csky_function_arg (cumulative_args_t pcum_v, machine_mode mode,
+                  const_tree type ATTRIBUTE_UNUSED,
+                  bool named ATTRIBUTE_UNUSED)
+{
+  CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v);
+
+  if (*pcum < CSKY_NPARM_REGS)
+    return gen_rtx_REG (mode, CSKY_FIRST_PARM_REGNUM + *pcum);
+
+  return NULL_RTX;
+}
+
+
+/* Return the number of registers (words) needed to pass an argument of
+   MODE and TYPE.  */
+
+static int
+csky_num_arg_regs (machine_mode mode, const_tree type)
+{
+  int size;
+
+  if (type && mode == BLKmode)
+    size = int_size_in_bytes (type);
+  else
+    size = GET_MODE_SIZE (mode);
+
+  return CSKY_NUM_WORDS (size);
+}
+
+
+/* Implement TARGET_FUNCTION_ARG_ADVANCE.  */
+
+static void
+csky_function_arg_advance (cumulative_args_t pcum_v, machine_mode mode,
+                          const_tree type, bool named ATTRIBUTE_UNUSED)
+{
+  CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v);
+  int param_size = csky_num_arg_regs (mode, type);
+
+  if (*pcum + param_size > CSKY_NPARM_REGS)
+    *pcum = CSKY_NPARM_REGS;
+  else
+    *pcum += param_size;
+}
+
+
+/* Implement TARGET_FUNCTION_VALUE.  */
+static rtx
+csky_function_value (const_tree type, const_tree func,
+                    bool outgoing ATTRIBUTE_UNUSED)
+{
+  machine_mode mode;
+  int unsignedp ATTRIBUTE_UNUSED;
+  int size;
+
+  mode = TYPE_MODE (type);
+  size = int_size_in_bytes (type);
+
+  /* Since we promote return types, we must promote the mode here too.  */
+  if (INTEGRAL_TYPE_P (type))
+    {
+      mode = promote_function_mode (type, mode, &unsignedp, func, 1);
+      return gen_rtx_REG (mode, CSKY_FIRST_RET_REGNUM);
+    }
+
+  if (mode == BLKmode && size > UNITS_PER_WORD
+      && size <= UNITS_PER_WORD * 2)
+    {
+      rtx ret_regs[2];
+      ret_regs[0] = gen_rtx_EXPR_LIST (SImode,
+                                      gen_rtx_REG (SImode,
+                                                   CSKY_FIRST_RET_REGNUM),
+                                      GEN_INT (0 * UNITS_PER_WORD));
+      ret_regs[1] = gen_rtx_EXPR_LIST (SImode,
+                                      gen_rtx_REG (SImode,
+                                                   CSKY_FIRST_RET_REGNUM + 1),
+                                      GEN_INT (1 * UNITS_PER_WORD));
+
+      rtvec vec = gen_rtvec (2, ret_regs[0], ret_regs[1]);
+
+      return gen_rtx_PARALLEL (mode, vec);
+    }
+
+    return gen_rtx_REG (mode, CSKY_FIRST_RET_REGNUM);
+}
+
+
+/* Implement TARGET_LIBCALL_VALUE.  */
+static rtx
+csky_libcall_value (machine_mode mode,
+                   const_rtx libcall ATTRIBUTE_UNUSED)
+{
+  return gen_rtx_REG (mode, CSKY_FIRST_RET_REGNUM);
+}
+
+
+/* Implement TARGET_FUNCTION_VALUE_REGNO_P.
+   On C-SKY, only r0 can return results.  */
+
+static bool
+csky_function_value_regno_p (const unsigned int regno)
+{
+  return (regno == CSKY_FIRST_RET_REGNUM);
+}
+
+
+/* Return an RTX indicating where the return address to the
+   calling function can be found.  */
+rtx
+csky_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
+{
+  if (count != 0)
+    return NULL_RTX;
+
+  return get_hard_reg_initial_val (Pmode, CSKY_LR_REGNUM);
+}
+
+
+/* Implement TARGET_ARG_PARTIAL_BYTES.
+   Return the number of bytes at the beginning of an argument
+   that must be put in registers. The value must be zero for arguments
+   that are passed entirely in registers or
+   that are entirely pushed on the stack.  */
+static int
+csky_arg_partial_bytes (cumulative_args_t pcum_v, machine_mode mode,
+                       tree type, bool named ATTRIBUTE_UNUSED)
+{
+  CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v);
+  int param_size = csky_num_arg_regs (mode, type);
+
+  if (*pcum < CSKY_NPARM_REGS
+      && *pcum + param_size > CSKY_NPARM_REGS)
+    return (CSKY_NPARM_REGS - *pcum) * UNITS_PER_WORD;
+
+  return 0;
+}
+
+
+/* Implement TARGET_SETUP_INCOMING_VARARGS.
+   On C-Sky the copy from the argument registers to the stack is emitted
+   by the prologue hooks, so here we just have to note how much stack space
+   to save.  */
+
+static void
+csky_setup_incoming_varargs (cumulative_args_t pcum_v,
+                            machine_mode mode,
+                            tree type,
+                            int *pretend_size,
+                            int second_time ATTRIBUTE_UNUSED)
+{
+  CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v);
+  CUMULATIVE_ARGS local_cum;
+  cumulative_args_t local_cum_v = pack_cumulative_args (&local_cum);
+  int regs_to_push;
+
+  cfun->machine->uses_anonymous_args = 1;
+  local_cum = *pcum;
+  csky_function_arg_advance (local_cum_v, mode, type, true);
+  regs_to_push = CSKY_NPARM_REGS - local_cum;
+  if (regs_to_push)
+    *pretend_size  = regs_to_push * UNITS_PER_WORD;
+}
+
+
+/* Implement TARGET_ASM_OUTPUT_MI_THUNK.
+   Output code to add DELTA to the first argument, and then jump
+   to FUNCTION.  Used for C++ multiple inheritance.  */
+
+static void
+csky_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
+                     HOST_WIDE_INT delta,
+                     HOST_WIDE_INT vcall_offset,
+                     tree function)
+{
+  const char *thiz = "a0";
+  const char *reg0 = "t0";
+  const char *reg1 = "t1";
+  int maxoff = 4096;           /* Constant range for addi/subi.  */
+
+  final_start_function (emit_barrier (), file, 1);
+
+  rtx fnaddr = XEXP (DECL_RTL (function), 0);
+
+  if (CSKY_TARGET_ARCH (CK801))
+    {
+      /* CK801 can't use t registers and has only 16-bit addi/subi.  */
+      reg0 = "l0";
+      reg1 = "l1";
+      maxoff = 256;
+      if (vcall_offset > maxoff || vcall_offset < -maxoff)
+       fprintf (file, "\tpush\tl0, l1\n");
+      else if (delta > maxoff || delta < -maxoff)
+       fprintf (file, "\tpush\tl0\n");
+    }
+
+  if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
+    thiz = "a1";
+
+  /* Add delta to this_rtx.  */
+  if (delta != 0)
+    {
+      if (delta > maxoff || delta < -maxoff)
+       {
+         fprintf (file, "\tlrw\t%s, %ld\n", reg0, (long)delta);
+         fprintf (file, "\taddu\t%s, %s, %s\n", thiz, thiz, reg0);
+       }
+      else
+       fprintf (file, "\t%s\t%s, %s, %ld\n",
+                (delta > 0 ? "addi" : "subi"), thiz, thiz,
+                (long)(delta > 0 ? delta : -delta));
+    }
+
+  /* If needed, add *(*this_rtx + vcall_offset) to this_rtx.  */
+  if (vcall_offset != 0)
+    {
+      fprintf (file, "\tld.w\t%s, (%s, 0)\n", reg0, thiz);
+
+      if (vcall_offset > maxoff || vcall_offset < -maxoff)
+       {
+         fprintf (file, "\tlrw\t%s, %ld\n", reg1, (long)vcall_offset);
+         fprintf (file, "\taddu\t%s, %s, %s\n", reg0, reg0, reg1);
+       }
+      else
+       fprintf (file, "\t%s\t%s, %s, %ld\n",
+                (vcall_offset > 0 ? "addi" : "subi"), reg0, reg0,
+                (long)(vcall_offset > 0 ? vcall_offset : -vcall_offset));
+
+      /* Load the offset and add it to this_rtx         */
+      fprintf (file, "\tld.w\t%s, (%s, 0)\n", reg0, reg0);
+      fprintf (file, "\taddu\t%s, %s, %s\n", thiz, thiz, reg0);
+    }
+
+  /* We must pop the scratch regs individually instead of using the
+     "pop" insn, which also does a return.  */
+  if (CSKY_TARGET_ARCH (CK801))
+    {
+      if (vcall_offset > maxoff || vcall_offset < -maxoff)
+       {
+         fprintf (file, "\tld.w\tl0, (sp, 0)\n");
+         fprintf (file, "\tld.w\tl1, (sp, 4)\n");
+         fprintf (file, "\taddi\t sp, sp, 8\n");
+       }
+      else if (delta > maxoff || delta < -maxoff)
+       {
+         fprintf (file, "\tld.w\tl0, (sp, 0)\n");
+         fprintf (file, "\taddi\tsp, sp, 4\n");
+       }
+    }
+
+  fprintf (file, "\tjbr\t");
+  output_addr_const (file, fnaddr);
+  fprintf (file, "\n");
+
+  final_end_function ();
+}
+
+
+/* Implement TARGET_CONDITIONAL_REGISTER_USAGE.
+   Conditionally modify five variables fixed_regs, call_used_regs, global_regs,
+   reg_names, and reg_class_contents, to take into account any dependence of
+   these register sets on target flags.
+
+   CK801 has registers r0-r8 and r13-r15.  CK802 and CK803 have registers
+   r0-r15 (the "low" registers).  Other cpus use registers r0-r31 with
+   -mhigh-registers, otherwise also only r0-r15.
+
+   CK801 only has 16-bit instructions, most of which can only reference
+   r0-r7 (the "mini" registers).  So we mark regs outside that range as
+   fixed.  -msmart can be used on other arch variants to force the same
+   behavior because it results in smaller code size.
+
+   TODO: investigate whether it's beneficial to use r8-r13 as a spill
+   class when TARGET_MINI_REGISTERS instead of making them unusable by
+   the register allocator.  */
+
+static void
+csky_conditional_register_usage (void)
+{
+  /* Only use mini registers in smart mode or 801.  */
+  if (TARGET_MINI_REGISTERS)
+    {
+      int i;
+
+      for (i = (CSKY_LAST_MINI_REGNUM + 1); i < 32; i++)
+       {
+         fixed_regs[i] = 1;
+         call_used_regs[i] = 1;
+         call_really_used_regs[i] = 1;
+       }
+    }
+  /* For some targets, the high registers are not supported.
+     CPUs other than ck801/ck802/ck803 use high registers
+     depending on -mhigh-registers option.  */
+  else if (CSKY_TARGET_ARCH (CK802)
+          || CSKY_TARGET_ARCH (CK803)
+          || !TARGET_HIGH_REGISTERS)
+   {
+      int i;
+
+      for (i = CSKY_FIRST_HIGH_REGNUM; i <= CSKY_LAST_HIGH_REGNUM; i++)
+       {
+         fixed_regs[i] = 1;
+         call_used_regs[i] = 1;
+         call_really_used_regs[i] = 1;
+       }
+   }
+
+  /* On CK801/CK802 we must mark lr as a fixed register because it is
+     used to implement far jumps.
+     FIXME: perhaps there should be a command-line option controlling
+     use of lr for far jumps on ck802 when !TARGET_MINI_REGS, when
+     you really want lr to be available to the register allocator and
+     you know there are no far jumps in the code.  */
+  if (CSKY_TARGET_ARCH (CK801) || CSKY_TARGET_ARCH (CK802))
+    {
+      fixed_regs[CSKY_LR_REGNUM] = 1;
+      call_used_regs[CSKY_LR_REGNUM] = 1;
+      call_really_used_regs[CSKY_LR_REGNUM] = 0;
+    }
+
+  /* The hi/lo registers are only supported in dsp mode.  */
+  if (!TARGET_DSP)
+    {
+      fixed_regs[CSKY_HI_REGNUM] = 1;
+      call_used_regs[CSKY_HI_REGNUM] = 1;
+      call_really_used_regs[CSKY_HI_REGNUM] = 1;
+
+      fixed_regs[CSKY_LO_REGNUM] = 1;
+      call_used_regs[CSKY_LO_REGNUM] = 1;
+      call_really_used_regs[CSKY_LO_REGNUM] = 1;
+    }
+
+  /* The V_REGS are only supported in hard float mode.  */
+  if (!TARGET_HARD_FLOAT)
+    {
+      int regno;
+
+      for (regno = CSKY_FIRST_VFP_REGNUM;
+          regno <= CSKY_LAST_VFP_REGNUM; regno++)
+       {
+         fixed_regs[regno] = 1;
+         call_used_regs[regno] = 1;
+         call_really_used_regs[regno] = 1;
+       }
+    }
+
+  /* In pic mode, the gb register is not available for register
+     allocation.  Since gb is not clobbered by function
+     calls, set its call_really_used_regs to 0.  */
+  if (flag_pic)
+    {
+      fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
+      call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
+      call_really_used_regs[PIC_OFFSET_TABLE_REGNUM] = 0;
+    }
+}
+
+/* Implement TARGET_HARD_REGNO_NREGS.  */
+static unsigned int
+csky_hard_regno_nregs (unsigned int regno, machine_mode mode)
+{
+  if (regno >= CSKY_FIRST_VFP_REGNUM && !CSKY_TARGET_ARCH (CK803))
+    return 1;
+  else
+    return CSKY_NUM_REGS (mode);
+}
+
+/* Implement TARGET_HARD_REGNO_MODE_OK.  Return true if REGNO is a
+   valid register for holding a quantity of type MODE.  */
+
+static bool
+csky_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
+{
+  int nregs = CSKY_NUM_REGS (mode);
+
+  /* We can't handle more than doubleword sizes for any register.  */
+  if (nregs > 2)
+    return false;
+
+  /* For general registers, return true if mode is one word size.
+     When the size is larger than one word size, there should
+     be two successive hard registers to put the data.  */
+  if (regno < CSKY_NGPR_REGS)
+    {
+      if (nregs < 2)
+       return true;
+      else if (TARGET_MINI_REGISTERS)
+       return (regno < CSKY_LAST_MINI_REGNUM);
+      else if (CSKY_TARGET_ARCH (CK802)
+              || CSKY_TARGET_ARCH (CK803)
+              || !TARGET_HIGH_REGISTERS)
+       /* Without high register, r15 cannot hold doubleword data.  */
+       return (regno < (CSKY_SP_REGNUM - 1));
+      else
+       return (regno < (CSKY_SP_REGNUM - 1)
+               || (regno >= CSKY_LR_REGNUM
+                   && regno < CSKY_LAST_HIGH_UNFIXED_REGNUM));
+    }
+  else if (regno == CSKY_CC_REGNUM)
+    return (mode == CCmode);
+  else if (regno == CSKY_HI_REGNUM || regno == CSKY_LO_REGNUM)
+    {
+      /* Don't allocate hi,lo register for float data even
+        if in dsp mode, because it will cause high cost
+        to reload data from hi,lo register.  */
+      if (!TARGET_DSP || mode == SFmode || mode == DFmode)
+       return false;
+      else if (nregs == 2)
+       return (regno == CSKY_HI_REGNUM);
+      else
+       return true;
+    }
+  else if (CSKY_VREG_P (regno) && TARGET_HARD_FLOAT)
+    return true;
+
+  return false;
+}
+
+/* Implement TARGET_MODES_TIEABLE_P.  We can't tie DFmode with other modes
+   when V_REGs might be in use because those registers mess with the stored
+   bits.  */
+static bool
+csky_modes_tieable_p (machine_mode mode1, machine_mode mode2)
+{
+  return !(TARGET_HARD_FLOAT
+          && mode1 != mode2
+          && (mode1 == DFmode || mode2 == DFmode));
+}
+
+/* Implement TARGET_CAN_CHANGE_MODE_CLASS.
+   V_REG registers can't do subreg as all values are reformatted to
+   internal precision.  */
+static bool
+csky_can_change_mode_class (machine_mode from,
+                           machine_mode to,
+                           reg_class_t rclass)
+{
+  return (GET_MODE_SIZE (from) == GET_MODE_SIZE (to)
+         || !reg_classes_intersect_p (V_REGS, rclass));
+}
+
+/* Implement TARGET_CLASS_LIKELY_SPILLED_P.
+   We need to define this for MINI_REGS when we only use r0 - r7.
+   Otherwise we can end up using r0-r4 for function arguments, and don't
+   have enough left over to do doubleword arithmetic.  */
+
+static bool
+csky_class_likely_spilled_p (reg_class_t rclass)
+{
+  if ((TARGET_MINI_REGISTERS && rclass == MINI_REGS)
+      || rclass == C_REGS)
+    return true;
+
+  return false;
+}
+
+
+/* Implement TARGET_PREFERRED_RELOAD_CLASS.
+   Given an rtx X being reloaded into a reg required to be
+   in class CLASS, return the class of reg to actually use.
+   In general this is just CLASS.  */
+
+static reg_class_t
+csky_preferred_reload_class (rtx x, reg_class_t rclass)
+{
+  if (TARGET_HARD_FLOAT
+      && CONST_DOUBLE_P (x)
+      && (GET_MODE (x) == DFmode || GET_MODE (x) == SFmode)
+      && rclass == NO_REGS)
+    return GENERAL_REGS;
+  return rclass;
+}
+
+
+/* Implement TARGET_CLASS_MAX_NREGS.
+   Return the maximum number of consecutive registers of class rclass needed
+   to hold a value of mode mode.
+   On the csky, this is the size of MODE in words,
+   except in the FP regs, where a single reg is always enough.  */
+
+static unsigned char
+csky_class_max_nregs (reg_class_t rclass, machine_mode mode)
+{
+  if (rclass == V_REGS)
+    return 1;
+  else
+    return CSKY_NUM_REGS (mode);
+}
+
+
+/* Implement TARGET_SECONDARY_RELOAD.
+   If copying a register of RCLASS from/to X requires an intermediate
+   register, the hook should return the REGISTER_CLASS required for this
+   intermediate register.
+   If no intermediate register is required, it should return NO_REGS.
+   If more than one intermediate register is required, describe the one
+   that is closest in the copy chain to the reload register.  */
+
+reg_class_t
+csky_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x,
+                      reg_class_t rclass,
+                      machine_mode mode,
+                      secondary_reload_info *sri ATTRIBUTE_UNUSED)
+{
+  int regno = -1;
+
+  /* Extract the real regno from X.  */
+  if (GET_CODE (x) == SIGN_EXTEND)
+    {
+      int off = 0;
+
+      x = XEXP (x, 0);
+
+      if (reg_renumber)
+       regno = true_regnum (x);
+      else
+       {
+         while (GET_CODE (x) == SUBREG)
+           {
+             off += subreg_regno_offset (REGNO (SUBREG_REG (x)),
+             GET_MODE (SUBREG_REG (x)),
+             SUBREG_BYTE (x), GET_MODE (x));
+             x = SUBREG_REG (x);
+           }
+
+           if (GET_CODE (x) == REG)
+             regno = REGNO (x) + off;
+       }
+    }
+  else if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG)
+    regno = true_regnum (x);
+
+  /* We always require a general register when copying anything to
+     HI/LO_REGNUM, except when copying an SImode value from HI/LO_REGNUM
+     to a general register, or when copying from register 0.  */
+  if ((rclass == HILO_REGS || rclass == LO_REGS || rclass == HI_REGS)
+      && !CSKY_GENERAL_REGNO_P (regno))
+    return GENERAL_REGS;
+
+  if (rclass == V_REGS && !CSKY_GENERAL_REGNO_P (regno))
+    {
+      /* Reload between vector reg and memory does not need an
+        intermediate register.  */
+      if (MEM_P (x) && (mode == SFmode || mode == DFmode))
+       return NO_REGS;
+      else
+       return GENERAL_REGS;
+    }
+
+  return NO_REGS;
+}
+
+/* Implement TARGET_SPILL_CLASS.
+   Try spilling to a larger register class before spilling to memory.  */
+
+static reg_class_t
+csky_spill_class (reg_class_t rclass, machine_mode mode ATTRIBUTE_UNUSED)
+{
+  if ((rclass == MINI_REGS && !TARGET_MINI_REGISTERS)
+      || (rclass == LOW_REGS && TARGET_HIGH_REGISTERS))
+    return GENERAL_REGS;
+  return NO_REGS;
+}
+
+/* Convert a static initializer array of feature bits to sbitmap
+   representation.  */
+static void
+csky_initialize_isa (sbitmap isa, const enum csky_isa_feature *isa_bits)
+{
+  bitmap_clear (isa);
+  while (*isa_bits != CSKY_ISA_FEATURE_GET (none))
+    bitmap_set_bit (isa, *(isa_bits++));
+}
+
+
+/* Configure a build target TARGET from the user-specified options OPTS and
+   OPTS_SET.  */
+static void
+csky_configure_build_target (struct csky_build_target *target,
+                            struct cl_target_option *opts,
+                            struct gcc_options *opts_set)
+{
+  const struct csky_processors *csky_selected_tune = NULL;
+  struct csky_processors *csky_selected_cpu = NULL;
+  struct csky_processors *csky_selected_arch = NULL;
+  sbitmap all_sbits = sbitmap_alloc (CSKY_ISA_FEATURE_GET (max));
+  bitmap_clear (all_sbits);
+
+  bitmap_clear (target->isa);
+  target->core_name = NULL;
+  target->arch_name = NULL;
+
+  if (opts_set->x_csky_arch_option)
+    csky_selected_arch = &all_architectures[opts->x_csky_arch_option];
+
+  if (opts_set->x_csky_cpu_option)
+    {
+      csky_selected_cpu = &all_cores[opts->x_csky_cpu_option];
+      csky_selected_tune = &all_cores[opts->x_csky_cpu_option];
+    }
+
+  if (csky_selected_cpu)
+    {
+      /* TODO: support combination of features
+        between different cpu & arch, should based on arch.  */
+      if (csky_selected_arch
+         && (csky_selected_cpu->base_arch != csky_selected_arch->base_arch))
+       warning (0, "cpu %s is not based on arch %s, ignoring the arch",
+                csky_selected_cpu->name, csky_selected_arch->name);
+      if (!csky_selected_arch)
+       csky_selected_arch = &all_architectures[csky_selected_cpu->base_arch];
+      csky_initialize_isa (all_sbits, csky_selected_arch->isa_bits);
+      target->core_name = csky_selected_cpu->name;
+    }
+  else if (csky_selected_arch)
+    {
+      csky_selected_cpu = csky_selected_arch;
+      target->arch_name = csky_selected_arch->name;
+    }
+  else /* If the user did not specify a processor, choose one for them.  */
+    {
+      csky_selected_cpu = &all_cores[TARGET_CPU_DEFAULT];
+      csky_selected_arch = &all_architectures[csky_selected_cpu->base_arch];
+      csky_initialize_isa (all_sbits, csky_selected_arch->isa_bits);
+      target->core_name = csky_selected_cpu->name;
+    }
+
+  /* The selected cpu may be an architecture, so lookup tuning by core ID.  */
+  if (!csky_selected_tune)
+    csky_selected_tune = &all_cores[csky_selected_cpu->core];
+  gcc_assert (csky_selected_tune);
+
+  gcc_assert (csky_selected_arch);
+  gcc_assert (csky_selected_cpu);
+  csky_initialize_isa (target->isa, csky_selected_cpu->isa_bits);
+  bitmap_ior (target->isa, target->isa, all_sbits);
+
+  /* Finish initializing the target structure.  */
+  target->arch_pp_name = csky_selected_cpu->arch;
+  target->base_arch = csky_selected_cpu->base_arch;
+  target->arch_core = csky_selected_cpu->core;
+
+  sbitmap_free (all_sbits);
+}
+
+
+/* Implement TARGET_OPTION_OVERRIDE.  */
+
+static void
+csky_option_override (void)
+{
+  csky_active_target.isa = sbitmap_alloc (CSKY_ISA_FEATURE_GET (max));
+
+  /* Create the default target_options structure.  We need this early
+     to configure the overall build target.  */
+  target_option_default_node = target_option_current_node
+                            = build_target_option_node (&global_options);
+
+  csky_configure_build_target (&csky_active_target,
+                             TREE_TARGET_OPTION (target_option_default_node),
+                             &global_options_set);
+
+#ifdef SUBTARGET_OVERRIDE_OPTIONS
+  SUBTARGET_OVERRIDE_OPTIONS;
+#endif
+
+  csky_base_arch = csky_active_target.base_arch;
+
+  if (flag_pic && !(CSKY_TARGET_ARCH (CK810) || CSKY_TARGET_ARCH (CK807)))
+    {
+      flag_pic = 0;
+      warning (0, "%qs is not supported by arch %s",
+              "-fPIC", csky_active_target.arch_pp_name);
+    }
+
+  /* Check floating-point options for consistency.  */
+  if (TARGET_HARD_FLOAT)
+    {
+      const struct csky_fpu_desc *csky_selected_fpu = NULL;
+
+      if (csky_fpu_index == TARGET_FPU_auto)
+       {
+         const char *target_fpu_name;
+         bool ok;
+         int fpu_index;
+
+#ifdef CSKY_FPUTYPE_DEFAULT
+         target_fpu_name = CSKY_FPUTYPE_DEFAULT;
+#else
+         target_fpu_name = "fpv2";
+#endif
+
+         if (csky_active_target.core_name != NULL
+             && !strchr (csky_active_target.core_name, 'f'))
+           target_fpu_name = "auto";
+         else if (CSKY_TARGET_ARCH (CK803) || !TARGET_DOUBLE_FLOAT)
+           target_fpu_name = "fpv2_sf";
+         else if (TARGET_DOUBLE_FLOAT && TARGET_FDIVDU)
+           target_fpu_name = "fpv2_divd";
+
+         ok = opt_enum_arg_to_value (OPT_mfpu_, target_fpu_name, &fpu_index,
+                                     CL_TARGET);
+         gcc_assert (ok);
+         csky_fpu_index = (enum csky_fpu_type) fpu_index;
+       }
+
+      if (CSKY_TARGET_ARCH (CK801) || CSKY_TARGET_ARCH (CK802))
+       error ("%qs is not supported by arch %s",
+              "-mhard-float", csky_active_target.arch_pp_name);
+      else if (csky_fpu_index == TARGET_FPU_auto)
+       error ("%<-mhard-float%> is not supported by the selected CPU");
+      else
+       {
+         csky_selected_fpu = &all_fpus[csky_fpu_index];
+         sbitmap fpu_bits = sbitmap_alloc (CSKY_ISA_FEATURE_GET (max));
+         csky_initialize_isa (fpu_bits, csky_selected_fpu->isa_bits);
+
+         bitmap_ior (csky_active_target.isa, csky_active_target.isa,
+                     fpu_bits);
+
+         sbitmap_free (fpu_bits);
+       }
+    }
+  else
+    {
+      if (TARGET_DOUBLE_FLOAT > 0)
+       warning (0, "%<-mdouble-float%> ignored without %<-mhard-float%>");
+      TARGET_DOUBLE_FLOAT = 0;
+      if (TARGET_FDIVDU > 0)
+       warning (0, "%<-mfdivdu%> ignored without %<-mhard-float%>");
+      TARGET_FDIVDU = 0;
+    }
+
+  /* Extended LRW instructions are enabled by default on CK801, disabled
+     otherwise.  */
+  if (TARGET_ELRW == -1)
+    TARGET_ELRW = CSKY_TARGET_ARCH (CK801);
+
+  /* DSP is enabled either by the processor feature or -mdsp
+     command-line option.  There is no -mno-dsp option as the assembler
+     doesn't take one.  */
+  if (!TARGET_DSP)
+    TARGET_DSP = CSKY_ISA_FEATURE (dsp);
+
+  /* There's both -mdiv and -mno-div.  Take default from processor if
+     neither is specified explicitly.  */
+  if (TARGET_DIV == -1)
+    TARGET_DIV = CSKY_ISA_FEATURE (div);
+
+  /* TARGET_CONSTANT_POOL is mandatory for CK801 and CK802 and optional
+     for other CPUs.
+     The reason why the compiler has to generate constant pools for CK801/2
+     instead of deferring to the assembler is that these cores don't have a
+     long branch instruction other than jbsr, which clobbers lr.  So for
+     the compiler to correctly save/restore lr it has to know whether there
+     are long branches, which depends on having accurate branch length
+     counts, which in turn depends on having control over where constant
+     pools are placed.  */
+  if ((CSKY_TARGET_ARCH (CK801) || CSKY_TARGET_ARCH (CK802))
+      && !TARGET_CONSTANT_POOL)
+    error ("%qs is not supported by arch %s",
+          "-mno-constpool", csky_active_target.arch_pp_name);
+  else if (TARGET_CONSTANT_POOL == -1)
+    TARGET_CONSTANT_POOL = (CSKY_TARGET_ARCH (CK801)
+                           || CSKY_TARGET_ARCH (CK802));
+
+  /* TARGET_MINI_REGISTERS is mandatory for CK801, the default for CK802,
+     and optional for other CPUs.  TARGET_HIGH_REGISTERS is incompatible
+     with TARGET_MINI_REGISTERS, is not supported by CK801/802/803,
+     and is the default for other processors.
+     See csky_conditional_register_usage.  */
+  if (TARGET_MINI_REGISTERS > 0 && TARGET_HIGH_REGISTERS > 0)
+    error ("%<-msmart%> is incompatible with %<-mhigh-registers%>");
+  else if (CSKY_TARGET_ARCH (CK801)
+          || CSKY_TARGET_ARCH (CK802)
+          || CSKY_TARGET_ARCH (CK803))
+    {
+      if (CSKY_TARGET_ARCH (CK801)
+         || (CSKY_TARGET_ARCH (CK802) && TARGET_MINI_REGISTERS == -1))
+       TARGET_MINI_REGISTERS = 1;
+      else if (TARGET_MINI_REGISTERS == -1)
+       TARGET_MINI_REGISTERS = 0;
+      if (TARGET_HIGH_REGISTERS > 0)
+       warning (0, "%qs is not supported by arch %s",
+                "-mhigh-registers", csky_active_target.arch_pp_name);
+      TARGET_HIGH_REGISTERS = 0;
+    }
+  else
+    {
+      if (TARGET_MINI_REGISTERS == -1)
+       TARGET_MINI_REGISTERS = 0;
+      if (TARGET_HIGH_REGISTERS == -1)
+       TARGET_HIGH_REGISTERS = !TARGET_MINI_REGISTERS;
+    }
+
+  /* -mmultiple-stld is the default for everything but CK801, which
+     doesn't support it.  */
+  if (CSKY_TARGET_ARCH (CK801))
+    {
+      if (TARGET_MULTIPLE_STLD > 0)
+       warning (0, "%qs is not supported by arch %s",
+                "-mmultiple-stld", csky_active_target.arch_pp_name);
+      TARGET_MULTIPLE_STLD = 0;
+    }
+
+  /* Initialize boolean versions of the architectural flags, for use
+     in the .md file.  */
+
+#undef CSKY_ISA
+#define CSKY_ISA(IDENT, DESC)                                            \
+  {                                                                      \
+    csky_arch_isa_features[CSKY_ISA_FEATURE_GET (IDENT)] =                \
+      bitmap_bit_p (csky_active_target.isa, CSKY_ISA_FEATURE_GET (IDENT)); \
+  }
+#include "csky_isa.def"
+#undef CSKY_ISA
+
+  /* TODO  */
+
+  /* Resynchronize the saved target options.  */
+  cl_target_option_save (TREE_TARGET_OPTION (target_option_default_node),
+                        &global_options);
+
+#ifdef ENABLE_TPF_DEBUG
+  /* Don't emit DWARF4 unless specifically selected.  The TPF
+     debuggers do not yet support DWARF 3/4.  */
+  if (!global_options_set.x_dwarf_strict)
+    dwarf_strict = 1;
+  if (!global_options_set.x_dwarf_version)
+    dwarf_version = 3;
+#endif
+
+  /* Don't run the scheduler before reload by default,
+     since it tends to increase register pressure.  */
+  if (!global_options_set.x_flag_schedule_insns)
+    flag_schedule_insns = 0;
+
+  csky_add_gc_roots ();
+}
+
+
+/* Return TRUE if X contains any references to TLS symbols.  */
+
+bool
+csky_tls_referenced_p (rtx x)
+{
+  if (!TARGET_TLS)
+    return false;
+
+  subrtx_iterator::array_type array;
+  FOR_EACH_SUBRTX (iter, array, x, ALL)
+    {
+      const_rtx x = *iter;
+      if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x) != 0)
+       return true;
+
+      /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
+        TLS offsets, not real symbol references.  */
+      if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
+       iter.skip_subrtxes ();
+    }
+  return false;
+}
+
+
+/* Implement TARGET_CANNOT_FORCE_CONST_MEM.
+   Determine if it's legal to put X into the constant pool.  This
+   is not possible for the address of thread-local symbols, which
+   is checked above.  */
+
+static bool
+csky_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED,
+                            rtx x)
+{
+  return csky_tls_referenced_p (x);
+}
+
+
+/* Implement TARGET_LEGITIMATE_CONSTANT_P.  Returns nonzero if the
+   constant value X is a legitimate general operand.
+   It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE.  */
+
+static bool
+csky_legitimate_constant_p (machine_mode mode, rtx x)
+{
+  return (!csky_cannot_force_const_mem (mode, x)
+         && CONSTANT_P (x));
+}
+
+
+/* Return true if X is valid as an CSKY addressing register.  */
+
+static bool
+is_csky_address_register_rtx_p (rtx x, int strict_p)
+{
+  int regno;
+
+  if (!x)
+    return false;
+  if (!REG_P (x))
+    return false;
+
+  regno = REGNO (x);
+
+  if (strict_p)
+    return (CSKY_GENERAL_REGNO_P (regno)
+           || CSKY_GENERAL_REGNO_P (reg_renumber[regno]));
+  else
+    return CSKY_GENERAL_REGNO_P (regno) || regno >= FIRST_PSEUDO_REGISTER;
+}
+
+
+/* Return TRUE if X is a thread-local symbol.  */
+
+static bool
+csky_tls_symbol_p (rtx x)
+{
+  if (!TARGET_TLS)
+    return false;
+
+  if (GET_CODE (x) != SYMBOL_REF)
+    return false;
+
+  return SYMBOL_REF_TLS_MODEL (x) != 0;
+}
+
+
+/* Handle lazy initialization of __tls_get_addr libfunc.  */
+static GTY(()) rtx tls_get_addr_libfunc;
+
+static rtx
+get_tls_get_addr (void)
+{
+  if (!tls_get_addr_libfunc)
+    tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr");
+  return tls_get_addr_libfunc;
+}
+
+
+/* Emit a call to __tls_get_addr.  */
+
+static rtx_insn *
+csky_call_tls_get_addr (rtx x, rtx reg, rtx *valuep, int reloc)
+{
+  rtx label, labelno, unspec, tmp;
+  rtx_insn *insns;
+
+  start_sequence ();
+
+  labelno = GEN_INT (tls_labelno++);
+  label = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno), UNSPEC_TLS_LABEL);
+  unspec = gen_rtx_UNSPEC (Pmode,
+                          gen_rtvec (3, x, GEN_INT (reloc), label),
+                          UNSPEC_TLS);
+  tmp = gen_reg_rtx (SImode);
+  emit_move_insn (reg, unspec);
+  emit_move_insn (tmp, label);
+  emit_insn (gen_addsi3 (reg, reg, tmp));
+  *valuep = emit_library_call_value (get_tls_get_addr (),
+                                    NULL_RTX, LCT_PURE, /* LCT_CONST?  */
+                                    Pmode, reg, Pmode);
+  insns = get_insns ();
+  end_sequence ();
+  return insns;
+}
+
+/* Helper function for csky_legitimize_address, to handle the TLS cases.
+   REG is a scratch register and may be null.  */
+
+rtx
+csky_legitimize_tls_address (rtx x, rtx reg)
+{
+  rtx dest, tp, label, labelno, unspec, ret, eqv, addend, tmp;
+  rtx_insn *insns;
+  unsigned int model = SYMBOL_REF_TLS_MODEL (x);
+
+  if (!reg)
+    reg = gen_reg_rtx (SImode);
+
+  switch (model)
+    {
+    case TLS_MODEL_GLOBAL_DYNAMIC:
+      insns = csky_call_tls_get_addr (x, reg, &ret, TLS_GD32);
+      dest = gen_reg_rtx (Pmode);
+      emit_libcall_block (insns, dest, ret, x);
+      return dest;
+
+    case TLS_MODEL_LOCAL_DYNAMIC:
+      insns = csky_call_tls_get_addr (x, reg, &ret, TLS_LDM32);
+
+      /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
+        share the LDM result with other LD model accesses.  */
+      eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const1_rtx), UNSPEC_TLS);
+      dest = gen_reg_rtx (Pmode);
+      emit_libcall_block (insns, dest, ret, eqv);
+
+      /* Load the addend.  */
+      addend = gen_rtx_UNSPEC (Pmode,
+                              gen_rtvec (2, x, GEN_INT (TLS_LDO32)),
+                              UNSPEC_TLS);
+      addend = force_reg (SImode, addend);
+      return gen_rtx_PLUS (Pmode, dest, addend);
+
+    case TLS_MODEL_INITIAL_EXEC:
+      labelno = GEN_INT (tls_labelno++);
+      label = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno), UNSPEC_TLS_LABEL);
+      unspec = gen_rtx_UNSPEC (Pmode,
+                              gen_rtvec (3, x, GEN_INT (TLS_IE32), label),
+                              UNSPEC_TLS);
+      tmp = gen_reg_rtx (SImode);
+      emit_move_insn (reg, unspec);
+      emit_move_insn (tmp, label);
+      emit_insn (gen_addsi3 (reg, reg, tmp));
+      emit_move_insn (reg, gen_const_mem (Pmode, reg));
+      tp = gen_rtx_REG (SImode, CSKY_TLS_REGNUM);
+      return gen_rtx_PLUS (Pmode, tp, reg);
+
+    case TLS_MODEL_LOCAL_EXEC:
+      unspec = gen_rtx_UNSPEC (Pmode,
+                              gen_rtvec (2, x, GEN_INT (TLS_LE32)),
+                              UNSPEC_TLS);
+      emit_move_insn (reg, unspec);
+      tp = gen_rtx_REG (SImode, CSKY_TLS_REGNUM);
+      return gen_rtx_PLUS (Pmode, tp, reg);
+
+    default:
+      abort ();
+    }
+}
+
+
+/* Implement TARGET_LEGITIMIZE_ADDRESS.  */
+
+static rtx
+csky_legitimize_address (rtx x, rtx orig_x ATTRIBUTE_UNUSED,
+                        machine_mode mode)
+{
+  if (csky_tls_symbol_p (x))
+    return csky_legitimize_tls_address (x, NULL_RTX);
+
+  if (GET_CODE (x) == PLUS)
+    {
+      rtx xop0 = XEXP (x, 0);
+      rtx xop1 = XEXP (x, 1);
+
+      if (is_csky_address_register_rtx_p (xop0, 0)
+         && CONST_INT_P (xop1))
+       {
+         HOST_WIDE_INT offset = INTVAL (xop1);
+
+         /* Try to replace ld32 rx,(ry, offset), to addi16 rz, oimm8
+            and ld16 rx,(rz, new_ld_offset) to avoid emitting a
+            32-bit ld, but this addi has a range limitation.  */
+         if (optimize_size
+             && offset > CSKY_LD16_MAX_OFFSET (mode)
+             && offset <= (CSKY_ADDI16_MAX_IMM
+                          + CSKY_LD16_MAX_OFFSET (mode)))
+           {
+             HOST_WIDE_INT new_ld_offset
+               = offset & CSKY_LD16_OFFSET_MASK (mode);
+
+             xop0 = force_operand (plus_constant (Pmode, xop0,
+                                                  offset - new_ld_offset),
+                                   NULL_RTX);
+             x = plus_constant (Pmode, xop0, new_ld_offset);
+           }
+         else if (offset < 0 && offset >= (-CSKY_SUBI16_MAX_IMM))
+           x = force_operand (x, NULL_RTX);
+         else if (offset > CSKY_LD16_MAX_OFFSET (mode)
+                  || offset < 0)
+           {
+             /* For the remaining cases, force the constant into a
+                register.  */
+             xop1 = force_reg (SImode, xop1);
+             x = gen_rtx_PLUS (SImode, xop0, xop1);
+           }
+       }
+
+      /* If the index is store in register, force the
+        base to register.  */
+      if (is_csky_address_register_rtx_p (xop1, 0)
+         && !is_csky_address_register_rtx_p (xop0, 0))
+       {
+         xop0 = force_operand (xop0, NULL_RTX);
+         x = gen_rtx_PLUS (SImode, xop0, xop1);
+       }
+    }
+  /* Make sure to take full advantage of the pre-indexed addressing mode
+     with absolute addresses which often allows for the base register to
+     be factorized for multiple adjacent memory references, and it might
+     even allows for the mini pool to be avoided entirely. */
+  else if (CONST_INT_P (x)  && optimize > 0)
+    {
+      HOST_WIDE_INT mask, base, index;
+      rtx base_reg;
+
+      mask = CSKY_LD16_OFFSET_MASK (mode);
+      base = INTVAL (x) & ~mask;
+      index = INTVAL (x) & mask;
+      base_reg = force_reg (SImode, GEN_INT (base));
+      x = plus_constant (Pmode, base_reg, index);
+    }
+
+  return x;
+}
+
+
+/* Return nonzero if INDEX is valid for an address index operand.
+   ck801 use 16 bits ld
+   ck802 use 16 and 32 bits ld
+   others use ld and ldr.  */
+
+static int
+ck801_legitimate_index_p (machine_mode mode, rtx index,
+                         int strict_p ATTRIBUTE_UNUSED)
+{
+  enum rtx_code code = GET_CODE (index);
+
+  /* When the mode size is larger than 4, we may use two ld instruction
+     to get data, the index and (index+1) should be valid.  */
+  if (GET_MODE_SIZE (mode) >= 8)
+    return (code == CONST_INT
+           && INTVAL (index) <  CSKY_LD16_MAX_OFFSET (SImode)
+           && INTVAL (index) >= 0 && (INTVAL (index) & 3) == 0);
+
+  if (code == CONST_INT && GET_MODE_SIZE (mode) > 0
+      && INTVAL (index) <= CSKY_LD16_MAX_OFFSET (mode)
+      && INTVAL (index) >= 0)
+    return ((INTVAL (index) % GET_MODE_SIZE (mode)) == 0);
+
+  return 0;
+}
+
+
+static int
+ck802_legitimate_index_p (machine_mode mode, rtx index,
+                         int strict_p ATTRIBUTE_UNUSED)
+{
+  enum rtx_code code = GET_CODE (index);
+
+  /* When the mode size is larger than 4, we may use two ld instruction
+     to get data, the index and (index+1) should be valid.  */
+  if (GET_MODE_SIZE (mode) >= 8)
+    return (code == CONST_INT
+           && INTVAL (index) < CSKY_LD32_MAX_OFFSET (SImode)
+           && INTVAL (index) >= 0 && (INTVAL (index) & 3) == 0);
+
+  if (code == CONST_INT && GET_MODE_SIZE (mode) > 0
+      && INTVAL (index) <= CSKY_LD32_MAX_OFFSET (mode)
+      && INTVAL (index) >= 0)
+    return ((INTVAL (index) % GET_MODE_SIZE (mode)) == 0);
+
+  return 0;
+}
+
+
+/* The instruction ldr rz, (rx, ry << i), i can be 0,1,2,3.
+   Check that SHIFT is valid, that the code is MULT, and that
+   the shift is a power of 2.  */
+
+static bool
+is_ldr_shift_p (HOST_WIDE_INT shift, enum rtx_code code)
+{
+  if (code == ASHIFT)
+    return (shift >= 0 && shift <= 3);
+  else if (code == MULT)
+    return (shift == 1
+           || shift == 2
+           || shift == 4
+           || shift == 8);
+  else
+    return false;
+}
+
+
+static int
+ck810_legitimate_index_p (machine_mode mode, rtx index, int strict_p)
+{
+  enum rtx_code code = GET_CODE (index);
+
+  if (TARGET_HARD_FLOAT
+      && (mode == SFmode || mode == DFmode))
+    return (code == CONST_INT && INTVAL (index) < 1024
+           && INTVAL (index) >= 0
+           && (INTVAL (index) & 3) == 0);
+
+  if (code == CONST_INT)
+    {
+      /* When the mode size is larger than 4, we may use two ld instruction
+        to get data, the index and (index+1) should be valid.  */
+      if (GET_MODE_SIZE (mode) >= 8)
+       return (INTVAL (index) < CSKY_LD32_MAX_OFFSET (SImode)
+               && INTVAL (index) >= 0 && (INTVAL (index) & 3) == 0);
+
+      if (GET_MODE_SIZE (mode) > 0
+         && INTVAL (index) <= CSKY_LD32_MAX_OFFSET (mode)
+         && INTVAL (index) >= 0)
+       return ((INTVAL (index) % GET_MODE_SIZE (mode)) == 0);
+    }
+  /* Allow ld.w rx, (gb, sym@got) when -fpic specially.  */
+  else if (code == UNSPEC)
+    return (flag_pic == 1
+           && (XINT (index, 1) == UNSPEC_PIC_SYMBOL_PLT
+               || XINT (index, 1) == UNSPEC_PIC_SYMBOL_GOT));
+  /* The follow index is for ldr instruction, the ldr cannot
+     load dword data, so the mode size should not be larger than
+     4.  */
+  else if (GET_MODE_SIZE (mode) <= 4)
+    {
+      if (is_csky_address_register_rtx_p (index, strict_p))
+       return 1;
+      else if (code == MULT || code == ASHIFT)
+       {
+         rtx xiop0 = XEXP (index, 0);
+         rtx xiop1 = XEXP (index, 1);
+
+         /* FIXME can the xiop1 be the reg and xiop0 be the int when mult?  */
+         return (is_csky_address_register_rtx_p (xiop0, strict_p)
+                 && CONST_INT_P (xiop1)
+                 && is_ldr_shift_p (INTVAL (xiop1), code));
+       }
+    }
+
+  return 0;
+}
+
+
+static int
+csky_legitimate_index_p (machine_mode mode, rtx index, int strict_p)
+{
+  if (CSKY_TARGET_ARCH (CK801))
+    return ck801_legitimate_index_p (mode, index, strict_p);
+  else if (CSKY_TARGET_ARCH (CK802))
+    return ck802_legitimate_index_p (mode, index, strict_p);
+  else
+    return ck810_legitimate_index_p (mode, index, strict_p);
+}
+
+
+/* Implement TARGET_LEGITIMATE_ADDRESS_P.
+   Recognizes RTL expressions that are valid memory addresses for an
+   instruction.  The MODE argument is the machine mode for the MEM
+   expression that wants to use this address.
+
+   It only recognizes address in canonical form.  LEGITIMIZE_ADDRESS should
+   convert common non-canonical forms to canonical form so that they will
+   be recognized.  */
+
+static bool
+csky_legitimate_address_p (machine_mode mode, rtx addr, bool strict_p)
+{
+  enum rtx_code code = GET_CODE (addr);
+
+  /* Match the RTX form emitted for constant pool references.
+     After reload constants split into minipools will have addresses
+     from a LABEL_REF.  */
+  if (reload_completed
+      && ((code == LABEL_REF)
+          || (code == CONST
+              && GET_CODE (XEXP (addr, 0)) == PLUS
+              && GET_CODE (XEXP (XEXP (addr, 0), 0)) == LABEL_REF
+              && CONST_INT_P (XEXP (XEXP (addr, 0), 1)))))
+    return 1;
+
+  if (is_csky_address_register_rtx_p (addr, strict_p))
+    return 1;
+  /* It is a pc-relative load, may be generated for constpool.  */
+  else if (GET_CODE (addr) == LABEL_REF)
+    return 1;
+
+  if (code == PLUS)
+    {
+      rtx xop0 = XEXP (addr, 0);
+      rtx xop1 = XEXP (addr, 1);
+
+      return ((is_csky_address_register_rtx_p (xop0, strict_p)
+              && csky_legitimate_index_p (mode, xop1, strict_p))
+             || (is_csky_address_register_rtx_p (xop1, strict_p)
+                 && csky_legitimate_index_p (mode, xop0, strict_p)));
+    }
+
+  return 0;
+}
+
+
+/* Functions to save and restore machine-specific function data.  */
+
+static struct machine_function *
+csky_init_machine_status (void)
+{
+  struct machine_function *machine;
+
+  machine = ggc_cleared_alloc<machine_function> ();
+
+#if CSKY_FT_UNKNOWN != 0
+  machine->func_type = CSKY_FT_UNKNOWN;
+#endif
+  return machine;
+}
+
+
+/* Implement INIT_EXPANDERS.  */
+
+void
+csky_init_expanders (void)
+{
+  /* Arrange to initialize and mark the machine per-function status.  */
+  init_machine_status = csky_init_machine_status;
+}
+
+
+/* Implement TARGET_CANNOT_COPY_INSN_P.
+   We must not copy any rtx that uses a pc-relative address.  */
+
+static bool
+csky_cannot_copy_insn_p (rtx_insn *insn)
+{
+  subrtx_iterator::array_type array;
+  FOR_EACH_SUBRTX (iter, array, PATTERN (insn), ALL)
+    {
+      const_rtx x = *iter;
+      if (GET_CODE (x) == UNSPEC
+         && (XINT (x, 1) == UNSPEC_TLS_LABEL
+             || XINT (x, 1) == UNSPEC_PIC_SYMBOL_GOTPC_GRS))
+       return true;
+    }
+  return false;
+}
+
+
+/* Extract the parts of an RTL expression that is a valid memory address
+   for an instruction.  Return FALSE if it is a invalid memory address.  */
+
+struct csky_address
+{
+  rtx base, index, symbol, label, disp;
+  HOST_WIDE_INT scale;
+};
+
+static bool
+decompose_csky_address (rtx addr, struct csky_address *out)
+{
+  rtx base = NULL_RTX, index = NULL_RTX, disp = NULL_RTX;
+  HOST_WIDE_INT scale = 1;
+  rtx scale_rtx = NULL_RTX;
+  int i;
+
+  out->base = out->index = out->symbol = out->label = out->disp = NULL_RTX;
+  out->scale = 0;
+
+  if (REG_P (addr))
+    {
+      out->base = addr;
+      return true;
+    }
+
+  if (GET_CODE (addr) == LABEL_REF)
+    {
+      out->label = addr;
+      return true;
+    }
+
+  if (GET_CODE (addr) == CONST)
+    addr = XEXP (addr, 0);
+
+  if (GET_CODE (addr) == PLUS)
+    {
+      rtx addends[2], op;
+
+      addends[0] = XEXP (addr, 0);
+      addends[1] = XEXP (addr, 1);
+
+      if (GET_CODE (addends[0]) == LABEL_REF && CONST_INT_P (addends[1]))
+       {
+         out->label = addends[0];
+         out->disp = addends[1];
+         return true;
+       }
+
+      if (!REG_P (addends[0]))
+       std::swap (addends[0], addends[1]);
+
+      for (i = 0; i < 2; ++i)
+       {
+         op = addends[i];
+         switch (GET_CODE (op))
+           {
+           case REG:
+             if (!base)
+               base = op;
+             else if (!index)
+               index = op;
+             else
+               return false;
+             break;
+           case CONST_INT:
+           case UNSPEC:
+             if (disp)
+               return false;
+             disp = op;
+             break;
+           case MULT:
+             if (index)
+               return false;
+             index = XEXP (op, 0);
+             scale_rtx = XEXP (op, 1);
+             if (!CONST_INT_P (index) && !CONST_INT_P (scale_rtx))
+               return false;
+             else if (CONST_INT_P (index))
+               std::swap (index, scale_rtx);
+             scale = INTVAL (scale_rtx);
+             break;
+           case ASHIFT:
+             if (index)
+               return false;
+             index = XEXP (op, 0);
+             scale_rtx = XEXP (op, 1);
+             if (!CONST_INT_P (scale_rtx))
+               return false;
+             scale = scale << INTVAL (scale_rtx);
+             break;
+           default:
+             return false;
+           }
+       }
+    }
+
+  if (!base)
+    return false;
+
+  out->base = base;
+  out->index = index;
+  out->disp = disp;
+  out->scale = scale;
+
+  return true;
+}
+
+/* Helper function for the csky_simple_mem_operand predicate.  Returns
+   true if OP is an address of the form reg + displacement.  */
+
+bool
+csky_simple_addr_operand_p (rtx op)
+{
+  struct csky_address addr;
+
+  if (!decompose_csky_address (op, &addr))
+    return false;
+
+  /* FIXME The PIC related code.
+     Check if load the symbol address from got table.  */
+  if (addr.disp && GET_CODE (addr.disp) == UNSPEC)
+    return false;
+  if (!addr.index && !addr.symbol)
+    return true;
+  return false;
+}
+
+
+/* Print the UNSPEC operand in X to the STREAM.  */
+
+static void
+csky_output_pic_addr_const (FILE *stream, rtx x, int code)
+{
+
+  if (GET_CODE (x) != UNSPEC)
+    return;
+
+  if (UNSPEC_TLS == XINT (x, 1))
+    {
+      /* FIXME It is not reached */
+      return;
+    }
+
+  csky_print_operand (stream, XVECEXP (x, 0, 0), code);
+
+  switch (XINT (x, 1))
+    {
+    case UNSPEC_PIC_SYMBOL_GOTOFF:
+      fputs ("@GOTOFF", stream);
+      break;
+    case UNSPEC_PIC_SYMBOL_PLT:
+      fputs ("@PLT", stream);
+      break;
+    case UNSPEC_PIC_SYMBOL_GOT:
+      fputs ("@GOT", stream);
+      break;
+    case UNSPEC_PIC_SYMBOL_GOTPC:
+      fputs ("@GOTPC", stream);
+      break;
+    case UNSPEC_PIC_SYMBOL_BSR:
+      break;
+    default:
+      break;
+    }
+}
+
+
+/* Output the constpool label according to the rtx expression X.  */
+
+static void
+csky_output_constpool_label (FILE *stream, rtx x)
+{
+  char buf[15];
+
+  gcc_assert (GET_CODE (x) == LABEL_REF);
+  x = XEXP (x, 0);
+
+  if (GET_CODE (x) == UNSPEC_VOLATILE && XINT (x, 1) == VUNSPEC_POOL_LABEL)
+    {
+      ASM_GENERATE_INTERNAL_LABEL (buf, CSKY_CONSTPOOL_LABEL_PREFIX,
+                                  INTVAL (XVECEXP (x, 0, 0)));
+      assemble_name (stream, buf);
+    }
+}
+
+
+/* Implement TARGET_PRINT_OPERAND_ADDRESS.  */
+
+static void
+csky_print_operand_address (FILE *stream,
+                           machine_mode mode ATTRIBUTE_UNUSED,
+                           rtx x)
+{
+
+  struct csky_address addr;
+
+  decompose_csky_address (x, &addr);
+
+  if (addr.label && addr.disp && GET_CODE (addr.disp) == CONST_INT)
+    {
+      fprintf (stream, "[");
+      csky_output_constpool_label (stream, addr.label);
+      fprintf (stream, "+%d]", (int) INTVAL (addr.disp));
+    }
+  else if (addr.label)
+    {
+      fprintf (stream, "[");
+      csky_output_constpool_label (stream, addr.label);
+      fprintf (stream, "]");
+    }
+  else if (addr.symbol && addr.disp && GET_CODE (addr.disp) == CONST_INT)
+    {
+      fprintf (stream, "[");
+      output_addr_const (stream, addr.symbol);
+      fprintf (stream, "+%d]", (int) INTVAL (addr.disp));
+    }
+  else if (addr.symbol)
+    {
+      fprintf (stream, "[");
+      output_addr_const (stream, addr.symbol);
+      fprintf (stream, "]");
+    }
+  else if (addr.disp && GET_CODE (addr.disp) == CONST_INT)
+    fprintf (stream, "(%s, %d)",
+            reg_names[REGNO (addr.base)], (int) INTVAL (addr.disp));
+  else if (addr.disp && GET_CODE (addr.disp) == UNSPEC)
+    {
+      if (REGNO (addr.base) != CSKY_GB_REGNUM)
+       fprintf (stream, "(%s, ", reg_names[REGNO (addr.base)]);
+      else
+       fprintf (stream, "[");
+      csky_output_pic_addr_const (stream, addr.disp, 0);
+      fprintf (stream, "%s", (REGNO (addr.base) != CSKY_GB_REGNUM)
+              ? ")" : "]");
+    }
+  else if (addr.index)
+    fprintf (stream, "(%s, %s << %d)",
+            reg_names[REGNO (addr.base)], reg_names[REGNO (addr.index)],
+            exact_log2 ((int) (addr.scale)));
+  else
+    fprintf (stream, "(%s, 0)", reg_names[REGNO (addr.base)]);
+}
+
+
+/* Implement TARGET_PRINT_OPERAND.
+   Print operand X (an rtx) in assembler syntax to file STREAM
+   according to modifier CODE.
+
+   'N' print the log2(X+1), mainly used for bmaski
+   'P' print the log2(X)
+   'Q' print the log2(~X)
+   'O' print a decimal number
+   'M' print a decimal number as its negative
+   'R' print the next register or memory location along, i.e. the lsw in
+   a double word value
+   'H' print the high 16 bits of a constant.  */
+
+static void
+csky_print_operand (FILE *stream, rtx x, int code)
+{
+  switch (code)
+    {
+    case 'N':
+      if ((INTVAL (x) & 0xffffffff) == 0xffffffff)
+       fprintf (stream, "0");
+      else
+       fprintf (stream, "%d",
+                (int) exact_log2 ((INTVAL (x) & 0xffffffff) + 1) % 32);
+      break;
+    case 'P':
+      fprintf (stream, "%d",
+              (int) exact_log2 (INTVAL (x) & 0xffffffff));
+      break;
+    case 'Q':
+      fprintf (stream, "%d",
+              (int) exact_log2 (~INTVAL (x) & 0xffffffff));
+      break;
+    case 'O':
+      fprintf (stream, "%d", (int) INTVAL (x));
+      break;
+    case 'M':
+      fprintf (stream, "%d", (int) (-INTVAL (x)));
+      break;
+    case 'R':
+      /* Next location along in memory or register.  */
+      switch (GET_CODE (x))
+       {
+       case REG:
+         fputs (reg_names[REGNO (x) + 1], stream);
+         break;
+       case MEM:
+         csky_print_operand_address
+           (stream, GET_MODE (x), XEXP (adjust_address (x, SImode, 4), 0));
+         break;
+       default:
+         gcc_unreachable ();
+       }
+      break;
+    case 'H':
+      fprintf (stream, "%ld", (long)((INTVAL (x) & 0xFFFF0000) >> 16));
+      break;
+    default:
+      switch (GET_CODE (x))
+       {
+       case REG:
+         fputs (reg_names[REGNO (x)], stream);
+         break;
+       case MEM:
+         output_address (GET_MODE (x), XEXP (x, 0));
+         break;
+       case UNSPEC:
+         csky_output_pic_addr_const (stream, x, code);
+         break;
+       default:
+         output_addr_const (stream, x);
+         break;
+       }
+      break;
+    }
+}
+
+
+
+/* Implement TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS.  */
+
+static bool
+csky_allocate_stack_slots_for_args (void)
+{
+  /* Naked functions should not allocate stack slots for arguments.  */
+  return !CSKY_FUNCTION_IS_NAKED (get_csky_current_func_type ());
+}
+
+
+/* Can we generate a constant with a single instruction, without using
+   lrw?         */
+
+static int
+const_ok_for_cskyv2 (HOST_WIDE_INT value)
+{
+  /* Try exact power of two. It can be generated by bgeni.  */
+  if (CSKY_CONST_OK_FOR_Ub (value))
+    return 1;
+
+  /* Try exact power of two - 1.  It can be generated by bmaski.  */
+  if (CSKY_CONST_OK_FOR_Uc (value) && value != -1)
+    return 1;
+
+  /* Try if it can be generated by movi.  */
+  if (CSKY_CONST_OK_FOR_I (value))
+    return 1;
+
+  /* The constant can be generated by movih.
+     Notice that movih is a 32-bit instruction.  */
+  if (CSKY_CONST_OK_FOR_MOVIH (value))
+    return 1;
+
+  return 0;
+}
+
+
+/* Tricks for synthesizing constants from values that can be directly
+   manipulated by machine instructions.  */
+
+enum csky_inline_const_type
+{
+  IC_UNINLINABLE = 0, /* Not inlineable */
+  IC_SINGLE,         /* Single instruction */
+  IC_APPEND_NOT,      /* Single instruction followed by a not */
+  IC_APPEND_ADDI,     /* Single insn followed by an addi */
+  IC_APPEND_SUBI,     /* Single insn followed by a subi */
+  IC_BGENI_ADDI,      /* Single insn(bgeni) followed by an addi */
+  IC_BGENI_SUBI,      /* Single insn(bgeni) followed by a subi */
+  IC_APPEND_BSETI,    /* Single insn followed by bseti */
+  IC_APPEND_MOVI,     /* Single insn followed by movi */
+  IC_APPEND_BCLRI,    /* Single insn followed by bclri */
+  IC_APPEND_ROTLI,    /* Single insn followed by rotli */
+  IC_APPEND_LSLI,     /* Single insn followed by lsli */
+  IC_APPEND_IXH,      /* Single insn followed by ixh */
+  IC_APPEND_IXW              /* Single insn followed by ixw */
+};
+
+
+/* Try tricks to load a constant inline and return the trick number if
+   success, or IC_UNINLINABLE.  */
+
+static enum csky_inline_const_type
+try_csky_constant_tricks (HOST_WIDE_INT value, HOST_WIDE_INT *x,
+                         HOST_WIDE_INT *y)
+{
+  HOST_WIDE_INT i, value_invert;
+  unsigned HOST_WIDE_INT bit, shf, rot, lobits, hibits;
+
+  value &= 0xffffffff;
+  value_invert = ~value & 0xffffffff;
+
+  if (const_ok_for_cskyv2 (value))
+    {
+      *x = value;
+      return IC_SINGLE;
+    }
+
+  /* Since movih is 32 bits, do not use it here, better code may
+     be generated later.  */
+  if (const_ok_for_cskyv2 (value_invert)
+      && !CSKY_CONST_OK_FOR_MOVIH (value_invert))
+    {
+      *x = value_invert;
+      return IC_APPEND_NOT;
+    }
+
+  /* One immediate generate instruction, and one 16-bit subi or addi.  */
+  for (i = 1; i <= 32; i++)
+    {
+      if (const_ok_for_cskyv2 (value - i)
+         && !CSKY_CONST_OK_FOR_MOVIH (value - i))
+       {
+         *x = value - i;
+         *y = i;
+         return IC_APPEND_ADDI;
+       }
+
+      if (const_ok_for_cskyv2 (value + i)
+         && !CSKY_CONST_OK_FOR_MOVIH (value - i))
+       {
+         *x = value + i;
+         *y = i;
+         return IC_APPEND_SUBI;
+       }
+    }
+
+  /* Generate bgeni + addi.  */
+  if (CSKY_CONST_OK_FOR_Ub (value & 0xfffff000))
+    {
+      *x = (value & 0xfffff000);
+      *y = (value & 0xfff);
+      return IC_BGENI_ADDI;
+    }
+
+  /* Generate bgeni + subi.  */
+  lobits = value & 0xfff;
+  hibits = (unsigned HOST_WIDE_INT)(value & 0xfffff000) + (1 << 12);
+  if (exact_log2 (hibits) >= 1
+      && exact_log2 (hibits) <= 30
+      && lobits != 0)
+    {
+      *x = hibits;
+      *y = (0x1000 - lobits);
+      return IC_BGENI_SUBI;
+    }
+
+  /* One immediate generate instruction, and one bseti or bclri.  */
+  bit = 0x80000000ULL;
+  for (i = 0; i <= 31; i++)
+    {
+      if (const_ok_for_cskyv2 (value & ~bit)
+         && !CSKY_CONST_OK_FOR_MOVIH (value & ~bit))
+       {
+         *y = bit;
+         *x = (value & ~bit);
+         return IC_APPEND_BSETI;
+       }
+
+      if (const_ok_for_cskyv2 (value | bit)
+         && !CSKY_CONST_OK_FOR_MOVIH (value | bit))
+       {
+         *y = ~bit & 0xffffffff;
+         *x = value | bit;
+         return IC_APPEND_BCLRI;
+       }
+
+      bit >>= 1;
+    }
+
+  /* One immediate generate instruction, and one rotli or lsli.  */
+  shf = value;
+  rot = value;
+  for (i = 1; i < 31; i++)
+    {
+      int c;
+
+      /* Rotate left.  */
+      c = rot << 31;
+      rot >>= 1;
+      rot &= 0x7FFFFFFF;
+      rot |= c;
+
+      if (const_ok_for_cskyv2 (rot) && !CSKY_CONST_OK_FOR_MOVIH (rot))
+       {
+         *y = i;
+         *x = rot;
+         return IC_APPEND_ROTLI;
+       }
+
+      /* Can't use logical shift when low order bit is one.  */
+      if (shf & 1)
+       shf = 0;
+      else
+       shf >>= 1;
+
+      if (shf != 0 && const_ok_for_cskyv2 (shf)
+         && !CSKY_CONST_OK_FOR_MOVIH (shf))
+       {
+         *y = i;
+         *x = shf;
+         return IC_APPEND_LSLI;
+       }
+    }
+
+  /* One immediate generate instruction, and one ixh.  */
+  if (CSKY_ISA_FEATURE (E2)
+      && (value % 3) == 0
+      && const_ok_for_cskyv2 (value / 3)
+      && !CSKY_CONST_OK_FOR_MOVIH (value / 3))
+    {
+      *x = value / 3;
+      return IC_APPEND_IXH;
+    }
+
+  /* One immediate generate instruction, and one ixw.  */
+  if (CSKY_ISA_FEATURE (E2)
+      && (value % 5) == 0
+      && const_ok_for_cskyv2 (value / 5)
+      && !CSKY_CONST_OK_FOR_MOVIH (value / 5))
+    {
+      *x = value / 5;
+      return IC_APPEND_IXW;
+    }
+
+  /* Generate movih + bseti.  */
+  if (CSKY_CONST_OK_FOR_Ub (value & 0xffff))
+    {
+      *x = value & 0xffff0000;
+      *y = value & 0xffff;
+      return IC_APPEND_BSETI;
+    }
+
+  /* Generate movih + not.  */
+  if (CSKY_CONST_OK_FOR_MOVIH (value_invert))
+    {
+      *x = value_invert;
+      return IC_APPEND_NOT;
+    }
+
+  /* One movih, and one 16bits addi or subi.  */
+  for (i = 1; i <= 32; i++)
+    {
+      if (CSKY_CONST_OK_FOR_MOVIH (value - i))
+       {
+         *x = value - i;
+         *y = i;
+         return IC_APPEND_ADDI;
+       }
+
+      if (CSKY_CONST_OK_FOR_MOVIH (value + i))
+       {
+         *x = value + i;
+         *y = i;
+         return IC_APPEND_SUBI;
+       }
+    }
+
+  /* One movih, and one bseti or bclri.  */
+  bit = 0x80000000ULL;
+  for (i = 0; i <= 31; i++)
+    {
+      if (CSKY_CONST_OK_FOR_MOVIH (value & ~bit))
+       {
+         *y = bit;
+         *x = value & ~bit;
+         return IC_APPEND_BSETI;
+       }
+
+      if (CSKY_CONST_OK_FOR_MOVIH (value | bit))
+       {
+         *y = ~bit & 0xffffffff;
+         *x = value | bit;
+         return IC_APPEND_BCLRI;
+       }
+
+       bit >>= 1;
+    }
+
+  /* One movih, and one rotli or lsli.  */
+  shf = value;
+  rot = value;
+  for (i = 1; i < 31; i++)
+    {
+      int c;
+
+      /* Rotate left.  */
+      c = rot << 31;
+      rot >>= 1;
+      rot &= 0x7FFFFFFF;
+      rot |= c;
+
+      if (CSKY_CONST_OK_FOR_MOVIH (rot))
+       {
+         *y = i;
+         *x = rot;
+         return IC_APPEND_ROTLI;
+       }
+
+      /* Can't use logical shift when low order bit is one.  */
+      if (shf & 1)
+       shf = 0;
+      else
+       shf >>= 1;
+
+      if (shf != 0 && CSKY_CONST_OK_FOR_MOVIH (shf))
+       {
+         *y = i;
+         *x = shf;
+         return IC_APPEND_LSLI;
+       }
+    }
+
+  return IC_UNINLINABLE;
+}
+
+
+/* Actually output a constant using a trick.
+   FIXME: I think this would be better handled by a splitter than at the
+   asm output level.  */
+
+static const char *
+csky_output_inline_const (machine_mode mode, rtx operands[])
+{
+  HOST_WIDE_INT x = 0, y = 0;
+  enum csky_inline_const_type trick_type;
+  rtx out_operands[3];
+  char buf[256];
+  char load_op[128];
+  const char *dst_fmt;
+  HOST_WIDE_INT value = INTVAL (operands[1]);
+  int ivalue = (int) value;
+  unsigned int uvalue = (unsigned int) value;
+
+  trick_type = try_csky_constant_tricks (value, &x, &y);
+  /* lrw's are handled separately: Large inlinable constants never get
+     turned into lrw's.  Our caller uses try_csky_constant_tricks to back
+     off to an lrw rather than calling this routine.  */
+  gcc_assert (trick_type != IC_UNINLINABLE);
+
+  /* Operands: 0 = dst, 1 = load immedate., 2 = adjust immedate.  */
+  out_operands[0] = operands[0];
+  out_operands[1] = GEN_INT (x);
+  if (trick_type != IC_SINGLE && trick_type != IC_APPEND_NOT)
+    out_operands[2] = GEN_INT (y);
+
+  /* Select dst format based on mode.  */
+  if (mode == DImode && TARGET_BIG_ENDIAN)
+    dst_fmt = "%R0";
+  else
+    dst_fmt = "%0";
+
+  /* Try movi16: 0~31,movi32: 0~65535.  */
+  if (CSKY_CONST_OK_FOR_I (x))
+    sprintf (load_op, "movi\t%s, %%1", dst_fmt);
+  /* Try exact power of two - 1.  */
+  else if (CSKY_CONST_OK_FOR_Uc (x))
+    sprintf (load_op, "bmaski\t%s, %%N1", dst_fmt);
+  /* Try movih.  */
+  else if (CSKY_CONST_OK_FOR_MOVIH (x))
+    sprintf (load_op, "movih\t%s, %%H1", dst_fmt);
+  else
+    {
+      sprintf (load_op, "BADMOVI-inline_const %s, %%1", dst_fmt);
+      gcc_unreachable ();
+    }
+
+  switch (trick_type)
+    {
+    case IC_SINGLE:
+      strcpy (buf, load_op);
+      break;
+    /* Add instruction 'not'.  */
+    case IC_APPEND_NOT:
+      sprintf (buf, "%s\n\tnot\t%s, %s\t// %d 0x%x", load_op, dst_fmt,
+              dst_fmt, ivalue, uvalue);
+      break;
+    /* Add instruction 'addi'.  */
+    case IC_APPEND_ADDI:
+      sprintf (buf, "%s\n\taddi\t%s, %s, %%2\t// %d 0x%x", load_op,
+              dst_fmt, dst_fmt, ivalue, uvalue);
+      break;
+    /* Add instruction 'subi'.  */
+    case IC_APPEND_SUBI:
+      sprintf (buf, "%s\n\tsubi\t%s, %s, %%2\t// %d 0x%x", load_op,
+              dst_fmt, dst_fmt, ivalue, uvalue);
+      break;
+    /* Add instruction 'addi', the last instruction is bgeni.  */
+    case IC_BGENI_ADDI:
+      sprintf (buf, "%s\n\taddi\t%s, %s, %%2\t// %d 0x%x", load_op,
+              dst_fmt, dst_fmt, ivalue, uvalue);
+      break;
+    /* Add instruction 'subi', the last instruction is bgeni.  */
+    case IC_BGENI_SUBI:
+      sprintf (buf, "%s\n\tsubi\t%s, %s, %%2\t// %d 0x%x", load_op,
+              dst_fmt, dst_fmt, ivalue, uvalue);
+      break;
+    /* Add instruction 'bseti'.  */
+    case IC_APPEND_BSETI:
+      sprintf (buf, "%s\n\tbseti\t%s, %s, %%P2\t// %d 0x%x", load_op,
+              dst_fmt, dst_fmt, ivalue, uvalue);
+      break;
+    /* Add instruction 'movi'.  */
+    case IC_APPEND_MOVI:
+      sprintf (buf, "%s\n\tmovi\t%s, %%2\t// %d 0x%x", load_op, dst_fmt,
+              ivalue, uvalue);
+      break;
+    /* Add instruction 'bclri'.  */
+    case IC_APPEND_BCLRI:
+      sprintf (buf, "%s\n\tbclri\t%s, %s, %%Q2\t// %d 0x%x", load_op,
+              dst_fmt, dst_fmt, ivalue, uvalue);
+      break;
+    /* Add instruction 'rotli'.  */
+    case IC_APPEND_ROTLI:
+      sprintf (buf, "%s\n\trotli\t%s, %s, %%2\t// %d 0x%x", load_op,
+              dst_fmt, dst_fmt, ivalue, uvalue);
+      break;
+    /* Add instruction 'lsli'.  */
+    case IC_APPEND_LSLI:
+      sprintf (buf, "%s\n\tlsli\t%s, %s, %%2\t// %d 0x%x", load_op,
+              dst_fmt, dst_fmt, ivalue, uvalue);
+      break;
+    /* Add instruction 'ixh'.  */
+    case IC_APPEND_IXH:
+      sprintf (buf, "%s\n\tixh\t%s, %s, %s\t// %d 0x%x", load_op,
+              dst_fmt, dst_fmt, dst_fmt, ivalue, uvalue);
+      break;
+    /* Add instruction 'ixw'.  */
+    case IC_APPEND_IXW:
+      sprintf (buf, "%s\n\tixw\t%s, %s, %s\t// %d 0x%x", load_op,
+              dst_fmt, dst_fmt, dst_fmt, ivalue, uvalue);
+      break;
+    default:
+      return "";
+    }
+
+  output_asm_insn (buf, out_operands);
+
+  return "";
+}
+
+/* This is a helper function for the Uo constraint for movsi patterns.  */
+
+bool
+csky_inlinable_constant (HOST_WIDE_INT value)
+{
+  HOST_WIDE_INT x, y;
+  return (!(CSKY_TARGET_ARCH (CK802) || CSKY_TARGET_ARCH (CK801))
+         && try_csky_constant_tricks (value, &x, &y));
+}
+
+
+/* Return true if the constant VAL can be expressed by an 8-bit constant
+   with a shift value, filling in *BASE and *SHIFT.  */
+
+bool
+csky_shifted_imm8_constant (unsigned HOST_WIDE_INT val,
+                           unsigned int *base, unsigned int *shift)
+{
+  unsigned HOST_WIDE_INT mask = 0xff;
+  int i;
+  val = val & (unsigned HOST_WIDE_INT) 0xffffffffu;
+  if (val == 0)
+    return 0;
+
+  for (i = 0; i < 25; i++)
+    if ((val & (mask << i)) == val)
+      {
+       if (base)
+         *base = (unsigned int) (val >> i);
+       if (shift)
+         *shift = (unsigned int) i;
+       return true;
+      }
+
+  return false;
+}
+
+
+/* Output a move of a word or less value.  */
+
+const char *
+csky_output_move (rtx insn ATTRIBUTE_UNUSED, rtx operands[],
+                 machine_mode mode ATTRIBUTE_UNUSED)
+{
+  rtx dst = operands[0];
+  rtx src = operands[1];
+  struct csky_address op0, op1;
+
+  if (REG_P (dst))
+    {
+      /* The situation mov reg to reg.  */
+      if (REG_P (src))
+       {
+         int dstreg = REGNO (dst);
+         int srcreg = REGNO (src);
+
+         /* hilo registers exchange their places,
+            and their order of Dimode as same as other
+            general registers in LITTLE_ENDIAN mode.  */
+         if (TARGET_BIG_ENDIAN)
+           {
+             if (dstreg == CSKY_HI_REGNUM)
+               return "mthi\t%1";
+             else if (dstreg == CSKY_LO_REGNUM)
+               return "mtlo\t%1";
+             else if (srcreg == CSKY_HI_REGNUM)
+               return "mfhi\t%0";
+             else if (srcreg == CSKY_LO_REGNUM)
+               return "mflo\t%0";
+           }
+         else
+           {
+             if (dstreg == CSKY_HI_REGNUM)
+               return "mtlo\t%1";
+             else if (dstreg == CSKY_LO_REGNUM)
+               return "mthi\t%1";
+             else if (srcreg == CSKY_HI_REGNUM)
+               return "mflo\t%0";
+             else if (srcreg == CSKY_LO_REGNUM)
+               return "mfhi\t%0";
+           }
+
+           if (CSKY_VREG_P (dstreg) && CSKY_VREG_P (srcreg))
+             return "fmovs\t%0, %1";
+           if (CSKY_VREG_P (dstreg))
+             return "fmtvrl\t%0, %1";
+           if (CSKY_VREG_P (srcreg))
+             return "fmfvrl\t%0, %1";
+
+           if (REGNO (src) == CSKY_CC_REGNUM)
+             return "mvc\t%0";
+           else
+             return "mov\t%0, %1";
+       }
+      /* The situation mov memory to reg.  */
+      else if (GET_CODE (src) == MEM)
+       {
+         decompose_csky_address (XEXP (src, 0), &op1);
+
+         if (op1.index)
+           switch (GET_MODE (src))
+             {
+             case E_HImode:
+               return "ldr.h\t%0, %1";
+             case E_QImode:
+               return "ldr.b\t%0, %1";
+             case E_SImode:
+             case E_SFmode:
+               if (CSKY_VREG_P (REGNO (dst)))
+                 return "fldrs\t%0, %1";
+               else
+                 return "ldr.w\t%0, %1";
+             default:
+               gcc_unreachable ();
+             }
+         /* Generate lrw rx, [LABEL].  This happens when the compiler
+            generates constant pool references and uses lrw to get the
+            constant into memory.  */
+         else if (op1.label)
+           return "lrw\t%0, %1";
+         /* Generate lrs.w rx, [symbol@GOT/PLT].  */
+         else if (flag_pic == 1 && op1.disp && GET_CODE (op1.disp) == UNSPEC)
+           return "lrs.w\t%0, %1";
+         else
+           switch (GET_MODE (src))
+             {
+             case E_HImode:
+               return "ld.h\t%0, %1";
+             case E_QImode:
+               return "ld.b\t%0, %1";
+             case E_SFmode:
+             case E_SImode:
+               if (CSKY_VREG_P (REGNO (dst)))
+                 return "flds\t%0, %1";
+               else
+                 return "ld.w\t%0, %1";
+             default:
+               gcc_unreachable ();
+             }
+       }
+      /* The situation mov integer to reg.  */
+      else if (GET_CODE (src) == CONST_INT ||
+              (GET_CODE (src) == CONST_DOUBLE && GET_MODE (src) == SFmode))
+       {
+         HOST_WIDE_INT x, y;
+         const REAL_VALUE_TYPE *d;
+         long l;
+
+         if (GET_CODE (src) == CONST_DOUBLE && GET_MODE (src) == SFmode)
+           {
+             d = CONST_DOUBLE_REAL_VALUE (src);
+             REAL_VALUE_TO_TARGET_SINGLE (*d, l);
+             operands[1] = GEN_INT (l);
+             src = operands[1];
+           }
+
+         if (try_csky_constant_tricks (INTVAL (src), &x, &y))
+           return csky_output_inline_const (SImode, operands);
+         /* Return '#' to split it.  */
+         else if (CSKY_CONST_OK_FOR_T (INTVAL (src)))
+           return "#";
+         else
+           return "lrw\t%0, %x1\t";
+       }
+      else if (TARGET_ANCHOR && GET_CODE (src) == SYMBOL_REF)
+       {
+         if (SYMBOL_REF_FUNCTION_P (src))
+           return "lrw\t%0, %1@BTEXT";
+         else
+           return "lrw\t%0, %1@BDATA";
+       }
+      else if (GET_CODE (src) == UNSPEC
+              && XINT (src, 1) == UNSPEC_PIC_SYMBOL_GRS)
+       return "grs\t%0, %1";
+      else
+       return "lrw\t%0, %1";
+    }
+  else if (GET_CODE (dst) == MEM)
+    {
+      decompose_csky_address (XEXP (dst, 0), &op0);
+
+      if (op0.index)
+       switch (GET_MODE (src))
+         {
+         case E_HImode:
+           return "str.h\t%1, %0";
+         case E_QImode:
+           return "str.b\t%1, %0";
+         case E_SFmode:
+         case E_SImode:
+           if (CSKY_VREG_P (REGNO (src)))
+             return "fstrs\t%1, %0";
+           else
+             return "str.w\t%1, %0";
+         default:
+           gcc_unreachable ();
+         }
+      else
+       switch (GET_MODE (dst))
+         {
+         case E_HImode:
+           return "st.h\t%1, %0";
+         case E_QImode:
+           return "st.b\t%1, %0";
+         case E_SImode:
+         case E_SFmode:
+           if (CSKY_VREG_P (REGNO (src)))
+             return "fsts\t%1, %0";
+           else
+             return "st.w\t%1, %0";
+         default:
+           gcc_unreachable ();
+         }
+    }
+
+  gcc_unreachable ();
+}
+
+
+/* Output a move of a word or less value.  Specific for ck801.  */
+
+const char *
+csky_output_ck801_move (rtx insn ATTRIBUTE_UNUSED, rtx operands[],
+                       machine_mode mode ATTRIBUTE_UNUSED)
+{
+  rtx dst = operands[0];
+  rtx src = operands[1];
+  struct csky_address op1;
+
+  if (REG_P (dst))
+    {
+      if (REG_P (src))
+       return "mov\t%0, %1";
+      else if (GET_CODE (src) == MEM)
+       {
+         decompose_csky_address (XEXP (src, 0), &op1);
+
+         /* Generate lrw rx, [LABEL].  This happens when the compiler
+            generates constant pool references and uses lrw to get the
+            constant in memory.  */
+         if (op1.label)
+           return "lrw\t%0, %1";
+         else
+           switch (GET_MODE (src))
+             {
+             case E_HImode:
+               return "ld.h\t%0, %1";
+             case E_QImode:
+               return "ld.b\t%0, %1";
+             case E_SFmode:
+             case E_SImode:
+               return "ld.w\t%0, %1";
+             default:
+               gcc_unreachable ();
+             }
+       }
+      else if (GET_CODE (src) == CONST_INT)
+       {
+         if (REGNO (dst) > 7)
+           return "lrw\t%0, %x1\t";
+         else if (CSKY_CONST_OK_FOR_N (INTVAL (src) + 1))
+           return "movi\t%0, %1";
+         /* Return '#' to split it.  */
+         else if (CSKY_CONST_OK_FOR_T (INTVAL (src)))
+           return "#";
+         else if (csky_shifted_imm8_constant (INTVAL (src), NULL, NULL))
+           return "#";
+         else
+           return "lrw\t%0, %x1\t";
+       }
+      else if (GET_CODE (src) == CONST_DOUBLE && GET_MODE (src) == SFmode)
+       {
+         const REAL_VALUE_TYPE *d;
+         long l;
+
+         d = CONST_DOUBLE_REAL_VALUE (src);
+         REAL_VALUE_TO_TARGET_SINGLE (*d, l);
+         operands[1] = GEN_INT (l);
+         src = operands[1];
+
+         if (CSKY_CONST_OK_FOR_N (INTVAL (src) + 1))
+           return "movi\t%0, %1";
+         else
+           return "lrw\t%0, %x1\t";
+       }
+      else if (TARGET_ANCHOR && GET_CODE (src) == SYMBOL_REF)
+       {
+         if (SYMBOL_REF_FUNCTION_P (src))
+           return "lrw\t%0, %1@BTEXT";
+         else
+           return "lrw\t%0, %1@BDATA";
+       }
+      else
+       return "lrw\t%0, %1";
+    }
+  else if (GET_CODE (dst) == MEM)
+    switch (GET_MODE (dst))
+      {
+      case E_HImode:
+       return "st.h\t%1, %0";
+      case E_QImode:
+       return "st.b\t%1, %0";
+      case E_SImode:
+      case E_SFmode:
+       return "st.w\t%1, %0";
+      default:
+       gcc_unreachable ();
+      }
+
+  gcc_unreachable ();
+}
+
+
+/* Return a sequence of instructions to perform DI or DF move.
+   Since the CSKY cannot move a DI or DF in one instruction, we have
+   to take care when we see overlapping source and dest registers.  */
+
+const char *
+csky_output_movedouble (rtx operands[],
+                       machine_mode mode ATTRIBUTE_UNUSED)
+{
+  rtx dst = operands[0];
+  rtx src = operands[1];
+
+  if (REG_P (dst))
+    {
+      if (REG_P (src))
+       {
+         int dstreg = REGNO (dst);
+         int srcreg = REGNO (src);
+
+         if (CSKY_HILO_REG_P (srcreg))
+           {
+             if (TARGET_BIG_ENDIAN)
+               return "mfhi\t%0\n\tmflo\t%R0";
+             else
+               return "mfhi\t%R0\n\tmflo\t%0";
+           }
+         else if (CSKY_HILO_REG_P (dstreg))
+           {
+             if (TARGET_BIG_ENDIAN)
+               return "mthi\t%1\n\tmtlo\t%R1";
+             else
+               return "mthi\t%R1\n\tmtlo\t%1";
+           }
+         else if (CSKY_VREG_P (srcreg) && CSKY_VREG_P (dstreg))
+           return "fmovd\t%0, %1";
+         else if (CSKY_VREG_P (srcreg))
+           {
+             /* Since the vector registers in fpuv2_soft processors
+                like ck803f are 32 bits wide, just one insn is needed
+                to complete the move operation.  */
+             if (TARGET_SOFT_FPU)
+                 return "fmfvrl\t%0, %1";
+             else if (TARGET_BIG_ENDIAN)
+               return "fmfvrh\t%0, %1\n\tfmfvrl\t%R0, %1";
+             else
+               return "fmfvrh\t%R0, %1\n\tfmfvrl\t%0, %1";
+           }
+         else if (CSKY_VREG_P (dstreg))
+           {
+             if (TARGET_SOFT_FPU)
+               return "fmtvrl\t%0, %1";
+             else if (TARGET_BIG_ENDIAN)
+               return "fmtvrh\t%0, %1\n\tfmtvrl\t%0, %R1";
+             else
+               return "fmtvrh\t%0, %R1\n\tfmtvrl\t%0, %1";
+           }
+
+         /* Ensure the second source not overwritten.  */
+         if (srcreg + 1 == dstreg)
+           return "mov\t%R0, %R1\n\tmov\t%0, %1";
+         else
+           return "mov\t%0, %1\n\tmov\t%R0, %R1";
+       }
+      else if (GET_CODE (src) == MEM)
+       {
+         rtx memexp = XEXP (src, 0);
+         int dstreg = REGNO (dst);
+         int basereg = -1;
+         struct csky_address op0;
+
+         decompose_csky_address (XEXP (src, 0), &op0);
+
+         if (GET_CODE (memexp) == LABEL_REF
+             || (GET_CODE (memexp) == CONST
+                 && GET_CODE (XEXP (memexp, 0)) == PLUS
+                 && GET_CODE (XEXP (XEXP (memexp, 0), 0)) == LABEL_REF))
+           return "lrw\t%0, [%1]\n\tlrw\t%R0, [%R1]";
+         else if (GET_CODE (memexp) == REG)
+           basereg = REGNO (memexp);
+         else if (GET_CODE (memexp) == PLUS)
+           {
+             if (GET_CODE (XEXP (memexp, 0)) == REG)
+               basereg = REGNO (XEXP (memexp, 0));
+             else if (GET_CODE (XEXP (memexp, 1)) == REG)
+               basereg = REGNO (XEXP (memexp, 1));
+             else
+               gcc_unreachable ();
+           }
+         else
+           gcc_unreachable ();
+
+
+         /* When FPUV2.  */
+         if (CSKY_VREG_P (dstreg))
+           {
+             if (op0.index)
+               return "fldrd\t%0, %1";
+             else
+               return "fldd\t%0, %1";
+           }
+         /* FIXME length attribute is wrong here.  */
+         if (dstreg == basereg)
+           /* Just load them in reverse order.  */
+           return "ld.w\t%R0, %R1\n\tld.w\t%0, %1";
+         else
+           return "ld.w\t%0, %1\n\tld.w\t%R0, %R1";
+       }
+      else if (GET_CODE (src) == CONST_INT || GET_CODE (src) == CONST_DOUBLE)
+       {
+         split_double (src, operands + 2, operands + 3);
+
+         if (CSKY_CONST_OK_FOR_I (INTVAL (operands[2])))
+           output_asm_insn ("movi\t%0, %2", operands);
+         else if (CSKY_CONST_OK_FOR_Uc (INTVAL (operands[2])))
+           output_asm_insn ("bmaski\t%0, %N2", operands);
+         else if (CSKY_CONST_OK_FOR_Ub (INTVAL (operands[2])))
+           output_asm_insn ("bgeni\t%0, %P2", operands);
+         else
+           output_asm_insn ("lrw\t%0, %2", operands);
+
+         if (CSKY_CONST_OK_FOR_I (INTVAL (operands[3])))
+           output_asm_insn ("movi\t%R0, %3", operands);
+         else if (CSKY_CONST_OK_FOR_Uc (INTVAL (operands[3])))
+           output_asm_insn ("bmaski\t%R0, %N3", operands);
+
+         else if (CSKY_CONST_OK_FOR_Ub (INTVAL (operands[3])))
+           output_asm_insn ("bgeni\t%R0, %P3", operands);
+         else
+           output_asm_insn ("lrw\t%R0, %3", operands);
+
+         return "";
+       }
+      else
+       gcc_unreachable ();
+    }
+  else if (GET_CODE (dst) == MEM && GET_CODE (src) == REG)
+    {
+      rtx memexp = XEXP (dst, 0);
+      int srcreg = REGNO (src);
+      int basereg = -1;
+      struct csky_address op0;
+
+      decompose_csky_address (XEXP (dst, 0), &op0);
+
+      if (GET_CODE (memexp) == REG)
+       basereg = REGNO (memexp);
+      else if (GET_CODE (memexp) == PLUS)
+       {
+         if (GET_CODE (XEXP (memexp, 0)) == REG)
+           basereg = REGNO (XEXP (memexp, 0));
+         else if (GET_CODE (XEXP (memexp, 1)) == REG)
+           basereg = REGNO (XEXP (memexp, 1));
+         else
+           gcc_unreachable ();
+       }
+      else
+       gcc_unreachable ();
+
+      /* When FPUV2.  */
+      if (CSKY_VREG_P (srcreg))
+       {
+         if (op0.index)
+           return "fstrd\t%1, %0";
+         else
+           return "fstd\t%1, %0";
+       }
+      /* FIXME length attribute is wrong here.  */
+      if (srcreg == basereg)
+       /* Just load them in reverse order.  */
+       return "st.w\t%R1, %R0\n\tst.w\t%1, %0";
+      else
+       return "st.w\t%1, %0\n\tst.w\t%R1, %R0";
+    }
+  else
+    gcc_unreachable ();
+}
+
+
+const char *
+csky_output_ck801_movedouble (rtx operands[],
+                             machine_mode mode ATTRIBUTE_UNUSED)
+{
+  rtx dst = operands[0];
+  rtx src = operands[1];
+
+  if (REG_P (dst))
+    {
+      if (REG_P (src))
+       {
+         int dstreg = REGNO (dst);
+         int srcreg = REGNO (src);
+
+         /* Ensure the second source not overwritten.  */
+         if (srcreg + 1 == dstreg)
+           return "mov\t%R0, %R1\n\tmov\t%0, %1";
+         else
+           return "mov\t%0, %1\n\tmov\t%R0, %R1";
+       }
+      else if (GET_CODE (src) == MEM)
+       {
+         rtx memexp = XEXP (src, 0);
+         int dstreg = REGNO (dst);
+         int basereg = -1;
+         struct csky_address op0;
+
+         decompose_csky_address (XEXP (src, 0), &op0);
+
+         if (GET_CODE (memexp) == LABEL_REF
+             || (GET_CODE (memexp) == CONST
+                 && GET_CODE (XEXP (memexp, 0)) == PLUS
+                 && GET_CODE (XEXP (XEXP (memexp, 0), 0)) == LABEL_REF))
+           return "lrw\t%0, [%1]\n\tlrw\t%R0, [%R1]";
+         else if (GET_CODE (memexp) == REG)
+           basereg = REGNO (memexp);
+         else if (GET_CODE (memexp) == PLUS)
+           {
+             if (GET_CODE (XEXP (memexp, 0)) == REG)
+               basereg = REGNO (XEXP (memexp, 0));
+             else if (GET_CODE (XEXP (memexp, 1)) == REG)
+               basereg = REGNO (XEXP (memexp, 1));
+             else
+               gcc_unreachable ();
+           }
+         else
+           gcc_unreachable ();
+
+         /* FIXME length attribute is wrong here.  */
+         if (dstreg == basereg)
+           /* Just load them in reverse order.  */
+           return "ld.w\t%R0, %R1\n\tld.w\t%0, %1";
+         else
+           return "ld.w\t%0, %1\n\tld.w\t%R0, %R1";
+       }
+      else if (GET_CODE (src) == CONST_INT || GET_CODE (src) == CONST_DOUBLE)
+       {
+         split_double (src, operands + 2, operands + 3);
+
+         if (REGNO (dst) <= 7
+             && CSKY_CONST_OK_FOR_N (INTVAL (operands[2]) + 1))
+           output_asm_insn ("movi\t%0, %2", operands);
+         else
+           output_asm_insn ("lrw\t%0, %2", operands);
+
+
+         if (REGNO (dst) <= 6
+             && CSKY_CONST_OK_FOR_N (INTVAL (operands[3]) + 1))
+           output_asm_insn ("movi\t%R0, %3", operands);
+         else
+           output_asm_insn ("lrw\t%R0, %3", operands);
+
+         return "";
+
+
+       }
+      else
+       gcc_unreachable ();
+    }
+  else if (GET_CODE (dst) == MEM && GET_CODE (src) == REG)
+    {
+      rtx memexp = XEXP (dst, 0);
+      int srcreg = REGNO (src);
+      int basereg = -1;
+      struct csky_address op0;
+
+      decompose_csky_address (XEXP (dst, 0), &op0);
+
+      if (GET_CODE (memexp) == REG)
+       basereg = REGNO (memexp);
+      else if (GET_CODE (memexp) == PLUS)
+       {
+         if (GET_CODE (XEXP (memexp, 0)) == REG)
+           basereg = REGNO (XEXP (memexp, 0));
+         else if (GET_CODE (XEXP (memexp, 1)) == REG)
+           basereg = REGNO (XEXP (memexp, 1));
+         else
+           gcc_unreachable ();
+       }
+      else
+       gcc_unreachable ();
+
+      /* FIXME length attribute is wrong here.  */
+      if (srcreg == basereg)
+       /* Just load them in reverse order.  */
+       return "st.w\t%R1, %R0\n\tst.w\t%1, %0";
+      else
+       return "st.w\t%1, %0\n\tst.w\t%R1, %R0";
+    }
+  else
+    gcc_unreachable ();
+}
+
+/* Split operands for an AND expression when OPERANDS[2] is a constant.
+   Note operands[0] is marked earlyclobber in this case and can be
+   overwritten.  Return true if "DONE", false otherwise.  */
+bool
+csky_split_and (rtx *operands)
+{
+  HOST_WIDE_INT mask = INTVAL (operands[2]);
+  rtx not_value = GEN_INT (~mask);
+  int i;
+
+  /* All zeros or all ones can be handled by a move instruction.  */
+  if (mask == 0)
+    {
+      emit_move_insn (operands[0], const0_rtx);
+      return true;
+    }
+  if (mask == -1)
+    {
+      emit_move_insn (operands[0], operands[1]);
+      return true;
+    }
+
+  /* Check for constants that can be handled directly by the 32-bit andi
+     instruction.  */
+  if (CSKY_ISA_FEATURE (E2) && csky_arith_O_operand (operands[2], SImode))
+    return false;
+
+  /* Try to transform to andni instruction.  */
+  if (CSKY_ISA_FEATURE (E2) && csky_arith_O_operand (not_value, SImode))
+    {
+      emit_insn (gen_cskyv2_andnsi3 (operands[0], not_value, operands[1]));
+      return true;
+    }
+
+  /* If there are only one or two 0 bits in the constant, we can
+     replace the operation with bclri instructions on those bits.
+     Note CK801 has only the 16-bit bclri that operates on a single
+     register, so we must count a move if we are post-reload.  */
+  if (popcount_hwi (~mask & 0xffffffff)
+      <= (reload_completed && !CSKY_ISA_FEATURE (E2) ? 1 : 2))
+    {
+      rtx input = operands[1];
+
+      if (!CSKY_ISA_FEATURE (E2))
+       {
+         emit_move_insn (operands[0], input);
+         input = operands[0];
+       }
+
+      for (i = 0; i < 32; i++)
+       if ((mask & (1 << i)) == 0x0)
+         {
+           emit_insn (gen_bclri (operands[0], input, GEN_INT (i)));
+           input = operands[0];
+         }
+      return true;
+    }
+
+  /* If the constant mask is outside the [0, 4095] range for
+     constraint O, or if constraint O is not allowed (ck801),
+     maybe the constant is a contiguous bit range that we can
+     handle by bit extract (low bits) or shifts (high bits).  */
+  for (i = (CSKY_ISA_FEATURE (E2) ? 13 : 1); i < 32; i++)
+    {
+      if ((((HOST_WIDE_INT) 1) << i) - 1 == mask)
+       {
+         if (CSKY_ISA_FEATURE (2E3))
+           emit_insn (gen_cskyv2_extzv (operands[0], operands[1],
+                                        GEN_INT (i), const0_rtx));
+         else
+           {
+             rtx shift = GEN_INT (32 - i);
+             rtx reg = (reload_completed
+                        ? operands[0] : gen_reg_rtx (SImode));
+
+             emit_insn (gen_ashlsi3 (reg, operands[1], shift));
+             emit_insn (gen_lshrsi3 (operands[0], reg, shift));
+           }
+         return true;
+       }
+      else if ((((HOST_WIDE_INT) 1) << i) - 1 == ~mask)
+       {
+         rtx shift = GEN_INT (i);
+         rtx reg = (reload_completed
+                    ? operands[0] : gen_reg_rtx (SImode));
+
+         emit_insn (gen_lshrsi3 (reg, operands[1], shift));
+         emit_insn (gen_ashlsi3 (operands[0], reg, shift));
+         return true;
+       }
+    }
+
+  /* If the constant is a negative number, it seems better to use
+     andn and copy the NOT_VALUE to a register instead of the
+     original value, since the NOT_VALUE is always smaller and thus
+     more likely to be representable as a small constant.
+     This transformation can only be done before reload because
+     it requires a temporary.  Hopefully register allocation can get
+     rid of the extra move required for CK801.  */
+  if (!reload_completed && INTVAL (operands[2]) < 0)
+    {
+      rtx reg = copy_to_mode_reg (SImode, not_value);
+
+      if (CSKY_ISA_FEATURE (E2))
+       emit_insn (gen_cskyv2_andnsi3 (operands[0], reg, operands[1]));
+      else
+       {
+         emit_move_insn (operands[0], operands[1]);
+         emit_insn (gen_ck801_andnsi3 (operands[0], reg, operands[0]));
+       }
+      return true;
+    }
+
+  /* If the above ways are all not working, move the constant
+     to a register.  We can clobber operands[0] as it is
+     marked earlyclobber in the insn constraints, but then we have to
+     swap operands 1 and 2 to match the constraints on the 2-operand
+     16-bit and instruction.  */
+  if (reload_completed)
+    {
+      emit_move_insn (operands[0], operands[2]);
+      operands[2] = operands[1];
+      operands[1] = operands[0];
+    }
+  else
+    operands[2] = copy_to_mode_reg (SImode, operands[2]);
+  return false;
+}
+
+/* Split operands for an IOR expression when OPERANDS[2] is a constant.
+   Note operands[0] is marked earlyclobber in this case and can be
+   overwritten.  Return true if "DONE", false otherwise.  */
+bool
+csky_split_ior (rtx *operands)
+{
+  HOST_WIDE_INT mask = INTVAL (operands[2]);
+  int i;
+
+  /* All zeros or all ones can be handled by a move instruction.  */
+  if (mask == 0)
+    {
+      emit_move_insn (operands[0], operands[1]);
+      return true;
+    }
+  if (mask == -1)
+    {
+      emit_move_insn (operands[0], gen_int_mode (-1, SImode));
+      return true;
+    }
+
+  /* Check for constants that can be handled directly by the 32-bit ori
+     instruction.  */
+  if (CSKY_ISA_FEATURE (E2) && csky_literal_I_operand (operands[2], SImode))
+    return false;
+
+  /* If there are only one or two 1 bits in the value, we can replace
+     the operation with bseti instructions to set those bits.
+     Note CK801 has only the 16-bit bclri that operates on a single
+     register, so we must count a move if we are post-reload.  */
+  if (popcount_hwi (mask & 0xffffffff)
+      <= (reload_completed && !CSKY_ISA_FEATURE (E2) ? 1 : 2))
+    {
+      rtx input = operands[1];
+
+      if (!CSKY_ISA_FEATURE (E2))
+       {
+         emit_move_insn (operands[0], input);
+         input = operands[0];
+       }
+
+      for (i = 0; i < 32; i++)
+       if (mask & (1 << i))
+         {
+           emit_insn (gen_bseti (operands[0], input, GEN_INT (i)));
+           input = operands[0];
+         }
+      return true;
+    }
+
+  /* If the above ways are all not working, move the constant
+     to a register.  We can clobber operands[0] as it is
+     marked earlyclobber in the insn constraints, but then we have to
+     swap operands 1 and 2 to match the constraints on the 2-operand
+     16-bit ior instruction.  */
+  if (reload_completed)
+    {
+      emit_move_insn (operands[0], operands[2]);
+      operands[2] = operands[1];
+      operands[1] = operands[0];
+    }
+  else
+    operands[2] = copy_to_mode_reg (SImode, operands[2]);
+  return false;
+}
+
+
+/* Split operands for an XOR expression when OPERANDS[2] is a constant.
+   Note operands[0] is marked earlyclobber in this case and can be
+   overwritten.  Return true if "DONE", false otherwise.  */
+bool
+csky_split_xor (rtx *operands)
+{
+  HOST_WIDE_INT mask = INTVAL (operands[2]);
+
+  /* All zeros can be turned into move instruction.  */
+  if (mask == 0)
+    {
+      emit_move_insn (operands[0], operands[1]);
+      return true;
+    }
+
+  /* All ones can be turned into a bitwise not.  */
+  if (mask == -1)
+    {
+      if (CSKY_ISA_FEATURE (E2))
+       emit_insn (gen_cskyv2_one_cmplsi2 (operands[0], operands[1]));
+      else
+       {
+         emit_move_insn (operands[0], operands[1]);
+         emit_insn (gen_ck801_one_cmplsi2 (operands[0], operands[0]));
+       }
+      return true;
+    }
+
+  /* Check for constants that can be handled directly by the 32-bit xori
+     instruction.  */
+  if (CSKY_ISA_FEATURE (E2) && csky_arith_O_operand (operands[2], SImode))
+    return false;
+
+  /* If the above ways are all not working, move the constant
+     to a register.  We can clobber operands[0] as it is
+     marked earlyclobber in the insn constraints, but then we have to
+     swap operands 1 and 2 to match the constraints on the 2-operand
+     16-bit ior instruction.  */
+  if (reload_completed)
+    {
+      emit_move_insn (operands[0], operands[2]);
+      operands[2] = operands[1];
+      operands[1] = operands[0];
+    }
+  else
+    operands[2] = copy_to_mode_reg (SImode, operands[2]);
+  return false;
+}
+
+
+/* Return true if X is an address form involving a symbol or label ref.  */
+bool
+csky_symbolic_address_p (rtx x)
+{
+  switch (GET_CODE (x))
+    {
+    case SYMBOL_REF:
+    case LABEL_REF:
+      return 1;
+    case CONST:
+      x = XEXP (x, 0);
+      return ((GET_CODE (XEXP (x, 0)) == SYMBOL_REF
+              || GET_CODE (XEXP (x, 0)) == LABEL_REF)
+             && GET_CODE (XEXP (x, 1)) == CONST_INT);
+    default:
+      return 0;
+    }
+}
+
+
+/* Emit a comparison instruction.
+   Return true if an inverted comparison is generated.  */
+
+bool
+csky_emit_compare (enum rtx_code code, rtx op0, rtx op1)
+{
+  bool invert;
+  rtx cc_reg = gen_rtx_REG (CCmode, CSKY_CC_REGNUM);
+
+  if (GET_CODE (op1) == CONST_INT)
+    {
+      HOST_WIDE_INT val = INTVAL (op1);
+
+      switch (code)
+       {
+       case GTU:
+         /* Unsigned (GTU 0) is the same as (NE 0); everything else is
+            converted below to LEU (reversed cmphs).  */
+         if (val == 0)
+           code = NE;
+         /* Check whether (GTU A imm) can become (GEU A  imm + 1).  */
+         else if (TARGET_MINI_REGISTERS
+                  ? CSKY_CONST_OK_FOR_J (val + 1)
+                  : CSKY_CONST_OK_FOR_Uk (val + 1))
+           {
+             op1 = GEN_INT (val + 1);
+             code = GEU;
+           }
+         break;
+       /* Check whether (LE A imm) can become (LT A imm + 1),
+          or (GT A imm) can become (GE A imm + 1).  */
+       case GT:
+       case LE:
+         if (TARGET_MINI_REGISTERS
+             ? CSKY_CONST_OK_FOR_J (val + 1)
+             : CSKY_CONST_OK_FOR_Uk (val + 1))
+           {
+             op1 = GEN_INT (val + 1);
+             code = code == LE ? LT : GE;
+           }
+         break;
+
+       default:
+         break;
+       }
+    }
+
+  if (CONSTANT_P (op1) && GET_CODE (op1) != CONST_INT)
+    op1 = force_reg (GET_MODE (op1), op1);
+
+  /* cmpnei: 0-31 (K immediate)
+     ti: 1-32 (J immediate, 0 using btsti x,31).  */
+  invert = false;
+  switch (code)
+    {
+      /* Use inverted condition, cmpne.  */
+      case EQ:
+       code = NE;
+       invert = true;
+      /* Fall through.  */
+      /* Use normal condition, cmpne.  */
+      case NE:
+       if (GET_CODE (op1) == CONST_INT
+           && (TARGET_MINI_REGISTERS
+               ? !csky_literal_K_operand (op1, SImode)
+               : !csky_literal_I_operand (op1, SImode)))
+         op1 = force_reg (SImode, op1);
+      break;
+
+      /* Use inverted condition, reversed cmplt.  */
+      case LE:
+       code = GT;
+       invert = true;
+      /* Fall through.  */
+      /* Use normal condition, reversed cmplt.  */
+      case GT:
+       if (GET_CODE (op1) == CONST_INT)
+         op1 = force_reg (SImode, op1);
+      break;
+
+      /* Use inverted condition, cmplt.  */
+      case GE:
+       code = LT;
+       invert = true;
+      /* Fall through.  */
+      /* Use normal condition, cmplt.  */
+      case LT:
+       /* covered by btsti x,31.  */
+       if (GET_CODE (op1) == CONST_INT && INTVAL (op1) != 0
+           && (TARGET_MINI_REGISTERS
+               ? !csky_literal_J_operand (op1, SImode)
+               : !csky_literal_Uk_operand (op1, SImode)))
+         op1 = force_reg (SImode, op1);
+       break;
+
+      /* Use inverted condition, cmple.  */
+      case GTU:
+       /* We coped with unsigned > 0 above.  */
+       gcc_assert (GET_CODE (op1) != CONST_INT || INTVAL (op1) != 0);
+       code = LEU;
+       invert = true;
+      /* Fall through.  */
+      /* Use normal condition, reversed cmphs.  */
+      case LEU:
+       if (GET_CODE (op1) == CONST_INT && INTVAL (op1) != 0)
+         op1 = force_reg (SImode, op1);
+       break;
+
+      /* Use inverted condition, cmphs.  */
+      case LTU:
+       code = GEU;
+       invert = true;
+      /* Fall through.  */
+      /* Use normal condition, cmphs.  */
+      case GEU:
+       if (GET_CODE (op1) == CONST_INT && INTVAL (op1) != 0
+           && (TARGET_MINI_REGISTERS
+               ? !csky_literal_J_operand (op1, SImode)
+               : !csky_literal_Uk_operand (op1, SImode)))
+         op1 = force_reg (SImode, op1);
+      break;
+
+    default:
+      break;
+    }
+
+  emit_insn (gen_rtx_SET (cc_reg,
+                         gen_rtx_fmt_ee (code, CCmode, op0, op1)));
+  return invert;
+}
+
+/* Return true if push/pop can be used to save/restore all the registers
+   indicated by MASK.  We currently don't attempt to handle situations where
+   some of the registers could be handled by push/pop and others saved and
+   restored individually.  */
+
+static bool
+csky_can_use_pushpop (unsigned int mask)
+{
+  int i;
+  int end_reg;
+
+  if (!TARGET_PUSHPOP)
+    return false;
+
+  if (mask == 0)
+    return false;
+
+  /* Regs 0-3, 12-14, 18-27, 29-31 cannot be in the mask.  */
+  if (mask & 0xeffc700f)
+    return false;
+
+  /* Regs in the range r4-r11 must be contiguous.  */
+  for (end_reg = 0, i = 11; i >= 4; i--)
+    {
+      if (!end_reg && (mask & (1 << i)))
+       end_reg = i;
+      if (end_reg && !(mask & (1 << i)))
+       return false;
+    }
+
+  /* Likewise for regs in the range r16-r17.  */
+  for (end_reg = 0, i = 17; i >= 16; i--)
+    {
+      if (!end_reg && (mask & (1 << i)))
+       end_reg = i;
+      if (end_reg && !(mask & (1 << i)))
+       return false;
+    }
+
+  return true;
+}
+
+
+/* Return true if store/load multiple instructions can be used to
+   save/restore at least some of the registers indicated by MASK.
+   Unlike the push/pop case, this does handle partial ranges.
+   Set *BR and *ER to the beginning and end (respectively) of the
+   register range that can be handled.  */
+
+static bool
+csky_can_use_ldstm (int mask, int *br, int *er)
+{
+  int regno;
+  int begin_reg = 0, end_reg = 0;
+  int count = 0;
+
+  if (!TARGET_MULTIPLE_STLD)
+    return false;
+
+  /* We'll only handle registers in the range 4-11, the contiguous range
+     of caller-saved registers.  Higher-numbered registers are handled
+     individually in addition to this, but we'll give up on doing ldstm
+     entirely if we need to save/restore the low-numbered EH registers.  */
+  if (mask & 0xf)
+    return false;
+
+  for (regno = 4; regno <= 11; regno++)
+    {
+      if (mask & 1 << regno)
+       {
+         if (!begin_reg)
+           begin_reg = regno;
+         end_reg = regno;
+         count++;
+       }
+      else if (begin_reg)
+       break;
+    }
+
+  if (count >= CSKY_MIN_MULTIPLE_STLD && count <= CSKY_MAX_MULTIPLE_STLD)
+    {
+      if (br)
+       *br = begin_reg;
+      if (er)
+       *er = end_reg;
+      return true;
+    }
+  return false;
+}
+
+
+const char *
+csky_output_return_instruction (void)
+{
+  unsigned long func_type = get_csky_current_func_type ();
+
+  if (CSKY_FUNCTION_IS_NAKED (func_type))
+    return "";
+  if (CSKY_FUNCTION_IS_INTERRUPT (func_type))
+    return "ipop\n\tnir\n";
+  else
+    return "rts\n";
+}
+
+
+/* Adjust the stack pointer by OFFSET bytes.  OFFSET is negative if this
+   is in the prologue, positive if in the epilogue.  This may require
+   multiple instructions and/or use of CSKY_STACKADJUST_REGNUM as
+   a scratch register.  Emit CFA notes as appropriate.  */
+static void
+expand_csky_stack_adjust (int offset)
+{
+  rtx set;
+  rtx_insn *insn;
+  int size = (offset > 0 ? offset : -offset);
+
+  if (offset == 0)
+    return;
+
+  /* If OFFSET is too large for addi/subi, load it into
+     CSKY_STACKADJUST_REGNUM and use a register add/sub instead.
+     This case is not mentioned in the ABI documentation, but it is
+     supported by GDB prologue analysis provided that the instruction(s)
+     to initialize CSKY_STACKADJUST_REGNUM appear directly before
+     the sub.  Depending on the value of OFFSET, this might be a
+     lrw instruction or the "tricks" used by csky_output_inline_const to
+     encode special-case integer constants.  */
+  if (size > CSKY_MAX_SP_ADJUST * 2)
+    {
+      rtx tmp, dwarf;
+
+      /* We should have reserved the scratch register already in
+        csky_layout_stack_frame.  */
+      gcc_assert (cfun->machine->reg_size != 0
+                 && (cfun->machine->reg_mask
+                     & (1 << CSKY_STACKADJUST_REGNUM)));
+
+      /* Prevent the optimizer from reordering these instructions to
+        keep GDB happy.  */
+      if (!flag_sched_prolog)
+       emit_insn (gen_blockage ());
+
+      tmp = gen_rtx_REG (SImode, CSKY_STACKADJUST_REGNUM);
+      emit_move_insn (tmp, GEN_INT (size));
+
+      if (offset > 0)
+       set = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, tmp);
+      else
+       set = gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, tmp);
+      insn = emit_insn (set);
+      RTX_FRAME_RELATED_P (insn) = 1;
+      dwarf = gen_rtx_SET (stack_pointer_rtx,
+                          plus_constant (Pmode, stack_pointer_rtx, offset));
+      add_reg_note (insn, REG_FRAME_RELATED_EXPR, dwarf);
+
+      /* More make GDB happy.  */
+      if (!flag_sched_prolog)
+       emit_insn (gen_blockage ());
+    }
+
+  /* Use one or two addi or subi insns to adjust stack.  */
+  else
+    while (size)
+      {
+       int delta = (size > CSKY_MAX_SP_ADJUST
+                    ? CSKY_MAX_SP_ADJUST : size);
+
+       if (offset > 0)
+         set = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
+                           GEN_INT (delta));
+       else
+         set = gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
+                           GEN_INT (delta));
+       insn = emit_insn (set);
+       RTX_FRAME_RELATED_P (insn) = 1;
+       size -= delta;
+      }
+}
+
+
+/* Generate and emit an insn that we will recognize as a push_multi.
+   Unfortunately, since this insn does not reflect very well the actual
+   semantics of the operation, we need to annotate the insn for the benefit
+   of DWARF2 frame unwind information.  DWARF_REGS_MASK is a subset of
+   MASK for registers that should be annotated for DWARF2 frame unwind
+   information.  */
+
+static rtx
+emit_csky_regs_push (unsigned long mask)
+{
+  int num_regs = 0;
+  int i, j;
+  rtx par;
+  rtx dwarf;
+  rtx tmp;
+  int dwarf_par_index;
+
+  for (i = 0; i < CSKY_NGPR_REGS; i++)
+    {
+      if (mask & (1 << i))
+       num_regs++;
+    }
+
+  /* The reg range for push is:r4-r11,r15-r17,r28.  */
+  gcc_assert (num_regs && num_regs <= 12);
+
+  /* For the body of the insn we are going to generate an UNSPEC in
+     parallel with several USEs.  This allows the insn to be recognized
+     by the push_multi pattern in the csky.md file.
+
+     The body of the insn looks something like this:
+
+       (parallel [
+          (set (mem:BLK (pre_modify:SI (reg:SI sp)
+                                       (const_int:SI <num>)))
+               (unspec:BLK [(reg:SI r4)] UNSPEC_PUSHPOP_MULT))
+          (use (reg:SI XX))
+          (use (reg:SI YY))
+          ...
+       ])
+
+     For the frame note however, we try to be more explicit and actually
+     show each register being stored into the stack frame, plus a (single)
+     decrement of the stack pointer.  We do it this way in order to be
+     friendly to the stack unwinding code, which only wants to see a single
+     stack decrement per instruction.  The RTL we generate for the note looks
+     something like this:
+
+      (sequence [
+          (set (reg:SI sp) (plus:SI (reg:SI sp) (const_int -20)))
+          (set (mem:SI (reg:SI sp)) (reg:SI r4))
+          (set (mem:SI (plus:SI (reg:SI sp) (const_int 4))) (reg:SI XX))
+          (set (mem:SI (plus:SI (reg:SI sp) (const_int 8))) (reg:SI YY))
+          ...
+       ])
+
+     FIXME:: In an ideal world the PRE_MODIFY would not exist and
+     instead we'd have a parallel expression detailing all
+     the stores to the various memory addresses so that debug
+     information is more up-to-date. Remember however while writing
+     this to take care of the constraints with the push instruction.
+
+     Note also that this has to be taken care of for the VFP registers.
+
+     For more see PR43399.  */
+
+  par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num_regs));
+  dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (num_regs + 1));
+  dwarf_par_index = 1;
+
+  for (i = 0; i < CSKY_NGPR_REGS; i++)
+    if (mask & (1 << i))
+      {
+       rtx reg = gen_rtx_REG (SImode, i);
+       rtx addr = plus_constant (Pmode, stack_pointer_rtx, -4 * num_regs);
+       tmp = gen_frame_mem (BLKmode,
+                            gen_rtx_PRE_MODIFY (Pmode,
+                                                stack_pointer_rtx, addr));
+       XVECEXP (par, 0, 0)
+         = gen_rtx_SET (tmp,
+                        gen_rtx_UNSPEC (BLKmode,
+                                        gen_rtvec (1, reg),
+                                        UNSPEC_PUSHPOP_MULT));
+       tmp = gen_rtx_SET (gen_frame_mem (SImode, stack_pointer_rtx),
+                          reg);
+       RTX_FRAME_RELATED_P (tmp) = 1;
+       XVECEXP (dwarf, 0, dwarf_par_index++) = tmp;
+
+       break;
+      }
+
+  for (j = 1, i++; j < num_regs; i++)
+    if (mask & (1 << i))
+      {
+       rtx reg = gen_rtx_REG (SImode, i);
+       rtx addr = plus_constant (Pmode, stack_pointer_rtx, 4 * j);
+       tmp = gen_rtx_SET (gen_frame_mem (SImode, addr), reg);
+       RTX_FRAME_RELATED_P (tmp) = 1;
+       XVECEXP (par, 0, j) = gen_rtx_USE (VOIDmode, reg);
+       XVECEXP (dwarf, 0, dwarf_par_index++) = tmp;
+       j++;
+      }
+
+  par = emit_insn (par);
+
+  tmp = gen_rtx_SET (stack_pointer_rtx,
+                    plus_constant (Pmode, stack_pointer_rtx, -4 * num_regs));
+  RTX_FRAME_RELATED_P (tmp) = 1;
+  XVECEXP (dwarf, 0, 0) = tmp;
+
+  add_reg_note (par, REG_FRAME_RELATED_EXPR, dwarf);
+  RTX_FRAME_RELATED_P (par) = 1;
+
+  return par;
+}
+
+
+/* Generate and emit an insn pattern that we will recognize as a pop_multi.
+   SAVED_REGS_MASK shows which registers need to be restored.
+
+   Unfortunately, since this insn does not reflect very well the actual
+   semantics of the operation, we need to annotate the insn for the benefit
+   of DWARF2 frame unwind information.  */
+
+static void
+emit_csky_regs_pop (unsigned long mask)
+{
+  int num_regs = 0;
+  int i, j;
+  rtx par;
+
+  for (i = 0; i < CSKY_NGPR_REGS; i++)
+    if (mask & (1 << i))
+      num_regs++;
+
+  /* The reg range for push is:r4-r11,r15-r17,r28.  */
+  gcc_assert (num_regs && num_regs <= 12);
+
+  /* The first element is (return),
+     the second element is
+       (set (reg:SI 'first reg number')
+           (unspec:SI [(mem)] UNSPEC_PUSHPOP_MULT),
+     the rest elements is (use (reg:SI 'rest reg number')),
+     so the length should be number of register to be poped
+     plus one.  */
+  par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num_regs + 1));
+
+  XVECEXP (par, 0, 0) = ret_rtx;
+
+  for (i = 0; i < CSKY_NGPR_REGS; i++)
+    if (mask & (1 << i))
+      {
+       rtx reg = gen_rtx_REG (SImode, i);
+       rtx addr = plus_constant (Pmode, stack_pointer_rtx, 4 * num_regs);
+       rtx tmp = gen_frame_mem (SImode,
+                                gen_rtx_POST_MODIFY (Pmode,
+                                                     stack_pointer_rtx, addr));
+       XVECEXP (par, 0, 1)
+         = gen_rtx_SET (reg,
+                        gen_rtx_UNSPEC (SImode,
+                                        gen_rtvec (1, tmp),
+                                        UNSPEC_PUSHPOP_MULT));
+       break;
+      }
+
+  for (j = 2, i++; j < (num_regs + 1); i++)
+    if (mask & (1 << i))
+      {
+       rtx reg = gen_rtx_REG (SImode, i);
+       XVECEXP (par, 0, j) = gen_rtx_USE (VOIDmode, reg);
+       j++;
+      }
+
+  par = emit_jump_insn (par);
+}
+
+
+/* Generate the function prologue.  */
+
+void
+csky_expand_prologue (void)
+{
+  rtx_insn *insn;
+  unsigned long func_type = get_csky_current_func_type ();
+  unsigned int reg_mask;
+  int reg_size;
+
+  if (CSKY_FUNCTION_IS_NAKED (func_type))
+    {
+      if (flag_stack_usage_info)
+       current_function_static_stack_size = 0;
+      return;
+    }
+
+  csky_layout_stack_frame ();
+  reg_mask = cfun->machine->reg_mask;
+  reg_size = cfun->machine->reg_size;
+
+  /* Adjust stack pointer past argument overflow area.  */
+  if (cfun->machine->arg_size != 0)
+    {
+      int offset = cfun->machine->arg_size;
+      expand_csky_stack_adjust (- offset);
+
+      /* If we have a parameter passed partially in regs and partially
+        in memory, the registers will have been stored to memory already
+        in function.c.  So we only need to copy varargs from registers
+        to stack.  */
+      if (cfun->machine->uses_anonymous_args)
+       {
+         int rn = CSKY_FIRST_PARM_REGNUM + CSKY_NPARM_REGS - 1;
+         for (offset -= 4; offset >= 0; offset -= 4, rn--)
+           {
+             rtx dst = gen_frame_mem (SImode,
+                                      plus_constant (Pmode,
+                                                     stack_pointer_rtx,
+                                                     offset));
+             insn = emit_move_insn (dst, gen_rtx_REG (SImode, rn));
+             RTX_FRAME_RELATED_P (insn) = 1;
+           }
+       }
+    }
+
+  /* Push caller-saved registers to stack.  */
+  if (csky_can_use_pushpop (reg_mask))
+    emit_csky_regs_push (reg_mask);
+  else if (reg_size)
+    {
+      int sreg = -1, ereg = -1;
+      bool stm_p = csky_can_use_ldstm (reg_mask, &sreg, &ereg);
+      int stm_regs = stm_p ? ereg - sreg + 1 : 0;
+      int stm_size = stm_regs * 4;
+
+      /* First adjust the SP to the low end of the register save area.  */
+      expand_csky_stack_adjust (- reg_size);
+
+      /* Emit individual register saves.  Even if we are going to emit an
+        stm, we may need to save individual registers above that too.  */
+      if (reg_size > stm_size)
+       {
+         int offset = reg_size - 4;
+         int regno = 31;
+         for ( ; regno > ereg; regno--)
+           if (reg_mask & (1 << regno))
+             {
+               rtx dst = gen_rtx_MEM (SImode,
+                                      plus_constant (Pmode,
+                                                     stack_pointer_rtx,
+                                                     offset));
+               rtx insn = emit_insn (gen_movsi (dst,
+                                                gen_rtx_REG (SImode, regno)));
+               RTX_FRAME_RELATED_P (insn) = 1;
+               if (offset == stm_size)
+                 break;
+               offset -= 4;
+             }
+       }
+
+      /* If possible, emit a stm to do a bulk store of sequential
+        registers to the stack.  Note that it is an error in the ABI
+        documentation that it doesn't list stm as a valid prologue
+        instruction.  */
+      if (stm_p)
+       {
+         rtx par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (stm_regs));
+         int regno, slot;
+         for (regno = sreg, slot = 0; regno <= ereg; regno++, slot++)
+           {
+             rtx reg = gen_rtx_REG (SImode, regno);
+             rtx addr = plus_constant (Pmode, stack_pointer_rtx, slot * 4);
+             rtx set = gen_rtx_SET (gen_frame_mem (SImode, addr), reg);
+             RTX_FRAME_RELATED_P (set) = 1;
+             XVECEXP (par, 0, slot) = set;
+           }
+         insn = emit_insn (par);
+         RTX_FRAME_RELATED_P (insn) = 1;
+       }
+    }
+
+  /* Initialize hard frame pointer, if necessary.  It points at the base
+     of the register save area.  */
+  if (frame_pointer_needed)
+    {
+      insn = emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx));
+      RTX_FRAME_RELATED_P (insn) = 1;
+    }
+
+  /* Reserve stack space for locals and outgoing args.  */
+  expand_csky_stack_adjust (- cfun->machine->reg_offset);
+
+  /* Put the GOT address in reg_gb for PIC, using R13 as a scratch.
+     See section 4.7.1 in  the ABI documentation,
+     "Function Prologue for PIC".  */
+  if (flag_pic && (reg_mask & (1 << PIC_OFFSET_TABLE_REGNUM)))
+    {
+      rtx l1 = gen_label_rtx ();
+      rtx grs_label = gen_rtx_LABEL_REF (SImode, l1);
+      rtx reg_gb = gen_rtx_REG (SImode, PIC_OFFSET_TABLE_REGNUM);
+      rtx reg_temp = gen_rtx_REG (SImode, 13);
+
+      rtx tmp0_unspec = gen_rtx_UNSPEC (Pmode,
+                                       gen_rtvec (1, grs_label),
+                                       UNSPEC_PIC_SYMBOL_GOTPC_GRS);
+      rtx tmp1_unspec = gen_rtx_UNSPEC (Pmode,
+                                       gen_rtvec (1, grs_label),
+                                       UNSPEC_PIC_SYMBOL_GOTPC);
+
+      emit_insn (gen_prologue_get_pc (tmp0_unspec));
+      emit_move_insn (reg_temp, tmp1_unspec);
+      emit_insn (gen_addsi3 (reg_gb, reg_gb, reg_temp));
+    }
+
+  if (flag_stack_usage_info)
+    current_function_static_stack_size = cfun->machine->frame_size;
+
+  if (!flag_sched_prolog)
+    emit_insn (gen_blockage ());
+}
+
+void
+csky_expand_epilogue (void)
+{
+  unsigned long func_type = get_csky_current_func_type ();
+  unsigned int reg_mask;
+  int reg_size;
+  int adjust;
+  rtx_insn *insn;
+
+  if (!flag_sched_prolog)
+    emit_insn (gen_blockage ());
+
+  if (CSKY_FUNCTION_IS_NAKED (func_type))
+    {
+      emit_jump_insn (gen_simple_return ());
+      return;
+    }
+
+  /* Get the frame information.  */
+  csky_layout_stack_frame ();
+  reg_mask = cfun->machine->reg_mask;
+  reg_size = cfun->machine->reg_size;
+  adjust = reg_size + cfun->machine->arg_size;
+
+  /* Restore the SP to the base of the register save area.  */
+  if (frame_pointer_needed)
+    {
+      insn = emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
+      RTX_FRAME_RELATED_P (insn) = 1;
+    }
+  else
+    expand_csky_stack_adjust (cfun->machine->reg_offset);
+
+  /* Restore the callee-saved registers.  */
+  if (csky_can_use_pushpop (reg_mask)
+      && cfun->machine->arg_size == 0
+      && !CSKY_FUNCTION_IS_INTERRUPT (func_type)
+      && !crtl->calls_eh_return)
+    {
+      /* Pop includes an implicit return, so we are done.  */
+      emit_csky_regs_pop (reg_mask);
+      return;
+    }
+  else if (reg_size)
+    {
+      int sreg = -1, ereg = -1;
+      bool ldm_p = csky_can_use_ldstm (reg_mask, &sreg, &ereg);
+      int ldm_regs = ldm_p ? ereg - sreg + 1 : 0;
+      int ldm_size = ldm_regs * 4;
+
+      /* Emit individual register loads.  Even if we are going to emit an
+        ldm, we may need to load individual registers above that too.  */
+      if (reg_size > ldm_size)
+       {
+         int offset = reg_size - 4;
+         int regno = 31;
+         for ( ; regno > ereg; regno--)
+           if (reg_mask & (1 << regno))
+             {
+               rtx src = gen_frame_mem (SImode,
+                                        plus_constant (Pmode,
+                                                       stack_pointer_rtx,
+                                                       offset));
+               rtx reg = gen_rtx_REG (SImode, regno);
+               insn = emit_move_insn (reg, src);
+               RTX_FRAME_RELATED_P (insn) = 1;
+               add_reg_note (insn, REG_CFA_RESTORE, reg);
+               if (offset == ldm_size)
+                 break;
+               offset -= 4;
+             }
+       }
+
+      /* If possible, emit a ldm to do a bulk load of sequential
+        registers from the stack.  */
+      if (ldm_p)
+       {
+         rtx par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (ldm_regs));
+         int regno, slot;
+         for (regno = sreg, slot = 0; regno <= ereg; regno++, slot++)
+           {
+             rtx reg = gen_rtx_REG (SImode, regno);
+             rtx addr = plus_constant (Pmode, stack_pointer_rtx, slot * 4);
+             rtx set = gen_rtx_SET (reg, gen_frame_mem (SImode, addr));
+             XVECEXP (par, 0, slot) = set;
+           }
+         insn = emit_insn (par);
+         RTX_FRAME_RELATED_P (insn) = 1;
+         for (regno = sreg; regno <= ereg; regno++)
+           {
+             rtx reg = gen_rtx_REG (SImode, regno);
+             add_reg_note (insn, REG_CFA_RESTORE, reg);
+           }
+       }
+    }
+
+  /* Emit the final stack pointer adjustment to deallocate the saved
+     registers and incoming argument area.  */
+  expand_csky_stack_adjust (adjust);
+
+  /* Extra stack adjustment for exception handler return.  */
+  if (crtl->calls_eh_return)
+    emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
+                          EH_RETURN_STACKADJ_RTX));
+
+  /* Now we can return.  */
+  emit_jump_insn (gen_simple_return ());
+}
+
+
+static void
+csky_output_function_prologue (FILE *f)
+{
+  unsigned long func_type = get_csky_current_func_type ();
+
+  switch ((int) CSKY_FUNCTION_TYPE (func_type))
+    {
+    default:
+    case CSKY_FT_NORMAL:
+      break;
+    case CSKY_FT_INTERRUPT:
+      {
+       asm_fprintf (f, "\t# Interrupt Service Routine.\n");
+       asm_fprintf (f, "\tnie\n\tipush\n");
+       break;
+      }
+    case CSKY_FT_FIQ:
+      asm_fprintf (f, "\t# Fast Interrupt Service Routine.\n");
+      break;
+    case CSKY_FT_EXCEPTION:
+      asm_fprintf (f, "\t# CSKY Exception Handler.\n");
+      break;
+    case CSKY_FT_NAKED:
+      asm_fprintf (f, "\t# Naked Function: prologue and epilogue \
+                     provided by programmer.\n");
+      return;
+    }
+
+  csky_layout_stack_frame ();
+
+  /* Generate .stack_size function-name, size for callgraph;
+     the default stack size is 0.  */
+  if (TARGET_STACK_SIZE && cfun->machine->frame_size > 0)
+    {
+      gcc_assert (current_function_decl != NULL);
+      const char *func_name =
+         IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl));
+      if (func_name[0] == '*')
+       asm_fprintf (f, "\t.stack_size %s, %d\n",
+                    &func_name[1], cfun->machine->frame_size);
+      else
+       asm_fprintf (f, "\t.stack_size %s, %d\n",
+                    func_name, cfun->machine->frame_size);
+    }
+}
+
+
+static void
+csky_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED)
+{
+
+}
+
+
+/* Helper for csky_eh_return splitter: store the call frame exception
+   handler address in lr.  */
+void
+csky_set_eh_return_address (rtx source, rtx scratch)
+{
+  HOST_WIDE_INT delta = 0;
+  rtx basereg, addr;
+  unsigned int reg_mask;
+
+  csky_layout_stack_frame ();
+  reg_mask = cfun->machine->reg_mask;
+
+  if (reg_mask & (1 << CSKY_LR_REGNUM))
+    {
+      /* Find LR in the stack frame.  */
+      int i = 0;
+
+      if (frame_pointer_needed)
+       {
+         basereg = frame_pointer_rtx;
+         delta = 0;
+       }
+      else
+       {
+         basereg = stack_pointer_rtx;
+         delta = cfun->machine->reg_offset;
+       }
+
+      /* At this point, (basereg + delta) points at the low end of
+        the reg save area.  Regs are saved sequentially from low
+        to high from this address.  */
+      for (i = 0; i < CSKY_LR_REGNUM; i++)
+       if (reg_mask & (1 << i))
+         delta += 4;
+
+      if ((CSKY_TARGET_ARCH (CK801) && delta >= CSKY_LD16_MAX_OFFSET (Pmode))
+         || delta >= CSKY_LD32_MAX_OFFSET (Pmode))
+       {
+         emit_insn (gen_movsi (scratch, GEN_INT (delta)));
+         emit_insn (gen_addsi3 (scratch, scratch, basereg));
+         addr = scratch;
+       }
+      else
+       addr = plus_constant (Pmode, basereg, delta);
+      emit_move_insn (gen_frame_mem (Pmode, addr), source);
+    }
+  else
+    emit_move_insn (gen_rtx_REG (Pmode, CSKY_LR_REGNUM), source);
+}
+
+/* Return TRUE if X references a SYMBOL_REF.  */
+
+bool
+csky_symbol_mentioned_p (rtx x)
+{
+  const char *fmt;
+  int i;
+
+  if (GET_CODE (x) == SYMBOL_REF)
+    return true;
+
+  fmt = GET_RTX_FORMAT (GET_CODE (x));
+  for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'E')
+       {
+         int j;
+
+         for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+           if (csky_symbol_mentioned_p (XVECEXP (x, i, j)))
+             return true;
+       }
+      else if (fmt[i] == 'e' && csky_symbol_mentioned_p (XEXP (x, i)))
+       return true;
+    }
+  return false;
+}
+
+
+/* Return TRUE if X references a LABEL_REF.  */
+
+bool
+csky_label_mentioned_p (rtx x)
+{
+  const char *fmt;
+  int i;
+
+  if (GET_CODE (x) == LABEL_REF)
+    return true;
+
+  fmt = GET_RTX_FORMAT (GET_CODE (x));
+  for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'E')
+       {
+         int j;
+
+         for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+           if (csky_label_mentioned_p (XVECEXP (x, i, j)))
+             return true;
+       }
+      else if (fmt[i] == 'e' && csky_label_mentioned_p (XEXP (x, i)))
+       return true;
+    }
+
+  return false;
+}
+
+
+static bool
+tls_unspec_mentioned_p (rtx x)
+{
+  switch (GET_CODE (x))
+    {
+    case CONST:
+      return tls_unspec_mentioned_p (XEXP (x, 0));
+
+    case UNSPEC:
+      if (XINT (x, 1) == UNSPEC_TLS)
+       return true;
+
+    /* Fall through.  */
+    default:
+      return false;
+    }
+}
+
+
+/* Implement LEGITIMATE_PIC_OPERAND_P.  */
+bool
+csky_legitimate_pic_operand_p (rtx x)
+{
+  if (tls_unspec_mentioned_p (x))
+    return true;
+  if (csky_symbol_mentioned_p (x) || csky_label_mentioned_p (x))
+    return false;
+  return true;
+}
+
+rtx
+csky_legitimize_pic_address (rtx orig, rtx reg, bool gotrel_p)
+{
+  rtx pic_reg = gen_rtx_REG (SImode, PIC_OFFSET_TABLE_REGNUM);
+  bool optimize_p = false;
+
+  if (GET_CODE (orig) == SYMBOL_REF || GET_CODE (orig) == LABEL_REF)
+    {
+      rtx pic_ref, address, rtx_tmp;
+      rtx insn;
+      rtx pic_reg = gen_rtx_REG (SImode, PIC_OFFSET_TABLE_REGNUM);
+      int subregs = 0;
+
+      if (reg == 0)
+       {
+         gcc_assert (can_create_pseudo_p ());
+         reg = gen_reg_rtx (Pmode);
+         subregs = 1;
+       }
+
+      if (subregs)
+       address = gen_reg_rtx (Pmode);
+      else
+       address = reg;
+
+      if (GET_CODE (orig) == SYMBOL_REF && !SYMBOL_REF_LOCAL_P (orig))
+       {
+         /* When gotrel_p generate sym@GOT, otherwise generate sym@PLT.  */
+         rtx_tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, orig),
+                                   (gotrel_p
+                                    ? UNSPEC_PIC_SYMBOL_GOT
+                                    : UNSPEC_PIC_SYMBOL_PLT));
+         optimize_p = gotrel_p;
+         if (flag_pic != 1)
+           {
+             emit_move_insn (address, rtx_tmp);
+             rtx_tmp = gen_rtx_MULT (Pmode, address, GEN_INT (1));
+           }
+         pic_ref = gen_const_mem (Pmode,
+                                  gen_rtx_PLUS (Pmode, pic_reg, rtx_tmp));
+       }
+      else
+       {
+         /* bsr symbol */
+         if (flag_pic == 1 && !gotrel_p)
+           {
+             pic_ref = gen_rtx_UNSPEC (Pmode,
+                                       gen_rtvec (1, orig),
+                                       UNSPEC_PIC_SYMBOL_BSR);
+             return pic_ref;
+           }
+         /* grs rx, symbol */
+         else if (flag_pic == 1 && (GET_CODE (orig) == SYMBOL_REF)
+                  && SYMBOL_REF_FUNCTION_P (orig))
+           {
+             pic_ref = gen_rtx_UNSPEC (Pmode,
+                                       gen_rtvec (1, orig),
+                                       UNSPEC_PIC_SYMBOL_GRS);
+             return pic_ref;
+           }
+         /* lrw rx, symbol@GOTOFF; add rx, rx, gb */
+         else
+           {
+             rtx_tmp = gen_rtx_UNSPEC (Pmode,
+                                       gen_rtvec (1, orig),
+                                       UNSPEC_PIC_SYMBOL_GOTOFF);
+             emit_move_insn (address, rtx_tmp);
+             pic_ref = gen_rtx_PLUS (Pmode, address, pic_reg);
+             optimize_p = true;
+           }
+       }
+
+      insn = emit_move_insn (reg, pic_ref);
+      /* Put a REG_EQUAL note on this insn,
+        so that it can be optimized by loop.  */
+      if (optimize_p)
+       set_unique_reg_note (insn, REG_EQUAL, orig);
+
+      return reg;
+    }
+  else if (GET_CODE (orig) == CONST)
+    {
+      rtx base, offset;
+
+      if (GET_CODE (XEXP (orig, 0)) == PLUS
+         && XEXP (XEXP (orig, 0), 1) == pic_reg)
+       return orig;
+
+      if (reg == 0)
+       {
+         gcc_assert (can_create_pseudo_p ());
+         reg = gen_reg_rtx (Pmode);
+       }
+
+      gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
+
+      base = csky_legitimize_pic_address (XEXP (XEXP (orig, 0), 0),
+                                         reg, gotrel_p);
+      offset = csky_legitimize_pic_address (XEXP (XEXP (orig, 0), 1),
+                                           base == reg ? 0 : reg, gotrel_p);
+
+      if (GET_CODE (offset) == CONST_INT)
+       return plus_constant (Pmode, base, INTVAL (offset));
+
+      return gen_rtx_PLUS (Pmode, base, offset);
+    }
+
+  return orig;
+}
+
+
+/* Functions to output assembly code for a function call.  */
+
+char *
+csky_output_call (rtx *operands, int index)
+{
+  static char buffer[20];
+  rtx addr = operands[index];
+
+  if (REG_P (addr))
+    sprintf (buffer, "jsr\t%%%d", index);
+  else if (flag_pic && (GET_CODE (addr) == UNSPEC))
+    sprintf (buffer, "bsr\t%%%d", index);
+  else
+    sprintf (buffer, "jbsr\t%%%d", index);
+
+  return buffer;
+}
+
+
+/* Worker function for TARGET_ASM_TRAMPOLINE_TEMPLATE.
+   Output assembler code for a block containing the constant parts
+   of a trampoline, leaving space for the variable parts.
+   Note that STATIC_CHAIN_REGNUM is t1 (aka r12) on ck801 and
+   t1 (r13) otherwise.  */
+
+static void
+csky_asm_trampoline_template (FILE *f)
+{
+  if (CSKY_ISA_FEATURE (2E3))
+    {
+      fprintf (f, "\tlrw\t%s, [.Lstatic_chain]\n",
+              reg_names[STATIC_CHAIN_REGNUM]);
+      fprintf (f, "\tjmpi\t[.Lfunc_address]\n");
+      /* 2 32-bit insns = 8 bytes.  */
+    }
+  else if (CSKY_TARGET_ARCH (CK801))
+    {
+      /* It's hard to provide general support for trampolines on this
+        core.  We need a register other than the one holding the
+        static chain (r13) to hold the function pointer for the
+        indirect jump to it.  But ck801 has such a limited register set
+        there is no other call-clobbered scratch register available -- in
+        particular, this core does not have r12, which we use for the
+        ck802 case below.  If we use a callee-saved register like r4,
+        saving the old value on the stack screws up the stack frame
+        if there are overflow arguments pushed on the stack
+        by the caller.  In theory we could test for that and handle
+        limited cases with parameters that all fit in r0-r3 with no
+        stack overflow, but punt for now.  */
+      sorry ("Nested function trampolines not supported on CK801.");
+    }
+  else
+    {
+      fprintf (f, "\tlrw\t%s, [.Lfunc_address]\n",
+              reg_names[CSKY_T1_REGNUM]);
+      fprintf (f, "\tlrw\t%s, [.Lstatic_chain]\n",
+              reg_names[STATIC_CHAIN_REGNUM]);
+      fprintf (f, "\tjmp\t%s\n",
+              reg_names[CSKY_T1_REGNUM]);
+      /* To align constant pool on a word boundary.  */
+      fprintf (f, "\t.align 2\n");
+      /* 2 32-bit lrw insns + 16-bit jump + 16-bit pad = 12 bytes.  */
+    }
+
+  fprintf (f, ".Lstatic_chain:\n");
+  fprintf (f, "\t.long 0\n");
+  fprintf (f, ".Lfunc_address:\n");
+  fprintf (f, "\t.long 0\n");
+  /* 2 words of constant pool = 8 bytes.  */
+}
+
+/* Worker function for TARGET_TRAMPOLINE_INIT.  */
+
+static void
+csky_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
+{
+  rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
+  rtx mem, a_tramp;
+  int pool = TRAMPOLINE_SIZE - 8;
+
+  emit_block_move (m_tramp, assemble_trampoline_template (),
+                  GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
+
+  mem = adjust_address (m_tramp, SImode, pool);
+  emit_move_insn (mem, chain_value);
+  mem = adjust_address (m_tramp, SImode, pool + 4);
+  emit_move_insn (mem, fnaddr);
+
+  a_tramp = XEXP (m_tramp, 0);
+  emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"),
+                    LCT_NORMAL, VOIDmode, a_tramp, Pmode,
+                    plus_constant (Pmode, a_tramp, TRAMPOLINE_SIZE), Pmode);
+}
+
+
+/* Emit a comparison insn for float values.
+   Return true if the comparison is inverted.  */
+
+bool
+csky_emit_compare_float (enum rtx_code code, rtx op0, rtx op1)
+{
+  rtx cc_reg = gen_rtx_REG (CCmode, CSKY_CC_REGNUM);
+  bool invert;
+  machine_mode mode = GET_MODE (op1);
+
+  if (op1 != CONST0_RTX (mode))
+    op1 = force_reg (mode, op1);
+
+  invert = false;
+  switch (code)
+    {
+    case EQ:
+      code = NE;
+      invert = true;
+      break;
+
+    case NE:
+      break;
+    case LE:
+      if (op1 == CONST0_RTX (mode))
+       op1 = force_reg (mode, op1);
+      break;
+    case GT:
+      if (op1 == CONST0_RTX (mode))
+       op1 = force_reg (mode, op1);
+      break;
+    case GE:
+      break;
+    case LT:
+      if (op1 == CONST0_RTX (mode))
+       {
+         code = GE;
+         invert = true;
+       }
+      break;
+    case UNORDERED:
+      break;
+    case ORDERED:
+      code = UNORDERED;
+      invert = true;
+      break;
+
+    default:
+      break;
+    }
+
+  emit_insn (gen_rtx_SET (cc_reg, gen_rtx_fmt_ee (code, CCmode, op0, op1)));
+
+  return invert;
+}
+
+/* Support for the Q memory constraint.  Returns true if OP is a MEM RTX
+   with an address consisting of base + index or base + displacement.  */
+bool
+csky_valid_fpuv2_mem_operand (rtx op)
+{
+  struct csky_address addr;
+
+  if (GET_CODE (op) != MEM)
+    return false;
+
+  if (!decompose_csky_address (XEXP (op, 0), &addr))
+    return false;
+
+  /* Verify base register. */
+  if (!is_csky_address_register_rtx_p (addr.base, 0))
+    return false;
+
+  /* Verify index operand. */
+  if (addr.index)
+    {
+      if (!is_csky_address_register_rtx_p (addr.index, 0))
+       return false;
+
+      if (addr.scale == 1 || addr.scale == 2 || addr.scale == 4
+         || addr.scale == 8)
+       return true;
+
+      return false;
+    }
+  /* Verify disp operand.  */
+  else if (addr.disp)
+    {
+      rtx disp = addr.disp;
+
+      if (!CONST_INT_P (disp))
+       return false;
+
+      if (((unsigned) INTVAL (disp) % 4) == 0
+         && (unsigned) INTVAL (disp) <= (unsigned) 1020)
+       return true;
+
+       return false;
+    }
+  return true;
+}
+
+
+/* Returns the (interrupt) function type of the current
+   function, or CSKY_FT_UNKNOWN if the type cannot be determined.  */
+
+static unsigned long
+csky_isr_value (tree argument)
+{
+  const isr_attribute_entry *ptr;
+  const char *arg;
+
+  /* No argument - default to IRQ.  */
+  if (argument == NULL_TREE)
+    return CSKY_FT_ISR;
+
+  /* Get the value of the argument.  */
+  if (TREE_VALUE (argument) == NULL_TREE
+      || TREE_CODE (TREE_VALUE (argument)) != STRING_CST)
+    return CSKY_FT_UNKNOWN;
+
+  arg = TREE_STRING_POINTER (TREE_VALUE (argument));
+
+  /* Check it against the list of known arguments.  */
+  for (ptr = isr_attribute_map; ptr->arg != NULL; ptr++)
+    if (strcmp (arg, ptr->arg) == 0)
+      return ptr->return_value;
+
+  /* An unrecognized interrupt type.  */
+  return CSKY_FT_UNKNOWN;
+}
+
+/* Handle an attribute requiring a FUNCTION_DECL;
+   arguments as in struct attribute_spec.handler.  */
+
+static tree
+csky_handle_fndecl_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
+                             int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) != FUNCTION_DECL)
+    {
+      warning (OPT_Wattributes, "%qE attribute only applies to functions",
+              name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle an "interrupt" or "isr" attribute;
+   arguments as in struct attribute_spec.handler.  */
+
+static tree
+csky_handle_isr_attribute (tree *node, tree name, tree args, int flags,
+                          bool *no_add_attrs)
+{
+
+  if (!TARGET_ISTACK)
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored without -mistack",
+              name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  if (DECL_P (*node))
+    {
+      if (TREE_CODE (*node) != FUNCTION_DECL)
+       {
+         warning (OPT_Wattributes, "%qE attribute only applies to functions",
+                  name);
+         *no_add_attrs = true;
+       }
+    }
+  else
+    {
+      if (TREE_CODE (*node) == FUNCTION_TYPE
+         || TREE_CODE (*node) == METHOD_TYPE)
+       {
+         if (csky_isr_value (args) == CSKY_FT_UNKNOWN)
+           {
+             warning (OPT_Wattributes, "%qE attribute ignored", name);
+             *no_add_attrs = true;
+           }
+       }
+      else if (TREE_CODE (*node) == POINTER_TYPE
+              && (TREE_CODE (TREE_TYPE (*node)) == FUNCTION_TYPE
+                  || TREE_CODE (TREE_TYPE (*node)) == METHOD_TYPE)
+              && csky_isr_value (args) != CSKY_FT_UNKNOWN)
+       {
+         *node = build_variant_type_copy (*node);
+         TREE_TYPE (*node) = build_type_attribute_variant (TREE_TYPE (*node),
+           tree_cons (name, args, TYPE_ATTRIBUTES (TREE_TYPE (*node))));
+         *no_add_attrs = true;
+       }
+      else if (flags & ((int)ATTR_FLAG_DECL_NEXT
+                       | (int)ATTR_FLAG_FUNCTION_NEXT
+                       | (int)ATTR_FLAG_ARRAY_NEXT))
+       {
+         *no_add_attrs = true;
+         return tree_cons (name, args, NULL_TREE);
+       }
+      else
+       warning (OPT_Wattributes, "%qE attribute ignored", name);
+    }
+  return NULL_TREE;
+}
+
+
+/* Implement TARGET_REGISTER_MOVE_COST: compute extra cost of moving data
+   between one register class and another.  */
+
+int
+csky_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED,
+                        reg_class_t from, reg_class_t to)
+{
+#define GR_REG_CLASS_P(CLASS) \
+  ((CLASS) == GENERAL_REGS || (CLASS) == MINI_REGS || (CLASS) == SP_REGS \
+   || (CLASS) == LOW_REGS)
+
+#define HILO_REG_CLASS_P(CLASS) \
+  ((CLASS) == HI_REGS || (CLASS) == LO_REGS || (CLASS) == HILO_REGS)
+
+#define V_REG_CLASS_P(CLASS) \
+  ((CLASS) == V_REGS)
+
+  if (V_REG_CLASS_P (from) && V_REG_CLASS_P (to))
+    return 2;
+
+  if ((V_REG_CLASS_P (from) && GR_REG_CLASS_P (to))
+      || (GR_REG_CLASS_P (from) && V_REG_CLASS_P (to)))
+    return 6;
+
+  if ((HILO_REG_CLASS_P (from) && GR_REG_CLASS_P (to))
+      || (GR_REG_CLASS_P (from) && HILO_REG_CLASS_P (to)))
+    return 16;
+
+  if (HILO_REG_CLASS_P (from) && HILO_REG_CLASS_P (to))
+    return 32;
+
+  if ((HILO_REG_CLASS_P (from) && V_REG_CLASS_P (to))
+      || (V_REG_CLASS_P (from) && HILO_REG_CLASS_P (to)))
+    return 64;
+
+  return 2;
+}
+
+
+/* Implement TARGET_MEMORY_MOVE_COST: compute the cost of moving data
+   between registers and memory.  */
+
+int
+csky_memory_move_cost (machine_mode mode, reg_class_t rclass,
+                      bool in)
+{
+  return (4 + memory_move_secondary_cost (mode, rclass, in));
+}
+
+
+/* TARGET_RTX_COSTS helper for ck801/ck802.  */
+
+static bool
+ck802_ck801_rtx_costs (rtx x, int code, int outer_code, int *total,
+                      bool speed)
+{
+  machine_mode mode = GET_MODE (x);
+  switch (code)
+    {
+      /* Accessing memory costs quite a lot for first word;  */
+    case MEM:
+      *total = COSTS_N_INSNS (1 + CSKY_NUM_REGS (mode));
+      return false;
+    case DIV:
+    case UDIV:
+    case MOD:
+    case UMOD:
+      *total = 100;
+      return true;
+
+    case ROTATE:
+    case ROTATERT:
+    case ASHIFT:
+    case LSHIFTRT:
+    case ASHIFTRT:
+      if (speed)
+       *total = 2;
+      else
+       *total = COSTS_N_INSNS (1);
+      return false;
+
+    case MINUS:
+    case PLUS:
+      *total = COSTS_N_INSNS (CSKY_NUM_REGS (mode));
+      return false;
+
+    case AND:
+      {
+       enum rtx_code subcode = GET_CODE (XEXP (x, 1));
+
+       /* If subcode is "not", we'll try to combine it into e.g. "andn"
+          instruction, so give AND itself zero cost. */
+       if (subcode == NOT)
+         {
+           *total = 0;
+           return false;
+         }
+      }
+      /* Fall through.  */
+    case XOR:
+    case IOR:
+      *total = COSTS_N_INSNS (CSKY_NUM_REGS (mode));
+      return false;
+
+    case MULT:
+      /* FIXME:         is ixw supported on ck801/ck802?  */
+      /* We can use "ix.h/w" insn to replace multiply by 2 or 4.
+        "ix.h/w" is a 32-bit insn, so let its cost be a little less than
+        "mult" insn.  */
+      if (REG_P (XEXP (x, 0)) && CONST_INT_P (XEXP (x, 1)))
+       {
+         unsigned HOST_WIDE_INT m
+           = (unsigned HOST_WIDE_INT) (INTVAL (XEXP (x, 1)));
+         if ((m == 2 || m == 4) && outer_code == PLUS)
+           {
+             *total = 2;
+             return true;
+           }
+         else
+           {
+             /* Because mult is relatively slower than other operations,
+                we try to use other insns when optimizing for speed.
+                When optimizing for size, give it lower cost.  */
+             if (speed)
+               {
+                 *total = COSTS_N_INSNS (10 * CSKY_NUM_REGS (mode));
+                 return true;
+               }
+             int cycle = 0;
+             while (m)
+               {
+                 m >>= 2;
+                 cycle++;
+               }
+             *total = COSTS_N_INSNS (1) + cycle;
+             return false;
+           }
+       }
+      if (!speed)
+       *total = COSTS_N_INSNS (1);
+      return false;
+
+    case NEG:
+      /* Usually, we use subtract from 0 to substitute for neg, and
+        it costs 1 extra insn to move 0 to a register.  */
+      *total = COSTS_N_INSNS (2 * CSKY_NUM_REGS (mode));
+      return false;
+
+    case NOT:
+      *total = COSTS_N_INSNS (CSKY_NUM_REGS (mode));
+      return false;
+
+    case COMPARE:
+      *total = COSTS_N_INSNS (1);
+      return false;
+
+    case SIGN_EXTEND:
+    case ZERO_EXTEND:
+      *total = COSTS_N_INSNS (CSKY_NUM_REGS (mode));
+      return false;
+
+    case SIGN_EXTRACT:
+    case ZERO_EXTRACT:
+      if (REG_P (XEXP (x, 0))
+         && CONST_INT_P (XEXP (x, 1))
+         && CONST_INT_P (XEXP (x, 2))
+         && INTVAL (XEXP (x, 1)) == 8
+         && INTVAL (XEXP (x, 2)) % 8 == 0)
+       {
+         *total = COSTS_N_INSNS (1);
+         return true;
+       }
+      *total = COSTS_N_INSNS (CSKY_NUM_REGS (mode));
+      return false;
+
+    case CONST_INT:
+      {
+       unsigned HOST_WIDE_INT t = (unsigned HOST_WIDE_INT) (INTVAL (x));
+
+       if (outer_code == COMPARE)
+         {
+           if (t < 0x10000)
+             *total = 0;
+           else
+             *total = COSTS_N_INSNS (2);
+         }
+       else if (outer_code == AND || outer_code == IOR || outer_code == XOR)
+         {
+           /* "andi,xori,ori" are 32-bit insns, so let it cost a
+              little more.  */
+           if (t < 0x1000)
+             {
+               /* Try replacing "andi" by "sextb/h", so let it cost more.  */
+               if (outer_code == AND && (t == 0xff || t == 0xffff))
+                 {
+                   *total = 8;
+                   return true;
+                 }
+               *total = 2;
+             }
+           else if (t < 0x10000)
+             *total = COSTS_N_INSNS (1);
+           else
+             *total = COSTS_N_INSNS (2);
+         }
+       else if (outer_code == PLUS || outer_code == MINUS)
+         {
+           /* "addi/subi rx,ry,imm", if imm<9, it is more often a
+              16-bit insn.  If imm>=9, use "movi" insn; it's probably
+              less than "addi/subi". */
+           if (t < 9)
+             *total = 0;
+           else if (t < 0x1000)
+             *total = 2;
+           else if (t < 0x10000)
+             *total = COSTS_N_INSNS (1);
+           else
+             *total = COSTS_N_INSNS (2);
+         }
+       else if (outer_code == ROTATE || outer_code == ROTATERT
+                || outer_code == LSHIFTRT || outer_code == ASHIFTRT
+                || outer_code == ASHIFT)
+         {
+           if (t < 32)
+             *total = 0;
+           else
+             *total = COSTS_N_INSNS (2);
+         }
+       else
+         {
+           if (t < 0x10000)
+             if (outer_code == SET && t < 256)
+               *total = 0;
+             else
+               *total = COSTS_N_INSNS (1);
+           else
+             *total = COSTS_N_INSNS (2);
+         }
+      }
+      return true;
+
+    case CONST:
+    case LABEL_REF:
+    case SYMBOL_REF:
+      *total = COSTS_N_INSNS (3);
+      return true;
+    default:
+      return false;
+    }
+}
+
+
+/* TARGET_RTX_COSTS helper for ck803.  */
+
+static bool
+ck803_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED,
+                int *total, bool speed ATTRIBUTE_UNUSED)
+{
+  switch (code)
+    {
+    case SET:
+      if (MEM_P (XEXP (x, 1)))
+       {
+         struct csky_address op1;
+         bool address_valid
+           = decompose_csky_address (XEXP (XEXP (x, 1), 0), &op1);
+         if (op1.index)
+           {
+             *total = COSTS_N_INSNS (3);
+             return true;
+           }
+         else if (address_valid)
+           {
+             *total = COSTS_N_INSNS (1);
+             return true;
+           }
+       }
+      if (REG_P (XEXP (x, 0)) && (GET_CODE (XEXP (x, 1)) == PLUS))
+       {
+        rtx sub_exp = XEXP (x, 1);
+        if (REG_P (XEXP (sub_exp, 0)) && REG_P (XEXP (sub_exp, 1)))
+          {
+            *total = COSTS_N_INSNS (1);
+            return true;
+          }
+       }
+      return false;
+    case MULT:
+      if (REG_P (XEXP (x, 0)) && CONST_INT_P (XEXP (x, 1)))
+       {
+         HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
+         if (val % 2 == 0 && val < 0xffffffff && val > 0)
+           {
+             *total = COSTS_N_INSNS (1);
+             return true;
+           }
+       }
+      return false;
+
+    case CONST:
+    case LABEL_REF:
+    case SYMBOL_REF:
+      *total = COSTS_N_INSNS (3);
+      return true;
+    default:
+      return false;
+    }
+}
+
+/* TARGET_RTX_COSTS helper for ck807+ arches.  */
+
+static bool
+ck807_ck810_rtx_costs (rtx x, int code,
+                      int outer_code ATTRIBUTE_UNUSED,
+                      int *total, bool speed ATTRIBUTE_UNUSED)
+{
+  switch (code)
+    {
+    case MULT:
+      if (REG_P (XEXP (x, 0)) && CONST_INT_P (XEXP (x, 1)))
+       {
+         HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
+         if (val % 2 == 0 && val < 0xffffffff && val > 0)
+           {
+             *total = COSTS_N_INSNS (1);
+             return true;
+           }
+       }
+      return false;
+
+    case CONST:
+    case LABEL_REF:
+    case SYMBOL_REF:
+      *total = COSTS_N_INSNS (3);
+      return true;
+    default:
+      return false;
+    }
+}
+
+
+/* Implement TARGET_RTX_COSTS, to compute a (partial) cost for rtx X.
+   Return true if the complete cost has been computed, and false if
+   subexpressions should be scanned.  In either case, *TOTAL contains
+   the cost result.  */
+
+static bool
+csky_rtx_costs (rtx x, machine_mode mode ATTRIBUTE_UNUSED, int outer_code,
+               int opno ATTRIBUTE_UNUSED, int *total, bool speed)
+{
+  int code = GET_CODE (x);
+
+  if (CSKY_TARGET_ARCH (CK802) || CSKY_TARGET_ARCH (CK801))
+    return ck802_ck801_rtx_costs (x, code, outer_code, total, speed);
+  else if (CSKY_TARGET_ARCH (CK803))
+    return ck803_rtx_costs (x, code, outer_code, total, speed);
+  else if (CSKY_TARGET_ARCH (CK807) || CSKY_TARGET_ARCH (CK810))
+    return ck807_ck810_rtx_costs (x, code, outer_code, total, speed);
+  else
+    gcc_unreachable ();
+}
+
+/* Emit assembly code for CASESI.  This is only used on CK801 and CK802
+   when optimizing for size, and uses helper functions in libgcc instead
+   of doing the control transfer inline.  */
+
+const char *
+csky_output_casesi (rtx *operands)
+{
+  rtx diff_vec = PATTERN (NEXT_INSN (as_a <rtx_insn *> (operands[0])));
+
+  gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
+
+  switch (GET_MODE (diff_vec))
+    {
+    case E_QImode:
+      return (ADDR_DIFF_VEC_FLAGS (diff_vec).offset_unsigned
+             ? "jbsr\t___gnu_csky_case_uqi"
+             : "jbsr\t___gnu_csky_case_sqi");
+    case E_HImode:
+      return (ADDR_DIFF_VEC_FLAGS (diff_vec).offset_unsigned
+             ? "jbsr\t___gnu_csky_case_uhi"
+             : "jbsr\t___gnu_csky_case_shi");
+    case E_SImode:
+      return "jbsr\t___gnu_csky_case_si";
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Implement TARGET_SCHED_ISSUE_RATE.  Lookup the issue rate in the
+   per-core tuning structs.  */
+static int
+csky_sched_issue_rate (void)
+{
+  if (CSKY_TARGET_ARCH (CK810))
+    return 2;
+  else
+    return 1;
+}
+
+
+/* This function implements the target macro TARGET_SCHED_ADJUST_COST.
+   It corrects the value of COST based on the relationship between
+   INSN and DEP through the dependence DEP_TYPE.  It returns the new
+   value.  */
+
+static int
+csky_sched_adjust_cost (rtx_insn *insn,
+                       int dep_type,
+                       rtx_insn *dep,
+                       int cost,
+                       unsigned int dw ATTRIBUTE_UNUSED)
+{
+  if (dep_type == REG_DEP_ANTI || dep_type == REG_DEP_OUTPUT)
+    return 0;
+  /* The REG_DEP_TRUE situation.  */
+  else if (recog_memoized (insn) >= 0 && recog_memoized (dep) >= 0)
+    {
+      enum attr_type insn_type = get_attr_type (insn);
+      if (CSKY_TARGET_ARCH (CK803))
+       {
+         /* The ld or st's base reg depends on the pre insn,
+            it will delay 1 cycle.  */
+         if (insn_type == TYPE_LOAD || insn_type == TYPE_STORE)
+           {
+             rtx pattern = PATTERN (insn);
+
+             gcc_assert (GET_CODE (pattern) == SET);
+             rtx addr = (insn_type == TYPE_LOAD
+                         ? SET_SRC (pattern) : SET_DEST (pattern));
+
+             enum rtx_code code = GET_CODE (addr);
+             if (code == ZERO_EXTEND || code == SIGN_EXTEND)
+               addr = XEXP (addr, 0);
+             gcc_assert (GET_CODE (addr) == MEM);
+
+             rtx base =  XEXP (addr, 0);
+             rtx reg = NULL_RTX;
+             if (REG_P (base))
+               reg = base;
+             if (GET_CODE (base) == PLUS
+                 && GET_CODE (XEXP (base, 0)) == REG)
+               reg = XEXP (base, 0);
+             if ((reg != NULL_RTX) && reg_set_p (reg, PATTERN (dep)))
+               return 2;
+           }
+       }
+      else if (CSKY_TARGET_ARCH (CK802))
+       {
+         if ((insn_type == TYPE_CALL_JSR || insn_type == TYPE_BRANCH_JMP)
+             && get_attr_type (dep) != TYPE_LOAD)
+           return 1;
+
+         if (insn_type == TYPE_LOAD || insn_type == TYPE_STORE)
+           {
+             rtx pattern = PATTERN (insn);
+
+             gcc_assert (GET_CODE (pattern) == SET);
+
+             rtx addr = (insn_type == TYPE_LOAD
+                         ? SET_SRC (pattern) : SET_DEST (pattern));
+
+             enum rtx_code code = GET_CODE (addr);
+             if (code == ZERO_EXTEND || code == SIGN_EXTEND)
+               addr = XEXP (addr, 0);
+             gcc_assert (GET_CODE (addr) == MEM);
+
+             rtx base =  XEXP (addr, 0);
+             rtx reg = NULL_RTX;
+             if (REG_P (base))
+               reg = base;
+             if (GET_CODE (base) == PLUS
+                 && GET_CODE (XEXP (base, 0)) == REG)
+               reg = XEXP (base, 0);
+             if ((reg != NULL_RTX) && reg_set_p (reg, PATTERN (dep))
+                 && get_attr_type (dep) != TYPE_LOAD)
+               return 1;
+
+             if (insn_type == TYPE_STORE
+                 && reg_referenced_p (SET_SRC (pattern), PATTERN (dep)))
+               return 1;
+           }
+       }
+    }
+  return cost;
+}
+
+static bool
+csky_warn_func_return (tree decl)
+{
+  /* Naked functions are implemented entirely in assembly, including the
+     return sequence, so suppress warnings about this.  */
+  return lookup_attribute ("naked", DECL_ATTRIBUTES (decl)) == NULL_TREE;
+}
+
+
+/* Implement TARGET_RETURN_IN_MEMORY to decide whether TYPE should be
+   returned in memory (true) or in a register (false).
+   FNTYPE is the type of the function making the call.  */
+static bool
+csky_return_in_memory (const_tree type,
+                      const_tree fntype ATTRIBUTE_UNUSED)
+{
+  const HOST_WIDE_INT size = int_size_in_bytes (type);
+  return (size == -1 || size > 2 * UNITS_PER_WORD);
+}
+
+
+/* Implement TARGET_DWARF_REGISTER_SPAN.
+   Dwarf models VFP registers as  64-bit or 128-bit registers default.
+   GCC models tham as 32-bit registers, so we need to describe this to
+   the DWARF generation code.  Other registers can use the default.  */
+static rtx
+csky_dwarf_register_span (rtx rtl)
+{
+  machine_mode mode;
+  unsigned regno;
+  rtx parts[16];
+  int nregs;
+  int i;
+
+  regno = REGNO (rtl);
+  if (!CSKY_VREG_P (regno))
+    return NULL_RTX;
+
+  mode = GET_MODE (rtl);
+  if (GET_MODE_SIZE (mode) < 8)
+    return NULL_RTX;
+
+  if (TARGET_SOFT_FPU)
+    {
+      nregs = GET_MODE_SIZE (mode) / 4;
+      for (i = 0; i < nregs; i += 2)
+      if (TARGET_BIG_ENDIAN)
+       {
+         parts[i] = gen_rtx_REG (SImode, regno + i + 1);
+         parts[i + 1] = gen_rtx_REG (SImode, regno + i);
+       }
+      else
+       {
+         parts[i] = gen_rtx_REG (SImode, regno + i);
+         parts[i + 1] = gen_rtx_REG (SImode, regno + i + 1);
+       }
+    }
+  else
+    {
+      /* FIXME: dwarf2 considers all general registers to be the same
+        as the CPU bit width. Transform the 64-bit FPU registers to
+        32 bits here, and we will modify the unwind processing to
+        fit CSKY architecture later.  */
+      nregs = GET_MODE_SIZE (mode) / 8;
+      for (i = 0; i < nregs; i++)
+       parts[i] = gen_rtx_REG (SImode, regno + i);
+    }
+
+  return gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (nregs , parts));
+}
+
+/* Implement TARGET_INIT_LIBFUNCS.  */
+
+static void
+csky_init_libfuncs (void)
+{
+  if (TARGET_CSKY_LINUX)
+    init_sync_libfuncs (UNITS_PER_WORD);
+  if (!TARGET_LIBCCRT)
+    return;
+
+  #define CSKY_GCC_SYM(sym) "__csky_ccrt_" # sym
+
+  /* int */
+
+  /* Arithmetic functions */
+  set_optab_libfunc (ashl_optab,    DImode, CSKY_GCC_SYM (ashldi3));
+  set_optab_libfunc (ashr_optab,    DImode, CSKY_GCC_SYM (ashrdi3));
+  set_optab_libfunc (sdiv_optab,    SImode, CSKY_GCC_SYM (divsi3));
+  set_optab_libfunc (sdiv_optab,    DImode, CSKY_GCC_SYM (divdi3));
+  set_optab_libfunc (lshr_optab,    DImode, CSKY_GCC_SYM (lshrdi3));
+  set_optab_libfunc (smod_optab,    SImode, CSKY_GCC_SYM (modsi3));
+  set_optab_libfunc (smod_optab,    DImode, CSKY_GCC_SYM (moddi3));
+  set_optab_libfunc (smul_optab,    DImode, CSKY_GCC_SYM (muldi3));
+  set_optab_libfunc (neg_optab,            DImode, CSKY_GCC_SYM (negdi2));
+  set_optab_libfunc (udiv_optab,    SImode, CSKY_GCC_SYM (udivsi3));
+  set_optab_libfunc (udiv_optab,    DImode, CSKY_GCC_SYM (udivdi3));
+  set_optab_libfunc (udivmod_optab, DImode, CSKY_GCC_SYM (udivmoddi4));
+  set_optab_libfunc (umod_optab,    SImode, CSKY_GCC_SYM (umodsi3));
+  set_optab_libfunc (umod_optab,    DImode, CSKY_GCC_SYM (umoddi3));
+
+  /* Comparison functions */
+  set_optab_libfunc (cmp_optab,            DImode, CSKY_GCC_SYM (cmpdi2));
+  set_optab_libfunc (ucmp_optab,    DImode, CSKY_GCC_SYM (ucmpdi2));
+
+  /* Trapping arithmetic functions */
+  set_optab_libfunc (absv_optab,    SImode, CSKY_GCC_SYM (absvsi2));
+  set_optab_libfunc (absv_optab,    DImode, CSKY_GCC_SYM (absvdi2));
+  set_optab_libfunc (addv_optab,    SImode, CSKY_GCC_SYM (addvsi3));
+  set_optab_libfunc (addv_optab,    DImode, CSKY_GCC_SYM (addvdi3));
+  set_optab_libfunc (smulv_optab,   SImode, CSKY_GCC_SYM (mulvsi3));
+  set_optab_libfunc (smulv_optab,   DImode, CSKY_GCC_SYM (mulvdi3));
+  set_optab_libfunc (negv_optab,    SImode, CSKY_GCC_SYM (negvsi2));
+  set_optab_libfunc (negv_optab,    DImode, CSKY_GCC_SYM (negvdi2));
+  set_optab_libfunc (subv_optab,    SImode, CSKY_GCC_SYM (subvsi3));
+  set_optab_libfunc (subv_optab,    DImode, CSKY_GCC_SYM (subvdi3));
+
+  /* Bit operations */
+  set_optab_libfunc (clz_optab,            SImode, CSKY_GCC_SYM (clzsi2));
+  set_optab_libfunc (clz_optab,            DImode, CSKY_GCC_SYM (clzdi2));
+  set_optab_libfunc (ctz_optab,            SImode, CSKY_GCC_SYM (ctzsi2));
+  set_optab_libfunc (ctz_optab,            DImode, CSKY_GCC_SYM (ctzdi2));
+  set_optab_libfunc (ffs_optab,            DImode, CSKY_GCC_SYM (ffsdi2));
+  set_optab_libfunc (parity_optab,  SImode, CSKY_GCC_SYM (paritysi2));
+  set_optab_libfunc (parity_optab,  DImode, CSKY_GCC_SYM (paritydi2));
+  set_optab_libfunc (popcount_optab,SImode, CSKY_GCC_SYM (popcountsi2));
+  set_optab_libfunc (popcount_optab,DImode, CSKY_GCC_SYM (popcountdi2));
+  set_optab_libfunc (bswap_optab,   SImode, CSKY_GCC_SYM (bswapsi2));
+  set_optab_libfunc (bswap_optab,   DImode, CSKY_GCC_SYM (bswapdi2));
+
+  /* float */
+
+  /* Arithmetic functions */
+  set_optab_libfunc (add_optab,            SFmode, CSKY_GCC_SYM (addsf3));
+  set_optab_libfunc (add_optab,            DFmode, CSKY_GCC_SYM (adddf3));
+  set_optab_libfunc (sub_optab,            SFmode, CSKY_GCC_SYM (subsf3));
+  set_optab_libfunc (sub_optab,            DFmode, CSKY_GCC_SYM (subdf3));
+  set_optab_libfunc (smul_optab,    SFmode, CSKY_GCC_SYM (mulsf3));
+  set_optab_libfunc (smul_optab,    DFmode, CSKY_GCC_SYM (muldf3));
+  set_optab_libfunc (sdiv_optab,    SFmode, CSKY_GCC_SYM (divsf3));
+  set_optab_libfunc (sdiv_optab,    DFmode, CSKY_GCC_SYM (divdf3));
+  set_optab_libfunc (neg_optab,            SFmode, CSKY_GCC_SYM (negsf2));
+  set_optab_libfunc (neg_optab,            DFmode, CSKY_GCC_SYM (negdf2));
+
+  /* Conversion functions */
+  set_conv_libfunc (sext_optab,           DFmode, SFmode, CSKY_GCC_SYM (extendsfdf2));
+  set_conv_libfunc (trunc_optab,   SFmode, DFmode, CSKY_GCC_SYM (truncdfsf2));
+  set_conv_libfunc (sfix_optab,           SImode, SFmode, CSKY_GCC_SYM (fixsfsi));
+  set_conv_libfunc (sfix_optab,           SImode, DFmode, CSKY_GCC_SYM (fixdfsi));
+  set_conv_libfunc (sfix_optab,           DImode, SFmode, CSKY_GCC_SYM (fixsfdi));
+  set_conv_libfunc (sfix_optab,           DImode, DFmode, CSKY_GCC_SYM (fixdfdi));
+  set_conv_libfunc (ufix_optab,           SImode, SFmode, CSKY_GCC_SYM (fixunssfsi));
+  set_conv_libfunc (ufix_optab,           SImode, DFmode, CSKY_GCC_SYM (fixunsdfsi));
+  set_conv_libfunc (ufix_optab,           DImode, SFmode, CSKY_GCC_SYM (fixunssfdi));
+  set_conv_libfunc (ufix_optab,           DImode, DFmode, CSKY_GCC_SYM (fixunsdfdi));
+  set_conv_libfunc (sfloat_optab,  SFmode, SImode, CSKY_GCC_SYM (floatsisf));
+  set_conv_libfunc (sfloat_optab,  DFmode, SImode, CSKY_GCC_SYM (floatsidf));
+  set_conv_libfunc (sfloat_optab,  SFmode, DImode, CSKY_GCC_SYM (floatdisf));
+  set_conv_libfunc (sfloat_optab,  DFmode, DImode, CSKY_GCC_SYM (floatdidf));
+  set_conv_libfunc (ufloat_optab,  SFmode, SImode, CSKY_GCC_SYM (floatunsisf));
+  set_conv_libfunc (ufloat_optab,  DFmode, SImode, CSKY_GCC_SYM (floatunsidf));
+  set_conv_libfunc (ufloat_optab,  SFmode, DImode, CSKY_GCC_SYM (floatundisf));
+  set_conv_libfunc (ufloat_optab,  DFmode, DImode, CSKY_GCC_SYM (floatundidf));
+
+  /* Comparison functions */
+  set_optab_libfunc (cmp_optab,           SFmode, CSKY_GCC_SYM (cmpsf2));
+  set_optab_libfunc (cmp_optab,           DFmode, CSKY_GCC_SYM (cmpdf2));
+  set_optab_libfunc (unord_optab,  SFmode, CSKY_GCC_SYM (unordsf2));
+  set_optab_libfunc (unord_optab,  DFmode, CSKY_GCC_SYM (unorddf2));
+  set_optab_libfunc (eq_optab,    SFmode, CSKY_GCC_SYM (eqsf2));
+  set_optab_libfunc (eq_optab,    DFmode, CSKY_GCC_SYM (eqdf2));
+  set_optab_libfunc (ne_optab,    SFmode, CSKY_GCC_SYM (nesf2));
+  set_optab_libfunc (ne_optab,    DFmode, CSKY_GCC_SYM (nedf2));
+  set_optab_libfunc (ge_optab,    SFmode, CSKY_GCC_SYM (gesf2));
+  set_optab_libfunc (ge_optab,    DFmode, CSKY_GCC_SYM (gedf2));
+  set_optab_libfunc (lt_optab,    SFmode, CSKY_GCC_SYM (ltsf2));
+  set_optab_libfunc (lt_optab,    DFmode, CSKY_GCC_SYM (ltdf2));
+  set_optab_libfunc (le_optab,    SFmode, CSKY_GCC_SYM (lesf2));
+  set_optab_libfunc (le_optab,    DFmode, CSKY_GCC_SYM (ledf2));
+  set_optab_libfunc (gt_optab,    SFmode, CSKY_GCC_SYM (gtsf2));
+  set_optab_libfunc (gt_optab,    DFmode, CSKY_GCC_SYM (gtdf2));
+}
+
+
+/* Implement TARGET_ADDRESS_COST to estimate cost of the memory address X.
+   For C-SKY, (register) and (register + offset) have the same cost.
+   Other situations cost more.  */
+
+static int
+csky_address_cost (rtx x, machine_mode mode ATTRIBUTE_UNUSED,
+                  addr_space_t as ATTRIBUTE_UNUSED,
+                  bool speed ATTRIBUTE_UNUSED)
+{
+  enum rtx_code code = GET_CODE (x);
+
+  if (code == REG)
+    return COSTS_N_INSNS (1);
+  if (code == PLUS
+      && REG_P (XEXP (x, 0))
+      && CONST_INT_P (XEXP (x, 1)))
+    return COSTS_N_INSNS (1);
+
+  return COSTS_N_INSNS (3);
+}
+
+
+/* Implement TARGET_FIXED_CONDITION_CODE_REGS.  */
+
+static bool
+csky_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2)
+{
+  *p1 = CSKY_CC_REGNUM;
+  *p2 = INVALID_REGNUM;
+  return true;
+}
+
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+
+#include "gt-csky.h"
diff --git a/gcc/config/csky/csky.h b/gcc/config/csky/csky.h
new file mode 100644 (file)
index 0000000..39aac6b
--- /dev/null
@@ -0,0 +1,1054 @@
+/* Declarations for the C-SKY back end.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   Contributed by C-SKY Microsystems and Mentor Graphics.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+
+#ifndef GCC_CSKY_H
+#define GCC_CSKY_H
+
+/* In some places e.g. csky_secondary_reload, we use -1 to indicate an
+   invalid register.  In other places where N is unsigned the comparison
+   to zero would give an error, so explicitly cast to int here.  */
+#define CSKY_GENERAL_REGNO_P(N)                        \
+  ((N) < CSKY_NGPR_REGS && (int)(N) >= 0)
+
+#define CSKY_VREG_P(N)              \
+  ((N) >= CSKY_FIRST_VFP_REGNUM && (N) <= CSKY_LAST_VFP_REGNUM)
+
+#define CSKY_HILO_REG_P(N)   \
+  ((N) == CSKY_HI_REGNUM || (N) == CSKY_LO_REGNUM)
+
+/* Helper macros for constant constraints and predicates.  */
+#define CSKY_VALUE_BETWEEN(VALUE, LOW, HIGH)   \
+  ((VALUE) >= (LOW) && (VALUE) <= (HIGH))
+
+#define CSKY_CONST_OK_FOR_I(VALUE)  \
+  CSKY_VALUE_BETWEEN (VALUE, 0, 65535)
+
+#define CSKY_CONST_OK_FOR_J(VALUE)  \
+  CSKY_VALUE_BETWEEN (VALUE, 1, 32)
+
+#define CSKY_CONST_OK_FOR_K(VALUE)  \
+  CSKY_VALUE_BETWEEN (VALUE, 0, 31)
+
+#define CSKY_CONST_OK_FOR_L(VALUE)  \
+  CSKY_VALUE_BETWEEN (VALUE, 1, 8)
+
+#define CSKY_CONST_OK_FOR_M(VALUE)  \
+  CSKY_VALUE_BETWEEN (VALUE, 1, 4096)
+
+#define CSKY_CONST_OK_FOR_N(VALUE)  \
+  CSKY_VALUE_BETWEEN (VALUE, 1, 256)
+
+#define CSKY_CONST_OK_FOR_O(VALUE)  \
+  CSKY_VALUE_BETWEEN (VALUE, 0, 4095)
+
+#define CSKY_CONST_OK_FOR_P(VALUE)  \
+  (((VALUE) & 0x3) == 0 && CSKY_VALUE_BETWEEN (VALUE, 4, 508))
+
+#define CSKY_CONST_OK_FOR_T(VALUE)  \
+  CSKY_VALUE_BETWEEN (VALUE, -256, -1)
+
+#define CSKY_CONST_OK_FOR_Ub(VALUE)  \
+  (exact_log2 (VALUE & 0xFFFFFFFF) >= 0)
+
+#define CSKY_CONST_OK_FOR_Uc(VALUE)         \
+  ((VALUE) == (HOST_WIDE_INT) -1            \
+   || (exact_log2 ((VALUE) + 1) >= 0        \
+       && exact_log2 ((VALUE) + 1) <= 31))
+
+#define CSKY_CONST_OK_FOR_Ud(VALUE)                            \
+  ((CSKY_CONST_OK_FOR_I ((VALUE) & 0xffffffff)                 \
+    || CSKY_CONST_OK_FOR_Ub ((VALUE))                          \
+    || CSKY_CONST_OK_FOR_Uc (((VALUE) << 32) >> 32))           \
+   && (CSKY_CONST_OK_FOR_I ((VALUE) >> 32)                     \
+       || CSKY_CONST_OK_FOR_Ub ((VALUE) >> 32)                 \
+       || CSKY_CONST_OK_FOR_Uc ((VALUE) >> 32)))               \
+
+#define CSKY_CONST_OK_FOR_Ug(VALUE)  \
+  (((VALUE) & 0x3) == 0 && CSKY_VALUE_BETWEEN (VALUE, -508, -4))
+
+#define CSKY_CONST_OK_FOR_Uh(VALUE)  \
+  CSKY_VALUE_BETWEEN (VALUE, -31, 0)
+
+#define CSKY_CONST_OK_FOR_Uj(VALUE)  \
+  (((VALUE) & 0x3) == 0 && CSKY_VALUE_BETWEEN (VALUE, 1, 1024))
+
+#define CSKY_CONST_OK_FOR_Uk(VALUE)  \
+  CSKY_VALUE_BETWEEN (VALUE, 1, 65536)
+
+#define CSKY_CONST_OK_FOR_Ul(VALUE)  \
+  (((VALUE) & 0x3) == 0 && CSKY_VALUE_BETWEEN (VALUE, -1024, -4))
+
+#define CSKY_CONST_OK_FOR_Um(VALUE)  \
+  CSKY_VALUE_BETWEEN (VALUE, -4096, -1)
+
+#define CSKY_CONST_OK_FOR_US(VALUE) \
+  CSKY_VALUE_BETWEEN (VALUE, -8, -1)
+
+#define CSKY_CONST_OK_FOR_MOVIH(VALUE)         \
+  (((VALUE) & 0xFFFF) == 0)
+
+#ifndef TARGET_CPU_DEFAULT
+#define TARGET_CPU_DEFAULT CSKY_TARGET_CORE_GET(ck810f)
+#endif
+
+/* Options that are enabled by default are specified as such in the
+   .opt file.  */
+#define TARGET_DEFAULT 0
+
+/* The highest CSKY architecture version supported by the target.  */
+#define CSKY_TARGET_ARCH(arch) \
+  (csky_base_arch == CSKY_TARGET_ARCH_GET (arch))
+
+/* Define some macros for target code generation options.  */
+#define TARGET_SOFT_FPU \
+  (csky_fpu_index == TARGET_FPU_fpv2_sf)
+#define TARGET_CASESI \
+  (optimize_size && TARGET_CONSTANT_POOL \
+   && (CSKY_TARGET_ARCH (CK801) || CSKY_TARGET_ARCH (CK802)))
+#define TARGET_TLS \
+  (CSKY_TARGET_ARCH (CK807) || CSKY_TARGET_ARCH (CK810))
+
+/* Number of loads/stores handled by ldm/stm.  */
+#define CSKY_MIN_MULTIPLE_STLD 3
+#define CSKY_MAX_MULTIPLE_STLD 12
+
+/* Pull in enums and defines for processor/arch variants.  This makes
+   it possible to use CSKY_TARGET_ARCH in macros defined in this file.  */
+#include "csky_opts.h"
+extern enum csky_base_architecture csky_base_arch;
+
+/* Pull in enums and defines for ISA features.  Likewise required to
+   support use of CSKY_ISA_FEATURE in this file.
+   Note that the CSKY_ISA_FEATURE macro tests properties of the
+   particular processor we're compiling for, not code generation
+   options that may have dependencies on those features.  The latter
+   are handled by TARGET_xxxx macros/variables instead.  See csky.opt.  */
+#include "csky_isa.h"
+extern int csky_arch_isa_features[];
+#define CSKY_ISA_FEATURE(IDENT) \
+  csky_arch_isa_features[CSKY_ISA_FEATURE_GET (IDENT)]
+
+/******************************************************************
+ *                        Storage Layout                         *
+ ******************************************************************/
+
+
+/* Define this if most significant bit is lowest numbered
+   in instructions that operate on numbered bit-fields.  */
+#define BITS_BIG_ENDIAN         0
+
+/* If the most significant byte of a word is the lowest numbered.  */
+#define BYTES_BIG_ENDIAN (TARGET_BIG_ENDIAN != 0)
+
+/* If the most significant word of a multiword number is the lowest.  */
+#define WORDS_BIG_ENDIAN (BYTES_BIG_ENDIAN)
+
+/* 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  32
+
+/* Boundary (in *bits*) on which stack pointer should be aligned.
+   Per C-SKY, the published V2 ABI document is incorrect and the proper
+   alignment is on a 4-byte boundary rather than 8 bytes.  */
+#define STACK_BOUNDARY 32
+
+/* Align definitions of arrays, unions and structures so that
+   initializations and copies can be made more efficient.  This is not
+   ABI-changing, so it only affects places where we can see the
+   definition. Increasing the alignment tends to introduce padding,
+   so don't do this when optimizing for size/conserving stack space. */
+#define CSKY_EXPAND_ALIGNMENT(COND, EXP, ALIGN) \
+  (((COND) && ((ALIGN) < BITS_PER_WORD)                 \
+    && (TREE_CODE (EXP) == ARRAY_TYPE           \
+       || TREE_CODE (EXP) == UNION_TYPE         \
+       || TREE_CODE (EXP) == RECORD_TYPE))      \
+   ? BITS_PER_WORD : (ALIGN))
+
+/* Align global data. */
+#define DATA_ALIGNMENT(EXP, ALIGN)     \
+  CSKY_EXPAND_ALIGNMENT (!optimize_size, EXP, ALIGN)
+
+/* Similarly, make sure that objects on the stack are sensibly aligned.  */
+#define LOCAL_ALIGNMENT(EXP, ALIGN)      \
+  CSKY_EXPAND_ALIGNMENT (!flag_conserve_stack, EXP, ALIGN)
+
+/* No data type wants to be aligned rounder than this.  */
+#define BIGGEST_ALIGNMENT 32
+
+/* Every structures size must be a multiple of 8 bits.  */
+#define STRUCTURE_SIZE_BOUNDARY 8
+
+/* Look at the fundamental type that is used for a bit-field and use
+   that to impose alignment on the enclosing structure.
+   struct s {int a:8}; should have same alignment as "int", not "char".  */
+#define PCC_BITFIELD_TYPE_MATTERS 1
+
+/* Largest integer machine mode for structures.  If undefined, the default
+   is GET_MODE_SIZE(DImode).  */
+#define MAX_FIXED_MODE_SIZE 64
+
+/* Allocation boundary (in *bits*) for the code of a function.
+   Optimize ck801 and ck802 a little harder for size.  */
+#define FUNCTION_BOUNDARY                                      \
+  (((CSKY_TARGET_ARCH (CK801) || CSKY_TARGET_ARCH (CK802))     \
+    && optimize_size)                                          \
+   ? 16 : 32)
+
+/* C-SKY does not support unaligned access.  */
+#define STRICT_ALIGNMENT    1
+
+#undef SIZE_TYPE
+#define SIZE_TYPE "unsigned int"
+
+#undef PTRDIFF_TYPE
+#define PTRDIFF_TYPE "int"
+
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "long int"
+
+#undef UINT_LEAST32_TYPE
+#define UINT_LEAST32_TYPE "unsigned int"
+
+#undef INT_LEAST32_TYPE
+#define INT_LEAST32_TYPE "int"
+
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE BITS_PER_WORD
+
+/******************************************************************
+ *             Layout of Source Language Data Types              *
+ ******************************************************************/
+
+
+/* 'char' is unsigned by default for backward compatibility.  */
+#define DEFAULT_SIGNED_CHAR    0
+
+
+/******************************************************************
+ *             Stack Layout and Calling Conventions              *
+ ******************************************************************/
+
+
+/* Basic Stack Layout  */
+
+
+/* Define this if pushing a word on the stack
+   makes the stack pointer a smaller address.  */
+#define STACK_GROWS_DOWNWARD   1
+
+/* Define this to nonzero if the nominal address of the stack frame
+   is at the high-address end of the local variables;
+   that is, each additional local variable allocated
+   goes at a more negative offset in the frame.  */
+#define FRAME_GROWS_DOWNWARD   1
+
+/* Offset of first parameter from the argument pointer register value.  */
+#define FIRST_PARM_OFFSET(FNDECL) 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) \
+  csky_return_addr (COUNT, FRAME)
+
+/* Pick up the return address upon entry to a procedure. Used for
+   dwarf2 unwind information.  This also enables the table driven
+   mechanism.  */
+#define INCOMING_RETURN_ADDR_RTX  gen_rtx_REG (Pmode, CSKY_LR_REGNUM)
+
+
+/* Exception Handling Support  */
+
+/* The register that holds the return address in exception handlers.  */
+#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (SImode, CSKY_EH_STACKADJ_REGNUM)
+
+
+/* Registers That Address the Stack Frame  */
+
+
+/* Register to use for pushing function arguments.  */
+#define STACK_POINTER_REGNUM  CSKY_SP_REGNUM
+
+/* Base register for access to local variables of the function.  */
+#define FRAME_POINTER_REGNUM  8
+
+/* Base register for access to arguments of the function.  This is a fake
+   register that is always eliminated.  */
+#define ARG_POINTER_REGNUM    32
+
+/* Static chain register.
+   Register use is more restricted on CK801.  */
+#define STATIC_CHAIN_REGNUM   (CSKY_TARGET_ARCH (CK801) ? 13 : 12)
+
+
+/* Eliminating Frame Pointer and Arg Pointer  */
+
+
+/* Definitions for register eliminations.
+
+   This is an array of structures.  Each structure initializes one pair
+   of eliminable registers.  The "from" register number is given first,
+   followed by "to".  Eliminations of the same "from" register are listed
+   in order of preference.
+
+   We have two registers that can be eliminated on the CSKY.  First, the
+   arg pointer register can often be eliminated in favor of the stack
+   pointer register.  Secondly, the pseudo frame pointer register can always
+   be eliminated; it is replaced with the stack pointer.  */
+#define ELIMINABLE_REGS                  \
+{{ ARG_POINTER_REGNUM,       STACK_POINTER_REGNUM            },\
+ { ARG_POINTER_REGNUM,       FRAME_POINTER_REGNUM            },\
+ { FRAME_POINTER_REGNUM,      STACK_POINTER_REGNUM           }}
+
+/* Define the offset between two registers, one to be eliminated, and the
+   other its replacement, at the start of a routine.  */
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET)     \
+  (OFFSET) = csky_initial_elimination_offset (FROM, TO)
+
+
+/* Passing Function Arguments on the Stack  */
+
+
+/* Define this if the maximum size of all the outgoing args is to be
+   accumulated and pushed during the prologue.  The amount can be
+   found in the variable crtl->outgoing_args_size.  */
+#define ACCUMULATE_OUTGOING_ARGS 1
+
+
+/* Passing Arguments in Registers  */
+
+
+/* A C type for declaring a variable that is used as the first argument of
+   TARGET_ FUNCTION_ARG and other related values.  */
+#define CUMULATIVE_ARGS         int
+
+/* 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.
+
+   On CSKY, the offset always starts at 0: the first parm reg is always
+   the same reg.  */
+#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) \
+  ((CUM) = 0)
+
+/* True if N is a possible register number for function argument passing.
+   On the CSKY, r0-r3 are used to pass args.
+   The int cast is to prevent a complaint about unsigned comparison to
+   zero, since CSKY_FIRST_PARM_REGNUM is zero.  */
+#define FUNCTION_ARG_REGNO_P(REGNO)        \
+  (((int)(REGNO) >= CSKY_FIRST_PARM_REGNUM) &&         \
+   ((REGNO) < (CSKY_NPARM_REGS + CSKY_FIRST_PARM_REGNUM)))
+
+/* How Large Values Are Returned  */
+
+
+/* Define DEFAULT_PCC_STRUCT_RETURN to 1 if all structure and union return
+   values must be in memory.  On the CSKY, small
+   structures (eight bytes or fewer) are returned in
+   the register pair r0/r1.  */
+#define DEFAULT_PCC_STRUCT_RETURN 0
+
+/* 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.
+
+   On the CSKY, the function epilogue recovers the stack pointer from the
+   frame.  */
+#define EXIT_IGNORE_STACK 1
+
+
+/******************************************************************
+ *             Register Usage & Register Classes                 *
+ ******************************************************************/
+
+
+#define FIRST_PSEUDO_REGISTER 71
+
+/* 1 for registers that have pervasive standard uses
+   and are not available for the register allocator.
+   On C-SKY, r14 is SP, r26 is used by linker,
+   r27 is used by assembler, r28 is data base address,
+   r29 is GOT base address, r30 is handler base address,
+   r31 is TLS register.  */
+#define FIXED_REGISTERS                                                        \
+ /*  r0           r1    r2    r3    r4    r5    r6    r7  */                   \
+{    0,           0,    0,    0,    0,    0,    0,    0,                       \
+ /*  r8           r9    r10   r11   r12   r13   r14   r15 */                   \
+     0,           0,    0,    0,    0,    0,    1,    0,                       \
+ /*  r16   r17  r18   r19   r20   r21   r22   r23 */                   \
+     0,           0,    0,    0,    0,    0,    0,    0,                       \
+ /*  r24   r25  r26   r27   r28   r29   r30   tls */                   \
+     0,           0,    1,    1,    1,    1,    1,    1,                       \
+ /*  reserved   c     hi    lo  */                                     \
+     1,                 1,    0,    0,                                         \
+ /*  reserved */                                                       \
+     1,           1,    1,    1,    1,    1,    1,    1,                       \
+     1,           1,    1,    1,    1,    1,    1,    1,                       \
+ /*  vr0   vr1  vr2   vr3   vr4   vr5   vr6   vr7  */                  \
+     0,           0,    0,    0,    0,    0,    0,    0,                       \
+ /*  vr8   vr9  vr10  vr11  vr12  vr13  vr14  vr15 */                  \
+     0,           0,    0,    0,    0,    0,    0,    0 ,                      \
+ /*  reserved */                                                       \
+     1,           1,                                                           \
+ /*  epc */                                                            \
+     1                                                                 \
+}
+
+/* 1 for registers that is clobbered (in general) by function calls.
+   If a register has 0, the compiler automatically saves it on
+   function entry and restores it on function exit, if the register
+   is used within the function.  */
+#define CALL_USED_REGISTERS \
+ /*  r0           r1    r2    r3    r4    r5    r6    r7  */                   \
+{    1,           1,    1,    1,    0,    0,    0,    0,                       \
+ /*  r8           r9    r10   r11   r12   r13   r14   r15 */                   \
+     0,           0,    0,    0,    1,    1,    1,    0,                       \
+ /*  r16   r17  r18   r19   r20   r21   r22   r23 */                   \
+     0,           0,    1,    1,    1,    1,    1,    1,                       \
+ /*  r24   r25  r26   r27   r28   r29   r30   r31 */                   \
+     1,           1,    1,    1,    1,    1,    1,    1,                       \
+ /*  reserved   c     hi    lo */                                      \
+     1,                 1,    1,    1,                                         \
+ /*  reserved */                                                       \
+     1,           1,    1,    1,    1,    1,    1,    1,                       \
+     1,           1,    1,    1,    1,    1,    1,    1,                       \
+ /*  vr0   vr1  vr2   vr3   vr4   vr5   vr6   vr7 */                   \
+     1,           1,    1,    1,    1,    1,    1,    1,                       \
+ /*  vr8   vr9  vr10  vr11  vr12  vr13  vr14  vr15 */                  \
+     1,           1,    1,    1,    1,    1,    1,    1,                       \
+ /*  reserved */                                                       \
+     1,           1,                                                           \
+ /*  epc */                                                            \
+     1                                                                 \
+}
+
+/* Like `CALL_USED_REGISTERS' but used to overcome a historical
+   problem which makes CALL_USED_REGISTERS *always* include
+   all the FIXED_REGISTERS.  Until this problem has been
+   resolved this macro can be used to overcome this situation.
+   In particular, block_propagate() requires this list
+   be accurate, or we can remove registers which should be live.
+   This macro is used in get_csky_live_regs().  */
+#define CALL_REALLY_USED_REGISTERS \
+ /*  r0           r1    r2    r3    r4    r5    r6    r7  */                   \
+{    1,           1,    1,    1,    0,    0,    0,    0,                       \
+ /*  r8           r9    r10   r11   r12   r13   r14   r15 */                   \
+     0,           0,    0,    0,    1,    1,    1,    0,                       \
+ /*  r16   r17  r18   r19   r20   r21   r22   r23 */                   \
+     0,           0,    1,    1,    1,    1,    1,    1,                       \
+ /*  r24   r25  r26   r27   r28   r29   r30   r31 */                   \
+     1,           1,    1,    1,    1,    1,    1,    1,                       \
+ /*  reserved   c     hi    lo */                                      \
+     1,                 1,    1,    1,                                         \
+ /*  reserved */                                                       \
+     1,           1,    1,    1,    1,    1,    1,    1,                       \
+     1,           1,    1,    1,    1,    1,    1,    1,                       \
+ /*  vr0   vr1  vr2   vr3   vr4   vr5   vr6   vr7 */                   \
+     1,           1,    1,    1,    1,    1,    1,    1,                       \
+ /*  vr8   vr9  vr10  vr11  vr12  vr13  vr14  vr15 */                  \
+     1,           1,    1,    1,    1,    1,    1,    1,                       \
+ /*  reserved */                                                       \
+     1,           1,                                                           \
+ /*  epc */                                                            \
+     1                                                                 \
+}
+
+#define REGISTER_NAMES                                                 \
+{                                                                      \
+  "a0",         "a1",  "a2",  "a3",  "l0",  "l1",  "l2",  "l3",                \
+  "l4",         "l5",  "l6",  "l7",  "t0",  "t1",  "sp",  "lr",                \
+  "l8",         "l9",  "t2",  "t3",  "t4",  "t5",  "t6",  "t7",                \
+  "t8",         "t9",  "r26", "r27", "gb",  "r29", "svbr", "r31",              \
+  /* reserved */                                                       \
+  "reserved",                                                          \
+  /* CC register: 33 */                                                        \
+  "c",                                                                 \
+  /* DSP instruction register: 34, 35 */                               \
+  "hi", "lo",                                                          \
+  "reserved", "reserved", "reserved", "reserved", "reserved",          \
+  "reserved", "reserved", "reserved", "reserved", "reserved",          \
+  "reserved", "reserved", "reserved", "reserved", "reserved",          \
+  "reserved",                                                          \
+  /* V registers: 52~67 */                                             \
+  "vr0", "vr1", "vr2", "vr3",  "vr4",  "vr5",  "vr6",  "vr7",          \
+  "vr8", "vr9", "vr10", "vr11", "vr12", "vr13", "vr14", "vr15",                \
+  "reserved", "reserved",                                              \
+  "epc"                                                                        \
+}
+
+/* Table of additional register names to use in user input.  */
+#define ADDITIONAL_REGISTER_NAMES   \
+{                                  \
+  {"r0",  0},                      \
+  {"r1",  1},                      \
+  {"r2",  2},                      \
+  {"r3",  3},                      \
+  {"r4",  4},                      \
+  {"r5",  5},                      \
+  {"r6",  6},                      \
+  {"r7",  7},                      \
+  {"r8",  8},                      \
+  {"r9",  9},                      \
+  {"r10", 10},                     \
+  {"r11", 11},                     \
+  {"r12", 12},                     \
+  {"r13", 13},                     \
+  {"r14", 14},                     \
+  {"r15", 15},                     \
+  {"r16", 16},                     \
+  {"r17", 17},                     \
+  {"r18", 18},                     \
+  {"r19", 19},                     \
+  {"r20", 20},                     \
+  {"r21", 21},                     \
+  {"r22", 22},                     \
+  {"r23", 23},                     \
+  {"r24", 24},                     \
+  {"r25", 25},                     \
+  {"r26", 26},                     \
+  {"r27", 27},                     \
+  {"r28", 28},                     \
+  {"r29", 29},                     \
+  {"r30", 30},                     \
+  {"r31", 31},                     \
+}
+
+/* The order in which registers should be allocated.
+   It is better to use the registers the caller need not save.
+   Allocate r0 through r3 in reverse order since r3 is least likely
+   to contain a function parameter; in addition results are returned
+   in r0.  It is quite good to use lr since other calls may clobber
+   it anyway.  */
+#define REG_ALLOC_ORDER                                                \
+/*   r3           r2    r1    r0   r12   r13   r18   r19 */            \
+  {   3,    2,   1,    0,   12,   13,   18,   19,              \
+/*  r20          r21   r22   r23   r24   r25 */                        \
+     20,   21,  22,   23,   24,   25,                          \
+/*   r15   r4   r5   r6     r7    r8    r9   r10   r11 */      \
+     15,    4,   5,   6,     7,    8,    9,   10,   11,        \
+/*  r16          r17   r26   r27   r28   r29   r30    hi    lo  */     \
+     16,   17,  26,   27,   28,   29,   30,   34,   35,        \
+/*  vr0          vr1   vr2   vr3   vr4   vr5   vr6   vr7  */           \
+     52,   53,  54,   55,   56,   57,   58,   59,              \
+/*  vr8          vr9   vr10  vr11  vr12  vr13  vr14  vr15 */           \
+     60,   61,  62,   63,   64,   65,   66,   67,              \
+/*  reserved  */                                               \
+     36,   37,  38,   39,   40,   41,   42,   43,              \
+     44,   45,  46,   47,   48,   49,   50,   51,              \
+/*  sp   tls   reserved     c     reserved         epc */      \
+     14,   31,  32,         33,   68,   69,         70  }
+
+/*  Register classes.  */
+enum reg_class
+{
+  NO_REGS,
+  MINI_REGS,
+  SP_REGS,
+  LOW_REGS,
+  GENERAL_REGS,
+  C_REGS,
+  HI_REGS,
+  LO_REGS,
+  HILO_REGS,
+  V_REGS,
+  OTHER_REGS,
+  RESERVE_REGS,
+  ALL_REGS,
+  LIM_REG_CLASSES
+};
+
+#define N_REG_CLASSES  (int) LIM_REG_CLASSES
+
+/* Give names of register classes as strings for dump file.  */
+#define REG_CLASS_NAMES \
+{                      \
+  "NO_REGS",           \
+  "MINI_REGS",         \
+  "SP_REGS",           \
+  "LOW_REGS",          \
+  "GENERAL_REGS",      \
+  "C_REGS",            \
+  "HI_REGS",           \
+  "LO_REGS",           \
+  "HILO_REGS",         \
+  "V_REGS",            \
+  "OTHER_REGS",                \
+  "RESERVE_REGS",      \
+  "ALL_REGS",          \
+}
+
+/* Define which registers fit in which classes.  This is an initializer
+   for a vector of HARD_REG_SET of length N_REG_CLASSES.  */
+#define REG_CLASS_CONTENTS                                          \
+{                                                                   \
+  {0x00000000, 0x00000000, 0x00000000 },  /* NO_REGS          */    \
+  {0x000000FF, 0x00000000, 0x00000000 },  /* MINI_REGS        */    \
+  {0x00004000, 0x00000000, 0x00000000 },  /* SP_REGS          */    \
+  {0x0000FFFF, 0x00000000, 0x00000000 },  /* LOW_REGS         */    \
+  {0xFFFFFFFF, 0x00000000, 0x00000000 },  /* GENERAL_REGS      */    \
+  {0x00000000, 0x00000002, 0x00000000 },  /* C_REGS           */    \
+  {0x00000000, 0x00000004, 0x00000000 },  /* HI_REG           */    \
+  {0x00000000, 0x00000008, 0x00000000 },  /* LO_REG           */    \
+  {0x00000000, 0x0000000c, 0x00000000 },  /* HILO_REGS        */    \
+  {0x00000000, 0xFFF00000, 0x0000000F },  /* V_REGS           */    \
+  {0x00000000, 0x00000000, 0x00000040 },  /* OTHER_REGS               */    \
+  {0x00000000, 0x0FF00001, 0x00000030 },  /* RESERVE_REGS      */    \
+  {0xFFFFFFFF, 0xFFFFFFFF, 0x0000007F },  /* ALL_REGS         */    \
+}
+
+/* Return register class from regno.  */
+extern enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER];
+#define REGNO_REG_CLASS(REGNO) regno_reg_class[REGNO]
+
+/* The class value for index registers, and the one for base regs.  */
+#define INDEX_REG_CLASS         (CSKY_ISA_FEATURE (2E3) ? GENERAL_REGS : NO_REGS)
+#define BASE_REG_CLASS GENERAL_REGS
+
+/* TODO is it necessary to set it to MINI_REGS to emit more 16-bit
+   instructions?  */
+#define MODE_BASE_REG_CLASS(MODE) GENERAL_REGS
+
+/* 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 unless they have been allocated suitable hard regs.
+   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.
+   Source files for reload pass need to be strict.
+   After reload, it makes no difference, since pseudo regs have
+   been eliminated by then.
+
+   The reg_renumber is used to map pseudo regs into hardware
+   regs, it is set up as a result of register allocation.  */
+#ifdef REG_OK_STRICT
+#define REGNO_OK_FOR_BASE_P(REGNO)                    \
+  (CSKY_GENERAL_REGNO_P (REGNO)                               \
+   || CSKY_GENERAL_REGNO_P (reg_renumber[(REGNO)]) )
+#else
+#define REGNO_OK_FOR_BASE_P(REGNO)                    \
+  (CSKY_GENERAL_REGNO_P (REGNO)                               \
+   || (REGNO) >= FIRST_PSEUDO_REGISTER)
+#endif
+
+
+#ifdef REG_OK_STRICT
+#define REGNO_OK_FOR_INDEX_P(REGNO)                    \
+  (CSKY_GENERAL_REGNO_P (REGNO)                                \
+   || CSKY_GENERAL_REGNO_P (reg_renumber[(REGNO)]) )
+#else
+#define REGNO_OK_FOR_INDEX_P(REGNO)                  \
+  (CSKY_GENERAL_REGNO_P (REGNO)                              \
+   || (REGNO) >= FIRST_PSEUDO_REGISTER)
+#endif
+
+
+/******************************************************************
+ *                       Addressing Modes                        *
+ ******************************************************************/
+
+
+/* Recognize any constant value that is a valid address.  */
+#define CONSTANT_ADDRESS_P(X) \
+  (GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF)
+
+/* Maximum number of registers that can appear in a valid memory address.
+   Shifts in addresses can't be by a register.  */
+#define MAX_REGS_PER_ADDRESS 2
+
+
+/******************************************************************
+ *                       Run-time Target                         *
+ ******************************************************************/
+
+
+#define TARGET_CPU_CPP_BUILTINS()                    \
+  csky_cpu_cpp_builtins (pfile)
+
+/******************************************************************
+ *                     Per-function Data                         *
+ ******************************************************************/
+
+
+/* Initialize data used by insn expanders.  This is called from insn_emit,
+   once for every function before code is generated.  */
+#define INIT_EXPANDERS csky_init_expanders ()
+
+
+/******************************************************************
+ *    Dividing the Output into Sections (Texts, Data, . . . )    *
+ ******************************************************************/
+
+
+/* Switch to the text or data segment.  */
+#define TEXT_SECTION_ASM_OP  "\t.text"
+#define DATA_SECTION_ASM_OP  "\t.data"
+
+/* The subroutine calls in the .init and .fini sections create literal
+   pools which must be jumped around...  */
+#define FORCE_CODE_SECTION_ALIGN    \
+  asm ("br 1f ; .literals ; .align 2 ; 1:");
+
+/* Define this macro to be an expression with a nonzero value if
+   jump tables (for tablejump insns) should be output in the text section,
+   along with the assembler instructions.  */
+#define JUMP_TABLES_IN_TEXT_SECTION TARGET_CASESI
+
+
+/******************************************************************
+ *                     Assembler Format                          *
+ ******************************************************************/
+
+
+/* A C string constant for text to be output before(after) each asm
+   statement or group of consecutive ones.  */
+#undef ASM_APP_ON
+#define ASM_APP_ON    "// inline asm begin\n"
+#undef ASM_APP_OFF
+#define ASM_APP_OFF   "// inline asm end\n"
+
+/* A C string constant describing how to begin a comment in the target
+   assembler language.  */
+#define ASM_COMMENT_START "\t//"
+
+/* This says how to output an assembler line
+   to define a global common symbol, with alignment information.  */
+#undef ASM_OUTPUT_ALIGNED_COMMON
+#define ASM_OUTPUT_ALIGNED_COMMON(STREAM, NAME, SIZE, ALIGN)   \
+  do                                                           \
+    {                                                          \
+      fputs ("\t.comm\t", STREAM);                             \
+      assemble_name (STREAM, NAME);                            \
+      fprintf (STREAM, ",%lu, %u\n", (unsigned long)(SIZE),    \
+              (ALIGN) / BITS_PER_UNIT);                        \
+    }                                                          \
+while (0)
+
+/* Define a local common symbol whose alignment we wish to specify.
+   ALIGN comes in as bits, we have to turn it into bytes.  */
+#undef ASM_OUTPUT_ALIGNED_LOCAL
+#define ASM_OUTPUT_ALIGNED_LOCAL(STREAM, NAME, SIZE, ALIGN)    \
+  do                                                           \
+{                                                              \
+  fputs ("\t.bss\t", (STREAM));                                        \
+  assemble_name ((STREAM), (NAME));                            \
+  fprintf ((STREAM), ",%d, %d\n", (int)(SIZE),                 \
+          (ALIGN) / BITS_PER_UNIT);                            \
+}                                                              \
+while (0)
+
+/* Globalizing directive for a label.  */
+#define GLOBAL_ASM_OP "\t.global\t"
+
+/* Output a reference to a label.  */
+#undef ASM_OUTPUT_LABELREF
+#define ASM_OUTPUT_LABELREF(STREAM, NAME)     \
+  fprintf (STREAM, "%s%s", user_label_prefix, \
+          (* targetm.strip_name_encoding) (NAME))
+
+/* Make an internal label into a string.  */
+#undef ASM_GENERATE_INTERNAL_LABEL
+#define ASM_GENERATE_INTERNAL_LABEL(STRING, PREFIX, NUM)  \
+  sprintf (STRING, "*.%s%ld", PREFIX, (long) NUM)
+
+/* This is how to output an insn to push a register on the stack.
+   It need not be very fast code.  */
+#define ASM_OUTPUT_REG_PUSH(STREAM,REGNO)                  \
+  fprintf (STREAM, "\tsubi\t %s,%d\n\tst.w\t %s,(%s)\n",    \
+          reg_names[STACK_POINTER_REGNUM],                 \
+          (STACK_BOUNDARY / BITS_PER_UNIT),                \
+          reg_names[REGNO],                                \
+          reg_names[STACK_POINTER_REGNUM])
+
+/* This is how to output an insn to pop a register from the stack.  */
+#define ASM_OUTPUT_REG_POP(STREAM,REGNO)                   \
+  fprintf (STREAM, "\tld.w\t %s,(%s)\n\taddi\t %s,%d\n",    \
+          reg_names[REGNO],                                \
+          reg_names[STACK_POINTER_REGNUM],                 \
+          reg_names[STACK_POINTER_REGNUM],                 \
+          (STACK_BOUNDARY / BITS_PER_UNIT))
+
+/* Output an element of a dispatch table.  */
+#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM,VALUE)  \
+  fprintf (STREAM, "\t.long\t.L%d\n", VALUE)
+
+/* This is how to output an assembler line
+   that says to advance the location counter by SIZE bytes.  */
+#undef ASM_OUTPUT_SKIP
+#define ASM_OUTPUT_SKIP(STREAM,SIZE)  \
+  fprintf (STREAM, "\t.fill %d, 1\n", (int)(SIZE))
+
+/* Align output to a power of two.  Note ".align 0" is redundant,
+   and also GAS will treat it as ".align 2" which we do not want.  */
+#define ASM_OUTPUT_ALIGN(STREAM, POWER)                        \
+  do                                                   \
+    {                                                  \
+      if ((POWER) > 0)                                 \
+       fprintf (STREAM, "\t.align\t%d\n", POWER);      \
+    }                                                  \
+  while (0)
+
+
+/******************************************************************
+ *             Controlling the Compilation Driver                *
+ ******************************************************************/
+
+
+/* Define this macro as a C expression for the initializer of an
+   array of string to tell the driver program which options are
+   defaults for this target and thus do not need to be handled
+   specially when using MULTILIB_OPTIONS.  */
+#undef MULTILIB_DEFAULTS
+#define MULTILIB_DEFAULTS    \
+    {"mlittle-endian", "mcpu=ck810f", "msoft-float"}
+
+/* Support for a compile-time default CPU, et cetera.  The rules are:
+   --with-arch is ignored if -march or -mcpu are specified.
+   --with-cpu is ignored if -march or -mcpu are specified, and is overridden
+    by --with-arch. */
+#define OPTION_DEFAULT_SPECS \
+  {"arch", "%{!march=*:%{!mcpu=*:-march=%(VALUE)}}" }, \
+  {"cpu", "%{!march=*:%{!mcpu=*:-mcpu=%(VALUE)}}" }, \
+  {"endian", "%{!mbig-endian:%{!mlittle-endian:-m%(VALUE)-endian}}" }, \
+  {"float", "%{!msoft-float:%{!mhard-float:-m%(VALUE)-float}}" },
+
+
+/******************************************************************
+ *                   Position Independent Code                   *
+ ******************************************************************/
+
+/* Define the global table register.  */
+#define PIC_OFFSET_TABLE_REGNUM (flag_pic ? CSKY_GB_REGNUM : INVALID_REGNUM)
+
+/* Nonzero if x is a legitimate immediate operand on the target machine
+   when generating position-independent code.  */
+#define LEGITIMATE_PIC_OPERAND_P(X) \
+  csky_legitimate_pic_operand_p (X)
+
+
+/******************************************************************
+ *           Controlling Debugging Information Format            *
+ ******************************************************************/
+
+
+/* Define this macro if GCC should produce dwarf version 2 format debugging
+   output in response to the `-g' option.  */
+#define DWARF2_DEBUGGING_INFO 1
+
+/* Define this macro to 0 if your target supports DWARF 2 frame unwind
+   information, but it does not yet work with exception handling.  */
+#define DWARF2_UNWIND_INFO 1
+
+/* Define this if you have arranged for GCC to support
+   more than one format of debugging output.
+   The value of this macro only affects the default debugging output.  */
+#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
+
+/* Define this macro if the target’s representation
+   for dwarf registers used in .eh_frame or .debug_frame
+   is different from that used in other debug info sections.
+   Given a GCC hard register number,
+   this macro should return the .eh_frame register number.*/
+#define DWARF_FRAME_REGNUM(REG)         DBX_REGISTER_NUMBER (REG)
+
+/* If INCOMING_RETURN_ADDR_RTX is defined & the RTL is REG,
+   define DWARF_FRAME_RETURN_COLUMN to DWARF_FRAME_REGNUM.  */
+#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (CSKY_LR_REGNUM)
+
+/* Use r0 and r1 to pass exception handling information.  */
+#define EH_RETURN_DATA_REGNO(N) ((N) < 2 ? N : INVALID_REGNUM)
+
+/* How to renumber registers for dbx and gdb.  */
+extern const int csky_dbx_regno[];
+#define DBX_REGISTER_NUMBER(REGNO) ((unsigned int) csky_dbx_regno[REGNO])
+
+
+/******************************************************************
+ *                   Miscellaneous Parameters                    *
+ ******************************************************************/
+
+
+/* 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 1
+
+/* Define if loading in MODE, an integral mode narrower than BITS_PER_WORD
+   will either zero-extend or sign-extend.  The value of this macro should
+   be the code that says which one of the two operations is implicitly
+   done, UNKNOWN if none.  */
+#define LOAD_EXTEND_OP(MODE) ZERO_EXTEND
+
+/* Max number of bytes we can move from memory to memory
+   in one reasonably fast instruction.  */
+#define MOVE_MAX 4
+
+/* Shift counts are truncated to 6-bits (0 to 63) instead of the expected
+   5-bits, so we can not define SHIFT_COUNT_TRUNCATED to true for this
+   target.  */
+#define SHIFT_COUNT_TRUNCATED 0
+
+#define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) ((VALUE) = 32, 1)
+
+/* The machine modes of pointers and functions.  */
+#define Pmode  SImode
+#define FUNCTION_MODE  Pmode
+
+/* Define this macro to be a C expression to indicate when jump-tables
+   should contain relative addresses.  */
+#define CASE_VECTOR_PC_RELATIVE \
+  (optimize_size && TARGET_CONSTANT_POOL \
+   && (CSKY_TARGET_ARCH (CK802) || CSKY_TARGET_ARCH (CK801)))
+
+/* Return the preferred mode for an addr_diff_vec when the minimum
+   and maximum offset are known.  */
+#define CASE_VECTOR_SHORTEN_MODE(min, max, body)                   \
+  (min >= 0 && max < 512                                           \
+   ? (ADDR_DIFF_VEC_FLAGS (body).offset_unsigned = 1, QImode)      \
+   : min >= -256 && max < 256                                      \
+     ? (ADDR_DIFF_VEC_FLAGS (body).offset_unsigned = 0, QImode)            \
+     : min >= 0 && max < 8192                                      \
+       ? (ADDR_DIFF_VEC_FLAGS (body).offset_unsigned = 1, HImode)   \
+       : min >= -4096 && max < 4096                                \
+        ? (ADDR_DIFF_VEC_FLAGS (body).offset_unsigned = 0, HImode) \
+        : SImode)
+
+/* This is how to output an element of a case-vector that is relative.  */
+#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM, BODY, VALUE, REL)         \
+  do                                                               \
+    {                                                              \
+      if (optimize_size && TARGET_CONSTANT_POOL                            \
+         && (CSKY_TARGET_ARCH (CK802) || CSKY_TARGET_ARCH (CK801)))  \
+       {                                                           \
+         switch (GET_MODE (BODY))                                  \
+           {                                                       \
+           case E_QImode:                                          \
+             asm_fprintf (STREAM, "\t.byte\t(.L%d-.L%d)/2\n",      \
+                          VALUE, REL);                             \
+             break;                                                \
+           case E_HImode: /* TBH */                                \
+             asm_fprintf (STREAM, "\t.short\t(.L%d-.L%d)/2\n",     \
+                          VALUE, REL);                             \
+             break;                                                \
+           case E_SImode:                                          \
+             asm_fprintf (STREAM, "\t.long\t.L%d-.L%d\n",          \
+                          VALUE, REL);                             \
+             break;                                                \
+           default:                                                \
+             gcc_unreachable ();                                   \
+           }                                                       \
+       }                                                           \
+      else                                                         \
+       asm_fprintf (STREAM, "\t.long\t.L%d@GOTOFF\n", VALUE);      \
+    } while (0)
+
+/* This macro is not documented yet.
+   But we do need it to make jump table vector aligned.  */
+#define ADDR_VEC_ALIGN(JUMPTABLE) 0
+
+/* We have to undef this first to override the version from elfos.h.  */
+#undef ASM_OUTPUT_CASE_LABEL
+#define ASM_OUTPUT_CASE_LABEL(stream, prefix, num, table)      \
+  do                                                           \
+    {                                                          \
+      if (GET_MODE (PATTERN (table)) == SImode)                        \
+       ASM_OUTPUT_ALIGN (stream, 2);                           \
+      (*targetm.asm_out.internal_label) (stream, prefix, num); \
+    } while (0)
+
+/* Make sure subsequent insns are aligned after a byte-sized jump offset
+   table.  */
+#define ASM_OUTPUT_CASE_END(stream, num, table)          \
+  do                                             \
+    {                                            \
+      if (GET_MODE (PATTERN (table)) == QImode)          \
+       ASM_OUTPUT_ALIGN (stream, 1);             \
+    } while (0)
+
+
+
+
+/******************************************************************
+ *               Trampolines for Nested Functions                *
+ ******************************************************************/
+
+
+/* Length in units of the trampoline for entering a nested function.  */
+#define TRAMPOLINE_SIZE         (CSKY_ISA_FEATURE (2E3) ? 16 : 20)
+
+/* Alignment required for a trampoline in bits.  */
+#define TRAMPOLINE_ALIGNMENT  32
+
+
+/******************************************************************
+ *           Describing Relative Costs of Operations             *
+ ******************************************************************/
+
+
+/* Nonzero if access to memory by bytes is slow and undesirable.
+   For RISC chips, it means that access to memory by bytes is no
+   better than access by words when possible, so grab a whole word
+   and maybe make use of that.  */
+#define SLOW_BYTE_ACCESS  0
+
+/* On C-SKY, function CSE would allow use of 16-bit jsr instructions
+   instead of normal 32-bit calls.  But it also needs a separate constant
+   pool entry for the function address and an instruction to load it, and
+   may cause additional spills due to increased register pressure, etc.
+   It doesn't seem like a good idea overall.  */
+#define NO_FUNCTION_CSE 1
+
+/* Try to generate sequences that don't involve branches, we can then use
+   conditional instructions.  */
+#define BRANCH_COST(speed_p, predictable_p)                    \
+  csky_default_branch_cost (speed_p, predictable_p)
+
+/* False if short circuit operation is preferred.  */
+#define LOGICAL_OP_NON_SHORT_CIRCUIT \
+  (csky_default_logical_op_non_short_circuit ())
+
+
+/******************************************************************
+ *                Generating Code for Profiling                  *
+ ******************************************************************/
+
+
+#define FUNCTION_PROFILER(FILE, LABELNO)
+
+#endif /* GCC_CSKY_H */
diff --git a/gcc/config/csky/csky.md b/gcc/config/csky/csky.md
new file mode 100644 (file)
index 0000000..4f6329d
--- /dev/null
@@ -0,0 +1,3798 @@
+;; Machine description for C-SKY processors.
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+;; Contributed by C-SKY Microsystems and Mentor Graphics.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.  */
+
+
+;; ------------------------------------------------------------------------
+;; Constant
+;; ------------------------------------------------------------------------
+
+;; Register numbering.
+
+(define_constants
+  [(CSKY_NGPR_REGS                     32)
+   (CSKY_NPARM_REGS                    4)
+   (CSKY_FIRST_PARM_REGNUM             0)
+   (CSKY_FIRST_RET_REGNUM              0)
+   (CSKY_FIRST_VFP_REGNUM              52)
+   (CSKY_LAST_VFP_REGNUM               67)
+   (CSKY_FIRST_HIGH_REGNUM             16)
+   (CSKY_LAST_HIGH_REGNUM              31)
+   (CSKY_FIRST_MINI_REGNUM             0)
+   (CSKY_LAST_MINI_REGNUM              7)
+   (CSKY_T0_REGNUM                     12)
+   (CSKY_T1_REGNUM                     13)
+   (CSKY_SP_REGNUM                     14)
+   (CSKY_CC_REGNUM                     33)
+   (CSKY_HI_REGNUM                     34)
+   (CSKY_LO_REGNUM                     35)
+   (CSKY_LR_REGNUM                     15)
+   (CSKY_LAST_HIGH_UNFIXED_REGNUM      25)
+   (CSKY_GB_REGNUM                     28)
+   (CSKY_TLS_REGNUM                    31)
+   (CSKY_FIRST_EH_RETDATA_REGNUM       0)
+   (CSKY_LAST_EH_RETDATA_REGNUM                1)
+   (CSKY_EH_STACKADJ_REGNUM            2)
+   (CSKY_STACKADJUST_REGNUM            4)
+])
+
+;; Supported TLS relocations.
+
+(define_constants
+  [(TLS_GD32              0)
+   (TLS_LDM32             1)
+   (TLS_LDO32             2)
+   (TLS_IE32              3)
+   (TLS_LE32              4)
+])
+
+;; Unspec constants.
+
+(define_c_enum "unspec"
+  [
+   ; Push or pop multiple operation: operand 0 is the first register,
+   ; subsequent registers are in parallel (use ...) expressions.
+   UNSPEC_PUSHPOP_MULT
+
+   ; Represent TLS base, TLS offset, and TLS base + offset, respectively.
+   UNSPEC_TLS_BASE
+   UNSPEC_TLS_LABEL
+   UNSPEC_TLS
+
+   ; PIC symbol relocations.
+   UNSPEC_PIC_SYMBOL_GOTPC
+   UNSPEC_PIC_SYMBOL_GOTPC_GRS
+   UNSPEC_PIC_SYMBOL_GOTOFF
+   UNSPEC_PIC_SYMBOL_GOT
+   UNSPEC_PIC_SYMBOL_PLT
+   UNSPEC_PIC_SYMBOL_BSR
+   UNSPEC_PIC_SYMBOL_GRS
+
+   ; casesi dispatch table.
+   UNSPEC_CSKY_CASESI
+  ])
+
+
+(define_c_enum "unspecv"
+  [
+   ; Used for constant pools.
+   VUNSPEC_ALIGN
+   VUNSPEC_POOL_LABEL
+   VUNSPEC_POOL_4
+   VUNSPEC_POOL_8
+   VUNSPEC_SYMBOL_REF
+
+   ; Support for the eh_return pattern.
+   VUNSPEC_EH_RETURN
+  ])
+
+
+;; ------------------------------------------------------------------------
+;; Attributes
+;; ------------------------------------------------------------------------
+
+;; LENGTH of an instruction (in bytes).
+
+(define_attr "length" ""
+  (if_then_else (match_test "CSKY_TARGET_ARCH (CK801)")
+    (const_int 2)
+    (const_int 4)))
+
+;; Used for ck801 to represent whether we need to use bsr for long
+;; distance jumps.  If set to yes, the function will save lr in the
+;; prologue.
+
+(define_attr "far_jump" "yes,no" (const_string "no"))
+
+;; Used for insn schedule.
+
+(define_attr "type"
+    "alu,load,store,cmp,branch,cbranch,addsub,alu_ix,branch_jmp,call_jsr,call"
+    (const_string "alu"))
+
+
+;; ------------------------------------------------------------------------
+;; Include files
+;; ------------------------------------------------------------------------
+
+(include "constraints.md")
+(include "predicates.md")
+(include "csky_insn_fpu.md")
+(include "csky_insn_dsp.md")
+(include "csky_pipeline_ck801.md")
+(include "csky_pipeline_ck802.md")
+(include "csky_pipeline_ck803.md")
+(include "csky_pipeline_ck810.md")
+
+;; ------------------------------------------------------------------------
+;; Mov insns
+;; ------------------------------------------------------------------------
+
+(define_mode_iterator QHI [QI HI])
+
+(define_expand "movsi"
+  [(set (match_operand:SI 0 "general_operand" "")
+       (match_operand:SI 1 "general_operand" ""))]
+  ""
+  "
+  {
+    rtx scratch = !can_create_pseudo_p () ? operands[0] : 0;
+    if (can_create_pseudo_p () && MEM_P (operands[0]))
+      {
+       operands[1] = force_reg (SImode, operands[1]);
+       emit_insn (gen_rtx_SET (operands[0], operands[1]));
+       DONE;
+      }
+
+    /* Recognize the case where operand[1] is a reference to thread-local
+       data and load its address to a register.  */
+    if (csky_tls_referenced_p (operands[1]))
+      {
+       rtx tmp = operands[1];
+       rtx addend = NULL;
+
+       if (GET_CODE (tmp) == CONST && GET_CODE (XEXP (tmp, 0)) == PLUS)
+         {
+           addend = XEXP (XEXP (tmp, 0), 1);
+           tmp = XEXP (XEXP (tmp, 0), 0);
+         }
+
+       gcc_assert (GET_CODE (tmp) == SYMBOL_REF);
+       gcc_assert (SYMBOL_REF_TLS_MODEL (tmp) != 0);
+
+       tmp = csky_legitimize_tls_address (tmp, scratch);
+       if (addend)
+         {
+           tmp = gen_rtx_PLUS (SImode, tmp, addend);
+           tmp = force_operand (tmp, operands[0]);
+         }
+       operands[1] = tmp;
+      }
+    else if (flag_pic
+            && (CONSTANT_P (operands[1])
+                || csky_symbol_mentioned_p (operands[1])
+                || csky_label_mentioned_p (operands[1])))
+       operands[1] = csky_legitimize_pic_address (operands[1], scratch, true);
+  }"
+)
+
+;; Note that we conservatively estimate all load and store insns as having
+;; a size of 4 bytes throughout even though some variants can be encoded
+;; as 2-byte machine instructions.  Getting more accurate instruction counts
+;; would be better handled by calling into a C function than encoding it
+;; as an RTL conditional here.
+;; Also note that we don't count the extra space required for constant
+;; pool entries here; that's handled by the constant pool entries themselves.
+;; In -mno-constpool cases where we're relying on the assembler to create
+;; the constant pool, we'll undercount branch lengths, but in that case the
+;; assembler also handles branch relaxation as needed.  It's only ck801 that
+;; requires compiler cooperation when long branches are needed.
+
+(define_insn "*cskyv2_movsi"
+  [(set (match_operand:SI 0 "nonimmediate_operand"  "=b,r,r,r, r, r, r,r,  m,r,*y,*r,*v,*r,*v")
+       (match_operand:SI 1 "general_operand"       " b,r,I,Un,Uc,Uo,m,miF,r,c,*r,*y,*r,*v,*v"))]
+  "CSKY_ISA_FEATURE (E2)"
+  "* return csky_output_move (insn, operands, SImode);"
+  [(set_attr "length" "2,4,4,4,4,8,4,4,4,4,4,4,4,4,4")
+   (set_attr "type" "alu,alu,alu,alu,alu,alu,load,load,store,alu,alu,alu,alu,alu,alu")]
+)
+
+(define_insn "*ck801_movsi"
+  [(set (match_operand:SI 0 "nonimmediate_operand"   "=r,a, a,r,r,  m,r")
+       (match_operand:SI 1 "general_operand"        "r, Up,T,m,miF,r,c"))]
+  "CSKY_ISA_FEATURE (E1)"
+  "* return csky_output_ck801_move (insn, operands, SImode);"
+  [(set_attr "length" "2,2,2,4,4,4,2")
+   (set_attr "type" "alu,alu,alu,load,load,store,alu")]
+)
+
+;; Convert negative assignments to zero minus positive numbers.
+(define_split
+  [(set (match_operand:SI 0 "register_operand" "")
+       (match_operand:SI 1 "const_int_operand" ""))]
+    "satisfies_constraint_T (operands[1])"
+    [(set (match_dup 0) (match_dup 2))
+     (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))]
+    "operands[2] = const0_rtx;"
+)
+
+;; Convert const assignments to small number of assignments and left shift.
+(define_split
+  [(set (match_operand:SI 0 "register_operand" "")
+       (match_operand:SI 1 "const_int_operand" ""))]
+  ""
+  [(set (match_dup 0) (match_dup 1))
+   (set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))]
+  "
+  {
+    unsigned int base, shift;
+
+    if (!csky_shifted_imm8_constant (INTVAL (operands[1]), &base, &shift))
+      FAIL;
+    if (shift == 0)
+      FAIL;
+    operands[1] = GEN_INT (base);
+    operands[2] = GEN_INT (shift);
+  }"
+)
+
+
+(define_expand "movhi"
+  [(set (match_operand:HI 0 "general_operand" "")
+       (match_operand:HI 1 "general_operand"  ""))]
+  ""
+  "
+  {
+    if (GET_CODE (operands[0]) == MEM)
+       operands[1] = force_reg (HImode, operands[1]);
+    else if (CONSTANT_P (operands[1])
+            && (GET_CODE (operands[1]) != CONST_INT
+                || (! CSKY_CONST_OK_FOR_I (INTVAL (operands[1]))
+                    && ! CSKY_CONST_OK_FOR_Ub (INTVAL (operands[1]))
+                    && ! CSKY_CONST_OK_FOR_Uc (INTVAL (operands[1]))))
+            && ! reload_completed && ! reload_in_progress)
+      {
+       rtx reg = gen_reg_rtx (SImode);
+       emit_insn (gen_movsi (reg, operands[1]));
+       operands[1] = gen_lowpart (HImode, reg);
+      }
+  }"
+)
+
+(define_insn "*cskyv2_movhi"
+  [(set (match_operand:HI 0 "nonimmediate_operand"  "=b,r,r,r, r, r, r,r,  m,r,*y,*r,*v,*r,*v")
+       (match_operand:HI 1 "general_operand"       " b,r,I,Un,Uc,Uo,m,miF,r,c,*r,*y,*r,*v,*v"))]
+  "CSKY_ISA_FEATURE (E2)"
+  "* return csky_output_move (insn, operands, HImode);"
+  [(set_attr "length" "2,4,4,4,4,8,4,4,4,4,4,4,4,4,4")
+   (set_attr "type" "alu,alu,alu,alu,alu,alu,load,load,store,alu,alu,alu,alu,alu,alu")]
+)
+
+(define_insn "*ck801_movhi"
+  [(set (match_operand:HI 0 "nonimmediate_operand"   "=r,a, a,r,r,  m,r")
+       (match_operand:HI 1 "general_operand"        "r, Up,T,m,miF,r,c"))]
+  "CSKY_ISA_FEATURE (E1)"
+  "* return csky_output_ck801_move (insn, operands, HImode);"
+  [(set_attr "length" "2,2,2,4,4,4,2")
+   (set_attr "type" "alu,alu,alu,load,load,store,alu")]
+)
+
+
+(define_expand "movqi"
+  [(set (match_operand:QI 0 "general_operand" "")
+       (match_operand:QI 1 "general_operand"  ""))]
+  ""
+  "
+  {
+    if (can_create_pseudo_p () && GET_CODE (operands[0]) == MEM)
+       operands[1] = force_reg (QImode, operands[1]);
+    else if (CONSTANT_P (operands[1])
+            && (GET_CODE (operands[1]) != CONST_INT
+                || (! CSKY_CONST_OK_FOR_I (INTVAL (operands[1]))
+                    && ! CSKY_CONST_OK_FOR_Ub (INTVAL (operands[1]))
+                    && ! CSKY_CONST_OK_FOR_Uc (INTVAL (operands[1]))))
+            && ! reload_completed && ! reload_in_progress)
+      {
+       rtx reg = gen_reg_rtx (SImode);
+       emit_insn (gen_movsi (reg, operands[1]));
+       operands[1] = gen_lowpart (QImode, reg);
+      }
+  }"
+)
+
+(define_insn "*cskyv2_movqi"
+  [(set (match_operand:QI 0 "nonimmediate_operand"  "=b,r,r,r, r, r, r,r,  m,r,*y,*r,*v,*r,*v")
+       (match_operand:QI 1 "general_operand"       " b,r,I,Un,Uc,Uo,m,miF,r,c,*r,*y,*r,*v,*v"))]
+  "CSKY_ISA_FEATURE (E2)"
+  "* return csky_output_move (insn, operands, QImode);"
+  [(set_attr "length" "2,4,4,4,4,8,4,4,4,4,4,4,4,4,4")
+   (set_attr "type" "alu,alu,alu,alu,alu,alu,load,load,store,alu,alu,alu,alu,alu,alu")]
+)
+
+(define_insn "*ck801_movqi"
+  [(set (match_operand:QI 0 "nonimmediate_operand"   "=r,a, a,r,r,  m,r")
+       (match_operand:QI 1 "general_operand"        "r, Up,T,m,miF,r,c"))]
+  "CSKY_ISA_FEATURE (E1)"
+  "* return csky_output_ck801_move (insn, operands, QImode);"
+  [(set_attr "length" "2,2,2,4,4,4,2")
+   (set_attr "type" "alu,alu,alu,load,load,store,alu")]
+)
+
+
+(define_expand "movdi"
+  [(set (match_operand:DI 0 "general_operand" "")
+       (match_operand:DI 1 "general_operand" ""))]
+  ""
+  "if (can_create_pseudo_p () && GET_CODE (operands[0]) == MEM)
+      operands[1] = force_reg (DImode, operands[1]);"
+)
+
+;; Convert negative assignments to zero minus positive numbers.
+(define_split
+  [(set (match_operand:QHI 0 "register_operand" "")
+       (match_operand:QHI 1 "const_int_operand" ""))]
+  "satisfies_constraint_T (operands[1])"
+  [(set (match_dup 4) (match_dup 2))
+   (set (match_dup 4) (match_dup 3))
+   (set (match_dup 0) (match_dup 5))]
+  "
+  {
+    int low;
+
+    if (TARGET_BIG_ENDIAN)
+      low = 4 - mode_size[GET_MODE (operands[0])];
+    else
+      low = 0;
+    operands[2] = const0_rtx;
+    if (can_create_pseudo_p ())
+      operands[4] = gen_reg_rtx (SImode);
+    else
+      operands[4] = gen_rtx_REG (SImode, REGNO (operands[0]));
+    operands[3] = gen_rtx_PLUS (SImode, operands[4], operands[1]);
+    operands[5] = gen_rtx_SUBREG (GET_MODE (operands[0]), operands[4], low);
+  }"
+)
+
+;; Convert const assignments to small number of assignments and left shift.
+(define_split
+  [(set (match_operand:QHI 0 "register_operand" "")
+       (match_operand:QHI 1 "const_int_operand" ""))]
+  ""
+  [(set (match_dup 3) (match_dup 1))
+   (set (match_dup 3) (ashift:SI (match_dup 3) (match_dup 2)))
+   (set (match_dup 0) (match_dup 4))]
+  "
+  {
+    unsigned int base, shift;
+    int low;
+
+    if (!csky_shifted_imm8_constant (INTVAL (operands[1]), &base, &shift))
+      FAIL;
+    if (shift == 0)
+      FAIL;
+
+    if (TARGET_BIG_ENDIAN)
+      low = 4 - mode_size[GET_MODE (operands[0])];
+    else
+      low = 0;
+
+    operands[1] = GEN_INT (base);
+    operands[2] = GEN_INT (shift);
+    if (can_create_pseudo_p ())
+      operands[3] = gen_reg_rtx (SImode);
+    else
+      operands[3] = gen_rtx_REG (SImode, REGNO (operands[0]));
+    operands[4] = gen_rtx_SUBREG (GET_MODE (operands[0]), operands[3], low);
+  }"
+)
+
+
+(define_insn "*csky_movdi"
+  [(set (match_operand:DI 0 "nonimmediate_operand"  "=b,r,r, r,r,  m,*r,*y,*v,*r,*v")
+       (match_operand:DI 1 "general_operand"       " b,r,Ud,m,miF,r,*y,*r,*r,*v,*v"))]
+ "CSKY_ISA_FEATURE (E2)"
+ "* return csky_output_movedouble (operands, DImode);"
+ [(set_attr "length" "4,8,8,8,8,8,16,16,16,16,16")
+  (set_attr "type" "alu,alu,alu,load,load,store,alu,alu,alu,alu,alu")]
+)
+
+(define_insn "*ck801_movdi"
+  [(set (match_operand:DI 0 "nonimmediate_operand"  "=r,a, a,r,r,  m")
+       (match_operand:DI 1 "general_operand"       "r, Up,T,m,miF,r"))]
+  "CSKY_ISA_FEATURE (E1)"
+  "* return csky_output_ck801_movedouble (operands, DImode);"
+  [(set_attr "length" "4,4,4,8,8,8")
+   (set_attr "type" "alu,alu,alu,load,load,store")]
+)
+
+;; Float mov instructions.
+
+(define_expand "movsf"
+  [(set (match_operand:SF 0 "general_operand" "")
+       (match_operand:SF 1 "general_operand" ""))]
+  ""
+  "
+  if (GET_CODE (operands[0]) == MEM && can_create_pseudo_p ())
+    operands[1] = force_reg (SFmode, operands[1]);
+  "
+)
+
+;; FIXME: maybe the vreg load/stores should have their own type attr.
+(define_insn "*csky_movsf_fpv2"
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=b,r,v,r,r,r, m,Q,v,v,v")
+       (match_operand:SF 1 "general_operand"      " b,r,r,v,m,mF,r,v,Q,v,m"))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "* return csky_output_move (insn, operands, SFmode);"
+  [(set_attr "length" "2,4,4,4,4,4,4,4,4,4,4")
+   (set_attr "type" "alu,alu,alu,alu,load,load,store,alu,alu,alu,alu")]
+)
+
+(define_insn "*ck801_movsf"
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,r, m")
+       (match_operand:SF 1 "general_operand"      " r,m,mF,r"))]
+  "CSKY_ISA_FEATURE (E1)"
+  "* return csky_output_ck801_move (insn, operands, SFmode);"
+  [(set_attr "length" "2,4,4,4")
+   (set_attr "type" "alu,load,load,store")]
+)
+
+(define_insn "*csky_movsf"
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=b,r,r,r, m")
+       (match_operand:SF 1 "general_operand"      " b,r,m,mF,r"))]
+  "CSKY_ISA_FEATURE (E2) && !CSKY_ISA_FEATURE (fpv2_sf)"
+  "* return csky_output_move (insn, operands, SFmode);"
+ [(set_attr "length" "2,4,4,4,4")
+  (set_attr "type" "alu,alu,load,load,store")]
+)
+
+
+(define_expand "movdf"
+  [(set (match_operand:DF 0 "general_operand" "")
+       (match_operand:DF 1 "general_operand" ""))]
+  ""
+  "
+  if (GET_CODE (operands[0]) == MEM && can_create_pseudo_p ())
+      operands[1] = force_reg (DFmode, operands[1]);
+  "
+)
+
+;; FIXME: maybe the vreg load/stores should have their own type attr.
+(define_insn "*csky_movdf_fpv2"
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=b,r,v,r,r,r, m,Q,v,v,v")
+       (match_operand:DF 1 "general_operand"       "b,r,r,v,m,mF,r,v,Q,v,m"))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "* return csky_output_movedouble (operands, DFmode);"
+  [(set_attr "length" "4,8,8,8,8,8,8,8,8,8,8")
+   (set_attr "type" "alu,alu,alu,alu,load,load,store,alu,alu,alu,alu")]
+)
+
+(define_insn "*ck801_movdf"
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,r, m")
+       (match_operand:DF 1 "general_operand"      " r,m,mF,r"))]
+  "CSKY_ISA_FEATURE (E1)"
+  "* return csky_output_ck801_movedouble (operands, DFmode);"
+  [(set_attr "length" "4,8,8,8")
+   (set_attr "type" "alu,load,load,store")]
+)
+
+(define_insn "*csky_movdf"
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=b,r,r,r, m")
+       (match_operand:DF 1 "general_operand"      " b,r,m,mF,r"))]
+  "CSKY_ISA_FEATURE (E2) && !CSKY_ISA_FEATURE (fpv2_df)"
+  "* return csky_output_movedouble (operands, DFmode);"
+ [(set_attr "length" "4,8,8,8,8")
+  (set_attr "type" "alu,alu,load,load,store")]
+)
+
+;; The only CCmode move supported is a nop.  Without this pattern,
+;; CSE is unable to eliminate redundant comparisons in conditional
+;; execution expressions.
+
+(define_insn "*movcc_nop"
+  [(set (reg:CC CSKY_CC_REGNUM) (reg:CC CSKY_CC_REGNUM))]
+  ""
+  ""
+  [(set_attr "length" "0")]
+)
+
+;; ------------------------------------------------------------------------
+;; Conditional mov insns
+;; ------------------------------------------------------------------------
+
+;; Only handle integer comparisons because float and double require
+;; library calls.
+
+(define_expand "movsicc"
+  [(set (match_operand 0 "register_operand" "")
+       (if_then_else:SI (match_operand    1 "ordered_comparison_operator" "")
+                        (match_operand:SI 2 "register_operand" "")
+                        (match_operand:SI 3 "register_operand" "")))]
+  "CSKY_ISA_FEATURE (E2)"
+  "
+  {
+    bool invert = csky_emit_compare (GET_CODE (operands[1]),
+                                    XEXP (operands[1], 0),
+                                    XEXP (operands[1], 1));
+
+    if (invert)
+      emit_insn (gen_movf (operands[0], operands[2], operands[3]));
+    else
+      emit_insn (gen_movt (operands[0], operands[2], operands[3]));
+    DONE;
+  }")
+
+(define_insn "movt"
+  [(set (match_operand:SI 0 "register_operand" "=r, r")
+       (if_then_else:SI (ne (reg:CC CSKY_CC_REGNUM) (const_int 0))
+                        (match_operand:SI 1 "register_operand" "r, 0")
+                        (match_operand:SI 2 "register_operand" "0, r")))]
+  "CSKY_ISA_FEATURE (E2)"
+  "@
+    movt\t%0, %1
+    movf\t%0, %2"
+  [(set_attr "length" "4,4")]
+)
+
+(define_insn "movf"
+  [(set (match_operand:SI 0 "register_operand" "=r, r")
+       (if_then_else:SI (eq (reg:CC CSKY_CC_REGNUM) (const_int 0))
+                        (match_operand:SI 1 "register_operand" "r, 0")
+                        (match_operand:SI 2 "register_operand" "0, r")))]
+  "CSKY_ISA_FEATURE (E2)"
+  "@
+    movf\t%0, %1
+    movt\t%0, %2"
+  [(set_attr "length" "4,4")]
+)
+
+(define_expand "cstoresi4"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (match_operator   1 "ordered_comparison_operator"
+         [(match_operand:SI 2 "csky_compare_operand" "")
+          (match_operand:SI 3 "nonmemory_operand" "")]))]
+  ""
+  "
+  {
+    bool invert = csky_emit_compare (GET_CODE (operands[1]),
+                                    operands[2], operands[3]);
+
+    if (invert)
+      emit_insn (gen_mvcv (operands[0]));
+    else if (CSKY_ISA_FEATURE (E1))
+      {
+       emit_insn (gen_movsi (operands[0], const0_rtx));
+       emit_insn (gen_ck801_addc (operands[0], operands[0], operands[0]));
+      }
+    else
+      emit_insn (gen_mvc (operands[0]));
+    DONE;
+  }"
+)
+
+(define_insn "mvc"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (ne:SI (reg:CC CSKY_CC_REGNUM) (const_int 0)))]
+  "CSKY_ISA_FEATURE (E2)"
+  "mvc\t%0"
+)
+
+(define_insn "mvcv"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (eq:SI (reg:CC CSKY_CC_REGNUM) (const_int 0)))]
+  ""
+  "mvcv\t%0"
+)
+
+;; ------------------------------------------------------------------------
+;; Arithmetic insns
+;; ------------------------------------------------------------------------
+
+(define_insn "abssi2"
+  [(set (match_operand:SI        0 "register_operand" "=r")
+       (abs:SI (match_operand:SI 1 "register_operand" "r")))]
+  "CSKY_ISA_FEATURE (2E3)"
+  "abs\t%0, %1"
+  [(set_attr "type" "alu")]
+)
+
+(define_insn "extvsi"
+  [(set (match_operand:SI                 0 "register_operand" "=r")
+       (sign_extract:SI (match_operand:SI 1 "register_operand" "r")
+                        (match_operand:SI 2 "const_int_operand" "")
+                        (match_operand:SI 3 "const_int_operand" "")))]
+  "CSKY_ISA_FEATURE (2E3)"
+  {
+    operands[2] = GEN_INT (INTVAL (operands[3]) + INTVAL (operands[2]) - 1);
+    return \"sext\t%0, %1, %2, %3\";
+  }
+)
+
+(define_insn "insvsi"
+  [(set (zero_extract:SI (match_operand:SI 0 "register_operand"         "+r")
+                        (match_operand:SI 1 "const_int_operand" "i")
+                        (match_operand:SI 2 "const_int_operand" "i"))
+       (match_operand:SI                  3 "register_operand"  "r"))]
+  "CSKY_ISA_FEATURE (2E3)"
+  {
+    operands[1] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[1]) - 1);
+    return \"ins\t%0, %3, %1, %2\";
+  }
+)
+
+(define_expand "bseti"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (ior:SI (match_operand:SI 1 "register_operand"  "")
+               (ashift:SI (const_int 1)
+                          (match_operand:SI 2 "csky_literal_K_operand" ""))))]
+  ""
+  "")
+
+(define_insn "smart_bseti"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (ior:SI (match_operand:SI 1 "register_operand"  "0")
+               (ashift:SI (const_int 1)
+                          (match_operand:SI 2 "csky_literal_K_operand" "K"))))]
+  "TARGET_MINI_REGISTERS"
+  "bseti\t%0, %2"
+  [(set_attr "length" "2")])
+
+(define_insn "fast_bseti"
+  [(set (match_operand:SI 0 "register_operand" "=a,r")
+       (ior:SI (match_operand:SI 1 "register_operand"  "0,r")
+               (ashift:SI (const_int 1)
+                          (match_operand:SI 2 "csky_literal_K_operand" "K,K"))))]
+  "!TARGET_MINI_REGISTERS"
+  "bseti\t%0, %1, %2"
+  [(set_attr "length" "2,4")])
+
+(define_expand "bclri"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (and:SI (match_operand:SI 1 "register_operand"  "")
+               (not:SI (ashift:SI (const_int 1)
+                                  (match_operand:SI 2 "csky_literal_K_operand" "")))))]
+  ""
+  "")
+
+(define_insn "smart_bclri"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (and:SI (match_operand:SI 1 "register_operand"  "0")
+               (not:SI (ashift:SI (const_int 1)
+                                  (match_operand:SI 2 "csky_literal_K_operand" "K")))))]
+  "TARGET_MINI_REGISTERS"
+  "bclri\t%0, %2"
+  [(set_attr "length" "2")])
+
+(define_insn "fast_bclri"
+  [(set (match_operand:SI 0 "register_operand" "=a,r")
+       (and:SI (match_operand:SI 1 "register_operand"  "0,r")
+               (not:SI (ashift:SI (const_int 1)
+                                  (match_operand:SI 2 "csky_literal_K_operand" "K,K")))))]
+  "!TARGET_MINI_REGISTERS"
+  "bclri\t%0, %1, %2"
+  [(set_attr "length" "2,4")])
+
+
+;; Shift instructions.
+
+(define_expand "ashlsi3"
+  [(set (match_operand:SI           0 "register_operand"     "")
+       (ashift:SI (match_operand:SI 1 "register_operand"     "")
+                  (match_operand:SI 2 "csky_arith_K_operand" "")))]
+  ""
+  ""
+)
+
+(define_insn "*cskyv2_ashlsi3"
+  [(set (match_operand:SI           0 "register_operand"     "=b,r,a,r")
+       (ashift:SI (match_operand:SI 1 "register_operand"     "0,r,a,r")
+                  (match_operand:SI 2 "csky_arith_K_operand" "b,r,K,K")))]
+  "CSKY_ISA_FEATURE (E2)"
+  "@
+  lsl  %0, %1, %2
+  lsl  %0, %1, %2
+  lsli %0, %1, %2
+  lsli %0, %1, %2"
+  [(set_attr "length" "2,4,2,4")]
+)
+
+(define_insn "ck801_ashlsi3"
+  [(set (match_operand:SI           0 "register_operand"     "=a,r")
+       (ashift:SI (match_operand:SI 1 "register_operand"     "a,0")
+                  (match_operand:SI 2 "csky_arith_K_operand" "K,r")))]
+  "CSKY_ISA_FEATURE (E1)"
+  "@
+  lsli %0, %1, %2
+  lsl  %0, %1, %2"
+)
+
+
+(define_expand "ashrsi3"
+  [(set (match_operand:SI             0 "register_operand"     "")
+       (ashiftrt:SI (match_operand:SI 1 "register_operand"     "")
+                    (match_operand:SI 2 "csky_arith_K_operand" "")))]
+  ""
+  ""
+)
+
+(define_insn "*cskyv2_ashrsi3"
+  [(set (match_operand:SI             0 "register_operand"     "=b,r,a,r")
+       (ashiftrt:SI (match_operand:SI 1 "register_operand"     "0,r,a,r")
+                    (match_operand:SI 2 "csky_arith_K_operand" "b,r,K,K")))]
+  "CSKY_ISA_FEATURE (E2)"
+  "@
+  asr  %0, %1, %2
+  asr  %0, %1, %2
+  asri %0, %1, %2
+  asri %0, %1, %2"
+  [(set_attr "length" "2,4,2,4")]
+)
+
+(define_insn "*ck801_ashrsi3"
+  [(set (match_operand:SI             0 "register_operand"     "=a,r")
+       (ashiftrt:SI (match_operand:SI 1 "register_operand"     "a,0")
+                    (match_operand:SI 2 "csky_arith_K_operand" "K,r")))]
+  "CSKY_ISA_FEATURE (E1)"
+  "@
+  asri %0, %1, %2
+  asr  %0, %1, %2"
+)
+
+
+(define_expand "lshrsi3"
+  [(set (match_operand:SI             0 "register_operand"     "")
+       (lshiftrt:SI (match_operand:SI 1 "register_operand"     "")
+                    (match_operand:SI 2 "csky_arith_K_operand" "")))]
+  ""
+  ""
+)
+
+(define_insn "*cskyv2_lshrsi3"
+  [(set (match_operand:SI             0 "register_operand"     "=b,r,a,r")
+       (lshiftrt:SI (match_operand:SI 1 "register_operand"     "0,r,a,r")
+                    (match_operand:SI 2 "csky_arith_K_operand" "b,r,K,K")))]
+  "CSKY_ISA_FEATURE (E2)"
+  "@
+  lsr  %0, %1, %2
+  lsr  %0, %1, %2
+  lsri %0, %1, %2
+  lsri %0, %1, %2"
+  [(set_attr "length" "2,4,2,4")]
+)
+
+(define_insn "ck801_lshrsi3"
+  [(set (match_operand:SI             0 "register_operand"     "=a,r")
+       (lshiftrt:SI (match_operand:SI 1 "register_operand"     "a,0")
+                    (match_operand:SI 2 "csky_arith_K_operand" "K,r")))]
+  "CSKY_ISA_FEATURE (E1)"
+  "@
+  lsri %0, %1, %2
+  lsr  %0, %1, %2"
+)
+
+
+(define_expand "rotlsi3"
+  [(set (match_operand:SI           0 "register_operand"     "")
+       (rotate:SI (match_operand:SI 1 "register_operand"     "")
+                  (match_operand:SI 2 "csky_arith_K_operand" "")))]
+  ""
+  ""
+)
+
+(define_insn "*cskyv2_rotlsi3"
+  [(set (match_operand:SI           0 "register_operand"     "=b,r,r")
+       (rotate:SI (match_operand:SI 1 "register_operand"     "0,r,r")
+                  (match_operand:SI 2 "csky_arith_K_operand" "b,r,K")))]
+  "CSKY_ISA_FEATURE (E2)"
+  "@
+  rotl %0, %1, %2
+  rotl %0, %1, %2
+  rotli %0, %1, %2"
+  [(set_attr "length" "2,4,4")]
+)
+
+(define_insn "*ck801_rotlsi3"
+  [(set (match_operand:SI           0 "register_operand"     "=r")
+       (rotate:SI (match_operand:SI 1 "register_operand"     "0")
+                  (match_operand:SI 2 "csky_arith_K_operand" "r")))]
+  "CSKY_ISA_FEATURE (E1)"
+  "rotl %0, %1, %2"
+)
+
+
+;; Add instructions.
+;; C-SKY addi and subi machine instructions only accept positive immediate
+;; values, so we have to special case immediates <= 0 in these patterns.
+
+(define_expand "addsi3"
+  [(set (match_operand:SI         0 "register_operand" "")
+       (plus:SI (match_operand:SI 1 "register_operand" "")
+                (match_operand:SI 2 "nonmemory_operand" "")))]
+  ""
+  ""
+)
+
+(define_insn "smart_addsi3"
+ [(set (match_operand:SI         0 "register_operand"  "=a,r,a,a,a,a, r,r")
+       (plus:SI (match_operand:SI 1 "register_operand" "%a,0,0,a,0,a, r,r")
+               (match_operand:SI 2 "nonmemory_operand" "a, r,N,L,T,Us,M,Um")))]
+ "TARGET_MINI_REGISTERS && CSKY_ISA_FEATURE (E2)
+  && operands[0] != stack_pointer_rtx
+  && operands[1] != stack_pointer_rtx"
+ "@
+     addu\t%0, %1, %2
+     addu\t%0, %1, %2
+     addi\t%0, %1, %2
+     addi\t%0, %1, %2
+     subi\t%0, %1, %M2
+     subi\t%0, %1, %M2
+     addi\t%0, %1, %2
+     subi\t%0, %1, %M2"
+  [(set_attr "length" "2,2,2,2,2,2,4,4")
+   (set_attr "type" "addsub")]
+)
+
+(define_insn_and_split "*smart_addsi3_sp"
+  [(set (match_operand:SI         0 "register_operand"  "=z,z, z,a,&a,z,a,r")
+       (plus:SI (match_operand:SI 1 "register_operand"  "0, 0, 0,z, z,a,z,r")
+                (match_operand:SI 2 "nonmemory_operand" "P, Ug,r,Uq,i,a,a,M")))]
+  "TARGET_MINI_REGISTERS && CSKY_ISA_FEATURE (E2)
+    && (operands[0] == stack_pointer_rtx || operands[1] == stack_pointer_rtx)"
+  "@
+     addi\t%0, %1, %2
+     subi\t%0, %1, %M2
+     addu\t%0, %1, %2
+     addi\t%0, %1, %2
+     #
+     addu\t%0, %1, %2
+     addu\t%0, %1, %2
+     addi\t%0, %1, %2"
+  "(operands[0] != stack_pointer_rtx
+    && operands[1] == stack_pointer_rtx
+    && !satisfies_constraint_Uq (operands[2]))"
+  [(set (match_dup 0)
+       (plus:SI (match_dup 1) (match_dup 0)))]
+  "emit_move_insn (operands[0], operands[2]);"
+  [(set_attr "type" "addsub")]
+)
+
+(define_insn "*ck801_addsi3"
+  [(set (match_operand:SI         0 "register_operand"  "=r,a,a,a,a,a, !z,!z,!z,a")
+       (plus:SI (match_operand:SI 1 "register_operand"  "%0,a,0,a,0,a, 0, 0, 0, !z")
+                (match_operand:SI 2 "nonmemory_operand" "r, a,N,L,T,Us,P, Ug,r, Uq")))]
+  "CSKY_ISA_FEATURE (E1)"
+  "@
+    addu\t%0, %1, %2
+    addu\t%0, %1, %2
+    addi\t%0, %1, %2
+    addi\t%0, %1, %2
+    subi\t%0, %1, %M2
+    subi\t%0, %1, %M2
+    addi\t%0, %1, %2
+    subi\t%0, %1, %M2
+    addu\t%0, %1, %2
+    addi\t%0, %1, %2"
+  [(set_attr "type" "addsub")]
+)
+
+(define_insn "fast_addsi3"
+  [(set (match_operand:SI         0 "register_operand"  "=r,r, r")
+       (plus:SI (match_operand:SI 1 "register_operand"  "%r,r, r")
+                (match_operand:SI 2 "nonmemory_operand" "M, Um,r")))]
+  "!TARGET_MINI_REGISTERS && CSKY_ISA_FEATURE (E2)"
+  "@
+    addi\t%0, %1, %2
+    subi\t%0, %1, %M2
+    addu\t%0, %1, %2"
+  [(set_attr "type" "addsub")]
+)
+
+(define_expand "adddi3"
+  [(parallel [(set (match_operand:DI 0 "register_operand" "")
+                  (plus:DI (match_operand:DI 1 "register_operand" "")
+                           (match_operand:DI 2 "csky_arith_int1_operand" "")))
+             (clobber (reg:CC CSKY_CC_REGNUM))])]
+  ""
+  "
+  if (CSKY_ISA_FEATURE (E1) && (GET_CODE (operands[2]) != REG))
+      operands[2] = force_reg (DImode, operands[2]);
+  "
+)
+
+/* Note that the csky addc instruction both reads and writes the carry bit.
+   The purpose of the initial cmplt instruction in the expansion is to
+   clear the carry bit before adding the lo words.  */
+
+(define_insn_and_split "*cskyv2_adddi3"
+  [(set (match_operand:DI         0 "register_operand" "=b,&r")
+       (plus:DI (match_operand:DI 1 "register_operand" "%0,r")
+                (match_operand:DI 2 "register_operand" "b, r")))
+   (clobber (reg:CC CSKY_CC_REGNUM))]
+  "CSKY_ISA_FEATURE (E2)"
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  {
+    int hi = TARGET_BIG_ENDIAN ? 0 : UNITS_PER_WORD;
+    int lo = TARGET_BIG_ENDIAN ? UNITS_PER_WORD : 0;
+    rtx l0 = simplify_gen_subreg (SImode, operands[0], DImode, lo);
+    rtx h0 = simplify_gen_subreg (SImode, operands[0], DImode, hi);
+    rtx l1 = simplify_gen_subreg (SImode, operands[1], DImode, lo);
+    rtx h1 = simplify_gen_subreg (SImode, operands[1], DImode, hi);
+    rtx l2 = simplify_gen_subreg (SImode, operands[2], DImode, lo);
+    rtx h2 = simplify_gen_subreg (SImode, operands[2], DImode, hi);
+
+    emit_insn (gen_cmpltsi_r (copy_rtx (l1), copy_rtx (l1)));
+    emit_insn (gen_cskyv2_addc (l0, l1, l2));
+    emit_insn (gen_cskyv2_addc (h0, h1, h2));
+    DONE;
+  }
+  [(set_attr "length" "6,12")]
+)
+
+(define_insn_and_split "*ck801_adddi3"
+  [(set (match_operand:DI         0 "register_operand" "=r")
+       (plus:DI (match_operand:DI 1 "register_operand" "%0")
+                (match_operand:DI 2 "register_operand" "r")))
+   (clobber (reg:CC CSKY_CC_REGNUM))]
+  "CSKY_ISA_FEATURE (E1)"
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  {
+    int hi = TARGET_BIG_ENDIAN ? 0 : UNITS_PER_WORD;
+    int lo = TARGET_BIG_ENDIAN ? UNITS_PER_WORD : 0;
+    rtx l0 = simplify_gen_subreg (SImode, operands[0], DImode, lo);
+    rtx h0 = simplify_gen_subreg (SImode, operands[0], DImode, hi);
+    rtx l1 = simplify_gen_subreg (SImode, operands[1], DImode, lo);
+    rtx h1 = simplify_gen_subreg (SImode, operands[1], DImode, hi);
+    rtx l2 = simplify_gen_subreg (SImode, operands[2], DImode, lo);
+    rtx h2 = simplify_gen_subreg (SImode, operands[2], DImode, hi);
+
+    emit_insn (gen_cmpltsi_r (copy_rtx (l1), copy_rtx (l1)));
+    emit_insn (gen_ck801_addc (l0, l1, l2));
+    emit_insn (gen_ck801_addc (h0, h1, h2));
+    DONE;
+  }
+  [(set_attr "length" "6")]
+)
+
+;; Special case for "longlong += 1".
+
+(define_insn_and_split "*cskyv2_adddi1_1"
+  [(set (match_operand:DI         0 "register_operand" "=&r")
+       (plus:DI (match_operand:DI 1 "register_operand" "0")
+                (const_int 1)))
+   (clobber (reg:CC CSKY_CC_REGNUM))]
+  "CSKY_ISA_FEATURE (E2)"
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  {
+    int hi = TARGET_BIG_ENDIAN ? 0 : UNITS_PER_WORD;
+    int lo = TARGET_BIG_ENDIAN ? UNITS_PER_WORD : 0;
+    rtx l0 = simplify_gen_subreg (SImode, operands[0], DImode, lo);
+    rtx h0 = simplify_gen_subreg (SImode, operands[0], DImode, hi);
+
+    if (TARGET_MINI_REGISTERS)
+      {
+       emit_insn (gen_smart_addsi3 (l0, copy_rtx (l0),
+                                    gen_int_mode (1, SImode)));
+       emit_insn (gen_smart_cmpnesi_i (copy_rtx (l0),
+                                       gen_int_mode (0, SImode)));
+       emit_insn (gen_cskyv2_addcc_invert (h0, copy_rtx (h0),
+                                           gen_int_mode (1, SImode)));
+      }
+    else
+      {
+       emit_insn (gen_fast_addsi3 (l0, copy_rtx (l0),
+                                   gen_int_mode (1, SImode)));
+       emit_insn (gen_fast_cmpnesi_i (copy_rtx (l0),
+                                      gen_int_mode (0, SImode)));
+       emit_insn (gen_cskyv2_addcc_invert (h0, copy_rtx (h0),
+                                       gen_int_mode (1, SImode)));
+      }
+    DONE;
+  }
+  [(set (attr "length")
+       (if_then_else (match_test "TARGET_MINI_REGISTERS")
+                     (const_int 8)
+                     (const_int 12)))]
+)
+
+;; sub instructions.
+
+(define_expand "subsi3"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (minus:SI (match_operand:SI 1 "register_operand" "")
+                 (match_operand:SI 2 "nonmemory_operand" "")))]
+  ""
+  ""
+)
+
+(define_insn "smart_subsi3"
+  [(set (match_operand:SI          0 "register_operand"    "=a,a,a,a,a,a")
+       (minus:SI (match_operand:SI 1 "register_operand"    "a, 0,0,a,0,a")
+                 (match_operand:SI 2 "nonmemory_operand"   "a, a,N,L,T,Us")))]
+  "TARGET_MINI_REGISTERS && CSKY_ISA_FEATURE (E2)
+   && operands[0] != stack_pointer_rtx
+   && operands[1] != stack_pointer_rtx"
+  "@
+    subu\t%0, %1, %2
+    subu\t%0, %1, %2
+    subi\t%0, %1, %2
+    subi\t%0, %1, %2
+    addi\t%0, %1, %M2
+    addi\t%0, %1, %M2"
+  [(set_attr "length" "2,2,2,2,2,2")
+   (set_attr "type" "addsub")]
+)
+
+(define_insn "*smart_subsi3_sp"
+  [(set (match_operand:SI          0 "register_operand"  "=z,z, z,a, a,r")
+       (minus:SI (match_operand:SI 1 "register_operand"  "0, 0, 0,z, a,r")
+                 (match_operand:SI 2 "nonmemory_operand" "P, Ug,a,Ur,a,M")))]
+  "TARGET_MINI_REGISTERS && CSKY_ISA_FEATURE (E2)
+   && (operands[0] == stack_pointer_rtx || operands[1] == stack_pointer_rtx)"
+  "@
+    subi\t%0, %1, %2
+    addi\t%0, %1, %M2
+    subu\t%0, %1, %2
+    addi\t%0, %1, %M2
+    subu\t%0, %1, %2
+    subi\t%0, %1, %2"
+  [(set_attr "length" "2,2,2,2,2,4")
+   (set_attr "type" "addsub")]
+)
+
+(define_insn "*ck801_subsi3"
+  [(set (match_operand:SI          0 "register_operand"    "=a,a,a,a,a,a")
+       (minus:SI (match_operand:SI 1 "register_operand"    "0, a,0,a,0,a")
+                 (match_operand:SI 2 "nonmemory_operand"   "a, a,N,L,T,Us")))]
+  "CSKY_ISA_FEATURE (E1)
+   && operands[0] != stack_pointer_rtx
+   && operands[1] != stack_pointer_rtx"
+  "@
+    subu\t%0, %1, %2
+    subu\t%0, %1, %2
+    subi\t%0, %1, %2
+    subi\t%0, %1, %2
+    addi\t%0, %1, %M2
+    addi\t%0, %1, %M2"
+  [(set_attr "type" "addsub")]
+)
+
+(define_insn "*ck801_subsi3_sp"
+  [(set (match_operand:SI          0 "register_operand"  "=a,z,z, z")
+       (minus:SI (match_operand:SI 1 "register_operand"  "z, 0,0, 0")
+                 (match_operand:SI 2 "nonmemory_operand" "Ur,P,Ug,r")))]
+  "CSKY_ISA_FEATURE (E1)
+   && (operands[0] == stack_pointer_rtx || operands[1] == stack_pointer_rtx)"
+  "@
+    addi\t%0, %1, %M2
+    subi\t%0, %1, %2
+    addi\t%0, %1, %M2
+    subu\t%0, %1, %2"
+  [(set_attr "type" "addsub")]
+)
+
+(define_insn "fast_subsi3"
+  [(set (match_operand:SI          0 "register_operand"  "=r,r,r")
+       (minus:SI (match_operand:SI 1 "register_operand"  "r, r,r")
+                 (match_operand:SI 2 "nonmemory_operand" "r, M,Um")))]
+  "!TARGET_MINI_REGISTERS && CSKY_ISA_FEATURE (E2)"
+  "@
+     subu\t%0, %1, %2
+     subi\t%0, %1, %2
+     addi\t%0, %1, %M2"
+  [(set_attr "type" "addsub")]
+)
+
+(define_expand "subdi3"
+  [(parallel [(set (match_operand:DI 0 "register_operand" "")
+                 (minus:DI (match_operand:DI 1 "register_operand" "")
+                           (match_operand:DI 2 "register_operand" "")))
+             (clobber (reg:CC CSKY_CC_REGNUM))])]
+  ""
+  ""
+)
+
+/* Note that the csky subc instruction both reads and writes the C bit.
+   The purpose of the initial cmphs instruction in the expansion is to
+   set the C bit before subtracting the lo words.  */
+
+(define_insn_and_split "*cskyv2_subdi3"
+  [(set (match_operand:DI          0 "register_operand" "=b,&r")
+       (minus:DI (match_operand:DI 1 "register_operand" "0, r")
+                 (match_operand:DI 2 "register_operand" "b, r")))
+   (clobber (reg:CC CSKY_CC_REGNUM))]
+  "CSKY_ISA_FEATURE (E2)"
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  {
+    int hi = TARGET_BIG_ENDIAN ? 0 : UNITS_PER_WORD;
+    int lo = TARGET_BIG_ENDIAN ? UNITS_PER_WORD : 0;
+    rtx l0 = simplify_gen_subreg (SImode, operands[0], DImode, lo);
+    rtx h0 = simplify_gen_subreg (SImode, operands[0], DImode, hi);
+    rtx l1 = simplify_gen_subreg (SImode, operands[1], DImode, lo);
+    rtx h1 = simplify_gen_subreg (SImode, operands[1], DImode, hi);
+    rtx l2 = simplify_gen_subreg (SImode, operands[2], DImode, lo);
+    rtx h2 = simplify_gen_subreg (SImode, operands[2], DImode, hi);
+
+    emit_insn (gen_cmpgeusi_r (copy_rtx (l1), copy_rtx (l1)));
+    emit_insn (gen_cskyv2_subc (l0, l1, l2));
+    emit_insn (gen_cskyv2_subc (h0, h1, h2));
+    DONE;
+  }
+  [(set_attr "length" "6,12")]
+)
+
+(define_insn_and_split "*ck801_subdi3"
+  [(set (match_operand:DI          0 "register_operand" "=r")
+       (minus:DI (match_operand:DI 1 "register_operand" "0")
+                 (match_operand:DI 2 "register_operand" "r")))
+   (clobber (reg:CC CSKY_CC_REGNUM))]
+  "CSKY_ISA_FEATURE (E1)"
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  {
+    int hi = TARGET_BIG_ENDIAN ? 0 : UNITS_PER_WORD;
+    int lo = TARGET_BIG_ENDIAN ? UNITS_PER_WORD : 0;
+    rtx l0 = simplify_gen_subreg (SImode, operands[0], DImode, lo);
+    rtx h0 = simplify_gen_subreg (SImode, operands[0], DImode, hi);
+    rtx l1 = simplify_gen_subreg (SImode, operands[1], DImode, lo);
+    rtx h1 = simplify_gen_subreg (SImode, operands[1], DImode, hi);
+    rtx l2 = simplify_gen_subreg (SImode, operands[2], DImode, lo);
+    rtx h2 = simplify_gen_subreg (SImode, operands[2], DImode, hi);
+
+    emit_insn (gen_cmpgeusi_r (copy_rtx (l1), copy_rtx (l1)));
+    emit_insn (gen_ck801_subc (l0, l1, l2));
+    emit_insn (gen_ck801_subc (h0, h1, h2));
+    DONE;
+  }
+  [(set_attr "length" "6")]
+)
+
+;; Special case for "longlong -= 1".
+
+(define_insn_and_split "*cskyv2_subdi1_1"
+  [(set (match_operand:DI         0 "register_operand" "=&r")
+       (plus:DI (match_operand:DI 1 "register_operand" "0")
+                (const_int -1)))
+   (clobber (reg:CC CSKY_CC_REGNUM))]
+  "CSKY_ISA_FEATURE (E2)"
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  {
+    int hi = TARGET_BIG_ENDIAN ? 0 : UNITS_PER_WORD;
+    int lo = TARGET_BIG_ENDIAN ? UNITS_PER_WORD : 0;
+    rtx l0 = simplify_gen_subreg (SImode, operands[0], DImode, lo);
+    rtx h0 = simplify_gen_subreg (SImode, operands[0], DImode, hi);
+
+    if (TARGET_MINI_REGISTERS)
+      {
+       emit_insn (gen_smart_cmpnesi_i (copy_rtx (l0),
+                                       gen_int_mode (0, SImode)));
+       emit_insn (gen_cskyv2_addcc_invert (h0, copy_rtx (h0),
+                                           gen_int_mode (-1, SImode)));
+       emit_insn (gen_smart_subsi3 (l0, copy_rtx (l0),
+                                    gen_int_mode (1, SImode)));
+      }
+    else
+      {
+       emit_insn (gen_fast_cmpnesi_i (copy_rtx (l0),
+                                      gen_int_mode (0, SImode)));
+       emit_insn (gen_cskyv2_addcc_invert (h0, copy_rtx (h0),
+                                           gen_int_mode (-1, SImode)));
+       emit_insn (gen_fast_subsi3 (l0, copy_rtx (l0),
+                                   gen_int_mode (1, SImode)));
+      }
+    DONE;
+  }
+  [(set (attr "length")
+       (if_then_else (match_test "TARGET_MINI_REGISTERS")
+                     (const_int 8)
+                     (const_int 12)))]
+)
+
+;; Add with carry.
+
+(define_insn "cskyv2_addc"
+  [(set (match_operand:SI                  0 "register_operand" "=r,r")
+       (plus:SI (ne:SI (reg:CC CSKY_CC_REGNUM) (const_int 0))
+                (plus:SI (match_operand:SI 1 "register_operand" "%0,r")
+                         (match_operand:SI 2 "register_operand" "r,r"))))
+   (set (reg:CC CSKY_CC_REGNUM)
+       (compare:CC
+         (plus:SI (match_dup 1) (match_dup 2))
+         (match_dup 1)))]
+  "CSKY_ISA_FEATURE (E2)"
+  "addc\t%0, %1, %2"
+  [(set_attr "length" "2,4")
+   (set_attr "type" "addsub")]
+)
+
+(define_insn "ck801_addc"
+  [(set (match_operand:SI                  0 "register_operand" "=r")
+       (plus:SI (ne:SI (reg:CC CSKY_CC_REGNUM) (const_int 0))
+                (plus:SI (match_operand:SI 1 "register_operand" "%0")
+                         (match_operand:SI 2 "register_operand" "r"))))
+   (set (reg:CC CSKY_CC_REGNUM)
+       (compare:CC
+         (plus:SI (match_dup 1) (match_dup 2))
+         (match_dup 1)))]
+  "CSKY_ISA_FEATURE (E1)"
+  "addc\t%0, %1, %2"
+  [(set_attr "length" "2")
+   (set_attr "type" "addsub")]
+)
+
+;; Subtract with borrow.
+;; Note that in these insns, the sense of C bit is reversed; they subtract 1
+;; if the C bit is not set, and on output the bit is set to 0 for borrow
+;; and 1 for no borrow.
+
+(define_insn "cskyv2_subc"
+  [(set (match_operand:SI                   0 "register_operand" "=r,r")
+       (minus:SI (match_operand:SI          1 "register_operand" "0, r")
+                 (plus:SI (match_operand:SI 2 "register_operand" "r, r")
+                          (eq:SI (reg:CC CSKY_CC_REGNUM) (const_int 0)))))
+   (set (reg:CC CSKY_CC_REGNUM)
+       (not (compare:CC (match_dup 1) (match_dup 2))))]
+  "CSKY_ISA_FEATURE (E2)"
+  "subc\t%0, %1, %2"
+  [(set_attr "length" "2,4")
+   (set_attr "type" "addsub")]
+)
+
+(define_insn "ck801_subc"
+  [(set (match_operand:SI                   0 "register_operand" "=r")
+       (minus:SI (match_operand:SI          1 "register_operand" "0")
+                 (plus:SI (match_operand:SI 2 "register_operand" "r")
+                          (eq:SI (reg:CC CSKY_CC_REGNUM) (const_int 0)))))
+   (set (reg:CC CSKY_CC_REGNUM)
+       (not (compare:CC (match_dup 1) (match_dup 2))))]
+  "CSKY_ISA_FEATURE (E1)"
+  "subc\t%0, %1, %2"
+  [(set_attr "length" "2")
+   (set_attr "type" "addsub")]
+)
+
+;; ------------------------------------------------------------------------
+;; Multiplication insns
+;; ------------------------------------------------------------------------
+
+(define_expand "mulsi3"
+  [(set (match_operand:SI         0 "register_operand" "")
+       (mult:SI (match_operand:SI 1 "register_operand" "")
+                (match_operand:SI 2 "register_operand" "")))]
+  ""
+  ""
+)
+
+(define_insn "*cskyv2_mulsi3"
+  [(set (match_operand:SI         0 "register_operand" "=r")
+       (mult:SI (match_operand:SI 1 "register_operand" "%r")
+                (match_operand:SI 2 "register_operand" "r")))]
+  "CSKY_ISA_FEATURE (E2)"
+  "mult\t%0, %1, %2"
+)
+
+(define_insn "*ck801_mulsi3"
+  [(set (match_operand:SI         0 "register_operand" "=r")
+       (mult:SI (match_operand:SI 1 "register_operand" "%0")
+                (match_operand:SI 2 "register_operand" "r")))]
+  "CSKY_ISA_FEATURE (E1)"
+  "mult\t%0, %1, %2"
+)
+
+(define_insn "mulhisi3"
+  [(set (match_operand:SI                         0 "register_operand" "=r")
+       (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%r"))
+                (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
+  "CSKY_ISA_FEATURE (2E3)"
+  "mulsh\t%0, %1, %2"
+)
+
+
+;; ------------------------------------------------------------------------
+;; Conditional add insns
+;; ------------------------------------------------------------------------
+
+(define_expand "addsicc"
+  [(match_operand:SI 0 "register_operand" "")
+   (match_operand    1 "ordered_comparison_operator" "")
+   (match_operand:SI 2 "register_operand" "")
+   (match_operand:SI 3 "csky_literal_K_Uh_operand" "")]
+  "CSKY_ISA_FEATURE (E2)"
+  "
+  {
+    bool invert = csky_emit_compare (GET_CODE (operands[1]),
+                                    XEXP (operands[1], 0),
+                                    XEXP (operands[1], 1));
+    if (invert)
+      emit_insn (gen_cskyv2_addcc_invert (operands[0], operands[2],
+                                         operands[3]));
+    else
+      emit_insn (gen_cskyv2_addcc (operands[0], operands[2], operands[3]));
+
+    DONE;
+  }"
+)
+
+(define_insn_and_split "cskyv2_addcc"
+  [(set (match_operand:SI           0 "register_operand"          "=r,r,&r,&r")
+       (if_then_else:SI
+         (ne (reg:CC CSKY_CC_REGNUM) (const_int 0))
+         (plus:SI (match_operand:SI 1 "register_operand"          "0,0,r,r")
+                  (match_operand:SI 2 "csky_literal_K_Uh_operand" "K,Uh,K,Uh"))
+         (match_dup 1)))]
+  "CSKY_ISA_FEATURE (E2)"
+  "@
+   inct\t%0, %1, %2
+   dect\t%0, %1, %M2
+   #
+   #"
+  "reload_completed && !rtx_equal_p (operands[0], operands[1])"
+  [(set (match_dup 0)
+       (if_then_else:SI (ne (reg:CC CSKY_CC_REGNUM) (const_int 0))
+                        (plus:SI (match_dup 0) (match_dup 2))))]
+  {
+    emit_insn (gen_movf (copy_rtx (operands[0]),
+                        copy_rtx (operands[1]),
+                        copy_rtx (operands[0])));
+  }
+  [(set_attr "length" "4,4,8,8")
+   (set_attr "type" "addsub")]
+)
+
+(define_insn_and_split "cskyv2_addcc_invert"
+  [(set (match_operand:SI           0 "register_operand"          "=r,r,r,r")
+       (if_then_else:SI
+         (eq (reg:CC CSKY_CC_REGNUM) (const_int 0))
+         (plus:SI (match_operand:SI 1 "register_operand"          "0,0,r,r")
+                  (match_operand:SI 2 "csky_literal_K_Uh_operand" "K,Uh,K,Uh"))
+         (match_dup 1)))]
+  "CSKY_ISA_FEATURE (E2)"
+  "@
+   incf\t%0, %1, %2
+   decf\t%0, %1, %M2
+   #
+   #"
+  "reload_completed && !rtx_equal_p (operands[0], operands[1])"
+  [(set (match_dup 0)
+       (if_then_else:SI (eq (reg:CC CSKY_CC_REGNUM) (const_int 0))
+                        (plus:SI (match_dup 0) (match_dup 2))))]
+  {
+    emit_insn (gen_movt (copy_rtx (operands[0]),
+                        copy_rtx (operands[1]),
+                        copy_rtx (operands[0])));
+  }
+  [(set_attr "length" "4,4,8,8")
+   (set_attr "type" "addsub")]
+)
+
+
+;; ------------------------------------------------------------------------
+;; Extzv insns
+;; ------------------------------------------------------------------------
+
+(define_expand "extzvsi"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (zero_extract:SI (match_operand:SI 1 "register_operand" "")
+                        (match_operand:SI 2 "const_int_operand" "")
+                        (match_operand:SI 3 "const_int_operand" "")))]
+  ""
+  "{
+    /* ck802 has xtrb but not zext, so we'll use xtrb if we can.  */
+    if (CSKY_ISA_FEATURE (E2) && !CSKY_ISA_FEATURE (2E3)
+       && (INTVAL (operands[2]) == 8)
+       && (INTVAL (operands[3]) % 8 == 0))
+      {
+       rtx xtrb = gen_rtx_SET (operands[0],
+                               gen_rtx_ZERO_EXTRACT (SImode,
+                                                     operands[1],
+                                                     operands[2],
+                                                     operands[3]));
+       emit (gen_rtx_PARALLEL (VOIDmode,
+                               gen_rtvec (2, xtrb,
+                               gen_hard_reg_clobber (CCmode, 33))));
+       DONE;
+      }
+    else if (!CSKY_ISA_FEATURE (2E3))
+      {
+       /* Use lsri and lsli to do extzv on targets without zext.  */
+       rtx lshft = GEN_INT (32 - (INTVAL (operands[2])
+                            + INTVAL (operands[3])));
+       rtx rshft = GEN_INT (32 - INTVAL (operands[2]));
+       rtx tmp1 = gen_reg_rtx (SImode);
+       rtx tmp2 = gen_reg_rtx (SImode);
+
+       emit_insn (gen_rtx_SET (tmp1, operands[1]));
+       emit_insn (gen_rtx_SET (tmp2, gen_rtx_ASHIFT (SImode, tmp1, lshft)));
+       emit_insn (gen_rtx_SET (operands[0],
+                               gen_rtx_LSHIFTRT (SImode, tmp2, rshft)));
+       DONE;
+      }
+    else
+      {
+       emit_insn (gen_cskyv2_extzv (operands[0], operands[1],
+                                    operands[2], operands[3]));
+       DONE;
+      }
+}")
+
+(define_insn "cskyv2_extzv"
+  [(set (match_operand:SI                 0 "register_operand" "=r")
+       (zero_extract:SI (match_operand:SI 1 "register_operand" "r")
+                        (match_operand:SI 2 "csky_literal_K_operand" "K")
+                        (match_operand:SI 3 "csky_literal_K_operand" "K")))]
+  "CSKY_ISA_FEATURE (2E3)"
+  {
+    operands[2] = GEN_INT (INTVAL (operands[3]) + INTVAL (operands[2]) - 1);
+    return \"zext\t%0, %1, %2, %3\";
+  }
+)
+
+(define_insn "*cskyv2_xtrb0"
+  [(set (match_operand:SI                 0 "register_operand" "=r,r")
+       (zero_extract:SI (match_operand:SI 1 "register_operand" "0,r")
+                        (const_int 8)
+                        (const_int 24)))
+       (clobber (reg:CC CSKY_CC_REGNUM))]
+  "CSKY_ISA_FEATURE (E2)"
+  "@
+    lsri\t%0, %0, 24
+    xtrb0\t%0, %1"
+)
+
+(define_insn "*cskyv2_xtrb1"
+  [(set (match_operand:SI                 0 "register_operand" "=r")
+       (zero_extract:SI (match_operand:SI 1 "register_operand" "r")
+                        (const_int 8)
+                        (const_int 16)))
+       (clobber (reg:CC CSKY_CC_REGNUM))]
+  "CSKY_ISA_FEATURE (E2)"
+  "xtrb1\t%0, %1"
+)
+
+(define_insn "*cskyv2_xtrb2"
+  [(set (match_operand:SI                 0 "register_operand" "=r")
+       (zero_extract:SI (match_operand:SI 1 "register_operand" "r")
+                        (const_int 8)
+                        (const_int 8)))
+       (clobber (reg:CC CSKY_CC_REGNUM))]
+  "CSKY_ISA_FEATURE (E2)"
+  "xtrb2\t%0, %1"
+)
+
+
+;; -------------------------------------------------------------------------
+;; Zero extension instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "zero_extendhisi2"
+  [(set (match_operand:SI                0 "register_operand" "=r")
+       (zero_extend:SI (match_operand:HI 1 "register_operand" "r")))]
+  ""
+  "zexth\t%0, %1"
+)
+
+(define_insn "*cskyv2_zextend_ldh"
+  [(set (match_operand:SI                0 "register_operand" "=r")
+       (zero_extend:SI (match_operand:HI 1 "csky_simple_mem_operand" "m")))]
+  ""
+  "ld.h\t%0, %1"
+  [(set_attr "length" "4")
+   (set_attr "type" "load")]
+)
+
+(define_insn "zero_extendqisi2"
+  [(set (match_operand:SI                0 "register_operand" "=r")
+       (zero_extend:SI (match_operand:QI 1 "register_operand" "r")))]
+  ""
+  "zextb\t%0, %1"
+)
+
+(define_insn "*cskyv2_zextend_ldb"
+  [(set (match_operand:SI                0 "register_operand" "=r")
+       (zero_extend:SI (match_operand:QI 1 "csky_simple_mem_operand" "m")))]
+  ""
+  "ld.b\t%0, %1"
+  [(set_attr "length" "4")
+   (set_attr "type" "load")]
+)
+
+(define_insn "zero_extendqihi2"
+  [(set (match_operand:HI                0 "register_operand" "=r")
+       (zero_extend:HI (match_operand:QI 1 "register_operand" "r")))]
+  ""
+  "zextb\t%0, %1"
+)
+
+(define_insn "*cskyv2_zextend_ldbhi"
+  [(set (match_operand:HI                0 "register_operand"   "=r")
+       (zero_extend:HI (match_operand:QI 1 "csky_simple_mem_operand" "m")))]
+  ""
+  "ld.b\t%0, %1"
+  [(set_attr "length" "4")
+   (set_attr "type" "load")]
+)
+
+;; -------------------------------------------------------------------------
+;; clzm2 instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "clzsi2"
+  [(set (match_operand:SI        0 "register_operand" "=r")
+       (clz:SI (match_operand:SI 1 "register_operand" "r")))]
+  "CSKY_ISA_FEATURE (E2)"
+  "ff1 %0,%1"
+)
+
+;; -------------------------------------------------------------------------
+;; one_cmplm2 instructions
+;; -------------------------------------------------------------------------
+
+(define_expand "one_cmplsi2"
+  [(set (match_operand:SI        0 "register_operand" "")
+       (not:SI (match_operand:SI 1 "register_operand" "")))]
+  ""
+  ""
+)
+
+(define_insn "cskyv2_one_cmplsi2"
+  [(set (match_operand:SI        0 "register_operand" "=b,r")
+       (not:SI (match_operand:SI 1 "register_operand" "0,r")))]
+  "CSKY_ISA_FEATURE (E2)"
+  "not %0, %1"
+  [(set_attr "length" "2,4")
+   (set_attr "type" "alu,alu")]
+)
+
+(define_insn "ck801_one_cmplsi2"
+  [(set (match_operand:SI        0 "register_operand" "=r")
+       (not:SI (match_operand:SI 1 "register_operand" "0")))]
+  "CSKY_ISA_FEATURE (E1)"
+  "not %0, %1"
+  [(set_attr "length" "2")
+   (set_attr "type" "alu")]
+)
+
+;; -------------------------------------------------------------------------
+;; Sign extension instructions
+;; -------------------------------------------------------------------------
+
+;; One test shows that the following code helps to
+;; reduce one 'load' and two 'mov'.
+(define_expand "extendsidi2"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (match_operand:SI 1 "register_operand" "r"))]
+  ""
+  "{
+    int low, high;
+
+    if (TARGET_BIG_ENDIAN)
+      low = 4, high = 0;
+    else
+      low = 0, high = 4;
+
+    emit_insn (gen_rtx_SET (gen_rtx_SUBREG (SImode, operands[0], low),
+                           operands[1]));
+
+    emit_insn (gen_rtx_SET (gen_rtx_SUBREG (SImode, operands[0], high),
+                           gen_rtx_ASHIFTRT (SImode,
+                                             gen_rtx_SUBREG (SImode,
+                                                             operands[0],
+                                                             low),
+                                             GEN_INT (31))));
+    DONE;
+  }"
+)
+
+(define_insn "extendhisi2"
+  [(set (match_operand:SI                0 "register_operand" "=r")
+       (sign_extend:SI (match_operand:HI 1 "register_operand" "r")))]
+  ""
+  "sexth  %0, %1"
+)
+
+(define_insn "*cskyv2_sextend_ldhs"
+  [(set (match_operand:SI                0 "register_operand" "=r")
+       (sign_extend:SI (match_operand:HI 1 "csky_simple_mem_operand" "m")))]
+  "CSKY_ISA_FEATURE (E2)"
+  "ld.hs\t%0, %1"
+  [(set_attr "length" "4")
+   (set_attr "type" "load")]
+)
+
+;; qi -> si
+(define_insn "extendqisi2"
+  [(set (match_operand:SI                0 "register_operand" "=r")
+       (sign_extend:SI (match_operand:QI 1 "register_operand" "r")))]
+  ""
+  "sextb  %0, %1"
+)
+
+;; qi -> hi
+(define_insn "extendqihi2"
+  [(set (match_operand:HI                0 "register_operand" "=r")
+       (sign_extend:HI (match_operand:QI 1 "register_operand" "r")))]
+  ""
+  "sextb  %0, %1"
+)
+
+;; -------------------------------------------------------------------------
+;; And instructions
+;; -------------------------------------------------------------------------
+
+(define_expand "andsi3"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (and:SI (match_operand:SI 1 "register_operand" "")
+               (match_operand:SI 2 "csky_arith_any_imm_operand" "")))]
+  ""
+  "")
+
+(define_insn_and_split "cskyv2_andsi3"
+  [(set (match_operand:SI        0 "register_operand"           "=b,r,r,&r")
+       (and:SI (match_operand:SI 1 "register_operand"           "%0,r,r,r")
+               (match_operand:SI 2 "csky_arith_any_imm_operand" "b,r,O,i")))]
+  "CSKY_ISA_FEATURE (E2)"
+  "@
+   and\t%0, %1, %2
+   and\t%0, %1, %2
+   andi\t%0, %1, %2
+   #"
+  "(CONST_INT_P (operands[2])
+    && (operands[2] == const0_rtx
+       || !csky_arith_O_operand (operands[2], SImode)))"
+  [(set (match_dup 0) (and:SI (match_dup 1) (match_dup 2)))]
+  {
+    if (csky_split_and (operands))
+      DONE;
+  }
+  [(set_attr "length" "2,4,4,8")
+   (set_attr "type" "alu,alu,alu,alu")]
+)
+
+(define_insn_and_split "ck801_andsi3"
+  [(set (match_operand:SI        0 "register_operand"           "=r,&r")
+       (and:SI (match_operand:SI 1 "register_operand"           "%0,r")
+               (match_operand:SI 2 "csky_arith_any_imm_operand" "r,i")))]
+  "CSKY_ISA_FEATURE (E1)"
+  "@
+   and\t%0, %1, %2
+   #"
+  "CONST_INT_P (operands[2])"
+  [(set (match_dup 0) (and:SI (match_dup 1) (match_dup 2)))]
+  {
+    if (csky_split_and (operands))
+      DONE;
+  }
+  [(set_attr "length" "2,4")
+   (set_attr "type" "alu,alu")]
+)
+
+;; Note that the operands for the andnsi3 patterns are reversed compared
+;; to the actual machine insn: operand 1 is the inverted operand.
+
+(define_insn "cskyv2_andnsi3"
+  [(use (and:SI (not:SI (match_operand:SI 1 "csky_arith_O_operand" "b,r,O"))
+       (match_operand:SI                 2 "register_operand"     "0,r,r")))
+   (set (match_operand:SI                0 "register_operand"     "=b,r,r")
+       (and:SI (not:SI (match_dup 1))
+               (match_dup 2)))]
+  "CSKY_ISA_FEATURE (E2)"
+  "@
+    andn\t%0, %2, %1
+    andn\t%0, %2, %1
+    andni\t%0, %2, %1"
+  [(set_attr "length" "2,4,4")
+   (set_attr "type" "alu,alu,alu")]
+)
+
+(define_insn "ck801_andnsi3"
+  [(use (and:SI (not:SI (match_operand:SI 1 "register_operand" "r"))
+               (match_operand:SI         2 "register_operand" "0")))
+   (set (match_operand:SI                0 "register_operand" "=r")
+       (and:SI (not:SI (match_dup 1))
+               (match_dup 2)))]
+ "CSKY_ISA_FEATURE (E1)"
+ "andn\t%0, %2, %1"
+)
+
+(define_expand "anddi3"
+  [(set (match_operand:DI 0 "register_operand" "")
+       (and:DI (match_operand:DI 1 "register_operand" "")
+               (match_operand:DI 2 "csky_arith_any_imm_operand" "")))]
+  ""
+  "
+  {
+    if (CONST_INT_P (operands[2]))
+      {
+       HOST_WIDE_INT ival = INTVAL (operands[2]);
+       if (ival == (HOST_WIDE_INT) 0xffffffff)
+         {
+           emit_move_insn (gen_lowpart (SImode, operands[0]),
+                           gen_lowpart (SImode, operands[1]));
+           emit_move_insn (gen_highpart (SImode, operands[0]), const0_rtx);
+           DONE;
+         }
+       else if (ival == (HOST_WIDE_INT) ((unsigned HOST_WIDE_INT) -1 << 32))
+         {
+           emit_move_insn (gen_lowpart (SImode, operands[0]), const0_rtx);
+           emit_move_insn (gen_highpart (SImode, operands[0]),
+                           gen_highpart (SImode, operands[1]));
+           DONE;
+         }
+       else
+          FAIL;
+      }
+  }")
+
+
+
+(define_insn_and_split "*cskyv2_anddi3"
+  [(set (match_operand:DI        0 "register_operand" "=&b,&r")
+       (and:DI (match_operand:DI 1 "register_operand" "%0,r")
+               (match_operand:DI 2 "register_operand" "b,r")))]
+  "CSKY_ISA_FEATURE (E2)"
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  {
+    int hi = TARGET_BIG_ENDIAN ? 0 : UNITS_PER_WORD;
+    int lo = TARGET_BIG_ENDIAN ? UNITS_PER_WORD : 0;
+    rtx l0 = simplify_gen_subreg (SImode, operands[0], DImode, lo);
+    rtx h0 = simplify_gen_subreg (SImode, operands[0], DImode, hi);
+    rtx l1 = simplify_gen_subreg (SImode, operands[1], DImode, lo);
+    rtx h1 = simplify_gen_subreg (SImode, operands[1], DImode, hi);
+    rtx l2 = simplify_gen_subreg (SImode, operands[2], DImode, lo);
+    rtx h2 = simplify_gen_subreg (SImode, operands[2], DImode, hi);
+
+    emit_insn (gen_cskyv2_andsi3 (l0, l1, l2));
+    emit_insn (gen_cskyv2_andsi3 (h0, h1, h2));
+    DONE;
+  }
+  [(set_attr "length" "4,8")]
+)
+
+(define_insn_and_split "*ck801_anddi3"
+ [(set (match_operand:DI        0 "register_operand" "=&r")
+       (and:DI (match_operand:DI 1 "register_operand" "%0")
+              (match_operand:DI 2 "register_operand" "r")))]
+  "CSKY_ISA_FEATURE (E1)"
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  {
+    int hi = TARGET_BIG_ENDIAN ? 0 : UNITS_PER_WORD;
+    int lo = TARGET_BIG_ENDIAN ? UNITS_PER_WORD : 0;
+    rtx l0 = simplify_gen_subreg (SImode, operands[0], DImode, lo);
+    rtx h0 = simplify_gen_subreg (SImode, operands[0], DImode, hi);
+    rtx l1 = simplify_gen_subreg (SImode, operands[1], DImode, lo);
+    rtx h1 = simplify_gen_subreg (SImode, operands[1], DImode, hi);
+    rtx l2 = simplify_gen_subreg (SImode, operands[2], DImode, lo);
+    rtx h2 = simplify_gen_subreg (SImode, operands[2], DImode, hi);
+
+    emit_insn (gen_ck801_andsi3 (l0, l1, l2));
+    emit_insn (gen_ck801_andsi3 (h0, h1, h2));
+    DONE;
+  }
+  [(set_attr "length" "4")]
+)
+
+
+;; -------------------------------------------------------------------------
+;; Ior instructions
+;; -------------------------------------------------------------------------
+
+(define_expand "iorsi3"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (ior:SI (match_operand:SI 1 "register_operand" "")
+               (match_operand:SI 2 "csky_arith_any_imm_operand" "")))]
+  ""
+  "")
+
+(define_insn_and_split "cskyv2_iorsi3"
+  [(set (match_operand:SI        0 "register_operand"           "=b,r,r,&r")
+       (ior:SI (match_operand:SI 1 "register_operand"           "%0,r,r,r")
+               (match_operand:SI 2 "csky_arith_any_imm_operand" "b, r,I,i")))]
+  "CSKY_ISA_FEATURE (E2)"
+  "@
+  or\t%0, %1, %2
+  or\t%0, %1, %2
+  ori\t%0, %1, %2
+  #"
+  "(CONST_INT_P (operands[2])
+    && (operands[2] == const0_rtx
+       || !csky_literal_I_operand (operands[2], SImode)))"
+  [(set (match_dup 0) (ior:SI (match_dup 1) (match_dup 2)))]
+  {
+    if (csky_split_ior (operands))
+      DONE;
+  }
+  [(set_attr "length" "2,4,4,8")
+   (set_attr "type" "alu,alu,alu,alu")]
+)
+
+(define_insn_and_split "ck801_iorsi3"
+  [(set (match_operand:SI        0 "register_operand"           "=r,&r")
+       (ior:SI (match_operand:SI 1 "register_operand"           "%0,r")
+               (match_operand:SI 2 "csky_arith_any_imm_operand" "r,i")))]
+  "CSKY_ISA_FEATURE (E1)"
+  "@
+  or\t%0, %1, %2
+  #"
+  "CONST_INT_P (operands[2])"
+  [(set (match_dup 0) (ior:SI (match_dup 1) (match_dup 2)))]
+  {
+    if (csky_split_ior (operands))
+      DONE;
+  }
+  [(set_attr "length" "2,4")
+   (set_attr "type" "alu,alu")]
+)
+
+(define_expand "iordi3"
+  [(set (match_operand:DI        0 "register_operand" "")
+       (ior:DI (match_operand:DI 1 "register_operand" "")
+               (match_operand:DI 2 "register_operand" "")))]
+  ""
+  ""
+)
+
+(define_insn_and_split "*cskyv2_iordi3"
+  [(set (match_operand:DI        0 "register_operand" "=&b,&r")
+       (ior:DI (match_operand:DI 1 "register_operand" "%0, r")
+               (match_operand:DI 2 "register_operand" "b,  r")))]
+  "CSKY_ISA_FEATURE (E2)"
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  {
+    int hi = TARGET_BIG_ENDIAN ? 0 : UNITS_PER_WORD;
+    int lo = TARGET_BIG_ENDIAN ? UNITS_PER_WORD : 0;
+    rtx l0 = simplify_gen_subreg (SImode, operands[0], DImode, lo);
+    rtx h0 = simplify_gen_subreg (SImode, operands[0], DImode, hi);
+    rtx l1 = simplify_gen_subreg (SImode, operands[1], DImode, lo);
+    rtx h1 = simplify_gen_subreg (SImode, operands[1], DImode, hi);
+    rtx l2 = simplify_gen_subreg (SImode, operands[2], DImode, lo);
+    rtx h2 = simplify_gen_subreg (SImode, operands[2], DImode, hi);
+
+    emit_insn (gen_cskyv2_iorsi3 (l0, l1, l2));
+    emit_insn (gen_cskyv2_iorsi3 (h0, h1, h2));
+    DONE;
+  }
+  [(set_attr "length" "4,8")]
+)
+
+(define_insn_and_split "*ck801_iordi3"
+  [(set (match_operand:DI        0 "register_operand" "=&r")
+       (ior:DI (match_operand:DI 1 "register_operand" "%0")
+               (match_operand:DI 2 "register_operand" "r")))]
+  "CSKY_ISA_FEATURE (E1)"
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  {
+    int hi = TARGET_BIG_ENDIAN ? 0 : UNITS_PER_WORD;
+    int lo = TARGET_BIG_ENDIAN ? UNITS_PER_WORD : 0;
+    rtx l0 = simplify_gen_subreg (SImode, operands[0], DImode, lo);
+    rtx h0 = simplify_gen_subreg (SImode, operands[0], DImode, hi);
+    rtx l1 = simplify_gen_subreg (SImode, operands[1], DImode, lo);
+    rtx h1 = simplify_gen_subreg (SImode, operands[1], DImode, hi);
+    rtx l2 = simplify_gen_subreg (SImode, operands[2], DImode, lo);
+    rtx h2 = simplify_gen_subreg (SImode, operands[2], DImode, hi);
+
+    emit_insn (gen_ck801_iorsi3 (l0, l1, l2));
+    emit_insn (gen_ck801_iorsi3 (h0, h1, h2));
+    DONE;
+  }
+  [(set_attr "length" "4")]
+)
+
+
+;; -------------------------------------------------------------------------
+;; Xor instructions
+;; -------------------------------------------------------------------------
+
+(define_expand "xorsi3"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (xor:SI (match_operand:SI 1 "register_operand" "")
+               (match_operand:SI 2 "csky_arith_any_imm_operand" "")))]
+  ""
+  "")
+
+(define_insn_and_split "cskyv2_xorsi3"
+  [(set (match_operand:SI        0 "register_operand"           "=b,r,r,&r")
+       (xor:SI (match_operand:SI 1 "register_operand"           "%0,r,r,r")
+               (match_operand:SI 2 "csky_arith_any_imm_operand" "b, r,O,i")))]
+  "CSKY_ISA_FEATURE (E2)"
+  "@
+  xor\t%0, %1, %2
+  xor\t%0, %1, %2
+  xori\t%0, %1, %2
+  #"
+  "(CONST_INT_P (operands[2])
+    && (operands[2] == const0_rtx
+       || !csky_arith_O_operand (operands[2], SImode)))"
+  [(set (match_dup 0) (xor:SI (match_dup 1) (match_dup 2)))]
+  {
+    if (csky_split_xor (operands))
+      DONE;
+  }
+  [(set_attr "length" "2,4,4,8")
+   (set_attr "type" "alu,alu,alu,alu")]
+)
+
+(define_insn_and_split "ck801_xorsi3"
+  [(set (match_operand:SI        0 "register_operand"           "=r,&r")
+       (xor:SI (match_operand:SI 1 "register_operand"           "%0,r")
+               (match_operand:SI 2 "csky_arith_any_imm_operand" "r,i")))]
+  "CSKY_ISA_FEATURE (E1)"
+  "@
+  xor\t%0, %1, %2
+  #"
+  "CONST_INT_P (operands[2])"
+  [(set (match_dup 0) (xor:SI (match_dup 1) (match_dup 2)))]
+  {
+    if (csky_split_xor (operands))
+      DONE;
+  }
+  [(set_attr "length" "2,4")
+   (set_attr "type" "alu,alu")]
+)
+
+(define_expand "xordi3"
+  [(set (match_operand:DI        0 "register_operand" "")
+       (xor:DI (match_operand:DI 1 "register_operand" "")
+               (match_operand:DI 2 "register_operand" "")))]
+  ""
+  ""
+)
+
+(define_insn_and_split "*cskyv2_xordi3"
+  [(set (match_operand:DI        0 "register_operand" "=&b,&r")
+       (xor:DI (match_operand:DI 1 "register_operand" "%0, r")
+               (match_operand:DI 2 "register_operand" "b,  r")))]
+  "CSKY_ISA_FEATURE (E2)"
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  {
+    int hi = TARGET_BIG_ENDIAN ? 0 : UNITS_PER_WORD;
+    int lo = TARGET_BIG_ENDIAN ? UNITS_PER_WORD : 0;
+    rtx l0 = simplify_gen_subreg (SImode, operands[0], DImode, lo);
+    rtx h0 = simplify_gen_subreg (SImode, operands[0], DImode, hi);
+    rtx l1 = simplify_gen_subreg (SImode, operands[1], DImode, lo);
+    rtx h1 = simplify_gen_subreg (SImode, operands[1], DImode, hi);
+    rtx l2 = simplify_gen_subreg (SImode, operands[2], DImode, lo);
+    rtx h2 = simplify_gen_subreg (SImode, operands[2], DImode, hi);
+
+    emit_insn (gen_cskyv2_xorsi3 (l0, l1, l2));
+    emit_insn (gen_cskyv2_xorsi3 (h0, h1, h2));
+    DONE;
+  }
+  [(set_attr "length" "4,8")]
+)
+
+(define_insn_and_split "*ck801_xordi3"
+  [(set (match_operand:DI        0 "register_operand" "=&r")
+       (xor:DI (match_operand:DI 1 "register_operand" "%0")
+               (match_operand:DI 2 "register_operand" "r")))]
+  "CSKY_ISA_FEATURE (E1)"
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  {
+    int hi = TARGET_BIG_ENDIAN ? 0 : UNITS_PER_WORD;
+    int lo = TARGET_BIG_ENDIAN ? UNITS_PER_WORD : 0;
+    rtx l0 = simplify_gen_subreg (SImode, operands[0], DImode, lo);
+    rtx h0 = simplify_gen_subreg (SImode, operands[0], DImode, hi);
+    rtx l1 = simplify_gen_subreg (SImode, operands[1], DImode, lo);
+    rtx h1 = simplify_gen_subreg (SImode, operands[1], DImode, hi);
+    rtx l2 = simplify_gen_subreg (SImode, operands[2], DImode, lo);
+    rtx h2 = simplify_gen_subreg (SImode, operands[2], DImode, hi);
+
+    emit_insn (gen_ck801_xorsi3 (l0, l1, l2));
+    emit_insn (gen_ck801_xorsi3 (h0, h1, h2));
+    DONE;
+  }
+  [(set_attr "length" "4")]
+)
+
+;; -------------------------------------------------------------------------
+;; Div instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "divsi3"
+  [(set (match_operand:SI        0 "register_operand" "=r")
+       (div:SI (match_operand:SI 1 "register_operand" "r")
+               (match_operand:SI 2 "register_operand" "r")))]
+  "TARGET_DIV"
+  "divs\t%0, %1, %2"
+)
+
+(define_insn "udivsi3"
+  [(set (match_operand:SI         0 "register_operand" "=r")
+       (udiv:SI (match_operand:SI 1 "register_operand" "r")
+                (match_operand:SI 2 "register_operand" "r")))]
+  "TARGET_DIV"
+  "divu\t%0, %1, %2"
+)
+
+
+;; -----------------------------------------------------------------
+;; Multiple load and store insns
+;; -----------------------------------------------------------------
+
+(define_expand "load_multiple"
+  [(match_par_dup 3 [(set (match_operand:SI 0 "" "")
+                         (match_operand:SI 1 "" ""))
+                    (use (match_operand:SI 2 "" ""))])]
+  "TARGET_MULTIPLE_STLD"
+  "{
+    int regno, count, i;
+    rtx base,src;
+
+    if (GET_CODE (operands[2]) != CONST_INT
+       || INTVAL (operands[2]) < 2
+       || INTVAL (operands[2]) > CSKY_MAX_MULTIPLE_STLD
+       || GET_CODE (operands[1]) != MEM
+       || !REG_P (XEXP (operands[1], 0))
+       || XEXP (operands[1], 0) != stack_pointer_rtx
+       || GET_CODE (operands[0]) != REG
+       || (REGNO (XEXP (operands[1], 0)) > REGNO (operands[0])
+           && (REGNO (XEXP (operands[1], 0))
+               < REGNO (operands[0]) + INTVAL (operands[2]))))
+      FAIL;
+
+    count = INTVAL (operands[2]);
+    regno = REGNO (operands[0]);
+
+    operands[3] = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
+
+    base = force_reg (SImode, XEXP (operands[1], 0));
+    src = replace_equiv_address (operands[1], base);
+
+    for (i = 0; i < count; i++)
+      XVECEXP (operands[3], 0, i)
+       = gen_rtx_SET (gen_rtx_REG (SImode, regno + i),
+                      adjust_address_nv (src, SImode, i * 4));
+  }"
+)
+
+(define_expand "store_multiple"
+  [(match_par_dup 3 [(set (match_operand:SI 0 "")
+                         (match_operand:SI 1 ""))
+                    (use (match_operand:SI 2 ""))])]
+  "TARGET_MULTIPLE_STLD"
+  "{
+    int regno, count, i;
+    rtx base, dest;
+
+    /* Support only storing a constant number of registers to memory and
+       only if at least two registers. */
+    if (GET_CODE (operands[2]) != CONST_INT
+       || INTVAL (operands[2]) < 2
+       || INTVAL (operands[2]) > CSKY_MAX_MULTIPLE_STLD
+       || GET_CODE (operands[0]) != MEM
+       || !REG_P (XEXP (operands[0], 0))
+       || XEXP (operands[0], 0) != stack_pointer_rtx
+       || GET_CODE (operands[1]) != REG
+       || (REGNO (XEXP (operands[0], 0)) >= REGNO (operands[1])
+           && (REGNO (XEXP (operands[0], 0))
+               < REGNO (operands[1]) + INTVAL (operands[2]))))
+      FAIL;
+
+    count = INTVAL (operands[2]);
+    regno = REGNO (operands[1]);
+
+    operands[3] = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
+
+    base = force_reg (SImode, XEXP (operands[0], 0));
+    dest = replace_equiv_address (operands[0], base);
+
+    for (i = 0; i < count; i++)
+      XVECEXP (operands[3], 0, i)
+       = gen_rtx_SET (adjust_address_nv (dest, SImode, i * 4),
+                      gen_rtx_REG (SImode, regno + i));
+  }"
+)
+
+
+(define_insn "*csky_ldmsi12"
+  [(match_parallel         0 "csky_load_multiple_operation"
+    [(set (match_operand:SI 1 "register_operand" "=r")
+         (mem:SI (match_operand:SI   2 "register_operand" "r")))
+     (set (match_operand:SI 3 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+     (set (match_operand:SI 4 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 8))))
+     (set (match_operand:SI 5 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 12))))
+     (set (match_operand:SI 6 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 16))))
+     (set (match_operand:SI 7 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 20))))
+     (set (match_operand:SI 8 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 24))))
+     (set (match_operand:SI 9 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 28))))
+     (set (match_operand:SI 10 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 32))))
+     (set (match_operand:SI 11 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 36))))
+     (set (match_operand:SI 12 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 40))))
+     (set (match_operand:SI 13 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 44))))
+    ])]
+  "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 12"
+  {
+    static char load_op[256] = {0};
+    int count = REGNO (operands[1]) + XVECLEN (operands[0], 0) - 1;
+    const char *reg_rz = reg_names[count];
+    sprintf (load_op, \"ldm\t%%1 - %s, (%%2)\", reg_rz);
+    return load_op;
+  }
+)
+
+(define_insn "*csky_ldmsi11"
+  [(match_parallel         0 "csky_load_multiple_operation"
+    [(set (match_operand:SI 1 "register_operand" "=r")
+         (mem:SI (match_operand:SI   2 "register_operand" "r")))
+     (set (match_operand:SI 3 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+     (set (match_operand:SI 4 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 8))))
+     (set (match_operand:SI 5 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 12))))
+     (set (match_operand:SI 6 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 16))))
+     (set (match_operand:SI 7 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 20))))
+     (set (match_operand:SI 8 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 24))))
+     (set (match_operand:SI 9 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 28))))
+     (set (match_operand:SI 10 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 32))))
+     (set (match_operand:SI 11 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 36))))
+     (set (match_operand:SI 12 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 40))))
+    ])]
+  "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 11"
+  {
+    static char load_op[256] = {0};
+    int count = REGNO (operands[1]) + XVECLEN (operands[0], 0) - 1;
+    const char *reg_rz = reg_names[count];
+    sprintf (load_op, \"ldm\t%%1 - %s, (%%2)\", reg_rz);
+    return load_op;
+  }
+)
+
+(define_insn "*csky_ldmsi10"
+  [(match_parallel         0 "csky_load_multiple_operation"
+    [(set (match_operand:SI 1 "register_operand" "=r")
+         (mem:SI (match_operand:SI   2 "register_operand" "r")))
+     (set (match_operand:SI 3 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+     (set (match_operand:SI 4 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 8))))
+     (set (match_operand:SI 5 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 12))))
+     (set (match_operand:SI 6 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 16))))
+     (set (match_operand:SI 7 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 20))))
+     (set (match_operand:SI 8 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 24))))
+     (set (match_operand:SI 9 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 28))))
+     (set (match_operand:SI 10 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 32))))
+     (set (match_operand:SI 11 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 36))))
+    ])]
+  "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 10"
+  {
+    static char load_op[256] = {0};
+    int count = REGNO (operands[1]) + XVECLEN (operands[0], 0) - 1;
+    const char *reg_rz = reg_names[count];
+    sprintf (load_op, \"ldm\t%%1 - %s, (%%2)\", reg_rz);
+    return load_op;
+  }
+)
+
+(define_insn "*csky_ldmsi9"
+  [(match_parallel         0 "csky_load_multiple_operation"
+    [(set (match_operand:SI 1 "register_operand" "=r")
+         (mem:SI (match_operand:SI   2 "register_operand" "r")))
+     (set (match_operand:SI 3 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+     (set (match_operand:SI 4 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 8))))
+     (set (match_operand:SI 5 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 12))))
+     (set (match_operand:SI 6 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 16))))
+     (set (match_operand:SI 7 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 20))))
+     (set (match_operand:SI 8 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 24))))
+     (set (match_operand:SI 9 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 28))))
+     (set (match_operand:SI 10 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 32))))
+    ])]
+  "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 9"
+  {
+    static char load_op[256] = {0};
+    int count = REGNO (operands[1]) + XVECLEN (operands[0], 0) - 1;
+    const char *reg_rz = reg_names[count];
+    sprintf (load_op, \"ldm\t%%1 - %s, (%%2)\", reg_rz);
+    return load_op;
+  }
+)
+
+(define_insn "*csky_ldmsi8"
+  [(match_parallel         0 "csky_load_multiple_operation"
+    [(set (match_operand:SI 1 "register_operand" "=r")
+         (mem:SI (match_operand:SI   2 "register_operand" "r")))
+     (set (match_operand:SI 3 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+     (set (match_operand:SI 4 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 8))))
+     (set (match_operand:SI 5 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 12))))
+     (set (match_operand:SI 6 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 16))))
+     (set (match_operand:SI 7 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 20))))
+     (set (match_operand:SI 8 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 24))))
+     (set (match_operand:SI 9 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 28))))
+    ])]
+  "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 8"
+  {
+    static char load_op[256] = {0};
+    int count = REGNO (operands[1]) + XVECLEN (operands[0], 0) - 1;
+    const char *reg_rz = reg_names[count];
+    sprintf (load_op, \"ldm\t%%1 - %s, (%%2)\", reg_rz);
+    return load_op;
+  }
+)
+
+(define_insn "*csky_ldmsi7"
+  [(match_parallel         0 "csky_load_multiple_operation"
+    [(set (match_operand:SI 1 "register_operand" "=r")
+         (mem:SI (match_operand:SI   2 "register_operand" "r")))
+     (set (match_operand:SI 3 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+     (set (match_operand:SI 4 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 8))))
+     (set (match_operand:SI 5 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 12))))
+     (set (match_operand:SI 6 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 16))))
+     (set (match_operand:SI 7 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 20))))
+     (set (match_operand:SI 8 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 24))))
+    ])]
+  "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 7"
+  {
+    static char load_op[256] = {0};
+    int count = REGNO (operands[1]) + XVECLEN (operands[0], 0) - 1;
+    const char *reg_rz = reg_names[count];
+    sprintf (load_op, \"ldm\t%%1 - %s, (%%2)\", reg_rz);
+    return load_op;
+  }
+)
+
+(define_insn "*csky_ldmsi6"
+  [(match_parallel         0 "csky_load_multiple_operation"
+    [(set (match_operand:SI 1 "register_operand" "=r")
+         (mem:SI (match_operand:SI   2 "register_operand" "r")))
+     (set (match_operand:SI 3 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+     (set (match_operand:SI 4 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 8))))
+     (set (match_operand:SI 5 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 12))))
+     (set (match_operand:SI 6 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 16))))
+     (set (match_operand:SI 7 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 20))))
+    ])]
+  "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 6"
+  {
+    static char load_op[256] = {0};
+    int count = REGNO (operands[1]) + XVECLEN (operands[0], 0) - 1;
+    const char *reg_rz = reg_names[count];
+    sprintf (load_op, \"ldm\t%%1 - %s, (%%2)\", reg_rz);
+    return load_op;
+  }
+)
+
+
+(define_insn "*csky_ldmsi5"
+  [(match_parallel         0 "csky_load_multiple_operation"
+    [(set (match_operand:SI 1 "register_operand" "=r")
+         (mem:SI (match_operand:SI   2 "register_operand" "r")))
+     (set (match_operand:SI 3 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+     (set (match_operand:SI 4 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 8))))
+     (set (match_operand:SI 5 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 12))))
+     (set (match_operand:SI 6 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 16))))
+    ])]
+  "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 5"
+  {
+    static char load_op[256] = {0};
+    int count = REGNO (operands[1]) + XVECLEN (operands[0], 0) - 1;
+    const char *reg_rz = reg_names[count];
+    sprintf (load_op, \"ldm\t%%1 - %s, (%%2)\", reg_rz);
+    return load_op;
+  }
+)
+
+
+(define_insn "*csky_ldmsi4"
+  [(match_parallel         0 "csky_load_multiple_operation"
+    [(set (match_operand:SI 1 "register_operand" "=r")
+         (mem:SI (match_operand:SI   2 "register_operand" "r")))
+     (set (match_operand:SI 3 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+     (set (match_operand:SI 4 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 8))))
+     (set (match_operand:SI 5 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 12))))
+    ])]
+  "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 4"
+  {
+    static char load_op[256] = {0};
+    int count = REGNO (operands[1]) + XVECLEN (operands[0], 0) - 1;
+    const char *reg_rz = reg_names[count];
+    sprintf (load_op, \"ldm\t%%1 - %s, (%%2)\", reg_rz);
+    return load_op;
+  }
+)
+
+
+(define_insn "*csky_ldmsi3"
+  [(match_parallel         0 "csky_load_multiple_operation"
+    [(set (match_operand:SI 1 "register_operand" "=r")
+         (mem:SI (match_operand:SI   2 "register_operand" "r")))
+     (set (match_operand:SI 3 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+     (set (match_operand:SI 4 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 8))))
+    ])]
+  "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 3"
+  {
+    static char load_op[256] = {0};
+    int count = REGNO (operands[1]) + XVECLEN (operands[0], 0) - 1;
+    const char *reg_rz = reg_names[count];
+    sprintf (load_op, \"ldm\t%%1 - %s, (%%2)\", reg_rz);
+    return load_op;
+  }
+)
+
+
+(define_insn "*csky_ldmsi2"
+  [(match_parallel         0 "csky_load_multiple_operation"
+    [(set (match_operand:SI 1 "register_operand" "=r")
+         (mem:SI (match_operand:SI   2 "register_operand" "r")))
+     (set (match_operand:SI 3 "register_operand" "=r")
+         (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+    ])]
+  "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 2"
+  {
+    static char load_op[256] = {0};
+    int count = REGNO (operands[1]) + XVECLEN (operands[0], 0) - 1;
+    const char *reg_rz = reg_names[count];
+    sprintf (load_op, \"ldm\t%%1 - %s, (%%2)\", reg_rz);
+    return load_op;
+  }
+)
+
+(define_insn "*csky_stmsi12"
+  [(match_parallel         0 "csky_store_multiple_operation"
+    [(set (mem:SI (match_operand:SI   1 "register_operand" "r"))
+         (match_operand:SI 2 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+         (match_operand:SI 3 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+         (match_operand:SI 4 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
+         (match_operand:SI 5 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 16)))
+         (match_operand:SI 6 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 20)))
+         (match_operand:SI 7 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 24)))
+         (match_operand:SI 8 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 28)))
+         (match_operand:SI 9 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 32)))
+         (match_operand:SI 10 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 36)))
+         (match_operand:SI 11 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 40)))
+         (match_operand:SI 12 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 44)))
+         (match_operand:SI 13 "register_operand" "r"))
+    ])]
+  "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 12"
+  {
+    static char load_op[256] = {0};
+    int end = REGNO (operands[2]) + XVECLEN (operands[0], 0) - 1;
+    const char *reg_rz = reg_names[end];
+    sprintf (load_op, \"stm\t%%2 - %s, (%%1)\", reg_rz);
+    return load_op;
+  }
+)
+
+
+(define_insn "*csky_stmsi11"
+  [(match_parallel         0 "csky_store_multiple_operation"
+    [(set (mem:SI (match_operand:SI   1 "register_operand" "r"))
+         (match_operand:SI 2 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+         (match_operand:SI 3 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+         (match_operand:SI 4 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
+         (match_operand:SI 5 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 16)))
+         (match_operand:SI 6 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 20)))
+         (match_operand:SI 7 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 24)))
+         (match_operand:SI 8 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 28)))
+         (match_operand:SI 9 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 32)))
+         (match_operand:SI 10 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 36)))
+         (match_operand:SI 11 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 40)))
+         (match_operand:SI 12 "register_operand" "r"))
+    ])]
+  "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 11"
+  {
+    static char load_op[256] = {0};
+    int end = REGNO (operands[2]) + XVECLEN (operands[0], 0) - 1;
+    const char *reg_rz = reg_names[end];
+    sprintf (load_op, \"stm\t%%2 - %s, (%%1)\", reg_rz);
+    return load_op;
+  }
+)
+
+
+(define_insn "*csky_stmsi10"
+  [(match_parallel         0 "csky_store_multiple_operation"
+    [(set (mem:SI (match_operand:SI   1 "register_operand" "r"))
+         (match_operand:SI 2 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+         (match_operand:SI 3 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+         (match_operand:SI 4 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
+         (match_operand:SI 5 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 16)))
+         (match_operand:SI 6 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 20)))
+         (match_operand:SI 7 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 24)))
+         (match_operand:SI 8 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 28)))
+         (match_operand:SI 9 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 32)))
+         (match_operand:SI 10 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 36)))
+         (match_operand:SI 11 "register_operand" "r"))
+    ])]
+  "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 10"
+  {
+    static char load_op[256] = {0};
+    int end = REGNO (operands[2]) + XVECLEN (operands[0], 0) - 1;
+    const char *reg_rz = reg_names[end];
+    sprintf (load_op, \"stm\t%%2 - %s, (%%1)\", reg_rz);
+    return load_op;
+  }
+)
+
+
+(define_insn "*csky_stmsi9"
+  [(match_parallel         0 "csky_store_multiple_operation"
+    [(set (mem:SI (match_operand:SI   1 "register_operand" "r"))
+         (match_operand:SI 2 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+         (match_operand:SI 3 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+         (match_operand:SI 4 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
+         (match_operand:SI 5 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 16)))
+         (match_operand:SI 6 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 20)))
+         (match_operand:SI 7 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 24)))
+         (match_operand:SI 8 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 28)))
+         (match_operand:SI 9 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 32)))
+         (match_operand:SI 10 "register_operand" "r"))
+    ])]
+  "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 9"
+  {
+    static char load_op[256] = {0};
+    int end = REGNO (operands[2]) + XVECLEN (operands[0], 0) - 1;
+    const char *reg_rz = reg_names[end];
+    sprintf (load_op, \"stm\t%%2 - %s, (%%1)\", reg_rz);
+    return load_op;
+  }
+)
+
+
+(define_insn "*csky_stmsi8"
+  [(match_parallel         0 "csky_store_multiple_operation"
+    [(set (mem:SI (match_operand:SI   1 "register_operand" "r"))
+         (match_operand:SI 2 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+         (match_operand:SI 3 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+         (match_operand:SI 4 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
+         (match_operand:SI 5 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 16)))
+         (match_operand:SI 6 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 20)))
+         (match_operand:SI 7 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 24)))
+         (match_operand:SI 8 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 28)))
+         (match_operand:SI 9 "register_operand" "r"))
+    ])]
+  "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 8"
+  {
+    static char load_op[256] = {0};
+    int end = REGNO (operands[2]) + XVECLEN (operands[0], 0) - 1;
+    const char *reg_rz = reg_names[end];
+    sprintf (load_op, \"stm\t%%2 - %s, (%%1)\", reg_rz);
+    return load_op;
+  }
+)
+
+
+(define_insn "*csky_stmsi7"
+  [(match_parallel         0 "csky_store_multiple_operation"
+    [(set (mem:SI (match_operand:SI   1 "register_operand" "r"))
+         (match_operand:SI 2 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+         (match_operand:SI 3 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+         (match_operand:SI 4 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
+         (match_operand:SI 5 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 16)))
+         (match_operand:SI 6 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 20)))
+         (match_operand:SI 7 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 24)))
+         (match_operand:SI 8 "register_operand" "r"))
+    ])]
+  "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 7"
+  {
+    static char load_op[256] = {0};
+    int end = REGNO (operands[2]) + XVECLEN (operands[0], 0) - 1;
+    const char *reg_rz = reg_names[end];
+    sprintf (load_op, \"stm\t%%2 - %s, (%%1)\", reg_rz);
+    return load_op;
+  }
+)
+
+
+(define_insn "*csky_stmsi6"
+  [(match_parallel         0 "csky_store_multiple_operation"
+    [(set (mem:SI (match_operand:SI   1 "register_operand" "r"))
+         (match_operand:SI 2 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+         (match_operand:SI 3 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+         (match_operand:SI 4 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
+         (match_operand:SI 5 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 16)))
+         (match_operand:SI 6 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 20)))
+         (match_operand:SI 7 "register_operand" "r"))
+    ])]
+  "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 6"
+  {
+    static char load_op[256] = {0};
+    int end = REGNO (operands[2]) + XVECLEN (operands[0], 0) - 1;
+    const char *reg_rz = reg_names[end];
+    sprintf (load_op, \"stm\t%%2 - %s, (%%1)\", reg_rz);
+    return load_op;
+  }
+)
+
+(define_insn "*csky_stmsi5"
+  [(match_parallel         0 "csky_store_multiple_operation"
+    [(set (mem:SI (match_operand:SI   1 "register_operand" "r"))
+         (match_operand:SI 2 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+         (match_operand:SI 3 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+         (match_operand:SI 4 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
+         (match_operand:SI 5 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 16)))
+         (match_operand:SI 6 "register_operand" "r"))
+    ])]
+  "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 5"
+  {
+    static char load_op[256] = {0};
+    int end = REGNO (operands[2]) + XVECLEN (operands[0], 0) - 1;
+    const char *reg_rz = reg_names[end];
+    sprintf (load_op, \"stm\t%%2 - %s, (%%1)\", reg_rz);
+    return load_op;
+  }
+)
+
+
+(define_insn "*csky_stmsi4"
+  [(match_parallel         0 "csky_store_multiple_operation"
+    [(set (mem:SI (match_operand:SI   1 "register_operand" "r"))
+         (match_operand:SI 2 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+         (match_operand:SI 3 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+         (match_operand:SI 4 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
+         (match_operand:SI 5 "register_operand" "r"))
+    ])]
+  "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 4"
+  {
+    static char load_op[256] = {0};
+    int end = REGNO (operands[2]) + XVECLEN (operands[0], 0) - 1;
+    const char *reg_rz = reg_names[end];
+    sprintf (load_op, \"stm\t%%2 - %s, (%%1)\", reg_rz);
+    return load_op;
+  }
+)
+
+
+(define_insn "*csky_stmsi3"
+  [(match_parallel         0 "csky_store_multiple_operation"
+    [(set (mem:SI (match_operand:SI   1 "register_operand" "r"))
+         (match_operand:SI 2 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+         (match_operand:SI 3 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+         (match_operand:SI 4 "register_operand" "r"))
+    ])]
+  "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 3"
+  {
+    static char load_op[256] = {0};
+    int end = REGNO (operands[2]) + XVECLEN (operands[0], 0) - 1;
+    const char *reg_rz = reg_names[end];
+    sprintf (load_op, \"stm\t%%2 - %s, (%%1)\", reg_rz);
+    return load_op;
+  }
+)
+
+
+(define_insn "*csky_stmsi2"
+  [(match_parallel         0 "csky_store_multiple_operation"
+    [(set (mem:SI (match_operand:SI   1 "register_operand" "r"))
+         (match_operand:SI 2 "register_operand" "r"))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+         (match_operand:SI 3 "register_operand" "r"))
+    ])]
+  "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 2"
+  {
+    static char load_op[256] = {0};
+    int end = REGNO (operands[2]) + XVECLEN (operands[0], 0) - 1;
+    const char *reg_rz = reg_names[end];
+    sprintf (load_op, \"stm\t%%2 - %s, (%%1)\", reg_rz);
+    return load_op;
+  }
+)
+
+
+;; ------------------------------------------------------------------------
+;; Jump and linkage insns
+;; ------------------------------------------------------------------------
+
+(define_expand "tablejump"
+  [(parallel [(set (pc) (match_operand:SI 0 "register_operand" "r"))
+             (use (label_ref (match_operand 1 "" "")))])]
+  ""
+  "
+  if (flag_pic)
+    operands[0] = expand_simple_binop (Pmode, PLUS, operands[0],
+                                      pic_offset_table_rtx, NULL_RTX,
+                                      1, OPTAB_DIRECT);
+  "
+)
+
+(define_insn "*tablejump"
+  [(set (pc) (match_operand:SI   0 "register_operand" "r"))
+   (use (label_ref (match_operand 1 ""                "")))]
+  ""
+  "jmp %0"
+  [(set_attr "type" "branch_jmp")]
+)
+
+(define_expand "jump"
+  [(set (pc) (label_ref (match_operand 0 "" "")))]
+  ""
+  ""
+)
+
+(define_insn "*csky_jump"
+  [(set (pc) (label_ref (match_operand 0 "" "")))]
+  "CSKY_ISA_FEATURE (E2)"
+  "jbr %l0"
+  [(set_attr "type" "branch")]
+)
+
+;; The length of bsr is not really 5; it's used to distinguish from br32.
+;; Since the length attribute is treated specially it doesn't seem possible
+;; to compute the far_jump attribute directly and use that.
+
+(define_insn "*ck801_ck802_jump"
+  [(set (pc) (label_ref (match_operand 0 "" "")))]
+  "CSKY_ISA_FEATURE (E1) || CSKY_ISA_FEATURE (E2)"
+  "*{
+    if (get_attr_length (insn) != 5)
+      return \"jbr\\t%l0\";
+    else
+      return \"bsr\\t%l0\\t//far jump\";
+  }"
+  [(set_attr "type" "branch")
+   (set (attr "far_jump")
+       (if_then_else
+         (eq_attr "length" "5")
+         (const_string "yes")
+         (const_string "no")))
+   (set (attr "length")
+       (if_then_else
+         (and (ge (minus (match_dup 0) (pc)) (const_int -1024))
+              (le (minus (match_dup 0) (pc)) (const_int 1022)))
+         (const_int 2)
+         (if_then_else
+           (and (ge (minus (match_dup 0) (pc)) (const_int -65536))
+                (le (minus (match_dup 0) (pc)) (const_int 65534)))
+           (const_int 4)
+           (const_int 5))))]
+)
+
+(define_insn "indirect_jump"
+  [(set (pc) (match_operand:SI 0 "register_operand" "b,r"))]
+  ""
+  "@
+    jmp\t%0
+    jmp\t%0"
+  [(set_attr "length" "2,4")
+   (set_attr "type" "branch_jmp")]
+)
+
+
+;; ------------------------------------------------------------------------
+;; Conditional jump insns
+;; ------------------------------------------------------------------------
+
+(define_expand "cbranchsi4"
+  [(set (pc)
+       (if_then_else (match_operator 0 "ordered_comparison_operator"
+                       [(match_operand:SI 1 "csky_compare_operand")
+                        (match_operand:SI 2 "nonmemory_operand")])
+                     (label_ref (match_operand 3 ""))
+                     (pc)))]
+  ""
+  "{
+    enum rtx_code code = GET_CODE (operands[0]);
+
+     if (CSKY_ISA_FEATURE (2E3)
+        && (code == LE || code == LT || code == GT
+            || code == GE || code == EQ || code == NE)
+        && operands[2] == const0_rtx)
+       {
+        /* These cases match the jbez, jbnez, etc insns below.
+           TODO: Handling this in the expander is suboptimal since it
+           fails to detect cases where the constant 0 would fall out
+           from subsequent forward propagation or loop optimizers; maybe
+           it would be better to have a splitter here, but when to split?  */
+       }
+     else
+       {
+        bool invert = csky_emit_compare (code, operands[1], operands[2]);
+
+        if (invert)
+          emit_jump_insn (gen_csky_jbf (operands[3]));
+        else
+          emit_jump_insn (gen_csky_jbt (operands[3]));
+        DONE;
+     }
+  }"
+)
+
+(define_insn "csky_jbt"
+  [(set (pc)
+       (if_then_else (ne (reg:CC CSKY_CC_REGNUM) (const_int 0))
+                     (label_ref (match_operand 0 "" ""))
+                     (pc)))]
+  "CSKY_ISA_FEATURE (2E3)"
+  "jbt\t%l0"
+  [(set_attr "type" "cbranch")]
+)
+
+(define_insn "csky_jbf"
+  [(set (pc)
+       (if_then_else (eq (reg:CC CSKY_CC_REGNUM) (const_int 0))
+                     (label_ref (match_operand 0 "" ""))
+                     (pc)))]
+  "CSKY_ISA_FEATURE (2E3)"
+  "jbf\t%l0"
+  [(set_attr "type" "cbranch")]
+)
+
+
+;;; CK802 has 32-bit jbt/jbf instructions, but no insn other
+;;; than bsr for far jumps.
+
+(define_insn "ck802_jbt"
+  [(set (pc) (if_then_else (ne (reg:CC CSKY_CC_REGNUM) (const_int 0))
+                          (label_ref (match_operand 0 "" ""))
+                          (pc)))]
+  "CSKY_ISA_FEATURE (E2)"
+  {
+    if (get_attr_length (insn) == 6)
+      return \"jbf\\t.LCB%=\;bsr\\t%l0\\t//far jump\\n.LCB%=:\";
+    else
+      return \"jbt\\t%l0\";
+   }
+  [(set_attr "type" "cbranch")
+   (set (attr "far_jump")
+       (if_then_else
+         (eq_attr "length" "6")
+         (const_string "yes")
+         (const_string "no")))
+   (set (attr "length")
+       (if_then_else
+         (and (ge (minus (match_dup 0) (pc)) (const_int -1024))
+              (le (minus (match_dup 0) (pc)) (const_int 1022)))
+         (const_int 2)
+         (if_then_else
+           (and (ge (minus (match_dup 0) (pc)) (const_int -65534))
+                (le (minus (match_dup 0) (pc)) (const_int 65534)))
+           (const_int 4)
+           (const_int 6))))]
+)
+
+(define_insn "ck802_jbf"
+  [(set (pc) (if_then_else (eq (reg:CC CSKY_CC_REGNUM) (const_int 0))
+                          (label_ref (match_operand 0 "" ""))
+                          (pc)))]
+  "CSKY_ISA_FEATURE (E2)"
+  {
+    if (get_attr_length (insn) == 6)
+      return \"jbt\\t.LCB%=\;bsr\\t%l0\\t//far jump\\n.LCB%=:\";
+    else
+      return \"jbf\\t%l0\";
+   }
+  [(set_attr "type" "cbranch")
+   (set (attr "far_jump")
+       (if_then_else
+         (eq_attr "length" "6")
+         (const_string "yes")
+         (const_string "no")))
+   (set (attr "length")
+       (if_then_else
+         (and (ge (minus (match_dup 0) (pc)) (const_int -1024))
+              (le (minus (match_dup 0) (pc)) (const_int 1022)))
+         (const_int 2)
+         (if_then_else
+           (and (ge (minus (match_dup 0) (pc)) (const_int -65534))
+                (le (minus (match_dup 0) (pc)) (const_int 65534)))
+           (const_int 4)
+           (const_int 6))))]
+)
+
+;; The length of the bsr case is not really 7; it's used to distinguish
+;; from br32.
+;; Note that we have to adjust the backward range of the jbr case to
+;; account for the jbf in front of it.
+(define_insn "ck801_jbt"
+  [(set (pc) (if_then_else (ne (reg:CC CSKY_CC_REGNUM) (const_int 0))
+                          (label_ref (match_operand 0 "" ""))
+                          (pc)))]
+  "CSKY_ISA_FEATURE (E1)"
+  {
+    if (get_attr_length (insn) == 6)
+      return \"jbf\\t.LCB%=\;jbr\\t%l0\\n.LCB%=:\";
+    else if (get_attr_length (insn) == 7)
+      return \"jbf\\t.LCB%=\;bsr\\t%l0\\t//far jump\\n.LCB%=:\";
+    else
+      return \"jbt\\t%l0\";
+   }
+  [(set_attr "type" "cbranch")
+   (set (attr "far_jump")
+       (if_then_else
+         (eq_attr "length" "7")
+         (const_string "yes")
+         (const_string "no")))
+   (set (attr "length")
+       (if_then_else
+         (and (ge (minus (match_dup 0) (pc)) (const_int -1024))
+              (le (minus (match_dup 0) (pc)) (const_int 1022)))
+         (const_int 2)
+         (if_then_else
+           (and (ge (minus (match_dup 0) (pc)) (const_int -65534))
+                (le (minus (match_dup 0) (pc)) (const_int 65534)))
+           (const_int 6)
+           (const_int 7))))]
+)
+
+(define_insn "ck801_jbf"
+  [(set (pc)
+       (if_then_else (eq (reg:CC CSKY_CC_REGNUM) (const_int 0))
+                     (label_ref (match_operand 0 "" ""))
+                     (pc)))]
+  "CSKY_ISA_FEATURE (E1)"
+  {
+    if (get_attr_length (insn) == 6)
+      return \"jbt\\t.LCB%=\;jbr\\t%l0\\n.LCB%=:\";
+    else if (get_attr_length (insn) == 7)
+      return \"jbt\\t.LCB%=\;bsr\\t%l0\\t//far jump\\n.LCB%=:\";
+    else
+      return \"jbf\\t%l0\";
+  }
+  [(set_attr "type" "cbranch")
+   (set (attr "far_jump")
+       (if_then_else
+         (eq_attr "length" "7")
+         (const_string "yes")
+         (const_string "no")))
+   (set (attr "length")
+       (if_then_else
+         (and (ge (minus (match_dup 0) (pc)) (const_int -1024))
+              (le (minus (match_dup 0) (pc)) (const_int 1022)))
+         (const_int 2)
+         (if_then_else
+           (and (ge (minus (match_dup 0) (pc)) (const_int -65534))
+                (le (minus (match_dup 0) (pc)) (const_int 65534)))
+           (const_int 6)
+           (const_int 7))))]
+)
+
+(define_code_iterator zero_cond [lt le gt ge eq ne])
+
+(define_code_attr inst [(lt "jblz") (le "jblsz") (gt "jbhz") (ge "jbhsz") (eq "jbez") (ne "jbnez")])
+
+(define_insn "*<inst>"
+  [(set (pc)
+       (if_then_else (zero_cond (match_operand:SI 0 "register_operand" "r")
+                                (const_int 0))
+                     (label_ref (match_operand 1 "" ""))
+                     (pc)))]
+  "CSKY_ISA_FEATURE (2E3)"
+  "<inst>\t%0, %l1"
+  [(set_attr "type" "cbranch")]
+)
+
+;; ------------------------------------------------------------------------
+;; return insns
+;; ------------------------------------------------------------------------
+
+(define_insn "simple_return"
+  [(simple_return)]
+  "reload_completed"
+  "*
+    return csky_output_return_instruction ();
+  "
+)
+
+(define_expand "eh_return"
+  [(use (match_operand 0 "general_operand" ""))]
+  ""
+  "{
+    emit_insn (gen_csky_eh_return (operands[0]));
+    DONE;
+  }"
+)
+
+;; We can't expand this before we know where the link register is stored.
+(define_insn_and_split "csky_eh_return"
+  [(unspec_volatile [(match_operand:SI 0 "register_operand" "r")]
+                   VUNSPEC_EH_RETURN)
+   (clobber (match_scratch:SI 1 "=&r"))]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+  "{
+    csky_set_eh_return_address (operands[0], operands[1]);
+    DONE;
+  }"
+)
+
+;; -------------------------------------------------------------------------
+;; SImode signed integer comparisons
+;; -------------------------------------------------------------------------
+
+(define_insn "*cmpnesi_r"
+  [(set (reg:CC CSKY_CC_REGNUM)
+       (ne:CC (match_operand:SI 0 "register_operand" "b,r")
+              (match_operand:SI 1 "register_operand" "b,r")))]
+  ""
+  "@
+    cmpne\t%0, %1
+    cmpne\t%0, %1"
+  [(set_attr "length" "2,4")
+   (set_attr "type" "cmp")]
+)
+
+;; cmpnei range is 0-31 for Smart mode.
+(define_insn "smart_cmpnesi_i"
+  [(set (reg:CC CSKY_CC_REGNUM)
+       (ne:CC (match_operand:SI 0 "register_operand"       "a")
+              (match_operand:SI 1 "csky_literal_K_operand" "K")))]
+  "TARGET_MINI_REGISTERS"
+  "cmpnei\t%0, %1"
+  [(set_attr "type" "cmp")]
+)
+
+;; cmpnei range is 0 - 65536 for Fast mode.
+(define_insn "fast_cmpnesi_i"
+  [(set (reg:CC CSKY_CC_REGNUM)
+       (ne:CC (match_operand:SI 0 "register_operand"       "r")
+              (match_operand:SI 1 "csky_literal_I_operand" "I")))]
+  "!TARGET_MINI_REGISTERS && CSKY_ISA_FEATURE (E2)"
+  "cmpnei\t%0, %1"
+  [(set_attr "type" "cmp")]
+)
+
+(define_insn "*cmpgtsi"
+  [(set (reg:CC CSKY_CC_REGNUM)
+       (gt:CC (match_operand:SI 0 "register_operand" "b,r")
+              (match_operand:SI 1 "register_operand" "b,r")))]
+  ""
+  "cmplt\t%1, %0"
+  [(set_attr "length" "2,4")
+   (set_attr "type" "cmp")]
+)
+
+(define_insn "cmpltsi_r"
+  [(set (reg:CC CSKY_CC_REGNUM)
+       (lt:CC (match_operand:SI 0 "register_operand" "b,r")
+              (match_operand:SI 1 "register_operand" "b,r")))]
+  ""
+  "cmplt\t%0, %1"
+  [(set_attr "length" "2,4")
+   (set_attr "type" "cmp")]
+)
+
+;; cmplti range is 1-32 for Smart mode.
+(define_insn "*smart_cmpltsi_i"
+  [(set (reg:CC CSKY_CC_REGNUM)
+       (lt:CC (match_operand:SI 0 "register_operand"       "a")
+              (match_operand:SI 1 "csky_literal_J_operand" "J")))]
+  "TARGET_MINI_REGISTERS"
+  "cmplti\t%0, %1"
+  [(set_attr "length" "2")
+   (set_attr "type" "cmp")]
+)
+
+
+;; cmplti range is 1-65536 for Fast mode.
+(define_insn "*fast_cmpltsi_i"
+  [(set (reg:CC CSKY_CC_REGNUM)
+       (lt:CC (match_operand:SI 0 "register_operand"        "a,r")
+              (match_operand:SI 1 "csky_literal_Uk_operand" "J,Uk")))]
+  "!TARGET_MINI_REGISTERS && CSKY_ISA_FEATURE (E2)"
+  "cmplti\t%0, %1"
+  [(set_attr "length" "2,4")
+   (set_attr "type" "cmp")]
+)
+
+; Covers cmplti x,0.
+(define_insn "*cskyv2_cmpltsi_0"
+  [(set (reg:CC CSKY_CC_REGNUM)
+       (lt:CC (match_operand:SI 0 "register_operand" "a,r")
+              (const_int 0)))]
+  "CSKY_ISA_FEATURE (E2)"
+  "btsti\t%0, 31"
+  [(set_attr "length" "2,4")
+   (set_attr "type" "cmp")]
+)
+
+(define_insn "*ck801_cmpltsi_0"
+  [(set (reg:CC CSKY_CC_REGNUM)
+       (lt:CC (match_operand:SI 0 "register_operand" "a")
+              (const_int 0)))]
+  "CSKY_ISA_FEATURE (E1)"
+  "btsti\t%0, 31"
+  [(set_attr "type" "cmp")]
+)
+
+;; Decrement and test instructions.
+;; In theory decne could be used in conjunction with jbt to implement
+;; doloop_end, but that seems to encourage the loop optimizer to introduce
+;; an additional induction variable and doesn't actually result in tighter
+;; loop code for that reason.
+
+(define_insn "*cskyv2_declt"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (match_operand:SI 1 "register_operand" "r")
+                (match_operand:SI 2 "const_int_operand" "Uh")))
+   (set (reg:CC CSKY_CC_REGNUM)
+       (lt:CC (plus:SI (match_dup 1) (match_dup 2))
+              (const_int 0)))]
+  "CSKY_ISA_FEATURE (2E3)"
+  "declt\t%0, %1, %M2"
+)
+
+(define_insn "*cskyv2_decgt"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (match_operand:SI 1 "register_operand" "r")
+                (match_operand:SI 2 "const_int_operand" "Uh")))
+   (set (reg:CC CSKY_CC_REGNUM)
+       (gt:CC (plus:SI (match_dup 1) (match_dup 2))
+              (const_int 0)))]
+  "CSKY_ISA_FEATURE (2E3)"
+  "decgt\t%0, %1, %M2"
+)
+
+(define_insn "*cskyv2_decne"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (match_operand:SI 1 "register_operand" "r")
+                (match_operand:SI 2 "const_int_operand" "Uh")))
+   (set (reg:CC CSKY_CC_REGNUM)
+       (ne:CC (plus:SI (match_dup 1) (match_dup 2))
+              (const_int 0)))]
+  "CSKY_ISA_FEATURE (2E3)"
+  "decne\t%0, %1, %M2"
+)
+
+;; -------------------------------------------------------------------------
+;; SImode unsigned integer comparisons
+;; -------------------------------------------------------------------------
+
+(define_insn "cmpgeusi_r"
+  [(set (reg:CC CSKY_CC_REGNUM)
+       (geu:CC (match_operand:SI 0 "register_operand" "b,r")
+               (match_operand:SI 1 "register_operand" "b,r")))]
+  ""
+  "cmphs\t%0, %1"
+  [(set_attr "length" "2,4")
+   (set_attr "type" "cmp")]
+)
+
+(define_insn "*smart_cmpgeusi_i"
+  [(set (reg:CC CSKY_CC_REGNUM)
+       (geu:CC (match_operand:SI 0 "register_operand"       "a")
+               (match_operand:SI 1 "csky_literal_J_operand" "J")))]
+  "TARGET_MINI_REGISTERS"
+  "cmphsi\t%0, %1"
+  [(set_attr "length" "2")
+   (set_attr "type" "cmp")]
+)
+
+(define_insn "*fast_cmpgeusi_i"
+  [(set (reg:CC CSKY_CC_REGNUM)
+       (geu:CC (match_operand:SI 0 "register_operand"        "a,r")
+               (match_operand:SI 1 "csky_literal_Uk_operand" "J,Uk")))]
+  "!TARGET_MINI_REGISTERS && CSKY_ISA_FEATURE (E2)"
+  "cmphsi\t%0, %1"
+  [(set_attr "length" "2,4")
+   (set_attr "type" "cmp")]
+)
+
+(define_insn "*cmpleusi"
+  [(set (reg:CC CSKY_CC_REGNUM)
+       (leu:CC (match_operand:SI 0 "register_operand" "b,r")
+               (match_operand:SI 1 "register_operand" "b,r")))]
+  ""
+  "cmphs\t%1, %0"
+  [(set_attr "length" "2,4")
+   (set_attr "type" "cmp")]
+)
+
+;; -------------------------------------------------------------------------
+;; Function call insns
+;; -------------------------------------------------------------------------
+
+(define_expand "call"
+  [(parallel [(call (match_operand:SI 0 "" "") (match_operand 1 "" ""))
+             (clobber (reg:SI CSKY_LR_REGNUM))])]
+  ""
+  "
+  {
+    rtx pic_ref;
+    rtx addr_ref = XEXP (operands[0], 0);
+
+    if (flag_pic
+       && (CONSTANT_P (addr_ref)
+           || csky_symbol_mentioned_p (addr_ref)
+           || csky_label_mentioned_p (addr_ref)))
+      {
+       pic_ref = csky_legitimize_pic_address (addr_ref, 0, false);
+       operands[0] = gen_rtx_MEM (GET_MODE (pic_ref), pic_ref);
+      }
+
+     if (GET_CODE (operands[0]) == MEM
+        && ! register_operand (XEXP (operands[0], 0), SImode)
+        && ! csky_symbolic_address_p (XEXP (operands[0], 0))
+        && ! (flag_pic
+              && csky_unspec_operand (XEXP (operands[0], 0), SImode)))
+       operands[0] = gen_rtx_MEM (GET_MODE (operands[0]),
+                                 force_reg (Pmode, XEXP (operands[0], 0)));
+  }"
+)
+
+
+(define_insn "*call_internal"
+  [(call (mem:SI (match_operand:SI 0 "csky_call_address_operand" "b,r,S"))
+        (match_operand 1 "" ""))
+   (clobber (reg:SI CSKY_LR_REGNUM))]
+  ""
+  "@
+    jsr\t%0
+    jsr\t%0
+    jbsr\t%0"
+  [(set_attr "length" "2,4,4")
+   (set_attr "type"   "call_jsr,call_jsr,call")]
+)
+
+(define_insn "*call_internal_pic"
+  [(call (mem:SI (match_operand:SI 0 "csky_unspec_operand" "X"))
+        (match_operand            1 "" ""))
+  (clobber (reg:SI CSKY_LR_REGNUM))]
+  "flag_pic"
+  "* return csky_output_call (operands, 0);"
+  [(set_attr "length" "4")]
+)
+
+(define_expand "call_value"
+  [(parallel [(set (match_operand 0 "register_operand" "")
+                  (call (match_operand:SI 1 "" "") (match_operand 2 "" "")))
+             (clobber (reg:SI CSKY_LR_REGNUM))])]
+  ""
+  "{
+    rtx pic_ref;
+    rtx addr_ref = XEXP (operands[1], 0);
+
+    if (flag_pic
+       && (CONSTANT_P (addr_ref)
+           || csky_symbol_mentioned_p (addr_ref)
+           || csky_label_mentioned_p (addr_ref)))
+      {
+       pic_ref = csky_legitimize_pic_address (addr_ref, 0, false);
+       operands[1] = gen_rtx_MEM (GET_MODE (pic_ref), pic_ref);
+      }
+
+     if (GET_CODE (operands[1]) == MEM
+        && ! register_operand (XEXP (operands[1], 0), SImode)
+        && ! csky_symbolic_address_p (XEXP (operands[1], 0))
+        && ! (flag_pic
+              && csky_unspec_operand (XEXP (operands[1], 0), SImode)))
+      operands[1] = gen_rtx_MEM (GET_MODE (operands[1]),
+                                force_reg (Pmode, XEXP (operands[1], 0)));
+  }")
+
+
+(define_insn "*call_value_internal"
+  [(set (match_operand                 0 "register_operand"          "=r,r,r")
+       (call (mem:SI (match_operand:SI 1 "csky_call_address_operand" "b, r,S"))
+             (match_operand 2 "" "")))
+   (clobber (reg:SI CSKY_LR_REGNUM))]
+  ""
+  "@
+    jsr\t%1
+    jsr\t%1
+    jbsr\t%1"
+  [(set_attr "length" "2,4,4")
+   (set_attr "type"   "call_jsr,call_jsr,call")]
+)
+
+(define_insn "*call_value_internal_pic"
+  [(set (match_operand                 0 "register_operand"    "=r")
+       (call (mem:SI (match_operand:SI 1 "csky_unspec_operand" "X"))
+                     (match_operand    2 "" "")))
+   (clobber (reg:SI CSKY_LR_REGNUM))]
+  "flag_pic"
+  "* return csky_output_call (operands, 1);"
+)
+
+(define_insn "*call_value_struct"
+  [(set (match_parallel 0 ""
+         [(expr_list (match_operand 3 "register_operand" "")
+                     (match_operand 4 "immediate_operand" ""))
+          (expr_list (match_operand 5 "register_operand" "")
+                     (match_operand 6 "immediate_operand" ""))])
+       (call (mem:SI (match_operand:SI 1 "csky_call_address_operand" "b,r,S"))
+             (match_operand 2 "" "")))
+       (clobber (reg:SI CSKY_LR_REGNUM))]
+  ""
+  "@
+    jsr\t%1
+    jsr\t%1
+    jbsr\t%1"
+  [(set_attr "length" "2,4,4")
+   (set_attr "type"   "call_jsr,call_jsr,call")]
+)
+
+(define_insn "*call_value_struct_pic"
+  [(set (match_parallel 0 ""
+         [(expr_list (match_operand 3 "register_operand"  "")
+                     (match_operand 4 "immediate_operand" ""))
+          (expr_list (match_operand 5 "register_operand"  "")
+                     (match_operand 6 "immediate_operand" ""))])
+       (call (mem:SI (match_operand:SI 1 "csky_unspec_operand" "X"))
+                     (match_operand    2 "" "")))
+   (clobber (reg:SI CSKY_LR_REGNUM))]
+  "flag_pic"
+  "* return csky_output_call (operands, 1);"
+)
+
+
+;; -------------------------------------------------------------
+;; prologue & epilogue
+;; -------------------------------------------------------------
+
+(define_expand "prologue"
+  [(clobber (const_int 0))]
+  ""
+  "
+  {
+    csky_expand_prologue ();
+    DONE;
+  }"
+)
+
+(define_expand "epilogue"
+  [(clobber (const_int 0))]
+  ""
+  "
+  {
+    csky_expand_epilogue ();
+    DONE;
+  }"
+)
+
+/* TODO: pushpop */
+;; Push multiple registers to the stack.  Registers are in parallel (use ...)
+;; expressions.  For simplicity, the first register is also in the unspec
+;; part.
+(define_insn "*push_multi"
+  [(match_parallel 2 "registers_push"
+    [(set (match_operand:BLK 0 "push_memory_operand" "")
+         (unspec:BLK [(match_operand:SI 1 "register_operand" "")]
+           UNSPEC_PUSHPOP_MULT))])]
+  ""
+  {
+    int num_saves = XVECLEN (operands[2], 0);
+    int i;
+    char pattern[100];
+
+    strcpy (pattern, \"push\\t%1\");
+
+    for (i = 1; i < num_saves; i++)
+      {
+       strcat (pattern, \", \");
+       strcat (pattern,
+               reg_names[REGNO (XEXP (XVECEXP (operands[2], 0, i), 0))]);
+      }
+
+    output_asm_insn (pattern, operands);
+
+    return \"\";
+  }
+  [(set (attr "length")
+       (symbol_ref "csky_compute_pushpop_length (operands)"))]
+)
+
+;; Pop (as used in epilogue RTL)
+;;
+(define_insn "*pop_multi"
+  [(match_parallel 2 "registers_pop"
+    [(return)
+     (set (match_operand:SI 1 "register_operand" "")
+         (unspec:SI [(match_operand:SI 0 "pop_memory_operand" "")]
+           UNSPEC_PUSHPOP_MULT))])]
+  ""
+  {
+    int num_saves = XVECLEN (operands[2], 0);
+    int i;
+    char pattern[100];
+
+    strcpy (pattern, \"pop\\t%1\");
+
+    for (i = 2; i < num_saves; i++)
+      {
+       strcat (pattern, \", \");
+       strcat (pattern,
+           reg_names[REGNO (XEXP (XVECEXP (operands[2], 0, i), 0))]);
+      }
+
+    output_asm_insn (pattern, operands);
+
+    return \"\";
+  }
+  [(set (attr "length")
+       (symbol_ref "csky_compute_pushpop_length (operands)"))]
+)
+
+
+;; -------------------------------------------------------------------------
+;; PIC related insns
+;; -------------------------------------------------------------------------
+
+(define_insn "prologue_get_pc"
+  [(set (reg:SI 28)
+       (match_operand:SI 0 "" "X"))]
+  "(GET_CODE (operands[0]) == UNSPEC)
+   && (XINT (operands[0], 1) == UNSPEC_PIC_SYMBOL_GOTPC_GRS)"
+  {
+    operands[0] = XVECEXP (operands[0], 0, 0);
+    output_asm_insn (\"grs\tgb, %0\", operands);
+    default_internal_label (asm_out_file, \"L\",
+                           CODE_LABEL_NUMBER (XEXP (operands[0], 0)));
+    return \"\";
+  }
+)
+
+(define_insn "*pic_got_pc"
+  [(set (match_operand:SI            0 "register_operand" "=r")
+       (unspec:SI [(match_operand:SI 1 "" "")] UNSPEC_PIC_SYMBOL_GOTPC))]
+  "flag_pic"
+  "lrw\t%0, %1@GOTPC"
+)
+
+(define_insn "*pic_symbol_gotoff"
+  [(set (match_operand:SI            0 "register_operand" "=r")
+       (unspec:SI [(match_operand:SI 1 "" "")] UNSPEC_PIC_SYMBOL_GOTOFF))]
+  "flag_pic"
+  "lrw\t%0, %1@GOTOFF"
+)
+
+(define_insn "*pic_symbol_got"
+  [(set (match_operand:SI            0 "register_operand" "=r")
+       (unspec:SI [(match_operand:SI 1 "" "")] UNSPEC_PIC_SYMBOL_GOT))]
+  "flag_pic"
+  "lrw\t%0, %1@GOT"
+)
+
+(define_insn "*pic_symbol_plt"
+  [(set (match_operand:SI            0 "register_operand" "=r")
+       (unspec:SI [(match_operand:SI 1 "" "")] UNSPEC_PIC_SYMBOL_PLT))]
+  "flag_pic"
+  "lrw\t%0, %1@PLT"
+)
+
+(define_insn "*pic_symbol_grs"
+  [(set (match_operand:SI            0 "register_operand" "=r")
+       (unspec:SI [(match_operand:SI 1 "" "")] UNSPEC_PIC_SYMBOL_GRS))]
+  "flag_pic"
+  "grs\t%0, %1"
+)
+
+(define_expand "builtin_setjmp_receiver"
+  [(label_ref (match_operand 0 "" ""))]
+  "flag_pic"
+  "{
+    rtx l1 = gen_label_rtx();
+    rtx grs_label = gen_rtx_LABEL_REF (SImode, l1);
+    rtx reg_gb = gen_rtx_REG (SImode, PIC_OFFSET_TABLE_REGNUM);
+    rtx reg_temp = gen_rtx_REG (SImode, 12);
+
+    rtx tmp0_unspec = gen_rtx_UNSPEC (Pmode,
+                                     gen_rtvec (1, grs_label),
+                                     UNSPEC_PIC_SYMBOL_GOTPC_GRS);
+    rtx tmp1_unspec = gen_rtx_UNSPEC (Pmode,
+                                     gen_rtvec (1, grs_label),
+                                     UNSPEC_PIC_SYMBOL_GOTPC);
+
+    emit_insn (gen_prologue_get_pc (tmp0_unspec));
+    emit_move_insn (reg_temp, tmp1_unspec);
+    emit_insn (gen_addsi3 (reg_gb, reg_gb, reg_temp));
+    emit_use (reg_gb);
+
+    DONE;
+  }"
+)
+
+;; -------------------------------------------------------------------------
+;; TLS related insns
+;; -------------------------------------------------------------------------
+
+
+;; UNSPEC_TLS can take either 2 or 3 operands.  Operand 0 is the symbol_ref,
+;; operand 1 is a CONST_INT identifying the TLS model, and the optional
+;; operand 3 is an UNSPEC_TLS_LABEL.
+;; The 3-operand case is for TLS_GD32, TLS_LDM32, and TLS_IE32.
+;; The 2-operand case is for TLS_LE32 and TLS_LDO32.
+
+;; Move PC-relative TLS label to reg.  This is used for the TLS_GD32
+;; and TLS_GD32 models (when setting up a call to tls_get_addr) and
+;; also TLS_IE32.
+
+(define_insn "*tls_pcrel_label"
+  [(set (match_operand:SI            0 "register_operand" "=r")
+       (unspec:SI [(match_operand:SI 1 "const_int_operand" "")]
+                  UNSPEC_TLS_LABEL))]
+  "TARGET_TLS"
+  "grs\t%0, .LTLS%1"
+  [(set_attr "length" "4")]
+)
+
+;; This pattern is used to load the TLS base for the same models as above.
+;; The embedded UNSPEC_TLS_LABEL only identifies the label to emit and
+;; doesn't generate a reference to it; that's handled by the *tls_pcrel_label
+;; pattern above.  The label offset needs to be added to the result stored
+;; in operand 0 by this insn.
+
+(define_insn "*tls_get_symbol_1"
+  [(set (match_operand:SI                     0 "register_operand" "=r")
+       (unspec:SI [(match_operand             1 "" "")
+                   (match_operand             2 "" "")
+                   (unspec:SI [(match_operand 3 "" "")] UNSPEC_TLS_LABEL)]
+                  UNSPEC_TLS))]
+  "TARGET_TLS"
+  {
+    default_internal_label (asm_out_file, \"LTLS\", INTVAL (operands[3]));
+    switch (INTVAL (operands[2]))
+      {
+      case TLS_GD32:
+       return \"lrw\t%0, %1@TLSGD32\";
+      case TLS_LDM32:
+       return \"lrw\t%0, %1@TLSLDM32\";
+      case TLS_IE32:
+       return \"lrw\t%0, %1@GOTTPOFF\";
+      default:
+       return \"\";
+      }
+  }
+)
+
+;; This pattern matches the two-operand form of UNSPEC_TLS.
+
+(define_insn "*tls_get_symbol_2"
+  [(set (match_operand:SI         0 "register_operand" "=r")
+       (unspec:SI [(match_operand 1 "" "")
+                   (match_operand 2 "" "")]
+                  UNSPEC_TLS))]
+  "TARGET_TLS"
+  {
+    switch (INTVAL (operands[2]))
+      {
+      case TLS_LE32:
+       return \"lrw\t%0, %1@TPOFF\";
+      case TLS_LDO32:
+       return \"lrw\t%0, %1@TLSLDO32\";
+      default:
+       return \"\";
+      }
+  }
+)
+
+
+;; -------------------------------------------------------------
+;; Misc insns
+;; -------------------------------------------------------------
+
+(define_insn "nop"
+  [(const_int 0)]
+  ""
+  "nop"
+  [(set_attr "length" "2")]
+)
+
+(define_insn "trap"
+  [(trap_if (const_int 1) (const_int 0))]
+  ""
+  "bkpt"
+  [(set (attr "length") (const_int 2))
+   (set_attr "type" "alu")]
+)
+
+
+;; -------------------------------------------------------------
+;; Special patterns for dealing with the constant pool
+;; -------------------------------------------------------------
+
+(define_insn "align_4"
+  [(unspec_volatile [(const_int 0)] VUNSPEC_ALIGN)]
+  ""
+  {
+    assemble_align(32);
+    return \"\";
+  }
+  [(set_attr "length" "0")]
+)
+
+(define_insn "csky_constpool_label"
+  [(unspec_volatile [(match_operand 0 "" "")] VUNSPEC_POOL_LABEL)]
+  ""
+  {
+    char tmp_label[15];
+    ASM_GENERATE_INTERNAL_LABEL (tmp_label, \"LCP\", INTVAL (operands[0]));
+    assemble_label (asm_out_file, tmp_label);
+    return \"\";
+  }
+  [(set_attr "length" "0")]
+)
+
+(define_insn "consttable_4"
+  [(unspec_volatile [(match_operand 0 "" "")] VUNSPEC_POOL_4)]
+  ""
+  {
+    if (CONST_DOUBLE_P (operands[0]))
+      assemble_real (*CONST_DOUBLE_REAL_VALUE (operands[0]),
+                    SFmode, BITS_PER_WORD);
+    else
+      {
+       assemble_integer (operands[0], 4, BITS_PER_WORD, 1);
+       mark_symbol_refs_as_used (operands[0]);
+      }
+    return \"\";
+  }
+  [(set_attr "length" "4")]
+)
+
+(define_insn "consttable_8"
+  [(unspec_volatile [(match_operand 0 "" "")] VUNSPEC_POOL_8)]
+  ""
+  {
+    if (CONST_DOUBLE_P (operands[0]))
+      assemble_real (*CONST_DOUBLE_REAL_VALUE (operands[0]),
+                    DFmode, BITS_PER_WORD);
+    else
+      assemble_integer (operands[0], 8, BITS_PER_WORD, 1);
+    return \"\";
+  }
+  [(set_attr "length" "8")]
+)
+
+;;FIXME record the deferred symbol_ref information with use insn
+(define_insn "*cskyv2_use_symbol_ref"
+  [(unspec_volatile [(match_operand 0 "" "")] VUNSPEC_SYMBOL_REF)]
+  ""
+  ""
+  [(set_attr "length" "0")]
+)
+
+
+;; ------------------------------------------------------------
+;; switch case optimize
+;; ------------------------------------------------------------
+
+(define_expand "casesi"
+  [(match_operand:SI 0 "register_operand" "")  ; index to jump on
+   (match_operand:SI 1 "const_int_operand" "") ; lower bound
+   (match_operand:SI 2 "const_int_operand" "") ; total range (max - min)
+   (match_operand:SI 3 "" "")                  ; table label
+   (match_operand:SI 4 "" "")]                 ; Out of range label (default:)
+  "TARGET_CASESI"
+  "
+  {
+    enum insn_code code;
+    if (operands[1] != const0_rtx)
+      {
+       rtx reg = gen_reg_rtx (SImode);
+       emit_insn (gen_subsi3 (reg,
+                              operands[0],
+                              GEN_INT (INTVAL (operands[1]))));
+       operands[0] = reg;
+      }
+
+    code = CODE_FOR_csky_casesi_internal;
+
+    if (!insn_data[(int) code].operand[1].predicate(operands[2], SImode))
+      operands[2] = force_reg (SImode,operands[2]);
+
+    emit_jump_insn (GEN_FCN ((int) code) (operands[0],operands[2],
+                   operands[3],operands[4]));
+    DONE;
+  }"
+)
+
+(define_expand "csky_casesi_internal"
+  [(match_operand:SI 0 "register_operand" "")
+   (match_operand:SI 1 "csky_literal_Uk_operand" "")
+   (match_operand    2 "" "")
+   (match_operand    3 "" "")]
+  ""
+  {
+    rtx reg0;
+    rtx test = gen_rtx_GTU (VOIDmode, operands[0], operands[1]);
+    emit_jump_insn (gen_cbranchsi4 (test, operands[0], operands[1],
+                                   operands[3]));
+    reg0 = gen_rtx_REG (SImode, 0);
+    emit_move_insn (reg0, operands[0]);
+    emit_jump_insn (gen_csky_casesi_dispatch (operands[2]));
+    DONE;
+  }
+)
+
+(define_insn "csky_casesi_dispatch"
+  [(parallel [(set (pc) (unspec [(reg:SI 0)
+                                (label_ref (match_operand 0 "" ""))]
+                               UNSPEC_CSKY_CASESI))
+             (clobber (reg:SI CSKY_LR_REGNUM))])]
+  ""
+  "*return csky_output_casesi (operands);"
+  [(set_attr "length" "4")]
+)
+
+;; ------------------------------------------------------------------------
+;; index insns
+;; ------------------------------------------------------------------------
+
+(define_insn "*cskyv2_indexsi_t"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "r")
+                         (const_int 4))
+                (match_operand:SI 2 "register_operand" "r")))]
+  "CSKY_ISA_FEATURE (E2)"
+  "ixw\t%0, %2, %1"
+)
+
+(define_insn "*cskyv2_indexhi_t"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "r")
+                         (const_int 2))
+                (match_operand:SI 2 "register_operand" "r")))]
+  "CSKY_ISA_FEATURE (E2)"
+  "ixh\t%0, %2, %1"
+)
+
+(define_insn "*cskyv2_indexdi_t"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "r")
+                         (const_int 8))
+                (match_operand:SI 2 "register_operand" "r")))]
+  "CSKY_ISA_FEATURE (2E3)"
+  "ixd\t%0, %2, %1"
+)
+
+;; ------------------------------------------------------------------------
+;; swap insns
+;; ------------------------------------------------------------------------
+
+(define_insn "bswapsi2"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (bswap:SI (match_operand:SI 1 "register_operand" "r")))]
+  "CSKY_ISA_FEATURE (E2)"
+  "revb\t%0, %1"
+)
diff --git a/gcc/config/csky/csky.opt b/gcc/config/csky/csky.opt
new file mode 100644 (file)
index 0000000..55d2659
--- /dev/null
@@ -0,0 +1,173 @@
+;; Command-line options for the C-SKY back end.
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+;; Contributed by C-SKY Microsystems and Mentor Graphics.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it under
+;; the terms of the GNU General Public License as published by the Free
+;; Software Foundation; either version 3, or (at your option) any later
+;; version.
+;;
+;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+;; WARRANTY; without even the implied warranty of MERCHANTABILITY or
+;; FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+;; for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+
+HeaderInclude
+config/csky/csky_opts.h
+
+;; Architecture/CPU options.
+;; Normal CPU and arch enums are loaded from csky_tables.opt.
+
+; For backward compatibility only.
+march=ck803s
+Target Report Var(flag_arch_ck803s) Undocumented
+
+march=
+Target RejectNegative ToLower Joined Enum(csky_arch) Var(csky_arch_option) Save
+Specify the target architecture.
+
+mcpu=
+Target RejectNegative ToLower Joined Enum(csky_processor_type) Var(csky_cpu_option) Init(TARGET_CPU_csky_none) Save
+Specify the target processor.
+
+;; Endianness options.
+
+mbig-endian
+Target RejectNegative Report Mask(BIG_ENDIAN)
+Generate big-endian code.
+
+EB
+Target RejectNegative Report Alias(mbig-endian) Undocumented
+
+mlittle-endian
+Target RejectNegative Report InverseMask(BIG_ENDIAN)
+Generate little-endian code.
+
+EL
+Target RejectNegative Report Alias(mlittle-endian) Undocumented
+
+;; Floating point options.  These affect code generation but not
+;; assembly.
+
+mhard-float
+Target Report RejectNegative Mask(HARD_FLOAT)
+Enable hardware floating-point instructions.
+
+msoft-float
+Target Report RejectNegative InverseMask(HARD_FLOAT)
+Use library calls to perform floating-point operations (default).
+
+mfpu=
+Target RejectNegative Joined Enum(csky_fpu) Var(csky_fpu_index) Init(TARGET_FPU_auto) Save
+Specify the target floating-point hardware/format.
+
+mdouble-float
+Target Report Var(TARGET_DOUBLE_FLOAT) Init(-1)
+Generate C-SKY FPU double float instructions (default for hard float).
+
+mfdivdu
+Target Report Var(TARGET_FDIVDU) Init(-1)
+Generate frecipd/fsqrtd/fdivd instructions (default for hard float).
+
+;; Instruction set extensions.  Most of these don't affect code
+;; generation, and are passed through to the assembler.
+;; There are builtin preprocessor defines for each of these.
+
+melrw
+Target Report Var(TARGET_ELRW) Init(-1)
+Enable the extended LRW instruction (default for CK801).
+
+mistack
+Target Report Mask(ISTACK)
+Enable interrupt stack instructions.
+
+mmp
+Target Report RejectNegative Mask(MP)
+Enable multiprocessor instructions.
+
+mcp
+Target Report RejectNegative Mask(CP)
+Enable coprocessor instructions.
+
+mcache
+Target Report RejectNegative Mask(CACHE)
+Enable cache prefetch instructions.
+
+msecurity
+Target Report RejectNegative Mask(SECURITY)
+Enable C-SKY SECURE instructions.
+
+mmac
+Target Report RejectNegative Alias(msecurity) Undocumented
+
+mtrust
+Target Report RejectNegative Mask(TRUST)
+Enable C-SKY TRUST instructions.
+
+mdsp
+Target Report RejectNegative Var(TARGET_DSP)
+Enable C-SKY DSP instructions.
+
+medsp
+Target Report RejectNegative Mask(EDSP)
+Enable C-SKY Enhanced DSP instructions.
+
+mvdsp
+Target Report RejectNegative Mask(VDSP)
+Enable C-SKY Vector DSP instructions.
+
+;; Code generation options not passed to the assembler.
+
+mdiv
+Target Report Var(TARGET_DIV) Init(-1)
+Generate divide instructions.
+
+msmart
+Target Report Var(TARGET_MINI_REGISTERS) Init(-1)
+Generate code for Smart Mode.
+
+mhigh-registers
+Target Report Var(TARGET_HIGH_REGISTERS) Init(-1)
+Enable use of R16-R31 (default).
+
+manchor
+Target Report Var(TARGET_ANCHOR)
+Generate code using global anchor symbol addresses.
+
+mpushpop
+Target Report Var(TARGET_PUSHPOP) Init(1)
+Generate push/pop instructions (default).
+
+mmultiple-stld
+Target Report Var(TARGET_MULTIPLE_STLD) Init(-1)
+Generate stm/ldm instructions (default).
+
+mstm
+Target Report Alias(mmultiple-stld) Undocumented
+
+mconstpool
+Target Report Var(TARGET_CONSTANT_POOL) Init(-1)
+Generate constant pools in the compiler instead of assembler.
+
+mstack-size
+Target Report Var(TARGET_STACK_SIZE) Init(0)
+Emit .stack_size directives.
+
+mccrt
+Target Report Var(TARGET_LIBCCRT) Init(0)
+Generate code for C-SKY compiler runtime instead of libgcc.
+
+mbranch-cost=
+Target Report Joined RejectNegative UInteger Var(csky_branch_cost) Init(1)
+Set the branch costs to roughly the specified number of instructions.
+
+msched-prolog
+Target Report Var(flag_sched_prolog) Init(0)
+Permit scheduling of function prologue and epilogue sequences.
diff --git a/gcc/config/csky/csky_cores.def b/gcc/config/csky/csky_cores.def
new file mode 100644 (file)
index 0000000..5159a07
--- /dev/null
@@ -0,0 +1,199 @@
+/* Architecture and core descriptions for the C-SKY back end.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   Contributed by C-SKY Microsystems and Mentor Graphics.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Before using #include to read this file, define a macro:
+
+      CSKY_ARCH(NAME, CORE, ARCH, ISA)
+
+   The NAME is the name of the architecture, represented as a string
+   constant.  The CORE is the identifier for a core representative of
+   this architecture.  ARCH is the architecture revision.  ISA is the
+   detailed architectural capabilities of the core.  */
+
+#ifdef CSKY_ARCH
+CSKY_ARCH ("ck801",  ck801,  CK801,
+          CSKY_ISA_FEAT (CSKY_ISA_CK801))
+CSKY_ARCH ("ck802",  ck802,  CK802,
+          CSKY_ISA_FEAT (CSKY_ISA_CK802))
+CSKY_ARCH ("ck803",  ck803,  CK803,
+          CSKY_ISA_FEAT (CSKY_ISA_CK803))
+CSKY_ARCH ("ck807",  ck807,  CK807,
+          CSKY_ISA_FEAT (CSKY_ISA_CK807) CSKY_ISA_FEAT (CSKY_ISA_DSP))
+CSKY_ARCH ("ck810",  ck810,  CK810,
+          CSKY_ISA_FEAT (CSKY_ISA_CK810) CSKY_ISA_FEAT (CSKY_ISA_DSP))
+#endif
+
+
+/* Before using #include to read this file, define a macro:
+
+      CSKY_CORE(CORE_NAME, INTERNAL_IDENT, TUNE_IDENT, ARCH, ISA)
+
+      The isa features of core will inherit the ARCH.
+
+   The CORE_NAME is the name of the core, represented as a string constant.
+   The INTERNAL_IDENT is the name of the core represented as an identifier.
+   This must be unique for each entry in this table.
+   The TUNE_IDENT is the name of the core for which scheduling decisions
+   should be made, represented as an identifier.
+   The ARCH is the architecture revision implemented by the chip.
+   The ISA is the detailed architectural capabilities of the core.  */
+
+#ifdef CSKY_CORE
+/* ck801 Architecture Processors */
+CSKY_CORE ("ck801",    ck801,   ck801,    CK801,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck801t",   ck801t,  ck801t,   CK801,
+          CSKY_ISA_FEAT_NONE)
+
+/* ck802 Architecture Processors */
+CSKY_CORE ("ck802",    ck802,   ck802,    CK802,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck802t",   ck802t,  ck802t,   CK802,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck802j",   ck802j,  ck802j,   CK802,
+          CSKY_ISA_FEAT (isa_bit_java))
+
+/* ck803 Architecture Processors */
+CSKY_CORE ("ck803",    ck803,   ck803,    CK803,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck803h",   ck803h,  ck803h,   CK803,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck803t",   ck803t,  ck803t,   CK803,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck803ht",  ck803ht,         ck803ht,  CK803,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck803f",   ck803f,  ck803f,   CK803,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck803fh",  ck803fh,         ck803fh,  CK803,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck803e",   ck803e,  ck803e,   CK803,
+          CSKY_ISA_FEAT (CSKY_ISA_DSP))
+CSKY_CORE ("ck803eh",  ck803eh,         ck803eh,  CK803,
+          CSKY_ISA_FEAT (CSKY_ISA_DSP))
+CSKY_CORE ("ck803et",  ck803et,         ck803et,  CK803,
+          CSKY_ISA_FEAT (CSKY_ISA_DSP))
+CSKY_CORE ("ck803eht", ck803eht, ck803eht, CK803,
+          CSKY_ISA_FEAT (CSKY_ISA_DSP))
+CSKY_CORE ("ck803ef",  ck803ef,         ck803ef,  CK803,
+          CSKY_ISA_FEAT (CSKY_ISA_DSP))
+CSKY_CORE ("ck803efh", ck803efh, ck803efh, CK803,
+          CSKY_ISA_FEAT (CSKY_ISA_DSP))
+CSKY_CORE ("ck803ft",  ck803ft,         ck803ft,  CK803,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck803eft", ck803eft, ck803eft, CK803,
+          CSKY_ISA_FEAT (CSKY_ISA_DSP))
+CSKY_CORE ("ck803efht", ck803efht, ck803efht, CK803,
+          CSKY_ISA_FEAT (CSKY_ISA_DSP))
+CSKY_CORE ("ck803r1",   ck803r1,    ck803r1,    CK803,
+          CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803hr1",  ck803hr1,   ck803hr1,   CK803,
+          CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803tr1",  ck803tr1,   ck803tr1,   CK803,
+          CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803htr1",         ck803htr1,  ck803htr1,  CK803,
+          CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803fr1",  ck803fr1,   ck803fr1,   CK803,
+          CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803fhr1",         ck803fhr1,  ck803fhr1,  CK803,
+          CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803er1",  ck803er1,   ck803er1,   CK803,
+          CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803ehr1",         ck803ehr1,  ck803ehr1,  CK803,
+          CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803etr1",         ck803etr1,  ck803etr1,  CK803,
+          CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803ehtr1", ck803ehtr1, ck803ehtr1, CK803,
+          CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803efr1",         ck803efr1,  ck803efr1,  CK803,
+          CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803efhr1", ck803efhr1, ck803efhr1, CK803,
+          CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803ftr1",         ck803ftr1,  ck803ftr1,  CK803,
+          CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803eftr1", ck803eftr1, ck803eftr1, CK803,
+          CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803efhtr1", ck803efhtr1, ck803efhtr1, CK803,
+          CSKY_ISA_FEAT (isa_bit_3E3r1))
+
+/* ck803s Architecture Processors */
+CSKY_CORE ("ck803s",   ck803s,  ck803s,   CK803,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck803st",  ck803st,         ck803st,  CK803,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck803se",  ck803se,         ck803se,  CK803,
+          CSKY_ISA_FEAT (CSKY_ISA_DSP))
+CSKY_CORE ("ck803sf",  ck803sf,         ck803sf,  CK803,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck803sef", ck803sef, ck803sef, CK803,
+          CSKY_ISA_FEAT (CSKY_ISA_DSP))
+CSKY_CORE ("ck803seft", ck803seft, ck803seft, CK803,
+          CSKY_ISA_FEAT (CSKY_ISA_DSP))
+
+/* ck807 Architecture Processors */
+CSKY_CORE ("ck807e",   ck807e,  ck807e,   CK807,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck807ef",  ck807ef,         ck807ef,  CK807,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck807",    ck807,   ck807,    CK807,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck807f",   ck807f,  ck807f,   CK807,
+          CSKY_ISA_FEAT_NONE)
+
+/* ck810 Architecture Processors */
+CSKY_CORE ("ck810e",   ck810e,  ck810e,   CK810,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck810et",  ck810et,         ck810et,  CK810,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck810ef",  ck810ef,         ck810ef,  CK810,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck810eft", ck810eft, ck810eft, CK810,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck810",    ck810,   ck810,    CK810,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck810v",   ck810v,  ck810v,   CK810,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck810f",   ck810f,  ck810f,   CK810,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck810t",   ck810t,  ck810t,   CK810,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck810fv",  ck810fv,         ck810fv,  CK810,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck810tv",  ck810tv,         ck810tv,  CK810,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck810ft",  ck810ff,         ck810ft,  CK810,
+          CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck810ftv", ck810ftv, ck810ftv, CK810,
+          CSKY_ISA_FEAT_NONE)
+#endif
+
+
+/* Before using #include to read this file, define a macro:
+
+      CSKY_FPU(NAME, CNAME, ISA)
+
+   NAME is the publicly visible option name.
+   CNAME is a C-compatible variable name substring.
+   ISA is the list of feature bits that this FPU provides.  */
+
+#ifdef CSKY_FPU
+CSKY_FPU ("fpv2_sf",   fpv2_sf,          CSKY_ISA_FEAT (CSKY_ISA_FPv2_SF))
+CSKY_FPU ("fpv2",      fpv2,     CSKY_ISA_FEAT (CSKY_ISA_FPv2))
+CSKY_FPU ("fpv2_divd", fpv2_divd, CSKY_ISA_FEAT (CSKY_ISA_FPv2_DIVD))
+#endif
diff --git a/gcc/config/csky/csky_genopt.sh b/gcc/config/csky/csky_genopt.sh
new file mode 100644 (file)
index 0000000..bf145a4
--- /dev/null
@@ -0,0 +1,97 @@
+#!/bin/sh
+# Generate csky_tables.opt from the lists in *.def.
+# Copyright (C) 2018 Free Software Foundation, Inc.
+# Contributed by C-SKY Microsystems and Mentor Graphics.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+cat <<EOF
+; -*- buffer-read-only: t -*-
+; Generated automatically by csky_genopt.sh from csky_cores.def.
+
+; Copyright (C) 2018 Free Software Foundation, Inc.
+;
+; This file is part of GCC.
+;
+; GCC is free software; you can redistribute it and/or modify it under
+; the terms of the GNU General Public License as published by the Free
+; Software Foundation; either version 3, or (at your option) any later
+; version.
+;
+; GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+; WARRANTY; without even the implied warranty of MERCHANTABILITY or
+; FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+; for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with GCC; see the file COPYING3.  If not see
+; <http://www.gnu.org/licenses/>.
+
+Enum
+Name(csky_processor_type) Type(enum csky_processor_type)
+Known CSKY CPUs (for use with the -mcpu= options):
+
+EOF
+
+awk -F'[(,     ]+' '/^CSKY_CORE/ {
+    name = $2
+    enum = $3
+    gsub("\"", "", name)
+    print "EnumValue"
+    print "Enum(csky_processor_type) String(" name ") Value( TARGET_CPU_" enum ")"
+    print ""
+}' $1/csky_cores.def
+
+cat <<EOF
+Enum
+Name(csky_arch) Type(int)
+Known CSKY architectures (for use with the -march= option):
+
+EOF
+
+awk -F'[(,     ]+' 'BEGIN {
+    value = 0
+}
+/^CSKY_ARCH/ {
+    name = $2
+    gsub("\"", "", name)
+    print "EnumValue"
+    print "Enum(csky_arch) String(" name ") Value(" value ")"
+    print ""
+    value++
+}' $1/csky_cores.def
+
+cat <<EOF
+Enum
+Name(csky_fpu) Type(enum csky_fpu_type)
+Known CSKY FPUs (for use with the -mfpu= option):
+
+EOF
+
+awk -F'[(,     ]+' '
+/^CSKY_FPU/ {
+    name = $2
+    enum = $3
+    gsub("\"", "", name)
+    print "EnumValue"
+    print "Enum(csky_fpu) String(" name ") Value(TARGET_FPU_" enum ")"
+    print ""
+}
+END {
+    print "EnumValue"
+    print "Enum(csky_fpu) String(auto) Value(TARGET_FPU_auto)"
+}' $1/csky_cores.def
diff --git a/gcc/config/csky/csky_insn_dsp.md b/gcc/config/csky/csky_insn_dsp.md
new file mode 100644 (file)
index 0000000..8b972d1
--- /dev/null
@@ -0,0 +1,95 @@
+;; C-SKY DSP instruction descriptions.
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+;; Contributed by C-SKY Microsystems and Mentor Graphics.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.  */
+
+;; ------------------------------------------------------------
+;; DSP insns
+;; ------------------------------------------------------------
+
+(define_insn "mulsidi3"
+  [(set (match_operand:DI                         0 "register_operand" "=y")
+       (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r"))
+                (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
+  "TARGET_DSP"
+  "muls\t%1, %2"
+)
+
+(define_insn "umulsidi3"
+  [(set (match_operand:DI                         0 "register_operand" "=y")
+       (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
+                (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
+  "TARGET_DSP"
+  "mulu\t%1, %2"
+)
+
+(define_insn "maddsidi4"
+  [(set (match_operand:DI                                  0 "register_operand" "=y")
+       (plus:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r"))
+                         (sign_extend:DI (match_operand:SI 2 "register_operand" "r")))
+                (match_operand:DI                          3 "register_operand" "0")))]
+  "TARGET_DSP"
+  "mulsa\t%1, %2"
+)
+
+(define_insn "umaddsidi4"
+  [(set (match_operand:DI                                  0 "register_operand" "=y")
+       (plus:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
+                         (zero_extend:DI (match_operand:SI 2 "register_operand" "r")))
+                (match_operand:DI                          3 "register_operand" "0")))]
+  "TARGET_DSP"
+  "mulua\t%1, %2"
+)
+
+(define_insn "msubsidi4"
+  [(set (match_operand:DI                                   0 "register_operand" "=y")
+       (minus:DI (match_operand:DI                          3 "register_operand" "0")
+                 (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r"))
+                          (sign_extend:DI (match_operand:SI 2 "register_operand" "r")))))]
+  "TARGET_DSP"
+  "mulss\t%1, %2"
+)
+
+(define_insn "umsubsidi4"
+  [(set (match_operand:DI                                   0 "register_operand" "=y")
+       (minus:DI (match_operand:DI                          3 "register_operand" "0")
+                 (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
+                          (zero_extend:DI (match_operand:SI 2 "register_operand" "r")))))]
+  "TARGET_DSP"
+  "mulus\t%1, %2"
+)
+
+(define_insn "*mulall_s16_0"
+  [(set (match_operand:SI 0 "register_operand"                  "=r")
+       (plus:SI (match_operand:SI 3 "register_operand"          " 0")
+                (mult:SI (match_operand:SI 1 "register_operand" " r")
+                         (match_operand:SI 2 "register_operand" " r"))))]
+  "CSKY_ISA_FEATURE (3E3r1)"
+  "mula.32.l\t%0, %1, %2"
+  [(set_attr "type" "alu")
+   (set_attr "length" "4")])
+
+(define_insn "*mulall_s16_1"
+  [(set (match_operand:SI 0 "register_operand"                  "=r")
+       (plus:SI (mult:SI (match_operand:SI 1 "register_operand" " r")
+                         (match_operand:SI 2 "register_operand" " r"))
+                (match_operand:SI 3 "register_operand"          " 0")))]
+  "CSKY_ISA_FEATURE (3E3r1)"
+  "mula.32.l\t%0, %1, %2"
+  [(set_attr "type" "alu")
+   (set_attr "length" "4")])
diff --git a/gcc/config/csky/csky_insn_fpu.md b/gcc/config/csky/csky_insn_fpu.md
new file mode 100644 (file)
index 0000000..d188ef2
--- /dev/null
@@ -0,0 +1,567 @@
+;; C-SKY FPU instruction descriptions.
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+;; Contributed by C-SKY Microsystems and Mentor Graphics.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.  */
+
+;; -------------------------------------------------------------------------
+;; Float Abs instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "abssf2"
+  [(set (match_operand:SF        0 "register_operand" "=v,r")
+       (abs:SF (match_operand:SF 1 "register_operand" "v, r")))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "@
+    fabss\t%0, %1
+    bclri\t%0, %1, 31")
+
+(define_insn "absdf2"
+  [(set (match_operand:DF        0 "register_operand" "=v")
+       (abs:DF (match_operand:DF 1 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "fabsd\t%0, %1")
+
+
+;; -------------------------------------------------------------------------
+;; Float Neg instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "negsf2"
+  [(set (match_operand:SF        0 "register_operand" "=v")
+       (neg:SF (match_operand:SF 1 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "fnegs\t%0, %1")
+
+(define_insn "negdf2"
+  [(set (match_operand:DF        0 "register_operand" "=v")
+       (neg:DF (match_operand:DF 1 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "fnegd\t%0, %1")
+
+
+;; -------------------------------------------------------------------------
+;; Float Sqrt instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "sqrtsf2"
+  [(set (match_operand:SF         0 "register_operand" "=v")
+       (sqrt:SF (match_operand:SF 1 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "fsqrts\t%0, %1")
+
+(define_insn "sqrtdf2"
+  [(set (match_operand:DF         0 "register_operand" "=v")
+       (sqrt:DF (match_operand:DF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_divd)"
+ "fsqrtd\t%0, %1")
+
+
+;; -------------------------------------------------------------------------
+;; Float Add instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "addsf3"
+  [(set (match_operand:SF         0 "register_operand" "=v")
+       (plus:SF (match_operand:SF 1 "register_operand" "v")
+                (match_operand:SF 2 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "fadds\t%0, %1, %2")
+
+(define_insn "adddf3"
+  [(set (match_operand:DF         0 "register_operand" "=v")
+       (plus:DF (match_operand:DF 1 "register_operand" "v")
+                (match_operand:DF 2 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "faddd\t%0, %1, %2")
+
+
+;; -------------------------------------------------------------------------
+;; Float Sub instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "subsf3"
+  [(set (match_operand:SF          0 "register_operand" "=v")
+       (minus:SF (match_operand:SF 1 "register_operand" "v")
+                 (match_operand:SF 2 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "fsubs\t%0, %1, %2")
+
+(define_insn "subdf3"
+  [(set (match_operand:DF          0 "register_operand" "=v")
+       (minus:DF (match_operand:DF 1 "register_operand" "v")
+                 (match_operand:DF 2 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "fsubd\t%0, %1, %2")
+
+
+;; -------------------------------------------------------------------------
+;; Float Mul instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "mulsf3"
+  [(set (match_operand:SF         0 "register_operand" "=v")
+       (mult:SF (match_operand:SF 1 "register_operand" "v")
+                (match_operand:SF 2 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "fmuls\t%0, %1, %2")
+
+(define_insn "muldf3"
+  [(set (match_operand:DF         0 "register_operand" "=v")
+       (mult:DF (match_operand:DF 1 "register_operand" "v")
+                (match_operand:DF 2 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "fmuld\t%0, %1, %2")
+
+(define_insn "*fpuv2_nmulsf3_1"
+  [(set (match_operand:SF                 0 "register_operand" "=v")
+       (mult:SF (neg:SF (match_operand:SF 1 "register_operand" "%v"))
+                (match_operand:SF         2 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "fnmuls\t%0, %1, %2")
+
+(define_insn "*fpuv2_nmulsf3_2"
+  [(set (match_operand:SF                 0 "register_operand" "=v")
+       (neg:SF (mult:SF (match_operand:SF 1 "register_operand" "v")
+                        (match_operand:SF 2 "register_operand" "v"))))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "fnmuls\t%0, %1, %2")
+
+(define_insn "*fpuv2_nmuldf3_1"
+  [(set (match_operand:DF                 0 "register_operand" "=v")
+       (mult:DF (neg:DF (match_operand:DF 1 "register_operand" "%v"))
+                (match_operand:DF         2 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fnmuld\t%0, %1, %2")
+
+(define_insn "*fpuv2_nmuldf3_2"
+  [(set (match_operand:DF                 0 "register_operand" "=v")
+       (neg:DF (mult:DF (match_operand:DF 1 "register_operand" "v")
+                        (match_operand:DF 2 "register_operand" "v"))))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "fnmuld\t%0, %1, %2")
+
+
+;; -------------------------------------------------------------------------
+;; Float Div instructions
+;; -------------------------------------------------------------------------
+
+(define_expand "divsf3"
+  [(set (match_operand:SF        0 "register_operand" "")
+       (div:SF (match_operand:SF 1 "csky_arith_float1_operand" "")
+               (match_operand:SF 2 "register_operand" "")))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "")
+
+(define_insn "*fpuv2_divsf3"
+  [(set (match_operand:SF        0 "register_operand" "=v")
+       (div:SF (match_operand:SF 1 "register_operand" "v")
+               (match_operand:SF 2 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "fdivs\t%0, %1, %2")
+
+(define_insn "*fpuv2_1_divsf3"
+  [(set (match_operand:SF        0 "register_operand"          "=v")
+       (div:SF (match_operand:SF 1 "csky_const_float1_operand" "i")
+               (match_operand:SF 2 "register_operand"          "v")))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "frecips\t%0, %2")
+
+
+(define_expand "divdf3"
+  [(set (match_operand:DF 0 "register_operand" "")
+       (div:DF (match_operand:DF 1 "csky_arith_float1_operand" "")
+               (match_operand:DF 2 "register_operand" "")))]
+  "CSKY_ISA_FEATURE (fpv2_divd)"
+  "")
+
+(define_insn "*fpuv2_divdf3"
+  [(set (match_operand:DF        0 "register_operand" "=v")
+       (div:DF (match_operand:DF 1 "register_operand" "v")
+               (match_operand:DF 2 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_divd)"
+  "fdivd\t%0, %1, %2")
+
+(define_insn "*fpuv2_1_divdf3"
+  [(set (match_operand:DF        0 "register_operand"          "=v")
+       (div:DF (match_operand:DF 1 "csky_const_float1_operand" "i")
+               (match_operand:DF 2 "register_operand"          "v")))]
+  "CSKY_ISA_FEATURE (fpv2_divd)"
+  "frecipd\t%0, %2")
+
+
+;; -------------------------------------------------------------------------
+;; Float add(sub) with mult instructions
+;; -------------------------------------------------------------------------
+
+;; vrz <= vrz + vrx * vry
+(define_insn "*fpuv2_fmacs"
+  [(set (match_operand:SF                  0 "register_operand" "=v")
+       (plus:SF (mult:SF (match_operand:SF 1 "register_operand" "v")
+                         (match_operand:SF 2 "register_operand" "v"))
+                (match_operand:SF          3 "register_operand" "0")))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "fmacs\t%0, %1, %2")
+
+(define_insn "*fpuv2_fmacd"
+  [(set (match_operand:DF                  0 "register_operand" "=v")
+       (plus:DF (mult:DF (match_operand:DF 1 "register_operand" "v")
+                         (match_operand:DF 2 "register_operand" "v"))
+                (match_operand:DF          3 "register_operand" "0")))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "fmacd\t%0, %1, %2")
+
+;; vrz <= vrz - vrx * vry
+(define_insn "*fpuv2_fnmacs"
+  [(set (match_operand:SF                   0 "register_operand" "=v")
+       (minus:SF (match_operand:SF          1 "register_operand" "0")
+                 (mult:SF (match_operand:SF 2 "register_operand" "v")
+                          (match_operand:SF 3 "register_operand" "v"))))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "fnmacs\t%0, %2, %3")
+
+(define_insn "*fpuv2_fnmacd"
+  [(set (match_operand:DF                   0 "register_operand" "=v")
+       (minus:DF (match_operand:DF          1 "register_operand" "0")
+                 (mult:DF (match_operand:DF 2 "register_operand" "v")
+                          (match_operand:DF 3 "register_operand" "v"))))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "fnmacd\t%0, %2, %3")
+
+;; vrz <= vrx * vry - vrz
+(define_insn "*fpuv2_fmscs"
+  [(set (match_operand:SF                   0 "register_operand" "=v")
+       (minus:SF (mult:SF (match_operand:SF 1 "register_operand" "v")
+                          (match_operand:SF 2 "register_operand" "v"))
+                 (match_operand:SF          3 "register_operand" "0")))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "fmscs\t%0, %1, %2")
+
+(define_insn "*fpuv2_fmscd"
+  [(set (match_operand:DF 0 "register_operand" "=v")
+       (minus:DF (mult:DF (match_operand:DF 1 "register_operand" "v")
+                          (match_operand:DF 2 "register_operand" "v"))
+                 (match_operand:DF 3 "register_operand" "0")))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "fmscd\t%0, %1, %2")
+
+;; vrz = - (vrz + vrx * vry)
+(define_insn "*fpuv2_fnmscs_1"
+  [(set (match_operand:SF                           0 "register_operand" "=v")
+       (minus:SF (mult:SF (neg:SF (match_operand:SF 1 "register_operand" "%v"))
+                          (match_operand:SF         2 "register_operand" "v"))
+                 (match_operand:SF                  3 "register_operand" "0")))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "fnmscs\t%0, %1, %2")
+
+(define_insn "*fpuv2_fnmscs_2"
+  [(set (match_operand:SF                          0 "register_operand" "=v")
+       (neg:SF (plus:SF (mult:SF (match_operand:SF 1 "register_operand" "v")
+                                 (match_operand:SF 2 "register_operand" "v"))
+                        (match_operand:SF          3 "register_operand" "0"))))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "fnmscs\t%0, %1, %2")
+
+(define_insn "*fpuv2_fnmscd_1"
+  [(set (match_operand:DF 0 "register_operand" "=v")
+       (minus:DF (mult:DF (neg:DF (match_operand:DF 1 "register_operand" "%v"))
+                          (match_operand:DF 2 "register_operand" "v"))
+                 (match_operand:DF 3 "register_operand" "0")))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "fnmscd\t%0, %1, %2")
+
+(define_insn "*fpuv2_fnmscd_2"
+  [(set (match_operand:DF 0 "register_operand" "=v")
+       (neg:DF (plus:DF (mult:DF (match_operand:DF 1 "register_operand" "v")
+                                 (match_operand:DF 2 "register_operand" "v"))
+                        (match_operand:DF 3 "register_operand" "0"))))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "fnmscd\t%0, %1, %2")
+
+
+;; -------------------------------------------------------------------------
+;; Float compare instructions
+;; -------------------------------------------------------------------------
+
+(define_expand "cbranchsf4"
+  [(set (pc) (if_then_else (match_operator 0 "csky_float_comparison_operator"
+                            [(match_operand:SF 1 "register_operand")
+                             (match_operand:SF 2 "csky_compare_operand_float")])
+                          (label_ref (match_operand 3 ""))
+                          (pc)))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "
+  {
+    enum rtx_code code = GET_CODE (operands[0]);
+    bool invert = csky_emit_compare_float (code, operands[1], operands[2]);
+
+    if (invert)
+      emit_jump_insn (gen_csky_jbf (operands[3]));
+    else
+      emit_jump_insn (gen_csky_jbt (operands[3]));
+
+    DONE;
+  }")
+
+(define_insn "*fpuv2_unordered"
+  [(set (reg:CC 33) (unordered:CC (match_operand:SF 0 "register_operand" "v")
+                                 (match_operand:SF 1 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "fcmpuos\t%0, %1")
+
+(define_insn "*fpuv2_unordered_zero"
+  [(set (reg:CC 33) (unordered:CC (match_operand:SF 0 "register_operand" "v")
+                                 (match_operand:SF 1 "csky_const_float0_operand" "i")))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "fcmpuos\t%0, %0")
+
+(define_insn "*fpuv2_ne"
+  [(set (reg:CC 33) (ne:CC (match_operand:SF 0 "register_operand" "v")
+                          (match_operand:SF 1 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "fcmpnes\t%0, %1")
+
+(define_insn "*fpuv2_gt"
+  [(set (reg:CC 33) (gt:CC (match_operand:SF 0 "register_operand" "v")
+                          (match_operand:SF 1 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "fcmplts\t%1, %0")
+
+(define_insn "*fpuv2_ge"
+  [(set (reg:CC 33) (ge:CC (match_operand:SF 0 "register_operand" "v")
+                          (match_operand:SF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fcmphss\t%0, %1")
+
+(define_insn "*fpuv2_lt"
+  [(set (reg:CC 33) (lt:CC (match_operand:SF 0 "register_operand" "v")
+                          (match_operand:SF 1 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "fcmplts\t%0, %1")
+
+(define_insn "*fpuv2_le"
+  [(set (reg:CC 33) (le:CC (match_operand:SF 0 "register_operand" "v")
+                          (match_operand:SF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fcmphss\t%1, %0")
+
+(define_insn "*fpuv2_gez"
+  [(set (reg:CC 33) (ge:CC (match_operand:SF 0 "register_operand"         "v")
+                          (match_operand:SF 1 "csky_const_float0_operand" "i")))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "fcmpzhss\t%0")
+
+(define_insn "*fpuv2_nez"
+  [(set (reg:CC 33) (ne:CC (match_operand:SF 0 "register_operand"         "v")
+                          (match_operand:SF 1 "csky_const_float0_operand" "i")))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "fcmpznes\t%0")
+
+
+(define_expand "cbranchdf4"
+  [(set (pc) (if_then_else (match_operator 0 "csky_float_comparison_operator"
+                            [(match_operand:DF 1 "register_operand")
+                             (match_operand:DF 2 "csky_compare_operand_float")])
+                          (label_ref (match_operand 3 ""))
+                          (pc)))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "
+  {
+    enum rtx_code code = GET_CODE (operands[0]);
+    bool invert = csky_emit_compare_float (code, operands[1], operands[2]);
+
+    if (invert)
+      emit_jump_insn (gen_csky_jbf (operands[3]));
+    else
+      emit_jump_insn (gen_csky_jbt (operands[3]));
+
+    DONE;
+}")
+
+(define_insn "*fpuv2_dunordered"
+  [(set (reg:CC 33) (unordered:CC (match_operand:DF 0 "register_operand" "v")
+                                 (match_operand:DF 1 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "fcmpuod\t%0, %1")
+
+(define_insn "*fpuv2_dunordered_zero"
+  [(set (reg:CC 33) (unordered:CC (match_operand:DF 0 "register_operand" "v")
+                                 (match_operand:DF 1 "csky_const_float0_operand" "i")))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "fcmpuod\t%0, %0")
+
+(define_insn "*fpuv2_dne"
+  [(set (reg:CC 33) (ne:CC (match_operand:DF 0 "register_operand" "v")
+                          (match_operand:DF 1 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "fcmpned\t%0, %1")
+
+(define_insn "*fpuv2_dgt"
+  [(set (reg:CC 33) (gt:CC (match_operand:DF 0 "register_operand" "v")
+                          (match_operand:DF 1 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "fcmpltd\t%1, %0")
+
+(define_insn "*fpuv2_dge"
+  [(set (reg:CC 33) (ge:CC (match_operand:DF 0 "register_operand" "v")
+                          (match_operand:DF 1 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "fcmphsd\t%0, %1")
+
+(define_insn "*fpuv2_dlt"
+  [(set (reg:CC 33) (lt:CC (match_operand:DF 0 "register_operand" "v")
+                          (match_operand:DF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fcmpltd\t%0, %1")
+
+(define_insn "*fpuv2_dle"
+  [(set (reg:CC 33) (le:CC (match_operand:DF 0 "register_operand" "v")
+                          (match_operand:DF 1 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "fcmphsd\t%1, %0")
+
+(define_insn "*fpuv2_dgez"
+  [(set (reg:CC 33) (ge:CC (match_operand:DF 0 "register_operand"         "v")
+                          (match_operand:DF 1 "csky_const_float0_operand" "i")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fcmpzhsd\t%0")
+
+(define_insn "*fpuv2_dnez"
+  [(set (reg:CC 33) (ne:CC (match_operand:DF 0 "register_operand"         "v")
+                          (match_operand:DF 1 "csky_const_float0_operand" "i")))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "fcmpzned\t%0")
+
+
+;; -------------------------------------------------------------------------
+;; Float convert instructions
+;; -------------------------------------------------------------------------
+
+;; DF <- SF
+(define_insn "extendsfdf2"
+  [(set (match_operand:DF                 0 "register_operand" "=v")
+       (float_extend:DF (match_operand:SF 1 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "fstod\t%0, %1")
+
+;; SF <- DF
+(define_insn "truncdfsf2"
+  [(set (match_operand:SF                   0 "register_operand" "=v")
+       (float_truncate:SF (match_operand:DF 1 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "fdtos\t%0, %1")
+
+;; SF <- SI
+(define_insn "floatsisf2"
+  [(set (match_operand:SF          0 "register_operand" "=v")
+       (float:SF (match_operand:SI 1 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "fsitos\t%0, %1")
+
+;; DF <- SI
+(define_insn "floatsidf2"
+  [(set (match_operand:DF          0 "register_operand" "=v")
+       (float:DF (match_operand:SI 1 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "fsitod\t%0, %1")
+
+;; SF <- unsigned SI
+(define_insn "floatunssisf2"
+  [(set (match_operand:SF                   0 "register_operand" "=v")
+       (unsigned_float:SF (match_operand:SI 1 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "fuitos\t%0, %1")
+
+;; DF <- unsigned SI
+(define_insn "floatunssidf2"
+  [(set (match_operand:DF                   0 "register_operand" "=v")
+       (unsigned_float:DF (match_operand:SI 1 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "fuitod\t%0, %1")
+
+;; SI <- SF
+(define_insn "fix_truncsfsi2"
+  [(set (match_operand:SI        0 "register_operand" "=v")
+       (fix:SI (match_operand:SF 1 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "fstosi.rz\t%0, %1")
+
+;; SI <- DF
+(define_insn "fix_truncdfsi2"
+  [(set (match_operand:SI        0 "register_operand" "=v")
+       (fix:SI (match_operand:DF 1 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "fdtosi.rz\t%0, %1")
+
+;; unsigned SI <- SF
+(define_insn "fixuns_truncsfsi2"
+  [(set (match_operand:SI                 0 "register_operand" "=v")
+       (unsigned_fix:SI (match_operand:SF 1 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "fstoui.rz\t%0, %1")
+
+;; unsigned SI <- DF
+(define_insn "fixuns_truncdfsi2"
+  [(set (match_operand:SI                 0 "register_operand" "=v")
+       (unsigned_fix:SI (match_operand:DF 1 "register_operand" "v")))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "fdtoui.rz\t%0, %1")
+
+
+;; -------------------------------------------------------------------------
+;; Float mov instructions
+;; -------------------------------------------------------------------------
+
+;; Note:  movsf and movdf patterns are in csky.md.
+
+;; cstore SF
+(define_expand "cstoresf4"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (match_operator   1 "ordered_comparison_operator"
+         [(match_operand:SF 2 "register_operand" "")
+          (match_operand:SF 3 "csky_compare_operand_float" "")]))]
+  "CSKY_ISA_FEATURE (fpv2_sf)"
+  "
+  {
+    bool invert = csky_emit_compare_float (GET_CODE (operands[1]),
+                                          operands[2], operands[3]);
+    if (invert)
+      emit_insn (gen_mvcv (operands[0]));
+    else
+      emit_insn (gen_mvc (operands[0]));
+    DONE;
+  }"
+)
+
+;; cstore DF
+(define_expand "cstoredf4"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (match_operator 1 "ordered_comparison_operator"
+         [(match_operand:DF 2 "register_operand" "")
+          (match_operand:DF 3 "csky_compare_operand_float" "")]))]
+  "CSKY_ISA_FEATURE (fpv2_df)"
+  "
+  {
+    bool invert = csky_emit_compare_float (GET_CODE (operands[1]),
+                                          operands[2], operands[3]);
+    if (invert)
+      emit_insn (gen_mvcv (operands[0]));
+    else
+      emit_insn (gen_mvc (operands[0]));
+    DONE;
+  }"
+)
diff --git a/gcc/config/csky/csky_isa.def b/gcc/config/csky/csky_isa.def
new file mode 100644 (file)
index 0000000..d99940e
--- /dev/null
@@ -0,0 +1,59 @@
+/* ISA feature descriptions for the C-SKY back end.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   Contributed by C-SKY Microsystems and Mentor Graphics.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Before using #include to read this file, define a macro:
+      CSKY_ISA(CNAME, DESCRIPTION)
+   */
+
+/* Common insns */
+CSKY_ISA (E1,   "Extended insns for arch ck801  from base")
+CSKY_ISA (E2,   "Extended insns for arch ck802  from base")
+CSKY_ISA (2E3,  "Extended insns for arch ck803  from ck802")
+CSKY_ISA (3E3r1, "Extended insns for cpu ck803n from ck803")
+CSKY_ISA (3E7,  "Extended insns for arch ck807  from ck803")
+CSKY_ISA (7E10,         "Extended insns for arch ck810  from ck807")
+
+/* Special insns */
+CSKY_ISA (div,   "divide insns")
+
+/* Extended insns */
+CSKY_ISA (dsp,  "Extended insns for DSP")
+CSKY_ISA (java,         "Extended insns for Java")
+
+CSKY_ISA (fpv2_sf,    "Single precision operations supported")
+CSKY_ISA (fpv2_df,    "Double precision operations supported")
+CSKY_ISA (fpv2_divd,  "Double precision div operations supported")
+
+/* Specific insns mode */
+#ifdef CSKY_ISA_MACRO
+#define CSKY_ISA_CK801     CSKY_ISA_FEATURE_GET (E1)
+#define CSKY_ISA_CK802     CSKY_ISA_FEATURE_GET (E2)
+#define CSKY_ISA_CK803     CSKY_ISA_CK802, CSKY_ISA_FEATURE_GET (2E3), \
+                           CSKY_ISA_FEATURE_GET (div)
+#define CSKY_ISA_CK803R1    CSKY_ISA_CK803, CSKY_ISA_FEATURE_GET (3E3r1)
+#define CSKY_ISA_CK807     CSKY_ISA_CK803, CSKY_ISA_FEATURE_GET (3E7)
+#define CSKY_ISA_CK810     CSKY_ISA_CK807, CSKY_ISA_FEATURE_GET (7E10)
+
+#define CSKY_ISA_DSP       CSKY_ISA_FEATURE_GET (dsp)
+
+#define CSKY_ISA_FPv2_SF    CSKY_ISA_FEATURE_GET (fpv2_sf)
+#define CSKY_ISA_FPv2      CSKY_ISA_FPv2_SF, CSKY_ISA_FEATURE_GET (fpv2_df)
+#define CSKY_ISA_FPv2_DIVD  CSKY_ISA_FPv2, CSKY_ISA_FEATURE_GET (fpv2_divd)
+#endif
diff --git a/gcc/config/csky/csky_isa.h b/gcc/config/csky/csky_isa.h
new file mode 100644 (file)
index 0000000..24578d7
--- /dev/null
@@ -0,0 +1,47 @@
+/* ISA feature enumerations for C-SKY targets.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   Contributed by C-SKY Microsystems and Mentor Graphics.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_CSKY_ISA_FEATURE_H
+#define GCC_CSKY_ISA_FEATURE_H
+
+
+#ifndef CSKY_ISA_MACRO
+#define CSKY_ISA_MACRO
+#endif
+
+#define CSKY_ISA_FEATURE_DEFINE(x)  isa_bit_ ## x
+#define CSKY_ISA_FEATURE_GET(x)            CSKY_ISA_FEATURE_DEFINE (x)
+
+enum csky_isa_feature
+  {
+    CSKY_ISA_FEATURE_DEFINE (none),
+#undef CSKY_ISA
+#define CSKY_ISA(IDENT, DESC) \
+    CSKY_ISA_FEATURE_DEFINE (IDENT),
+#include "csky_isa.def"
+#undef CSKY_ISA
+    CSKY_ISA_FEATURE_DEFINE (max)
+  };
+
+#define CSKY_ISA_FEAT(x) x,
+#define CSKY_ISA_FEAT_NONE CSKY_ISA_FEAT (isa_bit_none)
+
+
+#endif /* GCC_CSKY_ISA_FEATURE_H */
diff --git a/gcc/config/csky/csky_opts.h b/gcc/config/csky/csky_opts.h
new file mode 100644 (file)
index 0000000..f206537
--- /dev/null
@@ -0,0 +1,63 @@
+/* Processor and arch enumerations for C-SKY targets.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   Contributed by C-SKY Microsystems and Mentor Graphics.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+
+#ifndef CSKY_OPTS_H
+#define CSKY_OPTS_H
+
+
+/* The various CSKY cores.  */
+enum csky_processor_type
+{
+#undef CSKY_CORE
+#define CSKY_CORE(NAME, INTERNAL_IDENT, IDENT, ARCH, ISA) \
+  TARGET_CPU_##INTERNAL_IDENT,
+#include "csky_cores.def"
+#undef CSKY_CORE
+  /* Used to indicate that no processor has been specified.  */
+  TARGET_CPU_csky_none
+};
+#define CSKY_TARGET_CORE_GET(name) TARGET_CPU_ ## name
+
+/* The various CSKY architectures.  */
+enum csky_base_architecture
+{
+#undef CSKY_ARCH
+#define CSKY_ARCH(NAME, CORE_IDENT, ARCH, ISA) \
+  CSKY_BASE_ARCH_##ARCH,
+#include "csky_cores.def"
+#undef CSKY_ARCH
+  CSKY_BASE_ARCH_NONE
+};
+#define CSKY_TARGET_ARCH_GET(name) CSKY_BASE_ARCH_ ## name
+
+/* The various CSKY FPUs.  */
+enum csky_fpu_type
+{
+#undef CSKY_FPU
+#define CSKY_FPU(NAME, CNAME, ISA) TARGET_FPU_##CNAME,
+#include "csky_cores.def"
+  TARGET_FPU_auto
+#undef CSKY_FPU
+};
+#define CSKY_TARGET_FPU_GET(name) TARGET_FPU_ ## name
+
+
+#endif /* CSKY_OPTS_H */
diff --git a/gcc/config/csky/csky_pipeline_ck801.md b/gcc/config/csky/csky_pipeline_ck801.md
new file mode 100644 (file)
index 0000000..00fc465
--- /dev/null
@@ -0,0 +1,54 @@
+;; Scheduler information for C-SKY CK801 processors.
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+;; Contributed by C-SKY Microsystems and Mentor Graphics.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.  */
+
+;; This is just a placeholder for a more accurate pipeline
+;; description for CK801.
+
+(define_automaton "ck801")
+
+(define_cpu_unit "ck801_ex1" "ck801")
+(define_cpu_unit "ck801_exit" "ck801")
+
+(define_insn_reservation "ck801_generic" 1
+  (and (match_test "CSKY_TARGET_ARCH (CK801)")
+       (eq_attr "type" "alu,cmp,branch,cbranch,addsub,alu_ix,branch_jmp,call_jsr,call"))
+  "ck801_ex1+ck801_exit")
+
+(define_insn_reservation "ck801_load" 1
+  (and (match_test "CSKY_TARGET_ARCH (CK801)")
+       (and (eq_attr "type" "load")
+           (match_test "!csky_minipool_load_p (insn)")))
+  "ck801_ex1+ck801_exit")
+
+(define_insn_reservation "ck801_pool" 1
+  (and (match_test "CSKY_TARGET_ARCH (CK801)")
+       (and (eq_attr "type" "load")
+           (match_test "csky_minipool_load_p (insn)")))
+  "ck801_ex1+ck801_exit")
+
+(define_insn_reservation "ck801_store" 1
+  (and (match_test "CSKY_TARGET_ARCH (CK801)")
+       (eq_attr "type" "store"))
+  "ck801_ex1+ck801_exit")
+
+;; Switching between constant pool loads and loads/stores in the data section
+;; carries an extra penalty.
+(define_bypass 2 "ck801_load,ck801_store" "ck801_pool")
+(define_bypass 2 "ck801_pool" "ck801_load,ck801_store")
diff --git a/gcc/config/csky/csky_pipeline_ck802.md b/gcc/config/csky/csky_pipeline_ck802.md
new file mode 100644 (file)
index 0000000..f185d8c
--- /dev/null
@@ -0,0 +1,77 @@
+;; Instruction scheduling information for C-SKY CK802 processors.
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+;; Contributed by C-SKY Microsystems and Mentor Graphics.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.  */
+
+(define_automaton "csky_ck802")
+
+(define_cpu_unit "csky_ck802_ex" "csky_ck802")
+(define_cpu_unit "csky_ck802_wb" "csky_ck802")
+
+(define_insn_reservation "ck802_alu" 2
+  (and (match_test "CSKY_TARGET_ARCH (CK802)")
+       (eq_attr "type" "alu"))
+  "csky_ck802_ex, csky_ck802_wb")
+
+(define_insn_reservation "ck802_branch" 2
+  (and (match_test "CSKY_TARGET_ARCH (CK802)")
+       (eq_attr "type" "branch, branch_jmp"))
+  "csky_ck802_ex, csky_ck802_wb")
+
+(define_insn_reservation "ck802_cmp" 2
+  (and (match_test "CSKY_TARGET_ARCH (CK802)")
+       (eq_attr "type" "cmp"))
+  "csky_ck802_ex, csky_ck802_wb")
+
+(define_insn_reservation "ck802_cbranch" 2
+  (and (match_test "CSKY_TARGET_ARCH (CK802)")
+       (eq_attr "type" "cbranch"))
+  "csky_ck802_ex, csky_ck802_wb")
+
+(define_insn_reservation "ck802_call" 2
+  (and (match_test "CSKY_TARGET_ARCH (CK802)")
+       (eq_attr "type" "call, call_jsr"))
+  "csky_ck802_ex, csky_ck802_wb")
+
+(define_insn_reservation "ck802_load" 2
+  (and (match_test "CSKY_TARGET_ARCH (CK802)")
+       (and (eq_attr "type" "load")
+            (match_test "!csky_minipool_load_p (insn)")))
+  "csky_ck802_ex, csky_ck802_wb")
+
+(define_insn_reservation "ck802_pool" 2
+  (and (match_test "CSKY_TARGET_ARCH (CK802)")
+       (and (eq_attr "type" "load")
+           (match_test "csky_minipool_load_p (insn)")))
+  "csky_ck802_ex, csky_ck802_wb")
+
+(define_insn_reservation "ck802_store" 2
+  (and (match_test "CSKY_TARGET_ARCH (CK802)")
+       (eq_attr "type" "store"))
+  "csky_ck802_ex, csky_ck802_wb")
+
+;; Switching between constant pool loads and loads/stores in the data section
+;; carries an extra penalty.
+(define_bypass 3 "ck802_load,ck802_store" "ck802_pool")
+(define_bypass 3 "ck802_pool" "ck802_load,ck802_store")
+
+(define_bypass 1 "*" "ck802_alu")
+
+(define_bypass 1 "*" "ck802_branch")
+
+(define_bypass 2 "ck802_cmp" "ck802_cbranch")
diff --git a/gcc/config/csky/csky_pipeline_ck803.md b/gcc/config/csky/csky_pipeline_ck803.md
new file mode 100644 (file)
index 0000000..f140cf6
--- /dev/null
@@ -0,0 +1,64 @@
+;; Scheduler information for C-SKY CK803 processors.
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+;; Contributed by C-SKY Microsystems and Mentor Graphics.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.  */
+
+(define_automaton "ck803")
+
+(define_cpu_unit "ck803_ex1" "ck803")
+(define_cpu_unit "ck803_exit" "ck803")
+
+(define_insn_reservation "ck803_3cycle" 1
+  (and (match_test "CSKY_TARGET_ARCH (CK803)")
+       (eq_attr "type" "alu,cmp,branch,branch_jmp,call_jsr,call"))
+  "ck803_ex1+ck803_exit")
+
+(define_insn_reservation "ck803_alu1" 1
+  (and (match_test "CSKY_TARGET_ARCH (CK803)")
+       (eq_attr "type" "addsub,alu_ix"))
+  "ck803_ex1+ck803_exit")
+
+(define_insn_reservation "ck803_cbranch" 1
+  (and (match_test "CSKY_TARGET_ARCH (CK803)")
+       (eq_attr "type" "cbranch"))
+  "ck803_ex1+ck803_exit")
+
+(define_insn_reservation "ck803_load" 1
+  (and (match_test "CSKY_TARGET_ARCH (CK803)")
+       (and (eq_attr "type" "load")
+           (match_test "!csky_minipool_load_p (insn)")))
+  "ck803_ex1+ck803_exit")
+
+(define_insn_reservation "ck803_pool" 1
+  (and (match_test "CSKY_TARGET_ARCH (CK803)")
+       (and (eq_attr "type" "load")
+           (match_test "csky_minipool_load_p (insn)")))
+  "ck803_ex1+ck803_exit")
+
+(define_insn_reservation "ck803_store" 1
+  (and (match_test "CSKY_TARGET_ARCH (CK803)")
+       (eq_attr "type" "store"))
+  "ck803_ex1+ck803_exit")
+
+;; Switching between constant pool loads and loads/stores in the data section
+;; carries an extra penalty.
+(define_bypass 2 "ck803_load,ck803_store" "ck803_pool")
+(define_bypass 2 "ck803_pool" "ck803_load,ck803_store")
+
+(define_bypass 2 "ck803_3cycle,ck803_cbranch,ck803_load,ck803_store,ck803_pool"
+                "ck803_cbranch")
diff --git a/gcc/config/csky/csky_pipeline_ck810.md b/gcc/config/csky/csky_pipeline_ck810.md
new file mode 100644 (file)
index 0000000..aaba00b
--- /dev/null
@@ -0,0 +1,34 @@
+;; Instruction scheduling information for C-SKY CK810 processors.
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+;; Contributed by C-SKY Microsystems and Mentor Graphics.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.  */
+
+
+;;-------------------------------------------------------------
+;; Pipeline descriptions for ck810
+;;-------------------------------------------------------------
+
+(define_attr "cycle" "1,2,not_used_yet"
+    (const_string "1"))
+(define_automaton "cskyv2_ck810")
+(define_cpu_unit "pipeline_alu0" "cskyv2_ck810")
+(define_insn_reservation "alu_one_cycle" 1
+    (and (eq_attr "cycle" "1")
+        (not (ior (match_test "CSKY_TARGET_ARCH (CK803)")
+                  (match_test "CSKY_TARGET_ARCH (CK802)"))))
+    "pipeline_alu0")
diff --git a/gcc/config/csky/csky_tables.opt b/gcc/config/csky/csky_tables.opt
new file mode 100644 (file)
index 0000000..ae3438d
--- /dev/null
@@ -0,0 +1,230 @@
+; -*- buffer-read-only: t -*-
+; Generated automatically by csky_genopt.sh from csky_cores.def.
+
+; Copyright (C) 2018 Free Software Foundation, Inc.
+;
+; This file is part of GCC.
+;
+; GCC is free software; you can redistribute it and/or modify it under
+; the terms of the GNU General Public License as published by the Free
+; Software Foundation; either version 3, or (at your option) any later
+; version.
+;
+; GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+; WARRANTY; without even the implied warranty of MERCHANTABILITY or
+; FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+; for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with GCC; see the file COPYING3.  If not see
+; <http://www.gnu.org/licenses/>.
+
+Enum
+Name(csky_processor_type) Type(enum csky_processor_type)
+Known CSKY CPUs (for use with the -mcpu= options):
+
+EnumValue
+Enum(csky_processor_type) String(ck801) Value( TARGET_CPU_ck801)
+
+EnumValue
+Enum(csky_processor_type) String(ck801t) Value( TARGET_CPU_ck801t)
+
+EnumValue
+Enum(csky_processor_type) String(ck802) Value( TARGET_CPU_ck802)
+
+EnumValue
+Enum(csky_processor_type) String(ck802t) Value( TARGET_CPU_ck802t)
+
+EnumValue
+Enum(csky_processor_type) String(ck802j) Value( TARGET_CPU_ck802j)
+
+EnumValue
+Enum(csky_processor_type) String(ck803) Value( TARGET_CPU_ck803)
+
+EnumValue
+Enum(csky_processor_type) String(ck803h) Value( TARGET_CPU_ck803h)
+
+EnumValue
+Enum(csky_processor_type) String(ck803t) Value( TARGET_CPU_ck803t)
+
+EnumValue
+Enum(csky_processor_type) String(ck803ht) Value( TARGET_CPU_ck803ht)
+
+EnumValue
+Enum(csky_processor_type) String(ck803f) Value( TARGET_CPU_ck803f)
+
+EnumValue
+Enum(csky_processor_type) String(ck803fh) Value( TARGET_CPU_ck803fh)
+
+EnumValue
+Enum(csky_processor_type) String(ck803e) Value( TARGET_CPU_ck803e)
+
+EnumValue
+Enum(csky_processor_type) String(ck803eh) Value( TARGET_CPU_ck803eh)
+
+EnumValue
+Enum(csky_processor_type) String(ck803et) Value( TARGET_CPU_ck803et)
+
+EnumValue
+Enum(csky_processor_type) String(ck803eht) Value( TARGET_CPU_ck803eht)
+
+EnumValue
+Enum(csky_processor_type) String(ck803ef) Value( TARGET_CPU_ck803ef)
+
+EnumValue
+Enum(csky_processor_type) String(ck803efh) Value( TARGET_CPU_ck803efh)
+
+EnumValue
+Enum(csky_processor_type) String(ck803ft) Value( TARGET_CPU_ck803ft)
+
+EnumValue
+Enum(csky_processor_type) String(ck803eft) Value( TARGET_CPU_ck803eft)
+
+EnumValue
+Enum(csky_processor_type) String(ck803efht) Value( TARGET_CPU_ck803efht)
+
+EnumValue
+Enum(csky_processor_type) String(ck803r1) Value( TARGET_CPU_ck803r1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803hr1) Value( TARGET_CPU_ck803hr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803tr1) Value( TARGET_CPU_ck803tr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803htr1) Value( TARGET_CPU_ck803htr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803fr1) Value( TARGET_CPU_ck803fr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803fhr1) Value( TARGET_CPU_ck803fhr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803er1) Value( TARGET_CPU_ck803er1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803ehr1) Value( TARGET_CPU_ck803ehr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803etr1) Value( TARGET_CPU_ck803etr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803ehtr1) Value( TARGET_CPU_ck803ehtr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803efr1) Value( TARGET_CPU_ck803efr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803efhr1) Value( TARGET_CPU_ck803efhr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803ftr1) Value( TARGET_CPU_ck803ftr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803eftr1) Value( TARGET_CPU_ck803eftr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803efhtr1) Value( TARGET_CPU_ck803efhtr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803s) Value( TARGET_CPU_ck803s)
+
+EnumValue
+Enum(csky_processor_type) String(ck803st) Value( TARGET_CPU_ck803st)
+
+EnumValue
+Enum(csky_processor_type) String(ck803se) Value( TARGET_CPU_ck803se)
+
+EnumValue
+Enum(csky_processor_type) String(ck803sf) Value( TARGET_CPU_ck803sf)
+
+EnumValue
+Enum(csky_processor_type) String(ck803sef) Value( TARGET_CPU_ck803sef)
+
+EnumValue
+Enum(csky_processor_type) String(ck803seft) Value( TARGET_CPU_ck803seft)
+
+EnumValue
+Enum(csky_processor_type) String(ck807e) Value( TARGET_CPU_ck807e)
+
+EnumValue
+Enum(csky_processor_type) String(ck807ef) Value( TARGET_CPU_ck807ef)
+
+EnumValue
+Enum(csky_processor_type) String(ck807) Value( TARGET_CPU_ck807)
+
+EnumValue
+Enum(csky_processor_type) String(ck807f) Value( TARGET_CPU_ck807f)
+
+EnumValue
+Enum(csky_processor_type) String(ck810e) Value( TARGET_CPU_ck810e)
+
+EnumValue
+Enum(csky_processor_type) String(ck810et) Value( TARGET_CPU_ck810et)
+
+EnumValue
+Enum(csky_processor_type) String(ck810ef) Value( TARGET_CPU_ck810ef)
+
+EnumValue
+Enum(csky_processor_type) String(ck810eft) Value( TARGET_CPU_ck810eft)
+
+EnumValue
+Enum(csky_processor_type) String(ck810) Value( TARGET_CPU_ck810)
+
+EnumValue
+Enum(csky_processor_type) String(ck810v) Value( TARGET_CPU_ck810v)
+
+EnumValue
+Enum(csky_processor_type) String(ck810f) Value( TARGET_CPU_ck810f)
+
+EnumValue
+Enum(csky_processor_type) String(ck810t) Value( TARGET_CPU_ck810t)
+
+EnumValue
+Enum(csky_processor_type) String(ck810fv) Value( TARGET_CPU_ck810fv)
+
+EnumValue
+Enum(csky_processor_type) String(ck810tv) Value( TARGET_CPU_ck810tv)
+
+EnumValue
+Enum(csky_processor_type) String(ck810ft) Value( TARGET_CPU_ck810ff)
+
+EnumValue
+Enum(csky_processor_type) String(ck810ftv) Value( TARGET_CPU_ck810ftv)
+
+Enum
+Name(csky_arch) Type(int)
+Known CSKY architectures (for use with the -march= option):
+
+EnumValue
+Enum(csky_arch) String(ck801) Value(0)
+
+EnumValue
+Enum(csky_arch) String(ck802) Value(1)
+
+EnumValue
+Enum(csky_arch) String(ck803) Value(2)
+
+EnumValue
+Enum(csky_arch) String(ck807) Value(3)
+
+EnumValue
+Enum(csky_arch) String(ck810) Value(4)
+
+Enum
+Name(csky_fpu) Type(enum csky_fpu_type)
+Known CSKY FPUs (for use with the -mfpu= option):
+
+EnumValue
+Enum(csky_fpu) String(fpv2_sf) Value(TARGET_FPU_fpv2_sf)
+
+EnumValue
+Enum(csky_fpu) String(fpv2) Value(TARGET_FPU_fpv2)
+
+EnumValue
+Enum(csky_fpu) String(fpv2_divd) Value(TARGET_FPU_fpv2_divd)
+
+EnumValue
+Enum(csky_fpu) String(auto) Value(TARGET_FPU_auto)
diff --git a/gcc/config/csky/predicates.md b/gcc/config/csky/predicates.md
new file mode 100644 (file)
index 0000000..2899f0b
--- /dev/null
@@ -0,0 +1,298 @@
+;; Predicates for C-SKY.
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+;; Contributed by C-SKY Microsystems and Mentor Graphics.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.  */
+
+;; Return 1 if OP is a load multiple operation.
+
+(define_predicate "csky_load_multiple_operation"
+  (match_code "parallel")
+{
+  int count = XVECLEN (op, 0);
+  int dest_regno;
+  rtx src_addr;
+  int i;
+
+  /* Perform a quick check so we don't blow up below.  */
+  if (count <= 1
+      || GET_CODE (XVECEXP (op, 0, 0)) != SET
+      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
+      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM
+      || GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0)) != REG
+      || XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0) != stack_pointer_rtx)
+    return 0;
+
+  dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
+  src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
+
+  for (i = 1; i < count; i++)
+    {
+      rtx elt = XVECEXP (op, 0, i);
+
+      if (GET_CODE (elt) != SET
+         || GET_CODE (SET_DEST (elt)) != REG
+         || GET_MODE (SET_DEST (elt)) != SImode
+         || REGNO (SET_DEST (elt)) != (unsigned) (dest_regno + i)
+         || GET_CODE (SET_SRC (elt)) != MEM
+         || GET_MODE (SET_SRC (elt)) != SImode
+         || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
+         || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
+         || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
+         || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != i * 4)
+       return 0;
+    }
+  return 1;
+})
+
+;; Similar, for store multiple.
+
+(define_predicate "csky_store_multiple_operation"
+  (match_code "parallel")
+{
+  int count = XVECLEN (op, 0);
+  int src_regno;
+  rtx dest_addr;
+  int i;
+
+  /* Perform a quick check so we don't blow up below.  */
+  if (count <= 1
+      || GET_CODE (XVECEXP (op, 0, 0)) != SET
+      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM
+      || GET_CODE (XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0)) != REG
+      || XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0) != stack_pointer_rtx
+      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG)
+    return 0;
+
+  src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
+  dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
+
+  for (i = 1; i < count; i++)
+    {
+      rtx elt = XVECEXP (op, 0, i);
+
+      if (GET_CODE (elt) != SET
+         || GET_CODE (SET_SRC (elt)) != REG
+         || GET_MODE (SET_SRC (elt)) != SImode
+         || REGNO (SET_SRC (elt)) != (unsigned) (src_regno + i)
+         || GET_CODE (SET_DEST (elt)) != MEM
+         || GET_MODE (SET_DEST (elt)) != SImode
+         || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
+         || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
+         || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
+         || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != i * 4)
+       return 0;
+    }
+  return 1;
+})
+
+
+(define_predicate "csky_arith_K_operand"
+  (match_code "reg,subreg,const_int")
+  {
+    if (register_operand (op, mode))
+      return 1;
+    if (CONST_INT_P (op) && CSKY_CONST_OK_FOR_K (INTVAL (op)))
+      return 1;
+    return 0;
+  })
+
+(define_predicate "csky_literal_K_operand"
+  (match_code "const_int")
+  {
+    if (CONST_INT_P (op) && CSKY_CONST_OK_FOR_K (INTVAL (op)))
+      return 1;
+    return 0;
+  })
+
+(define_predicate "csky_literal_I_operand"
+  (match_code "const_int")
+  {
+    if (CONST_INT_P (op) && CSKY_CONST_OK_FOR_I (INTVAL (op)))
+      return 1;
+    return 0;
+  })
+
+(define_predicate "csky_literal_J_operand"
+  (match_code "const_int")
+  {
+    if (CONST_INT_P (op) && CSKY_CONST_OK_FOR_J (INTVAL (op)))
+      return 1;
+    return 0;
+  })
+
+(define_predicate "csky_literal_Uk_operand"
+  (match_code "const_int")
+  {
+    if (CONST_INT_P (op) && CSKY_CONST_OK_FOR_Uk (INTVAL (op)))
+      return 1;
+    return 0;
+  })
+
+;; Nonzero if OP is a register or constant value of 1
+
+(define_predicate "csky_arith_int1_operand"
+  (match_code "reg,subreg,const_int")
+  {
+    if (register_operand (op, mode))
+       return 1;
+    if (op == const1_rtx)
+       return 1;
+    return 0;
+  })
+
+
+;; Nonzero if OP is legal address for function call
+
+(define_predicate "csky_call_address_operand"
+  (match_code "reg,subreg,symbol_ref")
+  {
+    if (!flag_pic && (GET_CODE (op) == SYMBOL_REF))
+      return 1;
+    if (register_operand (op, mode))
+      return 1;
+    return 0;
+  })
+
+;; Nonzero if OP is a valid source operand for a compare operation.
+
+(define_predicate "csky_compare_operand"
+  (match_code "const_int,reg,subreg")
+  {
+    if (register_operand (op, mode))
+      return 1;
+    if (GET_CODE (op) == CONST_INT && INTVAL (op) == 0)
+      return 1;
+    return 0;
+  })
+
+(define_predicate "csky_literal_K_Uh_operand"
+  (match_code "const_int")
+  {
+    if (CONST_INT_P (op)
+       && (CSKY_CONST_OK_FOR_K (INTVAL (op))
+           || CSKY_CONST_OK_FOR_Uh (INTVAL (op))))
+         return 1;
+    return 0;
+  })
+
+;; True if OP is a mem with an reg + optional displacement address.
+
+(define_predicate "csky_simple_mem_operand"
+  (and (match_operand 0 "memory_operand")
+       (match_test "csky_simple_addr_operand_p (XEXP (op, 0))")))
+
+(define_predicate "csky_arith_any_imm_operand"
+  (match_code "const_int,reg,subreg")
+  {
+    if (register_operand (op, mode))
+      return 1;
+    if (CONST_INT_P (op))
+      return 1;
+    return 0;
+  })
+
+(define_predicate "csky_arith_O_operand"
+  (match_code "reg,subreg,const_int")
+  {
+    if (register_operand (op, mode))
+      return 1;
+    if (CONST_INT_P (op) && CSKY_CONST_OK_FOR_O (INTVAL (op)))
+      return 1;
+    return 0;
+  })
+
+(define_predicate "csky_unspec_operand"
+  (match_code "unspec")
+  {
+    if (op == NULL || GET_CODE(op) != UNSPEC)
+      return 0;
+    return 1;
+  }
+)
+
+(define_predicate "csky_const_float1_operand"
+  (and (match_code "const_double")
+       (match_test "(op == CONST1_RTX (mode))")))
+
+(define_predicate "csky_arith_float1_operand"
+  (ior (match_operand 0 "register_operand")
+       (match_operand 0 "csky_const_float1_operand")))
+
+(define_predicate "csky_const_float0_operand"
+  (and (match_code "const_double")
+       (match_test "(op == CONST0_RTX (mode))")))
+
+(define_predicate "csky_compare_operand_float"
+  (ior (match_operand 0 "register_operand")
+       (match_operand 0 "csky_const_float0_operand")))
+
+(define_special_predicate "registers_push"
+  (match_code "parallel")
+{
+  if ((GET_CODE (XVECEXP (op, 0, 0)) != SET)
+      || (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC)
+      || (XINT (SET_SRC (XVECEXP (op, 0, 0)), 1) != UNSPEC_PUSHPOP_MULT))
+    return false;
+  return true;
+})
+
+(define_special_predicate "registers_pop"
+  (match_code "parallel")
+{
+  if ((GET_CODE (XVECEXP (op, 0, 1)) != SET)
+      || (GET_CODE (SET_SRC (XVECEXP (op, 0, 1))) != UNSPEC)
+      || (XINT (SET_SRC (XVECEXP (op, 0, 1)), 1) != UNSPEC_PUSHPOP_MULT))
+    return false;
+  return true;
+})
+
+(define_predicate "push_memory_operand"
+  (match_code "mem")
+{
+  rtx x = XEXP (op, 0);
+  if (GET_CODE (x) != PRE_MODIFY)
+    return false;
+  if (XEXP (x, 0) != stack_pointer_rtx)
+    return false;
+  x = XEXP (x, 1);
+  if (GET_CODE (x) != PLUS)
+    return false;
+  if (XEXP (x, 0) != stack_pointer_rtx)
+    return false;
+  return CONST_INT_P (XEXP (x, 1));
+})
+
+(define_predicate "pop_memory_operand"
+  (match_code "mem")
+{
+  rtx x = XEXP (op, 0);
+  if (GET_CODE (x) != POST_MODIFY)
+    return false;
+  if (XEXP (x, 0) != stack_pointer_rtx)
+    return false;
+  x = XEXP (x, 1);
+  if (GET_CODE (x) != PLUS)
+    return false;
+  if (XEXP (x, 0) != stack_pointer_rtx)
+    return false;
+  return CONST_INT_P (XEXP (x, 1));
+})
+
+(define_special_predicate "csky_float_comparison_operator"
+  (match_code "eq,ne,le,lt,ge,gt,geu,gtu,leu,ltu,
+              unordered,ordered"))
diff --git a/gcc/config/csky/print-sysroot-suffix.sh b/gcc/config/csky/print-sysroot-suffix.sh
new file mode 100644 (file)
index 0000000..5cbdc3f
--- /dev/null
@@ -0,0 +1,147 @@
+#! /bin/sh
+# Script to generate SYSROOT_SUFFIX_SPEC equivalent to MULTILIB_OSDIRNAMES
+# Arguments are MULTILIB_OSDIRNAMES, MULTILIB_OPTIONS and MULTILIB_MATCHES.
+
+# Copyright (C) 2018 Free Software Foundation, Inc.
+# Contributed by C-SKY Microsystems and Mentor Graphics.
+
+# This file is part of GCC.
+
+# GCC is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 3, or (at your option) any later
+# version.
+
+# GCC is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# This shell script produces a header file fragment that defines
+# SYSROOT_SUFFIX_SPEC.  It assumes that the sysroots will have the same
+# structure and names used by the multilibs.
+
+# Invocation:
+#   print-sysroot-suffix.sh \
+#          MULTILIB_OSDIRNAMES \
+#          MULTILIB_OPTIONS \
+#          MULTILIB_MATCHES \
+#      > t-sysroot-suffix.h
+
+# The three options exactly correspond to the variables of the same
+# names defined in the tmake_file fragments.
+
+# Example:
+#   sh ./gcc/config/print-sysroot-suffix.sh "a=A" "a b/c/d" ""
+# =>
+#   #undef SYSROOT_SUFFIX_SPEC
+#   #define SYSROOT_SUFFIX_SPEC "" \
+#   "%{a:" \
+#     "%{b:A/b/;" \
+#     "c:A/c/;" \
+#     "d:A/d/;" \
+#     ":A/};" \
+#   ":}"
+
+# The script uses temporary subscripts in order to permit a recursive
+# algorithm without the use of functions.
+
+set -e
+
+dirnames="$1"
+options="$2"
+matches="$3"
+
+cat > print-sysroot-suffix3.sh <<\EOF
+#! /bin/sh
+# Print all the multilib matches for this option
+result="$1"
+EOF
+for x in $matches; do
+  l=`echo $x | sed -e 's/=.*$//' -e 's/?/=/g'`
+  r=`echo $x | sed -e 's/^.*=//' -e 's/?/=/g'`
+  echo "[ \"\$1\" = \"$l\" ] && result=\"\$result|$r\"" >> print-sysroot-suffix3.sh
+done
+echo 'echo $result' >> print-sysroot-suffix3.sh
+chmod +x print-sysroot-suffix3.sh
+
+cat > print-sysroot-suffix2.sh <<\EOF
+#! /bin/sh
+# Recursive script to enumerate all multilib combinations, match against
+# multilib directories and output a spec string of the result.
+# Will fold identical trees.
+
+padding="$1"
+optstring="$2"
+shift 2
+n="\" \\
+$padding\""
+if [ $# = 0 ]; then
+EOF
+
+pat=
+for x in $dirnames; do
+#  p=`echo $x | sed -e 's,=!,/$=/,'`
+  p=`echo $x | sed -e 's/=//g'`
+#  pat="$pat -e 's=^//$p='"
+   pat="$pat -e 's/$p/g'"
+done
+echo '  optstring=`echo "/$optstring" | sed '"$pat\`" >> print-sysroot-suffix2.sh
+cat >> print-sysroot-suffix2.sh <<\EOF
+  case $optstring in
+  //*)
+    ;;
+  *)
+    echo "$optstring"
+    ;;
+  esac
+else
+  thisopt="$1"
+  shift
+  bit=
+  lastcond=
+  result=
+  for x in `echo "$thisopt" | sed -e 's,/, ,g'`; do
+    case $x in
+EOF
+for x in `echo "$options" | sed -e 's,/, ,g'`; do
+  match=`./print-sysroot-suffix3.sh "$x"`
+  echo "$x) optmatch=\"$match\" ;;" >> print-sysroot-suffix2.sh
+done
+cat >> print-sysroot-suffix2.sh <<\EOF
+    esac
+    bit=`"$0" "$padding  " "$optstring$x/" "$@"`
+    if [ -z "$lastopt" ]; then
+      lastopt="$optmatch"
+    else
+      if [ "$lastbit" = "$bit" ]; then
+       lastopt="$lastopt|$optmatch"
+      else
+       result="$result$lastopt:$lastbit;$n"
+       lastopt="$optmatch"
+      fi
+    fi
+    lastbit="$bit"
+  done
+  bit=`"$0" "$padding  " "$optstring" "$@"`
+  if [ "$bit" = "$lastbit" ]; then
+    if [ -z "$result" ]; then
+      echo "$bit"
+    else
+      echo "$n%{$result:$bit}"
+    fi
+  else
+    echo "$n%{$result$lastopt:$lastbit;$n:$bit}"
+  fi
+fi
+EOF
+chmod +x ./print-sysroot-suffix2.sh
+result=`./print-sysroot-suffix2.sh \"\" \"\" $options`
+echo "#undef SYSROOT_SUFFIX_SPEC"
+echo "#define SYSROOT_SUFFIX_SPEC \"$result\""
+rm print-sysroot-suffix2.sh
+rm print-sysroot-suffix3.sh
diff --git a/gcc/config/csky/t-csky b/gcc/config/csky/t-csky
new file mode 100644 (file)
index 0000000..ab9be18
--- /dev/null
@@ -0,0 +1,29 @@
+# Make rules for all C-SKY targets.
+#
+# Copyright (C) 2018 Free Software Foundation, Inc.
+# Contributed by C-SKY Microsystems and Mentor Graphics.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+TM_H += $(srcdir)/config/csky/csky_cores.def
+OPTIONS_H_EXTRA += $(srcdir)/config/csky/csky_cores.def
+
+
+$(srcdir)/config/csky/csky_tables.opt: $(srcdir)/config/csky/csky_genopt.sh \
+  $(srcdir)/config/csky/csky_cores.def
+       $(SHELL) $(srcdir)/config/csky/csky_genopt.sh $(srcdir)/config/csky > \
+               $(srcdir)/config/csky/csky_tables.opt
diff --git a/gcc/config/csky/t-csky-elf b/gcc/config/csky/t-csky-elf
new file mode 100644 (file)
index 0000000..6864544
--- /dev/null
@@ -0,0 +1,107 @@
+# Multilib configuration for csky*-elf.
+#
+# Copyright (C) 2018 Free Software Foundation, Inc.
+# Contributed by C-SKY Microsystems and Mentor Graphics.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# Endiannesses.
+MULTILIB_OPTIONS      = mlittle-endian/mbig-endian
+MULTILIB_DIRNAMES     = little big
+MULTILIB_MATCHES      = mlittle-endian=EL
+MULTILIB_MATCHES      = mbig-endian=EB
+MULTILIB_EXCEPTIONS   =
+
+# Arch variants.
+MULTILIB_OPTIONS     += mcpu=ck802/mcpu=ck801/mcpu=ck803f/mcpu=ck807f/mcpu=ck810f
+MULTILIB_DIRNAMES    += ck802 ck801 ck803 ck807 ck810
+
+# For arch ck802.
+MULTILIB_MATCHES     += mcpu?ck802=march?ck802
+MULTILIB_MATCHES     += mcpu?ck802=mcpu?ck802t
+MULTILIB_MATCHES     += mcpu?ck802=mcpu?ck802j
+
+# For arch ck801.
+MULTILIB_MATCHES     += mcpu?ck801=march?ck801
+MULTILIB_MATCHES     += mcpu?ck801=mcpu?ck801t
+
+# For arch ck803.
+MULTILIB_MATCHES     += mcpu?ck803f=march?ck803
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803fh
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803h
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803t
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803ht
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803e
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803eh
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803et
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803eht
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803ef
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803efh
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803ft
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803eft
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803efht
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803r1
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803fr1
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803fhr1
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803hr1
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803tr1
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803htr1
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803er1
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803ehr1
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803etr1
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803ehtr1
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803efr1
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803efhr1
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803ftr1
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803eftr1
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803efhtr1
+
+# For arch ck803s.
+MULTILIB_MATCHES     += mcpu?ck803f=march?ck803s
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803s
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803st
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803se
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803sf
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803sef
+MULTILIB_MATCHES     += mcpu?ck803f=mcpu?ck803seft
+
+# For arch ck810.
+MULTILIB_MATCHES     += mcpu?ck810f=mcpu?ck810e
+MULTILIB_MATCHES     += mcpu?ck810f=mcpu?ck810et
+MULTILIB_MATCHES     += mcpu?ck810f=mcpu?ck810ef
+MULTILIB_MATCHES     += mcpu?ck810f=mcpu?ck810eft
+MULTILIB_MATCHES     += mcpu?ck810f=march?ck810
+MULTILIB_MATCHES     += mcpu?ck810f=mcpu?ck810
+MULTILIB_MATCHES     += mcpu?ck810f=mcpu?ck810v
+MULTILIB_MATCHES     += mcpu?ck810f=mcpu?ck810t
+MULTILIB_MATCHES     += mcpu?ck810f=mcpu?ck810vf
+MULTILIB_MATCHES     += mcpu?ck810f=mcpu?ck810tv
+MULTILIB_MATCHES     += mcpu?ck810f=mcpu?ck810ft
+MULTILIB_MATCHES     += mcpu?ck810f=mcpu?ck810ftv
+
+# For arch ck807.
+MULTILIB_MATCHES     += mcpu?ck807f=march?ck807e
+MULTILIB_MATCHES     += mcpu?ck807f=march?ck807ef
+MULTILIB_MATCHES     += mcpu?ck807f=march?ck807
+MULTILIB_MATCHES     += mcpu?ck807f=mcpu?ck807
+
+# For option -msoft-float/-mhard-float.
+MULTILIB_OPTIONS     += msoft-float/mhard-float
+MULTILIB_DIRNAMES    += soft-fp hard-fp
+MULTILIB_EXCEPTIONS  += *mcpu=ck801/*mhard-float*
+MULTILIB_EXCEPTIONS  += *mcpu=ck802/*mhard-float*
diff --git a/gcc/config/csky/t-csky-linux b/gcc/config/csky/t-csky-linux
new file mode 100644 (file)
index 0000000..4a145a6
--- /dev/null
@@ -0,0 +1,52 @@
+# Multilib configuration for csky*-linux-*.
+#
+# Copyright (C) 2018 Free Software Foundation, Inc.
+# Contributed by C-SKY Microsystems and Mentor Graphics.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+
+# Endiannesses.
+MULTILIB_OPTIONS     = mlittle-endian/mbig-endian
+MULTILIB_DIRNAMES    = little big
+MULTILIB_MATCHES     = mlittle-endian=EL
+MULTILIB_MATCHES     = mbig-endian=EB
+
+MULTILIB_EXCEPTIONS  =
+CSKY_MULTILIB_OSDIRNAMES = mbig-endian=/big mlittle-endian=/. mhard-float=/hard-fp msoft-float=/. mcpu.ck810f=/. mcpu.ck807f=/ck807
+
+# Arch variants.
+MULTILIB_OPTIONS     += mcpu=ck810f/mcpu=ck807f
+MULTILIB_DIRNAMES    += ck810 ck807
+
+# For ck807.
+MULTILIB_MATCHES     += mcpu?ck807f=march?ck807
+MULTILIB_MATCHES     += mcpu?ck807f=mcpu?ck807
+
+# For arch ck810.
+MULTILIB_MATCHES     += mcpu?ck810f=march?ck810
+MULTILIB_MATCHES     += mcpu?ck810f=mcpu?ck810
+MULTILIB_MATCHES     += mcpu?ck810f=mcpu?ck810v
+MULTILIB_MATCHES     += mcpu?ck810f=mcpu?ck810t
+MULTILIB_MATCHES     += mcpu?ck810f=mcpu?ck810vt
+MULTILIB_MATCHES     += mcpu?ck810f=mcpu?ck810vf
+MULTILIB_MATCHES     += mcpu?ck810f=mcpu?ck810ft
+MULTILIB_MATCHES     += mcpu?ck810f=mcpu?ck810vft
+
+# For option -msoft-float/-mhard-float.
+MULTILIB_OPTIONS    += msoft-float/mhard-float
+MULTILIB_DIRNAMES   += soft-fp hard-fp
diff --git a/gcc/config/csky/t-sysroot-suffix b/gcc/config/csky/t-sysroot-suffix
new file mode 100644 (file)
index 0000000..97c03d3
--- /dev/null
@@ -0,0 +1,28 @@
+# Makefile fragment for C-SKY sysroot suffix.
+#
+# Copyright (C) 2018 Free Software Foundation, Inc.
+# Contributed by C-SKY Microsystems and Mentor Graphics.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# Generate SYSROOT_SUFFIX_SPEC from MULTILIB_OSDIRNAMES.
+
+sysroot-suffix.h: $(srcdir)/config/csky/print-sysroot-suffix.sh
+       $(SHELL) $(srcdir)/config/csky/print-sysroot-suffix.sh \
+         "$(CSKY_MULTILIB_OSDIRNAMES)" "$(MULTILIB_OPTIONS)" \
+         "$(MULTILIB_MATCHES)" > tmp-sysroot-suffix.h
+       mv tmp-sysroot-suffix.h $@