+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>
--- /dev/null
+/* 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;
--- /dev/null
+;; 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)")))
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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 (®_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"
--- /dev/null
+/* 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 */
--- /dev/null
+;; 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"
+)
--- /dev/null
+;; 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.
--- /dev/null
+/* 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
--- /dev/null
+#!/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
--- /dev/null
+;; 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")])
--- /dev/null
+;; 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;
+ }"
+)
--- /dev/null
+/* 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
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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 */
--- /dev/null
+;; 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")
--- /dev/null
+;; 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")
--- /dev/null
+;; 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")
--- /dev/null
+;; 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")
--- /dev/null
+; -*- 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)
--- /dev/null
+;; 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"))
--- /dev/null
+#! /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
--- /dev/null
+# 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
--- /dev/null
+# 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*
--- /dev/null
+# 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
--- /dev/null
+# 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 $@