aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@gcc.gnu.org>2018-08-20 13:31:18 +0000
committerNathan Sidwell <nathan@gcc.gnu.org>2018-08-20 13:31:18 +0000
commit942c7776a2bc34113bbf5d749102401d330dd258 (patch)
treec7005661d07c65e4471c20540a8650ffb7ff4ec5
parentaa47c164cfe5c452f1f53763a8aac4221929a091 (diff)
parent3fb558b154f795983ae6a9dd6478e18a2c846584 (diff)
downloadgcc-942c7776a2bc34113bbf5d749102401d330dd258.zip
gcc-942c7776a2bc34113bbf5d749102401d330dd258.tar.gz
gcc-942c7776a2bc34113bbf5d749102401d330dd258.tar.bz2
Merge trunk r263658.
From-SVN: r263659
-rw-r--r--ChangeLog4
-rw-r--r--ChangeLog.name-lookup4
-rw-r--r--MAINTAINERS2
-rw-r--r--contrib/ChangeLog10
-rw-r--r--contrib/config-list.mk1
-rw-r--r--gcc/ChangeLog110
-rw-r--r--gcc/DATESTAMP2
-rw-r--r--gcc/c-family/ChangeLog27
-rw-r--r--gcc/c-family/c-format.c36
-rw-r--r--gcc/common/config/csky/csky-common.c42
-rw-r--r--gcc/config.gcc68
-rw-r--r--gcc/config/arm/arm-builtins.c5
-rw-r--r--gcc/config/csky/constraints.md174
-rw-r--r--gcc/config/csky/csky-elf.h81
-rw-r--r--gcc/config/csky/csky-linux-elf.h132
-rw-r--r--gcc/config/csky/csky-protos.h71
-rw-r--r--gcc/config/csky/csky.c6795
-rw-r--r--gcc/config/csky/csky.h1054
-rw-r--r--gcc/config/csky/csky.md3798
-rw-r--r--gcc/config/csky/csky.opt173
-rw-r--r--gcc/config/csky/csky_cores.def199
-rw-r--r--gcc/config/csky/csky_genopt.sh97
-rw-r--r--gcc/config/csky/csky_insn_dsp.md95
-rw-r--r--gcc/config/csky/csky_insn_fpu.md567
-rw-r--r--gcc/config/csky/csky_isa.def59
-rw-r--r--gcc/config/csky/csky_isa.h47
-rw-r--r--gcc/config/csky/csky_opts.h63
-rw-r--r--gcc/config/csky/csky_pipeline_ck801.md54
-rw-r--r--gcc/config/csky/csky_pipeline_ck802.md77
-rw-r--r--gcc/config/csky/csky_pipeline_ck803.md64
-rw-r--r--gcc/config/csky/csky_pipeline_ck810.md34
-rw-r--r--gcc/config/csky/csky_tables.opt230
-rw-r--r--gcc/config/csky/predicates.md298
-rw-r--r--gcc/config/csky/print-sysroot-suffix.sh147
-rw-r--r--gcc/config/csky/t-csky29
-rw-r--r--gcc/config/csky/t-csky-elf107
-rw-r--r--gcc/config/csky/t-csky-linux52
-rw-r--r--gcc/config/csky/t-sysroot-suffix28
-rw-r--r--gcc/config/darwin.c8
-rw-r--r--gcc/config/darwin.h6
-rw-r--r--gcc/config/i386/i386.c18
-rw-r--r--gcc/config/rs6000/rs6000.md10
-rwxr-xr-xgcc/configure2
-rw-r--r--gcc/configure.ac2
-rw-r--r--gcc/cp/ChangeLog5
-rw-r--r--gcc/cp/typeck.c10
-rw-r--r--gcc/doc/extend.texi33
-rw-r--r--gcc/doc/invoke.texi203
-rw-r--r--gcc/doc/md.texi38
-rw-r--r--gcc/dump-context.h7
-rw-r--r--gcc/dumpfile.c358
-rw-r--r--gcc/dumpfile.h20
-rw-r--r--gcc/testsuite/ChangeLog57
-rw-r--r--gcc/testsuite/g++.dg/Wno-frame-address.C2
-rw-r--r--gcc/testsuite/g++.dg/conversion/Wwrite-strings.C24
-rw-r--r--gcc/testsuite/g++.dg/debug/dwarf2/pr85302.C1
-rw-r--r--gcc/testsuite/g++.dg/torture/type-generic-1.C1
-rw-r--r--gcc/testsuite/gcc.c-torture/compile/20000804-1.c1
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/20101011-1.c4
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/ieee/mul-subnormal-single-1.x5
-rw-r--r--gcc/testsuite/gcc.dg/20020312-2.c5
-rw-r--r--gcc/testsuite/gcc.dg/Wno-frame-address.c2
-rw-r--r--gcc/testsuite/gcc.dg/c11-true_min-1.c1
-rw-r--r--gcc/testsuite/gcc.dg/debug/dwarf2/pr80263.c2
-rw-r--r--gcc/testsuite/gcc.dg/format/gcc_diag-1.c15
-rw-r--r--gcc/testsuite/gcc.dg/format/gcc_diag-10.c26
-rw-r--r--gcc/testsuite/gcc.dg/lto/pr83719_0.c1
-rw-r--r--gcc/testsuite/gcc.dg/pr86064.c1
-rw-r--r--gcc/testsuite/gcc.dg/sibcall-10.c2
-rw-r--r--gcc/testsuite/gcc.dg/sibcall-9.c2
-rw-r--r--gcc/testsuite/gcc.dg/stack-usage-1.c2
-rw-r--r--gcc/testsuite/gcc.dg/torture/float32-tg-3.c1
-rw-r--r--gcc/testsuite/gcc.dg/torture/float32x-tg-3.c1
-rw-r--r--gcc/testsuite/gcc.dg/torture/float64-tg-3.c1
-rw-r--r--gcc/testsuite/gcc.dg/torture/float64x-tg-3.c1
-rw-r--r--gcc/testsuite/gcc.dg/torture/type-generic-1.c1
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-1.c7
-rw-r--r--gcc/testsuite/gcc.target/csky/and1.c12
-rw-r--r--gcc/testsuite/gcc.target/csky/and2.c12
-rw-r--r--gcc/testsuite/gcc.target/csky/and3a.c12
-rw-r--r--gcc/testsuite/gcc.target/csky/and3b.c11
-rw-r--r--gcc/testsuite/gcc.target/csky/ck801-branch.c40
-rw-r--r--gcc/testsuite/gcc.target/csky/constpool-1.c16
-rw-r--r--gcc/testsuite/gcc.target/csky/constpool-2.c15
-rw-r--r--gcc/testsuite/gcc.target/csky/constpool-3.c15
-rw-r--r--gcc/testsuite/gcc.target/csky/cse-cc.c19
-rw-r--r--gcc/testsuite/gcc.target/csky/csky.exp79
-rw-r--r--gcc/testsuite/gcc.target/csky/fnargs-1.c38
-rw-r--r--gcc/testsuite/gcc.target/csky/fnargs-2.c52
-rw-r--r--gcc/testsuite/gcc.target/csky/fnargs-3.c31
-rw-r--r--gcc/testsuite/gcc.target/csky/land1.c11
-rw-r--r--gcc/testsuite/gcc.target/csky/land2.c11
-rw-r--r--gcc/testsuite/gcc.target/csky/naked.c16
-rw-r--r--gcc/testsuite/gcc.target/csky/or1.c11
-rw-r--r--gcc/testsuite/lib/target-supports.exp13
-rw-r--r--gcc/tree-vect-data-refs.c8
-rw-r--r--gcc/tree-vect-loop.c2
-rw-r--r--gcc/tree-vect-slp.c3
-rw-r--r--gcc/tree-vectorizer.c4
-rw-r--r--libcpp/ChangeLog31
-rw-r--r--libcpp/directives.c22
-rw-r--r--libcpp/include/cpplib.h2
-rw-r--r--libgcc/ChangeLog10
-rw-r--r--libgcc/config.host12
-rw-r--r--libgcc/config/csky/crti.S140
-rw-r--r--libgcc/config/csky/crtn.S55
-rw-r--r--libgcc/config/csky/lib1funcs.S675
-rw-r--r--libgcc/config/csky/linux-atomic.c299
-rw-r--r--libgcc/config/csky/linux-unwind.h131
-rw-r--r--libgcc/config/csky/t-csky28
-rw-r--r--libgcc/config/csky/t-linux-csky21
-rw-r--r--libstdc++-v3/ChangeLog51
-rw-r--r--libstdc++-v3/include/std/optional340
-rw-r--r--libstdc++-v3/include/std/tuple125
-rw-r--r--libstdc++-v3/include/std/type_traits5
-rw-r--r--libstdc++-v3/python/libstdcxx/v6/printers.py23
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/cons/value_neg.cc6
-rw-r--r--libstdc++-v3/testsuite/20_util/tuple/dr2729.cc179
-rw-r--r--libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/copy/86658.cc2
120 files changed, 17994 insertions, 318 deletions
diff --git a/ChangeLog b/ChangeLog
index d4b62349d..002d599 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2018-08-17 Sandra Loosemore <sandra@codesourcery.com>
+
+ MAINTAINERS: Add c-sky port maintainers.
+
2018-08-10 Martin Liska <mliska@suse.cz>
* MAINTAINERS: Revert change in previous commit and
diff --git a/ChangeLog.name-lookup b/ChangeLog.name-lookup
index 42f9135..389ab08 100644
--- a/ChangeLog.name-lookup
+++ b/ChangeLog.name-lookup
@@ -1,3 +1,7 @@
+2018-08-20 Nathan Sidwell <nathan@acm.org>
+
+ Merge trunk r263658.
+
2018-08-17 Nathan Sidwell <nathan@acm.org>
Merge trunk r263622.
diff --git a/MAINTAINERS b/MAINTAINERS
index a9f20d7..0a3b149 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -56,6 +56,8 @@ avr port Denis Chertykov <chertykov@gmail.com>
bfin port Jie Zhang <jzhang918@gmail.com>
c6x port Bernd Schmidt <bernds_cb1@t-online.de>
cris port Hans-Peter Nilsson <hp@axis.com>
+c-sky port Xianmiao Qu <xianmiao_qu@c-sky.com>
+c-sky port Yunhai Shang <yunhai_shang@c-sky.com>
epiphany port Joern Rennecke <gnu@amylaar.uk>
fr30 port Nick Clifton <nickc@redhat.com>
frv port Nick Clifton <nickc@redhat.com>
diff --git a/contrib/ChangeLog b/contrib/ChangeLog
index dc493dd..97ed200 100644
--- a/contrib/ChangeLog
+++ b/contrib/ChangeLog
@@ -1,3 +1,13 @@
+2018-08-17 Jojo <jijie_rong@c-sky.com>
+ Huibin Wang <huibin_wang@c-sky.com>
+ Sandra Loosemore <sandra@codesourcery.com>
+ Chung-Lin Tang <cltang@codesourcery.com>
+ Andrew Jenner <andrew@codesourcery.com>
+
+ C-SKY port: Configury
+
+ * config-list.mk (LIST): Add csky-elf and csky-linux-gnu.
+
2018-07-13 Tom de Vries <tdevries@suse.de>
* maintainers-verify.sh: New file.
diff --git a/contrib/config-list.mk b/contrib/config-list.mk
index c3537d2..d9e48a9 100644
--- a/contrib/config-list.mk
+++ b/contrib/config-list.mk
@@ -40,6 +40,7 @@ LIST = aarch64-elf aarch64-linux-gnu aarch64-rtems \
arm-symbianelf avr-elf \
bfin-elf bfin-uclinux bfin-linux-uclibc bfin-rtems bfin-openbsd \
c6x-elf c6x-uclinux cr16-elf cris-elf cris-linux crisv32-elf crisv32-linux \
+ csky-elf csky-linux-gnu \
epiphany-elf epiphany-elfOPT-with-stack-offset=16 fido-elf \
fr30-elf frv-elf frv-linux ft32-elf h8300-elf hppa-linux-gnu \
hppa-linux-gnuOPT-enable-sjlj-exceptions=yes hppa64-linux-gnu \
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 17545dc..ec1fb24 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,113 @@
+2018-08-19 Uros Bizjak <ubizjak@gmail.com>
+
+ PR target/86994
+ * config/i386/i386.c (ix86_rtx_costs) [case SET]: Check source for
+ register_operand when calling ix86_set_reg_reg_cost.
+ [case CONST_INT, case CONST, case LABEL_REF, case SYMBOL_REF]:
+ Set *total to 0 for operands that satisfy x86_64_immediate_operand
+ predicate and to 1 otherwise.
+
+2018-08-18 Iain Sandoe <iain@sandoe.co.uk>
+
+ * config/darwin.c (darwin_override_options): If -gsplit-dwarf is set,
+ emit a diagnostic that it is not supported and reset the option.
+ * config/darwin.h (DRIVER_SELF_SPECS): Note that gsplit-dwarf is not
+ supported and consume the option. (ASM_FINAL_SPEC): New.
+
+2018-08-17 Segher Boessenkool <segher@kernel.crashing.org>
+
+ * doc/md.texi (Patterns): Use @ref instead of @xref in the middle of
+ a sentence.
+
+2018-08-17 Sandra Loosemore <sandra@codesourcery.com>
+
+ C-SKY port: Documentation
+
+ * doc/extend.texi (C-SKY Function Attributes): New section.
+ * doc/invoke.texi (Option Summary): Add C-SKY options.
+ (C-SKY Options): New section.
+ * doc/md.texi (Machine Constraints): Document C-SKY constraints.
+
+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>
+ Chung-Lin Tang <cltang@codesourcery.com>
+ Andrew Jenner <andrew@codesourcery.com>
+
+ C-SKY port: Configury
+
+ * config.gcc (csky-*-*): New.
+ * configure.ac: Add csky to targets for dwarf2 debug_line support.
+ * configure: Regenerated.
+
+2018-08-17 David Malcolm <dmalcolm@redhat.com>
+
+ * dump-context.h: Include "dumpfile.h".
+ (dump_context::dump_printf_va): Convert final param from va_list
+ to va_list *. Convert from ATTRIBUTE_PRINTF to
+ ATTRIBUTE_GCC_DUMP_PRINTF.
+ (dump_context::dump_printf_loc_va): Likewise.
+ * dumpfile.c: Include "stringpool.h".
+ (make_item_for_dump_printf_va): Delete.
+ (make_item_for_dump_printf): Delete.
+ (class dump_pretty_printer): New class.
+ (dump_pretty_printer::dump_pretty_printer): New ctor.
+ (dump_pretty_printer::emit_items): New member function.
+ (dump_pretty_printer::emit_any_pending_textual_chunks): New member
+ function.
+ (dump_pretty_printer::emit_item): New member function.
+ (dump_pretty_printer::stash_item): New member function.
+ (dump_pretty_printer::format_decoder_cb): New member function.
+ (dump_pretty_printer::decode_format): New member function.
+ (dump_context::dump_printf_va): Reimplement in terms of
+ dump_pretty_printer.
+ (dump_context::dump_printf_loc_va): Convert final param from va_list
+ to va_list *.
+ (dump_context::begin_scope): Reimplement call to
+ make_item_for_dump_printf.
+ (dump_printf): Update for change to dump_printf_va.
+ (dump_printf_loc): Likewise.
+ (selftest::test_capture_of_dump_calls): Convert "stmt" from
+ greturn * to gimple *. Add a test_decl. Add tests of dump_printf
+ with %T, %E, and %G.
+ * dumpfile.h (ATTRIBUTE_GCC_DUMP_PRINTF): New macro.
+ (dump_printf): Replace ATTRIBUTE_PRINTF_2 with
+ ATTRIBUTE_GCC_DUMP_PRINTF (2, 3).
+ (dump_printf_loc): Replace ATTRIBUTE_PRINTF_3 with
+ ATTRIBUTE_GCC_DUMP_PRINTF (3, 0).
+ * tree-vect-data-refs.c (vect_lanes_optab_supported_p): Convert
+ use of HOST_WIDE_INT_PRINT_DEC on unsigned HOST_WIDE_INT "count"
+ within a dump_printf_loc call to "%wu".
+ (vector_alignment_reachable_p): Merge two dump_printf[_loc] calls,
+ converting a use of HOST_WIDE_INT_PRINT_DEC to "%wd". Add a
+ missing space after "=".
+ * tree-vect-loop.c (vect_analyze_loop_2) Within a dump_printf
+ call, convert use of HOST_WIDE_INT_PRINT_DEC to "%wd".
+ * tree-vect-slp.c (vect_slp_bb): Within a dump_printf_loc call,
+ convert use of HOST_WIDE_INT_PRINT_UNSIGNED to "%wu".
+ * tree-vectorizer.c (try_vectorize_loop_1): Likewise. Remove
+ duplicate "vectorized" from message.
+
+2018-08-17 Szabolcs Nagy <szabolcs.nagy@arm.com>
+
+ * config/arm/arm-builtins.c (arm_init_simd_builtin_types): Clear
+ polyNxK_t element's TYPE_STRING_FLAG.
+
+2018-08-17 Segher Boessenkool <segher@kernel.crashing.org>
+
+ * config/rs6000/rs6000.md (*cbranch, *creturn): Name these patterns
+ (they were unnamed before). Fix comments.
+
2018-08-17 Nathan Sidwell <nathan@acm.org>
* cppbuiltin.c: Include "cpplib.h", not "cpp-id-data.h".
diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP
index f0507b5..6770569 100644
--- a/gcc/DATESTAMP
+++ b/gcc/DATESTAMP
@@ -1 +1 @@
-20180817
+20180820
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 6ad2fe0..9ff4728 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,30 @@
+2018-08-20 Nathan Sidwell <nathan@acm.org>
+
+ * c-ada-spec.c (macro_length, dump_ada_macros): Adjust macro parm
+ access.
+
+2018-08-17 Nathan Sidwell <nathan@acm.org>
+
+ * c-cppbuiltin.c (struct lazy_hex_fp_value_struct): Remove macro
+ field.
+ (laxy_hex_fp_value_count): Make unsigned.
+ (lazy_hex_fp_value): Provided with macro & lazy number. Directly
+ manipulate the macro.
+ (builtin_defin_with_hex_fp_value): Adjust callback name, use
+ cpp_define_lazily.
+
+2018-08-17 David Malcolm <dmalcolm@redhat.com>
+
+ * c-format.c (enum format_type): Add gcc_dump_printf_format_type.
+ (gcc_dump_printf_length_specs): New.
+ (gcc_dump_printf_flag_pairs): New.
+ (gcc_dump_printf_flag_specs): New.
+ (gcc_dump_printf_char_table): New.
+ (format_types_orig): Add entry for "gcc_dump_printf".
+ (init_dynamic_diag_info): Set up length_char_specs and
+ conversion_specs for gcc_dump_printf_format_type.
+ (handle_format_attribute): Handle gcc_dump_printf_format_type.
+
2018-08-17 Nathan Sidwell <nathan@acm.org>
* c-ada-spec.c (macro_length, dump_ada_macros): Constify.
diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c
index 5a04f05..035878f 100644
--- a/gcc/c-family/c-format.c
+++ b/gcc/c-family/c-format.c
@@ -46,6 +46,7 @@ enum format_type { printf_format_type, asm_fprintf_format_type,
gcc_diag_format_type, gcc_tdiag_format_type,
gcc_cdiag_format_type,
gcc_cxxdiag_format_type, gcc_gfc_format_type,
+ gcc_dump_printf_format_type,
gcc_objc_string_format_type,
format_type_error = -1};
@@ -463,6 +464,7 @@ static const format_length_info gcc_diag_length_specs[] =
#define gcc_tdiag_length_specs gcc_diag_length_specs
#define gcc_cdiag_length_specs gcc_diag_length_specs
#define gcc_cxxdiag_length_specs gcc_diag_length_specs
+#define gcc_dump_printf_length_specs gcc_diag_length_specs
/* This differs from printf_length_specs only in that "Z" is not accepted. */
static const format_length_info scanf_length_specs[] =
@@ -552,6 +554,7 @@ static const format_flag_pair gcc_diag_flag_pairs[] =
#define gcc_cdiag_flag_pairs gcc_diag_flag_pairs
#define gcc_cxxdiag_flag_pairs gcc_diag_flag_pairs
#define gcc_gfc_flag_pairs gcc_diag_flag_pairs
+#define gcc_dump_printf_flag_pairs gcc_diag_flag_pairs
static const format_flag_spec gcc_diag_flag_specs[] =
{
@@ -567,6 +570,7 @@ static const format_flag_spec gcc_diag_flag_specs[] =
#define gcc_cdiag_flag_specs gcc_diag_flag_specs
#define gcc_cxxdiag_flag_specs gcc_diag_flag_specs
#define gcc_gfc_flag_specs gcc_diag_flag_specs
+#define gcc_dump_printf_flag_specs gcc_diag_flag_specs
static const format_flag_spec scanf_flag_specs[] =
{
@@ -788,6 +792,22 @@ static const format_char_info gcc_gfc_char_table[] =
{ NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
};
+static const format_char_info gcc_dump_printf_char_table[] =
+{
+ /* The conversion specifiers implemented within pp_format. */
+ PP_FORMAT_CHAR_TABLE,
+
+ /* Custom conversion specifiers implemented by dump_pretty_printer. */
+
+ /* E and G require a "gimple *" argument at runtime. */
+ { "EG", 1, STD_C89, { T89_G, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "\"", NULL },
+
+ /* T requires a "tree" at runtime. */
+ { "T", 1, STD_C89, { T89_T, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "\"", NULL },
+
+ { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
+};
+
static const format_char_info scan_char_table[] =
{
/* C89 conversion specifiers. */
@@ -887,6 +907,13 @@ static const format_kind_info format_types_orig[] =
0, 0, 0, 0, 0, 0,
NULL, NULL
},
+ { "gcc_dump_printf", gcc_dump_printf_length_specs,
+ gcc_dump_printf_char_table, "q+#", NULL,
+ gcc_dump_printf_flag_specs, gcc_dump_printf_flag_pairs,
+ FMT_FLAG_ARG_CONVERT,
+ 0, 0, 'p', 0, 'L', 0,
+ NULL, &integer_type_node
+ },
{ "NSString", NULL, NULL, NULL, NULL,
NULL, NULL,
FMT_FLAG_ARG_CONVERT|FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL, 0, 0, 0, 0, 0, 0,
@@ -3971,6 +3998,7 @@ init_dynamic_diag_info (void)
dynamic_format_types[gcc_tdiag_format_type].length_char_specs =
dynamic_format_types[gcc_cdiag_format_type].length_char_specs =
dynamic_format_types[gcc_cxxdiag_format_type].length_char_specs =
+ dynamic_format_types[gcc_dump_printf_format_type].length_char_specs =
diag_ls = (format_length_info *)
xmemdup (gcc_diag_length_specs,
sizeof (gcc_diag_length_specs),
@@ -3997,6 +4025,8 @@ init_dynamic_diag_info (void)
gcc_cdiag_char_table;
dynamic_format_types[gcc_cxxdiag_format_type].conversion_specs =
gcc_cxxdiag_char_table;
+ dynamic_format_types[gcc_dump_printf_format_type].conversion_specs =
+ gcc_dump_printf_char_table;
}
#ifdef TARGET_FORMAT_TYPES
@@ -4151,7 +4181,8 @@ handle_format_attribute (tree *node, tree ARG_UNUSED (name), tree args,
|| info.format_type == gcc_diag_format_type
|| info.format_type == gcc_tdiag_format_type
|| info.format_type == gcc_cdiag_format_type
- || info.format_type == gcc_cxxdiag_format_type)
+ || info.format_type == gcc_cxxdiag_format_type
+ || info.format_type == gcc_dump_printf_format_type)
{
/* Our first time through, we have to make sure that our
format_type data is allocated dynamically and is modifiable. */
@@ -4173,7 +4204,8 @@ handle_format_attribute (tree *node, tree ARG_UNUSED (name), tree args,
else if (info.format_type == gcc_diag_format_type
|| info.format_type == gcc_tdiag_format_type
|| info.format_type == gcc_cdiag_format_type
- || info.format_type == gcc_cxxdiag_format_type)
+ || info.format_type == gcc_cxxdiag_format_type
+ || info.format_type == gcc_dump_printf_format_type)
init_dynamic_diag_info ();
else
gcc_unreachable ();
diff --git a/gcc/common/config/csky/csky-common.c b/gcc/common/config/csky/csky-common.c
new file mode 100644
index 0000000..39095bf
--- /dev/null
+++ b/gcc/common/config/csky/csky-common.c
@@ -0,0 +1,42 @@
+/* Common hooks for CSKY.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ Contributed by C-SKY Microsystems and Mentor Graphics.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "common/common-target.h"
+#include "common/common-target-def.h"
+
+/* Set default optimization options. */
+static const struct default_options csky_option_optimization_table[] =
+ {
+ /* Enable section anchors by default at -O1 or higher. */
+ { OPT_LEVELS_1_PLUS, OPT_fsection_anchors, NULL, 1 },
+ { OPT_LEVELS_NONE, 0, NULL, 0 }
+ };
+
+#undef TARGET_DEFAULT_TARGET_FLAGS
+#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
+
+#undef TARGET_OPTION_OPTIMIZATION_TABLE
+#define TARGET_OPTION_OPTIMIZATION_TABLE csky_option_optimization_table
+
+struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER;
diff --git a/gcc/config.gcc b/gcc/config.gcc
index 17ca0cf..f81cf76 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -1278,6 +1278,70 @@ crisv32-*-linux* | cris-*-linux*)
;;
esac
;;
+csky-*-*)
+ if test x${with_endian} != x; then
+ case ${with_endian} in
+ big|little) ;;
+ *)
+ echo "with_endian=${with_endian} not supported."
+ exit 1
+ ;;
+ esac
+ fi
+ if test x${with_float} != x; then
+ case ${with_float} in
+ soft | hard) ;;
+ *) echo
+ "Unknown floating point type used in --with-float=$with_float"
+ exit 1
+ ;;
+ esac
+ fi
+ tm_file="csky/csky.h"
+ md_file="csky/csky.md"
+ out_file="csky/csky.c"
+ tm_p_file="${tm_p_file} csky/csky-protos.h"
+ extra_options="${extra_options} csky/csky_tables.opt"
+
+ if test x${enable_tpf_debug} = xyes; then
+ tm_defines="${tm_defines} ENABLE_TPF_DEBUG"
+ fi
+
+ case ${target} in
+ csky-*-elf*)
+ tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file} csky/csky-elf.h"
+ tmake_file="csky/t-csky csky/t-csky-elf"
+ default_use_cxa_atexit=no
+ ;;
+ csky-*-linux*)
+ tm_file="dbxelf.h elfos.h gnu-user.h linux.h glibc-stdint.h ${tm_file} csky/csky-linux-elf.h"
+ tmake_file="${tmake_file} csky/t-csky csky/t-csky-linux"
+
+ if test "x${enable_multilib}" = xyes ; then
+ tm_file="$tm_file ./sysroot-suffix.h"
+ tmake_file="${tmake_file} csky/t-sysroot-suffix"
+ fi
+
+ case ${target} in
+ csky-*-linux-gnu*)
+ tm_defines="$tm_defines DEFAULT_LIBC=LIBC_GLIBC"
+ ;;
+ csky-*-linux-uclibc*)
+ tm_defines="$tm_defines DEFAULT_LIBC=LIBC_UCLIBC"
+ default_use_cxa_atexit=no
+ ;;
+ *)
+ echo "Unknown target $target"
+ exit 1
+ ;;
+ esac
+ ;;
+ *)
+ echo "Unknown target $target"
+ exit 1
+ ;;
+ esac
+ ;;
epiphany-*-elf | epiphany-*-rtems*)
tm_file="${tm_file} dbxelf.h elfos.h"
tmake_file="${tmake_file} epiphany/t-epiphany"
@@ -3795,6 +3859,10 @@ case "${target}" in
fi
;;
+ csky-*-*)
+ supported_defaults="cpu endian float"
+ ;;
+
arm*-*-*)
supported_defaults="arch cpu float tune fpu abi mode tls"
for which in cpu tune arch; do
diff --git a/gcc/config/arm/arm-builtins.c b/gcc/config/arm/arm-builtins.c
index 183a7b9..563ca51 100644
--- a/gcc/config/arm/arm-builtins.c
+++ b/gcc/config/arm/arm-builtins.c
@@ -927,6 +927,11 @@ arm_init_simd_builtin_types (void)
(*lang_hooks.types.register_builtin_type) (arm_simd_polyTI_type_node,
"__builtin_neon_poly128");
+ /* Prevent front-ends from transforming poly vectors into string
+ literals. */
+ TYPE_STRING_FLAG (arm_simd_polyQI_type_node) = false;
+ TYPE_STRING_FLAG (arm_simd_polyHI_type_node) = false;
+
/* Init all the element types built by the front-end. */
arm_simd_types[Int8x8_t].eltype = intQI_type_node;
arm_simd_types[Int8x16_t].eltype = intQI_type_node;
diff --git a/gcc/config/csky/constraints.md b/gcc/config/csky/constraints.md
new file mode 100644
index 0000000..e08f7f8
--- /dev/null
+++ b/gcc/config/csky/constraints.md
@@ -0,0 +1,174 @@
+;; Constraints for C-SKY.
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+;; Contributed by C-SKY Microsystems and Mentor Graphics.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>. */
+
+;; Register constraints.
+
+(define_register_constraint "a" "MINI_REGS" "r0 - r7")
+(define_register_constraint "b" "LOW_REGS" "r0 - r15")
+(define_register_constraint "c" "C_REGS" "C register")
+(define_register_constraint "y" "HILO_REGS" "HI and LO registers")
+(define_register_constraint "l" "LO_REGS" "LO register")
+(define_register_constraint "h" "HI_REGS" "HI register")
+(define_register_constraint "v" "V_REGS" "vector registers")
+(define_register_constraint "z" "SP_REGS" "SP register")
+
+
+;; Memory and misc constraints.
+
+(define_memory_constraint "Q"
+ "Memory operands with base register, index register and short displacement for FPUV2"
+ (match_test "csky_valid_fpuv2_mem_operand (op)"))
+
+(define_constraint "R"
+ "Memory operands whose address is a label_ref"
+ (and (match_code "mem")
+ (match_test "GET_CODE (XEXP (op, 0)) == LABEL_REF")))
+
+(define_constraint "S"
+ "Symbol reference with optional offset"
+ (match_test "csky_symbolic_address_p (op)"))
+
+
+;; Constant integer constraints.
+
+(define_constraint "I"
+ "Constant in range [0, 65535]"
+ (and (match_code "const_int")
+ (match_test "CSKY_CONST_OK_FOR_I (ival)")))
+
+(define_constraint "J"
+ "Constant in range [1, 32]"
+ (and (match_code "const_int")
+ (match_test "CSKY_CONST_OK_FOR_J (ival)")))
+
+(define_constraint "K"
+ "Constant in range [0, 31]"
+ (and (match_code "const_int")
+ (match_test "CSKY_CONST_OK_FOR_K (ival)")))
+
+(define_constraint "L"
+ "Constant in range [1, 8]"
+ (and (match_code "const_int")
+ (match_test "CSKY_CONST_OK_FOR_L (ival)")))
+
+(define_constraint "M"
+ "Constant in range [1, 4096]"
+ (and (match_code "const_int")
+ (match_test "CSKY_CONST_OK_FOR_M (ival)")))
+
+(define_constraint "N"
+ "Constant in range [1, 256]"
+ (and (match_code "const_int")
+ (match_test "CSKY_CONST_OK_FOR_N (ival)")))
+
+(define_constraint "O"
+ "Constant in range [0, 4095]"
+ (and (match_code "const_int")
+ (match_test "CSKY_CONST_OK_FOR_O (ival)")))
+
+(define_constraint "P"
+ "Constant in range [4, 508] that is divisible by 4"
+ (and (match_code "const_int")
+ (match_test "CSKY_CONST_OK_FOR_P (ival)")))
+
+(define_constraint "T"
+ "Constant in range [-256, -1]"
+ (and (match_code "const_int")
+ (match_test "CSKY_CONST_OK_FOR_T (ival)")))
+
+(define_constraint "Ua"
+ "Constant 0"
+ (and (match_code "const_int")
+ (match_test "ival == 0")))
+
+(define_constraint "Ub"
+ "Unsigned int that is an exact power of 2"
+ (and (match_code "const_int")
+ (match_test "CSKY_CONST_OK_FOR_Ub (ival)")))
+
+(define_constraint "Uc"
+ "Unsigned int X such that X+1 is an exact power of 2"
+ (and (match_code "const_int")
+ (match_test "CSKY_CONST_OK_FOR_Uc (ival)")))
+
+(define_constraint "Ud"
+ "64-bit int whose high/low words separately satisfy I, Ub, or Uc"
+ (and (match_code "const_int")
+ (match_test "CSKY_CONST_OK_FOR_Ud (ival)")))
+
+(define_constraint "Ug"
+ "Constant in range [-508, -4] that is divisible by 4"
+ (and (match_code "const_int")
+ (match_test "CSKY_CONST_OK_FOR_Ug (ival)")))
+
+(define_constraint "Uh"
+ "Constant in range [-31, 0]"
+ (and (match_code "const_int")
+ (match_test "CSKY_CONST_OK_FOR_Uh (ival)")))
+
+(define_constraint "Uj"
+ "Constant in range [4, 1024] that is divisible by 4"
+ (and (match_code "const_int")
+ (match_test "CSKY_CONST_OK_FOR_Uj (ival)")))
+
+(define_constraint "Uk"
+ "Constant in range [1, 65536]"
+ (and (match_code "const_int")
+ (match_test "CSKY_CONST_OK_FOR_Uk (ival)")))
+
+(define_constraint "Ul"
+ "Constant in range [-1024, -4] that is divisible by 4"
+ (and (match_code "const_int")
+ (match_test "CSKY_CONST_OK_FOR_Ul (ival)")))
+
+(define_constraint "Um"
+ "Constant in range [-4096, -1]"
+ (and (match_code "const_int")
+ (match_test "CSKY_CONST_OK_FOR_Um (ival)")))
+
+(define_constraint "Un"
+ "Constant whose low 16 bits are all zeros"
+ (and (match_code "const_int")
+ (match_test "CSKY_CONST_OK_FOR_MOVIH (ival)")))
+
+(define_constraint "Uo"
+ "Constant that can be synthesized with an extra instruction"
+ (and (match_code "const_int")
+ (match_test "csky_inlinable_constant (ival)")))
+
+(define_constraint "Up"
+ "Constant in range [0, 255]"
+ (and (match_code "const_int")
+ (match_test "CSKY_CONST_OK_FOR_N (ival + 1)")))
+
+(define_constraint "Uq"
+ "Constant in range [0, 1020] that is divisible by 4"
+ (and (match_code "const_int")
+ (match_test "CSKY_CONST_OK_FOR_Uj (ival + 4)")))
+
+(define_constraint "Ur"
+ "Constant in range [-1020, -4] that is divisible by 4"
+ (and (match_code "const_int")
+ (match_test "CSKY_CONST_OK_FOR_Uj (-ival + 4)")))
+
+(define_constraint "Us"
+ "Constant in range [-8, -1]"
+ (and (match_code "const_int")
+ (match_test "CSKY_CONST_OK_FOR_US (ival)")))
diff --git a/gcc/config/csky/csky-elf.h b/gcc/config/csky/csky-elf.h
new file mode 100644
index 0000000..822caed
--- /dev/null
+++ b/gcc/config/csky/csky-elf.h
@@ -0,0 +1,81 @@
+/* Declarations for bare-metal C-SKY targets.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ Contributed by C-SKY Microsystems and Mentor Graphics.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+
+/******************************************************************
+ * Run-time Target Specification *
+ ******************************************************************/
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC \
+ "crt0.o%s crti.o%s crtbegin.o%s"
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC "crtend.o%s crtn.o%s"
+
+#undef CC1_SPEC
+#define CC1_SPEC \
+ "%{EB:-EB} \
+ %{EL:-EL} \
+ %{fpic|fPIC:-DPIC} \
+ %{march=ck803s:-march=ck803} \
+ "
+
+#undef ASM_SPEC
+#define ASM_SPEC \
+ "%{mbig-endian:-mbig-endian} \
+ %{EB:-EB} \
+ %{EL:-EL} \
+ %{fpic|fPIC:-pic} \
+ %{mcpu=*:-mcpu=%*} \
+ %{march=*:-march=%*} \
+ %{mhard-float:-mhard-float} \
+ %{melrw:-melrw} \
+ %{mno-elrw:-mno-elrw} \
+ %{mistack:-mistack} \
+ %{mno-istack:-mno-istack} \
+ %{mmp:-mmp} \
+ %{mcp:-mcp} \
+ %{mcache:-mcache} \
+ %{msecurity|mmac:-msecurity} \
+ %{mtrust:-mtrust} \
+ %{mdsp:-mdsp} \
+ %{medsp:-medsp} \
+ %{mvdsp:-mvdsp} \
+ "
+
+#undef LINK_SPEC
+#define LINK_SPEC \
+"%{mbig-endian:-EB} \
+ %{EB:-EB} \
+ %{EL:-EL} -X"
+
+#undef LIB_SPEC
+#define LIB_SPEC \
+ "%{pthread:-lpthread} -lc %{mccrt:-lcc-rt}"
+/* FIXME add this to LIB_SPEC when need */
+/* %{!shared:%{profile:-lc_p}%{!profile:-lc}}" */
+
+
+#define CPLUSPLUS_CPP_SPEC "-D_GNU_SOURCE %(cpp)"
+
+/* Disable features only for Linux toolchains. */
+#undef TARGET_POSIX_IO
+#define TARGET_CSKY_LINUX 0
diff --git a/gcc/config/csky/csky-linux-elf.h b/gcc/config/csky/csky-linux-elf.h
new file mode 100644
index 0000000..19a553c
--- /dev/null
+++ b/gcc/config/csky/csky-linux-elf.h
@@ -0,0 +1,132 @@
+/* Declarations for C-SKY targets running Linux.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ Contributed by C-SKY Microsystems and Mentor Graphics.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+/******************************************************************
+ * Run-time Target Specification *
+ ******************************************************************/
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC \
+ "%{!shared: %{pie:Scrt1.o%s;:crt1.o%s}} \
+ crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s}"
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC \
+ "%{shared|pie:crtendS.o%s;:crtend.o%s} crtn.o%s"
+
+#undef CC1_SPEC
+#define CC1_SPEC \
+ "%{EB:-EB} \
+ %{EL:-EL} \
+ "
+
+#undef ASM_SPEC
+#define ASM_SPEC \
+ "%{mbig-endian:-mbig-endian} \
+ %{EB:-EB} \
+ %{EL:-EL} \
+ %{fpic|fPIC:-pic} \
+ %{mcpu=*:-mcpu=%*} \
+ %{march=*:-march=%*} \
+ %{mhard-float:-mhard-float} \
+ %{melrw:-melrw} \
+ %{mno-elrw:-mno-elrw} \
+ %{mistack:-mistack} \
+ %{mno-istack:-mno-istack} \
+ %{mmp:-mmp} \
+ %{mcp:-mcp} \
+ %{mcache:-mcache} \
+ %{msecurity|mmac:-msecurity} \
+ %{mtrust:-mtrust} \
+ %{mdsp:-mdsp} \
+ %{medsp:-medsp} \
+ %{mvdsp:-mvdsp} \
+ "
+
+#define LINUX_DYNAMIC_LINKER "/lib/ld.so.1"
+
+#define LINUX_TARGET_LINK_SPEC "%{h*} %{version:-v} \
+ %{b} \
+ %{static:-Bstatic} \
+ %{shared:-shared} \
+ %{symbolic:-Bsymbolic} \
+ %{!static: \
+ %{rdynamic:-export-dynamic} \
+ %{!shared:-dynamic-linker " LINUX_DYNAMIC_LINKER "}} \
+ -X \
+ %{mbig-endian:-EB} %{mlittle-endian:-EL} \
+ %{EB:-EB} %{EL:-EL}"
+
+
+#undef LINK_SPEC
+#define LINK_SPEC LINUX_TARGET_LINK_SPEC
+
+
+#undef LIB_SPEC
+#define LIB_SPEC \
+ "%{pthread:-lpthread} -lc %{mccrt:-lcc-rt}"
+/* FIXME add this to LIB_SPEC when need */
+/* %{!shared:%{profile:-lc_p}%{!profile:-lc}}" */
+
+#define TARGET_OS_CPP_BUILTINS() \
+ do \
+ { \
+ GNU_USER_TARGET_OS_CPP_BUILTINS (); \
+ } \
+ while (0)
+
+/* In crtstuff.c to control section in where code resides.
+ We have to write it as asm code. */
+#ifdef __PIC__
+#define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC) \
+ asm (SECTION_OP "\n" \
+ "\tgrs\tr3, .Lgetpc_"#FUNC"\n\t" \
+ ".Lgetpc_"#FUNC":\n\t" \
+ "\tlrw\tr2,\t.Lgetpc_"#FUNC"@GOTPC\n\t" \
+ "\taddu\tr3, r2\n\t" \
+ "\tlrw\tr2, "#FUNC"@GOTOFF\n\t" \
+ "\taddu\tr2, r3\n\t" \
+ "\tjsr\tr2\n\t"); \
+ FORCE_CODE_SECTION_ALIGN \
+ asm (TEXT_SECTION_ASM_OP);
+#endif
+
+#undef CPP_SPEC
+#define CPP_SPEC "%{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}"
+
+#undef FUNCTION_PROFILER
+#define SAVE_LR \
+ "push\tlr"
+#define FUNCTION_PROFILER(file, labelno) \
+ fprintf (file, "\t%s\n\tjbsr\t_mcount\n", SAVE_LR);
+#define NO_PROFILE_COUNTERS 1
+
+/* Enable features only for Linux toolchains. */
+#define TARGET_CSKY_LINUX 1
+
+/* Clear the instruction cache from `BEG' to `END'. */
+#define CLEAR_INSN_CACHE(BEG, END) \
+ cacheflush (BEG, END-BEG, 3)
+
+/* For __clear_cache in libgcc2.c. The declaration is copied from
+ <sys/cachectl.h>. */
+#ifdef IN_LIBGCC2
+extern int cacheflush (void *__addr, const int __nbytes, const int __op);
+#endif
diff --git a/gcc/config/csky/csky-protos.h b/gcc/config/csky/csky-protos.h
new file mode 100644
index 0000000..c10267a
--- /dev/null
+++ b/gcc/config/csky/csky-protos.h
@@ -0,0 +1,71 @@
+/* Prototype declarations for the C-SKY back end.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ Contributed by C-SKY Microsystems and Mentor Graphics.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_CSKY_PROTOS_H
+#define GCC_CSKY_PROTOS_H
+
+extern bool csky_simple_addr_operand_p (rtx);
+extern bool csky_symbolic_address_p (rtx);
+extern bool csky_legitimate_pic_operand_p (rtx);
+
+extern void csky_cpu_cpp_builtins (cpp_reader *);
+
+extern bool csky_inlinable_constant (HOST_WIDE_INT value);
+extern bool csky_shifted_imm8_constant (unsigned HOST_WIDE_INT,
+ unsigned int *, unsigned int *);
+extern bool csky_valid_fpuv2_mem_operand (rtx);
+
+extern bool csky_minipool_load_p (rtx_insn *);
+extern const char *csky_output_move (rtx insn, rtx *, machine_mode);
+extern const char *csky_output_movedouble (rtx *, machine_mode);
+extern const char *csky_output_ck801_move (rtx, rtx *, machine_mode);
+extern const char *csky_output_ck801_movedouble (rtx *, machine_mode);
+extern char *csky_output_call (rtx *, int);
+extern const char *csky_output_casesi (rtx *);
+
+extern bool csky_split_and (rtx *);
+extern bool csky_split_ior (rtx *);
+extern bool csky_split_xor (rtx *);
+
+#ifdef RTX_CODE
+extern bool csky_emit_compare (enum rtx_code, rtx, rtx);
+extern bool csky_emit_compare_float (enum rtx_code, rtx, rtx);
+#endif /* RTX_CODE */
+
+extern rtx csky_return_addr (int, rtx);
+extern void csky_init_expanders (void);
+extern HOST_WIDE_INT csky_initial_elimination_offset (int, int);
+extern void csky_expand_prologue (void);
+extern void csky_expand_epilogue (void);
+extern const char *csky_output_return_instruction (void);
+extern void csky_set_eh_return_address (rtx, rtx);
+
+extern bool csky_symbol_mentioned_p (rtx);
+extern bool csky_label_mentioned_p (rtx);
+extern rtx csky_legitimize_pic_address (rtx, rtx, bool);
+
+extern bool csky_tls_referenced_p (rtx);
+extern rtx csky_legitimize_tls_address (rtx, rtx);
+
+extern int csky_compute_pushpop_length (rtx *);
+
+extern int csky_default_branch_cost (bool, bool);
+extern bool csky_default_logical_op_non_short_circuit (void);
+#endif /* GCC_CSKY_PROTOS_H */
diff --git a/gcc/config/csky/csky.c b/gcc/config/csky/csky.c
new file mode 100644
index 0000000..a9e196b
--- /dev/null
+++ b/gcc/config/csky/csky.c
@@ -0,0 +1,6795 @@
+/* GCC backend functions for C-SKY targets.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ Contributed by C-SKY Microsystems and Mentor Graphics.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+#define IN_TARGET_CODE 1
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "memmodel.h"
+#include "backend.h"
+#include "target.h"
+#include "rtl.h"
+#include "tree.h"
+#include "cfghooks.h"
+#include "df.h"
+#include "tm_p.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "optabs.h"
+#include "regs.h"
+#include "emit-rtl.h"
+#include "recog.h"
+#include "cgraph.h"
+#include "c-family/c-common.h"
+#include "cpplib.h"
+#include "diagnostic-core.h"
+#include "alias.h"
+#include "fold-const.h"
+#include "stor-layout.h"
+#include "calls.h"
+#include "varasm.h"
+#include "output.h"
+#include "insn-attr.h"
+#include "flags.h"
+#include "reload.h"
+#include "explow.h"
+#include "expr.h"
+#include "cfgrtl.h"
+#include "sched-int.h"
+#include "common/common-target.h"
+#include "langhooks.h"
+#include "intl.h"
+#include "libfuncs.h"
+#include "params.h"
+#include "opts.h"
+#include "dumpfile.h"
+#include "target-globals.h"
+#include "builtins.h"
+#include "tm-constrs.h"
+#include "rtl-iter.h"
+#include "pass_manager.h"
+#include "tree-pass.h"
+#include "context.h"
+
+/* This file should be included last. */
+#include "target-def.h"
+
+/* Stack and register size macros. */
+
+#define CSKY_NUM_WORDS(SIZE) \
+ (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+#define CSKY_NUM_REGS(MODE) \
+ CSKY_NUM_WORDS (GET_MODE_SIZE (MODE))
+#define CSKY_STACK_ALIGN(SIZE) \
+ (CSKY_NUM_WORDS (SIZE) * UNITS_PER_WORD)
+
+/* Offsets and range macros. */
+
+#define CSKY_LD16_MAX_OFFSET(MODE) \
+ (31 * GET_MODE_SIZE (MODE))
+#define CSKY_LD32_MAX_OFFSET(MODE) \
+ (4095 * GET_MODE_SIZE (MODE))
+#define CSKY_LD16_OFFSET_MASK(MODE) \
+ (CSKY_LD16_MAX_OFFSET (MODE) + GET_MODE_SIZE (MODE) - 1)
+
+#define CSKY_ADDI16_MAX_IMM 256
+#define CSKY_SUBI16_MAX_IMM 256
+
+#define CSKY_CONSTPOOL_LABEL_PREFIX "LCP"
+
+/* Array of the smallest class containing reg number REGNO, indexed by
+ REGNO. Used by REGNO_REG_CLASS. */
+enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER] =
+{
+ /* Registers r0-r7. */
+ MINI_REGS, MINI_REGS, MINI_REGS, MINI_REGS,
+ MINI_REGS, MINI_REGS, MINI_REGS, MINI_REGS,
+ /* Registers r8-r15. */
+ LOW_REGS, LOW_REGS, LOW_REGS, LOW_REGS,
+ LOW_REGS, LOW_REGS, SP_REGS, LOW_REGS,
+ /* Registers r16-r31. */
+ GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
+ GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
+ GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
+ GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
+ /* Reserved. */
+ RESERVE_REGS,
+ /* CC,HI,LO registers. */
+ C_REGS, HI_REGS, LO_REGS,
+ /* Reserved. */
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ RESERVE_REGS, RESERVE_REGS, RESERVE_REGS, RESERVE_REGS,
+ /* Vec registers. */
+ V_REGS, V_REGS, V_REGS, V_REGS,
+ V_REGS, V_REGS, V_REGS, V_REGS,
+ V_REGS, V_REGS, V_REGS, V_REGS,
+ V_REGS, V_REGS, V_REGS, V_REGS,
+ /* Reserved. */
+ RESERVE_REGS, RESERVE_REGS,
+ /* Register epc. */
+ OTHER_REGS
+};
+
+/* Arrays that map GCC register numbers to debugger register numbers,
+ '-1' means that is INVALID_REGNUM.
+ TODO: which rules according to here ? */
+const int csky_dbx_regno[FIRST_PSEUDO_REGISTER] =
+{
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ -1, -1, 36, 37, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67,
+ 68, 69, 70, 71, -1, -1, 72
+};
+
+/* Table of machine attributes. */
+static tree csky_handle_fndecl_attribute (tree *, tree, tree, int, bool *);
+static tree csky_handle_isr_attribute (tree *, tree, tree, int, bool *);
+static const struct attribute_spec csky_attribute_table[] =
+{
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req,
+ affects_type_identity, handler, exclude } */
+ { "naked", 0, 0, true, false, false, false, csky_handle_fndecl_attribute, NULL },
+ /* Interrupt Service Routines have special prologue and epilogue requirements. */
+ { "interrupt", 0, 1, false, false, false, false, csky_handle_isr_attribute, NULL },
+ { "isr", 0, 1, false, false, false, false, csky_handle_isr_attribute, NULL },
+ { NULL, 0, 0, false, false, false, false, NULL, NULL }
+};
+
+/* A C structure for machine-specific, per-function data.
+ This is added to the cfun structure. */
+typedef struct GTY(()) machine_function
+{
+ /* Records if LR has to be saved for far jumps. */
+ int far_jump_used;
+ /* Records the type of the current function. */
+ unsigned long func_type;
+ /* Record if the function has a variable argument list. */
+ int uses_anonymous_args;
+
+ /* Stack frame layout information. If frame_init_p is true,
+ these fields have been initialized and don't need to be
+ recomputed. */
+ unsigned int reg_mask; /* non-volatile reg saves */
+ int arg_size; /* stdarg spills (bytes) */
+ int reg_size; /* non-volatile reg saves (bytes) */
+ int local_size; /* locals */
+ int outbound_size; /* arg overflow on calls out */
+ int frame_size; /* total static size of stack frame */
+ int local_offset;
+ int reg_offset;
+ int arg_offset;
+ int frame_init_p;
+
+} machine_function;
+
+/* These macros are for the func_type values above. */
+#define CSKY_FT_TYPE_MASK ((1 << 3) - 1)
+#define CSKY_FT_UNKNOWN 0 /* Type not been determined */
+#define CSKY_FT_NORMAL 1 /* Normal function */
+#define CSKY_FT_ISR 4 /* Interrupt service routine */
+#define CSKY_FT_FIQ 5 /* Fast interrupt service routine */
+#define CSKY_FT_EXCEPTION 6 /* Exception handler */
+#define CSKY_FT_INTERRUPT (1 << 2) /* overlap CSKY_FT_ISR */
+#define CSKY_FT_NAKED (1 << 3) /* No prologue and epilogue */
+#define CSKY_FUNCTION_TYPE(t) ((t) & CSKY_FT_TYPE_MASK)
+#define CSKY_FUNCTION_IS_INTERRUPT(t) ((t) & CSKY_FT_INTERRUPT)
+#define CSKY_FUNCTION_IS_NAKED(t) ((t) & CSKY_FT_NAKED)
+
+struct csky_processors
+{
+ const char *const name;
+ enum csky_processor_type core;
+ const char *arch;
+ enum csky_base_architecture base_arch;
+ enum csky_isa_feature isa_bits[CSKY_ISA_FEATURE_GET (max)];
+};
+
+static struct csky_processors all_cores[] =
+{
+#undef CSKY_CORE
+#define CSKY_CORE(NAME, CORE, X, ARCH, ISA) \
+ {NAME, TARGET_CPU_##CORE, #ARCH, CSKY_BASE_ARCH_##ARCH, \
+ {ISA CSKY_ISA_FEATURE_GET (none)}},
+#include "csky_cores.def"
+#undef CSKY_CORE
+ {NULL, TARGET_CPU_csky_none, NULL, CSKY_BASE_ARCH_NONE, \
+ {CSKY_ISA_FEATURE_GET (none)}}
+};
+
+static struct csky_processors all_architectures[] =
+{
+#undef CSKY_ARCH
+#define CSKY_ARCH(NAME, CORE, ARCH, ISA) \
+ {NAME, TARGET_CPU_##CORE, #ARCH, CSKY_BASE_ARCH_##ARCH, \
+ {ISA CSKY_ISA_FEATURE_GET (none)}},
+#include "csky_cores.def"
+#undef CSKY_ARCH
+ {NULL, TARGET_CPU_csky_none, NULL, CSKY_BASE_ARCH_NONE, \
+ {CSKY_ISA_FEATURE_GET (none)}}
+};
+
+struct csky_fpu_desc
+{
+ const char *name;
+ enum csky_isa_feature isa_bits[CSKY_ISA_FEATURE_GET (max)];
+};
+
+static const struct csky_fpu_desc all_fpus[] =
+{
+#undef CSKY_FPU
+#define CSKY_FPU(NAME, CNAME, ISA) \
+ {NAME, {ISA CSKY_ISA_FEATURE_GET (none)}},
+#include "csky_cores.def"
+#undef CSKY_FPU
+};
+
+/* Active target architecture. */
+struct csky_build_target
+{
+ /* Name of the target CPU, if known, or NULL if the target CPU was not
+ specified by the user (and inferred from the -march option). */
+ const char *core_name;
+ /* Name of the target ARCH. NULL if there is a selected CPU. */
+ const char *arch_name;
+ /* Preprocessor substring (never NULL). */
+ const char *arch_pp_name;
+ /* CPU identifier for the core we're compiling for (architecturally). */
+ enum csky_processor_type arch_core;
+ /* The base architecture value. */
+ enum csky_base_architecture base_arch;
+ /* Bitmap encapsulating the isa_bits for the target environment. */
+ sbitmap isa;
+};
+
+struct csky_build_target csky_active_target;
+
+/* The following are used in the .md file as equivalents to bits. */
+int csky_arch_isa_features[CSKY_ISA_FEATURE_GET (max)] = {0};
+
+/* The highest CSKY architecture version supported by the target. */
+enum csky_base_architecture csky_base_arch = CSKY_TARGET_ARCH_GET (NONE);
+
+/* Forward definitions of types. */
+typedef struct minipool_node Mnode;
+typedef struct minipool_fixup Mfix;
+
+static GTY(()) int tls_labelno;
+
+
+/* Maximum constant offset that can be added/subtracted from SP in a
+ single instruction. For ck801, this is for addsp/subsp, otherwise
+ it is the range of addi/subi. */
+#define CSKY_MAX_SP_ADJUST \
+ (CSKY_TARGET_ARCH (CK801) ? 508 : 4096)
+
+
+/* Implement TARGET_CPU_CPP_BUILTINS. */
+
+#define builtin_define(MACRO) cpp_define (pfile, MACRO)
+
+void
+csky_cpu_cpp_builtins (cpp_reader *pfile)
+{
+ const char *arch_name = csky_active_target.arch_pp_name;
+ char *pp_name = (char *) alloca (1 + strlen (arch_name) + 4);
+ sprintf (pp_name, "__%s__", arch_name);
+ builtin_define (pp_name);
+
+ builtin_define ("__csky__=2");
+ builtin_define ("__CSKY__=2");
+ builtin_define ("__ckcore__=2");
+ builtin_define ("__CKCORE__=2");
+
+ builtin_define ("__CSKYABIV2__");
+ builtin_define ("__cskyabiv2__");
+ builtin_define ("__CSKYABI__=2");
+ builtin_define ("__cskyabi__=2");
+
+ if (TARGET_BIG_ENDIAN)
+ {
+ builtin_define ("__ckcoreBE__");
+ builtin_define ("__cskyBE__");
+ builtin_define ("__cskybe__");
+ builtin_define ("__CSKYBE__");
+ }
+ else
+ {
+ builtin_define ("__ckcoreLE__");
+ builtin_define ("__cskyLE__");
+ builtin_define ("__cskyle__");
+ builtin_define ("__CSKYLE__");
+ }
+
+ if (TARGET_HARD_FLOAT)
+ {
+ builtin_define ("__csky_hard_float__");
+ builtin_define ("__CSKY_HARD_FLOAT__");
+ }
+ else
+ {
+ builtin_define ("__csky_soft_float__");
+ builtin_define ("__CSKY_SOFT_FLOAT__");
+ }
+
+ if (CSKY_ISA_FEATURE (fpv2_sf))
+ {
+ builtin_define ("__csky_fpuv2__");
+ builtin_define ("__CSKY_FPUV2__");
+ }
+
+ if (TARGET_ELRW)
+ {
+ builtin_define ("__csky_elrw__");
+ builtin_define ("__CSKY_ELRW__");
+ }
+ if (TARGET_ISTACK)
+ {
+ builtin_define ("__csky_istack__");
+ builtin_define ("__CSKY_ISTACK__");
+ }
+ if (TARGET_MP)
+ {
+ builtin_define ("__csky_mp__");
+ builtin_define ("__CSKY_MP__");
+ }
+ if (TARGET_CP)
+ {
+ builtin_define ("__csky_cp__");
+ builtin_define ("__CSKY_CP__");
+ }
+ if (TARGET_CACHE)
+ {
+ builtin_define ("__csky_cache__");
+ builtin_define ("__CSKY_CACHE__");
+ }
+ if (TARGET_SECURITY)
+ {
+ builtin_define ("__csky_security__");
+ builtin_define ("__CSKY_SECURITY__");
+ }
+ if (TARGET_TRUST)
+ {
+ builtin_define ("__csky_trust__");
+ builtin_define ("__CSKY_TRUST__");
+ }
+ if (TARGET_DSP)
+ {
+ builtin_define ("__csky_dsp__");
+ builtin_define ("__CSKY_DSP__");
+ }
+ if (TARGET_EDSP)
+ {
+ builtin_define ("__csky_edsp__");
+ builtin_define ("__CSKY_EDSP__");
+ }
+ if (TARGET_VDSP)
+ {
+ builtin_define ("__csky_vdsp__");
+ builtin_define ("__CSKY_VDSP__");
+ }
+}
+
+
+/******************************************************************
+ * Storage Layout *
+ ******************************************************************/
+
+
+#undef TARGET_PROMOTE_FUNCTION_MODE
+#define TARGET_PROMOTE_FUNCTION_MODE \
+ default_promote_function_mode_always_promote
+
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT csky_constant_alignment
+
+
+/******************************************************************
+ * Stack Layout and Calling Conventions *
+ ******************************************************************/
+
+#undef TARGET_CAN_ELIMINATE
+#define TARGET_CAN_ELIMINATE csky_can_eliminate
+
+#undef TARGET_FUNCTION_ARG
+#define TARGET_FUNCTION_ARG csky_function_arg
+
+#undef TARGET_FUNCTION_ARG_ADVANCE
+#define TARGET_FUNCTION_ARG_ADVANCE csky_function_arg_advance
+
+#undef TARGET_FUNCTION_VALUE
+#define TARGET_FUNCTION_VALUE csky_function_value
+
+#undef TARGET_LIBCALL_VALUE
+#define TARGET_LIBCALL_VALUE csky_libcall_value
+
+#undef TARGET_FUNCTION_VALUE_REGNO_P
+#define TARGET_FUNCTION_VALUE_REGNO_P csky_function_value_regno_p
+
+#undef TARGET_SPLIT_COMPLEX_ARG
+#define TARGET_SPLIT_COMPLEX_ARG hook_bool_const_tree_true
+
+#undef TARGET_PROMOTE_PROTOTYPES
+#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
+
+#undef TARGET_MUST_PASS_IN_STACK
+#define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
+
+#undef TARGET_ARG_PARTIAL_BYTES
+#define TARGET_ARG_PARTIAL_BYTES csky_arg_partial_bytes
+
+#undef TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE hook_pass_by_reference_must_pass_in_stack
+
+#undef TARGET_ASM_OUTPUT_MI_THUNK
+#define TARGET_ASM_OUTPUT_MI_THUNK csky_output_mi_thunk
+
+#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
+#define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
+ hook_bool_const_tree_hwi_hwi_const_tree_true
+
+#undef TARGET_ASM_FUNCTION_PROLOGUE
+#define TARGET_ASM_FUNCTION_PROLOGUE csky_output_function_prologue
+
+#undef TARGET_ASM_FUNCTION_EPILOGUE
+#define TARGET_ASM_FUNCTION_EPILOGUE csky_output_function_epilogue
+
+#undef TARGET_WARN_FUNC_RETURN
+#define TARGET_WARN_FUNC_RETURN csky_warn_func_return
+
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY csky_return_in_memory
+
+
+/******************************************************************
+ * Implementing the Varargs Macros *
+ ******************************************************************/
+
+
+#undef TARGET_SETUP_INCOMING_VARARGS
+#define TARGET_SETUP_INCOMING_VARARGS csky_setup_incoming_varargs
+
+
+/******************************************************************
+ * Implicit Calls to Library Routines *
+ ******************************************************************/
+
+
+#undef TARGET_INIT_LIBFUNCS
+#define TARGET_INIT_LIBFUNCS csky_init_libfuncs
+
+
+/******************************************************************
+ * Dividing the Output into Sections (Texts, Data, . . . ) *
+ ******************************************************************/
+
+
+#undef TARGET_HAVE_TLS
+#define TARGET_HAVE_TLS TARGET_CSKY_LINUX
+
+
+/******************************************************************
+ * Defining target-specific uses of __attribute__ *
+ ******************************************************************/
+
+
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE csky_attribute_table
+
+#undef TARGET_OPTION_OVERRIDE
+#define TARGET_OPTION_OVERRIDE csky_option_override
+
+
+/* Implement the BRANCH_COST target macro. */
+
+int
+csky_default_branch_cost (bool speed_p ATTRIBUTE_UNUSED,
+ bool predictable_p ATTRIBUTE_UNUSED)
+{
+ return csky_branch_cost;
+}
+
+bool
+csky_default_logical_op_non_short_circuit (void)
+{
+ return BRANCH_COST (optimize_function_for_speed_p (cfun), false) >= 2;
+}
+
+/******************************************************************
+ * Register Usage *
+ ******************************************************************/
+
+#undef TARGET_HARD_REGNO_NREGS
+#define TARGET_HARD_REGNO_NREGS csky_hard_regno_nregs
+
+#undef TARGET_HARD_REGNO_MODE_OK
+#define TARGET_HARD_REGNO_MODE_OK csky_hard_regno_mode_ok
+
+#undef TARGET_MODES_TIEABLE_P
+#define TARGET_MODES_TIEABLE_P csky_modes_tieable_p
+
+#undef TARGET_CAN_CHANGE_MODE_CLASS
+#define TARGET_CAN_CHANGE_MODE_CLASS csky_can_change_mode_class
+
+#undef TARGET_CONDITIONAL_REGISTER_USAGE
+#define TARGET_CONDITIONAL_REGISTER_USAGE csky_conditional_register_usage
+
+#undef TARGET_CLASS_LIKELY_SPILLED_P
+#define TARGET_CLASS_LIKELY_SPILLED_P csky_class_likely_spilled_p
+
+#undef TARGET_PREFERRED_RELOAD_CLASS
+#define TARGET_PREFERRED_RELOAD_CLASS csky_preferred_reload_class
+
+#undef TARGET_CLASS_MAX_NREGS
+#define TARGET_CLASS_MAX_NREGS csky_class_max_nregs
+
+#undef TARGET_SECONDARY_RELOAD
+#define TARGET_SECONDARY_RELOAD csky_secondary_reload
+
+#undef TARGET_SPILL_CLASS
+#define TARGET_SPILL_CLASS csky_spill_class
+
+
+/******************************************************************
+ * Addressing Modes *
+ ******************************************************************/
+
+
+#undef TARGET_CANNOT_FORCE_CONST_MEM
+#define TARGET_CANNOT_FORCE_CONST_MEM csky_cannot_force_const_mem
+
+#undef TARGET_LEGITIMATE_CONSTANT_P
+#define TARGET_LEGITIMATE_CONSTANT_P csky_legitimate_constant_p
+
+#undef TARGET_LEGITIMIZE_ADDRESS
+#define TARGET_LEGITIMIZE_ADDRESS csky_legitimize_address
+
+#undef TARGET_LEGITIMATE_ADDRESS_P
+#define TARGET_LEGITIMATE_ADDRESS_P csky_legitimate_address_p
+
+
+/******************************************************************
+ * Others *
+ ******************************************************************/
+
+
+#undef TARGET_CANNOT_COPY_INSN_P
+#define TARGET_CANNOT_COPY_INSN_P csky_cannot_copy_insn_p
+
+
+/******************************************************************
+ * Assembler Format *
+ ******************************************************************/
+
+
+#undef TARGET_PRINT_OPERAND
+#define TARGET_PRINT_OPERAND csky_print_operand
+
+#undef TARGET_PRINT_OPERAND_ADDRESS
+#define TARGET_PRINT_OPERAND_ADDRESS csky_print_operand_address
+
+#undef TARGET_ASM_UNALIGNED_HI_OP
+#define TARGET_ASM_UNALIGNED_HI_OP "\t.short\t"
+
+#undef TARGET_ASM_UNALIGNED_SI_OP
+#define TARGET_ASM_UNALIGNED_SI_OP "\t.long\t"
+
+#undef TARGET_DWARF_REGISTER_SPAN
+#define TARGET_DWARF_REGISTER_SPAN csky_dwarf_register_span
+
+
+/******************************************************************
+ * Miscellaneous Parameters *
+ ******************************************************************/
+
+
+#undef TARGET_MACHINE_DEPENDENT_REORG
+#define TARGET_MACHINE_DEPENDENT_REORG csky_reorg
+
+#undef TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS
+#define TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS csky_allocate_stack_slots_for_args
+
+#undef TARGET_HAVE_SPECULATION_SAFE_VALUE
+#define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed
+
+
+/******************************************************************
+ * Trampolines for Nested Functions *
+ ******************************************************************/
+
+
+#undef TARGET_ASM_TRAMPOLINE_TEMPLATE
+#define TARGET_ASM_TRAMPOLINE_TEMPLATE csky_asm_trampoline_template
+#undef TARGET_TRAMPOLINE_INIT
+#define TARGET_TRAMPOLINE_INIT csky_trampoline_init
+
+/* The low bit is ignored by jsr and jmp instructions so is safe to use. */
+#undef TARGET_CUSTOM_FUNCTION_DESCRIPTORS
+#define TARGET_CUSTOM_FUNCTION_DESCRIPTORS 1
+
+/******************************************************************
+ * Describing Relative Costs of Operations *
+ ******************************************************************/
+
+
+#undef TARGET_REGISTER_MOVE_COST
+#define TARGET_REGISTER_MOVE_COST csky_register_move_cost
+
+#undef TARGET_MEMORY_MOVE_COST
+#define TARGET_MEMORY_MOVE_COST csky_memory_move_cost
+
+#undef TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS csky_rtx_costs
+
+#undef TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST csky_address_cost
+
+
+/******************************************************************
+ * Anchor address *
+ ******************************************************************/
+
+
+/* FIXME: the max offset is related to mode size, the following is
+ defined according to SImode. How to deal with HImode and
+ QImode, and should the min offset be defined? */
+#undef TARGET_MAX_ANCHOR_OFFSET
+#define TARGET_MAX_ANCHOR_OFFSET \
+ ((TARGET_MINI_REGISTERS && optimize_size) ? 127 : 4095)
+
+
+/******************************************************************
+ * Condition Code Status *
+ ******************************************************************/
+
+
+#undef TARGET_FIXED_CONDITION_CODE_REGS
+#define TARGET_FIXED_CONDITION_CODE_REGS csky_fixed_condition_code_regs
+
+
+/******************************************************************
+ * Adjusting the Instruction Scheduler *
+ ******************************************************************/
+
+
+#undef TARGET_SCHED_ISSUE_RATE
+#define TARGET_SCHED_ISSUE_RATE csky_sched_issue_rate
+
+#undef TARGET_SCHED_ADJUST_COST
+#define TARGET_SCHED_ADJUST_COST csky_sched_adjust_cost
+
+
+/* The declaration of functions. */
+static void push_csky_minipool_fix (rtx_insn *, HOST_WIDE_INT, rtx *,
+ machine_mode, rtx);
+static void csky_print_operand (FILE *stream, rtx x, int code);
+
+
+/* Define a table to map ISR attribute arguments onto function type
+ modifiers. */
+
+typedef struct
+{
+ const char *const arg;
+ const unsigned long return_value;
+} isr_attribute_entry;
+
+static const isr_attribute_entry isr_attribute_map[] =
+{
+ {"irq", CSKY_FT_ISR },
+ {"IRQ", CSKY_FT_ISR },
+ {"fiq", CSKY_FT_FIQ },
+ {"FIQ", CSKY_FT_FIQ },
+ {NULL, CSKY_FT_NORMAL }
+};
+
+
+/* Return the function type of the current function, if it has not been
+ determined, return CSKY_FT_UNKNOWN. */
+
+static unsigned long
+get_csky_isr_type (tree argument)
+{
+ const isr_attribute_entry *ptr;
+ const char *arg;
+
+ /* if argument is NULL, set default value ISR. */
+ if (argument == NULL_TREE)
+ return CSKY_FT_ISR;
+
+ if (TREE_VALUE (argument) == NULL_TREE
+ || TREE_CODE (TREE_VALUE (argument)) != STRING_CST)
+ return CSKY_FT_UNKNOWN;
+
+ arg = TREE_STRING_POINTER (TREE_VALUE (argument));
+
+ for (ptr = isr_attribute_map; ptr->arg != NULL; ptr++)
+ if (strcmp (arg, ptr->arg) == 0)
+ return ptr->return_value;
+
+ return CSKY_FT_UNKNOWN;
+}
+
+/* Classify cfun as a normal function or some sort of interrupt
+ handler, and set the corresponding bits in cfun->machine->func_type. */
+
+static unsigned long
+get_csky_current_func_type (void)
+{
+ if (CSKY_FUNCTION_TYPE (cfun->machine->func_type) == CSKY_FT_UNKNOWN)
+ {
+ unsigned long type = CSKY_FT_UNKNOWN;
+ tree a;
+ tree attr;
+
+ gcc_assert (TREE_CODE (current_function_decl) == FUNCTION_DECL);
+
+ attr = DECL_ATTRIBUTES (current_function_decl);
+ a = lookup_attribute ("naked", attr);
+ if (a != NULL_TREE)
+ type |= CSKY_FT_NAKED;
+ a = lookup_attribute ("isr", attr);
+ if (a == NULL_TREE)
+ a = lookup_attribute ("interrupt", attr);
+ if (a == NULL_TREE)
+ type |= CSKY_FT_NORMAL;
+ else
+ type |= get_csky_isr_type (TREE_VALUE (a));
+
+ cfun->machine->func_type = type;
+ }
+
+ return cfun->machine->func_type;
+}
+
+/* These typedefs are located at the start of this file, so that
+ they can be used in the prototypes there. This comment is to
+ remind readers of that fact so that the following structures
+ can be understood more easily.
+
+ typedef struct minipool_node Mnode;
+ typedef struct minipool_fixup Mfix; */
+
+struct minipool_node
+{
+ /* Doubly linked chain of entries. */
+ Mnode *next;
+ Mnode *prev;
+ /* The maximum offset into the code that this entry can be placed. While
+ pushing fixes for forward references, all entries are sorted in order
+ of increasing max_address. */
+ HOST_WIDE_INT max_address;
+ /* Similarly for an entry inserted for a backwards ref. */
+ HOST_WIDE_INT min_address;
+ /* The number of fixes referencing this entry. This can become zero
+ if we "unpush" an entry. In this case we ignore the entry when we
+ come to emit the code. */
+ int refcount;
+ /* The offset from the start of the minipool. */
+ HOST_WIDE_INT offset;
+ /* The value in table. */
+ rtx value;
+ /* The mode of value. */
+ machine_mode mode;
+ /* The size of the value. */
+ int fix_size;
+};
+
+struct minipool_fixup
+{
+ Mfix *next;
+ rtx_insn *insn;
+ HOST_WIDE_INT address;
+ rtx *loc;
+ machine_mode mode;
+ int fix_size;
+ rtx value;
+ Mnode *minipool;
+ HOST_WIDE_INT forwards;
+ HOST_WIDE_INT backwards;
+};
+
+static Mnode *minipool_vector_head;
+static Mnode *minipool_vector_tail;
+static rtx minipool_vector_label;
+static HOST_WIDE_INT constpool_label_no = 0;
+
+/* Obstack for minipool constant handling. */
+static struct obstack minipool_obstack;
+static char *minipool_startobj;
+/* The linked list of all minipool fixes required for this function. */
+Mfix *minipool_fix_head;
+Mfix *minipool_fix_tail;
+/* The fix entry for the current minipool, once it has been placed. */
+Mfix *minipool_barrier;
+
+/* Allow GC scanning of the minipool obstack. */
+static void
+csky_add_gc_roots (void)
+{
+ gcc_obstack_init (&minipool_obstack);
+ minipool_startobj = (char *) obstack_alloc (&minipool_obstack, 0);
+}
+
+/* Implement TARGET_CONSTANT_ALIGNMENT.
+ Make strings word-aligned so strcpy from constants will be faster. */
+static HOST_WIDE_INT
+csky_constant_alignment (const_tree exp, HOST_WIDE_INT align)
+{
+ if (TREE_CODE (exp) == STRING_CST
+ && !optimize_size
+ && align < BITS_PER_WORD)
+ return BITS_PER_WORD;
+ return align;
+}
+
+/* Record that there is a natural barrier in the insn stream at
+ ADDRESS. */
+
+static void
+push_csky_minipool_barrier (rtx_insn *insn, HOST_WIDE_INT address)
+{
+ Mfix *fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (*fix));
+
+ fix->insn = insn;
+ fix->address = address;
+
+ fix->next = NULL;
+ if (minipool_fix_head != NULL)
+ minipool_fix_tail->next = fix;
+ else
+ minipool_fix_head = fix;
+
+ minipool_fix_tail = fix;
+}
+
+/* Compute the size of a vector jump table. */
+
+static HOST_WIDE_INT
+get_csky_jump_table_size (rtx insn)
+{
+ /* ADDR_VECs only take room if read-only data does into the text
+ section. */
+ if (JUMP_TABLES_IN_TEXT_SECTION || readonly_data_section == text_section)
+ {
+ rtx body = PATTERN (insn);
+ int elt = GET_CODE (body) == ADDR_DIFF_VEC ? 1 : 0;
+ HOST_WIDE_INT size;
+ HOST_WIDE_INT modesize;
+
+ modesize = GET_MODE_SIZE (GET_MODE (body));
+ size = modesize * XVECLEN (body, elt);
+ switch (modesize)
+ {
+ case 1:
+ /* Round up size of TBB table to a halfword boundary. */
+ size = (size + 1) & ~(HOST_WIDE_INT)1;
+ break;
+ case 2:
+ /* No padding necessary for TBH. */
+ break;
+ case 4:
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ return size;
+ }
+
+ return 0;
+}
+
+
+/* Scan INSN and note any of its operands that need fixing.
+ If DO_PUSHES is false we do not actually push any of the fixups
+ needed. The function returns TRUE if any fixups were needed/pushed. */
+
+static bool
+note_csky_invalid_constants (rtx_insn *insn, HOST_WIDE_INT address,
+ int do_pushes)
+{
+ bool result = false;
+ int opno;
+
+ extract_constrain_insn (insn);
+
+ if (recog_data.n_alternatives == 0)
+ return false;
+
+ /* Fill in recog_op_alt with information about the constraints of
+ this insn. */
+ preprocess_constraints (insn);
+
+ const operand_alternative *op_alt = which_op_alt ();
+ for (opno = 0; opno < recog_data.n_operands; opno++)
+ {
+ /* Things we need to fix can only occur in inputs. */
+ if (recog_data.operand_type[opno] != OP_IN)
+ continue;
+
+ /* If this alternative is a memory reference, then any mention
+ of constants in this alternative is really to fool reload
+ into allowing us to accept one there. We need to fix them up
+ now so that we output the right code. */
+ if (op_alt[opno].memory_ok)
+ {
+ rtx op = recog_data.operand[opno];
+
+ if (CONSTANT_P (op))
+ {
+ if (do_pushes)
+ push_csky_minipool_fix (insn, address,
+ recog_data.operand_loc[opno],
+ recog_data.operand_mode[opno], op);
+ result = true;
+ }
+ }
+ }
+
+ return result;
+}
+
+
+/* Add a constant to the minipool for a forward reference. Returns the
+ node added or NULL if the constant will not fit in this pool. */
+
+static Mnode *
+add_csky_minipool_forward_ref (Mfix *fix)
+{
+ /* If set, max_mp is the first pool_entry that has a lower
+ constraint than the one we are trying to add. */
+ Mnode *max_mp = NULL;
+ HOST_WIDE_INT max_address = fix->address + fix->forwards;
+ Mnode *mp;
+
+ /* If the minipool starts before the end of FIX->INSN then this FIX
+ can not be placed into the current pool. Furthermore, adding the
+ new constant pool entry may cause the pool to start FIX_SIZE bytes
+ earlier. */
+ if (minipool_vector_head
+ && (fix->address + get_attr_length (fix->insn)
+ >= minipool_vector_head->max_address - fix->fix_size))
+ return NULL;
+
+ /* Scan the pool to see if a constant with the same value has
+ already been added. While we are doing this, also note the
+ location where we must insert the constant if it doesn't already
+ exist. */
+ for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
+ {
+ if (GET_CODE (fix->value) == GET_CODE (mp->value)
+ && fix->mode == mp->mode
+ && (GET_CODE (fix->value) != CODE_LABEL
+ || (CODE_LABEL_NUMBER (fix->value)
+ == CODE_LABEL_NUMBER (mp->value)))
+ && rtx_equal_p (fix->value, mp->value))
+ {
+ /* More than one fix references this entry. */
+ mp->refcount++;
+ return mp;
+ }
+
+ /* Note the insertion point if necessary. */
+ if (max_mp == NULL && mp->max_address > max_address)
+ max_mp = mp;
+ }
+
+ /* The value is not currently in the minipool, so we need to create
+ a new entry for it. If MAX_MP is NULL, the entry will be put on
+ the end of the list since the placement is less constrained than
+ any existing entry. Otherwise, we insert the new fix before
+ MAX_MP and, if necessary, adjust the constraints on the other
+ entries. */
+ mp = XNEW (Mnode);
+ mp->fix_size = fix->fix_size;
+ mp->mode = fix->mode;
+ mp->value = fix->value;
+ mp->refcount = 1;
+ /* Not yet required for a backwards ref. */
+ mp->min_address = -65536;
+
+ if (max_mp == NULL)
+ {
+ mp->max_address = max_address;
+ mp->next = NULL;
+ mp->prev = minipool_vector_tail;
+
+ if (mp->prev == NULL)
+ {
+ minipool_vector_head = mp;
+ minipool_vector_label
+ = gen_csky_constpool_label (gen_rtx_CONST_INT (VOIDmode,
+ constpool_label_no++));
+ }
+ else
+ mp->prev->next = mp;
+
+ minipool_vector_tail = mp;
+ }
+ else
+ {
+ if (max_address > max_mp->max_address - mp->fix_size)
+ mp->max_address = max_mp->max_address - mp->fix_size;
+ else
+ mp->max_address = max_address;
+
+ mp->next = max_mp;
+ mp->prev = max_mp->prev;
+ max_mp->prev = mp;
+ if (mp->prev != NULL)
+ mp->prev->next = mp;
+ else
+ minipool_vector_head = mp;
+ }
+
+ /* Save the new entry. */
+ max_mp = mp;
+
+ /* Scan over the preceding entries and adjust their addresses as
+ required. */
+ while (mp->prev != NULL
+ && mp->prev->max_address > mp->max_address - mp->prev->fix_size)
+ {
+ mp->prev->max_address = mp->max_address - mp->prev->fix_size;
+ mp = mp->prev;
+ }
+
+ return max_mp;
+}
+
+
+/* Return the cost of forcibly inserting a barrier after INSN. */
+
+static int
+get_csky_barrier_cost (rtx_insn *insn)
+{
+ /* Basing the location of the pool on the loop depth is preferable,
+ but at the moment, the basic block information seems to be
+ corrupt by this stage of the compilation. */
+ int base_cost = 50;
+ rtx next = next_nonnote_insn (insn);
+
+ if (next != NULL && GET_CODE (next) == CODE_LABEL)
+ base_cost -= 20;
+
+ switch (GET_CODE (insn))
+ {
+ case CODE_LABEL:
+ /* It will always be better to place the table before the label, rather
+ than after it. */
+ return 50;
+
+ case INSN:
+ case CALL_INSN:
+ return base_cost;
+
+ case JUMP_INSN:
+ return base_cost - 10;
+
+ default:
+ return base_cost + 10;
+ }
+}
+
+
+/* Find the best place in the insn stream in the range
+ (FIX->address,MAX_ADDRESS) to forcibly insert a minipool barrier.
+ Create the barrier by inserting a jump and add a new fix entry for
+ it. */
+static Mfix *
+create_csky_fix_barrier (Mfix *fix, Mfix *fix_next,
+ HOST_WIDE_INT max_address)
+{
+ rtx_barrier *barrier;
+ rtx_insn *from = (fix ? fix->insn : get_insns ());
+ /* The instruction after which we will insert the jump. */
+ rtx_insn *selected = NULL;
+ int selected_cost;
+ /* The address at which the jump instruction will be placed. */
+ HOST_WIDE_INT selected_address = 0;
+ Mfix *new_fix;
+ HOST_WIDE_INT count = (fix ? fix->address : 0);
+ HOST_WIDE_INT max_count = max_address;
+ rtx_code_label *label = gen_label_rtx ();
+
+ selected_cost = get_csky_barrier_cost (from);
+
+ while (from && count < max_count)
+ {
+ int new_cost;
+ rtx_jump_table_data *table;
+
+ /* Count the length of this insn. */
+ count += get_attr_length (from);
+
+ /* If there is a jump table, add its length. */
+ if (tablejump_p (from, NULL, &table))
+ {
+ count += get_csky_jump_table_size (table);
+
+ /* Jump tables aren't in a basic block, so base the cost on
+ the dispatch insn. If we select this location, we will
+ still put the pool after the table. */
+ new_cost = get_csky_barrier_cost (from);
+
+ if (count < max_count
+ && (!selected || new_cost <= selected_cost))
+ {
+ selected = table;
+ selected_cost = new_cost;
+ selected_address = count;
+ }
+
+ /* Continue after the dispatch table. */
+ from = NEXT_INSN (table);
+ continue;
+ }
+
+ new_cost = get_csky_barrier_cost (from);
+
+ if (count < max_count
+ && (!selected || new_cost <= selected_cost))
+ {
+ selected = from;
+ selected_cost = new_cost;
+ selected_address = count;
+ }
+
+ from = NEXT_INSN (from);
+ }
+
+ /* Make sure that we found a place to insert the jump. */
+ gcc_assert (selected);
+
+ /* Create a new JUMP_INSN that branches around a barrier. */
+ from = emit_jump_insn_after (gen_jump (label), selected);
+ JUMP_LABEL (from) = label;
+ barrier = emit_barrier_after (from);
+ emit_label_after (label, barrier);
+
+ /* Create a minipool barrier entry for the new barrier. */
+ new_fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* new_fix));
+ new_fix->insn = barrier;
+ new_fix->address = selected_address;
+ if (fix)
+ {
+ new_fix->next = fix->next;
+ fix->next = new_fix;
+ }
+ else
+ new_fix->next = fix_next;
+
+ return new_fix;
+}
+
+
+/* Print a symbolic form of the constant X to the dump file F.
+ This is used for dump output for -mconstpool in the target-dependent
+ reorg pass. */
+
+static void
+print_csky_value (FILE *f, rtx x)
+{
+ switch (GET_CODE (x))
+ {
+ case CONST_INT:
+ fprintf (f, HOST_WIDE_INT_PRINT_HEX, INTVAL (x));
+ return;
+
+ case CONST_DOUBLE:
+ fprintf (f, "<0x%lx,0x%lx>", (long)XWINT (x, 2), (long)XWINT (x, 3));
+ return;
+
+ case CONST_VECTOR:
+ {
+ int i;
+
+ fprintf (f, "<");
+ for (i = 0; i < CONST_VECTOR_NUNITS (x); i++)
+ {
+ fprintf (f, HOST_WIDE_INT_PRINT_HEX,
+ INTVAL (CONST_VECTOR_ELT (x, i)));
+ if (i < (CONST_VECTOR_NUNITS (x) - 1))
+ fputc (',', f);
+ }
+ fprintf (f, ">");
+ }
+ return;
+
+ case CONST_STRING:
+ fprintf (f, "\"%s\"", XSTR (x, 0));
+ return;
+
+ case SYMBOL_REF:
+ fprintf (f, "`%s'", XSTR (x, 0));
+ return;
+
+ case LABEL_REF:
+ fprintf (f, "L%d", INSN_UID (XEXP (x, 0)));
+ return;
+
+ case CONST:
+ print_csky_value (f, XEXP (x, 0));
+ return;
+
+ case PLUS:
+ print_csky_value (f, XEXP (x, 0));
+ fprintf (f, "+");
+ print_csky_value (f, XEXP (x, 1));
+ return;
+
+ case PC:
+ fprintf (f, "pc");
+ return;
+
+ default:
+ fprintf (f, "????");
+ return;
+ }
+}
+
+
+/* Record INSN, which will need fixing up to load a value from the
+ minipool. ADDRESS is the offset of the insn since the start of the
+ function; LOC is a pointer to the part of the insn which requires
+ fixing; VALUE is the constant that must be loaded, which is of type
+ MODE. */
+
+static void
+push_csky_minipool_fix (rtx_insn *insn, HOST_WIDE_INT address, rtx *loc,
+ machine_mode mode, rtx value)
+{
+ #define CSKY_ELRW16_RANGE 1400
+ #define CSKY_LRW16_RANGE 700
+ #define CSKY_CONSTANT_POOL_RANGE (TARGET_ELRW ? CSKY_ELRW16_RANGE \
+ : CSKY_LRW16_RANGE)
+
+ /* Fixes less than a word need padding out to a word boundary. */
+ #define CSKY_MINIPOOL_FIX_SIZE(mode) \
+ (GET_MODE_SIZE ((mode)) >= 4 ? GET_MODE_SIZE ((mode)) : 4)
+
+ Mfix *fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (*fix));
+
+ fix->insn = insn;
+ fix->address = address;
+ fix->loc = loc;
+ fix->mode = mode;
+ fix->fix_size = CSKY_MINIPOOL_FIX_SIZE (mode);
+ fix->value = value;
+ fix->forwards = CSKY_CONSTANT_POOL_RANGE;
+ fix->backwards = 0;
+ fix->minipool = NULL;
+
+ /* If an insn doesn't have a range defined for it, then it isn't
+ expecting to be reworked by this code. Better to stop now than
+ to generate duff assembly code. */
+ gcc_assert (fix->forwards || fix->backwards);
+
+ if (dump_file)
+ {
+ fprintf (dump_file,
+ ";; %smode fixup for i%d; addr %lu, range (%ld,%ld): ",
+ GET_MODE_NAME (mode),
+ INSN_UID (insn), (unsigned long) address,
+ -1 * (long)fix->backwards, (long)fix->forwards);
+ print_csky_value (dump_file, fix->value);
+ fprintf (dump_file, "\n");
+ }
+
+ /* Add it to the chain of fixes. */
+ fix->next = NULL;
+
+ if (minipool_fix_head != NULL)
+ minipool_fix_tail->next = fix;
+ else
+ minipool_fix_head = fix;
+
+ minipool_fix_tail = fix;
+}
+
+
+/* Fill in the offsets for minipool entries. */
+
+static void
+assign_csky_minipool_offsets (Mfix *barrier)
+{
+ HOST_WIDE_INT offset = 0;
+ Mnode *mp;
+
+ minipool_barrier = barrier;
+
+ for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
+ {
+ mp->offset = offset;
+
+ if (mp->refcount > 0)
+ offset += mp->fix_size;
+ }
+}
+
+
+/* Output the literal table. */
+
+static HOST_WIDE_INT
+dump_csky_minipool (rtx_insn *scan)
+{
+ Mnode *mp;
+ Mnode *nmp;
+ HOST_WIDE_INT pool_length = 0;
+
+ if (dump_file)
+ fprintf (dump_file,
+ ";; Emitting minipool after insn %u;\
+ address %ld; align %d (bytes)\n",
+ INSN_UID (scan), (unsigned long) minipool_barrier->address, 4);
+
+ scan = emit_insn_after (gen_align_4 (), scan);
+ scan = emit_insn_after (minipool_vector_label, scan);
+
+ for (mp = minipool_vector_head; mp != NULL; mp = nmp)
+ {
+ if (mp->refcount > 0)
+ {
+ if (dump_file)
+ {
+ fprintf (dump_file, ";; Offset %u, min %ld, max %ld ",
+ (unsigned) mp->offset, (unsigned long) mp->min_address,
+ (unsigned long) mp->max_address);
+ print_csky_value (dump_file, mp->value);
+ fputc ('\n', dump_file);
+ }
+
+ switch (mp->fix_size)
+ {
+ case 4:
+ scan = emit_insn_after (gen_consttable_4 (mp->value), scan);
+ pool_length += 4;
+ break;
+ case 8:
+ scan = emit_insn_after (gen_consttable_8 (mp->value), scan);
+ pool_length += 8;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
+
+ nmp = mp->next;
+ free (mp);
+ }
+
+ minipool_vector_head = minipool_vector_tail = NULL;
+ scan = emit_barrier_after (scan);
+
+ return pool_length;
+}
+
+/* Return true if INSN is a minipool load or instruction that will be
+ converted to one. It is assumed that INSN has type attribute "load". */
+
+bool
+csky_minipool_load_p (rtx_insn *insn)
+{
+ rtx op1, addr;
+
+ extract_insn_cached (insn);
+
+ op1 = recog_data.operand[1];
+
+ /* This is a constant that has not yet been turned into
+ a minipool load. */
+ if (CONSTANT_P (op1))
+ return true;
+
+ /* Constant pool loads are label_refs. */
+ if (GET_CODE (op1) == ZERO_EXTEND || GET_CODE (op1) == SIGN_EXTEND)
+ op1 = XEXP (op1, 0);
+ if (GET_CODE (op1) != MEM)
+ return false;
+ addr = XEXP (op1, 0);
+ if (GET_CODE (addr) == PLUS && CONST_INT_P (XEXP (addr, 1)))
+ addr = XEXP (addr, 0);
+ return GET_CODE (addr) == LABEL_REF;
+}
+
+
+/* Compute the attribute "length" of push or pop insn, according to
+ the registers it uses. */
+
+int
+csky_compute_pushpop_length (rtx *operands)
+{
+ rtx parallel_op = operands[2];
+ /* Initialize to elements number of PARALLEL. */
+ unsigned indx = XVECLEN (parallel_op, 0) - 1;
+ unsigned first_indx = 0;
+ unsigned regno = REGNO (operands[1]);
+
+ if (regno > CSKY_LR_REGNUM)
+ return 4;
+
+ /* Check each register in the list. */
+ for (; indx > first_indx; indx--)
+ {
+ regno = REGNO (XEXP (XVECEXP (parallel_op, 0, indx), 0));
+ /* If a register number higher than 15 is included, a 32-bit insn
+ is used. */
+ if (regno > CSKY_LR_REGNUM)
+ return 4;
+ }
+
+ return 2;
+}
+
+/* Emit constant pools for -mconstpool. */
+static void
+csky_emit_constant_pools (void)
+{
+ rtx_insn *insn;
+ HOST_WIDE_INT address = 0;
+ Mfix *fix;
+
+ minipool_fix_head = minipool_fix_tail = NULL;
+
+ /* The first insn must always be a note, or the code below won't
+ scan it properly. */
+ insn = get_insns ();
+ gcc_assert (NOTE_P (insn));
+
+ /* Scan the insns and record the operands that need fixing. */
+ for (insn = next_nonnote_insn (insn); insn;
+ insn = next_nonnote_insn (insn))
+ {
+ if (BARRIER_P (insn))
+ push_csky_minipool_barrier (insn, address);
+ else if (INSN_P (insn))
+ {
+ rtx_jump_table_data *table;
+
+ note_csky_invalid_constants (insn, address, true);
+ address += get_attr_length (insn);
+
+ /* If the insn is a vector jump, add the size of the table
+ and skip the table. */
+ if (tablejump_p (insn, NULL, &table))
+ {
+ address += get_csky_jump_table_size (table);
+ insn = table;
+ }
+ }
+ }
+
+ fix = minipool_fix_head;
+
+ /* Now scan the fixups and perform the required changes. */
+ while (fix)
+ {
+ Mfix *ftmp;
+ Mfix *last_added_fix;
+ Mfix *last_barrier = NULL;
+ Mfix *this_fix;
+ Mnode *mp;
+ bool has_pending_const = false;
+
+ /* Check if there is any pending constant not processed. */
+ for (mp = minipool_vector_head; mp; mp = mp->next)
+ if (mp->refcount > 0)
+ {
+ has_pending_const = true;
+ break;
+ }
+
+ /* If no pending constant, skip over barrier insns. */
+ if (has_pending_const == false)
+ {
+ while (fix && BARRIER_P (fix->insn))
+ fix = fix->next;
+ if (fix == NULL)
+ break;
+ }
+
+ last_added_fix = NULL;
+
+ for (ftmp = fix; ftmp; ftmp = ftmp->next)
+ {
+ if (BARRIER_P (ftmp->insn))
+ {
+ if (minipool_vector_head
+ && ftmp->address >= minipool_vector_head->max_address)
+ break;
+
+ last_barrier = ftmp;
+ }
+ else
+ {
+ ftmp->minipool = add_csky_minipool_forward_ref (ftmp);
+ if (ftmp->minipool == NULL)
+ break;
+ }
+ last_added_fix = ftmp; /* Keep track of the last fix added. */
+ }
+
+ /* If the last added fix is a barrier, dump minipool after it. */
+ if (last_added_fix && BARRIER_P (last_added_fix->insn))
+ ftmp = last_barrier;
+ else
+ {
+ /* ftmp is first fix that we can't fit into this pool.
+ Insert a new barrier in the code somewhere between the previous
+ fix and this one, and arrange to jump around it. */
+ HOST_WIDE_INT max_address;
+
+ /* The last item on the list of fixes must be a barrier, so
+ we can never run off the end of the list of fixes without
+ last_barrier being set. */
+ gcc_assert (ftmp);
+
+ /* Check that there isn't another fix that is in range that
+ we couldn't fit into this pool because the pool was
+ already too large: we need to put the pool before such an
+ instruction. The pool itself may come just after the
+ fix because create_csky_fix_barrier also allows space for a
+ jump instruction. */
+ max_address = minipool_vector_head->max_address;
+ if (ftmp->address < max_address)
+ max_address = ftmp->address + 1;
+ last_barrier = create_csky_fix_barrier (last_added_fix, ftmp,
+ max_address);
+ }
+
+ assign_csky_minipool_offsets (last_barrier);
+
+ /* Scan over the fixes we have identified for this pool, fixing them
+ up and adding the constants to the pool itself. */
+ for (this_fix = fix; this_fix && ftmp != this_fix;
+ this_fix = this_fix->next)
+ {
+ if (GET_CODE (this_fix->insn) != BARRIER)
+ {
+ rtx addr
+ = plus_constant (Pmode,
+ gen_rtx_LABEL_REF (VOIDmode,
+ minipool_vector_label),
+ this_fix->minipool->offset);
+ rtx insn_body = PATTERN (this_fix->insn);
+ rtx src = XEXP (insn_body, 1);
+ *this_fix->loc = gen_rtx_MEM (this_fix->mode, addr);
+ if (GET_CODE (this_fix->value) == SYMBOL_REF)
+ emit_insn_after (gen_rtx_UNSPEC_VOLATILE (VOIDmode,
+ gen_rtvec (1, src),
+ VUNSPEC_SYMBOL_REF),
+ this_fix->insn);
+ }
+ }
+ dump_csky_minipool (last_barrier->insn);
+ fix = ftmp;
+ if (fix->next == NULL)
+ break;
+ }
+
+ /* Free the minipool memory. */
+ obstack_free (&minipool_obstack, minipool_startobj);
+}
+
+
+/* Implement TARGET_MACHINE_DEPENDENT_REORG. This handles
+ -mconstpool output. */
+
+static void
+csky_reorg (void)
+{
+ if (TARGET_CONSTANT_POOL)
+ csky_emit_constant_pools ();
+}
+
+
+/* Check to see if the current function contains a branch insn with the
+ far jump attribute set. Such a function uses the LR register. */
+
+static bool
+csky_far_jump_used_p (void)
+{
+ rtx_insn *insn;
+ if (cfun->machine->far_jump_used)
+ return true;
+
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) == JUMP_INSN
+ /* Ignore tablejump patterns. */
+ && GET_CODE (PATTERN (insn)) != ADDR_VEC
+ && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC
+ && get_attr_far_jump (insn) == FAR_JUMP_YES)
+ {
+ cfun->machine->far_jump_used = 1;
+ return true;
+ }
+ return false;
+}
+
+
+/* Return the mask of registers used by the current function. Set
+ COUNT to the number of registers used. */
+
+static unsigned int
+get_csky_live_regs (int *count)
+{
+ int reg;
+ unsigned int live_regs_mask = 0;
+
+ *count = 0;
+ for (reg = 0; reg < CSKY_NGPR_REGS; reg++)
+ {
+ bool save = false;
+
+ /* Ignore unsupported registers. */
+ if (CSKY_TARGET_ARCH (CK801) && reg > 8 && reg < 13)
+ continue;
+ if ((CSKY_TARGET_ARCH (CK801)
+ || CSKY_TARGET_ARCH (CK802)
+ || CSKY_TARGET_ARCH (CK803))
+ && reg > 15)
+ break;
+
+ /* Caller-saved registers marked as used. */
+ if (df_regs_ever_live_p (reg) && !call_really_used_regs[reg])
+ save = true;
+
+ /* Frame pointer marked used. */
+ else if (frame_pointer_needed && reg == FRAME_POINTER_REGNUM)
+ save = true;
+
+ /* This is required for CK801/802 where FP is a fixed reg, otherwise
+ we end up with no FP value available to the DWARF-2 unwinder. */
+ else if (crtl->calls_eh_return && reg == FRAME_POINTER_REGNUM)
+ save = true;
+
+ /* CK801/802 also need special handling for LR because it's clobbered
+ by far jumps. */
+ else if ((CSKY_TARGET_ARCH (CK801) || CSKY_TARGET_ARCH (CK802))
+ && reg == CSKY_LR_REGNUM
+ && (!crtl->is_leaf || csky_far_jump_used_p ()))
+ save = true;
+
+ /* Register is used for EH data return. */
+ else if (crtl->calls_eh_return
+ && reg >= CSKY_FIRST_EH_RETDATA_REGNUM
+ && reg <= CSKY_LAST_EH_RETDATA_REGNUM)
+ save = true;
+
+ /* We need a temporary reg to hold the offset for adjusting the SP
+ for a large stack frame. */
+ if (reg == CSKY_STACKADJUST_REGNUM
+ && cfun->machine->reg_offset > CSKY_MAX_SP_ADJUST * 2)
+ save = true;
+
+ /* Add reg to the mask. */
+ if (save)
+ {
+ (*count)++;
+ live_regs_mask |= (1 << reg);
+ }
+ }
+ return live_regs_mask;
+}
+
+/* Compute the stack frame layout, storing sizes of the various pieces
+ in cfun->machine.
+
+ Stack frames constructed in the prologue look like:
+ ... caller's frame ...
+ incoming SP -> caller's outbound argument overflow
+ argument spill
+ optional FP -> register save
+ local variables
+ alloca() space
+ adjusted SP -> outbound argument overflow
+
+ with SP/FP pointing at the base (low address) of the respective area,
+ and each area aligned to a word boundary. */
+
+static void
+csky_layout_stack_frame (void)
+{
+ machine_function *infp = cfun->machine;
+ int reg_count;
+
+ if (infp->frame_init_p)
+ return;
+
+ /* Get sizes of local variables & outbound arguments. */
+ infp->outbound_size = CSKY_STACK_ALIGN (crtl->outgoing_args_size);
+ infp->local_offset = infp->outbound_size;
+ infp->local_size = CSKY_STACK_ALIGN (get_frame_size ());
+ infp->reg_offset = infp->local_offset + infp->local_size;
+
+ /* Now compute size of argument spill + saved regs. These do not
+ need explicit alignment since they are already word-sized. */
+ infp->reg_mask = get_csky_live_regs (&reg_count);
+ infp->reg_size = reg_count * UNITS_PER_WORD;
+ infp->arg_offset = infp->reg_offset + infp->reg_size;
+ infp->arg_size = crtl->args.pretend_args_size;
+ infp->frame_size = infp->arg_offset + infp->arg_size;
+ infp->frame_init_p = reload_completed;
+}
+
+/* Implement TARGET_CAN_ELIMINATE. */
+static bool
+csky_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
+{
+ if (to == STACK_POINTER_REGNUM)
+ return !frame_pointer_needed;
+ return true;
+}
+
+/* Worker function for INITIAL_ELIMINATION_OFFSET macro.
+ Define the offset between two registers, one to be eliminated, and
+ the other its replacement, at the start of a routine. */
+
+HOST_WIDE_INT
+csky_initial_elimination_offset (int from, int to)
+{
+ int offset;
+
+ csky_layout_stack_frame ();
+
+ /* Set OFFSET to the offset to the initial stack pointer. */
+ switch (from)
+ {
+ case FRAME_POINTER_REGNUM:
+ offset = cfun->machine->reg_offset;
+ break;
+
+ case ARG_POINTER_REGNUM:
+ offset = cfun->machine->arg_offset;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ /* If we are asked for the offset to the frame pointer instead,
+ then subtract the difference between the frame pointer and stack
+ pointer. */
+ if (to == FRAME_POINTER_REGNUM)
+ offset -= cfun->machine->reg_offset;
+ return offset;
+}
+
+
+/* Determine where to put an argument to a function.
+ Value is zero to push the argument on the stack,
+ or a hard register in which to store the argument.
+
+ MODE is the argument's machine mode.
+ TYPE is the data type of the argument (as a tree).
+ This is null for libcalls where that information may
+ not be available.
+ CUM is a variable of type CUMULATIVE_ARGS which gives info about
+ the preceding args and about the function being called.
+ NAMED is nonzero if this argument is a named parameter
+ (otherwise it is an extra parameter matching an ellipsis). */
+static rtx
+csky_function_arg (cumulative_args_t pcum_v, machine_mode mode,
+ const_tree type ATTRIBUTE_UNUSED,
+ bool named ATTRIBUTE_UNUSED)
+{
+ CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v);
+
+ if (*pcum < CSKY_NPARM_REGS)
+ return gen_rtx_REG (mode, CSKY_FIRST_PARM_REGNUM + *pcum);
+
+ return NULL_RTX;
+}
+
+
+/* Return the number of registers (words) needed to pass an argument of
+ MODE and TYPE. */
+
+static int
+csky_num_arg_regs (machine_mode mode, const_tree type)
+{
+ int size;
+
+ if (type && mode == BLKmode)
+ size = int_size_in_bytes (type);
+ else
+ size = GET_MODE_SIZE (mode);
+
+ return CSKY_NUM_WORDS (size);
+}
+
+
+/* Implement TARGET_FUNCTION_ARG_ADVANCE. */
+
+static void
+csky_function_arg_advance (cumulative_args_t pcum_v, machine_mode mode,
+ const_tree type, bool named ATTRIBUTE_UNUSED)
+{
+ CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v);
+ int param_size = csky_num_arg_regs (mode, type);
+
+ if (*pcum + param_size > CSKY_NPARM_REGS)
+ *pcum = CSKY_NPARM_REGS;
+ else
+ *pcum += param_size;
+}
+
+
+/* Implement TARGET_FUNCTION_VALUE. */
+static rtx
+csky_function_value (const_tree type, const_tree func,
+ bool outgoing ATTRIBUTE_UNUSED)
+{
+ machine_mode mode;
+ int unsignedp ATTRIBUTE_UNUSED;
+ int size;
+
+ mode = TYPE_MODE (type);
+ size = int_size_in_bytes (type);
+
+ /* Since we promote return types, we must promote the mode here too. */
+ if (INTEGRAL_TYPE_P (type))
+ {
+ mode = promote_function_mode (type, mode, &unsignedp, func, 1);
+ return gen_rtx_REG (mode, CSKY_FIRST_RET_REGNUM);
+ }
+
+ if (mode == BLKmode && size > UNITS_PER_WORD
+ && size <= UNITS_PER_WORD * 2)
+ {
+ rtx ret_regs[2];
+ ret_regs[0] = gen_rtx_EXPR_LIST (SImode,
+ gen_rtx_REG (SImode,
+ CSKY_FIRST_RET_REGNUM),
+ GEN_INT (0 * UNITS_PER_WORD));
+ ret_regs[1] = gen_rtx_EXPR_LIST (SImode,
+ gen_rtx_REG (SImode,
+ CSKY_FIRST_RET_REGNUM + 1),
+ GEN_INT (1 * UNITS_PER_WORD));
+
+ rtvec vec = gen_rtvec (2, ret_regs[0], ret_regs[1]);
+
+ return gen_rtx_PARALLEL (mode, vec);
+ }
+
+ return gen_rtx_REG (mode, CSKY_FIRST_RET_REGNUM);
+}
+
+
+/* Implement TARGET_LIBCALL_VALUE. */
+static rtx
+csky_libcall_value (machine_mode mode,
+ const_rtx libcall ATTRIBUTE_UNUSED)
+{
+ return gen_rtx_REG (mode, CSKY_FIRST_RET_REGNUM);
+}
+
+
+/* Implement TARGET_FUNCTION_VALUE_REGNO_P.
+ On C-SKY, only r0 can return results. */
+
+static bool
+csky_function_value_regno_p (const unsigned int regno)
+{
+ return (regno == CSKY_FIRST_RET_REGNUM);
+}
+
+
+/* Return an RTX indicating where the return address to the
+ calling function can be found. */
+rtx
+csky_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
+{
+ if (count != 0)
+ return NULL_RTX;
+
+ return get_hard_reg_initial_val (Pmode, CSKY_LR_REGNUM);
+}
+
+
+/* Implement TARGET_ARG_PARTIAL_BYTES.
+ Return the number of bytes at the beginning of an argument
+ that must be put in registers. The value must be zero for arguments
+ that are passed entirely in registers or
+ that are entirely pushed on the stack. */
+static int
+csky_arg_partial_bytes (cumulative_args_t pcum_v, machine_mode mode,
+ tree type, bool named ATTRIBUTE_UNUSED)
+{
+ CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v);
+ int param_size = csky_num_arg_regs (mode, type);
+
+ if (*pcum < CSKY_NPARM_REGS
+ && *pcum + param_size > CSKY_NPARM_REGS)
+ return (CSKY_NPARM_REGS - *pcum) * UNITS_PER_WORD;
+
+ return 0;
+}
+
+
+/* Implement TARGET_SETUP_INCOMING_VARARGS.
+ On C-Sky the copy from the argument registers to the stack is emitted
+ by the prologue hooks, so here we just have to note how much stack space
+ to save. */
+
+static void
+csky_setup_incoming_varargs (cumulative_args_t pcum_v,
+ machine_mode mode,
+ tree type,
+ int *pretend_size,
+ int second_time ATTRIBUTE_UNUSED)
+{
+ CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v);
+ CUMULATIVE_ARGS local_cum;
+ cumulative_args_t local_cum_v = pack_cumulative_args (&local_cum);
+ int regs_to_push;
+
+ cfun->machine->uses_anonymous_args = 1;
+ local_cum = *pcum;
+ csky_function_arg_advance (local_cum_v, mode, type, true);
+ regs_to_push = CSKY_NPARM_REGS - local_cum;
+ if (regs_to_push)
+ *pretend_size = regs_to_push * UNITS_PER_WORD;
+}
+
+
+/* Implement TARGET_ASM_OUTPUT_MI_THUNK.
+ Output code to add DELTA to the first argument, and then jump
+ to FUNCTION. Used for C++ multiple inheritance. */
+
+static void
+csky_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
+ HOST_WIDE_INT delta,
+ HOST_WIDE_INT vcall_offset,
+ tree function)
+{
+ const char *thiz = "a0";
+ const char *reg0 = "t0";
+ const char *reg1 = "t1";
+ int maxoff = 4096; /* Constant range for addi/subi. */
+
+ final_start_function (emit_barrier (), file, 1);
+
+ rtx fnaddr = XEXP (DECL_RTL (function), 0);
+
+ if (CSKY_TARGET_ARCH (CK801))
+ {
+ /* CK801 can't use t registers and has only 16-bit addi/subi. */
+ reg0 = "l0";
+ reg1 = "l1";
+ maxoff = 256;
+ if (vcall_offset > maxoff || vcall_offset < -maxoff)
+ fprintf (file, "\tpush\tl0, l1\n");
+ else if (delta > maxoff || delta < -maxoff)
+ fprintf (file, "\tpush\tl0\n");
+ }
+
+ if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
+ thiz = "a1";
+
+ /* Add delta to this_rtx. */
+ if (delta != 0)
+ {
+ if (delta > maxoff || delta < -maxoff)
+ {
+ fprintf (file, "\tlrw\t%s, %ld\n", reg0, (long)delta);
+ fprintf (file, "\taddu\t%s, %s, %s\n", thiz, thiz, reg0);
+ }
+ else
+ fprintf (file, "\t%s\t%s, %s, %ld\n",
+ (delta > 0 ? "addi" : "subi"), thiz, thiz,
+ (long)(delta > 0 ? delta : -delta));
+ }
+
+ /* If needed, add *(*this_rtx + vcall_offset) to this_rtx. */
+ if (vcall_offset != 0)
+ {
+ fprintf (file, "\tld.w\t%s, (%s, 0)\n", reg0, thiz);
+
+ if (vcall_offset > maxoff || vcall_offset < -maxoff)
+ {
+ fprintf (file, "\tlrw\t%s, %ld\n", reg1, (long)vcall_offset);
+ fprintf (file, "\taddu\t%s, %s, %s\n", reg0, reg0, reg1);
+ }
+ else
+ fprintf (file, "\t%s\t%s, %s, %ld\n",
+ (vcall_offset > 0 ? "addi" : "subi"), reg0, reg0,
+ (long)(vcall_offset > 0 ? vcall_offset : -vcall_offset));
+
+ /* Load the offset and add it to this_rtx */
+ fprintf (file, "\tld.w\t%s, (%s, 0)\n", reg0, reg0);
+ fprintf (file, "\taddu\t%s, %s, %s\n", thiz, thiz, reg0);
+ }
+
+ /* We must pop the scratch regs individually instead of using the
+ "pop" insn, which also does a return. */
+ if (CSKY_TARGET_ARCH (CK801))
+ {
+ if (vcall_offset > maxoff || vcall_offset < -maxoff)
+ {
+ fprintf (file, "\tld.w\tl0, (sp, 0)\n");
+ fprintf (file, "\tld.w\tl1, (sp, 4)\n");
+ fprintf (file, "\taddi\t sp, sp, 8\n");
+ }
+ else if (delta > maxoff || delta < -maxoff)
+ {
+ fprintf (file, "\tld.w\tl0, (sp, 0)\n");
+ fprintf (file, "\taddi\tsp, sp, 4\n");
+ }
+ }
+
+ fprintf (file, "\tjbr\t");
+ output_addr_const (file, fnaddr);
+ fprintf (file, "\n");
+
+ final_end_function ();
+}
+
+
+/* Implement TARGET_CONDITIONAL_REGISTER_USAGE.
+ Conditionally modify five variables fixed_regs, call_used_regs, global_regs,
+ reg_names, and reg_class_contents, to take into account any dependence of
+ these register sets on target flags.
+
+ CK801 has registers r0-r8 and r13-r15. CK802 and CK803 have registers
+ r0-r15 (the "low" registers). Other cpus use registers r0-r31 with
+ -mhigh-registers, otherwise also only r0-r15.
+
+ CK801 only has 16-bit instructions, most of which can only reference
+ r0-r7 (the "mini" registers). So we mark regs outside that range as
+ fixed. -msmart can be used on other arch variants to force the same
+ behavior because it results in smaller code size.
+
+ TODO: investigate whether it's beneficial to use r8-r13 as a spill
+ class when TARGET_MINI_REGISTERS instead of making them unusable by
+ the register allocator. */
+
+static void
+csky_conditional_register_usage (void)
+{
+ /* Only use mini registers in smart mode or 801. */
+ if (TARGET_MINI_REGISTERS)
+ {
+ int i;
+
+ for (i = (CSKY_LAST_MINI_REGNUM + 1); i < 32; i++)
+ {
+ fixed_regs[i] = 1;
+ call_used_regs[i] = 1;
+ call_really_used_regs[i] = 1;
+ }
+ }
+ /* For some targets, the high registers are not supported.
+ CPUs other than ck801/ck802/ck803 use high registers
+ depending on -mhigh-registers option. */
+ else if (CSKY_TARGET_ARCH (CK802)
+ || CSKY_TARGET_ARCH (CK803)
+ || !TARGET_HIGH_REGISTERS)
+ {
+ int i;
+
+ for (i = CSKY_FIRST_HIGH_REGNUM; i <= CSKY_LAST_HIGH_REGNUM; i++)
+ {
+ fixed_regs[i] = 1;
+ call_used_regs[i] = 1;
+ call_really_used_regs[i] = 1;
+ }
+ }
+
+ /* On CK801/CK802 we must mark lr as a fixed register because it is
+ used to implement far jumps.
+ FIXME: perhaps there should be a command-line option controlling
+ use of lr for far jumps on ck802 when !TARGET_MINI_REGS, when
+ you really want lr to be available to the register allocator and
+ you know there are no far jumps in the code. */
+ if (CSKY_TARGET_ARCH (CK801) || CSKY_TARGET_ARCH (CK802))
+ {
+ fixed_regs[CSKY_LR_REGNUM] = 1;
+ call_used_regs[CSKY_LR_REGNUM] = 1;
+ call_really_used_regs[CSKY_LR_REGNUM] = 0;
+ }
+
+ /* The hi/lo registers are only supported in dsp mode. */
+ if (!TARGET_DSP)
+ {
+ fixed_regs[CSKY_HI_REGNUM] = 1;
+ call_used_regs[CSKY_HI_REGNUM] = 1;
+ call_really_used_regs[CSKY_HI_REGNUM] = 1;
+
+ fixed_regs[CSKY_LO_REGNUM] = 1;
+ call_used_regs[CSKY_LO_REGNUM] = 1;
+ call_really_used_regs[CSKY_LO_REGNUM] = 1;
+ }
+
+ /* The V_REGS are only supported in hard float mode. */
+ if (!TARGET_HARD_FLOAT)
+ {
+ int regno;
+
+ for (regno = CSKY_FIRST_VFP_REGNUM;
+ regno <= CSKY_LAST_VFP_REGNUM; regno++)
+ {
+ fixed_regs[regno] = 1;
+ call_used_regs[regno] = 1;
+ call_really_used_regs[regno] = 1;
+ }
+ }
+
+ /* In pic mode, the gb register is not available for register
+ allocation. Since gb is not clobbered by function
+ calls, set its call_really_used_regs to 0. */
+ if (flag_pic)
+ {
+ fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
+ call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
+ call_really_used_regs[PIC_OFFSET_TABLE_REGNUM] = 0;
+ }
+}
+
+/* Implement TARGET_HARD_REGNO_NREGS. */
+static unsigned int
+csky_hard_regno_nregs (unsigned int regno, machine_mode mode)
+{
+ if (regno >= CSKY_FIRST_VFP_REGNUM && !CSKY_TARGET_ARCH (CK803))
+ return 1;
+ else
+ return CSKY_NUM_REGS (mode);
+}
+
+/* Implement TARGET_HARD_REGNO_MODE_OK. Return true if REGNO is a
+ valid register for holding a quantity of type MODE. */
+
+static bool
+csky_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
+{
+ int nregs = CSKY_NUM_REGS (mode);
+
+ /* We can't handle more than doubleword sizes for any register. */
+ if (nregs > 2)
+ return false;
+
+ /* For general registers, return true if mode is one word size.
+ When the size is larger than one word size, there should
+ be two successive hard registers to put the data. */
+ if (regno < CSKY_NGPR_REGS)
+ {
+ if (nregs < 2)
+ return true;
+ else if (TARGET_MINI_REGISTERS)
+ return (regno < CSKY_LAST_MINI_REGNUM);
+ else if (CSKY_TARGET_ARCH (CK802)
+ || CSKY_TARGET_ARCH (CK803)
+ || !TARGET_HIGH_REGISTERS)
+ /* Without high register, r15 cannot hold doubleword data. */
+ return (regno < (CSKY_SP_REGNUM - 1));
+ else
+ return (regno < (CSKY_SP_REGNUM - 1)
+ || (regno >= CSKY_LR_REGNUM
+ && regno < CSKY_LAST_HIGH_UNFIXED_REGNUM));
+ }
+ else if (regno == CSKY_CC_REGNUM)
+ return (mode == CCmode);
+ else if (regno == CSKY_HI_REGNUM || regno == CSKY_LO_REGNUM)
+ {
+ /* Don't allocate hi,lo register for float data even
+ if in dsp mode, because it will cause high cost
+ to reload data from hi,lo register. */
+ if (!TARGET_DSP || mode == SFmode || mode == DFmode)
+ return false;
+ else if (nregs == 2)
+ return (regno == CSKY_HI_REGNUM);
+ else
+ return true;
+ }
+ else if (CSKY_VREG_P (regno) && TARGET_HARD_FLOAT)
+ return true;
+
+ return false;
+}
+
+/* Implement TARGET_MODES_TIEABLE_P. We can't tie DFmode with other modes
+ when V_REGs might be in use because those registers mess with the stored
+ bits. */
+static bool
+csky_modes_tieable_p (machine_mode mode1, machine_mode mode2)
+{
+ return !(TARGET_HARD_FLOAT
+ && mode1 != mode2
+ && (mode1 == DFmode || mode2 == DFmode));
+}
+
+/* Implement TARGET_CAN_CHANGE_MODE_CLASS.
+ V_REG registers can't do subreg as all values are reformatted to
+ internal precision. */
+static bool
+csky_can_change_mode_class (machine_mode from,
+ machine_mode to,
+ reg_class_t rclass)
+{
+ return (GET_MODE_SIZE (from) == GET_MODE_SIZE (to)
+ || !reg_classes_intersect_p (V_REGS, rclass));
+}
+
+/* Implement TARGET_CLASS_LIKELY_SPILLED_P.
+ We need to define this for MINI_REGS when we only use r0 - r7.
+ Otherwise we can end up using r0-r4 for function arguments, and don't
+ have enough left over to do doubleword arithmetic. */
+
+static bool
+csky_class_likely_spilled_p (reg_class_t rclass)
+{
+ if ((TARGET_MINI_REGISTERS && rclass == MINI_REGS)
+ || rclass == C_REGS)
+ return true;
+
+ return false;
+}
+
+
+/* Implement TARGET_PREFERRED_RELOAD_CLASS.
+ Given an rtx X being reloaded into a reg required to be
+ in class CLASS, return the class of reg to actually use.
+ In general this is just CLASS. */
+
+static reg_class_t
+csky_preferred_reload_class (rtx x, reg_class_t rclass)
+{
+ if (TARGET_HARD_FLOAT
+ && CONST_DOUBLE_P (x)
+ && (GET_MODE (x) == DFmode || GET_MODE (x) == SFmode)
+ && rclass == NO_REGS)
+ return GENERAL_REGS;
+ return rclass;
+}
+
+
+/* Implement TARGET_CLASS_MAX_NREGS.
+ Return the maximum number of consecutive registers of class rclass needed
+ to hold a value of mode mode.
+ On the csky, this is the size of MODE in words,
+ except in the FP regs, where a single reg is always enough. */
+
+static unsigned char
+csky_class_max_nregs (reg_class_t rclass, machine_mode mode)
+{
+ if (rclass == V_REGS)
+ return 1;
+ else
+ return CSKY_NUM_REGS (mode);
+}
+
+
+/* Implement TARGET_SECONDARY_RELOAD.
+ If copying a register of RCLASS from/to X requires an intermediate
+ register, the hook should return the REGISTER_CLASS required for this
+ intermediate register.
+ If no intermediate register is required, it should return NO_REGS.
+ If more than one intermediate register is required, describe the one
+ that is closest in the copy chain to the reload register. */
+
+reg_class_t
+csky_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x,
+ reg_class_t rclass,
+ machine_mode mode,
+ secondary_reload_info *sri ATTRIBUTE_UNUSED)
+{
+ int regno = -1;
+
+ /* Extract the real regno from X. */
+ if (GET_CODE (x) == SIGN_EXTEND)
+ {
+ int off = 0;
+
+ x = XEXP (x, 0);
+
+ if (reg_renumber)
+ regno = true_regnum (x);
+ else
+ {
+ while (GET_CODE (x) == SUBREG)
+ {
+ off += subreg_regno_offset (REGNO (SUBREG_REG (x)),
+ GET_MODE (SUBREG_REG (x)),
+ SUBREG_BYTE (x), GET_MODE (x));
+ x = SUBREG_REG (x);
+ }
+
+ if (GET_CODE (x) == REG)
+ regno = REGNO (x) + off;
+ }
+ }
+ else if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG)
+ regno = true_regnum (x);
+
+ /* We always require a general register when copying anything to
+ HI/LO_REGNUM, except when copying an SImode value from HI/LO_REGNUM
+ to a general register, or when copying from register 0. */
+ if ((rclass == HILO_REGS || rclass == LO_REGS || rclass == HI_REGS)
+ && !CSKY_GENERAL_REGNO_P (regno))
+ return GENERAL_REGS;
+
+ if (rclass == V_REGS && !CSKY_GENERAL_REGNO_P (regno))
+ {
+ /* Reload between vector reg and memory does not need an
+ intermediate register. */
+ if (MEM_P (x) && (mode == SFmode || mode == DFmode))
+ return NO_REGS;
+ else
+ return GENERAL_REGS;
+ }
+
+ return NO_REGS;
+}
+
+/* Implement TARGET_SPILL_CLASS.
+ Try spilling to a larger register class before spilling to memory. */
+
+static reg_class_t
+csky_spill_class (reg_class_t rclass, machine_mode mode ATTRIBUTE_UNUSED)
+{
+ if ((rclass == MINI_REGS && !TARGET_MINI_REGISTERS)
+ || (rclass == LOW_REGS && TARGET_HIGH_REGISTERS))
+ return GENERAL_REGS;
+ return NO_REGS;
+}
+
+/* Convert a static initializer array of feature bits to sbitmap
+ representation. */
+static void
+csky_initialize_isa (sbitmap isa, const enum csky_isa_feature *isa_bits)
+{
+ bitmap_clear (isa);
+ while (*isa_bits != CSKY_ISA_FEATURE_GET (none))
+ bitmap_set_bit (isa, *(isa_bits++));
+}
+
+
+/* Configure a build target TARGET from the user-specified options OPTS and
+ OPTS_SET. */
+static void
+csky_configure_build_target (struct csky_build_target *target,
+ struct cl_target_option *opts,
+ struct gcc_options *opts_set)
+{
+ const struct csky_processors *csky_selected_tune = NULL;
+ struct csky_processors *csky_selected_cpu = NULL;
+ struct csky_processors *csky_selected_arch = NULL;
+ sbitmap all_sbits = sbitmap_alloc (CSKY_ISA_FEATURE_GET (max));
+ bitmap_clear (all_sbits);
+
+ bitmap_clear (target->isa);
+ target->core_name = NULL;
+ target->arch_name = NULL;
+
+ if (opts_set->x_csky_arch_option)
+ csky_selected_arch = &all_architectures[opts->x_csky_arch_option];
+
+ if (opts_set->x_csky_cpu_option)
+ {
+ csky_selected_cpu = &all_cores[opts->x_csky_cpu_option];
+ csky_selected_tune = &all_cores[opts->x_csky_cpu_option];
+ }
+
+ if (csky_selected_cpu)
+ {
+ /* TODO: support combination of features
+ between different cpu & arch, should based on arch. */
+ if (csky_selected_arch
+ && (csky_selected_cpu->base_arch != csky_selected_arch->base_arch))
+ warning (0, "cpu %s is not based on arch %s, ignoring the arch",
+ csky_selected_cpu->name, csky_selected_arch->name);
+ if (!csky_selected_arch)
+ csky_selected_arch = &all_architectures[csky_selected_cpu->base_arch];
+ csky_initialize_isa (all_sbits, csky_selected_arch->isa_bits);
+ target->core_name = csky_selected_cpu->name;
+ }
+ else if (csky_selected_arch)
+ {
+ csky_selected_cpu = csky_selected_arch;
+ target->arch_name = csky_selected_arch->name;
+ }
+ else /* If the user did not specify a processor, choose one for them. */
+ {
+ csky_selected_cpu = &all_cores[TARGET_CPU_DEFAULT];
+ csky_selected_arch = &all_architectures[csky_selected_cpu->base_arch];
+ csky_initialize_isa (all_sbits, csky_selected_arch->isa_bits);
+ target->core_name = csky_selected_cpu->name;
+ }
+
+ /* The selected cpu may be an architecture, so lookup tuning by core ID. */
+ if (!csky_selected_tune)
+ csky_selected_tune = &all_cores[csky_selected_cpu->core];
+ gcc_assert (csky_selected_tune);
+
+ gcc_assert (csky_selected_arch);
+ gcc_assert (csky_selected_cpu);
+ csky_initialize_isa (target->isa, csky_selected_cpu->isa_bits);
+ bitmap_ior (target->isa, target->isa, all_sbits);
+
+ /* Finish initializing the target structure. */
+ target->arch_pp_name = csky_selected_cpu->arch;
+ target->base_arch = csky_selected_cpu->base_arch;
+ target->arch_core = csky_selected_cpu->core;
+
+ sbitmap_free (all_sbits);
+}
+
+
+/* Implement TARGET_OPTION_OVERRIDE. */
+
+static void
+csky_option_override (void)
+{
+ csky_active_target.isa = sbitmap_alloc (CSKY_ISA_FEATURE_GET (max));
+
+ /* Create the default target_options structure. We need this early
+ to configure the overall build target. */
+ target_option_default_node = target_option_current_node
+ = build_target_option_node (&global_options);
+
+ csky_configure_build_target (&csky_active_target,
+ TREE_TARGET_OPTION (target_option_default_node),
+ &global_options_set);
+
+#ifdef SUBTARGET_OVERRIDE_OPTIONS
+ SUBTARGET_OVERRIDE_OPTIONS;
+#endif
+
+ csky_base_arch = csky_active_target.base_arch;
+
+ if (flag_pic && !(CSKY_TARGET_ARCH (CK810) || CSKY_TARGET_ARCH (CK807)))
+ {
+ flag_pic = 0;
+ warning (0, "%qs is not supported by arch %s",
+ "-fPIC", csky_active_target.arch_pp_name);
+ }
+
+ /* Check floating-point options for consistency. */
+ if (TARGET_HARD_FLOAT)
+ {
+ const struct csky_fpu_desc *csky_selected_fpu = NULL;
+
+ if (csky_fpu_index == TARGET_FPU_auto)
+ {
+ const char *target_fpu_name;
+ bool ok;
+ int fpu_index;
+
+#ifdef CSKY_FPUTYPE_DEFAULT
+ target_fpu_name = CSKY_FPUTYPE_DEFAULT;
+#else
+ target_fpu_name = "fpv2";
+#endif
+
+ if (csky_active_target.core_name != NULL
+ && !strchr (csky_active_target.core_name, 'f'))
+ target_fpu_name = "auto";
+ else if (CSKY_TARGET_ARCH (CK803) || !TARGET_DOUBLE_FLOAT)
+ target_fpu_name = "fpv2_sf";
+ else if (TARGET_DOUBLE_FLOAT && TARGET_FDIVDU)
+ target_fpu_name = "fpv2_divd";
+
+ ok = opt_enum_arg_to_value (OPT_mfpu_, target_fpu_name, &fpu_index,
+ CL_TARGET);
+ gcc_assert (ok);
+ csky_fpu_index = (enum csky_fpu_type) fpu_index;
+ }
+
+ if (CSKY_TARGET_ARCH (CK801) || CSKY_TARGET_ARCH (CK802))
+ error ("%qs is not supported by arch %s",
+ "-mhard-float", csky_active_target.arch_pp_name);
+ else if (csky_fpu_index == TARGET_FPU_auto)
+ error ("%<-mhard-float%> is not supported by the selected CPU");
+ else
+ {
+ csky_selected_fpu = &all_fpus[csky_fpu_index];
+ sbitmap fpu_bits = sbitmap_alloc (CSKY_ISA_FEATURE_GET (max));
+ csky_initialize_isa (fpu_bits, csky_selected_fpu->isa_bits);
+
+ bitmap_ior (csky_active_target.isa, csky_active_target.isa,
+ fpu_bits);
+
+ sbitmap_free (fpu_bits);
+ }
+ }
+ else
+ {
+ if (TARGET_DOUBLE_FLOAT > 0)
+ warning (0, "%<-mdouble-float%> ignored without %<-mhard-float%>");
+ TARGET_DOUBLE_FLOAT = 0;
+ if (TARGET_FDIVDU > 0)
+ warning (0, "%<-mfdivdu%> ignored without %<-mhard-float%>");
+ TARGET_FDIVDU = 0;
+ }
+
+ /* Extended LRW instructions are enabled by default on CK801, disabled
+ otherwise. */
+ if (TARGET_ELRW == -1)
+ TARGET_ELRW = CSKY_TARGET_ARCH (CK801);
+
+ /* DSP is enabled either by the processor feature or -mdsp
+ command-line option. There is no -mno-dsp option as the assembler
+ doesn't take one. */
+ if (!TARGET_DSP)
+ TARGET_DSP = CSKY_ISA_FEATURE (dsp);
+
+ /* There's both -mdiv and -mno-div. Take default from processor if
+ neither is specified explicitly. */
+ if (TARGET_DIV == -1)
+ TARGET_DIV = CSKY_ISA_FEATURE (div);
+
+ /* TARGET_CONSTANT_POOL is mandatory for CK801 and CK802 and optional
+ for other CPUs.
+ The reason why the compiler has to generate constant pools for CK801/2
+ instead of deferring to the assembler is that these cores don't have a
+ long branch instruction other than jbsr, which clobbers lr. So for
+ the compiler to correctly save/restore lr it has to know whether there
+ are long branches, which depends on having accurate branch length
+ counts, which in turn depends on having control over where constant
+ pools are placed. */
+ if ((CSKY_TARGET_ARCH (CK801) || CSKY_TARGET_ARCH (CK802))
+ && !TARGET_CONSTANT_POOL)
+ error ("%qs is not supported by arch %s",
+ "-mno-constpool", csky_active_target.arch_pp_name);
+ else if (TARGET_CONSTANT_POOL == -1)
+ TARGET_CONSTANT_POOL = (CSKY_TARGET_ARCH (CK801)
+ || CSKY_TARGET_ARCH (CK802));
+
+ /* TARGET_MINI_REGISTERS is mandatory for CK801, the default for CK802,
+ and optional for other CPUs. TARGET_HIGH_REGISTERS is incompatible
+ with TARGET_MINI_REGISTERS, is not supported by CK801/802/803,
+ and is the default for other processors.
+ See csky_conditional_register_usage. */
+ if (TARGET_MINI_REGISTERS > 0 && TARGET_HIGH_REGISTERS > 0)
+ error ("%<-msmart%> is incompatible with %<-mhigh-registers%>");
+ else if (CSKY_TARGET_ARCH (CK801)
+ || CSKY_TARGET_ARCH (CK802)
+ || CSKY_TARGET_ARCH (CK803))
+ {
+ if (CSKY_TARGET_ARCH (CK801)
+ || (CSKY_TARGET_ARCH (CK802) && TARGET_MINI_REGISTERS == -1))
+ TARGET_MINI_REGISTERS = 1;
+ else if (TARGET_MINI_REGISTERS == -1)
+ TARGET_MINI_REGISTERS = 0;
+ if (TARGET_HIGH_REGISTERS > 0)
+ warning (0, "%qs is not supported by arch %s",
+ "-mhigh-registers", csky_active_target.arch_pp_name);
+ TARGET_HIGH_REGISTERS = 0;
+ }
+ else
+ {
+ if (TARGET_MINI_REGISTERS == -1)
+ TARGET_MINI_REGISTERS = 0;
+ if (TARGET_HIGH_REGISTERS == -1)
+ TARGET_HIGH_REGISTERS = !TARGET_MINI_REGISTERS;
+ }
+
+ /* -mmultiple-stld is the default for everything but CK801, which
+ doesn't support it. */
+ if (CSKY_TARGET_ARCH (CK801))
+ {
+ if (TARGET_MULTIPLE_STLD > 0)
+ warning (0, "%qs is not supported by arch %s",
+ "-mmultiple-stld", csky_active_target.arch_pp_name);
+ TARGET_MULTIPLE_STLD = 0;
+ }
+
+ /* Initialize boolean versions of the architectural flags, for use
+ in the .md file. */
+
+#undef CSKY_ISA
+#define CSKY_ISA(IDENT, DESC) \
+ { \
+ csky_arch_isa_features[CSKY_ISA_FEATURE_GET (IDENT)] = \
+ bitmap_bit_p (csky_active_target.isa, CSKY_ISA_FEATURE_GET (IDENT)); \
+ }
+#include "csky_isa.def"
+#undef CSKY_ISA
+
+ /* TODO */
+
+ /* Resynchronize the saved target options. */
+ cl_target_option_save (TREE_TARGET_OPTION (target_option_default_node),
+ &global_options);
+
+#ifdef ENABLE_TPF_DEBUG
+ /* Don't emit DWARF4 unless specifically selected. The TPF
+ debuggers do not yet support DWARF 3/4. */
+ if (!global_options_set.x_dwarf_strict)
+ dwarf_strict = 1;
+ if (!global_options_set.x_dwarf_version)
+ dwarf_version = 3;
+#endif
+
+ /* Don't run the scheduler before reload by default,
+ since it tends to increase register pressure. */
+ if (!global_options_set.x_flag_schedule_insns)
+ flag_schedule_insns = 0;
+
+ csky_add_gc_roots ();
+}
+
+
+/* Return TRUE if X contains any references to TLS symbols. */
+
+bool
+csky_tls_referenced_p (rtx x)
+{
+ if (!TARGET_TLS)
+ return false;
+
+ subrtx_iterator::array_type array;
+ FOR_EACH_SUBRTX (iter, array, x, ALL)
+ {
+ const_rtx x = *iter;
+ if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x) != 0)
+ return true;
+
+ /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
+ TLS offsets, not real symbol references. */
+ if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
+ iter.skip_subrtxes ();
+ }
+ return false;
+}
+
+
+/* Implement TARGET_CANNOT_FORCE_CONST_MEM.
+ Determine if it's legal to put X into the constant pool. This
+ is not possible for the address of thread-local symbols, which
+ is checked above. */
+
+static bool
+csky_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED,
+ rtx x)
+{
+ return csky_tls_referenced_p (x);
+}
+
+
+/* Implement TARGET_LEGITIMATE_CONSTANT_P. Returns nonzero if the
+ constant value X is a legitimate general operand.
+ It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
+
+static bool
+csky_legitimate_constant_p (machine_mode mode, rtx x)
+{
+ return (!csky_cannot_force_const_mem (mode, x)
+ && CONSTANT_P (x));
+}
+
+
+/* Return true if X is valid as an CSKY addressing register. */
+
+static bool
+is_csky_address_register_rtx_p (rtx x, int strict_p)
+{
+ int regno;
+
+ if (!x)
+ return false;
+ if (!REG_P (x))
+ return false;
+
+ regno = REGNO (x);
+
+ if (strict_p)
+ return (CSKY_GENERAL_REGNO_P (regno)
+ || CSKY_GENERAL_REGNO_P (reg_renumber[regno]));
+ else
+ return CSKY_GENERAL_REGNO_P (regno) || regno >= FIRST_PSEUDO_REGISTER;
+}
+
+
+/* Return TRUE if X is a thread-local symbol. */
+
+static bool
+csky_tls_symbol_p (rtx x)
+{
+ if (!TARGET_TLS)
+ return false;
+
+ if (GET_CODE (x) != SYMBOL_REF)
+ return false;
+
+ return SYMBOL_REF_TLS_MODEL (x) != 0;
+}
+
+
+/* Handle lazy initialization of __tls_get_addr libfunc. */
+static GTY(()) rtx tls_get_addr_libfunc;
+
+static rtx
+get_tls_get_addr (void)
+{
+ if (!tls_get_addr_libfunc)
+ tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr");
+ return tls_get_addr_libfunc;
+}
+
+
+/* Emit a call to __tls_get_addr. */
+
+static rtx_insn *
+csky_call_tls_get_addr (rtx x, rtx reg, rtx *valuep, int reloc)
+{
+ rtx label, labelno, unspec, tmp;
+ rtx_insn *insns;
+
+ start_sequence ();
+
+ labelno = GEN_INT (tls_labelno++);
+ label = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno), UNSPEC_TLS_LABEL);
+ unspec = gen_rtx_UNSPEC (Pmode,
+ gen_rtvec (3, x, GEN_INT (reloc), label),
+ UNSPEC_TLS);
+ tmp = gen_reg_rtx (SImode);
+ emit_move_insn (reg, unspec);
+ emit_move_insn (tmp, label);
+ emit_insn (gen_addsi3 (reg, reg, tmp));
+ *valuep = emit_library_call_value (get_tls_get_addr (),
+ NULL_RTX, LCT_PURE, /* LCT_CONST? */
+ Pmode, reg, Pmode);
+ insns = get_insns ();
+ end_sequence ();
+ return insns;
+}
+
+/* Helper function for csky_legitimize_address, to handle the TLS cases.
+ REG is a scratch register and may be null. */
+
+rtx
+csky_legitimize_tls_address (rtx x, rtx reg)
+{
+ rtx dest, tp, label, labelno, unspec, ret, eqv, addend, tmp;
+ rtx_insn *insns;
+ unsigned int model = SYMBOL_REF_TLS_MODEL (x);
+
+ if (!reg)
+ reg = gen_reg_rtx (SImode);
+
+ switch (model)
+ {
+ case TLS_MODEL_GLOBAL_DYNAMIC:
+ insns = csky_call_tls_get_addr (x, reg, &ret, TLS_GD32);
+ dest = gen_reg_rtx (Pmode);
+ emit_libcall_block (insns, dest, ret, x);
+ return dest;
+
+ case TLS_MODEL_LOCAL_DYNAMIC:
+ insns = csky_call_tls_get_addr (x, reg, &ret, TLS_LDM32);
+
+ /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
+ share the LDM result with other LD model accesses. */
+ eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const1_rtx), UNSPEC_TLS);
+ dest = gen_reg_rtx (Pmode);
+ emit_libcall_block (insns, dest, ret, eqv);
+
+ /* Load the addend. */
+ addend = gen_rtx_UNSPEC (Pmode,
+ gen_rtvec (2, x, GEN_INT (TLS_LDO32)),
+ UNSPEC_TLS);
+ addend = force_reg (SImode, addend);
+ return gen_rtx_PLUS (Pmode, dest, addend);
+
+ case TLS_MODEL_INITIAL_EXEC:
+ labelno = GEN_INT (tls_labelno++);
+ label = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno), UNSPEC_TLS_LABEL);
+ unspec = gen_rtx_UNSPEC (Pmode,
+ gen_rtvec (3, x, GEN_INT (TLS_IE32), label),
+ UNSPEC_TLS);
+ tmp = gen_reg_rtx (SImode);
+ emit_move_insn (reg, unspec);
+ emit_move_insn (tmp, label);
+ emit_insn (gen_addsi3 (reg, reg, tmp));
+ emit_move_insn (reg, gen_const_mem (Pmode, reg));
+ tp = gen_rtx_REG (SImode, CSKY_TLS_REGNUM);
+ return gen_rtx_PLUS (Pmode, tp, reg);
+
+ case TLS_MODEL_LOCAL_EXEC:
+ unspec = gen_rtx_UNSPEC (Pmode,
+ gen_rtvec (2, x, GEN_INT (TLS_LE32)),
+ UNSPEC_TLS);
+ emit_move_insn (reg, unspec);
+ tp = gen_rtx_REG (SImode, CSKY_TLS_REGNUM);
+ return gen_rtx_PLUS (Pmode, tp, reg);
+
+ default:
+ abort ();
+ }
+}
+
+
+/* Implement TARGET_LEGITIMIZE_ADDRESS. */
+
+static rtx
+csky_legitimize_address (rtx x, rtx orig_x ATTRIBUTE_UNUSED,
+ machine_mode mode)
+{
+ if (csky_tls_symbol_p (x))
+ return csky_legitimize_tls_address (x, NULL_RTX);
+
+ if (GET_CODE (x) == PLUS)
+ {
+ rtx xop0 = XEXP (x, 0);
+ rtx xop1 = XEXP (x, 1);
+
+ if (is_csky_address_register_rtx_p (xop0, 0)
+ && CONST_INT_P (xop1))
+ {
+ HOST_WIDE_INT offset = INTVAL (xop1);
+
+ /* Try to replace ld32 rx,(ry, offset), to addi16 rz, oimm8
+ and ld16 rx,(rz, new_ld_offset) to avoid emitting a
+ 32-bit ld, but this addi has a range limitation. */
+ if (optimize_size
+ && offset > CSKY_LD16_MAX_OFFSET (mode)
+ && offset <= (CSKY_ADDI16_MAX_IMM
+ + CSKY_LD16_MAX_OFFSET (mode)))
+ {
+ HOST_WIDE_INT new_ld_offset
+ = offset & CSKY_LD16_OFFSET_MASK (mode);
+
+ xop0 = force_operand (plus_constant (Pmode, xop0,
+ offset - new_ld_offset),
+ NULL_RTX);
+ x = plus_constant (Pmode, xop0, new_ld_offset);
+ }
+ else if (offset < 0 && offset >= (-CSKY_SUBI16_MAX_IMM))
+ x = force_operand (x, NULL_RTX);
+ else if (offset > CSKY_LD16_MAX_OFFSET (mode)
+ || offset < 0)
+ {
+ /* For the remaining cases, force the constant into a
+ register. */
+ xop1 = force_reg (SImode, xop1);
+ x = gen_rtx_PLUS (SImode, xop0, xop1);
+ }
+ }
+
+ /* If the index is store in register, force the
+ base to register. */
+ if (is_csky_address_register_rtx_p (xop1, 0)
+ && !is_csky_address_register_rtx_p (xop0, 0))
+ {
+ xop0 = force_operand (xop0, NULL_RTX);
+ x = gen_rtx_PLUS (SImode, xop0, xop1);
+ }
+ }
+ /* Make sure to take full advantage of the pre-indexed addressing mode
+ with absolute addresses which often allows for the base register to
+ be factorized for multiple adjacent memory references, and it might
+ even allows for the mini pool to be avoided entirely. */
+ else if (CONST_INT_P (x) && optimize > 0)
+ {
+ HOST_WIDE_INT mask, base, index;
+ rtx base_reg;
+
+ mask = CSKY_LD16_OFFSET_MASK (mode);
+ base = INTVAL (x) & ~mask;
+ index = INTVAL (x) & mask;
+ base_reg = force_reg (SImode, GEN_INT (base));
+ x = plus_constant (Pmode, base_reg, index);
+ }
+
+ return x;
+}
+
+
+/* Return nonzero if INDEX is valid for an address index operand.
+ ck801 use 16 bits ld
+ ck802 use 16 and 32 bits ld
+ others use ld and ldr. */
+
+static int
+ck801_legitimate_index_p (machine_mode mode, rtx index,
+ int strict_p ATTRIBUTE_UNUSED)
+{
+ enum rtx_code code = GET_CODE (index);
+
+ /* When the mode size is larger than 4, we may use two ld instruction
+ to get data, the index and (index+1) should be valid. */
+ if (GET_MODE_SIZE (mode) >= 8)
+ return (code == CONST_INT
+ && INTVAL (index) < CSKY_LD16_MAX_OFFSET (SImode)
+ && INTVAL (index) >= 0 && (INTVAL (index) & 3) == 0);
+
+ if (code == CONST_INT && GET_MODE_SIZE (mode) > 0
+ && INTVAL (index) <= CSKY_LD16_MAX_OFFSET (mode)
+ && INTVAL (index) >= 0)
+ return ((INTVAL (index) % GET_MODE_SIZE (mode)) == 0);
+
+ return 0;
+}
+
+
+static int
+ck802_legitimate_index_p (machine_mode mode, rtx index,
+ int strict_p ATTRIBUTE_UNUSED)
+{
+ enum rtx_code code = GET_CODE (index);
+
+ /* When the mode size is larger than 4, we may use two ld instruction
+ to get data, the index and (index+1) should be valid. */
+ if (GET_MODE_SIZE (mode) >= 8)
+ return (code == CONST_INT
+ && INTVAL (index) < CSKY_LD32_MAX_OFFSET (SImode)
+ && INTVAL (index) >= 0 && (INTVAL (index) & 3) == 0);
+
+ if (code == CONST_INT && GET_MODE_SIZE (mode) > 0
+ && INTVAL (index) <= CSKY_LD32_MAX_OFFSET (mode)
+ && INTVAL (index) >= 0)
+ return ((INTVAL (index) % GET_MODE_SIZE (mode)) == 0);
+
+ return 0;
+}
+
+
+/* The instruction ldr rz, (rx, ry << i), i can be 0,1,2,3.
+ Check that SHIFT is valid, that the code is MULT, and that
+ the shift is a power of 2. */
+
+static bool
+is_ldr_shift_p (HOST_WIDE_INT shift, enum rtx_code code)
+{
+ if (code == ASHIFT)
+ return (shift >= 0 && shift <= 3);
+ else if (code == MULT)
+ return (shift == 1
+ || shift == 2
+ || shift == 4
+ || shift == 8);
+ else
+ return false;
+}
+
+
+static int
+ck810_legitimate_index_p (machine_mode mode, rtx index, int strict_p)
+{
+ enum rtx_code code = GET_CODE (index);
+
+ if (TARGET_HARD_FLOAT
+ && (mode == SFmode || mode == DFmode))
+ return (code == CONST_INT && INTVAL (index) < 1024
+ && INTVAL (index) >= 0
+ && (INTVAL (index) & 3) == 0);
+
+ if (code == CONST_INT)
+ {
+ /* When the mode size is larger than 4, we may use two ld instruction
+ to get data, the index and (index+1) should be valid. */
+ if (GET_MODE_SIZE (mode) >= 8)
+ return (INTVAL (index) < CSKY_LD32_MAX_OFFSET (SImode)
+ && INTVAL (index) >= 0 && (INTVAL (index) & 3) == 0);
+
+ if (GET_MODE_SIZE (mode) > 0
+ && INTVAL (index) <= CSKY_LD32_MAX_OFFSET (mode)
+ && INTVAL (index) >= 0)
+ return ((INTVAL (index) % GET_MODE_SIZE (mode)) == 0);
+ }
+ /* Allow ld.w rx, (gb, sym@got) when -fpic specially. */
+ else if (code == UNSPEC)
+ return (flag_pic == 1
+ && (XINT (index, 1) == UNSPEC_PIC_SYMBOL_PLT
+ || XINT (index, 1) == UNSPEC_PIC_SYMBOL_GOT));
+ /* The follow index is for ldr instruction, the ldr cannot
+ load dword data, so the mode size should not be larger than
+ 4. */
+ else if (GET_MODE_SIZE (mode) <= 4)
+ {
+ if (is_csky_address_register_rtx_p (index, strict_p))
+ return 1;
+ else if (code == MULT || code == ASHIFT)
+ {
+ rtx xiop0 = XEXP (index, 0);
+ rtx xiop1 = XEXP (index, 1);
+
+ /* FIXME can the xiop1 be the reg and xiop0 be the int when mult? */
+ return (is_csky_address_register_rtx_p (xiop0, strict_p)
+ && CONST_INT_P (xiop1)
+ && is_ldr_shift_p (INTVAL (xiop1), code));
+ }
+ }
+
+ return 0;
+}
+
+
+static int
+csky_legitimate_index_p (machine_mode mode, rtx index, int strict_p)
+{
+ if (CSKY_TARGET_ARCH (CK801))
+ return ck801_legitimate_index_p (mode, index, strict_p);
+ else if (CSKY_TARGET_ARCH (CK802))
+ return ck802_legitimate_index_p (mode, index, strict_p);
+ else
+ return ck810_legitimate_index_p (mode, index, strict_p);
+}
+
+
+/* Implement TARGET_LEGITIMATE_ADDRESS_P.
+ Recognizes RTL expressions that are valid memory addresses for an
+ instruction. The MODE argument is the machine mode for the MEM
+ expression that wants to use this address.
+
+ It only recognizes address in canonical form. LEGITIMIZE_ADDRESS should
+ convert common non-canonical forms to canonical form so that they will
+ be recognized. */
+
+static bool
+csky_legitimate_address_p (machine_mode mode, rtx addr, bool strict_p)
+{
+ enum rtx_code code = GET_CODE (addr);
+
+ /* Match the RTX form emitted for constant pool references.
+ After reload constants split into minipools will have addresses
+ from a LABEL_REF. */
+ if (reload_completed
+ && ((code == LABEL_REF)
+ || (code == CONST
+ && GET_CODE (XEXP (addr, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (addr, 0), 0)) == LABEL_REF
+ && CONST_INT_P (XEXP (XEXP (addr, 0), 1)))))
+ return 1;
+
+ if (is_csky_address_register_rtx_p (addr, strict_p))
+ return 1;
+ /* It is a pc-relative load, may be generated for constpool. */
+ else if (GET_CODE (addr) == LABEL_REF)
+ return 1;
+
+ if (code == PLUS)
+ {
+ rtx xop0 = XEXP (addr, 0);
+ rtx xop1 = XEXP (addr, 1);
+
+ return ((is_csky_address_register_rtx_p (xop0, strict_p)
+ && csky_legitimate_index_p (mode, xop1, strict_p))
+ || (is_csky_address_register_rtx_p (xop1, strict_p)
+ && csky_legitimate_index_p (mode, xop0, strict_p)));
+ }
+
+ return 0;
+}
+
+
+/* Functions to save and restore machine-specific function data. */
+
+static struct machine_function *
+csky_init_machine_status (void)
+{
+ struct machine_function *machine;
+
+ machine = ggc_cleared_alloc<machine_function> ();
+
+#if CSKY_FT_UNKNOWN != 0
+ machine->func_type = CSKY_FT_UNKNOWN;
+#endif
+ return machine;
+}
+
+
+/* Implement INIT_EXPANDERS. */
+
+void
+csky_init_expanders (void)
+{
+ /* Arrange to initialize and mark the machine per-function status. */
+ init_machine_status = csky_init_machine_status;
+}
+
+
+/* Implement TARGET_CANNOT_COPY_INSN_P.
+ We must not copy any rtx that uses a pc-relative address. */
+
+static bool
+csky_cannot_copy_insn_p (rtx_insn *insn)
+{
+ subrtx_iterator::array_type array;
+ FOR_EACH_SUBRTX (iter, array, PATTERN (insn), ALL)
+ {
+ const_rtx x = *iter;
+ if (GET_CODE (x) == UNSPEC
+ && (XINT (x, 1) == UNSPEC_TLS_LABEL
+ || XINT (x, 1) == UNSPEC_PIC_SYMBOL_GOTPC_GRS))
+ return true;
+ }
+ return false;
+}
+
+
+/* Extract the parts of an RTL expression that is a valid memory address
+ for an instruction. Return FALSE if it is a invalid memory address. */
+
+struct csky_address
+{
+ rtx base, index, symbol, label, disp;
+ HOST_WIDE_INT scale;
+};
+
+static bool
+decompose_csky_address (rtx addr, struct csky_address *out)
+{
+ rtx base = NULL_RTX, index = NULL_RTX, disp = NULL_RTX;
+ HOST_WIDE_INT scale = 1;
+ rtx scale_rtx = NULL_RTX;
+ int i;
+
+ out->base = out->index = out->symbol = out->label = out->disp = NULL_RTX;
+ out->scale = 0;
+
+ if (REG_P (addr))
+ {
+ out->base = addr;
+ return true;
+ }
+
+ if (GET_CODE (addr) == LABEL_REF)
+ {
+ out->label = addr;
+ return true;
+ }
+
+ if (GET_CODE (addr) == CONST)
+ addr = XEXP (addr, 0);
+
+ if (GET_CODE (addr) == PLUS)
+ {
+ rtx addends[2], op;
+
+ addends[0] = XEXP (addr, 0);
+ addends[1] = XEXP (addr, 1);
+
+ if (GET_CODE (addends[0]) == LABEL_REF && CONST_INT_P (addends[1]))
+ {
+ out->label = addends[0];
+ out->disp = addends[1];
+ return true;
+ }
+
+ if (!REG_P (addends[0]))
+ std::swap (addends[0], addends[1]);
+
+ for (i = 0; i < 2; ++i)
+ {
+ op = addends[i];
+ switch (GET_CODE (op))
+ {
+ case REG:
+ if (!base)
+ base = op;
+ else if (!index)
+ index = op;
+ else
+ return false;
+ break;
+ case CONST_INT:
+ case UNSPEC:
+ if (disp)
+ return false;
+ disp = op;
+ break;
+ case MULT:
+ if (index)
+ return false;
+ index = XEXP (op, 0);
+ scale_rtx = XEXP (op, 1);
+ if (!CONST_INT_P (index) && !CONST_INT_P (scale_rtx))
+ return false;
+ else if (CONST_INT_P (index))
+ std::swap (index, scale_rtx);
+ scale = INTVAL (scale_rtx);
+ break;
+ case ASHIFT:
+ if (index)
+ return false;
+ index = XEXP (op, 0);
+ scale_rtx = XEXP (op, 1);
+ if (!CONST_INT_P (scale_rtx))
+ return false;
+ scale = scale << INTVAL (scale_rtx);
+ break;
+ default:
+ return false;
+ }
+ }
+ }
+
+ if (!base)
+ return false;
+
+ out->base = base;
+ out->index = index;
+ out->disp = disp;
+ out->scale = scale;
+
+ return true;
+}
+
+/* Helper function for the csky_simple_mem_operand predicate. Returns
+ true if OP is an address of the form reg + displacement. */
+
+bool
+csky_simple_addr_operand_p (rtx op)
+{
+ struct csky_address addr;
+
+ if (!decompose_csky_address (op, &addr))
+ return false;
+
+ /* FIXME The PIC related code.
+ Check if load the symbol address from got table. */
+ if (addr.disp && GET_CODE (addr.disp) == UNSPEC)
+ return false;
+ if (!addr.index && !addr.symbol)
+ return true;
+ return false;
+}
+
+
+/* Print the UNSPEC operand in X to the STREAM. */
+
+static void
+csky_output_pic_addr_const (FILE *stream, rtx x, int code)
+{
+
+ if (GET_CODE (x) != UNSPEC)
+ return;
+
+ if (UNSPEC_TLS == XINT (x, 1))
+ {
+ /* FIXME It is not reached */
+ return;
+ }
+
+ csky_print_operand (stream, XVECEXP (x, 0, 0), code);
+
+ switch (XINT (x, 1))
+ {
+ case UNSPEC_PIC_SYMBOL_GOTOFF:
+ fputs ("@GOTOFF", stream);
+ break;
+ case UNSPEC_PIC_SYMBOL_PLT:
+ fputs ("@PLT", stream);
+ break;
+ case UNSPEC_PIC_SYMBOL_GOT:
+ fputs ("@GOT", stream);
+ break;
+ case UNSPEC_PIC_SYMBOL_GOTPC:
+ fputs ("@GOTPC", stream);
+ break;
+ case UNSPEC_PIC_SYMBOL_BSR:
+ break;
+ default:
+ break;
+ }
+}
+
+
+/* Output the constpool label according to the rtx expression X. */
+
+static void
+csky_output_constpool_label (FILE *stream, rtx x)
+{
+ char buf[15];
+
+ gcc_assert (GET_CODE (x) == LABEL_REF);
+ x = XEXP (x, 0);
+
+ if (GET_CODE (x) == UNSPEC_VOLATILE && XINT (x, 1) == VUNSPEC_POOL_LABEL)
+ {
+ ASM_GENERATE_INTERNAL_LABEL (buf, CSKY_CONSTPOOL_LABEL_PREFIX,
+ INTVAL (XVECEXP (x, 0, 0)));
+ assemble_name (stream, buf);
+ }
+}
+
+
+/* Implement TARGET_PRINT_OPERAND_ADDRESS. */
+
+static void
+csky_print_operand_address (FILE *stream,
+ machine_mode mode ATTRIBUTE_UNUSED,
+ rtx x)
+{
+
+ struct csky_address addr;
+
+ decompose_csky_address (x, &addr);
+
+ if (addr.label && addr.disp && GET_CODE (addr.disp) == CONST_INT)
+ {
+ fprintf (stream, "[");
+ csky_output_constpool_label (stream, addr.label);
+ fprintf (stream, "+%d]", (int) INTVAL (addr.disp));
+ }
+ else if (addr.label)
+ {
+ fprintf (stream, "[");
+ csky_output_constpool_label (stream, addr.label);
+ fprintf (stream, "]");
+ }
+ else if (addr.symbol && addr.disp && GET_CODE (addr.disp) == CONST_INT)
+ {
+ fprintf (stream, "[");
+ output_addr_const (stream, addr.symbol);
+ fprintf (stream, "+%d]", (int) INTVAL (addr.disp));
+ }
+ else if (addr.symbol)
+ {
+ fprintf (stream, "[");
+ output_addr_const (stream, addr.symbol);
+ fprintf (stream, "]");
+ }
+ else if (addr.disp && GET_CODE (addr.disp) == CONST_INT)
+ fprintf (stream, "(%s, %d)",
+ reg_names[REGNO (addr.base)], (int) INTVAL (addr.disp));
+ else if (addr.disp && GET_CODE (addr.disp) == UNSPEC)
+ {
+ if (REGNO (addr.base) != CSKY_GB_REGNUM)
+ fprintf (stream, "(%s, ", reg_names[REGNO (addr.base)]);
+ else
+ fprintf (stream, "[");
+ csky_output_pic_addr_const (stream, addr.disp, 0);
+ fprintf (stream, "%s", (REGNO (addr.base) != CSKY_GB_REGNUM)
+ ? ")" : "]");
+ }
+ else if (addr.index)
+ fprintf (stream, "(%s, %s << %d)",
+ reg_names[REGNO (addr.base)], reg_names[REGNO (addr.index)],
+ exact_log2 ((int) (addr.scale)));
+ else
+ fprintf (stream, "(%s, 0)", reg_names[REGNO (addr.base)]);
+}
+
+
+/* Implement TARGET_PRINT_OPERAND.
+ Print operand X (an rtx) in assembler syntax to file STREAM
+ according to modifier CODE.
+
+ 'N' print the log2(X+1), mainly used for bmaski
+ 'P' print the log2(X)
+ 'Q' print the log2(~X)
+ 'O' print a decimal number
+ 'M' print a decimal number as its negative
+ 'R' print the next register or memory location along, i.e. the lsw in
+ a double word value
+ 'H' print the high 16 bits of a constant. */
+
+static void
+csky_print_operand (FILE *stream, rtx x, int code)
+{
+ switch (code)
+ {
+ case 'N':
+ if ((INTVAL (x) & 0xffffffff) == 0xffffffff)
+ fprintf (stream, "0");
+ else
+ fprintf (stream, "%d",
+ (int) exact_log2 ((INTVAL (x) & 0xffffffff) + 1) % 32);
+ break;
+ case 'P':
+ fprintf (stream, "%d",
+ (int) exact_log2 (INTVAL (x) & 0xffffffff));
+ break;
+ case 'Q':
+ fprintf (stream, "%d",
+ (int) exact_log2 (~INTVAL (x) & 0xffffffff));
+ break;
+ case 'O':
+ fprintf (stream, "%d", (int) INTVAL (x));
+ break;
+ case 'M':
+ fprintf (stream, "%d", (int) (-INTVAL (x)));
+ break;
+ case 'R':
+ /* Next location along in memory or register. */
+ switch (GET_CODE (x))
+ {
+ case REG:
+ fputs (reg_names[REGNO (x) + 1], stream);
+ break;
+ case MEM:
+ csky_print_operand_address
+ (stream, GET_MODE (x), XEXP (adjust_address (x, SImode, 4), 0));
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ break;
+ case 'H':
+ fprintf (stream, "%ld", (long)((INTVAL (x) & 0xFFFF0000) >> 16));
+ break;
+ default:
+ switch (GET_CODE (x))
+ {
+ case REG:
+ fputs (reg_names[REGNO (x)], stream);
+ break;
+ case MEM:
+ output_address (GET_MODE (x), XEXP (x, 0));
+ break;
+ case UNSPEC:
+ csky_output_pic_addr_const (stream, x, code);
+ break;
+ default:
+ output_addr_const (stream, x);
+ break;
+ }
+ break;
+ }
+}
+
+
+
+/* Implement TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS. */
+
+static bool
+csky_allocate_stack_slots_for_args (void)
+{
+ /* Naked functions should not allocate stack slots for arguments. */
+ return !CSKY_FUNCTION_IS_NAKED (get_csky_current_func_type ());
+}
+
+
+/* Can we generate a constant with a single instruction, without using
+ lrw? */
+
+static int
+const_ok_for_cskyv2 (HOST_WIDE_INT value)
+{
+ /* Try exact power of two. It can be generated by bgeni. */
+ if (CSKY_CONST_OK_FOR_Ub (value))
+ return 1;
+
+ /* Try exact power of two - 1. It can be generated by bmaski. */
+ if (CSKY_CONST_OK_FOR_Uc (value) && value != -1)
+ return 1;
+
+ /* Try if it can be generated by movi. */
+ if (CSKY_CONST_OK_FOR_I (value))
+ return 1;
+
+ /* The constant can be generated by movih.
+ Notice that movih is a 32-bit instruction. */
+ if (CSKY_CONST_OK_FOR_MOVIH (value))
+ return 1;
+
+ return 0;
+}
+
+
+/* Tricks for synthesizing constants from values that can be directly
+ manipulated by machine instructions. */
+
+enum csky_inline_const_type
+{
+ IC_UNINLINABLE = 0, /* Not inlineable */
+ IC_SINGLE, /* Single instruction */
+ IC_APPEND_NOT, /* Single instruction followed by a not */
+ IC_APPEND_ADDI, /* Single insn followed by an addi */
+ IC_APPEND_SUBI, /* Single insn followed by a subi */
+ IC_BGENI_ADDI, /* Single insn(bgeni) followed by an addi */
+ IC_BGENI_SUBI, /* Single insn(bgeni) followed by a subi */
+ IC_APPEND_BSETI, /* Single insn followed by bseti */
+ IC_APPEND_MOVI, /* Single insn followed by movi */
+ IC_APPEND_BCLRI, /* Single insn followed by bclri */
+ IC_APPEND_ROTLI, /* Single insn followed by rotli */
+ IC_APPEND_LSLI, /* Single insn followed by lsli */
+ IC_APPEND_IXH, /* Single insn followed by ixh */
+ IC_APPEND_IXW /* Single insn followed by ixw */
+};
+
+
+/* Try tricks to load a constant inline and return the trick number if
+ success, or IC_UNINLINABLE. */
+
+static enum csky_inline_const_type
+try_csky_constant_tricks (HOST_WIDE_INT value, HOST_WIDE_INT *x,
+ HOST_WIDE_INT *y)
+{
+ HOST_WIDE_INT i, value_invert;
+ unsigned HOST_WIDE_INT bit, shf, rot, lobits, hibits;
+
+ value &= 0xffffffff;
+ value_invert = ~value & 0xffffffff;
+
+ if (const_ok_for_cskyv2 (value))
+ {
+ *x = value;
+ return IC_SINGLE;
+ }
+
+ /* Since movih is 32 bits, do not use it here, better code may
+ be generated later. */
+ if (const_ok_for_cskyv2 (value_invert)
+ && !CSKY_CONST_OK_FOR_MOVIH (value_invert))
+ {
+ *x = value_invert;
+ return IC_APPEND_NOT;
+ }
+
+ /* One immediate generate instruction, and one 16-bit subi or addi. */
+ for (i = 1; i <= 32; i++)
+ {
+ if (const_ok_for_cskyv2 (value - i)
+ && !CSKY_CONST_OK_FOR_MOVIH (value - i))
+ {
+ *x = value - i;
+ *y = i;
+ return IC_APPEND_ADDI;
+ }
+
+ if (const_ok_for_cskyv2 (value + i)
+ && !CSKY_CONST_OK_FOR_MOVIH (value - i))
+ {
+ *x = value + i;
+ *y = i;
+ return IC_APPEND_SUBI;
+ }
+ }
+
+ /* Generate bgeni + addi. */
+ if (CSKY_CONST_OK_FOR_Ub (value & 0xfffff000))
+ {
+ *x = (value & 0xfffff000);
+ *y = (value & 0xfff);
+ return IC_BGENI_ADDI;
+ }
+
+ /* Generate bgeni + subi. */
+ lobits = value & 0xfff;
+ hibits = (unsigned HOST_WIDE_INT)(value & 0xfffff000) + (1 << 12);
+ if (exact_log2 (hibits) >= 1
+ && exact_log2 (hibits) <= 30
+ && lobits != 0)
+ {
+ *x = hibits;
+ *y = (0x1000 - lobits);
+ return IC_BGENI_SUBI;
+ }
+
+ /* One immediate generate instruction, and one bseti or bclri. */
+ bit = 0x80000000ULL;
+ for (i = 0; i <= 31; i++)
+ {
+ if (const_ok_for_cskyv2 (value & ~bit)
+ && !CSKY_CONST_OK_FOR_MOVIH (value & ~bit))
+ {
+ *y = bit;
+ *x = (value & ~bit);
+ return IC_APPEND_BSETI;
+ }
+
+ if (const_ok_for_cskyv2 (value | bit)
+ && !CSKY_CONST_OK_FOR_MOVIH (value | bit))
+ {
+ *y = ~bit & 0xffffffff;
+ *x = value | bit;
+ return IC_APPEND_BCLRI;
+ }
+
+ bit >>= 1;
+ }
+
+ /* One immediate generate instruction, and one rotli or lsli. */
+ shf = value;
+ rot = value;
+ for (i = 1; i < 31; i++)
+ {
+ int c;
+
+ /* Rotate left. */
+ c = rot << 31;
+ rot >>= 1;
+ rot &= 0x7FFFFFFF;
+ rot |= c;
+
+ if (const_ok_for_cskyv2 (rot) && !CSKY_CONST_OK_FOR_MOVIH (rot))
+ {
+ *y = i;
+ *x = rot;
+ return IC_APPEND_ROTLI;
+ }
+
+ /* Can't use logical shift when low order bit is one. */
+ if (shf & 1)
+ shf = 0;
+ else
+ shf >>= 1;
+
+ if (shf != 0 && const_ok_for_cskyv2 (shf)
+ && !CSKY_CONST_OK_FOR_MOVIH (shf))
+ {
+ *y = i;
+ *x = shf;
+ return IC_APPEND_LSLI;
+ }
+ }
+
+ /* One immediate generate instruction, and one ixh. */
+ if (CSKY_ISA_FEATURE (E2)
+ && (value % 3) == 0
+ && const_ok_for_cskyv2 (value / 3)
+ && !CSKY_CONST_OK_FOR_MOVIH (value / 3))
+ {
+ *x = value / 3;
+ return IC_APPEND_IXH;
+ }
+
+ /* One immediate generate instruction, and one ixw. */
+ if (CSKY_ISA_FEATURE (E2)
+ && (value % 5) == 0
+ && const_ok_for_cskyv2 (value / 5)
+ && !CSKY_CONST_OK_FOR_MOVIH (value / 5))
+ {
+ *x = value / 5;
+ return IC_APPEND_IXW;
+ }
+
+ /* Generate movih + bseti. */
+ if (CSKY_CONST_OK_FOR_Ub (value & 0xffff))
+ {
+ *x = value & 0xffff0000;
+ *y = value & 0xffff;
+ return IC_APPEND_BSETI;
+ }
+
+ /* Generate movih + not. */
+ if (CSKY_CONST_OK_FOR_MOVIH (value_invert))
+ {
+ *x = value_invert;
+ return IC_APPEND_NOT;
+ }
+
+ /* One movih, and one 16bits addi or subi. */
+ for (i = 1; i <= 32; i++)
+ {
+ if (CSKY_CONST_OK_FOR_MOVIH (value - i))
+ {
+ *x = value - i;
+ *y = i;
+ return IC_APPEND_ADDI;
+ }
+
+ if (CSKY_CONST_OK_FOR_MOVIH (value + i))
+ {
+ *x = value + i;
+ *y = i;
+ return IC_APPEND_SUBI;
+ }
+ }
+
+ /* One movih, and one bseti or bclri. */
+ bit = 0x80000000ULL;
+ for (i = 0; i <= 31; i++)
+ {
+ if (CSKY_CONST_OK_FOR_MOVIH (value & ~bit))
+ {
+ *y = bit;
+ *x = value & ~bit;
+ return IC_APPEND_BSETI;
+ }
+
+ if (CSKY_CONST_OK_FOR_MOVIH (value | bit))
+ {
+ *y = ~bit & 0xffffffff;
+ *x = value | bit;
+ return IC_APPEND_BCLRI;
+ }
+
+ bit >>= 1;
+ }
+
+ /* One movih, and one rotli or lsli. */
+ shf = value;
+ rot = value;
+ for (i = 1; i < 31; i++)
+ {
+ int c;
+
+ /* Rotate left. */
+ c = rot << 31;
+ rot >>= 1;
+ rot &= 0x7FFFFFFF;
+ rot |= c;
+
+ if (CSKY_CONST_OK_FOR_MOVIH (rot))
+ {
+ *y = i;
+ *x = rot;
+ return IC_APPEND_ROTLI;
+ }
+
+ /* Can't use logical shift when low order bit is one. */
+ if (shf & 1)
+ shf = 0;
+ else
+ shf >>= 1;
+
+ if (shf != 0 && CSKY_CONST_OK_FOR_MOVIH (shf))
+ {
+ *y = i;
+ *x = shf;
+ return IC_APPEND_LSLI;
+ }
+ }
+
+ return IC_UNINLINABLE;
+}
+
+
+/* Actually output a constant using a trick.
+ FIXME: I think this would be better handled by a splitter than at the
+ asm output level. */
+
+static const char *
+csky_output_inline_const (machine_mode mode, rtx operands[])
+{
+ HOST_WIDE_INT x = 0, y = 0;
+ enum csky_inline_const_type trick_type;
+ rtx out_operands[3];
+ char buf[256];
+ char load_op[128];
+ const char *dst_fmt;
+ HOST_WIDE_INT value = INTVAL (operands[1]);
+ int ivalue = (int) value;
+ unsigned int uvalue = (unsigned int) value;
+
+ trick_type = try_csky_constant_tricks (value, &x, &y);
+ /* lrw's are handled separately: Large inlinable constants never get
+ turned into lrw's. Our caller uses try_csky_constant_tricks to back
+ off to an lrw rather than calling this routine. */
+ gcc_assert (trick_type != IC_UNINLINABLE);
+
+ /* Operands: 0 = dst, 1 = load immedate., 2 = adjust immedate. */
+ out_operands[0] = operands[0];
+ out_operands[1] = GEN_INT (x);
+ if (trick_type != IC_SINGLE && trick_type != IC_APPEND_NOT)
+ out_operands[2] = GEN_INT (y);
+
+ /* Select dst format based on mode. */
+ if (mode == DImode && TARGET_BIG_ENDIAN)
+ dst_fmt = "%R0";
+ else
+ dst_fmt = "%0";
+
+ /* Try movi16: 0~31,movi32: 0~65535. */
+ if (CSKY_CONST_OK_FOR_I (x))
+ sprintf (load_op, "movi\t%s, %%1", dst_fmt);
+ /* Try exact power of two - 1. */
+ else if (CSKY_CONST_OK_FOR_Uc (x))
+ sprintf (load_op, "bmaski\t%s, %%N1", dst_fmt);
+ /* Try movih. */
+ else if (CSKY_CONST_OK_FOR_MOVIH (x))
+ sprintf (load_op, "movih\t%s, %%H1", dst_fmt);
+ else
+ {
+ sprintf (load_op, "BADMOVI-inline_const %s, %%1", dst_fmt);
+ gcc_unreachable ();
+ }
+
+ switch (trick_type)
+ {
+ case IC_SINGLE:
+ strcpy (buf, load_op);
+ break;
+ /* Add instruction 'not'. */
+ case IC_APPEND_NOT:
+ sprintf (buf, "%s\n\tnot\t%s, %s\t// %d 0x%x", load_op, dst_fmt,
+ dst_fmt, ivalue, uvalue);
+ break;
+ /* Add instruction 'addi'. */
+ case IC_APPEND_ADDI:
+ sprintf (buf, "%s\n\taddi\t%s, %s, %%2\t// %d 0x%x", load_op,
+ dst_fmt, dst_fmt, ivalue, uvalue);
+ break;
+ /* Add instruction 'subi'. */
+ case IC_APPEND_SUBI:
+ sprintf (buf, "%s\n\tsubi\t%s, %s, %%2\t// %d 0x%x", load_op,
+ dst_fmt, dst_fmt, ivalue, uvalue);
+ break;
+ /* Add instruction 'addi', the last instruction is bgeni. */
+ case IC_BGENI_ADDI:
+ sprintf (buf, "%s\n\taddi\t%s, %s, %%2\t// %d 0x%x", load_op,
+ dst_fmt, dst_fmt, ivalue, uvalue);
+ break;
+ /* Add instruction 'subi', the last instruction is bgeni. */
+ case IC_BGENI_SUBI:
+ sprintf (buf, "%s\n\tsubi\t%s, %s, %%2\t// %d 0x%x", load_op,
+ dst_fmt, dst_fmt, ivalue, uvalue);
+ break;
+ /* Add instruction 'bseti'. */
+ case IC_APPEND_BSETI:
+ sprintf (buf, "%s\n\tbseti\t%s, %s, %%P2\t// %d 0x%x", load_op,
+ dst_fmt, dst_fmt, ivalue, uvalue);
+ break;
+ /* Add instruction 'movi'. */
+ case IC_APPEND_MOVI:
+ sprintf (buf, "%s\n\tmovi\t%s, %%2\t// %d 0x%x", load_op, dst_fmt,
+ ivalue, uvalue);
+ break;
+ /* Add instruction 'bclri'. */
+ case IC_APPEND_BCLRI:
+ sprintf (buf, "%s\n\tbclri\t%s, %s, %%Q2\t// %d 0x%x", load_op,
+ dst_fmt, dst_fmt, ivalue, uvalue);
+ break;
+ /* Add instruction 'rotli'. */
+ case IC_APPEND_ROTLI:
+ sprintf (buf, "%s\n\trotli\t%s, %s, %%2\t// %d 0x%x", load_op,
+ dst_fmt, dst_fmt, ivalue, uvalue);
+ break;
+ /* Add instruction 'lsli'. */
+ case IC_APPEND_LSLI:
+ sprintf (buf, "%s\n\tlsli\t%s, %s, %%2\t// %d 0x%x", load_op,
+ dst_fmt, dst_fmt, ivalue, uvalue);
+ break;
+ /* Add instruction 'ixh'. */
+ case IC_APPEND_IXH:
+ sprintf (buf, "%s\n\tixh\t%s, %s, %s\t// %d 0x%x", load_op,
+ dst_fmt, dst_fmt, dst_fmt, ivalue, uvalue);
+ break;
+ /* Add instruction 'ixw'. */
+ case IC_APPEND_IXW:
+ sprintf (buf, "%s\n\tixw\t%s, %s, %s\t// %d 0x%x", load_op,
+ dst_fmt, dst_fmt, dst_fmt, ivalue, uvalue);
+ break;
+ default:
+ return "";
+ }
+
+ output_asm_insn (buf, out_operands);
+
+ return "";
+}
+
+/* This is a helper function for the Uo constraint for movsi patterns. */
+
+bool
+csky_inlinable_constant (HOST_WIDE_INT value)
+{
+ HOST_WIDE_INT x, y;
+ return (!(CSKY_TARGET_ARCH (CK802) || CSKY_TARGET_ARCH (CK801))
+ && try_csky_constant_tricks (value, &x, &y));
+}
+
+
+/* Return true if the constant VAL can be expressed by an 8-bit constant
+ with a shift value, filling in *BASE and *SHIFT. */
+
+bool
+csky_shifted_imm8_constant (unsigned HOST_WIDE_INT val,
+ unsigned int *base, unsigned int *shift)
+{
+ unsigned HOST_WIDE_INT mask = 0xff;
+ int i;
+ val = val & (unsigned HOST_WIDE_INT) 0xffffffffu;
+ if (val == 0)
+ return 0;
+
+ for (i = 0; i < 25; i++)
+ if ((val & (mask << i)) == val)
+ {
+ if (base)
+ *base = (unsigned int) (val >> i);
+ if (shift)
+ *shift = (unsigned int) i;
+ return true;
+ }
+
+ return false;
+}
+
+
+/* Output a move of a word or less value. */
+
+const char *
+csky_output_move (rtx insn ATTRIBUTE_UNUSED, rtx operands[],
+ machine_mode mode ATTRIBUTE_UNUSED)
+{
+ rtx dst = operands[0];
+ rtx src = operands[1];
+ struct csky_address op0, op1;
+
+ if (REG_P (dst))
+ {
+ /* The situation mov reg to reg. */
+ if (REG_P (src))
+ {
+ int dstreg = REGNO (dst);
+ int srcreg = REGNO (src);
+
+ /* hilo registers exchange their places,
+ and their order of Dimode as same as other
+ general registers in LITTLE_ENDIAN mode. */
+ if (TARGET_BIG_ENDIAN)
+ {
+ if (dstreg == CSKY_HI_REGNUM)
+ return "mthi\t%1";
+ else if (dstreg == CSKY_LO_REGNUM)
+ return "mtlo\t%1";
+ else if (srcreg == CSKY_HI_REGNUM)
+ return "mfhi\t%0";
+ else if (srcreg == CSKY_LO_REGNUM)
+ return "mflo\t%0";
+ }
+ else
+ {
+ if (dstreg == CSKY_HI_REGNUM)
+ return "mtlo\t%1";
+ else if (dstreg == CSKY_LO_REGNUM)
+ return "mthi\t%1";
+ else if (srcreg == CSKY_HI_REGNUM)
+ return "mflo\t%0";
+ else if (srcreg == CSKY_LO_REGNUM)
+ return "mfhi\t%0";
+ }
+
+ if (CSKY_VREG_P (dstreg) && CSKY_VREG_P (srcreg))
+ return "fmovs\t%0, %1";
+ if (CSKY_VREG_P (dstreg))
+ return "fmtvrl\t%0, %1";
+ if (CSKY_VREG_P (srcreg))
+ return "fmfvrl\t%0, %1";
+
+ if (REGNO (src) == CSKY_CC_REGNUM)
+ return "mvc\t%0";
+ else
+ return "mov\t%0, %1";
+ }
+ /* The situation mov memory to reg. */
+ else if (GET_CODE (src) == MEM)
+ {
+ decompose_csky_address (XEXP (src, 0), &op1);
+
+ if (op1.index)
+ switch (GET_MODE (src))
+ {
+ case E_HImode:
+ return "ldr.h\t%0, %1";
+ case E_QImode:
+ return "ldr.b\t%0, %1";
+ case E_SImode:
+ case E_SFmode:
+ if (CSKY_VREG_P (REGNO (dst)))
+ return "fldrs\t%0, %1";
+ else
+ return "ldr.w\t%0, %1";
+ default:
+ gcc_unreachable ();
+ }
+ /* Generate lrw rx, [LABEL]. This happens when the compiler
+ generates constant pool references and uses lrw to get the
+ constant into memory. */
+ else if (op1.label)
+ return "lrw\t%0, %1";
+ /* Generate lrs.w rx, [symbol@GOT/PLT]. */
+ else if (flag_pic == 1 && op1.disp && GET_CODE (op1.disp) == UNSPEC)
+ return "lrs.w\t%0, %1";
+ else
+ switch (GET_MODE (src))
+ {
+ case E_HImode:
+ return "ld.h\t%0, %1";
+ case E_QImode:
+ return "ld.b\t%0, %1";
+ case E_SFmode:
+ case E_SImode:
+ if (CSKY_VREG_P (REGNO (dst)))
+ return "flds\t%0, %1";
+ else
+ return "ld.w\t%0, %1";
+ default:
+ gcc_unreachable ();
+ }
+ }
+ /* The situation mov integer to reg. */
+ else if (GET_CODE (src) == CONST_INT ||
+ (GET_CODE (src) == CONST_DOUBLE && GET_MODE (src) == SFmode))
+ {
+ HOST_WIDE_INT x, y;
+ const REAL_VALUE_TYPE *d;
+ long l;
+
+ if (GET_CODE (src) == CONST_DOUBLE && GET_MODE (src) == SFmode)
+ {
+ d = CONST_DOUBLE_REAL_VALUE (src);
+ REAL_VALUE_TO_TARGET_SINGLE (*d, l);
+ operands[1] = GEN_INT (l);
+ src = operands[1];
+ }
+
+ if (try_csky_constant_tricks (INTVAL (src), &x, &y))
+ return csky_output_inline_const (SImode, operands);
+ /* Return '#' to split it. */
+ else if (CSKY_CONST_OK_FOR_T (INTVAL (src)))
+ return "#";
+ else
+ return "lrw\t%0, %x1\t";
+ }
+ else if (TARGET_ANCHOR && GET_CODE (src) == SYMBOL_REF)
+ {
+ if (SYMBOL_REF_FUNCTION_P (src))
+ return "lrw\t%0, %1@BTEXT";
+ else
+ return "lrw\t%0, %1@BDATA";
+ }
+ else if (GET_CODE (src) == UNSPEC
+ && XINT (src, 1) == UNSPEC_PIC_SYMBOL_GRS)
+ return "grs\t%0, %1";
+ else
+ return "lrw\t%0, %1";
+ }
+ else if (GET_CODE (dst) == MEM)
+ {
+ decompose_csky_address (XEXP (dst, 0), &op0);
+
+ if (op0.index)
+ switch (GET_MODE (src))
+ {
+ case E_HImode:
+ return "str.h\t%1, %0";
+ case E_QImode:
+ return "str.b\t%1, %0";
+ case E_SFmode:
+ case E_SImode:
+ if (CSKY_VREG_P (REGNO (src)))
+ return "fstrs\t%1, %0";
+ else
+ return "str.w\t%1, %0";
+ default:
+ gcc_unreachable ();
+ }
+ else
+ switch (GET_MODE (dst))
+ {
+ case E_HImode:
+ return "st.h\t%1, %0";
+ case E_QImode:
+ return "st.b\t%1, %0";
+ case E_SImode:
+ case E_SFmode:
+ if (CSKY_VREG_P (REGNO (src)))
+ return "fsts\t%1, %0";
+ else
+ return "st.w\t%1, %0";
+ default:
+ gcc_unreachable ();
+ }
+ }
+
+ gcc_unreachable ();
+}
+
+
+/* Output a move of a word or less value. Specific for ck801. */
+
+const char *
+csky_output_ck801_move (rtx insn ATTRIBUTE_UNUSED, rtx operands[],
+ machine_mode mode ATTRIBUTE_UNUSED)
+{
+ rtx dst = operands[0];
+ rtx src = operands[1];
+ struct csky_address op1;
+
+ if (REG_P (dst))
+ {
+ if (REG_P (src))
+ return "mov\t%0, %1";
+ else if (GET_CODE (src) == MEM)
+ {
+ decompose_csky_address (XEXP (src, 0), &op1);
+
+ /* Generate lrw rx, [LABEL]. This happens when the compiler
+ generates constant pool references and uses lrw to get the
+ constant in memory. */
+ if (op1.label)
+ return "lrw\t%0, %1";
+ else
+ switch (GET_MODE (src))
+ {
+ case E_HImode:
+ return "ld.h\t%0, %1";
+ case E_QImode:
+ return "ld.b\t%0, %1";
+ case E_SFmode:
+ case E_SImode:
+ return "ld.w\t%0, %1";
+ default:
+ gcc_unreachable ();
+ }
+ }
+ else if (GET_CODE (src) == CONST_INT)
+ {
+ if (REGNO (dst) > 7)
+ return "lrw\t%0, %x1\t";
+ else if (CSKY_CONST_OK_FOR_N (INTVAL (src) + 1))
+ return "movi\t%0, %1";
+ /* Return '#' to split it. */
+ else if (CSKY_CONST_OK_FOR_T (INTVAL (src)))
+ return "#";
+ else if (csky_shifted_imm8_constant (INTVAL (src), NULL, NULL))
+ return "#";
+ else
+ return "lrw\t%0, %x1\t";
+ }
+ else if (GET_CODE (src) == CONST_DOUBLE && GET_MODE (src) == SFmode)
+ {
+ const REAL_VALUE_TYPE *d;
+ long l;
+
+ d = CONST_DOUBLE_REAL_VALUE (src);
+ REAL_VALUE_TO_TARGET_SINGLE (*d, l);
+ operands[1] = GEN_INT (l);
+ src = operands[1];
+
+ if (CSKY_CONST_OK_FOR_N (INTVAL (src) + 1))
+ return "movi\t%0, %1";
+ else
+ return "lrw\t%0, %x1\t";
+ }
+ else if (TARGET_ANCHOR && GET_CODE (src) == SYMBOL_REF)
+ {
+ if (SYMBOL_REF_FUNCTION_P (src))
+ return "lrw\t%0, %1@BTEXT";
+ else
+ return "lrw\t%0, %1@BDATA";
+ }
+ else
+ return "lrw\t%0, %1";
+ }
+ else if (GET_CODE (dst) == MEM)
+ switch (GET_MODE (dst))
+ {
+ case E_HImode:
+ return "st.h\t%1, %0";
+ case E_QImode:
+ return "st.b\t%1, %0";
+ case E_SImode:
+ case E_SFmode:
+ return "st.w\t%1, %0";
+ default:
+ gcc_unreachable ();
+ }
+
+ gcc_unreachable ();
+}
+
+
+/* Return a sequence of instructions to perform DI or DF move.
+ Since the CSKY cannot move a DI or DF in one instruction, we have
+ to take care when we see overlapping source and dest registers. */
+
+const char *
+csky_output_movedouble (rtx operands[],
+ machine_mode mode ATTRIBUTE_UNUSED)
+{
+ rtx dst = operands[0];
+ rtx src = operands[1];
+
+ if (REG_P (dst))
+ {
+ if (REG_P (src))
+ {
+ int dstreg = REGNO (dst);
+ int srcreg = REGNO (src);
+
+ if (CSKY_HILO_REG_P (srcreg))
+ {
+ if (TARGET_BIG_ENDIAN)
+ return "mfhi\t%0\n\tmflo\t%R0";
+ else
+ return "mfhi\t%R0\n\tmflo\t%0";
+ }
+ else if (CSKY_HILO_REG_P (dstreg))
+ {
+ if (TARGET_BIG_ENDIAN)
+ return "mthi\t%1\n\tmtlo\t%R1";
+ else
+ return "mthi\t%R1\n\tmtlo\t%1";
+ }
+ else if (CSKY_VREG_P (srcreg) && CSKY_VREG_P (dstreg))
+ return "fmovd\t%0, %1";
+ else if (CSKY_VREG_P (srcreg))
+ {
+ /* Since the vector registers in fpuv2_soft processors
+ like ck803f are 32 bits wide, just one insn is needed
+ to complete the move operation. */
+ if (TARGET_SOFT_FPU)
+ return "fmfvrl\t%0, %1";
+ else if (TARGET_BIG_ENDIAN)
+ return "fmfvrh\t%0, %1\n\tfmfvrl\t%R0, %1";
+ else
+ return "fmfvrh\t%R0, %1\n\tfmfvrl\t%0, %1";
+ }
+ else if (CSKY_VREG_P (dstreg))
+ {
+ if (TARGET_SOFT_FPU)
+ return "fmtvrl\t%0, %1";
+ else if (TARGET_BIG_ENDIAN)
+ return "fmtvrh\t%0, %1\n\tfmtvrl\t%0, %R1";
+ else
+ return "fmtvrh\t%0, %R1\n\tfmtvrl\t%0, %1";
+ }
+
+ /* Ensure the second source not overwritten. */
+ if (srcreg + 1 == dstreg)
+ return "mov\t%R0, %R1\n\tmov\t%0, %1";
+ else
+ return "mov\t%0, %1\n\tmov\t%R0, %R1";
+ }
+ else if (GET_CODE (src) == MEM)
+ {
+ rtx memexp = XEXP (src, 0);
+ int dstreg = REGNO (dst);
+ int basereg = -1;
+ struct csky_address op0;
+
+ decompose_csky_address (XEXP (src, 0), &op0);
+
+ if (GET_CODE (memexp) == LABEL_REF
+ || (GET_CODE (memexp) == CONST
+ && GET_CODE (XEXP (memexp, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (memexp, 0), 0)) == LABEL_REF))
+ return "lrw\t%0, [%1]\n\tlrw\t%R0, [%R1]";
+ else if (GET_CODE (memexp) == REG)
+ basereg = REGNO (memexp);
+ else if (GET_CODE (memexp) == PLUS)
+ {
+ if (GET_CODE (XEXP (memexp, 0)) == REG)
+ basereg = REGNO (XEXP (memexp, 0));
+ else if (GET_CODE (XEXP (memexp, 1)) == REG)
+ basereg = REGNO (XEXP (memexp, 1));
+ else
+ gcc_unreachable ();
+ }
+ else
+ gcc_unreachable ();
+
+
+ /* When FPUV2. */
+ if (CSKY_VREG_P (dstreg))
+ {
+ if (op0.index)
+ return "fldrd\t%0, %1";
+ else
+ return "fldd\t%0, %1";
+ }
+ /* FIXME length attribute is wrong here. */
+ if (dstreg == basereg)
+ /* Just load them in reverse order. */
+ return "ld.w\t%R0, %R1\n\tld.w\t%0, %1";
+ else
+ return "ld.w\t%0, %1\n\tld.w\t%R0, %R1";
+ }
+ else if (GET_CODE (src) == CONST_INT || GET_CODE (src) == CONST_DOUBLE)
+ {
+ split_double (src, operands + 2, operands + 3);
+
+ if (CSKY_CONST_OK_FOR_I (INTVAL (operands[2])))
+ output_asm_insn ("movi\t%0, %2", operands);
+ else if (CSKY_CONST_OK_FOR_Uc (INTVAL (operands[2])))
+ output_asm_insn ("bmaski\t%0, %N2", operands);
+ else if (CSKY_CONST_OK_FOR_Ub (INTVAL (operands[2])))
+ output_asm_insn ("bgeni\t%0, %P2", operands);
+ else
+ output_asm_insn ("lrw\t%0, %2", operands);
+
+ if (CSKY_CONST_OK_FOR_I (INTVAL (operands[3])))
+ output_asm_insn ("movi\t%R0, %3", operands);
+ else if (CSKY_CONST_OK_FOR_Uc (INTVAL (operands[3])))
+ output_asm_insn ("bmaski\t%R0, %N3", operands);
+
+ else if (CSKY_CONST_OK_FOR_Ub (INTVAL (operands[3])))
+ output_asm_insn ("bgeni\t%R0, %P3", operands);
+ else
+ output_asm_insn ("lrw\t%R0, %3", operands);
+
+ return "";
+ }
+ else
+ gcc_unreachable ();
+ }
+ else if (GET_CODE (dst) == MEM && GET_CODE (src) == REG)
+ {
+ rtx memexp = XEXP (dst, 0);
+ int srcreg = REGNO (src);
+ int basereg = -1;
+ struct csky_address op0;
+
+ decompose_csky_address (XEXP (dst, 0), &op0);
+
+ if (GET_CODE (memexp) == REG)
+ basereg = REGNO (memexp);
+ else if (GET_CODE (memexp) == PLUS)
+ {
+ if (GET_CODE (XEXP (memexp, 0)) == REG)
+ basereg = REGNO (XEXP (memexp, 0));
+ else if (GET_CODE (XEXP (memexp, 1)) == REG)
+ basereg = REGNO (XEXP (memexp, 1));
+ else
+ gcc_unreachable ();
+ }
+ else
+ gcc_unreachable ();
+
+ /* When FPUV2. */
+ if (CSKY_VREG_P (srcreg))
+ {
+ if (op0.index)
+ return "fstrd\t%1, %0";
+ else
+ return "fstd\t%1, %0";
+ }
+ /* FIXME length attribute is wrong here. */
+ if (srcreg == basereg)
+ /* Just load them in reverse order. */
+ return "st.w\t%R1, %R0\n\tst.w\t%1, %0";
+ else
+ return "st.w\t%1, %0\n\tst.w\t%R1, %R0";
+ }
+ else
+ gcc_unreachable ();
+}
+
+
+const char *
+csky_output_ck801_movedouble (rtx operands[],
+ machine_mode mode ATTRIBUTE_UNUSED)
+{
+ rtx dst = operands[0];
+ rtx src = operands[1];
+
+ if (REG_P (dst))
+ {
+ if (REG_P (src))
+ {
+ int dstreg = REGNO (dst);
+ int srcreg = REGNO (src);
+
+ /* Ensure the second source not overwritten. */
+ if (srcreg + 1 == dstreg)
+ return "mov\t%R0, %R1\n\tmov\t%0, %1";
+ else
+ return "mov\t%0, %1\n\tmov\t%R0, %R1";
+ }
+ else if (GET_CODE (src) == MEM)
+ {
+ rtx memexp = XEXP (src, 0);
+ int dstreg = REGNO (dst);
+ int basereg = -1;
+ struct csky_address op0;
+
+ decompose_csky_address (XEXP (src, 0), &op0);
+
+ if (GET_CODE (memexp) == LABEL_REF
+ || (GET_CODE (memexp) == CONST
+ && GET_CODE (XEXP (memexp, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (memexp, 0), 0)) == LABEL_REF))
+ return "lrw\t%0, [%1]\n\tlrw\t%R0, [%R1]";
+ else if (GET_CODE (memexp) == REG)
+ basereg = REGNO (memexp);
+ else if (GET_CODE (memexp) == PLUS)
+ {
+ if (GET_CODE (XEXP (memexp, 0)) == REG)
+ basereg = REGNO (XEXP (memexp, 0));
+ else if (GET_CODE (XEXP (memexp, 1)) == REG)
+ basereg = REGNO (XEXP (memexp, 1));
+ else
+ gcc_unreachable ();
+ }
+ else
+ gcc_unreachable ();
+
+ /* FIXME length attribute is wrong here. */
+ if (dstreg == basereg)
+ /* Just load them in reverse order. */
+ return "ld.w\t%R0, %R1\n\tld.w\t%0, %1";
+ else
+ return "ld.w\t%0, %1\n\tld.w\t%R0, %R1";
+ }
+ else if (GET_CODE (src) == CONST_INT || GET_CODE (src) == CONST_DOUBLE)
+ {
+ split_double (src, operands + 2, operands + 3);
+
+ if (REGNO (dst) <= 7
+ && CSKY_CONST_OK_FOR_N (INTVAL (operands[2]) + 1))
+ output_asm_insn ("movi\t%0, %2", operands);
+ else
+ output_asm_insn ("lrw\t%0, %2", operands);
+
+
+ if (REGNO (dst) <= 6
+ && CSKY_CONST_OK_FOR_N (INTVAL (operands[3]) + 1))
+ output_asm_insn ("movi\t%R0, %3", operands);
+ else
+ output_asm_insn ("lrw\t%R0, %3", operands);
+
+ return "";
+
+
+ }
+ else
+ gcc_unreachable ();
+ }
+ else if (GET_CODE (dst) == MEM && GET_CODE (src) == REG)
+ {
+ rtx memexp = XEXP (dst, 0);
+ int srcreg = REGNO (src);
+ int basereg = -1;
+ struct csky_address op0;
+
+ decompose_csky_address (XEXP (dst, 0), &op0);
+
+ if (GET_CODE (memexp) == REG)
+ basereg = REGNO (memexp);
+ else if (GET_CODE (memexp) == PLUS)
+ {
+ if (GET_CODE (XEXP (memexp, 0)) == REG)
+ basereg = REGNO (XEXP (memexp, 0));
+ else if (GET_CODE (XEXP (memexp, 1)) == REG)
+ basereg = REGNO (XEXP (memexp, 1));
+ else
+ gcc_unreachable ();
+ }
+ else
+ gcc_unreachable ();
+
+ /* FIXME length attribute is wrong here. */
+ if (srcreg == basereg)
+ /* Just load them in reverse order. */
+ return "st.w\t%R1, %R0\n\tst.w\t%1, %0";
+ else
+ return "st.w\t%1, %0\n\tst.w\t%R1, %R0";
+ }
+ else
+ gcc_unreachable ();
+}
+
+/* Split operands for an AND expression when OPERANDS[2] is a constant.
+ Note operands[0] is marked earlyclobber in this case and can be
+ overwritten. Return true if "DONE", false otherwise. */
+bool
+csky_split_and (rtx *operands)
+{
+ HOST_WIDE_INT mask = INTVAL (operands[2]);
+ rtx not_value = GEN_INT (~mask);
+ int i;
+
+ /* All zeros or all ones can be handled by a move instruction. */
+ if (mask == 0)
+ {
+ emit_move_insn (operands[0], const0_rtx);
+ return true;
+ }
+ if (mask == -1)
+ {
+ emit_move_insn (operands[0], operands[1]);
+ return true;
+ }
+
+ /* Check for constants that can be handled directly by the 32-bit andi
+ instruction. */
+ if (CSKY_ISA_FEATURE (E2) && csky_arith_O_operand (operands[2], SImode))
+ return false;
+
+ /* Try to transform to andni instruction. */
+ if (CSKY_ISA_FEATURE (E2) && csky_arith_O_operand (not_value, SImode))
+ {
+ emit_insn (gen_cskyv2_andnsi3 (operands[0], not_value, operands[1]));
+ return true;
+ }
+
+ /* If there are only one or two 0 bits in the constant, we can
+ replace the operation with bclri instructions on those bits.
+ Note CK801 has only the 16-bit bclri that operates on a single
+ register, so we must count a move if we are post-reload. */
+ if (popcount_hwi (~mask & 0xffffffff)
+ <= (reload_completed && !CSKY_ISA_FEATURE (E2) ? 1 : 2))
+ {
+ rtx input = operands[1];
+
+ if (!CSKY_ISA_FEATURE (E2))
+ {
+ emit_move_insn (operands[0], input);
+ input = operands[0];
+ }
+
+ for (i = 0; i < 32; i++)
+ if ((mask & (1 << i)) == 0x0)
+ {
+ emit_insn (gen_bclri (operands[0], input, GEN_INT (i)));
+ input = operands[0];
+ }
+ return true;
+ }
+
+ /* If the constant mask is outside the [0, 4095] range for
+ constraint O, or if constraint O is not allowed (ck801),
+ maybe the constant is a contiguous bit range that we can
+ handle by bit extract (low bits) or shifts (high bits). */
+ for (i = (CSKY_ISA_FEATURE (E2) ? 13 : 1); i < 32; i++)
+ {
+ if ((((HOST_WIDE_INT) 1) << i) - 1 == mask)
+ {
+ if (CSKY_ISA_FEATURE (2E3))
+ emit_insn (gen_cskyv2_extzv (operands[0], operands[1],
+ GEN_INT (i), const0_rtx));
+ else
+ {
+ rtx shift = GEN_INT (32 - i);
+ rtx reg = (reload_completed
+ ? operands[0] : gen_reg_rtx (SImode));
+
+ emit_insn (gen_ashlsi3 (reg, operands[1], shift));
+ emit_insn (gen_lshrsi3 (operands[0], reg, shift));
+ }
+ return true;
+ }
+ else if ((((HOST_WIDE_INT) 1) << i) - 1 == ~mask)
+ {
+ rtx shift = GEN_INT (i);
+ rtx reg = (reload_completed
+ ? operands[0] : gen_reg_rtx (SImode));
+
+ emit_insn (gen_lshrsi3 (reg, operands[1], shift));
+ emit_insn (gen_ashlsi3 (operands[0], reg, shift));
+ return true;
+ }
+ }
+
+ /* If the constant is a negative number, it seems better to use
+ andn and copy the NOT_VALUE to a register instead of the
+ original value, since the NOT_VALUE is always smaller and thus
+ more likely to be representable as a small constant.
+ This transformation can only be done before reload because
+ it requires a temporary. Hopefully register allocation can get
+ rid of the extra move required for CK801. */
+ if (!reload_completed && INTVAL (operands[2]) < 0)
+ {
+ rtx reg = copy_to_mode_reg (SImode, not_value);
+
+ if (CSKY_ISA_FEATURE (E2))
+ emit_insn (gen_cskyv2_andnsi3 (operands[0], reg, operands[1]));
+ else
+ {
+ emit_move_insn (operands[0], operands[1]);
+ emit_insn (gen_ck801_andnsi3 (operands[0], reg, operands[0]));
+ }
+ return true;
+ }
+
+ /* If the above ways are all not working, move the constant
+ to a register. We can clobber operands[0] as it is
+ marked earlyclobber in the insn constraints, but then we have to
+ swap operands 1 and 2 to match the constraints on the 2-operand
+ 16-bit and instruction. */
+ if (reload_completed)
+ {
+ emit_move_insn (operands[0], operands[2]);
+ operands[2] = operands[1];
+ operands[1] = operands[0];
+ }
+ else
+ operands[2] = copy_to_mode_reg (SImode, operands[2]);
+ return false;
+}
+
+/* Split operands for an IOR expression when OPERANDS[2] is a constant.
+ Note operands[0] is marked earlyclobber in this case and can be
+ overwritten. Return true if "DONE", false otherwise. */
+bool
+csky_split_ior (rtx *operands)
+{
+ HOST_WIDE_INT mask = INTVAL (operands[2]);
+ int i;
+
+ /* All zeros or all ones can be handled by a move instruction. */
+ if (mask == 0)
+ {
+ emit_move_insn (operands[0], operands[1]);
+ return true;
+ }
+ if (mask == -1)
+ {
+ emit_move_insn (operands[0], gen_int_mode (-1, SImode));
+ return true;
+ }
+
+ /* Check for constants that can be handled directly by the 32-bit ori
+ instruction. */
+ if (CSKY_ISA_FEATURE (E2) && csky_literal_I_operand (operands[2], SImode))
+ return false;
+
+ /* If there are only one or two 1 bits in the value, we can replace
+ the operation with bseti instructions to set those bits.
+ Note CK801 has only the 16-bit bclri that operates on a single
+ register, so we must count a move if we are post-reload. */
+ if (popcount_hwi (mask & 0xffffffff)
+ <= (reload_completed && !CSKY_ISA_FEATURE (E2) ? 1 : 2))
+ {
+ rtx input = operands[1];
+
+ if (!CSKY_ISA_FEATURE (E2))
+ {
+ emit_move_insn (operands[0], input);
+ input = operands[0];
+ }
+
+ for (i = 0; i < 32; i++)
+ if (mask & (1 << i))
+ {
+ emit_insn (gen_bseti (operands[0], input, GEN_INT (i)));
+ input = operands[0];
+ }
+ return true;
+ }
+
+ /* If the above ways are all not working, move the constant
+ to a register. We can clobber operands[0] as it is
+ marked earlyclobber in the insn constraints, but then we have to
+ swap operands 1 and 2 to match the constraints on the 2-operand
+ 16-bit ior instruction. */
+ if (reload_completed)
+ {
+ emit_move_insn (operands[0], operands[2]);
+ operands[2] = operands[1];
+ operands[1] = operands[0];
+ }
+ else
+ operands[2] = copy_to_mode_reg (SImode, operands[2]);
+ return false;
+}
+
+
+/* Split operands for an XOR expression when OPERANDS[2] is a constant.
+ Note operands[0] is marked earlyclobber in this case and can be
+ overwritten. Return true if "DONE", false otherwise. */
+bool
+csky_split_xor (rtx *operands)
+{
+ HOST_WIDE_INT mask = INTVAL (operands[2]);
+
+ /* All zeros can be turned into move instruction. */
+ if (mask == 0)
+ {
+ emit_move_insn (operands[0], operands[1]);
+ return true;
+ }
+
+ /* All ones can be turned into a bitwise not. */
+ if (mask == -1)
+ {
+ if (CSKY_ISA_FEATURE (E2))
+ emit_insn (gen_cskyv2_one_cmplsi2 (operands[0], operands[1]));
+ else
+ {
+ emit_move_insn (operands[0], operands[1]);
+ emit_insn (gen_ck801_one_cmplsi2 (operands[0], operands[0]));
+ }
+ return true;
+ }
+
+ /* Check for constants that can be handled directly by the 32-bit xori
+ instruction. */
+ if (CSKY_ISA_FEATURE (E2) && csky_arith_O_operand (operands[2], SImode))
+ return false;
+
+ /* If the above ways are all not working, move the constant
+ to a register. We can clobber operands[0] as it is
+ marked earlyclobber in the insn constraints, but then we have to
+ swap operands 1 and 2 to match the constraints on the 2-operand
+ 16-bit ior instruction. */
+ if (reload_completed)
+ {
+ emit_move_insn (operands[0], operands[2]);
+ operands[2] = operands[1];
+ operands[1] = operands[0];
+ }
+ else
+ operands[2] = copy_to_mode_reg (SImode, operands[2]);
+ return false;
+}
+
+
+/* Return true if X is an address form involving a symbol or label ref. */
+bool
+csky_symbolic_address_p (rtx x)
+{
+ switch (GET_CODE (x))
+ {
+ case SYMBOL_REF:
+ case LABEL_REF:
+ return 1;
+ case CONST:
+ x = XEXP (x, 0);
+ return ((GET_CODE (XEXP (x, 0)) == SYMBOL_REF
+ || GET_CODE (XEXP (x, 0)) == LABEL_REF)
+ && GET_CODE (XEXP (x, 1)) == CONST_INT);
+ default:
+ return 0;
+ }
+}
+
+
+/* Emit a comparison instruction.
+ Return true if an inverted comparison is generated. */
+
+bool
+csky_emit_compare (enum rtx_code code, rtx op0, rtx op1)
+{
+ bool invert;
+ rtx cc_reg = gen_rtx_REG (CCmode, CSKY_CC_REGNUM);
+
+ if (GET_CODE (op1) == CONST_INT)
+ {
+ HOST_WIDE_INT val = INTVAL (op1);
+
+ switch (code)
+ {
+ case GTU:
+ /* Unsigned (GTU 0) is the same as (NE 0); everything else is
+ converted below to LEU (reversed cmphs). */
+ if (val == 0)
+ code = NE;
+ /* Check whether (GTU A imm) can become (GEU A imm + 1). */
+ else if (TARGET_MINI_REGISTERS
+ ? CSKY_CONST_OK_FOR_J (val + 1)
+ : CSKY_CONST_OK_FOR_Uk (val + 1))
+ {
+ op1 = GEN_INT (val + 1);
+ code = GEU;
+ }
+ break;
+ /* Check whether (LE A imm) can become (LT A imm + 1),
+ or (GT A imm) can become (GE A imm + 1). */
+ case GT:
+ case LE:
+ if (TARGET_MINI_REGISTERS
+ ? CSKY_CONST_OK_FOR_J (val + 1)
+ : CSKY_CONST_OK_FOR_Uk (val + 1))
+ {
+ op1 = GEN_INT (val + 1);
+ code = code == LE ? LT : GE;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (CONSTANT_P (op1) && GET_CODE (op1) != CONST_INT)
+ op1 = force_reg (GET_MODE (op1), op1);
+
+ /* cmpnei: 0-31 (K immediate)
+ ti: 1-32 (J immediate, 0 using btsti x,31). */
+ invert = false;
+ switch (code)
+ {
+ /* Use inverted condition, cmpne. */
+ case EQ:
+ code = NE;
+ invert = true;
+ /* Fall through. */
+ /* Use normal condition, cmpne. */
+ case NE:
+ if (GET_CODE (op1) == CONST_INT
+ && (TARGET_MINI_REGISTERS
+ ? !csky_literal_K_operand (op1, SImode)
+ : !csky_literal_I_operand (op1, SImode)))
+ op1 = force_reg (SImode, op1);
+ break;
+
+ /* Use inverted condition, reversed cmplt. */
+ case LE:
+ code = GT;
+ invert = true;
+ /* Fall through. */
+ /* Use normal condition, reversed cmplt. */
+ case GT:
+ if (GET_CODE (op1) == CONST_INT)
+ op1 = force_reg (SImode, op1);
+ break;
+
+ /* Use inverted condition, cmplt. */
+ case GE:
+ code = LT;
+ invert = true;
+ /* Fall through. */
+ /* Use normal condition, cmplt. */
+ case LT:
+ /* covered by btsti x,31. */
+ if (GET_CODE (op1) == CONST_INT && INTVAL (op1) != 0
+ && (TARGET_MINI_REGISTERS
+ ? !csky_literal_J_operand (op1, SImode)
+ : !csky_literal_Uk_operand (op1, SImode)))
+ op1 = force_reg (SImode, op1);
+ break;
+
+ /* Use inverted condition, cmple. */
+ case GTU:
+ /* We coped with unsigned > 0 above. */
+ gcc_assert (GET_CODE (op1) != CONST_INT || INTVAL (op1) != 0);
+ code = LEU;
+ invert = true;
+ /* Fall through. */
+ /* Use normal condition, reversed cmphs. */
+ case LEU:
+ if (GET_CODE (op1) == CONST_INT && INTVAL (op1) != 0)
+ op1 = force_reg (SImode, op1);
+ break;
+
+ /* Use inverted condition, cmphs. */
+ case LTU:
+ code = GEU;
+ invert = true;
+ /* Fall through. */
+ /* Use normal condition, cmphs. */
+ case GEU:
+ if (GET_CODE (op1) == CONST_INT && INTVAL (op1) != 0
+ && (TARGET_MINI_REGISTERS
+ ? !csky_literal_J_operand (op1, SImode)
+ : !csky_literal_Uk_operand (op1, SImode)))
+ op1 = force_reg (SImode, op1);
+ break;
+
+ default:
+ break;
+ }
+
+ emit_insn (gen_rtx_SET (cc_reg,
+ gen_rtx_fmt_ee (code, CCmode, op0, op1)));
+ return invert;
+}
+
+/* Return true if push/pop can be used to save/restore all the registers
+ indicated by MASK. We currently don't attempt to handle situations where
+ some of the registers could be handled by push/pop and others saved and
+ restored individually. */
+
+static bool
+csky_can_use_pushpop (unsigned int mask)
+{
+ int i;
+ int end_reg;
+
+ if (!TARGET_PUSHPOP)
+ return false;
+
+ if (mask == 0)
+ return false;
+
+ /* Regs 0-3, 12-14, 18-27, 29-31 cannot be in the mask. */
+ if (mask & 0xeffc700f)
+ return false;
+
+ /* Regs in the range r4-r11 must be contiguous. */
+ for (end_reg = 0, i = 11; i >= 4; i--)
+ {
+ if (!end_reg && (mask & (1 << i)))
+ end_reg = i;
+ if (end_reg && !(mask & (1 << i)))
+ return false;
+ }
+
+ /* Likewise for regs in the range r16-r17. */
+ for (end_reg = 0, i = 17; i >= 16; i--)
+ {
+ if (!end_reg && (mask & (1 << i)))
+ end_reg = i;
+ if (end_reg && !(mask & (1 << i)))
+ return false;
+ }
+
+ return true;
+}
+
+
+/* Return true if store/load multiple instructions can be used to
+ save/restore at least some of the registers indicated by MASK.
+ Unlike the push/pop case, this does handle partial ranges.
+ Set *BR and *ER to the beginning and end (respectively) of the
+ register range that can be handled. */
+
+static bool
+csky_can_use_ldstm (int mask, int *br, int *er)
+{
+ int regno;
+ int begin_reg = 0, end_reg = 0;
+ int count = 0;
+
+ if (!TARGET_MULTIPLE_STLD)
+ return false;
+
+ /* We'll only handle registers in the range 4-11, the contiguous range
+ of caller-saved registers. Higher-numbered registers are handled
+ individually in addition to this, but we'll give up on doing ldstm
+ entirely if we need to save/restore the low-numbered EH registers. */
+ if (mask & 0xf)
+ return false;
+
+ for (regno = 4; regno <= 11; regno++)
+ {
+ if (mask & 1 << regno)
+ {
+ if (!begin_reg)
+ begin_reg = regno;
+ end_reg = regno;
+ count++;
+ }
+ else if (begin_reg)
+ break;
+ }
+
+ if (count >= CSKY_MIN_MULTIPLE_STLD && count <= CSKY_MAX_MULTIPLE_STLD)
+ {
+ if (br)
+ *br = begin_reg;
+ if (er)
+ *er = end_reg;
+ return true;
+ }
+ return false;
+}
+
+
+const char *
+csky_output_return_instruction (void)
+{
+ unsigned long func_type = get_csky_current_func_type ();
+
+ if (CSKY_FUNCTION_IS_NAKED (func_type))
+ return "";
+ if (CSKY_FUNCTION_IS_INTERRUPT (func_type))
+ return "ipop\n\tnir\n";
+ else
+ return "rts\n";
+}
+
+
+/* Adjust the stack pointer by OFFSET bytes. OFFSET is negative if this
+ is in the prologue, positive if in the epilogue. This may require
+ multiple instructions and/or use of CSKY_STACKADJUST_REGNUM as
+ a scratch register. Emit CFA notes as appropriate. */
+static void
+expand_csky_stack_adjust (int offset)
+{
+ rtx set;
+ rtx_insn *insn;
+ int size = (offset > 0 ? offset : -offset);
+
+ if (offset == 0)
+ return;
+
+ /* If OFFSET is too large for addi/subi, load it into
+ CSKY_STACKADJUST_REGNUM and use a register add/sub instead.
+ This case is not mentioned in the ABI documentation, but it is
+ supported by GDB prologue analysis provided that the instruction(s)
+ to initialize CSKY_STACKADJUST_REGNUM appear directly before
+ the sub. Depending on the value of OFFSET, this might be a
+ lrw instruction or the "tricks" used by csky_output_inline_const to
+ encode special-case integer constants. */
+ if (size > CSKY_MAX_SP_ADJUST * 2)
+ {
+ rtx tmp, dwarf;
+
+ /* We should have reserved the scratch register already in
+ csky_layout_stack_frame. */
+ gcc_assert (cfun->machine->reg_size != 0
+ && (cfun->machine->reg_mask
+ & (1 << CSKY_STACKADJUST_REGNUM)));
+
+ /* Prevent the optimizer from reordering these instructions to
+ keep GDB happy. */
+ if (!flag_sched_prolog)
+ emit_insn (gen_blockage ());
+
+ tmp = gen_rtx_REG (SImode, CSKY_STACKADJUST_REGNUM);
+ emit_move_insn (tmp, GEN_INT (size));
+
+ if (offset > 0)
+ set = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, tmp);
+ else
+ set = gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, tmp);
+ insn = emit_insn (set);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ dwarf = gen_rtx_SET (stack_pointer_rtx,
+ plus_constant (Pmode, stack_pointer_rtx, offset));
+ add_reg_note (insn, REG_FRAME_RELATED_EXPR, dwarf);
+
+ /* More make GDB happy. */
+ if (!flag_sched_prolog)
+ emit_insn (gen_blockage ());
+ }
+
+ /* Use one or two addi or subi insns to adjust stack. */
+ else
+ while (size)
+ {
+ int delta = (size > CSKY_MAX_SP_ADJUST
+ ? CSKY_MAX_SP_ADJUST : size);
+
+ if (offset > 0)
+ set = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (delta));
+ else
+ set = gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (delta));
+ insn = emit_insn (set);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ size -= delta;
+ }
+}
+
+
+/* Generate and emit an insn that we will recognize as a push_multi.
+ Unfortunately, since this insn does not reflect very well the actual
+ semantics of the operation, we need to annotate the insn for the benefit
+ of DWARF2 frame unwind information. DWARF_REGS_MASK is a subset of
+ MASK for registers that should be annotated for DWARF2 frame unwind
+ information. */
+
+static rtx
+emit_csky_regs_push (unsigned long mask)
+{
+ int num_regs = 0;
+ int i, j;
+ rtx par;
+ rtx dwarf;
+ rtx tmp;
+ int dwarf_par_index;
+
+ for (i = 0; i < CSKY_NGPR_REGS; i++)
+ {
+ if (mask & (1 << i))
+ num_regs++;
+ }
+
+ /* The reg range for push is:r4-r11,r15-r17,r28. */
+ gcc_assert (num_regs && num_regs <= 12);
+
+ /* For the body of the insn we are going to generate an UNSPEC in
+ parallel with several USEs. This allows the insn to be recognized
+ by the push_multi pattern in the csky.md file.
+
+ The body of the insn looks something like this:
+
+ (parallel [
+ (set (mem:BLK (pre_modify:SI (reg:SI sp)
+ (const_int:SI <num>)))
+ (unspec:BLK [(reg:SI r4)] UNSPEC_PUSHPOP_MULT))
+ (use (reg:SI XX))
+ (use (reg:SI YY))
+ ...
+ ])
+
+ For the frame note however, we try to be more explicit and actually
+ show each register being stored into the stack frame, plus a (single)
+ decrement of the stack pointer. We do it this way in order to be
+ friendly to the stack unwinding code, which only wants to see a single
+ stack decrement per instruction. The RTL we generate for the note looks
+ something like this:
+
+ (sequence [
+ (set (reg:SI sp) (plus:SI (reg:SI sp) (const_int -20)))
+ (set (mem:SI (reg:SI sp)) (reg:SI r4))
+ (set (mem:SI (plus:SI (reg:SI sp) (const_int 4))) (reg:SI XX))
+ (set (mem:SI (plus:SI (reg:SI sp) (const_int 8))) (reg:SI YY))
+ ...
+ ])
+
+ FIXME:: In an ideal world the PRE_MODIFY would not exist and
+ instead we'd have a parallel expression detailing all
+ the stores to the various memory addresses so that debug
+ information is more up-to-date. Remember however while writing
+ this to take care of the constraints with the push instruction.
+
+ Note also that this has to be taken care of for the VFP registers.
+
+ For more see PR43399. */
+
+ par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num_regs));
+ dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (num_regs + 1));
+ dwarf_par_index = 1;
+
+ for (i = 0; i < CSKY_NGPR_REGS; i++)
+ if (mask & (1 << i))
+ {
+ rtx reg = gen_rtx_REG (SImode, i);
+ rtx addr = plus_constant (Pmode, stack_pointer_rtx, -4 * num_regs);
+ tmp = gen_frame_mem (BLKmode,
+ gen_rtx_PRE_MODIFY (Pmode,
+ stack_pointer_rtx, addr));
+ XVECEXP (par, 0, 0)
+ = gen_rtx_SET (tmp,
+ gen_rtx_UNSPEC (BLKmode,
+ gen_rtvec (1, reg),
+ UNSPEC_PUSHPOP_MULT));
+ tmp = gen_rtx_SET (gen_frame_mem (SImode, stack_pointer_rtx),
+ reg);
+ RTX_FRAME_RELATED_P (tmp) = 1;
+ XVECEXP (dwarf, 0, dwarf_par_index++) = tmp;
+
+ break;
+ }
+
+ for (j = 1, i++; j < num_regs; i++)
+ if (mask & (1 << i))
+ {
+ rtx reg = gen_rtx_REG (SImode, i);
+ rtx addr = plus_constant (Pmode, stack_pointer_rtx, 4 * j);
+ tmp = gen_rtx_SET (gen_frame_mem (SImode, addr), reg);
+ RTX_FRAME_RELATED_P (tmp) = 1;
+ XVECEXP (par, 0, j) = gen_rtx_USE (VOIDmode, reg);
+ XVECEXP (dwarf, 0, dwarf_par_index++) = tmp;
+ j++;
+ }
+
+ par = emit_insn (par);
+
+ tmp = gen_rtx_SET (stack_pointer_rtx,
+ plus_constant (Pmode, stack_pointer_rtx, -4 * num_regs));
+ RTX_FRAME_RELATED_P (tmp) = 1;
+ XVECEXP (dwarf, 0, 0) = tmp;
+
+ add_reg_note (par, REG_FRAME_RELATED_EXPR, dwarf);
+ RTX_FRAME_RELATED_P (par) = 1;
+
+ return par;
+}
+
+
+/* Generate and emit an insn pattern that we will recognize as a pop_multi.
+ SAVED_REGS_MASK shows which registers need to be restored.
+
+ Unfortunately, since this insn does not reflect very well the actual
+ semantics of the operation, we need to annotate the insn for the benefit
+ of DWARF2 frame unwind information. */
+
+static void
+emit_csky_regs_pop (unsigned long mask)
+{
+ int num_regs = 0;
+ int i, j;
+ rtx par;
+
+ for (i = 0; i < CSKY_NGPR_REGS; i++)
+ if (mask & (1 << i))
+ num_regs++;
+
+ /* The reg range for push is:r4-r11,r15-r17,r28. */
+ gcc_assert (num_regs && num_regs <= 12);
+
+ /* The first element is (return),
+ the second element is
+ (set (reg:SI 'first reg number')
+ (unspec:SI [(mem)] UNSPEC_PUSHPOP_MULT),
+ the rest elements is (use (reg:SI 'rest reg number')),
+ so the length should be number of register to be poped
+ plus one. */
+ par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num_regs + 1));
+
+ XVECEXP (par, 0, 0) = ret_rtx;
+
+ for (i = 0; i < CSKY_NGPR_REGS; i++)
+ if (mask & (1 << i))
+ {
+ rtx reg = gen_rtx_REG (SImode, i);
+ rtx addr = plus_constant (Pmode, stack_pointer_rtx, 4 * num_regs);
+ rtx tmp = gen_frame_mem (SImode,
+ gen_rtx_POST_MODIFY (Pmode,
+ stack_pointer_rtx, addr));
+ XVECEXP (par, 0, 1)
+ = gen_rtx_SET (reg,
+ gen_rtx_UNSPEC (SImode,
+ gen_rtvec (1, tmp),
+ UNSPEC_PUSHPOP_MULT));
+ break;
+ }
+
+ for (j = 2, i++; j < (num_regs + 1); i++)
+ if (mask & (1 << i))
+ {
+ rtx reg = gen_rtx_REG (SImode, i);
+ XVECEXP (par, 0, j) = gen_rtx_USE (VOIDmode, reg);
+ j++;
+ }
+
+ par = emit_jump_insn (par);
+}
+
+
+/* Generate the function prologue. */
+
+void
+csky_expand_prologue (void)
+{
+ rtx_insn *insn;
+ unsigned long func_type = get_csky_current_func_type ();
+ unsigned int reg_mask;
+ int reg_size;
+
+ if (CSKY_FUNCTION_IS_NAKED (func_type))
+ {
+ if (flag_stack_usage_info)
+ current_function_static_stack_size = 0;
+ return;
+ }
+
+ csky_layout_stack_frame ();
+ reg_mask = cfun->machine->reg_mask;
+ reg_size = cfun->machine->reg_size;
+
+ /* Adjust stack pointer past argument overflow area. */
+ if (cfun->machine->arg_size != 0)
+ {
+ int offset = cfun->machine->arg_size;
+ expand_csky_stack_adjust (- offset);
+
+ /* If we have a parameter passed partially in regs and partially
+ in memory, the registers will have been stored to memory already
+ in function.c. So we only need to copy varargs from registers
+ to stack. */
+ if (cfun->machine->uses_anonymous_args)
+ {
+ int rn = CSKY_FIRST_PARM_REGNUM + CSKY_NPARM_REGS - 1;
+ for (offset -= 4; offset >= 0; offset -= 4, rn--)
+ {
+ rtx dst = gen_frame_mem (SImode,
+ plus_constant (Pmode,
+ stack_pointer_rtx,
+ offset));
+ insn = emit_move_insn (dst, gen_rtx_REG (SImode, rn));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+ }
+
+ /* Push caller-saved registers to stack. */
+ if (csky_can_use_pushpop (reg_mask))
+ emit_csky_regs_push (reg_mask);
+ else if (reg_size)
+ {
+ int sreg = -1, ereg = -1;
+ bool stm_p = csky_can_use_ldstm (reg_mask, &sreg, &ereg);
+ int stm_regs = stm_p ? ereg - sreg + 1 : 0;
+ int stm_size = stm_regs * 4;
+
+ /* First adjust the SP to the low end of the register save area. */
+ expand_csky_stack_adjust (- reg_size);
+
+ /* Emit individual register saves. Even if we are going to emit an
+ stm, we may need to save individual registers above that too. */
+ if (reg_size > stm_size)
+ {
+ int offset = reg_size - 4;
+ int regno = 31;
+ for ( ; regno > ereg; regno--)
+ if (reg_mask & (1 << regno))
+ {
+ rtx dst = gen_rtx_MEM (SImode,
+ plus_constant (Pmode,
+ stack_pointer_rtx,
+ offset));
+ rtx insn = emit_insn (gen_movsi (dst,
+ gen_rtx_REG (SImode, regno)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ if (offset == stm_size)
+ break;
+ offset -= 4;
+ }
+ }
+
+ /* If possible, emit a stm to do a bulk store of sequential
+ registers to the stack. Note that it is an error in the ABI
+ documentation that it doesn't list stm as a valid prologue
+ instruction. */
+ if (stm_p)
+ {
+ rtx par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (stm_regs));
+ int regno, slot;
+ for (regno = sreg, slot = 0; regno <= ereg; regno++, slot++)
+ {
+ rtx reg = gen_rtx_REG (SImode, regno);
+ rtx addr = plus_constant (Pmode, stack_pointer_rtx, slot * 4);
+ rtx set = gen_rtx_SET (gen_frame_mem (SImode, addr), reg);
+ RTX_FRAME_RELATED_P (set) = 1;
+ XVECEXP (par, 0, slot) = set;
+ }
+ insn = emit_insn (par);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+
+ /* Initialize hard frame pointer, if necessary. It points at the base
+ of the register save area. */
+ if (frame_pointer_needed)
+ {
+ insn = emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
+ /* Reserve stack space for locals and outgoing args. */
+ expand_csky_stack_adjust (- cfun->machine->reg_offset);
+
+ /* Put the GOT address in reg_gb for PIC, using R13 as a scratch.
+ See section 4.7.1 in the ABI documentation,
+ "Function Prologue for PIC". */
+ if (flag_pic && (reg_mask & (1 << PIC_OFFSET_TABLE_REGNUM)))
+ {
+ rtx l1 = gen_label_rtx ();
+ rtx grs_label = gen_rtx_LABEL_REF (SImode, l1);
+ rtx reg_gb = gen_rtx_REG (SImode, PIC_OFFSET_TABLE_REGNUM);
+ rtx reg_temp = gen_rtx_REG (SImode, 13);
+
+ rtx tmp0_unspec = gen_rtx_UNSPEC (Pmode,
+ gen_rtvec (1, grs_label),
+ UNSPEC_PIC_SYMBOL_GOTPC_GRS);
+ rtx tmp1_unspec = gen_rtx_UNSPEC (Pmode,
+ gen_rtvec (1, grs_label),
+ UNSPEC_PIC_SYMBOL_GOTPC);
+
+ emit_insn (gen_prologue_get_pc (tmp0_unspec));
+ emit_move_insn (reg_temp, tmp1_unspec);
+ emit_insn (gen_addsi3 (reg_gb, reg_gb, reg_temp));
+ }
+
+ if (flag_stack_usage_info)
+ current_function_static_stack_size = cfun->machine->frame_size;
+
+ if (!flag_sched_prolog)
+ emit_insn (gen_blockage ());
+}
+
+void
+csky_expand_epilogue (void)
+{
+ unsigned long func_type = get_csky_current_func_type ();
+ unsigned int reg_mask;
+ int reg_size;
+ int adjust;
+ rtx_insn *insn;
+
+ if (!flag_sched_prolog)
+ emit_insn (gen_blockage ());
+
+ if (CSKY_FUNCTION_IS_NAKED (func_type))
+ {
+ emit_jump_insn (gen_simple_return ());
+ return;
+ }
+
+ /* Get the frame information. */
+ csky_layout_stack_frame ();
+ reg_mask = cfun->machine->reg_mask;
+ reg_size = cfun->machine->reg_size;
+ adjust = reg_size + cfun->machine->arg_size;
+
+ /* Restore the SP to the base of the register save area. */
+ if (frame_pointer_needed)
+ {
+ insn = emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ else
+ expand_csky_stack_adjust (cfun->machine->reg_offset);
+
+ /* Restore the callee-saved registers. */
+ if (csky_can_use_pushpop (reg_mask)
+ && cfun->machine->arg_size == 0
+ && !CSKY_FUNCTION_IS_INTERRUPT (func_type)
+ && !crtl->calls_eh_return)
+ {
+ /* Pop includes an implicit return, so we are done. */
+ emit_csky_regs_pop (reg_mask);
+ return;
+ }
+ else if (reg_size)
+ {
+ int sreg = -1, ereg = -1;
+ bool ldm_p = csky_can_use_ldstm (reg_mask, &sreg, &ereg);
+ int ldm_regs = ldm_p ? ereg - sreg + 1 : 0;
+ int ldm_size = ldm_regs * 4;
+
+ /* Emit individual register loads. Even if we are going to emit an
+ ldm, we may need to load individual registers above that too. */
+ if (reg_size > ldm_size)
+ {
+ int offset = reg_size - 4;
+ int regno = 31;
+ for ( ; regno > ereg; regno--)
+ if (reg_mask & (1 << regno))
+ {
+ rtx src = gen_frame_mem (SImode,
+ plus_constant (Pmode,
+ stack_pointer_rtx,
+ offset));
+ rtx reg = gen_rtx_REG (SImode, regno);
+ insn = emit_move_insn (reg, src);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ add_reg_note (insn, REG_CFA_RESTORE, reg);
+ if (offset == ldm_size)
+ break;
+ offset -= 4;
+ }
+ }
+
+ /* If possible, emit a ldm to do a bulk load of sequential
+ registers from the stack. */
+ if (ldm_p)
+ {
+ rtx par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (ldm_regs));
+ int regno, slot;
+ for (regno = sreg, slot = 0; regno <= ereg; regno++, slot++)
+ {
+ rtx reg = gen_rtx_REG (SImode, regno);
+ rtx addr = plus_constant (Pmode, stack_pointer_rtx, slot * 4);
+ rtx set = gen_rtx_SET (reg, gen_frame_mem (SImode, addr));
+ XVECEXP (par, 0, slot) = set;
+ }
+ insn = emit_insn (par);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ for (regno = sreg; regno <= ereg; regno++)
+ {
+ rtx reg = gen_rtx_REG (SImode, regno);
+ add_reg_note (insn, REG_CFA_RESTORE, reg);
+ }
+ }
+ }
+
+ /* Emit the final stack pointer adjustment to deallocate the saved
+ registers and incoming argument area. */
+ expand_csky_stack_adjust (adjust);
+
+ /* Extra stack adjustment for exception handler return. */
+ if (crtl->calls_eh_return)
+ emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
+ EH_RETURN_STACKADJ_RTX));
+
+ /* Now we can return. */
+ emit_jump_insn (gen_simple_return ());
+}
+
+
+static void
+csky_output_function_prologue (FILE *f)
+{
+ unsigned long func_type = get_csky_current_func_type ();
+
+ switch ((int) CSKY_FUNCTION_TYPE (func_type))
+ {
+ default:
+ case CSKY_FT_NORMAL:
+ break;
+ case CSKY_FT_INTERRUPT:
+ {
+ asm_fprintf (f, "\t# Interrupt Service Routine.\n");
+ asm_fprintf (f, "\tnie\n\tipush\n");
+ break;
+ }
+ case CSKY_FT_FIQ:
+ asm_fprintf (f, "\t# Fast Interrupt Service Routine.\n");
+ break;
+ case CSKY_FT_EXCEPTION:
+ asm_fprintf (f, "\t# CSKY Exception Handler.\n");
+ break;
+ case CSKY_FT_NAKED:
+ asm_fprintf (f, "\t# Naked Function: prologue and epilogue \
+ provided by programmer.\n");
+ return;
+ }
+
+ csky_layout_stack_frame ();
+
+ /* Generate .stack_size function-name, size for callgraph;
+ the default stack size is 0. */
+ if (TARGET_STACK_SIZE && cfun->machine->frame_size > 0)
+ {
+ gcc_assert (current_function_decl != NULL);
+ const char *func_name =
+ IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl));
+ if (func_name[0] == '*')
+ asm_fprintf (f, "\t.stack_size %s, %d\n",
+ &func_name[1], cfun->machine->frame_size);
+ else
+ asm_fprintf (f, "\t.stack_size %s, %d\n",
+ func_name, cfun->machine->frame_size);
+ }
+}
+
+
+static void
+csky_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED)
+{
+
+}
+
+
+/* Helper for csky_eh_return splitter: store the call frame exception
+ handler address in lr. */
+void
+csky_set_eh_return_address (rtx source, rtx scratch)
+{
+ HOST_WIDE_INT delta = 0;
+ rtx basereg, addr;
+ unsigned int reg_mask;
+
+ csky_layout_stack_frame ();
+ reg_mask = cfun->machine->reg_mask;
+
+ if (reg_mask & (1 << CSKY_LR_REGNUM))
+ {
+ /* Find LR in the stack frame. */
+ int i = 0;
+
+ if (frame_pointer_needed)
+ {
+ basereg = frame_pointer_rtx;
+ delta = 0;
+ }
+ else
+ {
+ basereg = stack_pointer_rtx;
+ delta = cfun->machine->reg_offset;
+ }
+
+ /* At this point, (basereg + delta) points at the low end of
+ the reg save area. Regs are saved sequentially from low
+ to high from this address. */
+ for (i = 0; i < CSKY_LR_REGNUM; i++)
+ if (reg_mask & (1 << i))
+ delta += 4;
+
+ if ((CSKY_TARGET_ARCH (CK801) && delta >= CSKY_LD16_MAX_OFFSET (Pmode))
+ || delta >= CSKY_LD32_MAX_OFFSET (Pmode))
+ {
+ emit_insn (gen_movsi (scratch, GEN_INT (delta)));
+ emit_insn (gen_addsi3 (scratch, scratch, basereg));
+ addr = scratch;
+ }
+ else
+ addr = plus_constant (Pmode, basereg, delta);
+ emit_move_insn (gen_frame_mem (Pmode, addr), source);
+ }
+ else
+ emit_move_insn (gen_rtx_REG (Pmode, CSKY_LR_REGNUM), source);
+}
+
+/* Return TRUE if X references a SYMBOL_REF. */
+
+bool
+csky_symbol_mentioned_p (rtx x)
+{
+ const char *fmt;
+ int i;
+
+ if (GET_CODE (x) == SYMBOL_REF)
+ return true;
+
+ fmt = GET_RTX_FORMAT (GET_CODE (x));
+ for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'E')
+ {
+ int j;
+
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ if (csky_symbol_mentioned_p (XVECEXP (x, i, j)))
+ return true;
+ }
+ else if (fmt[i] == 'e' && csky_symbol_mentioned_p (XEXP (x, i)))
+ return true;
+ }
+ return false;
+}
+
+
+/* Return TRUE if X references a LABEL_REF. */
+
+bool
+csky_label_mentioned_p (rtx x)
+{
+ const char *fmt;
+ int i;
+
+ if (GET_CODE (x) == LABEL_REF)
+ return true;
+
+ fmt = GET_RTX_FORMAT (GET_CODE (x));
+ for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'E')
+ {
+ int j;
+
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ if (csky_label_mentioned_p (XVECEXP (x, i, j)))
+ return true;
+ }
+ else if (fmt[i] == 'e' && csky_label_mentioned_p (XEXP (x, i)))
+ return true;
+ }
+
+ return false;
+}
+
+
+static bool
+tls_unspec_mentioned_p (rtx x)
+{
+ switch (GET_CODE (x))
+ {
+ case CONST:
+ return tls_unspec_mentioned_p (XEXP (x, 0));
+
+ case UNSPEC:
+ if (XINT (x, 1) == UNSPEC_TLS)
+ return true;
+
+ /* Fall through. */
+ default:
+ return false;
+ }
+}
+
+
+/* Implement LEGITIMATE_PIC_OPERAND_P. */
+bool
+csky_legitimate_pic_operand_p (rtx x)
+{
+ if (tls_unspec_mentioned_p (x))
+ return true;
+ if (csky_symbol_mentioned_p (x) || csky_label_mentioned_p (x))
+ return false;
+ return true;
+}
+
+rtx
+csky_legitimize_pic_address (rtx orig, rtx reg, bool gotrel_p)
+{
+ rtx pic_reg = gen_rtx_REG (SImode, PIC_OFFSET_TABLE_REGNUM);
+ bool optimize_p = false;
+
+ if (GET_CODE (orig) == SYMBOL_REF || GET_CODE (orig) == LABEL_REF)
+ {
+ rtx pic_ref, address, rtx_tmp;
+ rtx insn;
+ rtx pic_reg = gen_rtx_REG (SImode, PIC_OFFSET_TABLE_REGNUM);
+ int subregs = 0;
+
+ if (reg == 0)
+ {
+ gcc_assert (can_create_pseudo_p ());
+ reg = gen_reg_rtx (Pmode);
+ subregs = 1;
+ }
+
+ if (subregs)
+ address = gen_reg_rtx (Pmode);
+ else
+ address = reg;
+
+ if (GET_CODE (orig) == SYMBOL_REF && !SYMBOL_REF_LOCAL_P (orig))
+ {
+ /* When gotrel_p generate sym@GOT, otherwise generate sym@PLT. */
+ rtx_tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, orig),
+ (gotrel_p
+ ? UNSPEC_PIC_SYMBOL_GOT
+ : UNSPEC_PIC_SYMBOL_PLT));
+ optimize_p = gotrel_p;
+ if (flag_pic != 1)
+ {
+ emit_move_insn (address, rtx_tmp);
+ rtx_tmp = gen_rtx_MULT (Pmode, address, GEN_INT (1));
+ }
+ pic_ref = gen_const_mem (Pmode,
+ gen_rtx_PLUS (Pmode, pic_reg, rtx_tmp));
+ }
+ else
+ {
+ /* bsr symbol */
+ if (flag_pic == 1 && !gotrel_p)
+ {
+ pic_ref = gen_rtx_UNSPEC (Pmode,
+ gen_rtvec (1, orig),
+ UNSPEC_PIC_SYMBOL_BSR);
+ return pic_ref;
+ }
+ /* grs rx, symbol */
+ else if (flag_pic == 1 && (GET_CODE (orig) == SYMBOL_REF)
+ && SYMBOL_REF_FUNCTION_P (orig))
+ {
+ pic_ref = gen_rtx_UNSPEC (Pmode,
+ gen_rtvec (1, orig),
+ UNSPEC_PIC_SYMBOL_GRS);
+ return pic_ref;
+ }
+ /* lrw rx, symbol@GOTOFF; add rx, rx, gb */
+ else
+ {
+ rtx_tmp = gen_rtx_UNSPEC (Pmode,
+ gen_rtvec (1, orig),
+ UNSPEC_PIC_SYMBOL_GOTOFF);
+ emit_move_insn (address, rtx_tmp);
+ pic_ref = gen_rtx_PLUS (Pmode, address, pic_reg);
+ optimize_p = true;
+ }
+ }
+
+ insn = emit_move_insn (reg, pic_ref);
+ /* Put a REG_EQUAL note on this insn,
+ so that it can be optimized by loop. */
+ if (optimize_p)
+ set_unique_reg_note (insn, REG_EQUAL, orig);
+
+ return reg;
+ }
+ else if (GET_CODE (orig) == CONST)
+ {
+ rtx base, offset;
+
+ if (GET_CODE (XEXP (orig, 0)) == PLUS
+ && XEXP (XEXP (orig, 0), 1) == pic_reg)
+ return orig;
+
+ if (reg == 0)
+ {
+ gcc_assert (can_create_pseudo_p ());
+ reg = gen_reg_rtx (Pmode);
+ }
+
+ gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
+
+ base = csky_legitimize_pic_address (XEXP (XEXP (orig, 0), 0),
+ reg, gotrel_p);
+ offset = csky_legitimize_pic_address (XEXP (XEXP (orig, 0), 1),
+ base == reg ? 0 : reg, gotrel_p);
+
+ if (GET_CODE (offset) == CONST_INT)
+ return plus_constant (Pmode, base, INTVAL (offset));
+
+ return gen_rtx_PLUS (Pmode, base, offset);
+ }
+
+ return orig;
+}
+
+
+/* Functions to output assembly code for a function call. */
+
+char *
+csky_output_call (rtx *operands, int index)
+{
+ static char buffer[20];
+ rtx addr = operands[index];
+
+ if (REG_P (addr))
+ sprintf (buffer, "jsr\t%%%d", index);
+ else if (flag_pic && (GET_CODE (addr) == UNSPEC))
+ sprintf (buffer, "bsr\t%%%d", index);
+ else
+ sprintf (buffer, "jbsr\t%%%d", index);
+
+ return buffer;
+}
+
+
+/* Worker function for TARGET_ASM_TRAMPOLINE_TEMPLATE.
+ Output assembler code for a block containing the constant parts
+ of a trampoline, leaving space for the variable parts.
+ Note that STATIC_CHAIN_REGNUM is t1 (aka r12) on ck801 and
+ t1 (r13) otherwise. */
+
+static void
+csky_asm_trampoline_template (FILE *f)
+{
+ if (CSKY_ISA_FEATURE (2E3))
+ {
+ fprintf (f, "\tlrw\t%s, [.Lstatic_chain]\n",
+ reg_names[STATIC_CHAIN_REGNUM]);
+ fprintf (f, "\tjmpi\t[.Lfunc_address]\n");
+ /* 2 32-bit insns = 8 bytes. */
+ }
+ else if (CSKY_TARGET_ARCH (CK801))
+ {
+ /* It's hard to provide general support for trampolines on this
+ core. We need a register other than the one holding the
+ static chain (r13) to hold the function pointer for the
+ indirect jump to it. But ck801 has such a limited register set
+ there is no other call-clobbered scratch register available -- in
+ particular, this core does not have r12, which we use for the
+ ck802 case below. If we use a callee-saved register like r4,
+ saving the old value on the stack screws up the stack frame
+ if there are overflow arguments pushed on the stack
+ by the caller. In theory we could test for that and handle
+ limited cases with parameters that all fit in r0-r3 with no
+ stack overflow, but punt for now. */
+ sorry ("Nested function trampolines not supported on CK801.");
+ }
+ else
+ {
+ fprintf (f, "\tlrw\t%s, [.Lfunc_address]\n",
+ reg_names[CSKY_T1_REGNUM]);
+ fprintf (f, "\tlrw\t%s, [.Lstatic_chain]\n",
+ reg_names[STATIC_CHAIN_REGNUM]);
+ fprintf (f, "\tjmp\t%s\n",
+ reg_names[CSKY_T1_REGNUM]);
+ /* To align constant pool on a word boundary. */
+ fprintf (f, "\t.align 2\n");
+ /* 2 32-bit lrw insns + 16-bit jump + 16-bit pad = 12 bytes. */
+ }
+
+ fprintf (f, ".Lstatic_chain:\n");
+ fprintf (f, "\t.long 0\n");
+ fprintf (f, ".Lfunc_address:\n");
+ fprintf (f, "\t.long 0\n");
+ /* 2 words of constant pool = 8 bytes. */
+}
+
+/* Worker function for TARGET_TRAMPOLINE_INIT. */
+
+static void
+csky_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
+{
+ rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
+ rtx mem, a_tramp;
+ int pool = TRAMPOLINE_SIZE - 8;
+
+ emit_block_move (m_tramp, assemble_trampoline_template (),
+ GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
+
+ mem = adjust_address (m_tramp, SImode, pool);
+ emit_move_insn (mem, chain_value);
+ mem = adjust_address (m_tramp, SImode, pool + 4);
+ emit_move_insn (mem, fnaddr);
+
+ a_tramp = XEXP (m_tramp, 0);
+ emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"),
+ LCT_NORMAL, VOIDmode, a_tramp, Pmode,
+ plus_constant (Pmode, a_tramp, TRAMPOLINE_SIZE), Pmode);
+}
+
+
+/* Emit a comparison insn for float values.
+ Return true if the comparison is inverted. */
+
+bool
+csky_emit_compare_float (enum rtx_code code, rtx op0, rtx op1)
+{
+ rtx cc_reg = gen_rtx_REG (CCmode, CSKY_CC_REGNUM);
+ bool invert;
+ machine_mode mode = GET_MODE (op1);
+
+ if (op1 != CONST0_RTX (mode))
+ op1 = force_reg (mode, op1);
+
+ invert = false;
+ switch (code)
+ {
+ case EQ:
+ code = NE;
+ invert = true;
+ break;
+
+ case NE:
+ break;
+ case LE:
+ if (op1 == CONST0_RTX (mode))
+ op1 = force_reg (mode, op1);
+ break;
+ case GT:
+ if (op1 == CONST0_RTX (mode))
+ op1 = force_reg (mode, op1);
+ break;
+ case GE:
+ break;
+ case LT:
+ if (op1 == CONST0_RTX (mode))
+ {
+ code = GE;
+ invert = true;
+ }
+ break;
+ case UNORDERED:
+ break;
+ case ORDERED:
+ code = UNORDERED;
+ invert = true;
+ break;
+
+ default:
+ break;
+ }
+
+ emit_insn (gen_rtx_SET (cc_reg, gen_rtx_fmt_ee (code, CCmode, op0, op1)));
+
+ return invert;
+}
+
+/* Support for the Q memory constraint. Returns true if OP is a MEM RTX
+ with an address consisting of base + index or base + displacement. */
+bool
+csky_valid_fpuv2_mem_operand (rtx op)
+{
+ struct csky_address addr;
+
+ if (GET_CODE (op) != MEM)
+ return false;
+
+ if (!decompose_csky_address (XEXP (op, 0), &addr))
+ return false;
+
+ /* Verify base register. */
+ if (!is_csky_address_register_rtx_p (addr.base, 0))
+ return false;
+
+ /* Verify index operand. */
+ if (addr.index)
+ {
+ if (!is_csky_address_register_rtx_p (addr.index, 0))
+ return false;
+
+ if (addr.scale == 1 || addr.scale == 2 || addr.scale == 4
+ || addr.scale == 8)
+ return true;
+
+ return false;
+ }
+ /* Verify disp operand. */
+ else if (addr.disp)
+ {
+ rtx disp = addr.disp;
+
+ if (!CONST_INT_P (disp))
+ return false;
+
+ if (((unsigned) INTVAL (disp) % 4) == 0
+ && (unsigned) INTVAL (disp) <= (unsigned) 1020)
+ return true;
+
+ return false;
+ }
+ return true;
+}
+
+
+/* Returns the (interrupt) function type of the current
+ function, or CSKY_FT_UNKNOWN if the type cannot be determined. */
+
+static unsigned long
+csky_isr_value (tree argument)
+{
+ const isr_attribute_entry *ptr;
+ const char *arg;
+
+ /* No argument - default to IRQ. */
+ if (argument == NULL_TREE)
+ return CSKY_FT_ISR;
+
+ /* Get the value of the argument. */
+ if (TREE_VALUE (argument) == NULL_TREE
+ || TREE_CODE (TREE_VALUE (argument)) != STRING_CST)
+ return CSKY_FT_UNKNOWN;
+
+ arg = TREE_STRING_POINTER (TREE_VALUE (argument));
+
+ /* Check it against the list of known arguments. */
+ for (ptr = isr_attribute_map; ptr->arg != NULL; ptr++)
+ if (strcmp (arg, ptr->arg) == 0)
+ return ptr->return_value;
+
+ /* An unrecognized interrupt type. */
+ return CSKY_FT_UNKNOWN;
+}
+
+/* Handle an attribute requiring a FUNCTION_DECL;
+ arguments as in struct attribute_spec.handler. */
+
+static tree
+csky_handle_fndecl_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute only applies to functions",
+ name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle an "interrupt" or "isr" attribute;
+ arguments as in struct attribute_spec.handler. */
+
+static tree
+csky_handle_isr_attribute (tree *node, tree name, tree args, int flags,
+ bool *no_add_attrs)
+{
+
+ if (!TARGET_ISTACK)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored without -mistack",
+ name);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ if (DECL_P (*node))
+ {
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute only applies to functions",
+ name);
+ *no_add_attrs = true;
+ }
+ }
+ else
+ {
+ if (TREE_CODE (*node) == FUNCTION_TYPE
+ || TREE_CODE (*node) == METHOD_TYPE)
+ {
+ if (csky_isr_value (args) == CSKY_FT_UNKNOWN)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+ }
+ else if (TREE_CODE (*node) == POINTER_TYPE
+ && (TREE_CODE (TREE_TYPE (*node)) == FUNCTION_TYPE
+ || TREE_CODE (TREE_TYPE (*node)) == METHOD_TYPE)
+ && csky_isr_value (args) != CSKY_FT_UNKNOWN)
+ {
+ *node = build_variant_type_copy (*node);
+ TREE_TYPE (*node) = build_type_attribute_variant (TREE_TYPE (*node),
+ tree_cons (name, args, TYPE_ATTRIBUTES (TREE_TYPE (*node))));
+ *no_add_attrs = true;
+ }
+ else if (flags & ((int)ATTR_FLAG_DECL_NEXT
+ | (int)ATTR_FLAG_FUNCTION_NEXT
+ | (int)ATTR_FLAG_ARRAY_NEXT))
+ {
+ *no_add_attrs = true;
+ return tree_cons (name, args, NULL_TREE);
+ }
+ else
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ }
+ return NULL_TREE;
+}
+
+
+/* Implement TARGET_REGISTER_MOVE_COST: compute extra cost of moving data
+ between one register class and another. */
+
+int
+csky_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED,
+ reg_class_t from, reg_class_t to)
+{
+#define GR_REG_CLASS_P(CLASS) \
+ ((CLASS) == GENERAL_REGS || (CLASS) == MINI_REGS || (CLASS) == SP_REGS \
+ || (CLASS) == LOW_REGS)
+
+#define HILO_REG_CLASS_P(CLASS) \
+ ((CLASS) == HI_REGS || (CLASS) == LO_REGS || (CLASS) == HILO_REGS)
+
+#define V_REG_CLASS_P(CLASS) \
+ ((CLASS) == V_REGS)
+
+ if (V_REG_CLASS_P (from) && V_REG_CLASS_P (to))
+ return 2;
+
+ if ((V_REG_CLASS_P (from) && GR_REG_CLASS_P (to))
+ || (GR_REG_CLASS_P (from) && V_REG_CLASS_P (to)))
+ return 6;
+
+ if ((HILO_REG_CLASS_P (from) && GR_REG_CLASS_P (to))
+ || (GR_REG_CLASS_P (from) && HILO_REG_CLASS_P (to)))
+ return 16;
+
+ if (HILO_REG_CLASS_P (from) && HILO_REG_CLASS_P (to))
+ return 32;
+
+ if ((HILO_REG_CLASS_P (from) && V_REG_CLASS_P (to))
+ || (V_REG_CLASS_P (from) && HILO_REG_CLASS_P (to)))
+ return 64;
+
+ return 2;
+}
+
+
+/* Implement TARGET_MEMORY_MOVE_COST: compute the cost of moving data
+ between registers and memory. */
+
+int
+csky_memory_move_cost (machine_mode mode, reg_class_t rclass,
+ bool in)
+{
+ return (4 + memory_move_secondary_cost (mode, rclass, in));
+}
+
+
+/* TARGET_RTX_COSTS helper for ck801/ck802. */
+
+static bool
+ck802_ck801_rtx_costs (rtx x, int code, int outer_code, int *total,
+ bool speed)
+{
+ machine_mode mode = GET_MODE (x);
+ switch (code)
+ {
+ /* Accessing memory costs quite a lot for first word; */
+ case MEM:
+ *total = COSTS_N_INSNS (1 + CSKY_NUM_REGS (mode));
+ return false;
+ case DIV:
+ case UDIV:
+ case MOD:
+ case UMOD:
+ *total = 100;
+ return true;
+
+ case ROTATE:
+ case ROTATERT:
+ case ASHIFT:
+ case LSHIFTRT:
+ case ASHIFTRT:
+ if (speed)
+ *total = 2;
+ else
+ *total = COSTS_N_INSNS (1);
+ return false;
+
+ case MINUS:
+ case PLUS:
+ *total = COSTS_N_INSNS (CSKY_NUM_REGS (mode));
+ return false;
+
+ case AND:
+ {
+ enum rtx_code subcode = GET_CODE (XEXP (x, 1));
+
+ /* If subcode is "not", we'll try to combine it into e.g. "andn"
+ instruction, so give AND itself zero cost. */
+ if (subcode == NOT)
+ {
+ *total = 0;
+ return false;
+ }
+ }
+ /* Fall through. */
+ case XOR:
+ case IOR:
+ *total = COSTS_N_INSNS (CSKY_NUM_REGS (mode));
+ return false;
+
+ case MULT:
+ /* FIXME: is ixw supported on ck801/ck802? */
+ /* We can use "ix.h/w" insn to replace multiply by 2 or 4.
+ "ix.h/w" is a 32-bit insn, so let its cost be a little less than
+ "mult" insn. */
+ if (REG_P (XEXP (x, 0)) && CONST_INT_P (XEXP (x, 1)))
+ {
+ unsigned HOST_WIDE_INT m
+ = (unsigned HOST_WIDE_INT) (INTVAL (XEXP (x, 1)));
+ if ((m == 2 || m == 4) && outer_code == PLUS)
+ {
+ *total = 2;
+ return true;
+ }
+ else
+ {
+ /* Because mult is relatively slower than other operations,
+ we try to use other insns when optimizing for speed.
+ When optimizing for size, give it lower cost. */
+ if (speed)
+ {
+ *total = COSTS_N_INSNS (10 * CSKY_NUM_REGS (mode));
+ return true;
+ }
+ int cycle = 0;
+ while (m)
+ {
+ m >>= 2;
+ cycle++;
+ }
+ *total = COSTS_N_INSNS (1) + cycle;
+ return false;
+ }
+ }
+ if (!speed)
+ *total = COSTS_N_INSNS (1);
+ return false;
+
+ case NEG:
+ /* Usually, we use subtract from 0 to substitute for neg, and
+ it costs 1 extra insn to move 0 to a register. */
+ *total = COSTS_N_INSNS (2 * CSKY_NUM_REGS (mode));
+ return false;
+
+ case NOT:
+ *total = COSTS_N_INSNS (CSKY_NUM_REGS (mode));
+ return false;
+
+ case COMPARE:
+ *total = COSTS_N_INSNS (1);
+ return false;
+
+ case SIGN_EXTEND:
+ case ZERO_EXTEND:
+ *total = COSTS_N_INSNS (CSKY_NUM_REGS (mode));
+ return false;
+
+ case SIGN_EXTRACT:
+ case ZERO_EXTRACT:
+ if (REG_P (XEXP (x, 0))
+ && CONST_INT_P (XEXP (x, 1))
+ && CONST_INT_P (XEXP (x, 2))
+ && INTVAL (XEXP (x, 1)) == 8
+ && INTVAL (XEXP (x, 2)) % 8 == 0)
+ {
+ *total = COSTS_N_INSNS (1);
+ return true;
+ }
+ *total = COSTS_N_INSNS (CSKY_NUM_REGS (mode));
+ return false;
+
+ case CONST_INT:
+ {
+ unsigned HOST_WIDE_INT t = (unsigned HOST_WIDE_INT) (INTVAL (x));
+
+ if (outer_code == COMPARE)
+ {
+ if (t < 0x10000)
+ *total = 0;
+ else
+ *total = COSTS_N_INSNS (2);
+ }
+ else if (outer_code == AND || outer_code == IOR || outer_code == XOR)
+ {
+ /* "andi,xori,ori" are 32-bit insns, so let it cost a
+ little more. */
+ if (t < 0x1000)
+ {
+ /* Try replacing "andi" by "sextb/h", so let it cost more. */
+ if (outer_code == AND && (t == 0xff || t == 0xffff))
+ {
+ *total = 8;
+ return true;
+ }
+ *total = 2;
+ }
+ else if (t < 0x10000)
+ *total = COSTS_N_INSNS (1);
+ else
+ *total = COSTS_N_INSNS (2);
+ }
+ else if (outer_code == PLUS || outer_code == MINUS)
+ {
+ /* "addi/subi rx,ry,imm", if imm<9, it is more often a
+ 16-bit insn. If imm>=9, use "movi" insn; it's probably
+ less than "addi/subi". */
+ if (t < 9)
+ *total = 0;
+ else if (t < 0x1000)
+ *total = 2;
+ else if (t < 0x10000)
+ *total = COSTS_N_INSNS (1);
+ else
+ *total = COSTS_N_INSNS (2);
+ }
+ else if (outer_code == ROTATE || outer_code == ROTATERT
+ || outer_code == LSHIFTRT || outer_code == ASHIFTRT
+ || outer_code == ASHIFT)
+ {
+ if (t < 32)
+ *total = 0;
+ else
+ *total = COSTS_N_INSNS (2);
+ }
+ else
+ {
+ if (t < 0x10000)
+ if (outer_code == SET && t < 256)
+ *total = 0;
+ else
+ *total = COSTS_N_INSNS (1);
+ else
+ *total = COSTS_N_INSNS (2);
+ }
+ }
+ return true;
+
+ case CONST:
+ case LABEL_REF:
+ case SYMBOL_REF:
+ *total = COSTS_N_INSNS (3);
+ return true;
+ default:
+ return false;
+ }
+}
+
+
+/* TARGET_RTX_COSTS helper for ck803. */
+
+static bool
+ck803_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED,
+ int *total, bool speed ATTRIBUTE_UNUSED)
+{
+ switch (code)
+ {
+ case SET:
+ if (MEM_P (XEXP (x, 1)))
+ {
+ struct csky_address op1;
+ bool address_valid
+ = decompose_csky_address (XEXP (XEXP (x, 1), 0), &op1);
+ if (op1.index)
+ {
+ *total = COSTS_N_INSNS (3);
+ return true;
+ }
+ else if (address_valid)
+ {
+ *total = COSTS_N_INSNS (1);
+ return true;
+ }
+ }
+ if (REG_P (XEXP (x, 0)) && (GET_CODE (XEXP (x, 1)) == PLUS))
+ {
+ rtx sub_exp = XEXP (x, 1);
+ if (REG_P (XEXP (sub_exp, 0)) && REG_P (XEXP (sub_exp, 1)))
+ {
+ *total = COSTS_N_INSNS (1);
+ return true;
+ }
+ }
+ return false;
+ case MULT:
+ if (REG_P (XEXP (x, 0)) && CONST_INT_P (XEXP (x, 1)))
+ {
+ HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
+ if (val % 2 == 0 && val < 0xffffffff && val > 0)
+ {
+ *total = COSTS_N_INSNS (1);
+ return true;
+ }
+ }
+ return false;
+
+ case CONST:
+ case LABEL_REF:
+ case SYMBOL_REF:
+ *total = COSTS_N_INSNS (3);
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* TARGET_RTX_COSTS helper for ck807+ arches. */
+
+static bool
+ck807_ck810_rtx_costs (rtx x, int code,
+ int outer_code ATTRIBUTE_UNUSED,
+ int *total, bool speed ATTRIBUTE_UNUSED)
+{
+ switch (code)
+ {
+ case MULT:
+ if (REG_P (XEXP (x, 0)) && CONST_INT_P (XEXP (x, 1)))
+ {
+ HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
+ if (val % 2 == 0 && val < 0xffffffff && val > 0)
+ {
+ *total = COSTS_N_INSNS (1);
+ return true;
+ }
+ }
+ return false;
+
+ case CONST:
+ case LABEL_REF:
+ case SYMBOL_REF:
+ *total = COSTS_N_INSNS (3);
+ return true;
+ default:
+ return false;
+ }
+}
+
+
+/* Implement TARGET_RTX_COSTS, to compute a (partial) cost for rtx X.
+ Return true if the complete cost has been computed, and false if
+ subexpressions should be scanned. In either case, *TOTAL contains
+ the cost result. */
+
+static bool
+csky_rtx_costs (rtx x, machine_mode mode ATTRIBUTE_UNUSED, int outer_code,
+ int opno ATTRIBUTE_UNUSED, int *total, bool speed)
+{
+ int code = GET_CODE (x);
+
+ if (CSKY_TARGET_ARCH (CK802) || CSKY_TARGET_ARCH (CK801))
+ return ck802_ck801_rtx_costs (x, code, outer_code, total, speed);
+ else if (CSKY_TARGET_ARCH (CK803))
+ return ck803_rtx_costs (x, code, outer_code, total, speed);
+ else if (CSKY_TARGET_ARCH (CK807) || CSKY_TARGET_ARCH (CK810))
+ return ck807_ck810_rtx_costs (x, code, outer_code, total, speed);
+ else
+ gcc_unreachable ();
+}
+
+/* Emit assembly code for CASESI. This is only used on CK801 and CK802
+ when optimizing for size, and uses helper functions in libgcc instead
+ of doing the control transfer inline. */
+
+const char *
+csky_output_casesi (rtx *operands)
+{
+ rtx diff_vec = PATTERN (NEXT_INSN (as_a <rtx_insn *> (operands[0])));
+
+ gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
+
+ switch (GET_MODE (diff_vec))
+ {
+ case E_QImode:
+ return (ADDR_DIFF_VEC_FLAGS (diff_vec).offset_unsigned
+ ? "jbsr\t___gnu_csky_case_uqi"
+ : "jbsr\t___gnu_csky_case_sqi");
+ case E_HImode:
+ return (ADDR_DIFF_VEC_FLAGS (diff_vec).offset_unsigned
+ ? "jbsr\t___gnu_csky_case_uhi"
+ : "jbsr\t___gnu_csky_case_shi");
+ case E_SImode:
+ return "jbsr\t___gnu_csky_case_si";
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Implement TARGET_SCHED_ISSUE_RATE. Lookup the issue rate in the
+ per-core tuning structs. */
+static int
+csky_sched_issue_rate (void)
+{
+ if (CSKY_TARGET_ARCH (CK810))
+ return 2;
+ else
+ return 1;
+}
+
+
+/* This function implements the target macro TARGET_SCHED_ADJUST_COST.
+ It corrects the value of COST based on the relationship between
+ INSN and DEP through the dependence DEP_TYPE. It returns the new
+ value. */
+
+static int
+csky_sched_adjust_cost (rtx_insn *insn,
+ int dep_type,
+ rtx_insn *dep,
+ int cost,
+ unsigned int dw ATTRIBUTE_UNUSED)
+{
+ if (dep_type == REG_DEP_ANTI || dep_type == REG_DEP_OUTPUT)
+ return 0;
+ /* The REG_DEP_TRUE situation. */
+ else if (recog_memoized (insn) >= 0 && recog_memoized (dep) >= 0)
+ {
+ enum attr_type insn_type = get_attr_type (insn);
+ if (CSKY_TARGET_ARCH (CK803))
+ {
+ /* The ld or st's base reg depends on the pre insn,
+ it will delay 1 cycle. */
+ if (insn_type == TYPE_LOAD || insn_type == TYPE_STORE)
+ {
+ rtx pattern = PATTERN (insn);
+
+ gcc_assert (GET_CODE (pattern) == SET);
+ rtx addr = (insn_type == TYPE_LOAD
+ ? SET_SRC (pattern) : SET_DEST (pattern));
+
+ enum rtx_code code = GET_CODE (addr);
+ if (code == ZERO_EXTEND || code == SIGN_EXTEND)
+ addr = XEXP (addr, 0);
+ gcc_assert (GET_CODE (addr) == MEM);
+
+ rtx base = XEXP (addr, 0);
+ rtx reg = NULL_RTX;
+ if (REG_P (base))
+ reg = base;
+ if (GET_CODE (base) == PLUS
+ && GET_CODE (XEXP (base, 0)) == REG)
+ reg = XEXP (base, 0);
+ if ((reg != NULL_RTX) && reg_set_p (reg, PATTERN (dep)))
+ return 2;
+ }
+ }
+ else if (CSKY_TARGET_ARCH (CK802))
+ {
+ if ((insn_type == TYPE_CALL_JSR || insn_type == TYPE_BRANCH_JMP)
+ && get_attr_type (dep) != TYPE_LOAD)
+ return 1;
+
+ if (insn_type == TYPE_LOAD || insn_type == TYPE_STORE)
+ {
+ rtx pattern = PATTERN (insn);
+
+ gcc_assert (GET_CODE (pattern) == SET);
+
+ rtx addr = (insn_type == TYPE_LOAD
+ ? SET_SRC (pattern) : SET_DEST (pattern));
+
+ enum rtx_code code = GET_CODE (addr);
+ if (code == ZERO_EXTEND || code == SIGN_EXTEND)
+ addr = XEXP (addr, 0);
+ gcc_assert (GET_CODE (addr) == MEM);
+
+ rtx base = XEXP (addr, 0);
+ rtx reg = NULL_RTX;
+ if (REG_P (base))
+ reg = base;
+ if (GET_CODE (base) == PLUS
+ && GET_CODE (XEXP (base, 0)) == REG)
+ reg = XEXP (base, 0);
+ if ((reg != NULL_RTX) && reg_set_p (reg, PATTERN (dep))
+ && get_attr_type (dep) != TYPE_LOAD)
+ return 1;
+
+ if (insn_type == TYPE_STORE
+ && reg_referenced_p (SET_SRC (pattern), PATTERN (dep)))
+ return 1;
+ }
+ }
+ }
+ return cost;
+}
+
+static bool
+csky_warn_func_return (tree decl)
+{
+ /* Naked functions are implemented entirely in assembly, including the
+ return sequence, so suppress warnings about this. */
+ return lookup_attribute ("naked", DECL_ATTRIBUTES (decl)) == NULL_TREE;
+}
+
+
+/* Implement TARGET_RETURN_IN_MEMORY to decide whether TYPE should be
+ returned in memory (true) or in a register (false).
+ FNTYPE is the type of the function making the call. */
+static bool
+csky_return_in_memory (const_tree type,
+ const_tree fntype ATTRIBUTE_UNUSED)
+{
+ const HOST_WIDE_INT size = int_size_in_bytes (type);
+ return (size == -1 || size > 2 * UNITS_PER_WORD);
+}
+
+
+/* Implement TARGET_DWARF_REGISTER_SPAN.
+ Dwarf models VFP registers as 64-bit or 128-bit registers default.
+ GCC models tham as 32-bit registers, so we need to describe this to
+ the DWARF generation code. Other registers can use the default. */
+static rtx
+csky_dwarf_register_span (rtx rtl)
+{
+ machine_mode mode;
+ unsigned regno;
+ rtx parts[16];
+ int nregs;
+ int i;
+
+ regno = REGNO (rtl);
+ if (!CSKY_VREG_P (regno))
+ return NULL_RTX;
+
+ mode = GET_MODE (rtl);
+ if (GET_MODE_SIZE (mode) < 8)
+ return NULL_RTX;
+
+ if (TARGET_SOFT_FPU)
+ {
+ nregs = GET_MODE_SIZE (mode) / 4;
+ for (i = 0; i < nregs; i += 2)
+ if (TARGET_BIG_ENDIAN)
+ {
+ parts[i] = gen_rtx_REG (SImode, regno + i + 1);
+ parts[i + 1] = gen_rtx_REG (SImode, regno + i);
+ }
+ else
+ {
+ parts[i] = gen_rtx_REG (SImode, regno + i);
+ parts[i + 1] = gen_rtx_REG (SImode, regno + i + 1);
+ }
+ }
+ else
+ {
+ /* FIXME: dwarf2 considers all general registers to be the same
+ as the CPU bit width. Transform the 64-bit FPU registers to
+ 32 bits here, and we will modify the unwind processing to
+ fit CSKY architecture later. */
+ nregs = GET_MODE_SIZE (mode) / 8;
+ for (i = 0; i < nregs; i++)
+ parts[i] = gen_rtx_REG (SImode, regno + i);
+ }
+
+ return gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (nregs , parts));
+}
+
+/* Implement TARGET_INIT_LIBFUNCS. */
+
+static void
+csky_init_libfuncs (void)
+{
+ if (TARGET_CSKY_LINUX)
+ init_sync_libfuncs (UNITS_PER_WORD);
+ if (!TARGET_LIBCCRT)
+ return;
+
+ #define CSKY_GCC_SYM(sym) "__csky_ccrt_" # sym
+
+ /* int */
+
+ /* Arithmetic functions */
+ set_optab_libfunc (ashl_optab, DImode, CSKY_GCC_SYM (ashldi3));
+ set_optab_libfunc (ashr_optab, DImode, CSKY_GCC_SYM (ashrdi3));
+ set_optab_libfunc (sdiv_optab, SImode, CSKY_GCC_SYM (divsi3));
+ set_optab_libfunc (sdiv_optab, DImode, CSKY_GCC_SYM (divdi3));
+ set_optab_libfunc (lshr_optab, DImode, CSKY_GCC_SYM (lshrdi3));
+ set_optab_libfunc (smod_optab, SImode, CSKY_GCC_SYM (modsi3));
+ set_optab_libfunc (smod_optab, DImode, CSKY_GCC_SYM (moddi3));
+ set_optab_libfunc (smul_optab, DImode, CSKY_GCC_SYM (muldi3));
+ set_optab_libfunc (neg_optab, DImode, CSKY_GCC_SYM (negdi2));
+ set_optab_libfunc (udiv_optab, SImode, CSKY_GCC_SYM (udivsi3));
+ set_optab_libfunc (udiv_optab, DImode, CSKY_GCC_SYM (udivdi3));
+ set_optab_libfunc (udivmod_optab, DImode, CSKY_GCC_SYM (udivmoddi4));
+ set_optab_libfunc (umod_optab, SImode, CSKY_GCC_SYM (umodsi3));
+ set_optab_libfunc (umod_optab, DImode, CSKY_GCC_SYM (umoddi3));
+
+ /* Comparison functions */
+ set_optab_libfunc (cmp_optab, DImode, CSKY_GCC_SYM (cmpdi2));
+ set_optab_libfunc (ucmp_optab, DImode, CSKY_GCC_SYM (ucmpdi2));
+
+ /* Trapping arithmetic functions */
+ set_optab_libfunc (absv_optab, SImode, CSKY_GCC_SYM (absvsi2));
+ set_optab_libfunc (absv_optab, DImode, CSKY_GCC_SYM (absvdi2));
+ set_optab_libfunc (addv_optab, SImode, CSKY_GCC_SYM (addvsi3));
+ set_optab_libfunc (addv_optab, DImode, CSKY_GCC_SYM (addvdi3));
+ set_optab_libfunc (smulv_optab, SImode, CSKY_GCC_SYM (mulvsi3));
+ set_optab_libfunc (smulv_optab, DImode, CSKY_GCC_SYM (mulvdi3));
+ set_optab_libfunc (negv_optab, SImode, CSKY_GCC_SYM (negvsi2));
+ set_optab_libfunc (negv_optab, DImode, CSKY_GCC_SYM (negvdi2));
+ set_optab_libfunc (subv_optab, SImode, CSKY_GCC_SYM (subvsi3));
+ set_optab_libfunc (subv_optab, DImode, CSKY_GCC_SYM (subvdi3));
+
+ /* Bit operations */
+ set_optab_libfunc (clz_optab, SImode, CSKY_GCC_SYM (clzsi2));
+ set_optab_libfunc (clz_optab, DImode, CSKY_GCC_SYM (clzdi2));
+ set_optab_libfunc (ctz_optab, SImode, CSKY_GCC_SYM (ctzsi2));
+ set_optab_libfunc (ctz_optab, DImode, CSKY_GCC_SYM (ctzdi2));
+ set_optab_libfunc (ffs_optab, DImode, CSKY_GCC_SYM (ffsdi2));
+ set_optab_libfunc (parity_optab, SImode, CSKY_GCC_SYM (paritysi2));
+ set_optab_libfunc (parity_optab, DImode, CSKY_GCC_SYM (paritydi2));
+ set_optab_libfunc (popcount_optab,SImode, CSKY_GCC_SYM (popcountsi2));
+ set_optab_libfunc (popcount_optab,DImode, CSKY_GCC_SYM (popcountdi2));
+ set_optab_libfunc (bswap_optab, SImode, CSKY_GCC_SYM (bswapsi2));
+ set_optab_libfunc (bswap_optab, DImode, CSKY_GCC_SYM (bswapdi2));
+
+ /* float */
+
+ /* Arithmetic functions */
+ set_optab_libfunc (add_optab, SFmode, CSKY_GCC_SYM (addsf3));
+ set_optab_libfunc (add_optab, DFmode, CSKY_GCC_SYM (adddf3));
+ set_optab_libfunc (sub_optab, SFmode, CSKY_GCC_SYM (subsf3));
+ set_optab_libfunc (sub_optab, DFmode, CSKY_GCC_SYM (subdf3));
+ set_optab_libfunc (smul_optab, SFmode, CSKY_GCC_SYM (mulsf3));
+ set_optab_libfunc (smul_optab, DFmode, CSKY_GCC_SYM (muldf3));
+ set_optab_libfunc (sdiv_optab, SFmode, CSKY_GCC_SYM (divsf3));
+ set_optab_libfunc (sdiv_optab, DFmode, CSKY_GCC_SYM (divdf3));
+ set_optab_libfunc (neg_optab, SFmode, CSKY_GCC_SYM (negsf2));
+ set_optab_libfunc (neg_optab, DFmode, CSKY_GCC_SYM (negdf2));
+
+ /* Conversion functions */
+ set_conv_libfunc (sext_optab, DFmode, SFmode, CSKY_GCC_SYM (extendsfdf2));
+ set_conv_libfunc (trunc_optab, SFmode, DFmode, CSKY_GCC_SYM (truncdfsf2));
+ set_conv_libfunc (sfix_optab, SImode, SFmode, CSKY_GCC_SYM (fixsfsi));
+ set_conv_libfunc (sfix_optab, SImode, DFmode, CSKY_GCC_SYM (fixdfsi));
+ set_conv_libfunc (sfix_optab, DImode, SFmode, CSKY_GCC_SYM (fixsfdi));
+ set_conv_libfunc (sfix_optab, DImode, DFmode, CSKY_GCC_SYM (fixdfdi));
+ set_conv_libfunc (ufix_optab, SImode, SFmode, CSKY_GCC_SYM (fixunssfsi));
+ set_conv_libfunc (ufix_optab, SImode, DFmode, CSKY_GCC_SYM (fixunsdfsi));
+ set_conv_libfunc (ufix_optab, DImode, SFmode, CSKY_GCC_SYM (fixunssfdi));
+ set_conv_libfunc (ufix_optab, DImode, DFmode, CSKY_GCC_SYM (fixunsdfdi));
+ set_conv_libfunc (sfloat_optab, SFmode, SImode, CSKY_GCC_SYM (floatsisf));
+ set_conv_libfunc (sfloat_optab, DFmode, SImode, CSKY_GCC_SYM (floatsidf));
+ set_conv_libfunc (sfloat_optab, SFmode, DImode, CSKY_GCC_SYM (floatdisf));
+ set_conv_libfunc (sfloat_optab, DFmode, DImode, CSKY_GCC_SYM (floatdidf));
+ set_conv_libfunc (ufloat_optab, SFmode, SImode, CSKY_GCC_SYM (floatunsisf));
+ set_conv_libfunc (ufloat_optab, DFmode, SImode, CSKY_GCC_SYM (floatunsidf));
+ set_conv_libfunc (ufloat_optab, SFmode, DImode, CSKY_GCC_SYM (floatundisf));
+ set_conv_libfunc (ufloat_optab, DFmode, DImode, CSKY_GCC_SYM (floatundidf));
+
+ /* Comparison functions */
+ set_optab_libfunc (cmp_optab, SFmode, CSKY_GCC_SYM (cmpsf2));
+ set_optab_libfunc (cmp_optab, DFmode, CSKY_GCC_SYM (cmpdf2));
+ set_optab_libfunc (unord_optab, SFmode, CSKY_GCC_SYM (unordsf2));
+ set_optab_libfunc (unord_optab, DFmode, CSKY_GCC_SYM (unorddf2));
+ set_optab_libfunc (eq_optab, SFmode, CSKY_GCC_SYM (eqsf2));
+ set_optab_libfunc (eq_optab, DFmode, CSKY_GCC_SYM (eqdf2));
+ set_optab_libfunc (ne_optab, SFmode, CSKY_GCC_SYM (nesf2));
+ set_optab_libfunc (ne_optab, DFmode, CSKY_GCC_SYM (nedf2));
+ set_optab_libfunc (ge_optab, SFmode, CSKY_GCC_SYM (gesf2));
+ set_optab_libfunc (ge_optab, DFmode, CSKY_GCC_SYM (gedf2));
+ set_optab_libfunc (lt_optab, SFmode, CSKY_GCC_SYM (ltsf2));
+ set_optab_libfunc (lt_optab, DFmode, CSKY_GCC_SYM (ltdf2));
+ set_optab_libfunc (le_optab, SFmode, CSKY_GCC_SYM (lesf2));
+ set_optab_libfunc (le_optab, DFmode, CSKY_GCC_SYM (ledf2));
+ set_optab_libfunc (gt_optab, SFmode, CSKY_GCC_SYM (gtsf2));
+ set_optab_libfunc (gt_optab, DFmode, CSKY_GCC_SYM (gtdf2));
+}
+
+
+/* Implement TARGET_ADDRESS_COST to estimate cost of the memory address X.
+ For C-SKY, (register) and (register + offset) have the same cost.
+ Other situations cost more. */
+
+static int
+csky_address_cost (rtx x, machine_mode mode ATTRIBUTE_UNUSED,
+ addr_space_t as ATTRIBUTE_UNUSED,
+ bool speed ATTRIBUTE_UNUSED)
+{
+ enum rtx_code code = GET_CODE (x);
+
+ if (code == REG)
+ return COSTS_N_INSNS (1);
+ if (code == PLUS
+ && REG_P (XEXP (x, 0))
+ && CONST_INT_P (XEXP (x, 1)))
+ return COSTS_N_INSNS (1);
+
+ return COSTS_N_INSNS (3);
+}
+
+
+/* Implement TARGET_FIXED_CONDITION_CODE_REGS. */
+
+static bool
+csky_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2)
+{
+ *p1 = CSKY_CC_REGNUM;
+ *p2 = INVALID_REGNUM;
+ return true;
+}
+
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+
+#include "gt-csky.h"
diff --git a/gcc/config/csky/csky.h b/gcc/config/csky/csky.h
new file mode 100644
index 0000000..39aac6b
--- /dev/null
+++ b/gcc/config/csky/csky.h
@@ -0,0 +1,1054 @@
+/* Declarations for the C-SKY back end.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ Contributed by C-SKY Microsystems and Mentor Graphics.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+
+#ifndef GCC_CSKY_H
+#define GCC_CSKY_H
+
+/* In some places e.g. csky_secondary_reload, we use -1 to indicate an
+ invalid register. In other places where N is unsigned the comparison
+ to zero would give an error, so explicitly cast to int here. */
+#define CSKY_GENERAL_REGNO_P(N) \
+ ((N) < CSKY_NGPR_REGS && (int)(N) >= 0)
+
+#define CSKY_VREG_P(N) \
+ ((N) >= CSKY_FIRST_VFP_REGNUM && (N) <= CSKY_LAST_VFP_REGNUM)
+
+#define CSKY_HILO_REG_P(N) \
+ ((N) == CSKY_HI_REGNUM || (N) == CSKY_LO_REGNUM)
+
+/* Helper macros for constant constraints and predicates. */
+#define CSKY_VALUE_BETWEEN(VALUE, LOW, HIGH) \
+ ((VALUE) >= (LOW) && (VALUE) <= (HIGH))
+
+#define CSKY_CONST_OK_FOR_I(VALUE) \
+ CSKY_VALUE_BETWEEN (VALUE, 0, 65535)
+
+#define CSKY_CONST_OK_FOR_J(VALUE) \
+ CSKY_VALUE_BETWEEN (VALUE, 1, 32)
+
+#define CSKY_CONST_OK_FOR_K(VALUE) \
+ CSKY_VALUE_BETWEEN (VALUE, 0, 31)
+
+#define CSKY_CONST_OK_FOR_L(VALUE) \
+ CSKY_VALUE_BETWEEN (VALUE, 1, 8)
+
+#define CSKY_CONST_OK_FOR_M(VALUE) \
+ CSKY_VALUE_BETWEEN (VALUE, 1, 4096)
+
+#define CSKY_CONST_OK_FOR_N(VALUE) \
+ CSKY_VALUE_BETWEEN (VALUE, 1, 256)
+
+#define CSKY_CONST_OK_FOR_O(VALUE) \
+ CSKY_VALUE_BETWEEN (VALUE, 0, 4095)
+
+#define CSKY_CONST_OK_FOR_P(VALUE) \
+ (((VALUE) & 0x3) == 0 && CSKY_VALUE_BETWEEN (VALUE, 4, 508))
+
+#define CSKY_CONST_OK_FOR_T(VALUE) \
+ CSKY_VALUE_BETWEEN (VALUE, -256, -1)
+
+#define CSKY_CONST_OK_FOR_Ub(VALUE) \
+ (exact_log2 (VALUE & 0xFFFFFFFF) >= 0)
+
+#define CSKY_CONST_OK_FOR_Uc(VALUE) \
+ ((VALUE) == (HOST_WIDE_INT) -1 \
+ || (exact_log2 ((VALUE) + 1) >= 0 \
+ && exact_log2 ((VALUE) + 1) <= 31))
+
+#define CSKY_CONST_OK_FOR_Ud(VALUE) \
+ ((CSKY_CONST_OK_FOR_I ((VALUE) & 0xffffffff) \
+ || CSKY_CONST_OK_FOR_Ub ((VALUE)) \
+ || CSKY_CONST_OK_FOR_Uc (((VALUE) << 32) >> 32)) \
+ && (CSKY_CONST_OK_FOR_I ((VALUE) >> 32) \
+ || CSKY_CONST_OK_FOR_Ub ((VALUE) >> 32) \
+ || CSKY_CONST_OK_FOR_Uc ((VALUE) >> 32))) \
+
+#define CSKY_CONST_OK_FOR_Ug(VALUE) \
+ (((VALUE) & 0x3) == 0 && CSKY_VALUE_BETWEEN (VALUE, -508, -4))
+
+#define CSKY_CONST_OK_FOR_Uh(VALUE) \
+ CSKY_VALUE_BETWEEN (VALUE, -31, 0)
+
+#define CSKY_CONST_OK_FOR_Uj(VALUE) \
+ (((VALUE) & 0x3) == 0 && CSKY_VALUE_BETWEEN (VALUE, 1, 1024))
+
+#define CSKY_CONST_OK_FOR_Uk(VALUE) \
+ CSKY_VALUE_BETWEEN (VALUE, 1, 65536)
+
+#define CSKY_CONST_OK_FOR_Ul(VALUE) \
+ (((VALUE) & 0x3) == 0 && CSKY_VALUE_BETWEEN (VALUE, -1024, -4))
+
+#define CSKY_CONST_OK_FOR_Um(VALUE) \
+ CSKY_VALUE_BETWEEN (VALUE, -4096, -1)
+
+#define CSKY_CONST_OK_FOR_US(VALUE) \
+ CSKY_VALUE_BETWEEN (VALUE, -8, -1)
+
+#define CSKY_CONST_OK_FOR_MOVIH(VALUE) \
+ (((VALUE) & 0xFFFF) == 0)
+
+#ifndef TARGET_CPU_DEFAULT
+#define TARGET_CPU_DEFAULT CSKY_TARGET_CORE_GET(ck810f)
+#endif
+
+/* Options that are enabled by default are specified as such in the
+ .opt file. */
+#define TARGET_DEFAULT 0
+
+/* The highest CSKY architecture version supported by the target. */
+#define CSKY_TARGET_ARCH(arch) \
+ (csky_base_arch == CSKY_TARGET_ARCH_GET (arch))
+
+/* Define some macros for target code generation options. */
+#define TARGET_SOFT_FPU \
+ (csky_fpu_index == TARGET_FPU_fpv2_sf)
+#define TARGET_CASESI \
+ (optimize_size && TARGET_CONSTANT_POOL \
+ && (CSKY_TARGET_ARCH (CK801) || CSKY_TARGET_ARCH (CK802)))
+#define TARGET_TLS \
+ (CSKY_TARGET_ARCH (CK807) || CSKY_TARGET_ARCH (CK810))
+
+/* Number of loads/stores handled by ldm/stm. */
+#define CSKY_MIN_MULTIPLE_STLD 3
+#define CSKY_MAX_MULTIPLE_STLD 12
+
+/* Pull in enums and defines for processor/arch variants. This makes
+ it possible to use CSKY_TARGET_ARCH in macros defined in this file. */
+#include "csky_opts.h"
+extern enum csky_base_architecture csky_base_arch;
+
+/* Pull in enums and defines for ISA features. Likewise required to
+ support use of CSKY_ISA_FEATURE in this file.
+ Note that the CSKY_ISA_FEATURE macro tests properties of the
+ particular processor we're compiling for, not code generation
+ options that may have dependencies on those features. The latter
+ are handled by TARGET_xxxx macros/variables instead. See csky.opt. */
+#include "csky_isa.h"
+extern int csky_arch_isa_features[];
+#define CSKY_ISA_FEATURE(IDENT) \
+ csky_arch_isa_features[CSKY_ISA_FEATURE_GET (IDENT)]
+
+/******************************************************************
+ * Storage Layout *
+ ******************************************************************/
+
+
+/* Define this if most significant bit is lowest numbered
+ in instructions that operate on numbered bit-fields. */
+#define BITS_BIG_ENDIAN 0
+
+/* If the most significant byte of a word is the lowest numbered. */
+#define BYTES_BIG_ENDIAN (TARGET_BIG_ENDIAN != 0)
+
+/* If the most significant word of a multiword number is the lowest. */
+#define WORDS_BIG_ENDIAN (BYTES_BIG_ENDIAN)
+
+/* Width of a word, in units (bytes). */
+#define UNITS_PER_WORD 4
+
+/* Define this macro if it is advisable to hold scalars in registers
+ in a wider mode than that declared by the program. In such cases,
+ the value is constrained to be within the bounds of the declared
+ type, but kept valid in the wider mode. The signedness of the
+ extension may differ from that of the type. */
+#define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE) \
+ if (GET_MODE_CLASS (MODE) == MODE_INT \
+ && GET_MODE_SIZE (MODE) < UNITS_PER_WORD) \
+ (MODE) = SImode;
+
+
+/* Allocation boundary (in *bits*) for storing arguments in argument list. */
+#define PARM_BOUNDARY 32
+
+/* Boundary (in *bits*) on which stack pointer should be aligned.
+ Per C-SKY, the published V2 ABI document is incorrect and the proper
+ alignment is on a 4-byte boundary rather than 8 bytes. */
+#define STACK_BOUNDARY 32
+
+/* Align definitions of arrays, unions and structures so that
+ initializations and copies can be made more efficient. This is not
+ ABI-changing, so it only affects places where we can see the
+ definition. Increasing the alignment tends to introduce padding,
+ so don't do this when optimizing for size/conserving stack space. */
+#define CSKY_EXPAND_ALIGNMENT(COND, EXP, ALIGN) \
+ (((COND) && ((ALIGN) < BITS_PER_WORD) \
+ && (TREE_CODE (EXP) == ARRAY_TYPE \
+ || TREE_CODE (EXP) == UNION_TYPE \
+ || TREE_CODE (EXP) == RECORD_TYPE)) \
+ ? BITS_PER_WORD : (ALIGN))
+
+/* Align global data. */
+#define DATA_ALIGNMENT(EXP, ALIGN) \
+ CSKY_EXPAND_ALIGNMENT (!optimize_size, EXP, ALIGN)
+
+/* Similarly, make sure that objects on the stack are sensibly aligned. */
+#define LOCAL_ALIGNMENT(EXP, ALIGN) \
+ CSKY_EXPAND_ALIGNMENT (!flag_conserve_stack, EXP, ALIGN)
+
+/* No data type wants to be aligned rounder than this. */
+#define BIGGEST_ALIGNMENT 32
+
+/* Every structures size must be a multiple of 8 bits. */
+#define STRUCTURE_SIZE_BOUNDARY 8
+
+/* Look at the fundamental type that is used for a bit-field and use
+ that to impose alignment on the enclosing structure.
+ struct s {int a:8}; should have same alignment as "int", not "char". */
+#define PCC_BITFIELD_TYPE_MATTERS 1
+
+/* Largest integer machine mode for structures. If undefined, the default
+ is GET_MODE_SIZE(DImode). */
+#define MAX_FIXED_MODE_SIZE 64
+
+/* Allocation boundary (in *bits*) for the code of a function.
+ Optimize ck801 and ck802 a little harder for size. */
+#define FUNCTION_BOUNDARY \
+ (((CSKY_TARGET_ARCH (CK801) || CSKY_TARGET_ARCH (CK802)) \
+ && optimize_size) \
+ ? 16 : 32)
+
+/* C-SKY does not support unaligned access. */
+#define STRICT_ALIGNMENT 1
+
+#undef SIZE_TYPE
+#define SIZE_TYPE "unsigned int"
+
+#undef PTRDIFF_TYPE
+#define PTRDIFF_TYPE "int"
+
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "long int"
+
+#undef UINT_LEAST32_TYPE
+#define UINT_LEAST32_TYPE "unsigned int"
+
+#undef INT_LEAST32_TYPE
+#define INT_LEAST32_TYPE "int"
+
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE BITS_PER_WORD
+
+/******************************************************************
+ * Layout of Source Language Data Types *
+ ******************************************************************/
+
+
+/* 'char' is unsigned by default for backward compatibility. */
+#define DEFAULT_SIGNED_CHAR 0
+
+
+/******************************************************************
+ * Stack Layout and Calling Conventions *
+ ******************************************************************/
+
+
+/* Basic Stack Layout */
+
+
+/* Define this if pushing a word on the stack
+ makes the stack pointer a smaller address. */
+#define STACK_GROWS_DOWNWARD 1
+
+/* Define this to nonzero if the nominal address of the stack frame
+ is at the high-address end of the local variables;
+ that is, each additional local variable allocated
+ goes at a more negative offset in the frame. */
+#define FRAME_GROWS_DOWNWARD 1
+
+/* Offset of first parameter from the argument pointer register value. */
+#define FIRST_PARM_OFFSET(FNDECL) 0
+
+/* A C expression whose value is RTL representing the value of the return
+ address for the frame COUNT steps up from the current frame. */
+#define RETURN_ADDR_RTX(COUNT, FRAME) \
+ csky_return_addr (COUNT, FRAME)
+
+/* Pick up the return address upon entry to a procedure. Used for
+ dwarf2 unwind information. This also enables the table driven
+ mechanism. */
+#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, CSKY_LR_REGNUM)
+
+
+/* Exception Handling Support */
+
+/* The register that holds the return address in exception handlers. */
+#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (SImode, CSKY_EH_STACKADJ_REGNUM)
+
+
+/* Registers That Address the Stack Frame */
+
+
+/* Register to use for pushing function arguments. */
+#define STACK_POINTER_REGNUM CSKY_SP_REGNUM
+
+/* Base register for access to local variables of the function. */
+#define FRAME_POINTER_REGNUM 8
+
+/* Base register for access to arguments of the function. This is a fake
+ register that is always eliminated. */
+#define ARG_POINTER_REGNUM 32
+
+/* Static chain register.
+ Register use is more restricted on CK801. */
+#define STATIC_CHAIN_REGNUM (CSKY_TARGET_ARCH (CK801) ? 13 : 12)
+
+
+/* Eliminating Frame Pointer and Arg Pointer */
+
+
+/* Definitions for register eliminations.
+
+ This is an array of structures. Each structure initializes one pair
+ of eliminable registers. The "from" register number is given first,
+ followed by "to". Eliminations of the same "from" register are listed
+ in order of preference.
+
+ We have two registers that can be eliminated on the CSKY. First, the
+ arg pointer register can often be eliminated in favor of the stack
+ pointer register. Secondly, the pseudo frame pointer register can always
+ be eliminated; it is replaced with the stack pointer. */
+#define ELIMINABLE_REGS \
+{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM },\
+ { ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM },\
+ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM }}
+
+/* Define the offset between two registers, one to be eliminated, and the
+ other its replacement, at the start of a routine. */
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
+ (OFFSET) = csky_initial_elimination_offset (FROM, TO)
+
+
+/* Passing Function Arguments on the Stack */
+
+
+/* Define this if the maximum size of all the outgoing args is to be
+ accumulated and pushed during the prologue. The amount can be
+ found in the variable crtl->outgoing_args_size. */
+#define ACCUMULATE_OUTGOING_ARGS 1
+
+
+/* Passing Arguments in Registers */
+
+
+/* A C type for declaring a variable that is used as the first argument of
+ TARGET_ FUNCTION_ARG and other related values. */
+#define CUMULATIVE_ARGS int
+
+/* Initialize a variable CUM of type CUMULATIVE_ARGS
+ for a call to a function whose data type is FNTYPE.
+ For a library call, FNTYPE is 0.
+
+ On CSKY, the offset always starts at 0: the first parm reg is always
+ the same reg. */
+#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) \
+ ((CUM) = 0)
+
+/* True if N is a possible register number for function argument passing.
+ On the CSKY, r0-r3 are used to pass args.
+ The int cast is to prevent a complaint about unsigned comparison to
+ zero, since CSKY_FIRST_PARM_REGNUM is zero. */
+#define FUNCTION_ARG_REGNO_P(REGNO) \
+ (((int)(REGNO) >= CSKY_FIRST_PARM_REGNUM) && \
+ ((REGNO) < (CSKY_NPARM_REGS + CSKY_FIRST_PARM_REGNUM)))
+
+/* How Large Values Are Returned */
+
+
+/* Define DEFAULT_PCC_STRUCT_RETURN to 1 if all structure and union return
+ values must be in memory. On the CSKY, small
+ structures (eight bytes or fewer) are returned in
+ the register pair r0/r1. */
+#define DEFAULT_PCC_STRUCT_RETURN 0
+
+/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function,
+ the stack pointer does not matter. The value is tested only in
+ functions that have frame pointers.
+ No definition is equivalent to always zero.
+
+ On the CSKY, the function epilogue recovers the stack pointer from the
+ frame. */
+#define EXIT_IGNORE_STACK 1
+
+
+/******************************************************************
+ * Register Usage & Register Classes *
+ ******************************************************************/
+
+
+#define FIRST_PSEUDO_REGISTER 71
+
+/* 1 for registers that have pervasive standard uses
+ and are not available for the register allocator.
+ On C-SKY, r14 is SP, r26 is used by linker,
+ r27 is used by assembler, r28 is data base address,
+ r29 is GOT base address, r30 is handler base address,
+ r31 is TLS register. */
+#define FIXED_REGISTERS \
+ /* r0 r1 r2 r3 r4 r5 r6 r7 */ \
+{ 0, 0, 0, 0, 0, 0, 0, 0, \
+ /* r8 r9 r10 r11 r12 r13 r14 r15 */ \
+ 0, 0, 0, 0, 0, 0, 1, 0, \
+ /* r16 r17 r18 r19 r20 r21 r22 r23 */ \
+ 0, 0, 0, 0, 0, 0, 0, 0, \
+ /* r24 r25 r26 r27 r28 r29 r30 tls */ \
+ 0, 0, 1, 1, 1, 1, 1, 1, \
+ /* reserved c hi lo */ \
+ 1, 1, 0, 0, \
+ /* reserved */ \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ /* vr0 vr1 vr2 vr3 vr4 vr5 vr6 vr7 */ \
+ 0, 0, 0, 0, 0, 0, 0, 0, \
+ /* vr8 vr9 vr10 vr11 vr12 vr13 vr14 vr15 */ \
+ 0, 0, 0, 0, 0, 0, 0, 0 , \
+ /* reserved */ \
+ 1, 1, \
+ /* epc */ \
+ 1 \
+}
+
+/* 1 for registers that is clobbered (in general) by function calls.
+ If a register has 0, the compiler automatically saves it on
+ function entry and restores it on function exit, if the register
+ is used within the function. */
+#define CALL_USED_REGISTERS \
+ /* r0 r1 r2 r3 r4 r5 r6 r7 */ \
+{ 1, 1, 1, 1, 0, 0, 0, 0, \
+ /* r8 r9 r10 r11 r12 r13 r14 r15 */ \
+ 0, 0, 0, 0, 1, 1, 1, 0, \
+ /* r16 r17 r18 r19 r20 r21 r22 r23 */ \
+ 0, 0, 1, 1, 1, 1, 1, 1, \
+ /* r24 r25 r26 r27 r28 r29 r30 r31 */ \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ /* reserved c hi lo */ \
+ 1, 1, 1, 1, \
+ /* reserved */ \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ /* vr0 vr1 vr2 vr3 vr4 vr5 vr6 vr7 */ \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ /* vr8 vr9 vr10 vr11 vr12 vr13 vr14 vr15 */ \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ /* reserved */ \
+ 1, 1, \
+ /* epc */ \
+ 1 \
+}
+
+/* Like `CALL_USED_REGISTERS' but used to overcome a historical
+ problem which makes CALL_USED_REGISTERS *always* include
+ all the FIXED_REGISTERS. Until this problem has been
+ resolved this macro can be used to overcome this situation.
+ In particular, block_propagate() requires this list
+ be accurate, or we can remove registers which should be live.
+ This macro is used in get_csky_live_regs(). */
+#define CALL_REALLY_USED_REGISTERS \
+ /* r0 r1 r2 r3 r4 r5 r6 r7 */ \
+{ 1, 1, 1, 1, 0, 0, 0, 0, \
+ /* r8 r9 r10 r11 r12 r13 r14 r15 */ \
+ 0, 0, 0, 0, 1, 1, 1, 0, \
+ /* r16 r17 r18 r19 r20 r21 r22 r23 */ \
+ 0, 0, 1, 1, 1, 1, 1, 1, \
+ /* r24 r25 r26 r27 r28 r29 r30 r31 */ \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ /* reserved c hi lo */ \
+ 1, 1, 1, 1, \
+ /* reserved */ \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ /* vr0 vr1 vr2 vr3 vr4 vr5 vr6 vr7 */ \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ /* vr8 vr9 vr10 vr11 vr12 vr13 vr14 vr15 */ \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ /* reserved */ \
+ 1, 1, \
+ /* epc */ \
+ 1 \
+}
+
+#define REGISTER_NAMES \
+{ \
+ "a0", "a1", "a2", "a3", "l0", "l1", "l2", "l3", \
+ "l4", "l5", "l6", "l7", "t0", "t1", "sp", "lr", \
+ "l8", "l9", "t2", "t3", "t4", "t5", "t6", "t7", \
+ "t8", "t9", "r26", "r27", "gb", "r29", "svbr", "r31", \
+ /* reserved */ \
+ "reserved", \
+ /* CC register: 33 */ \
+ "c", \
+ /* DSP instruction register: 34, 35 */ \
+ "hi", "lo", \
+ "reserved", "reserved", "reserved", "reserved", "reserved", \
+ "reserved", "reserved", "reserved", "reserved", "reserved", \
+ "reserved", "reserved", "reserved", "reserved", "reserved", \
+ "reserved", \
+ /* V registers: 52~67 */ \
+ "vr0", "vr1", "vr2", "vr3", "vr4", "vr5", "vr6", "vr7", \
+ "vr8", "vr9", "vr10", "vr11", "vr12", "vr13", "vr14", "vr15", \
+ "reserved", "reserved", \
+ "epc" \
+}
+
+/* Table of additional register names to use in user input. */
+#define ADDITIONAL_REGISTER_NAMES \
+{ \
+ {"r0", 0}, \
+ {"r1", 1}, \
+ {"r2", 2}, \
+ {"r3", 3}, \
+ {"r4", 4}, \
+ {"r5", 5}, \
+ {"r6", 6}, \
+ {"r7", 7}, \
+ {"r8", 8}, \
+ {"r9", 9}, \
+ {"r10", 10}, \
+ {"r11", 11}, \
+ {"r12", 12}, \
+ {"r13", 13}, \
+ {"r14", 14}, \
+ {"r15", 15}, \
+ {"r16", 16}, \
+ {"r17", 17}, \
+ {"r18", 18}, \
+ {"r19", 19}, \
+ {"r20", 20}, \
+ {"r21", 21}, \
+ {"r22", 22}, \
+ {"r23", 23}, \
+ {"r24", 24}, \
+ {"r25", 25}, \
+ {"r26", 26}, \
+ {"r27", 27}, \
+ {"r28", 28}, \
+ {"r29", 29}, \
+ {"r30", 30}, \
+ {"r31", 31}, \
+}
+
+/* The order in which registers should be allocated.
+ It is better to use the registers the caller need not save.
+ Allocate r0 through r3 in reverse order since r3 is least likely
+ to contain a function parameter; in addition results are returned
+ in r0. It is quite good to use lr since other calls may clobber
+ it anyway. */
+#define REG_ALLOC_ORDER \
+/* r3 r2 r1 r0 r12 r13 r18 r19 */ \
+ { 3, 2, 1, 0, 12, 13, 18, 19, \
+/* r20 r21 r22 r23 r24 r25 */ \
+ 20, 21, 22, 23, 24, 25, \
+/* r15 r4 r5 r6 r7 r8 r9 r10 r11 */ \
+ 15, 4, 5, 6, 7, 8, 9, 10, 11, \
+/* r16 r17 r26 r27 r28 r29 r30 hi lo */ \
+ 16, 17, 26, 27, 28, 29, 30, 34, 35, \
+/* vr0 vr1 vr2 vr3 vr4 vr5 vr6 vr7 */ \
+ 52, 53, 54, 55, 56, 57, 58, 59, \
+/* vr8 vr9 vr10 vr11 vr12 vr13 vr14 vr15 */ \
+ 60, 61, 62, 63, 64, 65, 66, 67, \
+/* reserved */ \
+ 36, 37, 38, 39, 40, 41, 42, 43, \
+ 44, 45, 46, 47, 48, 49, 50, 51, \
+/* sp tls reserved c reserved epc */ \
+ 14, 31, 32, 33, 68, 69, 70 }
+
+/* Register classes. */
+enum reg_class
+{
+ NO_REGS,
+ MINI_REGS,
+ SP_REGS,
+ LOW_REGS,
+ GENERAL_REGS,
+ C_REGS,
+ HI_REGS,
+ LO_REGS,
+ HILO_REGS,
+ V_REGS,
+ OTHER_REGS,
+ RESERVE_REGS,
+ ALL_REGS,
+ LIM_REG_CLASSES
+};
+
+#define N_REG_CLASSES (int) LIM_REG_CLASSES
+
+/* Give names of register classes as strings for dump file. */
+#define REG_CLASS_NAMES \
+{ \
+ "NO_REGS", \
+ "MINI_REGS", \
+ "SP_REGS", \
+ "LOW_REGS", \
+ "GENERAL_REGS", \
+ "C_REGS", \
+ "HI_REGS", \
+ "LO_REGS", \
+ "HILO_REGS", \
+ "V_REGS", \
+ "OTHER_REGS", \
+ "RESERVE_REGS", \
+ "ALL_REGS", \
+}
+
+/* Define which registers fit in which classes. This is an initializer
+ for a vector of HARD_REG_SET of length N_REG_CLASSES. */
+#define REG_CLASS_CONTENTS \
+{ \
+ {0x00000000, 0x00000000, 0x00000000 }, /* NO_REGS */ \
+ {0x000000FF, 0x00000000, 0x00000000 }, /* MINI_REGS */ \
+ {0x00004000, 0x00000000, 0x00000000 }, /* SP_REGS */ \
+ {0x0000FFFF, 0x00000000, 0x00000000 }, /* LOW_REGS */ \
+ {0xFFFFFFFF, 0x00000000, 0x00000000 }, /* GENERAL_REGS */ \
+ {0x00000000, 0x00000002, 0x00000000 }, /* C_REGS */ \
+ {0x00000000, 0x00000004, 0x00000000 }, /* HI_REG */ \
+ {0x00000000, 0x00000008, 0x00000000 }, /* LO_REG */ \
+ {0x00000000, 0x0000000c, 0x00000000 }, /* HILO_REGS */ \
+ {0x00000000, 0xFFF00000, 0x0000000F }, /* V_REGS */ \
+ {0x00000000, 0x00000000, 0x00000040 }, /* OTHER_REGS */ \
+ {0x00000000, 0x0FF00001, 0x00000030 }, /* RESERVE_REGS */ \
+ {0xFFFFFFFF, 0xFFFFFFFF, 0x0000007F }, /* ALL_REGS */ \
+}
+
+/* Return register class from regno. */
+extern enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER];
+#define REGNO_REG_CLASS(REGNO) regno_reg_class[REGNO]
+
+/* The class value for index registers, and the one for base regs. */
+#define INDEX_REG_CLASS (CSKY_ISA_FEATURE (2E3) ? GENERAL_REGS : NO_REGS)
+#define BASE_REG_CLASS GENERAL_REGS
+
+/* TODO is it necessary to set it to MINI_REGS to emit more 16-bit
+ instructions? */
+#define MODE_BASE_REG_CLASS(MODE) GENERAL_REGS
+
+/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
+ and check its validity for a certain class.
+ We have two alternate definitions for each of them.
+ The usual definition accepts all pseudo regs; the other rejects
+ them unless they have been allocated suitable hard regs.
+ The symbol REG_OK_STRICT causes the latter definition to be used.
+
+ Most source files want to accept pseudo regs in the hope that
+ they will get allocated to the class that the insn wants them to be in.
+ Source files for reload pass need to be strict.
+ After reload, it makes no difference, since pseudo regs have
+ been eliminated by then.
+
+ The reg_renumber is used to map pseudo regs into hardware
+ regs, it is set up as a result of register allocation. */
+#ifdef REG_OK_STRICT
+#define REGNO_OK_FOR_BASE_P(REGNO) \
+ (CSKY_GENERAL_REGNO_P (REGNO) \
+ || CSKY_GENERAL_REGNO_P (reg_renumber[(REGNO)]) )
+#else
+#define REGNO_OK_FOR_BASE_P(REGNO) \
+ (CSKY_GENERAL_REGNO_P (REGNO) \
+ || (REGNO) >= FIRST_PSEUDO_REGISTER)
+#endif
+
+
+#ifdef REG_OK_STRICT
+#define REGNO_OK_FOR_INDEX_P(REGNO) \
+ (CSKY_GENERAL_REGNO_P (REGNO) \
+ || CSKY_GENERAL_REGNO_P (reg_renumber[(REGNO)]) )
+#else
+#define REGNO_OK_FOR_INDEX_P(REGNO) \
+ (CSKY_GENERAL_REGNO_P (REGNO) \
+ || (REGNO) >= FIRST_PSEUDO_REGISTER)
+#endif
+
+
+/******************************************************************
+ * Addressing Modes *
+ ******************************************************************/
+
+
+/* Recognize any constant value that is a valid address. */
+#define CONSTANT_ADDRESS_P(X) \
+ (GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF)
+
+/* Maximum number of registers that can appear in a valid memory address.
+ Shifts in addresses can't be by a register. */
+#define MAX_REGS_PER_ADDRESS 2
+
+
+/******************************************************************
+ * Run-time Target *
+ ******************************************************************/
+
+
+#define TARGET_CPU_CPP_BUILTINS() \
+ csky_cpu_cpp_builtins (pfile)
+
+/******************************************************************
+ * Per-function Data *
+ ******************************************************************/
+
+
+/* Initialize data used by insn expanders. This is called from insn_emit,
+ once for every function before code is generated. */
+#define INIT_EXPANDERS csky_init_expanders ()
+
+
+/******************************************************************
+ * Dividing the Output into Sections (Texts, Data, . . . ) *
+ ******************************************************************/
+
+
+/* Switch to the text or data segment. */
+#define TEXT_SECTION_ASM_OP "\t.text"
+#define DATA_SECTION_ASM_OP "\t.data"
+
+/* The subroutine calls in the .init and .fini sections create literal
+ pools which must be jumped around... */
+#define FORCE_CODE_SECTION_ALIGN \
+ asm ("br 1f ; .literals ; .align 2 ; 1:");
+
+/* Define this macro to be an expression with a nonzero value if
+ jump tables (for tablejump insns) should be output in the text section,
+ along with the assembler instructions. */
+#define JUMP_TABLES_IN_TEXT_SECTION TARGET_CASESI
+
+
+/******************************************************************
+ * Assembler Format *
+ ******************************************************************/
+
+
+/* A C string constant for text to be output before(after) each asm
+ statement or group of consecutive ones. */
+#undef ASM_APP_ON
+#define ASM_APP_ON "// inline asm begin\n"
+#undef ASM_APP_OFF
+#define ASM_APP_OFF "// inline asm end\n"
+
+/* A C string constant describing how to begin a comment in the target
+ assembler language. */
+#define ASM_COMMENT_START "\t//"
+
+/* This says how to output an assembler line
+ to define a global common symbol, with alignment information. */
+#undef ASM_OUTPUT_ALIGNED_COMMON
+#define ASM_OUTPUT_ALIGNED_COMMON(STREAM, NAME, SIZE, ALIGN) \
+ do \
+ { \
+ fputs ("\t.comm\t", STREAM); \
+ assemble_name (STREAM, NAME); \
+ fprintf (STREAM, ",%lu, %u\n", (unsigned long)(SIZE), \
+ (ALIGN) / BITS_PER_UNIT); \
+ } \
+while (0)
+
+/* Define a local common symbol whose alignment we wish to specify.
+ ALIGN comes in as bits, we have to turn it into bytes. */
+#undef ASM_OUTPUT_ALIGNED_LOCAL
+#define ASM_OUTPUT_ALIGNED_LOCAL(STREAM, NAME, SIZE, ALIGN) \
+ do \
+{ \
+ fputs ("\t.bss\t", (STREAM)); \
+ assemble_name ((STREAM), (NAME)); \
+ fprintf ((STREAM), ",%d, %d\n", (int)(SIZE), \
+ (ALIGN) / BITS_PER_UNIT); \
+} \
+while (0)
+
+/* Globalizing directive for a label. */
+#define GLOBAL_ASM_OP "\t.global\t"
+
+/* Output a reference to a label. */
+#undef ASM_OUTPUT_LABELREF
+#define ASM_OUTPUT_LABELREF(STREAM, NAME) \
+ fprintf (STREAM, "%s%s", user_label_prefix, \
+ (* targetm.strip_name_encoding) (NAME))
+
+/* Make an internal label into a string. */
+#undef ASM_GENERATE_INTERNAL_LABEL
+#define ASM_GENERATE_INTERNAL_LABEL(STRING, PREFIX, NUM) \
+ sprintf (STRING, "*.%s%ld", PREFIX, (long) NUM)
+
+/* This is how to output an insn to push a register on the stack.
+ It need not be very fast code. */
+#define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \
+ fprintf (STREAM, "\tsubi\t %s,%d\n\tst.w\t %s,(%s)\n", \
+ reg_names[STACK_POINTER_REGNUM], \
+ (STACK_BOUNDARY / BITS_PER_UNIT), \
+ reg_names[REGNO], \
+ reg_names[STACK_POINTER_REGNUM])
+
+/* This is how to output an insn to pop a register from the stack. */
+#define ASM_OUTPUT_REG_POP(STREAM,REGNO) \
+ fprintf (STREAM, "\tld.w\t %s,(%s)\n\taddi\t %s,%d\n", \
+ reg_names[REGNO], \
+ reg_names[STACK_POINTER_REGNUM], \
+ reg_names[STACK_POINTER_REGNUM], \
+ (STACK_BOUNDARY / BITS_PER_UNIT))
+
+/* Output an element of a dispatch table. */
+#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM,VALUE) \
+ fprintf (STREAM, "\t.long\t.L%d\n", VALUE)
+
+/* This is how to output an assembler line
+ that says to advance the location counter by SIZE bytes. */
+#undef ASM_OUTPUT_SKIP
+#define ASM_OUTPUT_SKIP(STREAM,SIZE) \
+ fprintf (STREAM, "\t.fill %d, 1\n", (int)(SIZE))
+
+/* Align output to a power of two. Note ".align 0" is redundant,
+ and also GAS will treat it as ".align 2" which we do not want. */
+#define ASM_OUTPUT_ALIGN(STREAM, POWER) \
+ do \
+ { \
+ if ((POWER) > 0) \
+ fprintf (STREAM, "\t.align\t%d\n", POWER); \
+ } \
+ while (0)
+
+
+/******************************************************************
+ * Controlling the Compilation Driver *
+ ******************************************************************/
+
+
+/* Define this macro as a C expression for the initializer of an
+ array of string to tell the driver program which options are
+ defaults for this target and thus do not need to be handled
+ specially when using MULTILIB_OPTIONS. */
+#undef MULTILIB_DEFAULTS
+#define MULTILIB_DEFAULTS \
+ {"mlittle-endian", "mcpu=ck810f", "msoft-float"}
+
+/* Support for a compile-time default CPU, et cetera. The rules are:
+ --with-arch is ignored if -march or -mcpu are specified.
+ --with-cpu is ignored if -march or -mcpu are specified, and is overridden
+ by --with-arch. */
+#define OPTION_DEFAULT_SPECS \
+ {"arch", "%{!march=*:%{!mcpu=*:-march=%(VALUE)}}" }, \
+ {"cpu", "%{!march=*:%{!mcpu=*:-mcpu=%(VALUE)}}" }, \
+ {"endian", "%{!mbig-endian:%{!mlittle-endian:-m%(VALUE)-endian}}" }, \
+ {"float", "%{!msoft-float:%{!mhard-float:-m%(VALUE)-float}}" },
+
+
+/******************************************************************
+ * Position Independent Code *
+ ******************************************************************/
+
+/* Define the global table register. */
+#define PIC_OFFSET_TABLE_REGNUM (flag_pic ? CSKY_GB_REGNUM : INVALID_REGNUM)
+
+/* Nonzero if x is a legitimate immediate operand on the target machine
+ when generating position-independent code. */
+#define LEGITIMATE_PIC_OPERAND_P(X) \
+ csky_legitimate_pic_operand_p (X)
+
+
+/******************************************************************
+ * Controlling Debugging Information Format *
+ ******************************************************************/
+
+
+/* Define this macro if GCC should produce dwarf version 2 format debugging
+ output in response to the `-g' option. */
+#define DWARF2_DEBUGGING_INFO 1
+
+/* Define this macro to 0 if your target supports DWARF 2 frame unwind
+ information, but it does not yet work with exception handling. */
+#define DWARF2_UNWIND_INFO 1
+
+/* Define this if you have arranged for GCC to support
+ more than one format of debugging output.
+ The value of this macro only affects the default debugging output. */
+#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
+
+/* Define this macro if the target’s representation
+ for dwarf registers used in .eh_frame or .debug_frame
+ is different from that used in other debug info sections.
+ Given a GCC hard register number,
+ this macro should return the .eh_frame register number.*/
+#define DWARF_FRAME_REGNUM(REG) DBX_REGISTER_NUMBER (REG)
+
+/* If INCOMING_RETURN_ADDR_RTX is defined & the RTL is REG,
+ define DWARF_FRAME_RETURN_COLUMN to DWARF_FRAME_REGNUM. */
+#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (CSKY_LR_REGNUM)
+
+/* Use r0 and r1 to pass exception handling information. */
+#define EH_RETURN_DATA_REGNO(N) ((N) < 2 ? N : INVALID_REGNUM)
+
+/* How to renumber registers for dbx and gdb. */
+extern const int csky_dbx_regno[];
+#define DBX_REGISTER_NUMBER(REGNO) ((unsigned int) csky_dbx_regno[REGNO])
+
+
+/******************************************************************
+ * Miscellaneous Parameters *
+ ******************************************************************/
+
+
+/* Specify the machine mode that this machine uses
+ for the index in the tablejump instruction. */
+#define CASE_VECTOR_MODE SImode
+
+/* Define if operations between registers always perform the operation
+ on the full register even if a narrower mode is specified. */
+#define WORD_REGISTER_OPERATIONS 1
+
+/* Define if loading in MODE, an integral mode narrower than BITS_PER_WORD
+ will either zero-extend or sign-extend. The value of this macro should
+ be the code that says which one of the two operations is implicitly
+ done, UNKNOWN if none. */
+#define LOAD_EXTEND_OP(MODE) ZERO_EXTEND
+
+/* Max number of bytes we can move from memory to memory
+ in one reasonably fast instruction. */
+#define MOVE_MAX 4
+
+/* Shift counts are truncated to 6-bits (0 to 63) instead of the expected
+ 5-bits, so we can not define SHIFT_COUNT_TRUNCATED to true for this
+ target. */
+#define SHIFT_COUNT_TRUNCATED 0
+
+#define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) ((VALUE) = 32, 1)
+
+/* The machine modes of pointers and functions. */
+#define Pmode SImode
+#define FUNCTION_MODE Pmode
+
+/* Define this macro to be a C expression to indicate when jump-tables
+ should contain relative addresses. */
+#define CASE_VECTOR_PC_RELATIVE \
+ (optimize_size && TARGET_CONSTANT_POOL \
+ && (CSKY_TARGET_ARCH (CK802) || CSKY_TARGET_ARCH (CK801)))
+
+/* Return the preferred mode for an addr_diff_vec when the minimum
+ and maximum offset are known. */
+#define CASE_VECTOR_SHORTEN_MODE(min, max, body) \
+ (min >= 0 && max < 512 \
+ ? (ADDR_DIFF_VEC_FLAGS (body).offset_unsigned = 1, QImode) \
+ : min >= -256 && max < 256 \
+ ? (ADDR_DIFF_VEC_FLAGS (body).offset_unsigned = 0, QImode) \
+ : min >= 0 && max < 8192 \
+ ? (ADDR_DIFF_VEC_FLAGS (body).offset_unsigned = 1, HImode) \
+ : min >= -4096 && max < 4096 \
+ ? (ADDR_DIFF_VEC_FLAGS (body).offset_unsigned = 0, HImode) \
+ : SImode)
+
+/* This is how to output an element of a case-vector that is relative. */
+#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM, BODY, VALUE, REL) \
+ do \
+ { \
+ if (optimize_size && TARGET_CONSTANT_POOL \
+ && (CSKY_TARGET_ARCH (CK802) || CSKY_TARGET_ARCH (CK801))) \
+ { \
+ switch (GET_MODE (BODY)) \
+ { \
+ case E_QImode: \
+ asm_fprintf (STREAM, "\t.byte\t(.L%d-.L%d)/2\n", \
+ VALUE, REL); \
+ break; \
+ case E_HImode: /* TBH */ \
+ asm_fprintf (STREAM, "\t.short\t(.L%d-.L%d)/2\n", \
+ VALUE, REL); \
+ break; \
+ case E_SImode: \
+ asm_fprintf (STREAM, "\t.long\t.L%d-.L%d\n", \
+ VALUE, REL); \
+ break; \
+ default: \
+ gcc_unreachable (); \
+ } \
+ } \
+ else \
+ asm_fprintf (STREAM, "\t.long\t.L%d@GOTOFF\n", VALUE); \
+ } while (0)
+
+/* This macro is not documented yet.
+ But we do need it to make jump table vector aligned. */
+#define ADDR_VEC_ALIGN(JUMPTABLE) 0
+
+/* We have to undef this first to override the version from elfos.h. */
+#undef ASM_OUTPUT_CASE_LABEL
+#define ASM_OUTPUT_CASE_LABEL(stream, prefix, num, table) \
+ do \
+ { \
+ if (GET_MODE (PATTERN (table)) == SImode) \
+ ASM_OUTPUT_ALIGN (stream, 2); \
+ (*targetm.asm_out.internal_label) (stream, prefix, num); \
+ } while (0)
+
+/* Make sure subsequent insns are aligned after a byte-sized jump offset
+ table. */
+#define ASM_OUTPUT_CASE_END(stream, num, table) \
+ do \
+ { \
+ if (GET_MODE (PATTERN (table)) == QImode) \
+ ASM_OUTPUT_ALIGN (stream, 1); \
+ } while (0)
+
+
+
+
+/******************************************************************
+ * Trampolines for Nested Functions *
+ ******************************************************************/
+
+
+/* Length in units of the trampoline for entering a nested function. */
+#define TRAMPOLINE_SIZE (CSKY_ISA_FEATURE (2E3) ? 16 : 20)
+
+/* Alignment required for a trampoline in bits. */
+#define TRAMPOLINE_ALIGNMENT 32
+
+
+/******************************************************************
+ * Describing Relative Costs of Operations *
+ ******************************************************************/
+
+
+/* Nonzero if access to memory by bytes is slow and undesirable.
+ For RISC chips, it means that access to memory by bytes is no
+ better than access by words when possible, so grab a whole word
+ and maybe make use of that. */
+#define SLOW_BYTE_ACCESS 0
+
+/* On C-SKY, function CSE would allow use of 16-bit jsr instructions
+ instead of normal 32-bit calls. But it also needs a separate constant
+ pool entry for the function address and an instruction to load it, and
+ may cause additional spills due to increased register pressure, etc.
+ It doesn't seem like a good idea overall. */
+#define NO_FUNCTION_CSE 1
+
+/* Try to generate sequences that don't involve branches, we can then use
+ conditional instructions. */
+#define BRANCH_COST(speed_p, predictable_p) \
+ csky_default_branch_cost (speed_p, predictable_p)
+
+/* False if short circuit operation is preferred. */
+#define LOGICAL_OP_NON_SHORT_CIRCUIT \
+ (csky_default_logical_op_non_short_circuit ())
+
+
+/******************************************************************
+ * Generating Code for Profiling *
+ ******************************************************************/
+
+
+#define FUNCTION_PROFILER(FILE, LABELNO)
+
+#endif /* GCC_CSKY_H */
diff --git a/gcc/config/csky/csky.md b/gcc/config/csky/csky.md
new file mode 100644
index 0000000..4f6329d
--- /dev/null
+++ b/gcc/config/csky/csky.md
@@ -0,0 +1,3798 @@
+;; Machine description for C-SKY processors.
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+;; Contributed by C-SKY Microsystems and Mentor Graphics.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>. */
+
+
+;; ------------------------------------------------------------------------
+;; Constant
+;; ------------------------------------------------------------------------
+
+;; Register numbering.
+
+(define_constants
+ [(CSKY_NGPR_REGS 32)
+ (CSKY_NPARM_REGS 4)
+ (CSKY_FIRST_PARM_REGNUM 0)
+ (CSKY_FIRST_RET_REGNUM 0)
+ (CSKY_FIRST_VFP_REGNUM 52)
+ (CSKY_LAST_VFP_REGNUM 67)
+ (CSKY_FIRST_HIGH_REGNUM 16)
+ (CSKY_LAST_HIGH_REGNUM 31)
+ (CSKY_FIRST_MINI_REGNUM 0)
+ (CSKY_LAST_MINI_REGNUM 7)
+ (CSKY_T0_REGNUM 12)
+ (CSKY_T1_REGNUM 13)
+ (CSKY_SP_REGNUM 14)
+ (CSKY_CC_REGNUM 33)
+ (CSKY_HI_REGNUM 34)
+ (CSKY_LO_REGNUM 35)
+ (CSKY_LR_REGNUM 15)
+ (CSKY_LAST_HIGH_UNFIXED_REGNUM 25)
+ (CSKY_GB_REGNUM 28)
+ (CSKY_TLS_REGNUM 31)
+ (CSKY_FIRST_EH_RETDATA_REGNUM 0)
+ (CSKY_LAST_EH_RETDATA_REGNUM 1)
+ (CSKY_EH_STACKADJ_REGNUM 2)
+ (CSKY_STACKADJUST_REGNUM 4)
+])
+
+;; Supported TLS relocations.
+
+(define_constants
+ [(TLS_GD32 0)
+ (TLS_LDM32 1)
+ (TLS_LDO32 2)
+ (TLS_IE32 3)
+ (TLS_LE32 4)
+])
+
+;; Unspec constants.
+
+(define_c_enum "unspec"
+ [
+ ; Push or pop multiple operation: operand 0 is the first register,
+ ; subsequent registers are in parallel (use ...) expressions.
+ UNSPEC_PUSHPOP_MULT
+
+ ; Represent TLS base, TLS offset, and TLS base + offset, respectively.
+ UNSPEC_TLS_BASE
+ UNSPEC_TLS_LABEL
+ UNSPEC_TLS
+
+ ; PIC symbol relocations.
+ UNSPEC_PIC_SYMBOL_GOTPC
+ UNSPEC_PIC_SYMBOL_GOTPC_GRS
+ UNSPEC_PIC_SYMBOL_GOTOFF
+ UNSPEC_PIC_SYMBOL_GOT
+ UNSPEC_PIC_SYMBOL_PLT
+ UNSPEC_PIC_SYMBOL_BSR
+ UNSPEC_PIC_SYMBOL_GRS
+
+ ; casesi dispatch table.
+ UNSPEC_CSKY_CASESI
+ ])
+
+
+(define_c_enum "unspecv"
+ [
+ ; Used for constant pools.
+ VUNSPEC_ALIGN
+ VUNSPEC_POOL_LABEL
+ VUNSPEC_POOL_4
+ VUNSPEC_POOL_8
+ VUNSPEC_SYMBOL_REF
+
+ ; Support for the eh_return pattern.
+ VUNSPEC_EH_RETURN
+ ])
+
+
+;; ------------------------------------------------------------------------
+;; Attributes
+;; ------------------------------------------------------------------------
+
+;; LENGTH of an instruction (in bytes).
+
+(define_attr "length" ""
+ (if_then_else (match_test "CSKY_TARGET_ARCH (CK801)")
+ (const_int 2)
+ (const_int 4)))
+
+;; Used for ck801 to represent whether we need to use bsr for long
+;; distance jumps. If set to yes, the function will save lr in the
+;; prologue.
+
+(define_attr "far_jump" "yes,no" (const_string "no"))
+
+;; Used for insn schedule.
+
+(define_attr "type"
+ "alu,load,store,cmp,branch,cbranch,addsub,alu_ix,branch_jmp,call_jsr,call"
+ (const_string "alu"))
+
+
+;; ------------------------------------------------------------------------
+;; Include files
+;; ------------------------------------------------------------------------
+
+(include "constraints.md")
+(include "predicates.md")
+(include "csky_insn_fpu.md")
+(include "csky_insn_dsp.md")
+(include "csky_pipeline_ck801.md")
+(include "csky_pipeline_ck802.md")
+(include "csky_pipeline_ck803.md")
+(include "csky_pipeline_ck810.md")
+
+;; ------------------------------------------------------------------------
+;; Mov insns
+;; ------------------------------------------------------------------------
+
+(define_mode_iterator QHI [QI HI])
+
+(define_expand "movsi"
+ [(set (match_operand:SI 0 "general_operand" "")
+ (match_operand:SI 1 "general_operand" ""))]
+ ""
+ "
+ {
+ rtx scratch = !can_create_pseudo_p () ? operands[0] : 0;
+ if (can_create_pseudo_p () && MEM_P (operands[0]))
+ {
+ operands[1] = force_reg (SImode, operands[1]);
+ emit_insn (gen_rtx_SET (operands[0], operands[1]));
+ DONE;
+ }
+
+ /* Recognize the case where operand[1] is a reference to thread-local
+ data and load its address to a register. */
+ if (csky_tls_referenced_p (operands[1]))
+ {
+ rtx tmp = operands[1];
+ rtx addend = NULL;
+
+ if (GET_CODE (tmp) == CONST && GET_CODE (XEXP (tmp, 0)) == PLUS)
+ {
+ addend = XEXP (XEXP (tmp, 0), 1);
+ tmp = XEXP (XEXP (tmp, 0), 0);
+ }
+
+ gcc_assert (GET_CODE (tmp) == SYMBOL_REF);
+ gcc_assert (SYMBOL_REF_TLS_MODEL (tmp) != 0);
+
+ tmp = csky_legitimize_tls_address (tmp, scratch);
+ if (addend)
+ {
+ tmp = gen_rtx_PLUS (SImode, tmp, addend);
+ tmp = force_operand (tmp, operands[0]);
+ }
+ operands[1] = tmp;
+ }
+ else if (flag_pic
+ && (CONSTANT_P (operands[1])
+ || csky_symbol_mentioned_p (operands[1])
+ || csky_label_mentioned_p (operands[1])))
+ operands[1] = csky_legitimize_pic_address (operands[1], scratch, true);
+ }"
+)
+
+;; Note that we conservatively estimate all load and store insns as having
+;; a size of 4 bytes throughout even though some variants can be encoded
+;; as 2-byte machine instructions. Getting more accurate instruction counts
+;; would be better handled by calling into a C function than encoding it
+;; as an RTL conditional here.
+;; Also note that we don't count the extra space required for constant
+;; pool entries here; that's handled by the constant pool entries themselves.
+;; In -mno-constpool cases where we're relying on the assembler to create
+;; the constant pool, we'll undercount branch lengths, but in that case the
+;; assembler also handles branch relaxation as needed. It's only ck801 that
+;; requires compiler cooperation when long branches are needed.
+
+(define_insn "*cskyv2_movsi"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=b,r,r,r, r, r, r,r, m,r,*y,*r,*v,*r,*v")
+ (match_operand:SI 1 "general_operand" " b,r,I,Un,Uc,Uo,m,miF,r,c,*r,*y,*r,*v,*v"))]
+ "CSKY_ISA_FEATURE (E2)"
+ "* return csky_output_move (insn, operands, SImode);"
+ [(set_attr "length" "2,4,4,4,4,8,4,4,4,4,4,4,4,4,4")
+ (set_attr "type" "alu,alu,alu,alu,alu,alu,load,load,store,alu,alu,alu,alu,alu,alu")]
+)
+
+(define_insn "*ck801_movsi"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,a, a,r,r, m,r")
+ (match_operand:SI 1 "general_operand" "r, Up,T,m,miF,r,c"))]
+ "CSKY_ISA_FEATURE (E1)"
+ "* return csky_output_ck801_move (insn, operands, SImode);"
+ [(set_attr "length" "2,2,2,4,4,4,2")
+ (set_attr "type" "alu,alu,alu,load,load,store,alu")]
+)
+
+;; Convert negative assignments to zero minus positive numbers.
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "const_int_operand" ""))]
+ "satisfies_constraint_T (operands[1])"
+ [(set (match_dup 0) (match_dup 2))
+ (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))]
+ "operands[2] = const0_rtx;"
+)
+
+;; Convert const assignments to small number of assignments and left shift.
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "const_int_operand" ""))]
+ ""
+ [(set (match_dup 0) (match_dup 1))
+ (set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))]
+ "
+ {
+ unsigned int base, shift;
+
+ if (!csky_shifted_imm8_constant (INTVAL (operands[1]), &base, &shift))
+ FAIL;
+ if (shift == 0)
+ FAIL;
+ operands[1] = GEN_INT (base);
+ operands[2] = GEN_INT (shift);
+ }"
+)
+
+
+(define_expand "movhi"
+ [(set (match_operand:HI 0 "general_operand" "")
+ (match_operand:HI 1 "general_operand" ""))]
+ ""
+ "
+ {
+ if (GET_CODE (operands[0]) == MEM)
+ operands[1] = force_reg (HImode, operands[1]);
+ else if (CONSTANT_P (operands[1])
+ && (GET_CODE (operands[1]) != CONST_INT
+ || (! CSKY_CONST_OK_FOR_I (INTVAL (operands[1]))
+ && ! CSKY_CONST_OK_FOR_Ub (INTVAL (operands[1]))
+ && ! CSKY_CONST_OK_FOR_Uc (INTVAL (operands[1]))))
+ && ! reload_completed && ! reload_in_progress)
+ {
+ rtx reg = gen_reg_rtx (SImode);
+ emit_insn (gen_movsi (reg, operands[1]));
+ operands[1] = gen_lowpart (HImode, reg);
+ }
+ }"
+)
+
+(define_insn "*cskyv2_movhi"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=b,r,r,r, r, r, r,r, m,r,*y,*r,*v,*r,*v")
+ (match_operand:HI 1 "general_operand" " b,r,I,Un,Uc,Uo,m,miF,r,c,*r,*y,*r,*v,*v"))]
+ "CSKY_ISA_FEATURE (E2)"
+ "* return csky_output_move (insn, operands, HImode);"
+ [(set_attr "length" "2,4,4,4,4,8,4,4,4,4,4,4,4,4,4")
+ (set_attr "type" "alu,alu,alu,alu,alu,alu,load,load,store,alu,alu,alu,alu,alu,alu")]
+)
+
+(define_insn "*ck801_movhi"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=r,a, a,r,r, m,r")
+ (match_operand:HI 1 "general_operand" "r, Up,T,m,miF,r,c"))]
+ "CSKY_ISA_FEATURE (E1)"
+ "* return csky_output_ck801_move (insn, operands, HImode);"
+ [(set_attr "length" "2,2,2,4,4,4,2")
+ (set_attr "type" "alu,alu,alu,load,load,store,alu")]
+)
+
+
+(define_expand "movqi"
+ [(set (match_operand:QI 0 "general_operand" "")
+ (match_operand:QI 1 "general_operand" ""))]
+ ""
+ "
+ {
+ if (can_create_pseudo_p () && GET_CODE (operands[0]) == MEM)
+ operands[1] = force_reg (QImode, operands[1]);
+ else if (CONSTANT_P (operands[1])
+ && (GET_CODE (operands[1]) != CONST_INT
+ || (! CSKY_CONST_OK_FOR_I (INTVAL (operands[1]))
+ && ! CSKY_CONST_OK_FOR_Ub (INTVAL (operands[1]))
+ && ! CSKY_CONST_OK_FOR_Uc (INTVAL (operands[1]))))
+ && ! reload_completed && ! reload_in_progress)
+ {
+ rtx reg = gen_reg_rtx (SImode);
+ emit_insn (gen_movsi (reg, operands[1]));
+ operands[1] = gen_lowpart (QImode, reg);
+ }
+ }"
+)
+
+(define_insn "*cskyv2_movqi"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=b,r,r,r, r, r, r,r, m,r,*y,*r,*v,*r,*v")
+ (match_operand:QI 1 "general_operand" " b,r,I,Un,Uc,Uo,m,miF,r,c,*r,*y,*r,*v,*v"))]
+ "CSKY_ISA_FEATURE (E2)"
+ "* return csky_output_move (insn, operands, QImode);"
+ [(set_attr "length" "2,4,4,4,4,8,4,4,4,4,4,4,4,4,4")
+ (set_attr "type" "alu,alu,alu,alu,alu,alu,load,load,store,alu,alu,alu,alu,alu,alu")]
+)
+
+(define_insn "*ck801_movqi"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=r,a, a,r,r, m,r")
+ (match_operand:QI 1 "general_operand" "r, Up,T,m,miF,r,c"))]
+ "CSKY_ISA_FEATURE (E1)"
+ "* return csky_output_ck801_move (insn, operands, QImode);"
+ [(set_attr "length" "2,2,2,4,4,4,2")
+ (set_attr "type" "alu,alu,alu,load,load,store,alu")]
+)
+
+
+(define_expand "movdi"
+ [(set (match_operand:DI 0 "general_operand" "")
+ (match_operand:DI 1 "general_operand" ""))]
+ ""
+ "if (can_create_pseudo_p () && GET_CODE (operands[0]) == MEM)
+ operands[1] = force_reg (DImode, operands[1]);"
+)
+
+;; Convert negative assignments to zero minus positive numbers.
+(define_split
+ [(set (match_operand:QHI 0 "register_operand" "")
+ (match_operand:QHI 1 "const_int_operand" ""))]
+ "satisfies_constraint_T (operands[1])"
+ [(set (match_dup 4) (match_dup 2))
+ (set (match_dup 4) (match_dup 3))
+ (set (match_dup 0) (match_dup 5))]
+ "
+ {
+ int low;
+
+ if (TARGET_BIG_ENDIAN)
+ low = 4 - mode_size[GET_MODE (operands[0])];
+ else
+ low = 0;
+ operands[2] = const0_rtx;
+ if (can_create_pseudo_p ())
+ operands[4] = gen_reg_rtx (SImode);
+ else
+ operands[4] = gen_rtx_REG (SImode, REGNO (operands[0]));
+ operands[3] = gen_rtx_PLUS (SImode, operands[4], operands[1]);
+ operands[5] = gen_rtx_SUBREG (GET_MODE (operands[0]), operands[4], low);
+ }"
+)
+
+;; Convert const assignments to small number of assignments and left shift.
+(define_split
+ [(set (match_operand:QHI 0 "register_operand" "")
+ (match_operand:QHI 1 "const_int_operand" ""))]
+ ""
+ [(set (match_dup 3) (match_dup 1))
+ (set (match_dup 3) (ashift:SI (match_dup 3) (match_dup 2)))
+ (set (match_dup 0) (match_dup 4))]
+ "
+ {
+ unsigned int base, shift;
+ int low;
+
+ if (!csky_shifted_imm8_constant (INTVAL (operands[1]), &base, &shift))
+ FAIL;
+ if (shift == 0)
+ FAIL;
+
+ if (TARGET_BIG_ENDIAN)
+ low = 4 - mode_size[GET_MODE (operands[0])];
+ else
+ low = 0;
+
+ operands[1] = GEN_INT (base);
+ operands[2] = GEN_INT (shift);
+ if (can_create_pseudo_p ())
+ operands[3] = gen_reg_rtx (SImode);
+ else
+ operands[3] = gen_rtx_REG (SImode, REGNO (operands[0]));
+ operands[4] = gen_rtx_SUBREG (GET_MODE (operands[0]), operands[3], low);
+ }"
+)
+
+
+(define_insn "*csky_movdi"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=b,r,r, r,r, m,*r,*y,*v,*r,*v")
+ (match_operand:DI 1 "general_operand" " b,r,Ud,m,miF,r,*y,*r,*r,*v,*v"))]
+ "CSKY_ISA_FEATURE (E2)"
+ "* return csky_output_movedouble (operands, DImode);"
+ [(set_attr "length" "4,8,8,8,8,8,16,16,16,16,16")
+ (set_attr "type" "alu,alu,alu,load,load,store,alu,alu,alu,alu,alu")]
+)
+
+(define_insn "*ck801_movdi"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,a, a,r,r, m")
+ (match_operand:DI 1 "general_operand" "r, Up,T,m,miF,r"))]
+ "CSKY_ISA_FEATURE (E1)"
+ "* return csky_output_ck801_movedouble (operands, DImode);"
+ [(set_attr "length" "4,4,4,8,8,8")
+ (set_attr "type" "alu,alu,alu,load,load,store")]
+)
+
+;; Float mov instructions.
+
+(define_expand "movsf"
+ [(set (match_operand:SF 0 "general_operand" "")
+ (match_operand:SF 1 "general_operand" ""))]
+ ""
+ "
+ if (GET_CODE (operands[0]) == MEM && can_create_pseudo_p ())
+ operands[1] = force_reg (SFmode, operands[1]);
+ "
+)
+
+;; FIXME: maybe the vreg load/stores should have their own type attr.
+(define_insn "*csky_movsf_fpv2"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=b,r,v,r,r,r, m,Q,v,v,v")
+ (match_operand:SF 1 "general_operand" " b,r,r,v,m,mF,r,v,Q,v,m"))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "* return csky_output_move (insn, operands, SFmode);"
+ [(set_attr "length" "2,4,4,4,4,4,4,4,4,4,4")
+ (set_attr "type" "alu,alu,alu,alu,load,load,store,alu,alu,alu,alu")]
+)
+
+(define_insn "*ck801_movsf"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,r, m")
+ (match_operand:SF 1 "general_operand" " r,m,mF,r"))]
+ "CSKY_ISA_FEATURE (E1)"
+ "* return csky_output_ck801_move (insn, operands, SFmode);"
+ [(set_attr "length" "2,4,4,4")
+ (set_attr "type" "alu,load,load,store")]
+)
+
+(define_insn "*csky_movsf"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=b,r,r,r, m")
+ (match_operand:SF 1 "general_operand" " b,r,m,mF,r"))]
+ "CSKY_ISA_FEATURE (E2) && !CSKY_ISA_FEATURE (fpv2_sf)"
+ "* return csky_output_move (insn, operands, SFmode);"
+ [(set_attr "length" "2,4,4,4,4")
+ (set_attr "type" "alu,alu,load,load,store")]
+)
+
+
+(define_expand "movdf"
+ [(set (match_operand:DF 0 "general_operand" "")
+ (match_operand:DF 1 "general_operand" ""))]
+ ""
+ "
+ if (GET_CODE (operands[0]) == MEM && can_create_pseudo_p ())
+ operands[1] = force_reg (DFmode, operands[1]);
+ "
+)
+
+;; FIXME: maybe the vreg load/stores should have their own type attr.
+(define_insn "*csky_movdf_fpv2"
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=b,r,v,r,r,r, m,Q,v,v,v")
+ (match_operand:DF 1 "general_operand" "b,r,r,v,m,mF,r,v,Q,v,m"))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "* return csky_output_movedouble (operands, DFmode);"
+ [(set_attr "length" "4,8,8,8,8,8,8,8,8,8,8")
+ (set_attr "type" "alu,alu,alu,alu,load,load,store,alu,alu,alu,alu")]
+)
+
+(define_insn "*ck801_movdf"
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,r, m")
+ (match_operand:DF 1 "general_operand" " r,m,mF,r"))]
+ "CSKY_ISA_FEATURE (E1)"
+ "* return csky_output_ck801_movedouble (operands, DFmode);"
+ [(set_attr "length" "4,8,8,8")
+ (set_attr "type" "alu,load,load,store")]
+)
+
+(define_insn "*csky_movdf"
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=b,r,r,r, m")
+ (match_operand:DF 1 "general_operand" " b,r,m,mF,r"))]
+ "CSKY_ISA_FEATURE (E2) && !CSKY_ISA_FEATURE (fpv2_df)"
+ "* return csky_output_movedouble (operands, DFmode);"
+ [(set_attr "length" "4,8,8,8,8")
+ (set_attr "type" "alu,alu,load,load,store")]
+)
+
+;; The only CCmode move supported is a nop. Without this pattern,
+;; CSE is unable to eliminate redundant comparisons in conditional
+;; execution expressions.
+
+(define_insn "*movcc_nop"
+ [(set (reg:CC CSKY_CC_REGNUM) (reg:CC CSKY_CC_REGNUM))]
+ ""
+ ""
+ [(set_attr "length" "0")]
+)
+
+;; ------------------------------------------------------------------------
+;; Conditional mov insns
+;; ------------------------------------------------------------------------
+
+;; Only handle integer comparisons because float and double require
+;; library calls.
+
+(define_expand "movsicc"
+ [(set (match_operand 0 "register_operand" "")
+ (if_then_else:SI (match_operand 1 "ordered_comparison_operator" "")
+ (match_operand:SI 2 "register_operand" "")
+ (match_operand:SI 3 "register_operand" "")))]
+ "CSKY_ISA_FEATURE (E2)"
+ "
+ {
+ bool invert = csky_emit_compare (GET_CODE (operands[1]),
+ XEXP (operands[1], 0),
+ XEXP (operands[1], 1));
+
+ if (invert)
+ emit_insn (gen_movf (operands[0], operands[2], operands[3]));
+ else
+ emit_insn (gen_movt (operands[0], operands[2], operands[3]));
+ DONE;
+ }")
+
+(define_insn "movt"
+ [(set (match_operand:SI 0 "register_operand" "=r, r")
+ (if_then_else:SI (ne (reg:CC CSKY_CC_REGNUM) (const_int 0))
+ (match_operand:SI 1 "register_operand" "r, 0")
+ (match_operand:SI 2 "register_operand" "0, r")))]
+ "CSKY_ISA_FEATURE (E2)"
+ "@
+ movt\t%0, %1
+ movf\t%0, %2"
+ [(set_attr "length" "4,4")]
+)
+
+(define_insn "movf"
+ [(set (match_operand:SI 0 "register_operand" "=r, r")
+ (if_then_else:SI (eq (reg:CC CSKY_CC_REGNUM) (const_int 0))
+ (match_operand:SI 1 "register_operand" "r, 0")
+ (match_operand:SI 2 "register_operand" "0, r")))]
+ "CSKY_ISA_FEATURE (E2)"
+ "@
+ movf\t%0, %1
+ movt\t%0, %2"
+ [(set_attr "length" "4,4")]
+)
+
+(define_expand "cstoresi4"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (match_operator 1 "ordered_comparison_operator"
+ [(match_operand:SI 2 "csky_compare_operand" "")
+ (match_operand:SI 3 "nonmemory_operand" "")]))]
+ ""
+ "
+ {
+ bool invert = csky_emit_compare (GET_CODE (operands[1]),
+ operands[2], operands[3]);
+
+ if (invert)
+ emit_insn (gen_mvcv (operands[0]));
+ else if (CSKY_ISA_FEATURE (E1))
+ {
+ emit_insn (gen_movsi (operands[0], const0_rtx));
+ emit_insn (gen_ck801_addc (operands[0], operands[0], operands[0]));
+ }
+ else
+ emit_insn (gen_mvc (operands[0]));
+ DONE;
+ }"
+)
+
+(define_insn "mvc"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ne:SI (reg:CC CSKY_CC_REGNUM) (const_int 0)))]
+ "CSKY_ISA_FEATURE (E2)"
+ "mvc\t%0"
+)
+
+(define_insn "mvcv"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (eq:SI (reg:CC CSKY_CC_REGNUM) (const_int 0)))]
+ ""
+ "mvcv\t%0"
+)
+
+;; ------------------------------------------------------------------------
+;; Arithmetic insns
+;; ------------------------------------------------------------------------
+
+(define_insn "abssi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (abs:SI (match_operand:SI 1 "register_operand" "r")))]
+ "CSKY_ISA_FEATURE (2E3)"
+ "abs\t%0, %1"
+ [(set_attr "type" "alu")]
+)
+
+(define_insn "extvsi"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extract:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "const_int_operand" "")
+ (match_operand:SI 3 "const_int_operand" "")))]
+ "CSKY_ISA_FEATURE (2E3)"
+ {
+ operands[2] = GEN_INT (INTVAL (operands[3]) + INTVAL (operands[2]) - 1);
+ return \"sext\t%0, %1, %2, %3\";
+ }
+)
+
+(define_insn "insvsi"
+ [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r")
+ (match_operand:SI 1 "const_int_operand" "i")
+ (match_operand:SI 2 "const_int_operand" "i"))
+ (match_operand:SI 3 "register_operand" "r"))]
+ "CSKY_ISA_FEATURE (2E3)"
+ {
+ operands[1] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[1]) - 1);
+ return \"ins\t%0, %3, %1, %2\";
+ }
+)
+
+(define_expand "bseti"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (ior:SI (match_operand:SI 1 "register_operand" "")
+ (ashift:SI (const_int 1)
+ (match_operand:SI 2 "csky_literal_K_operand" ""))))]
+ ""
+ "")
+
+(define_insn "smart_bseti"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ior:SI (match_operand:SI 1 "register_operand" "0")
+ (ashift:SI (const_int 1)
+ (match_operand:SI 2 "csky_literal_K_operand" "K"))))]
+ "TARGET_MINI_REGISTERS"
+ "bseti\t%0, %2"
+ [(set_attr "length" "2")])
+
+(define_insn "fast_bseti"
+ [(set (match_operand:SI 0 "register_operand" "=a,r")
+ (ior:SI (match_operand:SI 1 "register_operand" "0,r")
+ (ashift:SI (const_int 1)
+ (match_operand:SI 2 "csky_literal_K_operand" "K,K"))))]
+ "!TARGET_MINI_REGISTERS"
+ "bseti\t%0, %1, %2"
+ [(set_attr "length" "2,4")])
+
+(define_expand "bclri"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (and:SI (match_operand:SI 1 "register_operand" "")
+ (not:SI (ashift:SI (const_int 1)
+ (match_operand:SI 2 "csky_literal_K_operand" "")))))]
+ ""
+ "")
+
+(define_insn "smart_bclri"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (and:SI (match_operand:SI 1 "register_operand" "0")
+ (not:SI (ashift:SI (const_int 1)
+ (match_operand:SI 2 "csky_literal_K_operand" "K")))))]
+ "TARGET_MINI_REGISTERS"
+ "bclri\t%0, %2"
+ [(set_attr "length" "2")])
+
+(define_insn "fast_bclri"
+ [(set (match_operand:SI 0 "register_operand" "=a,r")
+ (and:SI (match_operand:SI 1 "register_operand" "0,r")
+ (not:SI (ashift:SI (const_int 1)
+ (match_operand:SI 2 "csky_literal_K_operand" "K,K")))))]
+ "!TARGET_MINI_REGISTERS"
+ "bclri\t%0, %1, %2"
+ [(set_attr "length" "2,4")])
+
+
+;; Shift instructions.
+
+(define_expand "ashlsi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (ashift:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "csky_arith_K_operand" "")))]
+ ""
+ ""
+)
+
+(define_insn "*cskyv2_ashlsi3"
+ [(set (match_operand:SI 0 "register_operand" "=b,r,a,r")
+ (ashift:SI (match_operand:SI 1 "register_operand" "0,r,a,r")
+ (match_operand:SI 2 "csky_arith_K_operand" "b,r,K,K")))]
+ "CSKY_ISA_FEATURE (E2)"
+ "@
+ lsl %0, %1, %2
+ lsl %0, %1, %2
+ lsli %0, %1, %2
+ lsli %0, %1, %2"
+ [(set_attr "length" "2,4,2,4")]
+)
+
+(define_insn "ck801_ashlsi3"
+ [(set (match_operand:SI 0 "register_operand" "=a,r")
+ (ashift:SI (match_operand:SI 1 "register_operand" "a,0")
+ (match_operand:SI 2 "csky_arith_K_operand" "K,r")))]
+ "CSKY_ISA_FEATURE (E1)"
+ "@
+ lsli %0, %1, %2
+ lsl %0, %1, %2"
+)
+
+
+(define_expand "ashrsi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (ashiftrt:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "csky_arith_K_operand" "")))]
+ ""
+ ""
+)
+
+(define_insn "*cskyv2_ashrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=b,r,a,r")
+ (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,r,a,r")
+ (match_operand:SI 2 "csky_arith_K_operand" "b,r,K,K")))]
+ "CSKY_ISA_FEATURE (E2)"
+ "@
+ asr %0, %1, %2
+ asr %0, %1, %2
+ asri %0, %1, %2
+ asri %0, %1, %2"
+ [(set_attr "length" "2,4,2,4")]
+)
+
+(define_insn "*ck801_ashrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=a,r")
+ (ashiftrt:SI (match_operand:SI 1 "register_operand" "a,0")
+ (match_operand:SI 2 "csky_arith_K_operand" "K,r")))]
+ "CSKY_ISA_FEATURE (E1)"
+ "@
+ asri %0, %1, %2
+ asr %0, %1, %2"
+)
+
+
+(define_expand "lshrsi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (lshiftrt:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "csky_arith_K_operand" "")))]
+ ""
+ ""
+)
+
+(define_insn "*cskyv2_lshrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=b,r,a,r")
+ (lshiftrt:SI (match_operand:SI 1 "register_operand" "0,r,a,r")
+ (match_operand:SI 2 "csky_arith_K_operand" "b,r,K,K")))]
+ "CSKY_ISA_FEATURE (E2)"
+ "@
+ lsr %0, %1, %2
+ lsr %0, %1, %2
+ lsri %0, %1, %2
+ lsri %0, %1, %2"
+ [(set_attr "length" "2,4,2,4")]
+)
+
+(define_insn "ck801_lshrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=a,r")
+ (lshiftrt:SI (match_operand:SI 1 "register_operand" "a,0")
+ (match_operand:SI 2 "csky_arith_K_operand" "K,r")))]
+ "CSKY_ISA_FEATURE (E1)"
+ "@
+ lsri %0, %1, %2
+ lsr %0, %1, %2"
+)
+
+
+(define_expand "rotlsi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (rotate:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "csky_arith_K_operand" "")))]
+ ""
+ ""
+)
+
+(define_insn "*cskyv2_rotlsi3"
+ [(set (match_operand:SI 0 "register_operand" "=b,r,r")
+ (rotate:SI (match_operand:SI 1 "register_operand" "0,r,r")
+ (match_operand:SI 2 "csky_arith_K_operand" "b,r,K")))]
+ "CSKY_ISA_FEATURE (E2)"
+ "@
+ rotl %0, %1, %2
+ rotl %0, %1, %2
+ rotli %0, %1, %2"
+ [(set_attr "length" "2,4,4")]
+)
+
+(define_insn "*ck801_rotlsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (rotate:SI (match_operand:SI 1 "register_operand" "0")
+ (match_operand:SI 2 "csky_arith_K_operand" "r")))]
+ "CSKY_ISA_FEATURE (E1)"
+ "rotl %0, %1, %2"
+)
+
+
+;; Add instructions.
+;; C-SKY addi and subi machine instructions only accept positive immediate
+;; values, so we have to special case immediates <= 0 in these patterns.
+
+(define_expand "addsi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (plus:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "nonmemory_operand" "")))]
+ ""
+ ""
+)
+
+(define_insn "smart_addsi3"
+ [(set (match_operand:SI 0 "register_operand" "=a,r,a,a,a,a, r,r")
+ (plus:SI (match_operand:SI 1 "register_operand" "%a,0,0,a,0,a, r,r")
+ (match_operand:SI 2 "nonmemory_operand" "a, r,N,L,T,Us,M,Um")))]
+ "TARGET_MINI_REGISTERS && CSKY_ISA_FEATURE (E2)
+ && operands[0] != stack_pointer_rtx
+ && operands[1] != stack_pointer_rtx"
+ "@
+ addu\t%0, %1, %2
+ addu\t%0, %1, %2
+ addi\t%0, %1, %2
+ addi\t%0, %1, %2
+ subi\t%0, %1, %M2
+ subi\t%0, %1, %M2
+ addi\t%0, %1, %2
+ subi\t%0, %1, %M2"
+ [(set_attr "length" "2,2,2,2,2,2,4,4")
+ (set_attr "type" "addsub")]
+)
+
+(define_insn_and_split "*smart_addsi3_sp"
+ [(set (match_operand:SI 0 "register_operand" "=z,z, z,a,&a,z,a,r")
+ (plus:SI (match_operand:SI 1 "register_operand" "0, 0, 0,z, z,a,z,r")
+ (match_operand:SI 2 "nonmemory_operand" "P, Ug,r,Uq,i,a,a,M")))]
+ "TARGET_MINI_REGISTERS && CSKY_ISA_FEATURE (E2)
+ && (operands[0] == stack_pointer_rtx || operands[1] == stack_pointer_rtx)"
+ "@
+ addi\t%0, %1, %2
+ subi\t%0, %1, %M2
+ addu\t%0, %1, %2
+ addi\t%0, %1, %2
+ #
+ addu\t%0, %1, %2
+ addu\t%0, %1, %2
+ addi\t%0, %1, %2"
+ "(operands[0] != stack_pointer_rtx
+ && operands[1] == stack_pointer_rtx
+ && !satisfies_constraint_Uq (operands[2]))"
+ [(set (match_dup 0)
+ (plus:SI (match_dup 1) (match_dup 0)))]
+ "emit_move_insn (operands[0], operands[2]);"
+ [(set_attr "type" "addsub")]
+)
+
+(define_insn "*ck801_addsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,a,a,a,a,a, !z,!z,!z,a")
+ (plus:SI (match_operand:SI 1 "register_operand" "%0,a,0,a,0,a, 0, 0, 0, !z")
+ (match_operand:SI 2 "nonmemory_operand" "r, a,N,L,T,Us,P, Ug,r, Uq")))]
+ "CSKY_ISA_FEATURE (E1)"
+ "@
+ addu\t%0, %1, %2
+ addu\t%0, %1, %2
+ addi\t%0, %1, %2
+ addi\t%0, %1, %2
+ subi\t%0, %1, %M2
+ subi\t%0, %1, %M2
+ addi\t%0, %1, %2
+ subi\t%0, %1, %M2
+ addu\t%0, %1, %2
+ addi\t%0, %1, %2"
+ [(set_attr "type" "addsub")]
+)
+
+(define_insn "fast_addsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r, r")
+ (plus:SI (match_operand:SI 1 "register_operand" "%r,r, r")
+ (match_operand:SI 2 "nonmemory_operand" "M, Um,r")))]
+ "!TARGET_MINI_REGISTERS && CSKY_ISA_FEATURE (E2)"
+ "@
+ addi\t%0, %1, %2
+ subi\t%0, %1, %M2
+ addu\t%0, %1, %2"
+ [(set_attr "type" "addsub")]
+)
+
+(define_expand "adddi3"
+ [(parallel [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "csky_arith_int1_operand" "")))
+ (clobber (reg:CC CSKY_CC_REGNUM))])]
+ ""
+ "
+ if (CSKY_ISA_FEATURE (E1) && (GET_CODE (operands[2]) != REG))
+ operands[2] = force_reg (DImode, operands[2]);
+ "
+)
+
+/* Note that the csky addc instruction both reads and writes the carry bit.
+ The purpose of the initial cmplt instruction in the expansion is to
+ clear the carry bit before adding the lo words. */
+
+(define_insn_and_split "*cskyv2_adddi3"
+ [(set (match_operand:DI 0 "register_operand" "=b,&r")
+ (plus:DI (match_operand:DI 1 "register_operand" "%0,r")
+ (match_operand:DI 2 "register_operand" "b, r")))
+ (clobber (reg:CC CSKY_CC_REGNUM))]
+ "CSKY_ISA_FEATURE (E2)"
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+ {
+ int hi = TARGET_BIG_ENDIAN ? 0 : UNITS_PER_WORD;
+ int lo = TARGET_BIG_ENDIAN ? UNITS_PER_WORD : 0;
+ rtx l0 = simplify_gen_subreg (SImode, operands[0], DImode, lo);
+ rtx h0 = simplify_gen_subreg (SImode, operands[0], DImode, hi);
+ rtx l1 = simplify_gen_subreg (SImode, operands[1], DImode, lo);
+ rtx h1 = simplify_gen_subreg (SImode, operands[1], DImode, hi);
+ rtx l2 = simplify_gen_subreg (SImode, operands[2], DImode, lo);
+ rtx h2 = simplify_gen_subreg (SImode, operands[2], DImode, hi);
+
+ emit_insn (gen_cmpltsi_r (copy_rtx (l1), copy_rtx (l1)));
+ emit_insn (gen_cskyv2_addc (l0, l1, l2));
+ emit_insn (gen_cskyv2_addc (h0, h1, h2));
+ DONE;
+ }
+ [(set_attr "length" "6,12")]
+)
+
+(define_insn_and_split "*ck801_adddi3"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (match_operand:DI 1 "register_operand" "%0")
+ (match_operand:DI 2 "register_operand" "r")))
+ (clobber (reg:CC CSKY_CC_REGNUM))]
+ "CSKY_ISA_FEATURE (E1)"
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+ {
+ int hi = TARGET_BIG_ENDIAN ? 0 : UNITS_PER_WORD;
+ int lo = TARGET_BIG_ENDIAN ? UNITS_PER_WORD : 0;
+ rtx l0 = simplify_gen_subreg (SImode, operands[0], DImode, lo);
+ rtx h0 = simplify_gen_subreg (SImode, operands[0], DImode, hi);
+ rtx l1 = simplify_gen_subreg (SImode, operands[1], DImode, lo);
+ rtx h1 = simplify_gen_subreg (SImode, operands[1], DImode, hi);
+ rtx l2 = simplify_gen_subreg (SImode, operands[2], DImode, lo);
+ rtx h2 = simplify_gen_subreg (SImode, operands[2], DImode, hi);
+
+ emit_insn (gen_cmpltsi_r (copy_rtx (l1), copy_rtx (l1)));
+ emit_insn (gen_ck801_addc (l0, l1, l2));
+ emit_insn (gen_ck801_addc (h0, h1, h2));
+ DONE;
+ }
+ [(set_attr "length" "6")]
+)
+
+;; Special case for "longlong += 1".
+
+(define_insn_and_split "*cskyv2_adddi1_1"
+ [(set (match_operand:DI 0 "register_operand" "=&r")
+ (plus:DI (match_operand:DI 1 "register_operand" "0")
+ (const_int 1)))
+ (clobber (reg:CC CSKY_CC_REGNUM))]
+ "CSKY_ISA_FEATURE (E2)"
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+ {
+ int hi = TARGET_BIG_ENDIAN ? 0 : UNITS_PER_WORD;
+ int lo = TARGET_BIG_ENDIAN ? UNITS_PER_WORD : 0;
+ rtx l0 = simplify_gen_subreg (SImode, operands[0], DImode, lo);
+ rtx h0 = simplify_gen_subreg (SImode, operands[0], DImode, hi);
+
+ if (TARGET_MINI_REGISTERS)
+ {
+ emit_insn (gen_smart_addsi3 (l0, copy_rtx (l0),
+ gen_int_mode (1, SImode)));
+ emit_insn (gen_smart_cmpnesi_i (copy_rtx (l0),
+ gen_int_mode (0, SImode)));
+ emit_insn (gen_cskyv2_addcc_invert (h0, copy_rtx (h0),
+ gen_int_mode (1, SImode)));
+ }
+ else
+ {
+ emit_insn (gen_fast_addsi3 (l0, copy_rtx (l0),
+ gen_int_mode (1, SImode)));
+ emit_insn (gen_fast_cmpnesi_i (copy_rtx (l0),
+ gen_int_mode (0, SImode)));
+ emit_insn (gen_cskyv2_addcc_invert (h0, copy_rtx (h0),
+ gen_int_mode (1, SImode)));
+ }
+ DONE;
+ }
+ [(set (attr "length")
+ (if_then_else (match_test "TARGET_MINI_REGISTERS")
+ (const_int 8)
+ (const_int 12)))]
+)
+
+;; sub instructions.
+
+(define_expand "subsi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (minus:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "nonmemory_operand" "")))]
+ ""
+ ""
+)
+
+(define_insn "smart_subsi3"
+ [(set (match_operand:SI 0 "register_operand" "=a,a,a,a,a,a")
+ (minus:SI (match_operand:SI 1 "register_operand" "a, 0,0,a,0,a")
+ (match_operand:SI 2 "nonmemory_operand" "a, a,N,L,T,Us")))]
+ "TARGET_MINI_REGISTERS && CSKY_ISA_FEATURE (E2)
+ && operands[0] != stack_pointer_rtx
+ && operands[1] != stack_pointer_rtx"
+ "@
+ subu\t%0, %1, %2
+ subu\t%0, %1, %2
+ subi\t%0, %1, %2
+ subi\t%0, %1, %2
+ addi\t%0, %1, %M2
+ addi\t%0, %1, %M2"
+ [(set_attr "length" "2,2,2,2,2,2")
+ (set_attr "type" "addsub")]
+)
+
+(define_insn "*smart_subsi3_sp"
+ [(set (match_operand:SI 0 "register_operand" "=z,z, z,a, a,r")
+ (minus:SI (match_operand:SI 1 "register_operand" "0, 0, 0,z, a,r")
+ (match_operand:SI 2 "nonmemory_operand" "P, Ug,a,Ur,a,M")))]
+ "TARGET_MINI_REGISTERS && CSKY_ISA_FEATURE (E2)
+ && (operands[0] == stack_pointer_rtx || operands[1] == stack_pointer_rtx)"
+ "@
+ subi\t%0, %1, %2
+ addi\t%0, %1, %M2
+ subu\t%0, %1, %2
+ addi\t%0, %1, %M2
+ subu\t%0, %1, %2
+ subi\t%0, %1, %2"
+ [(set_attr "length" "2,2,2,2,2,4")
+ (set_attr "type" "addsub")]
+)
+
+(define_insn "*ck801_subsi3"
+ [(set (match_operand:SI 0 "register_operand" "=a,a,a,a,a,a")
+ (minus:SI (match_operand:SI 1 "register_operand" "0, a,0,a,0,a")
+ (match_operand:SI 2 "nonmemory_operand" "a, a,N,L,T,Us")))]
+ "CSKY_ISA_FEATURE (E1)
+ && operands[0] != stack_pointer_rtx
+ && operands[1] != stack_pointer_rtx"
+ "@
+ subu\t%0, %1, %2
+ subu\t%0, %1, %2
+ subi\t%0, %1, %2
+ subi\t%0, %1, %2
+ addi\t%0, %1, %M2
+ addi\t%0, %1, %M2"
+ [(set_attr "type" "addsub")]
+)
+
+(define_insn "*ck801_subsi3_sp"
+ [(set (match_operand:SI 0 "register_operand" "=a,z,z, z")
+ (minus:SI (match_operand:SI 1 "register_operand" "z, 0,0, 0")
+ (match_operand:SI 2 "nonmemory_operand" "Ur,P,Ug,r")))]
+ "CSKY_ISA_FEATURE (E1)
+ && (operands[0] == stack_pointer_rtx || operands[1] == stack_pointer_rtx)"
+ "@
+ addi\t%0, %1, %M2
+ subi\t%0, %1, %2
+ addi\t%0, %1, %M2
+ subu\t%0, %1, %2"
+ [(set_attr "type" "addsub")]
+)
+
+(define_insn "fast_subsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+ (minus:SI (match_operand:SI 1 "register_operand" "r, r,r")
+ (match_operand:SI 2 "nonmemory_operand" "r, M,Um")))]
+ "!TARGET_MINI_REGISTERS && CSKY_ISA_FEATURE (E2)"
+ "@
+ subu\t%0, %1, %2
+ subi\t%0, %1, %2
+ addi\t%0, %1, %M2"
+ [(set_attr "type" "addsub")]
+)
+
+(define_expand "subdi3"
+ [(parallel [(set (match_operand:DI 0 "register_operand" "")
+ (minus:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "register_operand" "")))
+ (clobber (reg:CC CSKY_CC_REGNUM))])]
+ ""
+ ""
+)
+
+/* Note that the csky subc instruction both reads and writes the C bit.
+ The purpose of the initial cmphs instruction in the expansion is to
+ set the C bit before subtracting the lo words. */
+
+(define_insn_and_split "*cskyv2_subdi3"
+ [(set (match_operand:DI 0 "register_operand" "=b,&r")
+ (minus:DI (match_operand:DI 1 "register_operand" "0, r")
+ (match_operand:DI 2 "register_operand" "b, r")))
+ (clobber (reg:CC CSKY_CC_REGNUM))]
+ "CSKY_ISA_FEATURE (E2)"
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+ {
+ int hi = TARGET_BIG_ENDIAN ? 0 : UNITS_PER_WORD;
+ int lo = TARGET_BIG_ENDIAN ? UNITS_PER_WORD : 0;
+ rtx l0 = simplify_gen_subreg (SImode, operands[0], DImode, lo);
+ rtx h0 = simplify_gen_subreg (SImode, operands[0], DImode, hi);
+ rtx l1 = simplify_gen_subreg (SImode, operands[1], DImode, lo);
+ rtx h1 = simplify_gen_subreg (SImode, operands[1], DImode, hi);
+ rtx l2 = simplify_gen_subreg (SImode, operands[2], DImode, lo);
+ rtx h2 = simplify_gen_subreg (SImode, operands[2], DImode, hi);
+
+ emit_insn (gen_cmpgeusi_r (copy_rtx (l1), copy_rtx (l1)));
+ emit_insn (gen_cskyv2_subc (l0, l1, l2));
+ emit_insn (gen_cskyv2_subc (h0, h1, h2));
+ DONE;
+ }
+ [(set_attr "length" "6,12")]
+)
+
+(define_insn_and_split "*ck801_subdi3"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (minus:DI (match_operand:DI 1 "register_operand" "0")
+ (match_operand:DI 2 "register_operand" "r")))
+ (clobber (reg:CC CSKY_CC_REGNUM))]
+ "CSKY_ISA_FEATURE (E1)"
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+ {
+ int hi = TARGET_BIG_ENDIAN ? 0 : UNITS_PER_WORD;
+ int lo = TARGET_BIG_ENDIAN ? UNITS_PER_WORD : 0;
+ rtx l0 = simplify_gen_subreg (SImode, operands[0], DImode, lo);
+ rtx h0 = simplify_gen_subreg (SImode, operands[0], DImode, hi);
+ rtx l1 = simplify_gen_subreg (SImode, operands[1], DImode, lo);
+ rtx h1 = simplify_gen_subreg (SImode, operands[1], DImode, hi);
+ rtx l2 = simplify_gen_subreg (SImode, operands[2], DImode, lo);
+ rtx h2 = simplify_gen_subreg (SImode, operands[2], DImode, hi);
+
+ emit_insn (gen_cmpgeusi_r (copy_rtx (l1), copy_rtx (l1)));
+ emit_insn (gen_ck801_subc (l0, l1, l2));
+ emit_insn (gen_ck801_subc (h0, h1, h2));
+ DONE;
+ }
+ [(set_attr "length" "6")]
+)
+
+;; Special case for "longlong -= 1".
+
+(define_insn_and_split "*cskyv2_subdi1_1"
+ [(set (match_operand:DI 0 "register_operand" "=&r")
+ (plus:DI (match_operand:DI 1 "register_operand" "0")
+ (const_int -1)))
+ (clobber (reg:CC CSKY_CC_REGNUM))]
+ "CSKY_ISA_FEATURE (E2)"
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+ {
+ int hi = TARGET_BIG_ENDIAN ? 0 : UNITS_PER_WORD;
+ int lo = TARGET_BIG_ENDIAN ? UNITS_PER_WORD : 0;
+ rtx l0 = simplify_gen_subreg (SImode, operands[0], DImode, lo);
+ rtx h0 = simplify_gen_subreg (SImode, operands[0], DImode, hi);
+
+ if (TARGET_MINI_REGISTERS)
+ {
+ emit_insn (gen_smart_cmpnesi_i (copy_rtx (l0),
+ gen_int_mode (0, SImode)));
+ emit_insn (gen_cskyv2_addcc_invert (h0, copy_rtx (h0),
+ gen_int_mode (-1, SImode)));
+ emit_insn (gen_smart_subsi3 (l0, copy_rtx (l0),
+ gen_int_mode (1, SImode)));
+ }
+ else
+ {
+ emit_insn (gen_fast_cmpnesi_i (copy_rtx (l0),
+ gen_int_mode (0, SImode)));
+ emit_insn (gen_cskyv2_addcc_invert (h0, copy_rtx (h0),
+ gen_int_mode (-1, SImode)));
+ emit_insn (gen_fast_subsi3 (l0, copy_rtx (l0),
+ gen_int_mode (1, SImode)));
+ }
+ DONE;
+ }
+ [(set (attr "length")
+ (if_then_else (match_test "TARGET_MINI_REGISTERS")
+ (const_int 8)
+ (const_int 12)))]
+)
+
+;; Add with carry.
+
+(define_insn "cskyv2_addc"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (plus:SI (ne:SI (reg:CC CSKY_CC_REGNUM) (const_int 0))
+ (plus:SI (match_operand:SI 1 "register_operand" "%0,r")
+ (match_operand:SI 2 "register_operand" "r,r"))))
+ (set (reg:CC CSKY_CC_REGNUM)
+ (compare:CC
+ (plus:SI (match_dup 1) (match_dup 2))
+ (match_dup 1)))]
+ "CSKY_ISA_FEATURE (E2)"
+ "addc\t%0, %1, %2"
+ [(set_attr "length" "2,4")
+ (set_attr "type" "addsub")]
+)
+
+(define_insn "ck801_addc"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (ne:SI (reg:CC CSKY_CC_REGNUM) (const_int 0))
+ (plus:SI (match_operand:SI 1 "register_operand" "%0")
+ (match_operand:SI 2 "register_operand" "r"))))
+ (set (reg:CC CSKY_CC_REGNUM)
+ (compare:CC
+ (plus:SI (match_dup 1) (match_dup 2))
+ (match_dup 1)))]
+ "CSKY_ISA_FEATURE (E1)"
+ "addc\t%0, %1, %2"
+ [(set_attr "length" "2")
+ (set_attr "type" "addsub")]
+)
+
+;; Subtract with borrow.
+;; Note that in these insns, the sense of C bit is reversed; they subtract 1
+;; if the C bit is not set, and on output the bit is set to 0 for borrow
+;; and 1 for no borrow.
+
+(define_insn "cskyv2_subc"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (minus:SI (match_operand:SI 1 "register_operand" "0, r")
+ (plus:SI (match_operand:SI 2 "register_operand" "r, r")
+ (eq:SI (reg:CC CSKY_CC_REGNUM) (const_int 0)))))
+ (set (reg:CC CSKY_CC_REGNUM)
+ (not (compare:CC (match_dup 1) (match_dup 2))))]
+ "CSKY_ISA_FEATURE (E2)"
+ "subc\t%0, %1, %2"
+ [(set_attr "length" "2,4")
+ (set_attr "type" "addsub")]
+)
+
+(define_insn "ck801_subc"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (match_operand:SI 1 "register_operand" "0")
+ (plus:SI (match_operand:SI 2 "register_operand" "r")
+ (eq:SI (reg:CC CSKY_CC_REGNUM) (const_int 0)))))
+ (set (reg:CC CSKY_CC_REGNUM)
+ (not (compare:CC (match_dup 1) (match_dup 2))))]
+ "CSKY_ISA_FEATURE (E1)"
+ "subc\t%0, %1, %2"
+ [(set_attr "length" "2")
+ (set_attr "type" "addsub")]
+)
+
+;; ------------------------------------------------------------------------
+;; Multiplication insns
+;; ------------------------------------------------------------------------
+
+(define_expand "mulsi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (mult:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))]
+ ""
+ ""
+)
+
+(define_insn "*cskyv2_mulsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (mult:SI (match_operand:SI 1 "register_operand" "%r")
+ (match_operand:SI 2 "register_operand" "r")))]
+ "CSKY_ISA_FEATURE (E2)"
+ "mult\t%0, %1, %2"
+)
+
+(define_insn "*ck801_mulsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (mult:SI (match_operand:SI 1 "register_operand" "%0")
+ (match_operand:SI 2 "register_operand" "r")))]
+ "CSKY_ISA_FEATURE (E1)"
+ "mult\t%0, %1, %2"
+)
+
+(define_insn "mulhisi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%r"))
+ (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
+ "CSKY_ISA_FEATURE (2E3)"
+ "mulsh\t%0, %1, %2"
+)
+
+
+;; ------------------------------------------------------------------------
+;; Conditional add insns
+;; ------------------------------------------------------------------------
+
+(define_expand "addsicc"
+ [(match_operand:SI 0 "register_operand" "")
+ (match_operand 1 "ordered_comparison_operator" "")
+ (match_operand:SI 2 "register_operand" "")
+ (match_operand:SI 3 "csky_literal_K_Uh_operand" "")]
+ "CSKY_ISA_FEATURE (E2)"
+ "
+ {
+ bool invert = csky_emit_compare (GET_CODE (operands[1]),
+ XEXP (operands[1], 0),
+ XEXP (operands[1], 1));
+ if (invert)
+ emit_insn (gen_cskyv2_addcc_invert (operands[0], operands[2],
+ operands[3]));
+ else
+ emit_insn (gen_cskyv2_addcc (operands[0], operands[2], operands[3]));
+
+ DONE;
+ }"
+)
+
+(define_insn_and_split "cskyv2_addcc"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,&r,&r")
+ (if_then_else:SI
+ (ne (reg:CC CSKY_CC_REGNUM) (const_int 0))
+ (plus:SI (match_operand:SI 1 "register_operand" "0,0,r,r")
+ (match_operand:SI 2 "csky_literal_K_Uh_operand" "K,Uh,K,Uh"))
+ (match_dup 1)))]
+ "CSKY_ISA_FEATURE (E2)"
+ "@
+ inct\t%0, %1, %2
+ dect\t%0, %1, %M2
+ #
+ #"
+ "reload_completed && !rtx_equal_p (operands[0], operands[1])"
+ [(set (match_dup 0)
+ (if_then_else:SI (ne (reg:CC CSKY_CC_REGNUM) (const_int 0))
+ (plus:SI (match_dup 0) (match_dup 2))))]
+ {
+ emit_insn (gen_movf (copy_rtx (operands[0]),
+ copy_rtx (operands[1]),
+ copy_rtx (operands[0])));
+ }
+ [(set_attr "length" "4,4,8,8")
+ (set_attr "type" "addsub")]
+)
+
+(define_insn_and_split "cskyv2_addcc_invert"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+ (if_then_else:SI
+ (eq (reg:CC CSKY_CC_REGNUM) (const_int 0))
+ (plus:SI (match_operand:SI 1 "register_operand" "0,0,r,r")
+ (match_operand:SI 2 "csky_literal_K_Uh_operand" "K,Uh,K,Uh"))
+ (match_dup 1)))]
+ "CSKY_ISA_FEATURE (E2)"
+ "@
+ incf\t%0, %1, %2
+ decf\t%0, %1, %M2
+ #
+ #"
+ "reload_completed && !rtx_equal_p (operands[0], operands[1])"
+ [(set (match_dup 0)
+ (if_then_else:SI (eq (reg:CC CSKY_CC_REGNUM) (const_int 0))
+ (plus:SI (match_dup 0) (match_dup 2))))]
+ {
+ emit_insn (gen_movt (copy_rtx (operands[0]),
+ copy_rtx (operands[1]),
+ copy_rtx (operands[0])));
+ }
+ [(set_attr "length" "4,4,8,8")
+ (set_attr "type" "addsub")]
+)
+
+
+;; ------------------------------------------------------------------------
+;; Extzv insns
+;; ------------------------------------------------------------------------
+
+(define_expand "extzvsi"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (zero_extract:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")
+ (match_operand:SI 3 "const_int_operand" "")))]
+ ""
+ "{
+ /* ck802 has xtrb but not zext, so we'll use xtrb if we can. */
+ if (CSKY_ISA_FEATURE (E2) && !CSKY_ISA_FEATURE (2E3)
+ && (INTVAL (operands[2]) == 8)
+ && (INTVAL (operands[3]) % 8 == 0))
+ {
+ rtx xtrb = gen_rtx_SET (operands[0],
+ gen_rtx_ZERO_EXTRACT (SImode,
+ operands[1],
+ operands[2],
+ operands[3]));
+ emit (gen_rtx_PARALLEL (VOIDmode,
+ gen_rtvec (2, xtrb,
+ gen_hard_reg_clobber (CCmode, 33))));
+ DONE;
+ }
+ else if (!CSKY_ISA_FEATURE (2E3))
+ {
+ /* Use lsri and lsli to do extzv on targets without zext. */
+ rtx lshft = GEN_INT (32 - (INTVAL (operands[2])
+ + INTVAL (operands[3])));
+ rtx rshft = GEN_INT (32 - INTVAL (operands[2]));
+ rtx tmp1 = gen_reg_rtx (SImode);
+ rtx tmp2 = gen_reg_rtx (SImode);
+
+ emit_insn (gen_rtx_SET (tmp1, operands[1]));
+ emit_insn (gen_rtx_SET (tmp2, gen_rtx_ASHIFT (SImode, tmp1, lshft)));
+ emit_insn (gen_rtx_SET (operands[0],
+ gen_rtx_LSHIFTRT (SImode, tmp2, rshft)));
+ DONE;
+ }
+ else
+ {
+ emit_insn (gen_cskyv2_extzv (operands[0], operands[1],
+ operands[2], operands[3]));
+ DONE;
+ }
+}")
+
+(define_insn "cskyv2_extzv"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extract:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "csky_literal_K_operand" "K")
+ (match_operand:SI 3 "csky_literal_K_operand" "K")))]
+ "CSKY_ISA_FEATURE (2E3)"
+ {
+ operands[2] = GEN_INT (INTVAL (operands[3]) + INTVAL (operands[2]) - 1);
+ return \"zext\t%0, %1, %2, %3\";
+ }
+)
+
+(define_insn "*cskyv2_xtrb0"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (zero_extract:SI (match_operand:SI 1 "register_operand" "0,r")
+ (const_int 8)
+ (const_int 24)))
+ (clobber (reg:CC CSKY_CC_REGNUM))]
+ "CSKY_ISA_FEATURE (E2)"
+ "@
+ lsri\t%0, %0, 24
+ xtrb0\t%0, %1"
+)
+
+(define_insn "*cskyv2_xtrb1"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extract:SI (match_operand:SI 1 "register_operand" "r")
+ (const_int 8)
+ (const_int 16)))
+ (clobber (reg:CC CSKY_CC_REGNUM))]
+ "CSKY_ISA_FEATURE (E2)"
+ "xtrb1\t%0, %1"
+)
+
+(define_insn "*cskyv2_xtrb2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extract:SI (match_operand:SI 1 "register_operand" "r")
+ (const_int 8)
+ (const_int 8)))
+ (clobber (reg:CC CSKY_CC_REGNUM))]
+ "CSKY_ISA_FEATURE (E2)"
+ "xtrb2\t%0, %1"
+)
+
+
+;; -------------------------------------------------------------------------
+;; Zero extension instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "zero_extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extend:SI (match_operand:HI 1 "register_operand" "r")))]
+ ""
+ "zexth\t%0, %1"
+)
+
+(define_insn "*cskyv2_zextend_ldh"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extend:SI (match_operand:HI 1 "csky_simple_mem_operand" "m")))]
+ ""
+ "ld.h\t%0, %1"
+ [(set_attr "length" "4")
+ (set_attr "type" "load")]
+)
+
+(define_insn "zero_extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extend:SI (match_operand:QI 1 "register_operand" "r")))]
+ ""
+ "zextb\t%0, %1"
+)
+
+(define_insn "*cskyv2_zextend_ldb"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extend:SI (match_operand:QI 1 "csky_simple_mem_operand" "m")))]
+ ""
+ "ld.b\t%0, %1"
+ [(set_attr "length" "4")
+ (set_attr "type" "load")]
+)
+
+(define_insn "zero_extendqihi2"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (zero_extend:HI (match_operand:QI 1 "register_operand" "r")))]
+ ""
+ "zextb\t%0, %1"
+)
+
+(define_insn "*cskyv2_zextend_ldbhi"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (zero_extend:HI (match_operand:QI 1 "csky_simple_mem_operand" "m")))]
+ ""
+ "ld.b\t%0, %1"
+ [(set_attr "length" "4")
+ (set_attr "type" "load")]
+)
+
+;; -------------------------------------------------------------------------
+;; clzm2 instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "clzsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (clz:SI (match_operand:SI 1 "register_operand" "r")))]
+ "CSKY_ISA_FEATURE (E2)"
+ "ff1 %0,%1"
+)
+
+;; -------------------------------------------------------------------------
+;; one_cmplm2 instructions
+;; -------------------------------------------------------------------------
+
+(define_expand "one_cmplsi2"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (not:SI (match_operand:SI 1 "register_operand" "")))]
+ ""
+ ""
+)
+
+(define_insn "cskyv2_one_cmplsi2"
+ [(set (match_operand:SI 0 "register_operand" "=b,r")
+ (not:SI (match_operand:SI 1 "register_operand" "0,r")))]
+ "CSKY_ISA_FEATURE (E2)"
+ "not %0, %1"
+ [(set_attr "length" "2,4")
+ (set_attr "type" "alu,alu")]
+)
+
+(define_insn "ck801_one_cmplsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (not:SI (match_operand:SI 1 "register_operand" "0")))]
+ "CSKY_ISA_FEATURE (E1)"
+ "not %0, %1"
+ [(set_attr "length" "2")
+ (set_attr "type" "alu")]
+)
+
+;; -------------------------------------------------------------------------
+;; Sign extension instructions
+;; -------------------------------------------------------------------------
+
+;; One test shows that the following code helps to
+;; reduce one 'load' and two 'mov'.
+(define_expand "extendsidi2"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (match_operand:SI 1 "register_operand" "r"))]
+ ""
+ "{
+ int low, high;
+
+ if (TARGET_BIG_ENDIAN)
+ low = 4, high = 0;
+ else
+ low = 0, high = 4;
+
+ emit_insn (gen_rtx_SET (gen_rtx_SUBREG (SImode, operands[0], low),
+ operands[1]));
+
+ emit_insn (gen_rtx_SET (gen_rtx_SUBREG (SImode, operands[0], high),
+ gen_rtx_ASHIFTRT (SImode,
+ gen_rtx_SUBREG (SImode,
+ operands[0],
+ low),
+ GEN_INT (31))));
+ DONE;
+ }"
+)
+
+(define_insn "extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (match_operand:HI 1 "register_operand" "r")))]
+ ""
+ "sexth %0, %1"
+)
+
+(define_insn "*cskyv2_sextend_ldhs"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (match_operand:HI 1 "csky_simple_mem_operand" "m")))]
+ "CSKY_ISA_FEATURE (E2)"
+ "ld.hs\t%0, %1"
+ [(set_attr "length" "4")
+ (set_attr "type" "load")]
+)
+
+;; qi -> si
+(define_insn "extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (match_operand:QI 1 "register_operand" "r")))]
+ ""
+ "sextb %0, %1"
+)
+
+;; qi -> hi
+(define_insn "extendqihi2"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (sign_extend:HI (match_operand:QI 1 "register_operand" "r")))]
+ ""
+ "sextb %0, %1"
+)
+
+;; -------------------------------------------------------------------------
+;; And instructions
+;; -------------------------------------------------------------------------
+
+(define_expand "andsi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (and:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "csky_arith_any_imm_operand" "")))]
+ ""
+ "")
+
+(define_insn_and_split "cskyv2_andsi3"
+ [(set (match_operand:SI 0 "register_operand" "=b,r,r,&r")
+ (and:SI (match_operand:SI 1 "register_operand" "%0,r,r,r")
+ (match_operand:SI 2 "csky_arith_any_imm_operand" "b,r,O,i")))]
+ "CSKY_ISA_FEATURE (E2)"
+ "@
+ and\t%0, %1, %2
+ and\t%0, %1, %2
+ andi\t%0, %1, %2
+ #"
+ "(CONST_INT_P (operands[2])
+ && (operands[2] == const0_rtx
+ || !csky_arith_O_operand (operands[2], SImode)))"
+ [(set (match_dup 0) (and:SI (match_dup 1) (match_dup 2)))]
+ {
+ if (csky_split_and (operands))
+ DONE;
+ }
+ [(set_attr "length" "2,4,4,8")
+ (set_attr "type" "alu,alu,alu,alu")]
+)
+
+(define_insn_and_split "ck801_andsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,&r")
+ (and:SI (match_operand:SI 1 "register_operand" "%0,r")
+ (match_operand:SI 2 "csky_arith_any_imm_operand" "r,i")))]
+ "CSKY_ISA_FEATURE (E1)"
+ "@
+ and\t%0, %1, %2
+ #"
+ "CONST_INT_P (operands[2])"
+ [(set (match_dup 0) (and:SI (match_dup 1) (match_dup 2)))]
+ {
+ if (csky_split_and (operands))
+ DONE;
+ }
+ [(set_attr "length" "2,4")
+ (set_attr "type" "alu,alu")]
+)
+
+;; Note that the operands for the andnsi3 patterns are reversed compared
+;; to the actual machine insn: operand 1 is the inverted operand.
+
+(define_insn "cskyv2_andnsi3"
+ [(use (and:SI (not:SI (match_operand:SI 1 "csky_arith_O_operand" "b,r,O"))
+ (match_operand:SI 2 "register_operand" "0,r,r")))
+ (set (match_operand:SI 0 "register_operand" "=b,r,r")
+ (and:SI (not:SI (match_dup 1))
+ (match_dup 2)))]
+ "CSKY_ISA_FEATURE (E2)"
+ "@
+ andn\t%0, %2, %1
+ andn\t%0, %2, %1
+ andni\t%0, %2, %1"
+ [(set_attr "length" "2,4,4")
+ (set_attr "type" "alu,alu,alu")]
+)
+
+(define_insn "ck801_andnsi3"
+ [(use (and:SI (not:SI (match_operand:SI 1 "register_operand" "r"))
+ (match_operand:SI 2 "register_operand" "0")))
+ (set (match_operand:SI 0 "register_operand" "=r")
+ (and:SI (not:SI (match_dup 1))
+ (match_dup 2)))]
+ "CSKY_ISA_FEATURE (E1)"
+ "andn\t%0, %2, %1"
+)
+
+(define_expand "anddi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (and:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "csky_arith_any_imm_operand" "")))]
+ ""
+ "
+ {
+ if (CONST_INT_P (operands[2]))
+ {
+ HOST_WIDE_INT ival = INTVAL (operands[2]);
+ if (ival == (HOST_WIDE_INT) 0xffffffff)
+ {
+ emit_move_insn (gen_lowpart (SImode, operands[0]),
+ gen_lowpart (SImode, operands[1]));
+ emit_move_insn (gen_highpart (SImode, operands[0]), const0_rtx);
+ DONE;
+ }
+ else if (ival == (HOST_WIDE_INT) ((unsigned HOST_WIDE_INT) -1 << 32))
+ {
+ emit_move_insn (gen_lowpart (SImode, operands[0]), const0_rtx);
+ emit_move_insn (gen_highpart (SImode, operands[0]),
+ gen_highpart (SImode, operands[1]));
+ DONE;
+ }
+ else
+ FAIL;
+ }
+ }")
+
+
+
+(define_insn_and_split "*cskyv2_anddi3"
+ [(set (match_operand:DI 0 "register_operand" "=&b,&r")
+ (and:DI (match_operand:DI 1 "register_operand" "%0,r")
+ (match_operand:DI 2 "register_operand" "b,r")))]
+ "CSKY_ISA_FEATURE (E2)"
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+ {
+ int hi = TARGET_BIG_ENDIAN ? 0 : UNITS_PER_WORD;
+ int lo = TARGET_BIG_ENDIAN ? UNITS_PER_WORD : 0;
+ rtx l0 = simplify_gen_subreg (SImode, operands[0], DImode, lo);
+ rtx h0 = simplify_gen_subreg (SImode, operands[0], DImode, hi);
+ rtx l1 = simplify_gen_subreg (SImode, operands[1], DImode, lo);
+ rtx h1 = simplify_gen_subreg (SImode, operands[1], DImode, hi);
+ rtx l2 = simplify_gen_subreg (SImode, operands[2], DImode, lo);
+ rtx h2 = simplify_gen_subreg (SImode, operands[2], DImode, hi);
+
+ emit_insn (gen_cskyv2_andsi3 (l0, l1, l2));
+ emit_insn (gen_cskyv2_andsi3 (h0, h1, h2));
+ DONE;
+ }
+ [(set_attr "length" "4,8")]
+)
+
+(define_insn_and_split "*ck801_anddi3"
+ [(set (match_operand:DI 0 "register_operand" "=&r")
+ (and:DI (match_operand:DI 1 "register_operand" "%0")
+ (match_operand:DI 2 "register_operand" "r")))]
+ "CSKY_ISA_FEATURE (E1)"
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+ {
+ int hi = TARGET_BIG_ENDIAN ? 0 : UNITS_PER_WORD;
+ int lo = TARGET_BIG_ENDIAN ? UNITS_PER_WORD : 0;
+ rtx l0 = simplify_gen_subreg (SImode, operands[0], DImode, lo);
+ rtx h0 = simplify_gen_subreg (SImode, operands[0], DImode, hi);
+ rtx l1 = simplify_gen_subreg (SImode, operands[1], DImode, lo);
+ rtx h1 = simplify_gen_subreg (SImode, operands[1], DImode, hi);
+ rtx l2 = simplify_gen_subreg (SImode, operands[2], DImode, lo);
+ rtx h2 = simplify_gen_subreg (SImode, operands[2], DImode, hi);
+
+ emit_insn (gen_ck801_andsi3 (l0, l1, l2));
+ emit_insn (gen_ck801_andsi3 (h0, h1, h2));
+ DONE;
+ }
+ [(set_attr "length" "4")]
+)
+
+
+;; -------------------------------------------------------------------------
+;; Ior instructions
+;; -------------------------------------------------------------------------
+
+(define_expand "iorsi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (ior:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "csky_arith_any_imm_operand" "")))]
+ ""
+ "")
+
+(define_insn_and_split "cskyv2_iorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=b,r,r,&r")
+ (ior:SI (match_operand:SI 1 "register_operand" "%0,r,r,r")
+ (match_operand:SI 2 "csky_arith_any_imm_operand" "b, r,I,i")))]
+ "CSKY_ISA_FEATURE (E2)"
+ "@
+ or\t%0, %1, %2
+ or\t%0, %1, %2
+ ori\t%0, %1, %2
+ #"
+ "(CONST_INT_P (operands[2])
+ && (operands[2] == const0_rtx
+ || !csky_literal_I_operand (operands[2], SImode)))"
+ [(set (match_dup 0) (ior:SI (match_dup 1) (match_dup 2)))]
+ {
+ if (csky_split_ior (operands))
+ DONE;
+ }
+ [(set_attr "length" "2,4,4,8")
+ (set_attr "type" "alu,alu,alu,alu")]
+)
+
+(define_insn_and_split "ck801_iorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,&r")
+ (ior:SI (match_operand:SI 1 "register_operand" "%0,r")
+ (match_operand:SI 2 "csky_arith_any_imm_operand" "r,i")))]
+ "CSKY_ISA_FEATURE (E1)"
+ "@
+ or\t%0, %1, %2
+ #"
+ "CONST_INT_P (operands[2])"
+ [(set (match_dup 0) (ior:SI (match_dup 1) (match_dup 2)))]
+ {
+ if (csky_split_ior (operands))
+ DONE;
+ }
+ [(set_attr "length" "2,4")
+ (set_attr "type" "alu,alu")]
+)
+
+(define_expand "iordi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (ior:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "register_operand" "")))]
+ ""
+ ""
+)
+
+(define_insn_and_split "*cskyv2_iordi3"
+ [(set (match_operand:DI 0 "register_operand" "=&b,&r")
+ (ior:DI (match_operand:DI 1 "register_operand" "%0, r")
+ (match_operand:DI 2 "register_operand" "b, r")))]
+ "CSKY_ISA_FEATURE (E2)"
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+ {
+ int hi = TARGET_BIG_ENDIAN ? 0 : UNITS_PER_WORD;
+ int lo = TARGET_BIG_ENDIAN ? UNITS_PER_WORD : 0;
+ rtx l0 = simplify_gen_subreg (SImode, operands[0], DImode, lo);
+ rtx h0 = simplify_gen_subreg (SImode, operands[0], DImode, hi);
+ rtx l1 = simplify_gen_subreg (SImode, operands[1], DImode, lo);
+ rtx h1 = simplify_gen_subreg (SImode, operands[1], DImode, hi);
+ rtx l2 = simplify_gen_subreg (SImode, operands[2], DImode, lo);
+ rtx h2 = simplify_gen_subreg (SImode, operands[2], DImode, hi);
+
+ emit_insn (gen_cskyv2_iorsi3 (l0, l1, l2));
+ emit_insn (gen_cskyv2_iorsi3 (h0, h1, h2));
+ DONE;
+ }
+ [(set_attr "length" "4,8")]
+)
+
+(define_insn_and_split "*ck801_iordi3"
+ [(set (match_operand:DI 0 "register_operand" "=&r")
+ (ior:DI (match_operand:DI 1 "register_operand" "%0")
+ (match_operand:DI 2 "register_operand" "r")))]
+ "CSKY_ISA_FEATURE (E1)"
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+ {
+ int hi = TARGET_BIG_ENDIAN ? 0 : UNITS_PER_WORD;
+ int lo = TARGET_BIG_ENDIAN ? UNITS_PER_WORD : 0;
+ rtx l0 = simplify_gen_subreg (SImode, operands[0], DImode, lo);
+ rtx h0 = simplify_gen_subreg (SImode, operands[0], DImode, hi);
+ rtx l1 = simplify_gen_subreg (SImode, operands[1], DImode, lo);
+ rtx h1 = simplify_gen_subreg (SImode, operands[1], DImode, hi);
+ rtx l2 = simplify_gen_subreg (SImode, operands[2], DImode, lo);
+ rtx h2 = simplify_gen_subreg (SImode, operands[2], DImode, hi);
+
+ emit_insn (gen_ck801_iorsi3 (l0, l1, l2));
+ emit_insn (gen_ck801_iorsi3 (h0, h1, h2));
+ DONE;
+ }
+ [(set_attr "length" "4")]
+)
+
+
+;; -------------------------------------------------------------------------
+;; Xor instructions
+;; -------------------------------------------------------------------------
+
+(define_expand "xorsi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (xor:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "csky_arith_any_imm_operand" "")))]
+ ""
+ "")
+
+(define_insn_and_split "cskyv2_xorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=b,r,r,&r")
+ (xor:SI (match_operand:SI 1 "register_operand" "%0,r,r,r")
+ (match_operand:SI 2 "csky_arith_any_imm_operand" "b, r,O,i")))]
+ "CSKY_ISA_FEATURE (E2)"
+ "@
+ xor\t%0, %1, %2
+ xor\t%0, %1, %2
+ xori\t%0, %1, %2
+ #"
+ "(CONST_INT_P (operands[2])
+ && (operands[2] == const0_rtx
+ || !csky_arith_O_operand (operands[2], SImode)))"
+ [(set (match_dup 0) (xor:SI (match_dup 1) (match_dup 2)))]
+ {
+ if (csky_split_xor (operands))
+ DONE;
+ }
+ [(set_attr "length" "2,4,4,8")
+ (set_attr "type" "alu,alu,alu,alu")]
+)
+
+(define_insn_and_split "ck801_xorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,&r")
+ (xor:SI (match_operand:SI 1 "register_operand" "%0,r")
+ (match_operand:SI 2 "csky_arith_any_imm_operand" "r,i")))]
+ "CSKY_ISA_FEATURE (E1)"
+ "@
+ xor\t%0, %1, %2
+ #"
+ "CONST_INT_P (operands[2])"
+ [(set (match_dup 0) (xor:SI (match_dup 1) (match_dup 2)))]
+ {
+ if (csky_split_xor (operands))
+ DONE;
+ }
+ [(set_attr "length" "2,4")
+ (set_attr "type" "alu,alu")]
+)
+
+(define_expand "xordi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (xor:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "register_operand" "")))]
+ ""
+ ""
+)
+
+(define_insn_and_split "*cskyv2_xordi3"
+ [(set (match_operand:DI 0 "register_operand" "=&b,&r")
+ (xor:DI (match_operand:DI 1 "register_operand" "%0, r")
+ (match_operand:DI 2 "register_operand" "b, r")))]
+ "CSKY_ISA_FEATURE (E2)"
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+ {
+ int hi = TARGET_BIG_ENDIAN ? 0 : UNITS_PER_WORD;
+ int lo = TARGET_BIG_ENDIAN ? UNITS_PER_WORD : 0;
+ rtx l0 = simplify_gen_subreg (SImode, operands[0], DImode, lo);
+ rtx h0 = simplify_gen_subreg (SImode, operands[0], DImode, hi);
+ rtx l1 = simplify_gen_subreg (SImode, operands[1], DImode, lo);
+ rtx h1 = simplify_gen_subreg (SImode, operands[1], DImode, hi);
+ rtx l2 = simplify_gen_subreg (SImode, operands[2], DImode, lo);
+ rtx h2 = simplify_gen_subreg (SImode, operands[2], DImode, hi);
+
+ emit_insn (gen_cskyv2_xorsi3 (l0, l1, l2));
+ emit_insn (gen_cskyv2_xorsi3 (h0, h1, h2));
+ DONE;
+ }
+ [(set_attr "length" "4,8")]
+)
+
+(define_insn_and_split "*ck801_xordi3"
+ [(set (match_operand:DI 0 "register_operand" "=&r")
+ (xor:DI (match_operand:DI 1 "register_operand" "%0")
+ (match_operand:DI 2 "register_operand" "r")))]
+ "CSKY_ISA_FEATURE (E1)"
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+ {
+ int hi = TARGET_BIG_ENDIAN ? 0 : UNITS_PER_WORD;
+ int lo = TARGET_BIG_ENDIAN ? UNITS_PER_WORD : 0;
+ rtx l0 = simplify_gen_subreg (SImode, operands[0], DImode, lo);
+ rtx h0 = simplify_gen_subreg (SImode, operands[0], DImode, hi);
+ rtx l1 = simplify_gen_subreg (SImode, operands[1], DImode, lo);
+ rtx h1 = simplify_gen_subreg (SImode, operands[1], DImode, hi);
+ rtx l2 = simplify_gen_subreg (SImode, operands[2], DImode, lo);
+ rtx h2 = simplify_gen_subreg (SImode, operands[2], DImode, hi);
+
+ emit_insn (gen_ck801_xorsi3 (l0, l1, l2));
+ emit_insn (gen_ck801_xorsi3 (h0, h1, h2));
+ DONE;
+ }
+ [(set_attr "length" "4")]
+)
+
+;; -------------------------------------------------------------------------
+;; Div instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "divsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (div:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "register_operand" "r")))]
+ "TARGET_DIV"
+ "divs\t%0, %1, %2"
+)
+
+(define_insn "udivsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (udiv:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "register_operand" "r")))]
+ "TARGET_DIV"
+ "divu\t%0, %1, %2"
+)
+
+
+;; -----------------------------------------------------------------
+;; Multiple load and store insns
+;; -----------------------------------------------------------------
+
+(define_expand "load_multiple"
+ [(match_par_dup 3 [(set (match_operand:SI 0 "" "")
+ (match_operand:SI 1 "" ""))
+ (use (match_operand:SI 2 "" ""))])]
+ "TARGET_MULTIPLE_STLD"
+ "{
+ int regno, count, i;
+ rtx base,src;
+
+ if (GET_CODE (operands[2]) != CONST_INT
+ || INTVAL (operands[2]) < 2
+ || INTVAL (operands[2]) > CSKY_MAX_MULTIPLE_STLD
+ || GET_CODE (operands[1]) != MEM
+ || !REG_P (XEXP (operands[1], 0))
+ || XEXP (operands[1], 0) != stack_pointer_rtx
+ || GET_CODE (operands[0]) != REG
+ || (REGNO (XEXP (operands[1], 0)) > REGNO (operands[0])
+ && (REGNO (XEXP (operands[1], 0))
+ < REGNO (operands[0]) + INTVAL (operands[2]))))
+ FAIL;
+
+ count = INTVAL (operands[2]);
+ regno = REGNO (operands[0]);
+
+ operands[3] = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
+
+ base = force_reg (SImode, XEXP (operands[1], 0));
+ src = replace_equiv_address (operands[1], base);
+
+ for (i = 0; i < count; i++)
+ XVECEXP (operands[3], 0, i)
+ = gen_rtx_SET (gen_rtx_REG (SImode, regno + i),
+ adjust_address_nv (src, SImode, i * 4));
+ }"
+)
+
+(define_expand "store_multiple"
+ [(match_par_dup 3 [(set (match_operand:SI 0 "")
+ (match_operand:SI 1 ""))
+ (use (match_operand:SI 2 ""))])]
+ "TARGET_MULTIPLE_STLD"
+ "{
+ int regno, count, i;
+ rtx base, dest;
+
+ /* Support only storing a constant number of registers to memory and
+ only if at least two registers. */
+ if (GET_CODE (operands[2]) != CONST_INT
+ || INTVAL (operands[2]) < 2
+ || INTVAL (operands[2]) > CSKY_MAX_MULTIPLE_STLD
+ || GET_CODE (operands[0]) != MEM
+ || !REG_P (XEXP (operands[0], 0))
+ || XEXP (operands[0], 0) != stack_pointer_rtx
+ || GET_CODE (operands[1]) != REG
+ || (REGNO (XEXP (operands[0], 0)) >= REGNO (operands[1])
+ && (REGNO (XEXP (operands[0], 0))
+ < REGNO (operands[1]) + INTVAL (operands[2]))))
+ FAIL;
+
+ count = INTVAL (operands[2]);
+ regno = REGNO (operands[1]);
+
+ operands[3] = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
+
+ base = force_reg (SImode, XEXP (operands[0], 0));
+ dest = replace_equiv_address (operands[0], base);
+
+ for (i = 0; i < count; i++)
+ XVECEXP (operands[3], 0, i)
+ = gen_rtx_SET (adjust_address_nv (dest, SImode, i * 4),
+ gen_rtx_REG (SImode, regno + i));
+ }"
+)
+
+
+(define_insn "*csky_ldmsi12"
+ [(match_parallel 0 "csky_load_multiple_operation"
+ [(set (match_operand:SI 1 "register_operand" "=r")
+ (mem:SI (match_operand:SI 2 "register_operand" "r")))
+ (set (match_operand:SI 3 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+ (set (match_operand:SI 4 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 8))))
+ (set (match_operand:SI 5 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 12))))
+ (set (match_operand:SI 6 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 16))))
+ (set (match_operand:SI 7 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 20))))
+ (set (match_operand:SI 8 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 24))))
+ (set (match_operand:SI 9 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 28))))
+ (set (match_operand:SI 10 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 32))))
+ (set (match_operand:SI 11 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 36))))
+ (set (match_operand:SI 12 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 40))))
+ (set (match_operand:SI 13 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 44))))
+ ])]
+ "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 12"
+ {
+ static char load_op[256] = {0};
+ int count = REGNO (operands[1]) + XVECLEN (operands[0], 0) - 1;
+ const char *reg_rz = reg_names[count];
+ sprintf (load_op, \"ldm\t%%1 - %s, (%%2)\", reg_rz);
+ return load_op;
+ }
+)
+
+(define_insn "*csky_ldmsi11"
+ [(match_parallel 0 "csky_load_multiple_operation"
+ [(set (match_operand:SI 1 "register_operand" "=r")
+ (mem:SI (match_operand:SI 2 "register_operand" "r")))
+ (set (match_operand:SI 3 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+ (set (match_operand:SI 4 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 8))))
+ (set (match_operand:SI 5 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 12))))
+ (set (match_operand:SI 6 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 16))))
+ (set (match_operand:SI 7 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 20))))
+ (set (match_operand:SI 8 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 24))))
+ (set (match_operand:SI 9 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 28))))
+ (set (match_operand:SI 10 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 32))))
+ (set (match_operand:SI 11 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 36))))
+ (set (match_operand:SI 12 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 40))))
+ ])]
+ "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 11"
+ {
+ static char load_op[256] = {0};
+ int count = REGNO (operands[1]) + XVECLEN (operands[0], 0) - 1;
+ const char *reg_rz = reg_names[count];
+ sprintf (load_op, \"ldm\t%%1 - %s, (%%2)\", reg_rz);
+ return load_op;
+ }
+)
+
+(define_insn "*csky_ldmsi10"
+ [(match_parallel 0 "csky_load_multiple_operation"
+ [(set (match_operand:SI 1 "register_operand" "=r")
+ (mem:SI (match_operand:SI 2 "register_operand" "r")))
+ (set (match_operand:SI 3 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+ (set (match_operand:SI 4 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 8))))
+ (set (match_operand:SI 5 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 12))))
+ (set (match_operand:SI 6 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 16))))
+ (set (match_operand:SI 7 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 20))))
+ (set (match_operand:SI 8 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 24))))
+ (set (match_operand:SI 9 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 28))))
+ (set (match_operand:SI 10 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 32))))
+ (set (match_operand:SI 11 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 36))))
+ ])]
+ "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 10"
+ {
+ static char load_op[256] = {0};
+ int count = REGNO (operands[1]) + XVECLEN (operands[0], 0) - 1;
+ const char *reg_rz = reg_names[count];
+ sprintf (load_op, \"ldm\t%%1 - %s, (%%2)\", reg_rz);
+ return load_op;
+ }
+)
+
+(define_insn "*csky_ldmsi9"
+ [(match_parallel 0 "csky_load_multiple_operation"
+ [(set (match_operand:SI 1 "register_operand" "=r")
+ (mem:SI (match_operand:SI 2 "register_operand" "r")))
+ (set (match_operand:SI 3 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+ (set (match_operand:SI 4 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 8))))
+ (set (match_operand:SI 5 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 12))))
+ (set (match_operand:SI 6 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 16))))
+ (set (match_operand:SI 7 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 20))))
+ (set (match_operand:SI 8 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 24))))
+ (set (match_operand:SI 9 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 28))))
+ (set (match_operand:SI 10 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 32))))
+ ])]
+ "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 9"
+ {
+ static char load_op[256] = {0};
+ int count = REGNO (operands[1]) + XVECLEN (operands[0], 0) - 1;
+ const char *reg_rz = reg_names[count];
+ sprintf (load_op, \"ldm\t%%1 - %s, (%%2)\", reg_rz);
+ return load_op;
+ }
+)
+
+(define_insn "*csky_ldmsi8"
+ [(match_parallel 0 "csky_load_multiple_operation"
+ [(set (match_operand:SI 1 "register_operand" "=r")
+ (mem:SI (match_operand:SI 2 "register_operand" "r")))
+ (set (match_operand:SI 3 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+ (set (match_operand:SI 4 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 8))))
+ (set (match_operand:SI 5 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 12))))
+ (set (match_operand:SI 6 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 16))))
+ (set (match_operand:SI 7 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 20))))
+ (set (match_operand:SI 8 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 24))))
+ (set (match_operand:SI 9 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 28))))
+ ])]
+ "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 8"
+ {
+ static char load_op[256] = {0};
+ int count = REGNO (operands[1]) + XVECLEN (operands[0], 0) - 1;
+ const char *reg_rz = reg_names[count];
+ sprintf (load_op, \"ldm\t%%1 - %s, (%%2)\", reg_rz);
+ return load_op;
+ }
+)
+
+(define_insn "*csky_ldmsi7"
+ [(match_parallel 0 "csky_load_multiple_operation"
+ [(set (match_operand:SI 1 "register_operand" "=r")
+ (mem:SI (match_operand:SI 2 "register_operand" "r")))
+ (set (match_operand:SI 3 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+ (set (match_operand:SI 4 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 8))))
+ (set (match_operand:SI 5 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 12))))
+ (set (match_operand:SI 6 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 16))))
+ (set (match_operand:SI 7 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 20))))
+ (set (match_operand:SI 8 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 24))))
+ ])]
+ "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 7"
+ {
+ static char load_op[256] = {0};
+ int count = REGNO (operands[1]) + XVECLEN (operands[0], 0) - 1;
+ const char *reg_rz = reg_names[count];
+ sprintf (load_op, \"ldm\t%%1 - %s, (%%2)\", reg_rz);
+ return load_op;
+ }
+)
+
+(define_insn "*csky_ldmsi6"
+ [(match_parallel 0 "csky_load_multiple_operation"
+ [(set (match_operand:SI 1 "register_operand" "=r")
+ (mem:SI (match_operand:SI 2 "register_operand" "r")))
+ (set (match_operand:SI 3 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+ (set (match_operand:SI 4 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 8))))
+ (set (match_operand:SI 5 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 12))))
+ (set (match_operand:SI 6 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 16))))
+ (set (match_operand:SI 7 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 20))))
+ ])]
+ "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 6"
+ {
+ static char load_op[256] = {0};
+ int count = REGNO (operands[1]) + XVECLEN (operands[0], 0) - 1;
+ const char *reg_rz = reg_names[count];
+ sprintf (load_op, \"ldm\t%%1 - %s, (%%2)\", reg_rz);
+ return load_op;
+ }
+)
+
+
+(define_insn "*csky_ldmsi5"
+ [(match_parallel 0 "csky_load_multiple_operation"
+ [(set (match_operand:SI 1 "register_operand" "=r")
+ (mem:SI (match_operand:SI 2 "register_operand" "r")))
+ (set (match_operand:SI 3 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+ (set (match_operand:SI 4 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 8))))
+ (set (match_operand:SI 5 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 12))))
+ (set (match_operand:SI 6 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 16))))
+ ])]
+ "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 5"
+ {
+ static char load_op[256] = {0};
+ int count = REGNO (operands[1]) + XVECLEN (operands[0], 0) - 1;
+ const char *reg_rz = reg_names[count];
+ sprintf (load_op, \"ldm\t%%1 - %s, (%%2)\", reg_rz);
+ return load_op;
+ }
+)
+
+
+(define_insn "*csky_ldmsi4"
+ [(match_parallel 0 "csky_load_multiple_operation"
+ [(set (match_operand:SI 1 "register_operand" "=r")
+ (mem:SI (match_operand:SI 2 "register_operand" "r")))
+ (set (match_operand:SI 3 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+ (set (match_operand:SI 4 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 8))))
+ (set (match_operand:SI 5 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 12))))
+ ])]
+ "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 4"
+ {
+ static char load_op[256] = {0};
+ int count = REGNO (operands[1]) + XVECLEN (operands[0], 0) - 1;
+ const char *reg_rz = reg_names[count];
+ sprintf (load_op, \"ldm\t%%1 - %s, (%%2)\", reg_rz);
+ return load_op;
+ }
+)
+
+
+(define_insn "*csky_ldmsi3"
+ [(match_parallel 0 "csky_load_multiple_operation"
+ [(set (match_operand:SI 1 "register_operand" "=r")
+ (mem:SI (match_operand:SI 2 "register_operand" "r")))
+ (set (match_operand:SI 3 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+ (set (match_operand:SI 4 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 8))))
+ ])]
+ "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 3"
+ {
+ static char load_op[256] = {0};
+ int count = REGNO (operands[1]) + XVECLEN (operands[0], 0) - 1;
+ const char *reg_rz = reg_names[count];
+ sprintf (load_op, \"ldm\t%%1 - %s, (%%2)\", reg_rz);
+ return load_op;
+ }
+)
+
+
+(define_insn "*csky_ldmsi2"
+ [(match_parallel 0 "csky_load_multiple_operation"
+ [(set (match_operand:SI 1 "register_operand" "=r")
+ (mem:SI (match_operand:SI 2 "register_operand" "r")))
+ (set (match_operand:SI 3 "register_operand" "=r")
+ (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+ ])]
+ "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 2"
+ {
+ static char load_op[256] = {0};
+ int count = REGNO (operands[1]) + XVECLEN (operands[0], 0) - 1;
+ const char *reg_rz = reg_names[count];
+ sprintf (load_op, \"ldm\t%%1 - %s, (%%2)\", reg_rz);
+ return load_op;
+ }
+)
+
+(define_insn "*csky_stmsi12"
+ [(match_parallel 0 "csky_store_multiple_operation"
+ [(set (mem:SI (match_operand:SI 1 "register_operand" "r"))
+ (match_operand:SI 2 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+ (match_operand:SI 3 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+ (match_operand:SI 4 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
+ (match_operand:SI 5 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 16)))
+ (match_operand:SI 6 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 20)))
+ (match_operand:SI 7 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 24)))
+ (match_operand:SI 8 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 28)))
+ (match_operand:SI 9 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 32)))
+ (match_operand:SI 10 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 36)))
+ (match_operand:SI 11 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 40)))
+ (match_operand:SI 12 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 44)))
+ (match_operand:SI 13 "register_operand" "r"))
+ ])]
+ "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 12"
+ {
+ static char load_op[256] = {0};
+ int end = REGNO (operands[2]) + XVECLEN (operands[0], 0) - 1;
+ const char *reg_rz = reg_names[end];
+ sprintf (load_op, \"stm\t%%2 - %s, (%%1)\", reg_rz);
+ return load_op;
+ }
+)
+
+
+(define_insn "*csky_stmsi11"
+ [(match_parallel 0 "csky_store_multiple_operation"
+ [(set (mem:SI (match_operand:SI 1 "register_operand" "r"))
+ (match_operand:SI 2 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+ (match_operand:SI 3 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+ (match_operand:SI 4 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
+ (match_operand:SI 5 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 16)))
+ (match_operand:SI 6 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 20)))
+ (match_operand:SI 7 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 24)))
+ (match_operand:SI 8 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 28)))
+ (match_operand:SI 9 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 32)))
+ (match_operand:SI 10 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 36)))
+ (match_operand:SI 11 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 40)))
+ (match_operand:SI 12 "register_operand" "r"))
+ ])]
+ "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 11"
+ {
+ static char load_op[256] = {0};
+ int end = REGNO (operands[2]) + XVECLEN (operands[0], 0) - 1;
+ const char *reg_rz = reg_names[end];
+ sprintf (load_op, \"stm\t%%2 - %s, (%%1)\", reg_rz);
+ return load_op;
+ }
+)
+
+
+(define_insn "*csky_stmsi10"
+ [(match_parallel 0 "csky_store_multiple_operation"
+ [(set (mem:SI (match_operand:SI 1 "register_operand" "r"))
+ (match_operand:SI 2 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+ (match_operand:SI 3 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+ (match_operand:SI 4 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
+ (match_operand:SI 5 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 16)))
+ (match_operand:SI 6 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 20)))
+ (match_operand:SI 7 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 24)))
+ (match_operand:SI 8 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 28)))
+ (match_operand:SI 9 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 32)))
+ (match_operand:SI 10 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 36)))
+ (match_operand:SI 11 "register_operand" "r"))
+ ])]
+ "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 10"
+ {
+ static char load_op[256] = {0};
+ int end = REGNO (operands[2]) + XVECLEN (operands[0], 0) - 1;
+ const char *reg_rz = reg_names[end];
+ sprintf (load_op, \"stm\t%%2 - %s, (%%1)\", reg_rz);
+ return load_op;
+ }
+)
+
+
+(define_insn "*csky_stmsi9"
+ [(match_parallel 0 "csky_store_multiple_operation"
+ [(set (mem:SI (match_operand:SI 1 "register_operand" "r"))
+ (match_operand:SI 2 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+ (match_operand:SI 3 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+ (match_operand:SI 4 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
+ (match_operand:SI 5 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 16)))
+ (match_operand:SI 6 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 20)))
+ (match_operand:SI 7 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 24)))
+ (match_operand:SI 8 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 28)))
+ (match_operand:SI 9 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 32)))
+ (match_operand:SI 10 "register_operand" "r"))
+ ])]
+ "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 9"
+ {
+ static char load_op[256] = {0};
+ int end = REGNO (operands[2]) + XVECLEN (operands[0], 0) - 1;
+ const char *reg_rz = reg_names[end];
+ sprintf (load_op, \"stm\t%%2 - %s, (%%1)\", reg_rz);
+ return load_op;
+ }
+)
+
+
+(define_insn "*csky_stmsi8"
+ [(match_parallel 0 "csky_store_multiple_operation"
+ [(set (mem:SI (match_operand:SI 1 "register_operand" "r"))
+ (match_operand:SI 2 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+ (match_operand:SI 3 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+ (match_operand:SI 4 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
+ (match_operand:SI 5 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 16)))
+ (match_operand:SI 6 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 20)))
+ (match_operand:SI 7 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 24)))
+ (match_operand:SI 8 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 28)))
+ (match_operand:SI 9 "register_operand" "r"))
+ ])]
+ "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 8"
+ {
+ static char load_op[256] = {0};
+ int end = REGNO (operands[2]) + XVECLEN (operands[0], 0) - 1;
+ const char *reg_rz = reg_names[end];
+ sprintf (load_op, \"stm\t%%2 - %s, (%%1)\", reg_rz);
+ return load_op;
+ }
+)
+
+
+(define_insn "*csky_stmsi7"
+ [(match_parallel 0 "csky_store_multiple_operation"
+ [(set (mem:SI (match_operand:SI 1 "register_operand" "r"))
+ (match_operand:SI 2 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+ (match_operand:SI 3 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+ (match_operand:SI 4 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
+ (match_operand:SI 5 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 16)))
+ (match_operand:SI 6 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 20)))
+ (match_operand:SI 7 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 24)))
+ (match_operand:SI 8 "register_operand" "r"))
+ ])]
+ "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 7"
+ {
+ static char load_op[256] = {0};
+ int end = REGNO (operands[2]) + XVECLEN (operands[0], 0) - 1;
+ const char *reg_rz = reg_names[end];
+ sprintf (load_op, \"stm\t%%2 - %s, (%%1)\", reg_rz);
+ return load_op;
+ }
+)
+
+
+(define_insn "*csky_stmsi6"
+ [(match_parallel 0 "csky_store_multiple_operation"
+ [(set (mem:SI (match_operand:SI 1 "register_operand" "r"))
+ (match_operand:SI 2 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+ (match_operand:SI 3 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+ (match_operand:SI 4 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
+ (match_operand:SI 5 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 16)))
+ (match_operand:SI 6 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 20)))
+ (match_operand:SI 7 "register_operand" "r"))
+ ])]
+ "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 6"
+ {
+ static char load_op[256] = {0};
+ int end = REGNO (operands[2]) + XVECLEN (operands[0], 0) - 1;
+ const char *reg_rz = reg_names[end];
+ sprintf (load_op, \"stm\t%%2 - %s, (%%1)\", reg_rz);
+ return load_op;
+ }
+)
+
+(define_insn "*csky_stmsi5"
+ [(match_parallel 0 "csky_store_multiple_operation"
+ [(set (mem:SI (match_operand:SI 1 "register_operand" "r"))
+ (match_operand:SI 2 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+ (match_operand:SI 3 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+ (match_operand:SI 4 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
+ (match_operand:SI 5 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 16)))
+ (match_operand:SI 6 "register_operand" "r"))
+ ])]
+ "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 5"
+ {
+ static char load_op[256] = {0};
+ int end = REGNO (operands[2]) + XVECLEN (operands[0], 0) - 1;
+ const char *reg_rz = reg_names[end];
+ sprintf (load_op, \"stm\t%%2 - %s, (%%1)\", reg_rz);
+ return load_op;
+ }
+)
+
+
+(define_insn "*csky_stmsi4"
+ [(match_parallel 0 "csky_store_multiple_operation"
+ [(set (mem:SI (match_operand:SI 1 "register_operand" "r"))
+ (match_operand:SI 2 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+ (match_operand:SI 3 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+ (match_operand:SI 4 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
+ (match_operand:SI 5 "register_operand" "r"))
+ ])]
+ "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 4"
+ {
+ static char load_op[256] = {0};
+ int end = REGNO (operands[2]) + XVECLEN (operands[0], 0) - 1;
+ const char *reg_rz = reg_names[end];
+ sprintf (load_op, \"stm\t%%2 - %s, (%%1)\", reg_rz);
+ return load_op;
+ }
+)
+
+
+(define_insn "*csky_stmsi3"
+ [(match_parallel 0 "csky_store_multiple_operation"
+ [(set (mem:SI (match_operand:SI 1 "register_operand" "r"))
+ (match_operand:SI 2 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+ (match_operand:SI 3 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+ (match_operand:SI 4 "register_operand" "r"))
+ ])]
+ "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 3"
+ {
+ static char load_op[256] = {0};
+ int end = REGNO (operands[2]) + XVECLEN (operands[0], 0) - 1;
+ const char *reg_rz = reg_names[end];
+ sprintf (load_op, \"stm\t%%2 - %s, (%%1)\", reg_rz);
+ return load_op;
+ }
+)
+
+
+(define_insn "*csky_stmsi2"
+ [(match_parallel 0 "csky_store_multiple_operation"
+ [(set (mem:SI (match_operand:SI 1 "register_operand" "r"))
+ (match_operand:SI 2 "register_operand" "r"))
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+ (match_operand:SI 3 "register_operand" "r"))
+ ])]
+ "TARGET_MULTIPLE_STLD && XVECLEN (operands[0], 0) == 2"
+ {
+ static char load_op[256] = {0};
+ int end = REGNO (operands[2]) + XVECLEN (operands[0], 0) - 1;
+ const char *reg_rz = reg_names[end];
+ sprintf (load_op, \"stm\t%%2 - %s, (%%1)\", reg_rz);
+ return load_op;
+ }
+)
+
+
+;; ------------------------------------------------------------------------
+;; Jump and linkage insns
+;; ------------------------------------------------------------------------
+
+(define_expand "tablejump"
+ [(parallel [(set (pc) (match_operand:SI 0 "register_operand" "r"))
+ (use (label_ref (match_operand 1 "" "")))])]
+ ""
+ "
+ if (flag_pic)
+ operands[0] = expand_simple_binop (Pmode, PLUS, operands[0],
+ pic_offset_table_rtx, NULL_RTX,
+ 1, OPTAB_DIRECT);
+ "
+)
+
+(define_insn "*tablejump"
+ [(set (pc) (match_operand:SI 0 "register_operand" "r"))
+ (use (label_ref (match_operand 1 "" "")))]
+ ""
+ "jmp %0"
+ [(set_attr "type" "branch_jmp")]
+)
+
+(define_expand "jump"
+ [(set (pc) (label_ref (match_operand 0 "" "")))]
+ ""
+ ""
+)
+
+(define_insn "*csky_jump"
+ [(set (pc) (label_ref (match_operand 0 "" "")))]
+ "CSKY_ISA_FEATURE (E2)"
+ "jbr %l0"
+ [(set_attr "type" "branch")]
+)
+
+;; The length of bsr is not really 5; it's used to distinguish from br32.
+;; Since the length attribute is treated specially it doesn't seem possible
+;; to compute the far_jump attribute directly and use that.
+
+(define_insn "*ck801_ck802_jump"
+ [(set (pc) (label_ref (match_operand 0 "" "")))]
+ "CSKY_ISA_FEATURE (E1) || CSKY_ISA_FEATURE (E2)"
+ "*{
+ if (get_attr_length (insn) != 5)
+ return \"jbr\\t%l0\";
+ else
+ return \"bsr\\t%l0\\t//far jump\";
+ }"
+ [(set_attr "type" "branch")
+ (set (attr "far_jump")
+ (if_then_else
+ (eq_attr "length" "5")
+ (const_string "yes")
+ (const_string "no")))
+ (set (attr "length")
+ (if_then_else
+ (and (ge (minus (match_dup 0) (pc)) (const_int -1024))
+ (le (minus (match_dup 0) (pc)) (const_int 1022)))
+ (const_int 2)
+ (if_then_else
+ (and (ge (minus (match_dup 0) (pc)) (const_int -65536))
+ (le (minus (match_dup 0) (pc)) (const_int 65534)))
+ (const_int 4)
+ (const_int 5))))]
+)
+
+(define_insn "indirect_jump"
+ [(set (pc) (match_operand:SI 0 "register_operand" "b,r"))]
+ ""
+ "@
+ jmp\t%0
+ jmp\t%0"
+ [(set_attr "length" "2,4")
+ (set_attr "type" "branch_jmp")]
+)
+
+
+;; ------------------------------------------------------------------------
+;; Conditional jump insns
+;; ------------------------------------------------------------------------
+
+(define_expand "cbranchsi4"
+ [(set (pc)
+ (if_then_else (match_operator 0 "ordered_comparison_operator"
+ [(match_operand:SI 1 "csky_compare_operand")
+ (match_operand:SI 2 "nonmemory_operand")])
+ (label_ref (match_operand 3 ""))
+ (pc)))]
+ ""
+ "{
+ enum rtx_code code = GET_CODE (operands[0]);
+
+ if (CSKY_ISA_FEATURE (2E3)
+ && (code == LE || code == LT || code == GT
+ || code == GE || code == EQ || code == NE)
+ && operands[2] == const0_rtx)
+ {
+ /* These cases match the jbez, jbnez, etc insns below.
+ TODO: Handling this in the expander is suboptimal since it
+ fails to detect cases where the constant 0 would fall out
+ from subsequent forward propagation or loop optimizers; maybe
+ it would be better to have a splitter here, but when to split? */
+ }
+ else
+ {
+ bool invert = csky_emit_compare (code, operands[1], operands[2]);
+
+ if (invert)
+ emit_jump_insn (gen_csky_jbf (operands[3]));
+ else
+ emit_jump_insn (gen_csky_jbt (operands[3]));
+ DONE;
+ }
+ }"
+)
+
+(define_insn "csky_jbt"
+ [(set (pc)
+ (if_then_else (ne (reg:CC CSKY_CC_REGNUM) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ "CSKY_ISA_FEATURE (2E3)"
+ "jbt\t%l0"
+ [(set_attr "type" "cbranch")]
+)
+
+(define_insn "csky_jbf"
+ [(set (pc)
+ (if_then_else (eq (reg:CC CSKY_CC_REGNUM) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ "CSKY_ISA_FEATURE (2E3)"
+ "jbf\t%l0"
+ [(set_attr "type" "cbranch")]
+)
+
+
+;;; CK802 has 32-bit jbt/jbf instructions, but no insn other
+;;; than bsr for far jumps.
+
+(define_insn "ck802_jbt"
+ [(set (pc) (if_then_else (ne (reg:CC CSKY_CC_REGNUM) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ "CSKY_ISA_FEATURE (E2)"
+ {
+ if (get_attr_length (insn) == 6)
+ return \"jbf\\t.LCB%=\;bsr\\t%l0\\t//far jump\\n.LCB%=:\";
+ else
+ return \"jbt\\t%l0\";
+ }
+ [(set_attr "type" "cbranch")
+ (set (attr "far_jump")
+ (if_then_else
+ (eq_attr "length" "6")
+ (const_string "yes")
+ (const_string "no")))
+ (set (attr "length")
+ (if_then_else
+ (and (ge (minus (match_dup 0) (pc)) (const_int -1024))
+ (le (minus (match_dup 0) (pc)) (const_int 1022)))
+ (const_int 2)
+ (if_then_else
+ (and (ge (minus (match_dup 0) (pc)) (const_int -65534))
+ (le (minus (match_dup 0) (pc)) (const_int 65534)))
+ (const_int 4)
+ (const_int 6))))]
+)
+
+(define_insn "ck802_jbf"
+ [(set (pc) (if_then_else (eq (reg:CC CSKY_CC_REGNUM) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ "CSKY_ISA_FEATURE (E2)"
+ {
+ if (get_attr_length (insn) == 6)
+ return \"jbt\\t.LCB%=\;bsr\\t%l0\\t//far jump\\n.LCB%=:\";
+ else
+ return \"jbf\\t%l0\";
+ }
+ [(set_attr "type" "cbranch")
+ (set (attr "far_jump")
+ (if_then_else
+ (eq_attr "length" "6")
+ (const_string "yes")
+ (const_string "no")))
+ (set (attr "length")
+ (if_then_else
+ (and (ge (minus (match_dup 0) (pc)) (const_int -1024))
+ (le (minus (match_dup 0) (pc)) (const_int 1022)))
+ (const_int 2)
+ (if_then_else
+ (and (ge (minus (match_dup 0) (pc)) (const_int -65534))
+ (le (minus (match_dup 0) (pc)) (const_int 65534)))
+ (const_int 4)
+ (const_int 6))))]
+)
+
+;; The length of the bsr case is not really 7; it's used to distinguish
+;; from br32.
+;; Note that we have to adjust the backward range of the jbr case to
+;; account for the jbf in front of it.
+(define_insn "ck801_jbt"
+ [(set (pc) (if_then_else (ne (reg:CC CSKY_CC_REGNUM) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ "CSKY_ISA_FEATURE (E1)"
+ {
+ if (get_attr_length (insn) == 6)
+ return \"jbf\\t.LCB%=\;jbr\\t%l0\\n.LCB%=:\";
+ else if (get_attr_length (insn) == 7)
+ return \"jbf\\t.LCB%=\;bsr\\t%l0\\t//far jump\\n.LCB%=:\";
+ else
+ return \"jbt\\t%l0\";
+ }
+ [(set_attr "type" "cbranch")
+ (set (attr "far_jump")
+ (if_then_else
+ (eq_attr "length" "7")
+ (const_string "yes")
+ (const_string "no")))
+ (set (attr "length")
+ (if_then_else
+ (and (ge (minus (match_dup 0) (pc)) (const_int -1024))
+ (le (minus (match_dup 0) (pc)) (const_int 1022)))
+ (const_int 2)
+ (if_then_else
+ (and (ge (minus (match_dup 0) (pc)) (const_int -65534))
+ (le (minus (match_dup 0) (pc)) (const_int 65534)))
+ (const_int 6)
+ (const_int 7))))]
+)
+
+(define_insn "ck801_jbf"
+ [(set (pc)
+ (if_then_else (eq (reg:CC CSKY_CC_REGNUM) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ "CSKY_ISA_FEATURE (E1)"
+ {
+ if (get_attr_length (insn) == 6)
+ return \"jbt\\t.LCB%=\;jbr\\t%l0\\n.LCB%=:\";
+ else if (get_attr_length (insn) == 7)
+ return \"jbt\\t.LCB%=\;bsr\\t%l0\\t//far jump\\n.LCB%=:\";
+ else
+ return \"jbf\\t%l0\";
+ }
+ [(set_attr "type" "cbranch")
+ (set (attr "far_jump")
+ (if_then_else
+ (eq_attr "length" "7")
+ (const_string "yes")
+ (const_string "no")))
+ (set (attr "length")
+ (if_then_else
+ (and (ge (minus (match_dup 0) (pc)) (const_int -1024))
+ (le (minus (match_dup 0) (pc)) (const_int 1022)))
+ (const_int 2)
+ (if_then_else
+ (and (ge (minus (match_dup 0) (pc)) (const_int -65534))
+ (le (minus (match_dup 0) (pc)) (const_int 65534)))
+ (const_int 6)
+ (const_int 7))))]
+)
+
+(define_code_iterator zero_cond [lt le gt ge eq ne])
+
+(define_code_attr inst [(lt "jblz") (le "jblsz") (gt "jbhz") (ge "jbhsz") (eq "jbez") (ne "jbnez")])
+
+(define_insn "*<inst>"
+ [(set (pc)
+ (if_then_else (zero_cond (match_operand:SI 0 "register_operand" "r")
+ (const_int 0))
+ (label_ref (match_operand 1 "" ""))
+ (pc)))]
+ "CSKY_ISA_FEATURE (2E3)"
+ "<inst>\t%0, %l1"
+ [(set_attr "type" "cbranch")]
+)
+
+;; ------------------------------------------------------------------------
+;; return insns
+;; ------------------------------------------------------------------------
+
+(define_insn "simple_return"
+ [(simple_return)]
+ "reload_completed"
+ "*
+ return csky_output_return_instruction ();
+ "
+)
+
+(define_expand "eh_return"
+ [(use (match_operand 0 "general_operand" ""))]
+ ""
+ "{
+ emit_insn (gen_csky_eh_return (operands[0]));
+ DONE;
+ }"
+)
+
+;; We can't expand this before we know where the link register is stored.
+(define_insn_and_split "csky_eh_return"
+ [(unspec_volatile [(match_operand:SI 0 "register_operand" "r")]
+ VUNSPEC_EH_RETURN)
+ (clobber (match_scratch:SI 1 "=&r"))]
+ ""
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+ "{
+ csky_set_eh_return_address (operands[0], operands[1]);
+ DONE;
+ }"
+)
+
+;; -------------------------------------------------------------------------
+;; SImode signed integer comparisons
+;; -------------------------------------------------------------------------
+
+(define_insn "*cmpnesi_r"
+ [(set (reg:CC CSKY_CC_REGNUM)
+ (ne:CC (match_operand:SI 0 "register_operand" "b,r")
+ (match_operand:SI 1 "register_operand" "b,r")))]
+ ""
+ "@
+ cmpne\t%0, %1
+ cmpne\t%0, %1"
+ [(set_attr "length" "2,4")
+ (set_attr "type" "cmp")]
+)
+
+;; cmpnei range is 0-31 for Smart mode.
+(define_insn "smart_cmpnesi_i"
+ [(set (reg:CC CSKY_CC_REGNUM)
+ (ne:CC (match_operand:SI 0 "register_operand" "a")
+ (match_operand:SI 1 "csky_literal_K_operand" "K")))]
+ "TARGET_MINI_REGISTERS"
+ "cmpnei\t%0, %1"
+ [(set_attr "type" "cmp")]
+)
+
+;; cmpnei range is 0 - 65536 for Fast mode.
+(define_insn "fast_cmpnesi_i"
+ [(set (reg:CC CSKY_CC_REGNUM)
+ (ne:CC (match_operand:SI 0 "register_operand" "r")
+ (match_operand:SI 1 "csky_literal_I_operand" "I")))]
+ "!TARGET_MINI_REGISTERS && CSKY_ISA_FEATURE (E2)"
+ "cmpnei\t%0, %1"
+ [(set_attr "type" "cmp")]
+)
+
+(define_insn "*cmpgtsi"
+ [(set (reg:CC CSKY_CC_REGNUM)
+ (gt:CC (match_operand:SI 0 "register_operand" "b,r")
+ (match_operand:SI 1 "register_operand" "b,r")))]
+ ""
+ "cmplt\t%1, %0"
+ [(set_attr "length" "2,4")
+ (set_attr "type" "cmp")]
+)
+
+(define_insn "cmpltsi_r"
+ [(set (reg:CC CSKY_CC_REGNUM)
+ (lt:CC (match_operand:SI 0 "register_operand" "b,r")
+ (match_operand:SI 1 "register_operand" "b,r")))]
+ ""
+ "cmplt\t%0, %1"
+ [(set_attr "length" "2,4")
+ (set_attr "type" "cmp")]
+)
+
+;; cmplti range is 1-32 for Smart mode.
+(define_insn "*smart_cmpltsi_i"
+ [(set (reg:CC CSKY_CC_REGNUM)
+ (lt:CC (match_operand:SI 0 "register_operand" "a")
+ (match_operand:SI 1 "csky_literal_J_operand" "J")))]
+ "TARGET_MINI_REGISTERS"
+ "cmplti\t%0, %1"
+ [(set_attr "length" "2")
+ (set_attr "type" "cmp")]
+)
+
+
+;; cmplti range is 1-65536 for Fast mode.
+(define_insn "*fast_cmpltsi_i"
+ [(set (reg:CC CSKY_CC_REGNUM)
+ (lt:CC (match_operand:SI 0 "register_operand" "a,r")
+ (match_operand:SI 1 "csky_literal_Uk_operand" "J,Uk")))]
+ "!TARGET_MINI_REGISTERS && CSKY_ISA_FEATURE (E2)"
+ "cmplti\t%0, %1"
+ [(set_attr "length" "2,4")
+ (set_attr "type" "cmp")]
+)
+
+; Covers cmplti x,0.
+(define_insn "*cskyv2_cmpltsi_0"
+ [(set (reg:CC CSKY_CC_REGNUM)
+ (lt:CC (match_operand:SI 0 "register_operand" "a,r")
+ (const_int 0)))]
+ "CSKY_ISA_FEATURE (E2)"
+ "btsti\t%0, 31"
+ [(set_attr "length" "2,4")
+ (set_attr "type" "cmp")]
+)
+
+(define_insn "*ck801_cmpltsi_0"
+ [(set (reg:CC CSKY_CC_REGNUM)
+ (lt:CC (match_operand:SI 0 "register_operand" "a")
+ (const_int 0)))]
+ "CSKY_ISA_FEATURE (E1)"
+ "btsti\t%0, 31"
+ [(set_attr "type" "cmp")]
+)
+
+;; Decrement and test instructions.
+;; In theory decne could be used in conjunction with jbt to implement
+;; doloop_end, but that seems to encourage the loop optimizer to introduce
+;; an additional induction variable and doesn't actually result in tighter
+;; loop code for that reason.
+
+(define_insn "*cskyv2_declt"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "const_int_operand" "Uh")))
+ (set (reg:CC CSKY_CC_REGNUM)
+ (lt:CC (plus:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))]
+ "CSKY_ISA_FEATURE (2E3)"
+ "declt\t%0, %1, %M2"
+)
+
+(define_insn "*cskyv2_decgt"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "const_int_operand" "Uh")))
+ (set (reg:CC CSKY_CC_REGNUM)
+ (gt:CC (plus:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))]
+ "CSKY_ISA_FEATURE (2E3)"
+ "decgt\t%0, %1, %M2"
+)
+
+(define_insn "*cskyv2_decne"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "const_int_operand" "Uh")))
+ (set (reg:CC CSKY_CC_REGNUM)
+ (ne:CC (plus:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))]
+ "CSKY_ISA_FEATURE (2E3)"
+ "decne\t%0, %1, %M2"
+)
+
+;; -------------------------------------------------------------------------
+;; SImode unsigned integer comparisons
+;; -------------------------------------------------------------------------
+
+(define_insn "cmpgeusi_r"
+ [(set (reg:CC CSKY_CC_REGNUM)
+ (geu:CC (match_operand:SI 0 "register_operand" "b,r")
+ (match_operand:SI 1 "register_operand" "b,r")))]
+ ""
+ "cmphs\t%0, %1"
+ [(set_attr "length" "2,4")
+ (set_attr "type" "cmp")]
+)
+
+(define_insn "*smart_cmpgeusi_i"
+ [(set (reg:CC CSKY_CC_REGNUM)
+ (geu:CC (match_operand:SI 0 "register_operand" "a")
+ (match_operand:SI 1 "csky_literal_J_operand" "J")))]
+ "TARGET_MINI_REGISTERS"
+ "cmphsi\t%0, %1"
+ [(set_attr "length" "2")
+ (set_attr "type" "cmp")]
+)
+
+(define_insn "*fast_cmpgeusi_i"
+ [(set (reg:CC CSKY_CC_REGNUM)
+ (geu:CC (match_operand:SI 0 "register_operand" "a,r")
+ (match_operand:SI 1 "csky_literal_Uk_operand" "J,Uk")))]
+ "!TARGET_MINI_REGISTERS && CSKY_ISA_FEATURE (E2)"
+ "cmphsi\t%0, %1"
+ [(set_attr "length" "2,4")
+ (set_attr "type" "cmp")]
+)
+
+(define_insn "*cmpleusi"
+ [(set (reg:CC CSKY_CC_REGNUM)
+ (leu:CC (match_operand:SI 0 "register_operand" "b,r")
+ (match_operand:SI 1 "register_operand" "b,r")))]
+ ""
+ "cmphs\t%1, %0"
+ [(set_attr "length" "2,4")
+ (set_attr "type" "cmp")]
+)
+
+;; -------------------------------------------------------------------------
+;; Function call insns
+;; -------------------------------------------------------------------------
+
+(define_expand "call"
+ [(parallel [(call (match_operand:SI 0 "" "") (match_operand 1 "" ""))
+ (clobber (reg:SI CSKY_LR_REGNUM))])]
+ ""
+ "
+ {
+ rtx pic_ref;
+ rtx addr_ref = XEXP (operands[0], 0);
+
+ if (flag_pic
+ && (CONSTANT_P (addr_ref)
+ || csky_symbol_mentioned_p (addr_ref)
+ || csky_label_mentioned_p (addr_ref)))
+ {
+ pic_ref = csky_legitimize_pic_address (addr_ref, 0, false);
+ operands[0] = gen_rtx_MEM (GET_MODE (pic_ref), pic_ref);
+ }
+
+ if (GET_CODE (operands[0]) == MEM
+ && ! register_operand (XEXP (operands[0], 0), SImode)
+ && ! csky_symbolic_address_p (XEXP (operands[0], 0))
+ && ! (flag_pic
+ && csky_unspec_operand (XEXP (operands[0], 0), SImode)))
+ operands[0] = gen_rtx_MEM (GET_MODE (operands[0]),
+ force_reg (Pmode, XEXP (operands[0], 0)));
+ }"
+)
+
+
+(define_insn "*call_internal"
+ [(call (mem:SI (match_operand:SI 0 "csky_call_address_operand" "b,r,S"))
+ (match_operand 1 "" ""))
+ (clobber (reg:SI CSKY_LR_REGNUM))]
+ ""
+ "@
+ jsr\t%0
+ jsr\t%0
+ jbsr\t%0"
+ [(set_attr "length" "2,4,4")
+ (set_attr "type" "call_jsr,call_jsr,call")]
+)
+
+(define_insn "*call_internal_pic"
+ [(call (mem:SI (match_operand:SI 0 "csky_unspec_operand" "X"))
+ (match_operand 1 "" ""))
+ (clobber (reg:SI CSKY_LR_REGNUM))]
+ "flag_pic"
+ "* return csky_output_call (operands, 0);"
+ [(set_attr "length" "4")]
+)
+
+(define_expand "call_value"
+ [(parallel [(set (match_operand 0 "register_operand" "")
+ (call (match_operand:SI 1 "" "") (match_operand 2 "" "")))
+ (clobber (reg:SI CSKY_LR_REGNUM))])]
+ ""
+ "{
+ rtx pic_ref;
+ rtx addr_ref = XEXP (operands[1], 0);
+
+ if (flag_pic
+ && (CONSTANT_P (addr_ref)
+ || csky_symbol_mentioned_p (addr_ref)
+ || csky_label_mentioned_p (addr_ref)))
+ {
+ pic_ref = csky_legitimize_pic_address (addr_ref, 0, false);
+ operands[1] = gen_rtx_MEM (GET_MODE (pic_ref), pic_ref);
+ }
+
+ if (GET_CODE (operands[1]) == MEM
+ && ! register_operand (XEXP (operands[1], 0), SImode)
+ && ! csky_symbolic_address_p (XEXP (operands[1], 0))
+ && ! (flag_pic
+ && csky_unspec_operand (XEXP (operands[1], 0), SImode)))
+ operands[1] = gen_rtx_MEM (GET_MODE (operands[1]),
+ force_reg (Pmode, XEXP (operands[1], 0)));
+ }")
+
+
+(define_insn "*call_value_internal"
+ [(set (match_operand 0 "register_operand" "=r,r,r")
+ (call (mem:SI (match_operand:SI 1 "csky_call_address_operand" "b, r,S"))
+ (match_operand 2 "" "")))
+ (clobber (reg:SI CSKY_LR_REGNUM))]
+ ""
+ "@
+ jsr\t%1
+ jsr\t%1
+ jbsr\t%1"
+ [(set_attr "length" "2,4,4")
+ (set_attr "type" "call_jsr,call_jsr,call")]
+)
+
+(define_insn "*call_value_internal_pic"
+ [(set (match_operand 0 "register_operand" "=r")
+ (call (mem:SI (match_operand:SI 1 "csky_unspec_operand" "X"))
+ (match_operand 2 "" "")))
+ (clobber (reg:SI CSKY_LR_REGNUM))]
+ "flag_pic"
+ "* return csky_output_call (operands, 1);"
+)
+
+(define_insn "*call_value_struct"
+ [(set (match_parallel 0 ""
+ [(expr_list (match_operand 3 "register_operand" "")
+ (match_operand 4 "immediate_operand" ""))
+ (expr_list (match_operand 5 "register_operand" "")
+ (match_operand 6 "immediate_operand" ""))])
+ (call (mem:SI (match_operand:SI 1 "csky_call_address_operand" "b,r,S"))
+ (match_operand 2 "" "")))
+ (clobber (reg:SI CSKY_LR_REGNUM))]
+ ""
+ "@
+ jsr\t%1
+ jsr\t%1
+ jbsr\t%1"
+ [(set_attr "length" "2,4,4")
+ (set_attr "type" "call_jsr,call_jsr,call")]
+)
+
+(define_insn "*call_value_struct_pic"
+ [(set (match_parallel 0 ""
+ [(expr_list (match_operand 3 "register_operand" "")
+ (match_operand 4 "immediate_operand" ""))
+ (expr_list (match_operand 5 "register_operand" "")
+ (match_operand 6 "immediate_operand" ""))])
+ (call (mem:SI (match_operand:SI 1 "csky_unspec_operand" "X"))
+ (match_operand 2 "" "")))
+ (clobber (reg:SI CSKY_LR_REGNUM))]
+ "flag_pic"
+ "* return csky_output_call (operands, 1);"
+)
+
+
+;; -------------------------------------------------------------
+;; prologue & epilogue
+;; -------------------------------------------------------------
+
+(define_expand "prologue"
+ [(clobber (const_int 0))]
+ ""
+ "
+ {
+ csky_expand_prologue ();
+ DONE;
+ }"
+)
+
+(define_expand "epilogue"
+ [(clobber (const_int 0))]
+ ""
+ "
+ {
+ csky_expand_epilogue ();
+ DONE;
+ }"
+)
+
+/* TODO: pushpop */
+;; Push multiple registers to the stack. Registers are in parallel (use ...)
+;; expressions. For simplicity, the first register is also in the unspec
+;; part.
+(define_insn "*push_multi"
+ [(match_parallel 2 "registers_push"
+ [(set (match_operand:BLK 0 "push_memory_operand" "")
+ (unspec:BLK [(match_operand:SI 1 "register_operand" "")]
+ UNSPEC_PUSHPOP_MULT))])]
+ ""
+ {
+ int num_saves = XVECLEN (operands[2], 0);
+ int i;
+ char pattern[100];
+
+ strcpy (pattern, \"push\\t%1\");
+
+ for (i = 1; i < num_saves; i++)
+ {
+ strcat (pattern, \", \");
+ strcat (pattern,
+ reg_names[REGNO (XEXP (XVECEXP (operands[2], 0, i), 0))]);
+ }
+
+ output_asm_insn (pattern, operands);
+
+ return \"\";
+ }
+ [(set (attr "length")
+ (symbol_ref "csky_compute_pushpop_length (operands)"))]
+)
+
+;; Pop (as used in epilogue RTL)
+;;
+(define_insn "*pop_multi"
+ [(match_parallel 2 "registers_pop"
+ [(return)
+ (set (match_operand:SI 1 "register_operand" "")
+ (unspec:SI [(match_operand:SI 0 "pop_memory_operand" "")]
+ UNSPEC_PUSHPOP_MULT))])]
+ ""
+ {
+ int num_saves = XVECLEN (operands[2], 0);
+ int i;
+ char pattern[100];
+
+ strcpy (pattern, \"pop\\t%1\");
+
+ for (i = 2; i < num_saves; i++)
+ {
+ strcat (pattern, \", \");
+ strcat (pattern,
+ reg_names[REGNO (XEXP (XVECEXP (operands[2], 0, i), 0))]);
+ }
+
+ output_asm_insn (pattern, operands);
+
+ return \"\";
+ }
+ [(set (attr "length")
+ (symbol_ref "csky_compute_pushpop_length (operands)"))]
+)
+
+
+;; -------------------------------------------------------------------------
+;; PIC related insns
+;; -------------------------------------------------------------------------
+
+(define_insn "prologue_get_pc"
+ [(set (reg:SI 28)
+ (match_operand:SI 0 "" "X"))]
+ "(GET_CODE (operands[0]) == UNSPEC)
+ && (XINT (operands[0], 1) == UNSPEC_PIC_SYMBOL_GOTPC_GRS)"
+ {
+ operands[0] = XVECEXP (operands[0], 0, 0);
+ output_asm_insn (\"grs\tgb, %0\", operands);
+ default_internal_label (asm_out_file, \"L\",
+ CODE_LABEL_NUMBER (XEXP (operands[0], 0)));
+ return \"\";
+ }
+)
+
+(define_insn "*pic_got_pc"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand:SI 1 "" "")] UNSPEC_PIC_SYMBOL_GOTPC))]
+ "flag_pic"
+ "lrw\t%0, %1@GOTPC"
+)
+
+(define_insn "*pic_symbol_gotoff"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand:SI 1 "" "")] UNSPEC_PIC_SYMBOL_GOTOFF))]
+ "flag_pic"
+ "lrw\t%0, %1@GOTOFF"
+)
+
+(define_insn "*pic_symbol_got"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand:SI 1 "" "")] UNSPEC_PIC_SYMBOL_GOT))]
+ "flag_pic"
+ "lrw\t%0, %1@GOT"
+)
+
+(define_insn "*pic_symbol_plt"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand:SI 1 "" "")] UNSPEC_PIC_SYMBOL_PLT))]
+ "flag_pic"
+ "lrw\t%0, %1@PLT"
+)
+
+(define_insn "*pic_symbol_grs"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand:SI 1 "" "")] UNSPEC_PIC_SYMBOL_GRS))]
+ "flag_pic"
+ "grs\t%0, %1"
+)
+
+(define_expand "builtin_setjmp_receiver"
+ [(label_ref (match_operand 0 "" ""))]
+ "flag_pic"
+ "{
+ rtx l1 = gen_label_rtx();
+ rtx grs_label = gen_rtx_LABEL_REF (SImode, l1);
+ rtx reg_gb = gen_rtx_REG (SImode, PIC_OFFSET_TABLE_REGNUM);
+ rtx reg_temp = gen_rtx_REG (SImode, 12);
+
+ rtx tmp0_unspec = gen_rtx_UNSPEC (Pmode,
+ gen_rtvec (1, grs_label),
+ UNSPEC_PIC_SYMBOL_GOTPC_GRS);
+ rtx tmp1_unspec = gen_rtx_UNSPEC (Pmode,
+ gen_rtvec (1, grs_label),
+ UNSPEC_PIC_SYMBOL_GOTPC);
+
+ emit_insn (gen_prologue_get_pc (tmp0_unspec));
+ emit_move_insn (reg_temp, tmp1_unspec);
+ emit_insn (gen_addsi3 (reg_gb, reg_gb, reg_temp));
+ emit_use (reg_gb);
+
+ DONE;
+ }"
+)
+
+;; -------------------------------------------------------------------------
+;; TLS related insns
+;; -------------------------------------------------------------------------
+
+
+;; UNSPEC_TLS can take either 2 or 3 operands. Operand 0 is the symbol_ref,
+;; operand 1 is a CONST_INT identifying the TLS model, and the optional
+;; operand 3 is an UNSPEC_TLS_LABEL.
+;; The 3-operand case is for TLS_GD32, TLS_LDM32, and TLS_IE32.
+;; The 2-operand case is for TLS_LE32 and TLS_LDO32.
+
+;; Move PC-relative TLS label to reg. This is used for the TLS_GD32
+;; and TLS_GD32 models (when setting up a call to tls_get_addr) and
+;; also TLS_IE32.
+
+(define_insn "*tls_pcrel_label"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand:SI 1 "const_int_operand" "")]
+ UNSPEC_TLS_LABEL))]
+ "TARGET_TLS"
+ "grs\t%0, .LTLS%1"
+ [(set_attr "length" "4")]
+)
+
+;; This pattern is used to load the TLS base for the same models as above.
+;; The embedded UNSPEC_TLS_LABEL only identifies the label to emit and
+;; doesn't generate a reference to it; that's handled by the *tls_pcrel_label
+;; pattern above. The label offset needs to be added to the result stored
+;; in operand 0 by this insn.
+
+(define_insn "*tls_get_symbol_1"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand 1 "" "")
+ (match_operand 2 "" "")
+ (unspec:SI [(match_operand 3 "" "")] UNSPEC_TLS_LABEL)]
+ UNSPEC_TLS))]
+ "TARGET_TLS"
+ {
+ default_internal_label (asm_out_file, \"LTLS\", INTVAL (operands[3]));
+ switch (INTVAL (operands[2]))
+ {
+ case TLS_GD32:
+ return \"lrw\t%0, %1@TLSGD32\";
+ case TLS_LDM32:
+ return \"lrw\t%0, %1@TLSLDM32\";
+ case TLS_IE32:
+ return \"lrw\t%0, %1@GOTTPOFF\";
+ default:
+ return \"\";
+ }
+ }
+)
+
+;; This pattern matches the two-operand form of UNSPEC_TLS.
+
+(define_insn "*tls_get_symbol_2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand 1 "" "")
+ (match_operand 2 "" "")]
+ UNSPEC_TLS))]
+ "TARGET_TLS"
+ {
+ switch (INTVAL (operands[2]))
+ {
+ case TLS_LE32:
+ return \"lrw\t%0, %1@TPOFF\";
+ case TLS_LDO32:
+ return \"lrw\t%0, %1@TLSLDO32\";
+ default:
+ return \"\";
+ }
+ }
+)
+
+
+;; -------------------------------------------------------------
+;; Misc insns
+;; -------------------------------------------------------------
+
+(define_insn "nop"
+ [(const_int 0)]
+ ""
+ "nop"
+ [(set_attr "length" "2")]
+)
+
+(define_insn "trap"
+ [(trap_if (const_int 1) (const_int 0))]
+ ""
+ "bkpt"
+ [(set (attr "length") (const_int 2))
+ (set_attr "type" "alu")]
+)
+
+
+;; -------------------------------------------------------------
+;; Special patterns for dealing with the constant pool
+;; -------------------------------------------------------------
+
+(define_insn "align_4"
+ [(unspec_volatile [(const_int 0)] VUNSPEC_ALIGN)]
+ ""
+ {
+ assemble_align(32);
+ return \"\";
+ }
+ [(set_attr "length" "0")]
+)
+
+(define_insn "csky_constpool_label"
+ [(unspec_volatile [(match_operand 0 "" "")] VUNSPEC_POOL_LABEL)]
+ ""
+ {
+ char tmp_label[15];
+ ASM_GENERATE_INTERNAL_LABEL (tmp_label, \"LCP\", INTVAL (operands[0]));
+ assemble_label (asm_out_file, tmp_label);
+ return \"\";
+ }
+ [(set_attr "length" "0")]
+)
+
+(define_insn "consttable_4"
+ [(unspec_volatile [(match_operand 0 "" "")] VUNSPEC_POOL_4)]
+ ""
+ {
+ if (CONST_DOUBLE_P (operands[0]))
+ assemble_real (*CONST_DOUBLE_REAL_VALUE (operands[0]),
+ SFmode, BITS_PER_WORD);
+ else
+ {
+ assemble_integer (operands[0], 4, BITS_PER_WORD, 1);
+ mark_symbol_refs_as_used (operands[0]);
+ }
+ return \"\";
+ }
+ [(set_attr "length" "4")]
+)
+
+(define_insn "consttable_8"
+ [(unspec_volatile [(match_operand 0 "" "")] VUNSPEC_POOL_8)]
+ ""
+ {
+ if (CONST_DOUBLE_P (operands[0]))
+ assemble_real (*CONST_DOUBLE_REAL_VALUE (operands[0]),
+ DFmode, BITS_PER_WORD);
+ else
+ assemble_integer (operands[0], 8, BITS_PER_WORD, 1);
+ return \"\";
+ }
+ [(set_attr "length" "8")]
+)
+
+;;FIXME record the deferred symbol_ref information with use insn
+(define_insn "*cskyv2_use_symbol_ref"
+ [(unspec_volatile [(match_operand 0 "" "")] VUNSPEC_SYMBOL_REF)]
+ ""
+ ""
+ [(set_attr "length" "0")]
+)
+
+
+;; ------------------------------------------------------------
+;; switch case optimize
+;; ------------------------------------------------------------
+
+(define_expand "casesi"
+ [(match_operand:SI 0 "register_operand" "") ; index to jump on
+ (match_operand:SI 1 "const_int_operand" "") ; lower bound
+ (match_operand:SI 2 "const_int_operand" "") ; total range (max - min)
+ (match_operand:SI 3 "" "") ; table label
+ (match_operand:SI 4 "" "")] ; Out of range label (default:)
+ "TARGET_CASESI"
+ "
+ {
+ enum insn_code code;
+ if (operands[1] != const0_rtx)
+ {
+ rtx reg = gen_reg_rtx (SImode);
+ emit_insn (gen_subsi3 (reg,
+ operands[0],
+ GEN_INT (INTVAL (operands[1]))));
+ operands[0] = reg;
+ }
+
+ code = CODE_FOR_csky_casesi_internal;
+
+ if (!insn_data[(int) code].operand[1].predicate(operands[2], SImode))
+ operands[2] = force_reg (SImode,operands[2]);
+
+ emit_jump_insn (GEN_FCN ((int) code) (operands[0],operands[2],
+ operands[3],operands[4]));
+ DONE;
+ }"
+)
+
+(define_expand "csky_casesi_internal"
+ [(match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "csky_literal_Uk_operand" "")
+ (match_operand 2 "" "")
+ (match_operand 3 "" "")]
+ ""
+ {
+ rtx reg0;
+ rtx test = gen_rtx_GTU (VOIDmode, operands[0], operands[1]);
+ emit_jump_insn (gen_cbranchsi4 (test, operands[0], operands[1],
+ operands[3]));
+ reg0 = gen_rtx_REG (SImode, 0);
+ emit_move_insn (reg0, operands[0]);
+ emit_jump_insn (gen_csky_casesi_dispatch (operands[2]));
+ DONE;
+ }
+)
+
+(define_insn "csky_casesi_dispatch"
+ [(parallel [(set (pc) (unspec [(reg:SI 0)
+ (label_ref (match_operand 0 "" ""))]
+ UNSPEC_CSKY_CASESI))
+ (clobber (reg:SI CSKY_LR_REGNUM))])]
+ ""
+ "*return csky_output_casesi (operands);"
+ [(set_attr "length" "4")]
+)
+
+;; ------------------------------------------------------------------------
+;; index insns
+;; ------------------------------------------------------------------------
+
+(define_insn "*cskyv2_indexsi_t"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "r")
+ (const_int 4))
+ (match_operand:SI 2 "register_operand" "r")))]
+ "CSKY_ISA_FEATURE (E2)"
+ "ixw\t%0, %2, %1"
+)
+
+(define_insn "*cskyv2_indexhi_t"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "r")
+ (const_int 2))
+ (match_operand:SI 2 "register_operand" "r")))]
+ "CSKY_ISA_FEATURE (E2)"
+ "ixh\t%0, %2, %1"
+)
+
+(define_insn "*cskyv2_indexdi_t"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "r")
+ (const_int 8))
+ (match_operand:SI 2 "register_operand" "r")))]
+ "CSKY_ISA_FEATURE (2E3)"
+ "ixd\t%0, %2, %1"
+)
+
+;; ------------------------------------------------------------------------
+;; swap insns
+;; ------------------------------------------------------------------------
+
+(define_insn "bswapsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (bswap:SI (match_operand:SI 1 "register_operand" "r")))]
+ "CSKY_ISA_FEATURE (E2)"
+ "revb\t%0, %1"
+)
diff --git a/gcc/config/csky/csky.opt b/gcc/config/csky/csky.opt
new file mode 100644
index 0000000..55d2659
--- /dev/null
+++ b/gcc/config/csky/csky.opt
@@ -0,0 +1,173 @@
+;; Command-line options for the C-SKY back end.
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+;; Contributed by C-SKY Microsystems and Mentor Graphics.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it under
+;; the terms of the GNU General Public License as published by the Free
+;; Software Foundation; either version 3, or (at your option) any later
+;; version.
+;;
+;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+;; WARRANTY; without even the implied warranty of MERCHANTABILITY or
+;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+;; for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>.
+
+
+HeaderInclude
+config/csky/csky_opts.h
+
+;; Architecture/CPU options.
+;; Normal CPU and arch enums are loaded from csky_tables.opt.
+
+; For backward compatibility only.
+march=ck803s
+Target Report Var(flag_arch_ck803s) Undocumented
+
+march=
+Target RejectNegative ToLower Joined Enum(csky_arch) Var(csky_arch_option) Save
+Specify the target architecture.
+
+mcpu=
+Target RejectNegative ToLower Joined Enum(csky_processor_type) Var(csky_cpu_option) Init(TARGET_CPU_csky_none) Save
+Specify the target processor.
+
+;; Endianness options.
+
+mbig-endian
+Target RejectNegative Report Mask(BIG_ENDIAN)
+Generate big-endian code.
+
+EB
+Target RejectNegative Report Alias(mbig-endian) Undocumented
+
+mlittle-endian
+Target RejectNegative Report InverseMask(BIG_ENDIAN)
+Generate little-endian code.
+
+EL
+Target RejectNegative Report Alias(mlittle-endian) Undocumented
+
+;; Floating point options. These affect code generation but not
+;; assembly.
+
+mhard-float
+Target Report RejectNegative Mask(HARD_FLOAT)
+Enable hardware floating-point instructions.
+
+msoft-float
+Target Report RejectNegative InverseMask(HARD_FLOAT)
+Use library calls to perform floating-point operations (default).
+
+mfpu=
+Target RejectNegative Joined Enum(csky_fpu) Var(csky_fpu_index) Init(TARGET_FPU_auto) Save
+Specify the target floating-point hardware/format.
+
+mdouble-float
+Target Report Var(TARGET_DOUBLE_FLOAT) Init(-1)
+Generate C-SKY FPU double float instructions (default for hard float).
+
+mfdivdu
+Target Report Var(TARGET_FDIVDU) Init(-1)
+Generate frecipd/fsqrtd/fdivd instructions (default for hard float).
+
+;; Instruction set extensions. Most of these don't affect code
+;; generation, and are passed through to the assembler.
+;; There are builtin preprocessor defines for each of these.
+
+melrw
+Target Report Var(TARGET_ELRW) Init(-1)
+Enable the extended LRW instruction (default for CK801).
+
+mistack
+Target Report Mask(ISTACK)
+Enable interrupt stack instructions.
+
+mmp
+Target Report RejectNegative Mask(MP)
+Enable multiprocessor instructions.
+
+mcp
+Target Report RejectNegative Mask(CP)
+Enable coprocessor instructions.
+
+mcache
+Target Report RejectNegative Mask(CACHE)
+Enable cache prefetch instructions.
+
+msecurity
+Target Report RejectNegative Mask(SECURITY)
+Enable C-SKY SECURE instructions.
+
+mmac
+Target Report RejectNegative Alias(msecurity) Undocumented
+
+mtrust
+Target Report RejectNegative Mask(TRUST)
+Enable C-SKY TRUST instructions.
+
+mdsp
+Target Report RejectNegative Var(TARGET_DSP)
+Enable C-SKY DSP instructions.
+
+medsp
+Target Report RejectNegative Mask(EDSP)
+Enable C-SKY Enhanced DSP instructions.
+
+mvdsp
+Target Report RejectNegative Mask(VDSP)
+Enable C-SKY Vector DSP instructions.
+
+;; Code generation options not passed to the assembler.
+
+mdiv
+Target Report Var(TARGET_DIV) Init(-1)
+Generate divide instructions.
+
+msmart
+Target Report Var(TARGET_MINI_REGISTERS) Init(-1)
+Generate code for Smart Mode.
+
+mhigh-registers
+Target Report Var(TARGET_HIGH_REGISTERS) Init(-1)
+Enable use of R16-R31 (default).
+
+manchor
+Target Report Var(TARGET_ANCHOR)
+Generate code using global anchor symbol addresses.
+
+mpushpop
+Target Report Var(TARGET_PUSHPOP) Init(1)
+Generate push/pop instructions (default).
+
+mmultiple-stld
+Target Report Var(TARGET_MULTIPLE_STLD) Init(-1)
+Generate stm/ldm instructions (default).
+
+mstm
+Target Report Alias(mmultiple-stld) Undocumented
+
+mconstpool
+Target Report Var(TARGET_CONSTANT_POOL) Init(-1)
+Generate constant pools in the compiler instead of assembler.
+
+mstack-size
+Target Report Var(TARGET_STACK_SIZE) Init(0)
+Emit .stack_size directives.
+
+mccrt
+Target Report Var(TARGET_LIBCCRT) Init(0)
+Generate code for C-SKY compiler runtime instead of libgcc.
+
+mbranch-cost=
+Target Report Joined RejectNegative UInteger Var(csky_branch_cost) Init(1)
+Set the branch costs to roughly the specified number of instructions.
+
+msched-prolog
+Target Report Var(flag_sched_prolog) Init(0)
+Permit scheduling of function prologue and epilogue sequences.
diff --git a/gcc/config/csky/csky_cores.def b/gcc/config/csky/csky_cores.def
new file mode 100644
index 0000000..5159a07
--- /dev/null
+++ b/gcc/config/csky/csky_cores.def
@@ -0,0 +1,199 @@
+/* Architecture and core descriptions for the C-SKY back end.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ Contributed by C-SKY Microsystems and Mentor Graphics.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+/* Before using #include to read this file, define a macro:
+
+ CSKY_ARCH(NAME, CORE, ARCH, ISA)
+
+ The NAME is the name of the architecture, represented as a string
+ constant. The CORE is the identifier for a core representative of
+ this architecture. ARCH is the architecture revision. ISA is the
+ detailed architectural capabilities of the core. */
+
+#ifdef CSKY_ARCH
+CSKY_ARCH ("ck801", ck801, CK801,
+ CSKY_ISA_FEAT (CSKY_ISA_CK801))
+CSKY_ARCH ("ck802", ck802, CK802,
+ CSKY_ISA_FEAT (CSKY_ISA_CK802))
+CSKY_ARCH ("ck803", ck803, CK803,
+ CSKY_ISA_FEAT (CSKY_ISA_CK803))
+CSKY_ARCH ("ck807", ck807, CK807,
+ CSKY_ISA_FEAT (CSKY_ISA_CK807) CSKY_ISA_FEAT (CSKY_ISA_DSP))
+CSKY_ARCH ("ck810", ck810, CK810,
+ CSKY_ISA_FEAT (CSKY_ISA_CK810) CSKY_ISA_FEAT (CSKY_ISA_DSP))
+#endif
+
+
+/* Before using #include to read this file, define a macro:
+
+ CSKY_CORE(CORE_NAME, INTERNAL_IDENT, TUNE_IDENT, ARCH, ISA)
+
+ The isa features of core will inherit the ARCH.
+
+ The CORE_NAME is the name of the core, represented as a string constant.
+ The INTERNAL_IDENT is the name of the core represented as an identifier.
+ This must be unique for each entry in this table.
+ The TUNE_IDENT is the name of the core for which scheduling decisions
+ should be made, represented as an identifier.
+ The ARCH is the architecture revision implemented by the chip.
+ The ISA is the detailed architectural capabilities of the core. */
+
+#ifdef CSKY_CORE
+/* ck801 Architecture Processors */
+CSKY_CORE ("ck801", ck801, ck801, CK801,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck801t", ck801t, ck801t, CK801,
+ CSKY_ISA_FEAT_NONE)
+
+/* ck802 Architecture Processors */
+CSKY_CORE ("ck802", ck802, ck802, CK802,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck802t", ck802t, ck802t, CK802,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck802j", ck802j, ck802j, CK802,
+ CSKY_ISA_FEAT (isa_bit_java))
+
+/* ck803 Architecture Processors */
+CSKY_CORE ("ck803", ck803, ck803, CK803,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck803h", ck803h, ck803h, CK803,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck803t", ck803t, ck803t, CK803,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck803ht", ck803ht, ck803ht, CK803,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck803f", ck803f, ck803f, CK803,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck803fh", ck803fh, ck803fh, CK803,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck803e", ck803e, ck803e, CK803,
+ CSKY_ISA_FEAT (CSKY_ISA_DSP))
+CSKY_CORE ("ck803eh", ck803eh, ck803eh, CK803,
+ CSKY_ISA_FEAT (CSKY_ISA_DSP))
+CSKY_CORE ("ck803et", ck803et, ck803et, CK803,
+ CSKY_ISA_FEAT (CSKY_ISA_DSP))
+CSKY_CORE ("ck803eht", ck803eht, ck803eht, CK803,
+ CSKY_ISA_FEAT (CSKY_ISA_DSP))
+CSKY_CORE ("ck803ef", ck803ef, ck803ef, CK803,
+ CSKY_ISA_FEAT (CSKY_ISA_DSP))
+CSKY_CORE ("ck803efh", ck803efh, ck803efh, CK803,
+ CSKY_ISA_FEAT (CSKY_ISA_DSP))
+CSKY_CORE ("ck803ft", ck803ft, ck803ft, CK803,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck803eft", ck803eft, ck803eft, CK803,
+ CSKY_ISA_FEAT (CSKY_ISA_DSP))
+CSKY_CORE ("ck803efht", ck803efht, ck803efht, CK803,
+ CSKY_ISA_FEAT (CSKY_ISA_DSP))
+CSKY_CORE ("ck803r1", ck803r1, ck803r1, CK803,
+ CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803hr1", ck803hr1, ck803hr1, CK803,
+ CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803tr1", ck803tr1, ck803tr1, CK803,
+ CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803htr1", ck803htr1, ck803htr1, CK803,
+ CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803fr1", ck803fr1, ck803fr1, CK803,
+ CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803fhr1", ck803fhr1, ck803fhr1, CK803,
+ CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803er1", ck803er1, ck803er1, CK803,
+ CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803ehr1", ck803ehr1, ck803ehr1, CK803,
+ CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803etr1", ck803etr1, ck803etr1, CK803,
+ CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803ehtr1", ck803ehtr1, ck803ehtr1, CK803,
+ CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803efr1", ck803efr1, ck803efr1, CK803,
+ CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803efhr1", ck803efhr1, ck803efhr1, CK803,
+ CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803ftr1", ck803ftr1, ck803ftr1, CK803,
+ CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803eftr1", ck803eftr1, ck803eftr1, CK803,
+ CSKY_ISA_FEAT (isa_bit_3E3r1))
+CSKY_CORE ("ck803efhtr1", ck803efhtr1, ck803efhtr1, CK803,
+ CSKY_ISA_FEAT (isa_bit_3E3r1))
+
+/* ck803s Architecture Processors */
+CSKY_CORE ("ck803s", ck803s, ck803s, CK803,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck803st", ck803st, ck803st, CK803,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck803se", ck803se, ck803se, CK803,
+ CSKY_ISA_FEAT (CSKY_ISA_DSP))
+CSKY_CORE ("ck803sf", ck803sf, ck803sf, CK803,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck803sef", ck803sef, ck803sef, CK803,
+ CSKY_ISA_FEAT (CSKY_ISA_DSP))
+CSKY_CORE ("ck803seft", ck803seft, ck803seft, CK803,
+ CSKY_ISA_FEAT (CSKY_ISA_DSP))
+
+/* ck807 Architecture Processors */
+CSKY_CORE ("ck807e", ck807e, ck807e, CK807,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck807ef", ck807ef, ck807ef, CK807,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck807", ck807, ck807, CK807,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck807f", ck807f, ck807f, CK807,
+ CSKY_ISA_FEAT_NONE)
+
+/* ck810 Architecture Processors */
+CSKY_CORE ("ck810e", ck810e, ck810e, CK810,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck810et", ck810et, ck810et, CK810,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck810ef", ck810ef, ck810ef, CK810,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck810eft", ck810eft, ck810eft, CK810,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck810", ck810, ck810, CK810,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck810v", ck810v, ck810v, CK810,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck810f", ck810f, ck810f, CK810,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck810t", ck810t, ck810t, CK810,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck810fv", ck810fv, ck810fv, CK810,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck810tv", ck810tv, ck810tv, CK810,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck810ft", ck810ff, ck810ft, CK810,
+ CSKY_ISA_FEAT_NONE)
+CSKY_CORE ("ck810ftv", ck810ftv, ck810ftv, CK810,
+ CSKY_ISA_FEAT_NONE)
+#endif
+
+
+/* Before using #include to read this file, define a macro:
+
+ CSKY_FPU(NAME, CNAME, ISA)
+
+ NAME is the publicly visible option name.
+ CNAME is a C-compatible variable name substring.
+ ISA is the list of feature bits that this FPU provides. */
+
+#ifdef CSKY_FPU
+CSKY_FPU ("fpv2_sf", fpv2_sf, CSKY_ISA_FEAT (CSKY_ISA_FPv2_SF))
+CSKY_FPU ("fpv2", fpv2, CSKY_ISA_FEAT (CSKY_ISA_FPv2))
+CSKY_FPU ("fpv2_divd", fpv2_divd, CSKY_ISA_FEAT (CSKY_ISA_FPv2_DIVD))
+#endif
diff --git a/gcc/config/csky/csky_genopt.sh b/gcc/config/csky/csky_genopt.sh
new file mode 100644
index 0000000..bf145a4
--- /dev/null
+++ b/gcc/config/csky/csky_genopt.sh
@@ -0,0 +1,97 @@
+#!/bin/sh
+# Generate csky_tables.opt from the lists in *.def.
+# Copyright (C) 2018 Free Software Foundation, Inc.
+# Contributed by C-SKY Microsystems and Mentor Graphics.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+cat <<EOF
+; -*- buffer-read-only: t -*-
+; Generated automatically by csky_genopt.sh from csky_cores.def.
+
+; Copyright (C) 2018 Free Software Foundation, Inc.
+;
+; This file is part of GCC.
+;
+; GCC is free software; you can redistribute it and/or modify it under
+; the terms of the GNU General Public License as published by the Free
+; Software Foundation; either version 3, or (at your option) any later
+; version.
+;
+; GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+; WARRANTY; without even the implied warranty of MERCHANTABILITY or
+; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+; for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with GCC; see the file COPYING3. If not see
+; <http://www.gnu.org/licenses/>.
+
+Enum
+Name(csky_processor_type) Type(enum csky_processor_type)
+Known CSKY CPUs (for use with the -mcpu= options):
+
+EOF
+
+awk -F'[(, ]+' '/^CSKY_CORE/ {
+ name = $2
+ enum = $3
+ gsub("\"", "", name)
+ print "EnumValue"
+ print "Enum(csky_processor_type) String(" name ") Value( TARGET_CPU_" enum ")"
+ print ""
+}' $1/csky_cores.def
+
+cat <<EOF
+Enum
+Name(csky_arch) Type(int)
+Known CSKY architectures (for use with the -march= option):
+
+EOF
+
+awk -F'[(, ]+' 'BEGIN {
+ value = 0
+}
+/^CSKY_ARCH/ {
+ name = $2
+ gsub("\"", "", name)
+ print "EnumValue"
+ print "Enum(csky_arch) String(" name ") Value(" value ")"
+ print ""
+ value++
+}' $1/csky_cores.def
+
+cat <<EOF
+Enum
+Name(csky_fpu) Type(enum csky_fpu_type)
+Known CSKY FPUs (for use with the -mfpu= option):
+
+EOF
+
+awk -F'[(, ]+' '
+/^CSKY_FPU/ {
+ name = $2
+ enum = $3
+ gsub("\"", "", name)
+ print "EnumValue"
+ print "Enum(csky_fpu) String(" name ") Value(TARGET_FPU_" enum ")"
+ print ""
+}
+END {
+ print "EnumValue"
+ print "Enum(csky_fpu) String(auto) Value(TARGET_FPU_auto)"
+}' $1/csky_cores.def
diff --git a/gcc/config/csky/csky_insn_dsp.md b/gcc/config/csky/csky_insn_dsp.md
new file mode 100644
index 0000000..8b972d1
--- /dev/null
+++ b/gcc/config/csky/csky_insn_dsp.md
@@ -0,0 +1,95 @@
+;; C-SKY DSP instruction descriptions.
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+;; Contributed by C-SKY Microsystems and Mentor Graphics.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>. */
+
+;; ------------------------------------------------------------
+;; DSP insns
+;; ------------------------------------------------------------
+
+(define_insn "mulsidi3"
+ [(set (match_operand:DI 0 "register_operand" "=y")
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r"))
+ (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
+ "TARGET_DSP"
+ "muls\t%1, %2"
+)
+
+(define_insn "umulsidi3"
+ [(set (match_operand:DI 0 "register_operand" "=y")
+ (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
+ (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
+ "TARGET_DSP"
+ "mulu\t%1, %2"
+)
+
+(define_insn "maddsidi4"
+ [(set (match_operand:DI 0 "register_operand" "=y")
+ (plus:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r"))
+ (sign_extend:DI (match_operand:SI 2 "register_operand" "r")))
+ (match_operand:DI 3 "register_operand" "0")))]
+ "TARGET_DSP"
+ "mulsa\t%1, %2"
+)
+
+(define_insn "umaddsidi4"
+ [(set (match_operand:DI 0 "register_operand" "=y")
+ (plus:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
+ (zero_extend:DI (match_operand:SI 2 "register_operand" "r")))
+ (match_operand:DI 3 "register_operand" "0")))]
+ "TARGET_DSP"
+ "mulua\t%1, %2"
+)
+
+(define_insn "msubsidi4"
+ [(set (match_operand:DI 0 "register_operand" "=y")
+ (minus:DI (match_operand:DI 3 "register_operand" "0")
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r"))
+ (sign_extend:DI (match_operand:SI 2 "register_operand" "r")))))]
+ "TARGET_DSP"
+ "mulss\t%1, %2"
+)
+
+(define_insn "umsubsidi4"
+ [(set (match_operand:DI 0 "register_operand" "=y")
+ (minus:DI (match_operand:DI 3 "register_operand" "0")
+ (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
+ (zero_extend:DI (match_operand:SI 2 "register_operand" "r")))))]
+ "TARGET_DSP"
+ "mulus\t%1, %2"
+)
+
+(define_insn "*mulall_s16_0"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (match_operand:SI 3 "register_operand" " 0")
+ (mult:SI (match_operand:SI 1 "register_operand" " r")
+ (match_operand:SI 2 "register_operand" " r"))))]
+ "CSKY_ISA_FEATURE (3E3r1)"
+ "mula.32.l\t%0, %1, %2"
+ [(set_attr "type" "alu")
+ (set_attr "length" "4")])
+
+(define_insn "*mulall_s16_1"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (mult:SI (match_operand:SI 1 "register_operand" " r")
+ (match_operand:SI 2 "register_operand" " r"))
+ (match_operand:SI 3 "register_operand" " 0")))]
+ "CSKY_ISA_FEATURE (3E3r1)"
+ "mula.32.l\t%0, %1, %2"
+ [(set_attr "type" "alu")
+ (set_attr "length" "4")])
diff --git a/gcc/config/csky/csky_insn_fpu.md b/gcc/config/csky/csky_insn_fpu.md
new file mode 100644
index 0000000..d188ef2
--- /dev/null
+++ b/gcc/config/csky/csky_insn_fpu.md
@@ -0,0 +1,567 @@
+;; C-SKY FPU instruction descriptions.
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+;; Contributed by C-SKY Microsystems and Mentor Graphics.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>. */
+
+;; -------------------------------------------------------------------------
+;; Float Abs instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "abssf2"
+ [(set (match_operand:SF 0 "register_operand" "=v,r")
+ (abs:SF (match_operand:SF 1 "register_operand" "v, r")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "@
+ fabss\t%0, %1
+ bclri\t%0, %1, 31")
+
+(define_insn "absdf2"
+ [(set (match_operand:DF 0 "register_operand" "=v")
+ (abs:DF (match_operand:DF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fabsd\t%0, %1")
+
+
+;; -------------------------------------------------------------------------
+;; Float Neg instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "negsf2"
+ [(set (match_operand:SF 0 "register_operand" "=v")
+ (neg:SF (match_operand:SF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fnegs\t%0, %1")
+
+(define_insn "negdf2"
+ [(set (match_operand:DF 0 "register_operand" "=v")
+ (neg:DF (match_operand:DF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fnegd\t%0, %1")
+
+
+;; -------------------------------------------------------------------------
+;; Float Sqrt instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "sqrtsf2"
+ [(set (match_operand:SF 0 "register_operand" "=v")
+ (sqrt:SF (match_operand:SF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fsqrts\t%0, %1")
+
+(define_insn "sqrtdf2"
+ [(set (match_operand:DF 0 "register_operand" "=v")
+ (sqrt:DF (match_operand:DF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_divd)"
+ "fsqrtd\t%0, %1")
+
+
+;; -------------------------------------------------------------------------
+;; Float Add instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "addsf3"
+ [(set (match_operand:SF 0 "register_operand" "=v")
+ (plus:SF (match_operand:SF 1 "register_operand" "v")
+ (match_operand:SF 2 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fadds\t%0, %1, %2")
+
+(define_insn "adddf3"
+ [(set (match_operand:DF 0 "register_operand" "=v")
+ (plus:DF (match_operand:DF 1 "register_operand" "v")
+ (match_operand:DF 2 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "faddd\t%0, %1, %2")
+
+
+;; -------------------------------------------------------------------------
+;; Float Sub instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "subsf3"
+ [(set (match_operand:SF 0 "register_operand" "=v")
+ (minus:SF (match_operand:SF 1 "register_operand" "v")
+ (match_operand:SF 2 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fsubs\t%0, %1, %2")
+
+(define_insn "subdf3"
+ [(set (match_operand:DF 0 "register_operand" "=v")
+ (minus:DF (match_operand:DF 1 "register_operand" "v")
+ (match_operand:DF 2 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fsubd\t%0, %1, %2")
+
+
+;; -------------------------------------------------------------------------
+;; Float Mul instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "mulsf3"
+ [(set (match_operand:SF 0 "register_operand" "=v")
+ (mult:SF (match_operand:SF 1 "register_operand" "v")
+ (match_operand:SF 2 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fmuls\t%0, %1, %2")
+
+(define_insn "muldf3"
+ [(set (match_operand:DF 0 "register_operand" "=v")
+ (mult:DF (match_operand:DF 1 "register_operand" "v")
+ (match_operand:DF 2 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fmuld\t%0, %1, %2")
+
+(define_insn "*fpuv2_nmulsf3_1"
+ [(set (match_operand:SF 0 "register_operand" "=v")
+ (mult:SF (neg:SF (match_operand:SF 1 "register_operand" "%v"))
+ (match_operand:SF 2 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fnmuls\t%0, %1, %2")
+
+(define_insn "*fpuv2_nmulsf3_2"
+ [(set (match_operand:SF 0 "register_operand" "=v")
+ (neg:SF (mult:SF (match_operand:SF 1 "register_operand" "v")
+ (match_operand:SF 2 "register_operand" "v"))))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fnmuls\t%0, %1, %2")
+
+(define_insn "*fpuv2_nmuldf3_1"
+ [(set (match_operand:DF 0 "register_operand" "=v")
+ (mult:DF (neg:DF (match_operand:DF 1 "register_operand" "%v"))
+ (match_operand:DF 2 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fnmuld\t%0, %1, %2")
+
+(define_insn "*fpuv2_nmuldf3_2"
+ [(set (match_operand:DF 0 "register_operand" "=v")
+ (neg:DF (mult:DF (match_operand:DF 1 "register_operand" "v")
+ (match_operand:DF 2 "register_operand" "v"))))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fnmuld\t%0, %1, %2")
+
+
+;; -------------------------------------------------------------------------
+;; Float Div instructions
+;; -------------------------------------------------------------------------
+
+(define_expand "divsf3"
+ [(set (match_operand:SF 0 "register_operand" "")
+ (div:SF (match_operand:SF 1 "csky_arith_float1_operand" "")
+ (match_operand:SF 2 "register_operand" "")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "")
+
+(define_insn "*fpuv2_divsf3"
+ [(set (match_operand:SF 0 "register_operand" "=v")
+ (div:SF (match_operand:SF 1 "register_operand" "v")
+ (match_operand:SF 2 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fdivs\t%0, %1, %2")
+
+(define_insn "*fpuv2_1_divsf3"
+ [(set (match_operand:SF 0 "register_operand" "=v")
+ (div:SF (match_operand:SF 1 "csky_const_float1_operand" "i")
+ (match_operand:SF 2 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "frecips\t%0, %2")
+
+
+(define_expand "divdf3"
+ [(set (match_operand:DF 0 "register_operand" "")
+ (div:DF (match_operand:DF 1 "csky_arith_float1_operand" "")
+ (match_operand:DF 2 "register_operand" "")))]
+ "CSKY_ISA_FEATURE (fpv2_divd)"
+ "")
+
+(define_insn "*fpuv2_divdf3"
+ [(set (match_operand:DF 0 "register_operand" "=v")
+ (div:DF (match_operand:DF 1 "register_operand" "v")
+ (match_operand:DF 2 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_divd)"
+ "fdivd\t%0, %1, %2")
+
+(define_insn "*fpuv2_1_divdf3"
+ [(set (match_operand:DF 0 "register_operand" "=v")
+ (div:DF (match_operand:DF 1 "csky_const_float1_operand" "i")
+ (match_operand:DF 2 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_divd)"
+ "frecipd\t%0, %2")
+
+
+;; -------------------------------------------------------------------------
+;; Float add(sub) with mult instructions
+;; -------------------------------------------------------------------------
+
+;; vrz <= vrz + vrx * vry
+(define_insn "*fpuv2_fmacs"
+ [(set (match_operand:SF 0 "register_operand" "=v")
+ (plus:SF (mult:SF (match_operand:SF 1 "register_operand" "v")
+ (match_operand:SF 2 "register_operand" "v"))
+ (match_operand:SF 3 "register_operand" "0")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fmacs\t%0, %1, %2")
+
+(define_insn "*fpuv2_fmacd"
+ [(set (match_operand:DF 0 "register_operand" "=v")
+ (plus:DF (mult:DF (match_operand:DF 1 "register_operand" "v")
+ (match_operand:DF 2 "register_operand" "v"))
+ (match_operand:DF 3 "register_operand" "0")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fmacd\t%0, %1, %2")
+
+;; vrz <= vrz - vrx * vry
+(define_insn "*fpuv2_fnmacs"
+ [(set (match_operand:SF 0 "register_operand" "=v")
+ (minus:SF (match_operand:SF 1 "register_operand" "0")
+ (mult:SF (match_operand:SF 2 "register_operand" "v")
+ (match_operand:SF 3 "register_operand" "v"))))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fnmacs\t%0, %2, %3")
+
+(define_insn "*fpuv2_fnmacd"
+ [(set (match_operand:DF 0 "register_operand" "=v")
+ (minus:DF (match_operand:DF 1 "register_operand" "0")
+ (mult:DF (match_operand:DF 2 "register_operand" "v")
+ (match_operand:DF 3 "register_operand" "v"))))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fnmacd\t%0, %2, %3")
+
+;; vrz <= vrx * vry - vrz
+(define_insn "*fpuv2_fmscs"
+ [(set (match_operand:SF 0 "register_operand" "=v")
+ (minus:SF (mult:SF (match_operand:SF 1 "register_operand" "v")
+ (match_operand:SF 2 "register_operand" "v"))
+ (match_operand:SF 3 "register_operand" "0")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fmscs\t%0, %1, %2")
+
+(define_insn "*fpuv2_fmscd"
+ [(set (match_operand:DF 0 "register_operand" "=v")
+ (minus:DF (mult:DF (match_operand:DF 1 "register_operand" "v")
+ (match_operand:DF 2 "register_operand" "v"))
+ (match_operand:DF 3 "register_operand" "0")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fmscd\t%0, %1, %2")
+
+;; vrz = - (vrz + vrx * vry)
+(define_insn "*fpuv2_fnmscs_1"
+ [(set (match_operand:SF 0 "register_operand" "=v")
+ (minus:SF (mult:SF (neg:SF (match_operand:SF 1 "register_operand" "%v"))
+ (match_operand:SF 2 "register_operand" "v"))
+ (match_operand:SF 3 "register_operand" "0")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fnmscs\t%0, %1, %2")
+
+(define_insn "*fpuv2_fnmscs_2"
+ [(set (match_operand:SF 0 "register_operand" "=v")
+ (neg:SF (plus:SF (mult:SF (match_operand:SF 1 "register_operand" "v")
+ (match_operand:SF 2 "register_operand" "v"))
+ (match_operand:SF 3 "register_operand" "0"))))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fnmscs\t%0, %1, %2")
+
+(define_insn "*fpuv2_fnmscd_1"
+ [(set (match_operand:DF 0 "register_operand" "=v")
+ (minus:DF (mult:DF (neg:DF (match_operand:DF 1 "register_operand" "%v"))
+ (match_operand:DF 2 "register_operand" "v"))
+ (match_operand:DF 3 "register_operand" "0")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fnmscd\t%0, %1, %2")
+
+(define_insn "*fpuv2_fnmscd_2"
+ [(set (match_operand:DF 0 "register_operand" "=v")
+ (neg:DF (plus:DF (mult:DF (match_operand:DF 1 "register_operand" "v")
+ (match_operand:DF 2 "register_operand" "v"))
+ (match_operand:DF 3 "register_operand" "0"))))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fnmscd\t%0, %1, %2")
+
+
+;; -------------------------------------------------------------------------
+;; Float compare instructions
+;; -------------------------------------------------------------------------
+
+(define_expand "cbranchsf4"
+ [(set (pc) (if_then_else (match_operator 0 "csky_float_comparison_operator"
+ [(match_operand:SF 1 "register_operand")
+ (match_operand:SF 2 "csky_compare_operand_float")])
+ (label_ref (match_operand 3 ""))
+ (pc)))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "
+ {
+ enum rtx_code code = GET_CODE (operands[0]);
+ bool invert = csky_emit_compare_float (code, operands[1], operands[2]);
+
+ if (invert)
+ emit_jump_insn (gen_csky_jbf (operands[3]));
+ else
+ emit_jump_insn (gen_csky_jbt (operands[3]));
+
+ DONE;
+ }")
+
+(define_insn "*fpuv2_unordered"
+ [(set (reg:CC 33) (unordered:CC (match_operand:SF 0 "register_operand" "v")
+ (match_operand:SF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fcmpuos\t%0, %1")
+
+(define_insn "*fpuv2_unordered_zero"
+ [(set (reg:CC 33) (unordered:CC (match_operand:SF 0 "register_operand" "v")
+ (match_operand:SF 1 "csky_const_float0_operand" "i")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fcmpuos\t%0, %0")
+
+(define_insn "*fpuv2_ne"
+ [(set (reg:CC 33) (ne:CC (match_operand:SF 0 "register_operand" "v")
+ (match_operand:SF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fcmpnes\t%0, %1")
+
+(define_insn "*fpuv2_gt"
+ [(set (reg:CC 33) (gt:CC (match_operand:SF 0 "register_operand" "v")
+ (match_operand:SF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fcmplts\t%1, %0")
+
+(define_insn "*fpuv2_ge"
+ [(set (reg:CC 33) (ge:CC (match_operand:SF 0 "register_operand" "v")
+ (match_operand:SF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fcmphss\t%0, %1")
+
+(define_insn "*fpuv2_lt"
+ [(set (reg:CC 33) (lt:CC (match_operand:SF 0 "register_operand" "v")
+ (match_operand:SF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fcmplts\t%0, %1")
+
+(define_insn "*fpuv2_le"
+ [(set (reg:CC 33) (le:CC (match_operand:SF 0 "register_operand" "v")
+ (match_operand:SF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fcmphss\t%1, %0")
+
+(define_insn "*fpuv2_gez"
+ [(set (reg:CC 33) (ge:CC (match_operand:SF 0 "register_operand" "v")
+ (match_operand:SF 1 "csky_const_float0_operand" "i")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fcmpzhss\t%0")
+
+(define_insn "*fpuv2_nez"
+ [(set (reg:CC 33) (ne:CC (match_operand:SF 0 "register_operand" "v")
+ (match_operand:SF 1 "csky_const_float0_operand" "i")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fcmpznes\t%0")
+
+
+(define_expand "cbranchdf4"
+ [(set (pc) (if_then_else (match_operator 0 "csky_float_comparison_operator"
+ [(match_operand:DF 1 "register_operand")
+ (match_operand:DF 2 "csky_compare_operand_float")])
+ (label_ref (match_operand 3 ""))
+ (pc)))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "
+ {
+ enum rtx_code code = GET_CODE (operands[0]);
+ bool invert = csky_emit_compare_float (code, operands[1], operands[2]);
+
+ if (invert)
+ emit_jump_insn (gen_csky_jbf (operands[3]));
+ else
+ emit_jump_insn (gen_csky_jbt (operands[3]));
+
+ DONE;
+}")
+
+(define_insn "*fpuv2_dunordered"
+ [(set (reg:CC 33) (unordered:CC (match_operand:DF 0 "register_operand" "v")
+ (match_operand:DF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fcmpuod\t%0, %1")
+
+(define_insn "*fpuv2_dunordered_zero"
+ [(set (reg:CC 33) (unordered:CC (match_operand:DF 0 "register_operand" "v")
+ (match_operand:DF 1 "csky_const_float0_operand" "i")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fcmpuod\t%0, %0")
+
+(define_insn "*fpuv2_dne"
+ [(set (reg:CC 33) (ne:CC (match_operand:DF 0 "register_operand" "v")
+ (match_operand:DF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fcmpned\t%0, %1")
+
+(define_insn "*fpuv2_dgt"
+ [(set (reg:CC 33) (gt:CC (match_operand:DF 0 "register_operand" "v")
+ (match_operand:DF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fcmpltd\t%1, %0")
+
+(define_insn "*fpuv2_dge"
+ [(set (reg:CC 33) (ge:CC (match_operand:DF 0 "register_operand" "v")
+ (match_operand:DF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fcmphsd\t%0, %1")
+
+(define_insn "*fpuv2_dlt"
+ [(set (reg:CC 33) (lt:CC (match_operand:DF 0 "register_operand" "v")
+ (match_operand:DF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fcmpltd\t%0, %1")
+
+(define_insn "*fpuv2_dle"
+ [(set (reg:CC 33) (le:CC (match_operand:DF 0 "register_operand" "v")
+ (match_operand:DF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fcmphsd\t%1, %0")
+
+(define_insn "*fpuv2_dgez"
+ [(set (reg:CC 33) (ge:CC (match_operand:DF 0 "register_operand" "v")
+ (match_operand:DF 1 "csky_const_float0_operand" "i")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fcmpzhsd\t%0")
+
+(define_insn "*fpuv2_dnez"
+ [(set (reg:CC 33) (ne:CC (match_operand:DF 0 "register_operand" "v")
+ (match_operand:DF 1 "csky_const_float0_operand" "i")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fcmpzned\t%0")
+
+
+;; -------------------------------------------------------------------------
+;; Float convert instructions
+;; -------------------------------------------------------------------------
+
+;; DF <- SF
+(define_insn "extendsfdf2"
+ [(set (match_operand:DF 0 "register_operand" "=v")
+ (float_extend:DF (match_operand:SF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fstod\t%0, %1")
+
+;; SF <- DF
+(define_insn "truncdfsf2"
+ [(set (match_operand:SF 0 "register_operand" "=v")
+ (float_truncate:SF (match_operand:DF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fdtos\t%0, %1")
+
+;; SF <- SI
+(define_insn "floatsisf2"
+ [(set (match_operand:SF 0 "register_operand" "=v")
+ (float:SF (match_operand:SI 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fsitos\t%0, %1")
+
+;; DF <- SI
+(define_insn "floatsidf2"
+ [(set (match_operand:DF 0 "register_operand" "=v")
+ (float:DF (match_operand:SI 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fsitod\t%0, %1")
+
+;; SF <- unsigned SI
+(define_insn "floatunssisf2"
+ [(set (match_operand:SF 0 "register_operand" "=v")
+ (unsigned_float:SF (match_operand:SI 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fuitos\t%0, %1")
+
+;; DF <- unsigned SI
+(define_insn "floatunssidf2"
+ [(set (match_operand:DF 0 "register_operand" "=v")
+ (unsigned_float:DF (match_operand:SI 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fuitod\t%0, %1")
+
+;; SI <- SF
+(define_insn "fix_truncsfsi2"
+ [(set (match_operand:SI 0 "register_operand" "=v")
+ (fix:SI (match_operand:SF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fstosi.rz\t%0, %1")
+
+;; SI <- DF
+(define_insn "fix_truncdfsi2"
+ [(set (match_operand:SI 0 "register_operand" "=v")
+ (fix:SI (match_operand:DF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fdtosi.rz\t%0, %1")
+
+;; unsigned SI <- SF
+(define_insn "fixuns_truncsfsi2"
+ [(set (match_operand:SI 0 "register_operand" "=v")
+ (unsigned_fix:SI (match_operand:SF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "fstoui.rz\t%0, %1")
+
+;; unsigned SI <- DF
+(define_insn "fixuns_truncdfsi2"
+ [(set (match_operand:SI 0 "register_operand" "=v")
+ (unsigned_fix:SI (match_operand:DF 1 "register_operand" "v")))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "fdtoui.rz\t%0, %1")
+
+
+;; -------------------------------------------------------------------------
+;; Float mov instructions
+;; -------------------------------------------------------------------------
+
+;; Note: movsf and movdf patterns are in csky.md.
+
+;; cstore SF
+(define_expand "cstoresf4"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (match_operator 1 "ordered_comparison_operator"
+ [(match_operand:SF 2 "register_operand" "")
+ (match_operand:SF 3 "csky_compare_operand_float" "")]))]
+ "CSKY_ISA_FEATURE (fpv2_sf)"
+ "
+ {
+ bool invert = csky_emit_compare_float (GET_CODE (operands[1]),
+ operands[2], operands[3]);
+ if (invert)
+ emit_insn (gen_mvcv (operands[0]));
+ else
+ emit_insn (gen_mvc (operands[0]));
+ DONE;
+ }"
+)
+
+;; cstore DF
+(define_expand "cstoredf4"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (match_operator 1 "ordered_comparison_operator"
+ [(match_operand:DF 2 "register_operand" "")
+ (match_operand:DF 3 "csky_compare_operand_float" "")]))]
+ "CSKY_ISA_FEATURE (fpv2_df)"
+ "
+ {
+ bool invert = csky_emit_compare_float (GET_CODE (operands[1]),
+ operands[2], operands[3]);
+ if (invert)
+ emit_insn (gen_mvcv (operands[0]));
+ else
+ emit_insn (gen_mvc (operands[0]));
+ DONE;
+ }"
+)
diff --git a/gcc/config/csky/csky_isa.def b/gcc/config/csky/csky_isa.def
new file mode 100644
index 0000000..d99940e
--- /dev/null
+++ b/gcc/config/csky/csky_isa.def
@@ -0,0 +1,59 @@
+/* ISA feature descriptions for the C-SKY back end.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ Contributed by C-SKY Microsystems and Mentor Graphics.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+/* Before using #include to read this file, define a macro:
+ CSKY_ISA(CNAME, DESCRIPTION)
+ */
+
+/* Common insns */
+CSKY_ISA (E1, "Extended insns for arch ck801 from base")
+CSKY_ISA (E2, "Extended insns for arch ck802 from base")
+CSKY_ISA (2E3, "Extended insns for arch ck803 from ck802")
+CSKY_ISA (3E3r1, "Extended insns for cpu ck803n from ck803")
+CSKY_ISA (3E7, "Extended insns for arch ck807 from ck803")
+CSKY_ISA (7E10, "Extended insns for arch ck810 from ck807")
+
+/* Special insns */
+CSKY_ISA (div, "divide insns")
+
+/* Extended insns */
+CSKY_ISA (dsp, "Extended insns for DSP")
+CSKY_ISA (java, "Extended insns for Java")
+
+CSKY_ISA (fpv2_sf, "Single precision operations supported")
+CSKY_ISA (fpv2_df, "Double precision operations supported")
+CSKY_ISA (fpv2_divd, "Double precision div operations supported")
+
+/* Specific insns mode */
+#ifdef CSKY_ISA_MACRO
+#define CSKY_ISA_CK801 CSKY_ISA_FEATURE_GET (E1)
+#define CSKY_ISA_CK802 CSKY_ISA_FEATURE_GET (E2)
+#define CSKY_ISA_CK803 CSKY_ISA_CK802, CSKY_ISA_FEATURE_GET (2E3), \
+ CSKY_ISA_FEATURE_GET (div)
+#define CSKY_ISA_CK803R1 CSKY_ISA_CK803, CSKY_ISA_FEATURE_GET (3E3r1)
+#define CSKY_ISA_CK807 CSKY_ISA_CK803, CSKY_ISA_FEATURE_GET (3E7)
+#define CSKY_ISA_CK810 CSKY_ISA_CK807, CSKY_ISA_FEATURE_GET (7E10)
+
+#define CSKY_ISA_DSP CSKY_ISA_FEATURE_GET (dsp)
+
+#define CSKY_ISA_FPv2_SF CSKY_ISA_FEATURE_GET (fpv2_sf)
+#define CSKY_ISA_FPv2 CSKY_ISA_FPv2_SF, CSKY_ISA_FEATURE_GET (fpv2_df)
+#define CSKY_ISA_FPv2_DIVD CSKY_ISA_FPv2, CSKY_ISA_FEATURE_GET (fpv2_divd)
+#endif
diff --git a/gcc/config/csky/csky_isa.h b/gcc/config/csky/csky_isa.h
new file mode 100644
index 0000000..24578d7
--- /dev/null
+++ b/gcc/config/csky/csky_isa.h
@@ -0,0 +1,47 @@
+/* ISA feature enumerations for C-SKY targets.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ Contributed by C-SKY Microsystems and Mentor Graphics.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_CSKY_ISA_FEATURE_H
+#define GCC_CSKY_ISA_FEATURE_H
+
+
+#ifndef CSKY_ISA_MACRO
+#define CSKY_ISA_MACRO
+#endif
+
+#define CSKY_ISA_FEATURE_DEFINE(x) isa_bit_ ## x
+#define CSKY_ISA_FEATURE_GET(x) CSKY_ISA_FEATURE_DEFINE (x)
+
+enum csky_isa_feature
+ {
+ CSKY_ISA_FEATURE_DEFINE (none),
+#undef CSKY_ISA
+#define CSKY_ISA(IDENT, DESC) \
+ CSKY_ISA_FEATURE_DEFINE (IDENT),
+#include "csky_isa.def"
+#undef CSKY_ISA
+ CSKY_ISA_FEATURE_DEFINE (max)
+ };
+
+#define CSKY_ISA_FEAT(x) x,
+#define CSKY_ISA_FEAT_NONE CSKY_ISA_FEAT (isa_bit_none)
+
+
+#endif /* GCC_CSKY_ISA_FEATURE_H */
diff --git a/gcc/config/csky/csky_opts.h b/gcc/config/csky/csky_opts.h
new file mode 100644
index 0000000..f206537
--- /dev/null
+++ b/gcc/config/csky/csky_opts.h
@@ -0,0 +1,63 @@
+/* Processor and arch enumerations for C-SKY targets.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ Contributed by C-SKY Microsystems and Mentor Graphics.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+
+#ifndef CSKY_OPTS_H
+#define CSKY_OPTS_H
+
+
+/* The various CSKY cores. */
+enum csky_processor_type
+{
+#undef CSKY_CORE
+#define CSKY_CORE(NAME, INTERNAL_IDENT, IDENT, ARCH, ISA) \
+ TARGET_CPU_##INTERNAL_IDENT,
+#include "csky_cores.def"
+#undef CSKY_CORE
+ /* Used to indicate that no processor has been specified. */
+ TARGET_CPU_csky_none
+};
+#define CSKY_TARGET_CORE_GET(name) TARGET_CPU_ ## name
+
+/* The various CSKY architectures. */
+enum csky_base_architecture
+{
+#undef CSKY_ARCH
+#define CSKY_ARCH(NAME, CORE_IDENT, ARCH, ISA) \
+ CSKY_BASE_ARCH_##ARCH,
+#include "csky_cores.def"
+#undef CSKY_ARCH
+ CSKY_BASE_ARCH_NONE
+};
+#define CSKY_TARGET_ARCH_GET(name) CSKY_BASE_ARCH_ ## name
+
+/* The various CSKY FPUs. */
+enum csky_fpu_type
+{
+#undef CSKY_FPU
+#define CSKY_FPU(NAME, CNAME, ISA) TARGET_FPU_##CNAME,
+#include "csky_cores.def"
+ TARGET_FPU_auto
+#undef CSKY_FPU
+};
+#define CSKY_TARGET_FPU_GET(name) TARGET_FPU_ ## name
+
+
+#endif /* CSKY_OPTS_H */
diff --git a/gcc/config/csky/csky_pipeline_ck801.md b/gcc/config/csky/csky_pipeline_ck801.md
new file mode 100644
index 0000000..00fc465
--- /dev/null
+++ b/gcc/config/csky/csky_pipeline_ck801.md
@@ -0,0 +1,54 @@
+;; Scheduler information for C-SKY CK801 processors.
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+;; Contributed by C-SKY Microsystems and Mentor Graphics.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>. */
+
+;; This is just a placeholder for a more accurate pipeline
+;; description for CK801.
+
+(define_automaton "ck801")
+
+(define_cpu_unit "ck801_ex1" "ck801")
+(define_cpu_unit "ck801_exit" "ck801")
+
+(define_insn_reservation "ck801_generic" 1
+ (and (match_test "CSKY_TARGET_ARCH (CK801)")
+ (eq_attr "type" "alu,cmp,branch,cbranch,addsub,alu_ix,branch_jmp,call_jsr,call"))
+ "ck801_ex1+ck801_exit")
+
+(define_insn_reservation "ck801_load" 1
+ (and (match_test "CSKY_TARGET_ARCH (CK801)")
+ (and (eq_attr "type" "load")
+ (match_test "!csky_minipool_load_p (insn)")))
+ "ck801_ex1+ck801_exit")
+
+(define_insn_reservation "ck801_pool" 1
+ (and (match_test "CSKY_TARGET_ARCH (CK801)")
+ (and (eq_attr "type" "load")
+ (match_test "csky_minipool_load_p (insn)")))
+ "ck801_ex1+ck801_exit")
+
+(define_insn_reservation "ck801_store" 1
+ (and (match_test "CSKY_TARGET_ARCH (CK801)")
+ (eq_attr "type" "store"))
+ "ck801_ex1+ck801_exit")
+
+;; Switching between constant pool loads and loads/stores in the data section
+;; carries an extra penalty.
+(define_bypass 2 "ck801_load,ck801_store" "ck801_pool")
+(define_bypass 2 "ck801_pool" "ck801_load,ck801_store")
diff --git a/gcc/config/csky/csky_pipeline_ck802.md b/gcc/config/csky/csky_pipeline_ck802.md
new file mode 100644
index 0000000..f185d8c
--- /dev/null
+++ b/gcc/config/csky/csky_pipeline_ck802.md
@@ -0,0 +1,77 @@
+;; Instruction scheduling information for C-SKY CK802 processors.
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+;; Contributed by C-SKY Microsystems and Mentor Graphics.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>. */
+
+(define_automaton "csky_ck802")
+
+(define_cpu_unit "csky_ck802_ex" "csky_ck802")
+(define_cpu_unit "csky_ck802_wb" "csky_ck802")
+
+(define_insn_reservation "ck802_alu" 2
+ (and (match_test "CSKY_TARGET_ARCH (CK802)")
+ (eq_attr "type" "alu"))
+ "csky_ck802_ex, csky_ck802_wb")
+
+(define_insn_reservation "ck802_branch" 2
+ (and (match_test "CSKY_TARGET_ARCH (CK802)")
+ (eq_attr "type" "branch, branch_jmp"))
+ "csky_ck802_ex, csky_ck802_wb")
+
+(define_insn_reservation "ck802_cmp" 2
+ (and (match_test "CSKY_TARGET_ARCH (CK802)")
+ (eq_attr "type" "cmp"))
+ "csky_ck802_ex, csky_ck802_wb")
+
+(define_insn_reservation "ck802_cbranch" 2
+ (and (match_test "CSKY_TARGET_ARCH (CK802)")
+ (eq_attr "type" "cbranch"))
+ "csky_ck802_ex, csky_ck802_wb")
+
+(define_insn_reservation "ck802_call" 2
+ (and (match_test "CSKY_TARGET_ARCH (CK802)")
+ (eq_attr "type" "call, call_jsr"))
+ "csky_ck802_ex, csky_ck802_wb")
+
+(define_insn_reservation "ck802_load" 2
+ (and (match_test "CSKY_TARGET_ARCH (CK802)")
+ (and (eq_attr "type" "load")
+ (match_test "!csky_minipool_load_p (insn)")))
+ "csky_ck802_ex, csky_ck802_wb")
+
+(define_insn_reservation "ck802_pool" 2
+ (and (match_test "CSKY_TARGET_ARCH (CK802)")
+ (and (eq_attr "type" "load")
+ (match_test "csky_minipool_load_p (insn)")))
+ "csky_ck802_ex, csky_ck802_wb")
+
+(define_insn_reservation "ck802_store" 2
+ (and (match_test "CSKY_TARGET_ARCH (CK802)")
+ (eq_attr "type" "store"))
+ "csky_ck802_ex, csky_ck802_wb")
+
+;; Switching between constant pool loads and loads/stores in the data section
+;; carries an extra penalty.
+(define_bypass 3 "ck802_load,ck802_store" "ck802_pool")
+(define_bypass 3 "ck802_pool" "ck802_load,ck802_store")
+
+(define_bypass 1 "*" "ck802_alu")
+
+(define_bypass 1 "*" "ck802_branch")
+
+(define_bypass 2 "ck802_cmp" "ck802_cbranch")
diff --git a/gcc/config/csky/csky_pipeline_ck803.md b/gcc/config/csky/csky_pipeline_ck803.md
new file mode 100644
index 0000000..f140cf6
--- /dev/null
+++ b/gcc/config/csky/csky_pipeline_ck803.md
@@ -0,0 +1,64 @@
+;; Scheduler information for C-SKY CK803 processors.
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+;; Contributed by C-SKY Microsystems and Mentor Graphics.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>. */
+
+(define_automaton "ck803")
+
+(define_cpu_unit "ck803_ex1" "ck803")
+(define_cpu_unit "ck803_exit" "ck803")
+
+(define_insn_reservation "ck803_3cycle" 1
+ (and (match_test "CSKY_TARGET_ARCH (CK803)")
+ (eq_attr "type" "alu,cmp,branch,branch_jmp,call_jsr,call"))
+ "ck803_ex1+ck803_exit")
+
+(define_insn_reservation "ck803_alu1" 1
+ (and (match_test "CSKY_TARGET_ARCH (CK803)")
+ (eq_attr "type" "addsub,alu_ix"))
+ "ck803_ex1+ck803_exit")
+
+(define_insn_reservation "ck803_cbranch" 1
+ (and (match_test "CSKY_TARGET_ARCH (CK803)")
+ (eq_attr "type" "cbranch"))
+ "ck803_ex1+ck803_exit")
+
+(define_insn_reservation "ck803_load" 1
+ (and (match_test "CSKY_TARGET_ARCH (CK803)")
+ (and (eq_attr "type" "load")
+ (match_test "!csky_minipool_load_p (insn)")))
+ "ck803_ex1+ck803_exit")
+
+(define_insn_reservation "ck803_pool" 1
+ (and (match_test "CSKY_TARGET_ARCH (CK803)")
+ (and (eq_attr "type" "load")
+ (match_test "csky_minipool_load_p (insn)")))
+ "ck803_ex1+ck803_exit")
+
+(define_insn_reservation "ck803_store" 1
+ (and (match_test "CSKY_TARGET_ARCH (CK803)")
+ (eq_attr "type" "store"))
+ "ck803_ex1+ck803_exit")
+
+;; Switching between constant pool loads and loads/stores in the data section
+;; carries an extra penalty.
+(define_bypass 2 "ck803_load,ck803_store" "ck803_pool")
+(define_bypass 2 "ck803_pool" "ck803_load,ck803_store")
+
+(define_bypass 2 "ck803_3cycle,ck803_cbranch,ck803_load,ck803_store,ck803_pool"
+ "ck803_cbranch")
diff --git a/gcc/config/csky/csky_pipeline_ck810.md b/gcc/config/csky/csky_pipeline_ck810.md
new file mode 100644
index 0000000..aaba00b
--- /dev/null
+++ b/gcc/config/csky/csky_pipeline_ck810.md
@@ -0,0 +1,34 @@
+;; Instruction scheduling information for C-SKY CK810 processors.
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+;; Contributed by C-SKY Microsystems and Mentor Graphics.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>. */
+
+
+;;-------------------------------------------------------------
+;; Pipeline descriptions for ck810
+;;-------------------------------------------------------------
+
+(define_attr "cycle" "1,2,not_used_yet"
+ (const_string "1"))
+(define_automaton "cskyv2_ck810")
+(define_cpu_unit "pipeline_alu0" "cskyv2_ck810")
+(define_insn_reservation "alu_one_cycle" 1
+ (and (eq_attr "cycle" "1")
+ (not (ior (match_test "CSKY_TARGET_ARCH (CK803)")
+ (match_test "CSKY_TARGET_ARCH (CK802)"))))
+ "pipeline_alu0")
diff --git a/gcc/config/csky/csky_tables.opt b/gcc/config/csky/csky_tables.opt
new file mode 100644
index 0000000..ae3438d
--- /dev/null
+++ b/gcc/config/csky/csky_tables.opt
@@ -0,0 +1,230 @@
+; -*- buffer-read-only: t -*-
+; Generated automatically by csky_genopt.sh from csky_cores.def.
+
+; Copyright (C) 2018 Free Software Foundation, Inc.
+;
+; This file is part of GCC.
+;
+; GCC is free software; you can redistribute it and/or modify it under
+; the terms of the GNU General Public License as published by the Free
+; Software Foundation; either version 3, or (at your option) any later
+; version.
+;
+; GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+; WARRANTY; without even the implied warranty of MERCHANTABILITY or
+; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+; for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with GCC; see the file COPYING3. If not see
+; <http://www.gnu.org/licenses/>.
+
+Enum
+Name(csky_processor_type) Type(enum csky_processor_type)
+Known CSKY CPUs (for use with the -mcpu= options):
+
+EnumValue
+Enum(csky_processor_type) String(ck801) Value( TARGET_CPU_ck801)
+
+EnumValue
+Enum(csky_processor_type) String(ck801t) Value( TARGET_CPU_ck801t)
+
+EnumValue
+Enum(csky_processor_type) String(ck802) Value( TARGET_CPU_ck802)
+
+EnumValue
+Enum(csky_processor_type) String(ck802t) Value( TARGET_CPU_ck802t)
+
+EnumValue
+Enum(csky_processor_type) String(ck802j) Value( TARGET_CPU_ck802j)
+
+EnumValue
+Enum(csky_processor_type) String(ck803) Value( TARGET_CPU_ck803)
+
+EnumValue
+Enum(csky_processor_type) String(ck803h) Value( TARGET_CPU_ck803h)
+
+EnumValue
+Enum(csky_processor_type) String(ck803t) Value( TARGET_CPU_ck803t)
+
+EnumValue
+Enum(csky_processor_type) String(ck803ht) Value( TARGET_CPU_ck803ht)
+
+EnumValue
+Enum(csky_processor_type) String(ck803f) Value( TARGET_CPU_ck803f)
+
+EnumValue
+Enum(csky_processor_type) String(ck803fh) Value( TARGET_CPU_ck803fh)
+
+EnumValue
+Enum(csky_processor_type) String(ck803e) Value( TARGET_CPU_ck803e)
+
+EnumValue
+Enum(csky_processor_type) String(ck803eh) Value( TARGET_CPU_ck803eh)
+
+EnumValue
+Enum(csky_processor_type) String(ck803et) Value( TARGET_CPU_ck803et)
+
+EnumValue
+Enum(csky_processor_type) String(ck803eht) Value( TARGET_CPU_ck803eht)
+
+EnumValue
+Enum(csky_processor_type) String(ck803ef) Value( TARGET_CPU_ck803ef)
+
+EnumValue
+Enum(csky_processor_type) String(ck803efh) Value( TARGET_CPU_ck803efh)
+
+EnumValue
+Enum(csky_processor_type) String(ck803ft) Value( TARGET_CPU_ck803ft)
+
+EnumValue
+Enum(csky_processor_type) String(ck803eft) Value( TARGET_CPU_ck803eft)
+
+EnumValue
+Enum(csky_processor_type) String(ck803efht) Value( TARGET_CPU_ck803efht)
+
+EnumValue
+Enum(csky_processor_type) String(ck803r1) Value( TARGET_CPU_ck803r1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803hr1) Value( TARGET_CPU_ck803hr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803tr1) Value( TARGET_CPU_ck803tr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803htr1) Value( TARGET_CPU_ck803htr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803fr1) Value( TARGET_CPU_ck803fr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803fhr1) Value( TARGET_CPU_ck803fhr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803er1) Value( TARGET_CPU_ck803er1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803ehr1) Value( TARGET_CPU_ck803ehr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803etr1) Value( TARGET_CPU_ck803etr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803ehtr1) Value( TARGET_CPU_ck803ehtr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803efr1) Value( TARGET_CPU_ck803efr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803efhr1) Value( TARGET_CPU_ck803efhr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803ftr1) Value( TARGET_CPU_ck803ftr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803eftr1) Value( TARGET_CPU_ck803eftr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803efhtr1) Value( TARGET_CPU_ck803efhtr1)
+
+EnumValue
+Enum(csky_processor_type) String(ck803s) Value( TARGET_CPU_ck803s)
+
+EnumValue
+Enum(csky_processor_type) String(ck803st) Value( TARGET_CPU_ck803st)
+
+EnumValue
+Enum(csky_processor_type) String(ck803se) Value( TARGET_CPU_ck803se)
+
+EnumValue
+Enum(csky_processor_type) String(ck803sf) Value( TARGET_CPU_ck803sf)
+
+EnumValue
+Enum(csky_processor_type) String(ck803sef) Value( TARGET_CPU_ck803sef)
+
+EnumValue
+Enum(csky_processor_type) String(ck803seft) Value( TARGET_CPU_ck803seft)
+
+EnumValue
+Enum(csky_processor_type) String(ck807e) Value( TARGET_CPU_ck807e)
+
+EnumValue
+Enum(csky_processor_type) String(ck807ef) Value( TARGET_CPU_ck807ef)
+
+EnumValue
+Enum(csky_processor_type) String(ck807) Value( TARGET_CPU_ck807)
+
+EnumValue
+Enum(csky_processor_type) String(ck807f) Value( TARGET_CPU_ck807f)
+
+EnumValue
+Enum(csky_processor_type) String(ck810e) Value( TARGET_CPU_ck810e)
+
+EnumValue
+Enum(csky_processor_type) String(ck810et) Value( TARGET_CPU_ck810et)
+
+EnumValue
+Enum(csky_processor_type) String(ck810ef) Value( TARGET_CPU_ck810ef)
+
+EnumValue
+Enum(csky_processor_type) String(ck810eft) Value( TARGET_CPU_ck810eft)
+
+EnumValue
+Enum(csky_processor_type) String(ck810) Value( TARGET_CPU_ck810)
+
+EnumValue
+Enum(csky_processor_type) String(ck810v) Value( TARGET_CPU_ck810v)
+
+EnumValue
+Enum(csky_processor_type) String(ck810f) Value( TARGET_CPU_ck810f)
+
+EnumValue
+Enum(csky_processor_type) String(ck810t) Value( TARGET_CPU_ck810t)
+
+EnumValue
+Enum(csky_processor_type) String(ck810fv) Value( TARGET_CPU_ck810fv)
+
+EnumValue
+Enum(csky_processor_type) String(ck810tv) Value( TARGET_CPU_ck810tv)
+
+EnumValue
+Enum(csky_processor_type) String(ck810ft) Value( TARGET_CPU_ck810ff)
+
+EnumValue
+Enum(csky_processor_type) String(ck810ftv) Value( TARGET_CPU_ck810ftv)
+
+Enum
+Name(csky_arch) Type(int)
+Known CSKY architectures (for use with the -march= option):
+
+EnumValue
+Enum(csky_arch) String(ck801) Value(0)
+
+EnumValue
+Enum(csky_arch) String(ck802) Value(1)
+
+EnumValue
+Enum(csky_arch) String(ck803) Value(2)
+
+EnumValue
+Enum(csky_arch) String(ck807) Value(3)
+
+EnumValue
+Enum(csky_arch) String(ck810) Value(4)
+
+Enum
+Name(csky_fpu) Type(enum csky_fpu_type)
+Known CSKY FPUs (for use with the -mfpu= option):
+
+EnumValue
+Enum(csky_fpu) String(fpv2_sf) Value(TARGET_FPU_fpv2_sf)
+
+EnumValue
+Enum(csky_fpu) String(fpv2) Value(TARGET_FPU_fpv2)
+
+EnumValue
+Enum(csky_fpu) String(fpv2_divd) Value(TARGET_FPU_fpv2_divd)
+
+EnumValue
+Enum(csky_fpu) String(auto) Value(TARGET_FPU_auto)
diff --git a/gcc/config/csky/predicates.md b/gcc/config/csky/predicates.md
new file mode 100644
index 0000000..2899f0b
--- /dev/null
+++ b/gcc/config/csky/predicates.md
@@ -0,0 +1,298 @@
+;; Predicates for C-SKY.
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+;; Contributed by C-SKY Microsystems and Mentor Graphics.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>. */
+
+;; Return 1 if OP is a load multiple operation.
+
+(define_predicate "csky_load_multiple_operation"
+ (match_code "parallel")
+{
+ int count = XVECLEN (op, 0);
+ int dest_regno;
+ rtx src_addr;
+ int i;
+
+ /* Perform a quick check so we don't blow up below. */
+ if (count <= 1
+ || GET_CODE (XVECEXP (op, 0, 0)) != SET
+ || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
+ || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM
+ || GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0)) != REG
+ || XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0) != stack_pointer_rtx)
+ return 0;
+
+ dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
+ src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
+
+ for (i = 1; i < count; i++)
+ {
+ rtx elt = XVECEXP (op, 0, i);
+
+ if (GET_CODE (elt) != SET
+ || GET_CODE (SET_DEST (elt)) != REG
+ || GET_MODE (SET_DEST (elt)) != SImode
+ || REGNO (SET_DEST (elt)) != (unsigned) (dest_regno + i)
+ || GET_CODE (SET_SRC (elt)) != MEM
+ || GET_MODE (SET_SRC (elt)) != SImode
+ || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
+ || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
+ || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
+ || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != i * 4)
+ return 0;
+ }
+ return 1;
+})
+
+;; Similar, for store multiple.
+
+(define_predicate "csky_store_multiple_operation"
+ (match_code "parallel")
+{
+ int count = XVECLEN (op, 0);
+ int src_regno;
+ rtx dest_addr;
+ int i;
+
+ /* Perform a quick check so we don't blow up below. */
+ if (count <= 1
+ || GET_CODE (XVECEXP (op, 0, 0)) != SET
+ || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM
+ || GET_CODE (XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0)) != REG
+ || XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0) != stack_pointer_rtx
+ || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG)
+ return 0;
+
+ src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
+ dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
+
+ for (i = 1; i < count; i++)
+ {
+ rtx elt = XVECEXP (op, 0, i);
+
+ if (GET_CODE (elt) != SET
+ || GET_CODE (SET_SRC (elt)) != REG
+ || GET_MODE (SET_SRC (elt)) != SImode
+ || REGNO (SET_SRC (elt)) != (unsigned) (src_regno + i)
+ || GET_CODE (SET_DEST (elt)) != MEM
+ || GET_MODE (SET_DEST (elt)) != SImode
+ || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
+ || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
+ || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
+ || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != i * 4)
+ return 0;
+ }
+ return 1;
+})
+
+
+(define_predicate "csky_arith_K_operand"
+ (match_code "reg,subreg,const_int")
+ {
+ if (register_operand (op, mode))
+ return 1;
+ if (CONST_INT_P (op) && CSKY_CONST_OK_FOR_K (INTVAL (op)))
+ return 1;
+ return 0;
+ })
+
+(define_predicate "csky_literal_K_operand"
+ (match_code "const_int")
+ {
+ if (CONST_INT_P (op) && CSKY_CONST_OK_FOR_K (INTVAL (op)))
+ return 1;
+ return 0;
+ })
+
+(define_predicate "csky_literal_I_operand"
+ (match_code "const_int")
+ {
+ if (CONST_INT_P (op) && CSKY_CONST_OK_FOR_I (INTVAL (op)))
+ return 1;
+ return 0;
+ })
+
+(define_predicate "csky_literal_J_operand"
+ (match_code "const_int")
+ {
+ if (CONST_INT_P (op) && CSKY_CONST_OK_FOR_J (INTVAL (op)))
+ return 1;
+ return 0;
+ })
+
+(define_predicate "csky_literal_Uk_operand"
+ (match_code "const_int")
+ {
+ if (CONST_INT_P (op) && CSKY_CONST_OK_FOR_Uk (INTVAL (op)))
+ return 1;
+ return 0;
+ })
+
+;; Nonzero if OP is a register or constant value of 1
+
+(define_predicate "csky_arith_int1_operand"
+ (match_code "reg,subreg,const_int")
+ {
+ if (register_operand (op, mode))
+ return 1;
+ if (op == const1_rtx)
+ return 1;
+ return 0;
+ })
+
+
+;; Nonzero if OP is legal address for function call
+
+(define_predicate "csky_call_address_operand"
+ (match_code "reg,subreg,symbol_ref")
+ {
+ if (!flag_pic && (GET_CODE (op) == SYMBOL_REF))
+ return 1;
+ if (register_operand (op, mode))
+ return 1;
+ return 0;
+ })
+
+;; Nonzero if OP is a valid source operand for a compare operation.
+
+(define_predicate "csky_compare_operand"
+ (match_code "const_int,reg,subreg")
+ {
+ if (register_operand (op, mode))
+ return 1;
+ if (GET_CODE (op) == CONST_INT && INTVAL (op) == 0)
+ return 1;
+ return 0;
+ })
+
+(define_predicate "csky_literal_K_Uh_operand"
+ (match_code "const_int")
+ {
+ if (CONST_INT_P (op)
+ && (CSKY_CONST_OK_FOR_K (INTVAL (op))
+ || CSKY_CONST_OK_FOR_Uh (INTVAL (op))))
+ return 1;
+ return 0;
+ })
+
+;; True if OP is a mem with an reg + optional displacement address.
+
+(define_predicate "csky_simple_mem_operand"
+ (and (match_operand 0 "memory_operand")
+ (match_test "csky_simple_addr_operand_p (XEXP (op, 0))")))
+
+(define_predicate "csky_arith_any_imm_operand"
+ (match_code "const_int,reg,subreg")
+ {
+ if (register_operand (op, mode))
+ return 1;
+ if (CONST_INT_P (op))
+ return 1;
+ return 0;
+ })
+
+(define_predicate "csky_arith_O_operand"
+ (match_code "reg,subreg,const_int")
+ {
+ if (register_operand (op, mode))
+ return 1;
+ if (CONST_INT_P (op) && CSKY_CONST_OK_FOR_O (INTVAL (op)))
+ return 1;
+ return 0;
+ })
+
+(define_predicate "csky_unspec_operand"
+ (match_code "unspec")
+ {
+ if (op == NULL || GET_CODE(op) != UNSPEC)
+ return 0;
+ return 1;
+ }
+)
+
+(define_predicate "csky_const_float1_operand"
+ (and (match_code "const_double")
+ (match_test "(op == CONST1_RTX (mode))")))
+
+(define_predicate "csky_arith_float1_operand"
+ (ior (match_operand 0 "register_operand")
+ (match_operand 0 "csky_const_float1_operand")))
+
+(define_predicate "csky_const_float0_operand"
+ (and (match_code "const_double")
+ (match_test "(op == CONST0_RTX (mode))")))
+
+(define_predicate "csky_compare_operand_float"
+ (ior (match_operand 0 "register_operand")
+ (match_operand 0 "csky_const_float0_operand")))
+
+(define_special_predicate "registers_push"
+ (match_code "parallel")
+{
+ if ((GET_CODE (XVECEXP (op, 0, 0)) != SET)
+ || (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC)
+ || (XINT (SET_SRC (XVECEXP (op, 0, 0)), 1) != UNSPEC_PUSHPOP_MULT))
+ return false;
+ return true;
+})
+
+(define_special_predicate "registers_pop"
+ (match_code "parallel")
+{
+ if ((GET_CODE (XVECEXP (op, 0, 1)) != SET)
+ || (GET_CODE (SET_SRC (XVECEXP (op, 0, 1))) != UNSPEC)
+ || (XINT (SET_SRC (XVECEXP (op, 0, 1)), 1) != UNSPEC_PUSHPOP_MULT))
+ return false;
+ return true;
+})
+
+(define_predicate "push_memory_operand"
+ (match_code "mem")
+{
+ rtx x = XEXP (op, 0);
+ if (GET_CODE (x) != PRE_MODIFY)
+ return false;
+ if (XEXP (x, 0) != stack_pointer_rtx)
+ return false;
+ x = XEXP (x, 1);
+ if (GET_CODE (x) != PLUS)
+ return false;
+ if (XEXP (x, 0) != stack_pointer_rtx)
+ return false;
+ return CONST_INT_P (XEXP (x, 1));
+})
+
+(define_predicate "pop_memory_operand"
+ (match_code "mem")
+{
+ rtx x = XEXP (op, 0);
+ if (GET_CODE (x) != POST_MODIFY)
+ return false;
+ if (XEXP (x, 0) != stack_pointer_rtx)
+ return false;
+ x = XEXP (x, 1);
+ if (GET_CODE (x) != PLUS)
+ return false;
+ if (XEXP (x, 0) != stack_pointer_rtx)
+ return false;
+ return CONST_INT_P (XEXP (x, 1));
+})
+
+(define_special_predicate "csky_float_comparison_operator"
+ (match_code "eq,ne,le,lt,ge,gt,geu,gtu,leu,ltu,
+ unordered,ordered"))
diff --git a/gcc/config/csky/print-sysroot-suffix.sh b/gcc/config/csky/print-sysroot-suffix.sh
new file mode 100644
index 0000000..5cbdc3f
--- /dev/null
+++ b/gcc/config/csky/print-sysroot-suffix.sh
@@ -0,0 +1,147 @@
+#! /bin/sh
+# Script to generate SYSROOT_SUFFIX_SPEC equivalent to MULTILIB_OSDIRNAMES
+# Arguments are MULTILIB_OSDIRNAMES, MULTILIB_OPTIONS and MULTILIB_MATCHES.
+
+# Copyright (C) 2018 Free Software Foundation, Inc.
+# Contributed by C-SKY Microsystems and Mentor Graphics.
+
+# This file is part of GCC.
+
+# GCC is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 3, or (at your option) any later
+# version.
+
+# GCC is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# This shell script produces a header file fragment that defines
+# SYSROOT_SUFFIX_SPEC. It assumes that the sysroots will have the same
+# structure and names used by the multilibs.
+
+# Invocation:
+# print-sysroot-suffix.sh \
+# MULTILIB_OSDIRNAMES \
+# MULTILIB_OPTIONS \
+# MULTILIB_MATCHES \
+# > t-sysroot-suffix.h
+
+# The three options exactly correspond to the variables of the same
+# names defined in the tmake_file fragments.
+
+# Example:
+# sh ./gcc/config/print-sysroot-suffix.sh "a=A" "a b/c/d" ""
+# =>
+# #undef SYSROOT_SUFFIX_SPEC
+# #define SYSROOT_SUFFIX_SPEC "" \
+# "%{a:" \
+# "%{b:A/b/;" \
+# "c:A/c/;" \
+# "d:A/d/;" \
+# ":A/};" \
+# ":}"
+
+# The script uses temporary subscripts in order to permit a recursive
+# algorithm without the use of functions.
+
+set -e
+
+dirnames="$1"
+options="$2"
+matches="$3"
+
+cat > print-sysroot-suffix3.sh <<\EOF
+#! /bin/sh
+# Print all the multilib matches for this option
+result="$1"
+EOF
+for x in $matches; do
+ l=`echo $x | sed -e 's/=.*$//' -e 's/?/=/g'`
+ r=`echo $x | sed -e 's/^.*=//' -e 's/?/=/g'`
+ echo "[ \"\$1\" = \"$l\" ] && result=\"\$result|$r\"" >> print-sysroot-suffix3.sh
+done
+echo 'echo $result' >> print-sysroot-suffix3.sh
+chmod +x print-sysroot-suffix3.sh
+
+cat > print-sysroot-suffix2.sh <<\EOF
+#! /bin/sh
+# Recursive script to enumerate all multilib combinations, match against
+# multilib directories and output a spec string of the result.
+# Will fold identical trees.
+
+padding="$1"
+optstring="$2"
+shift 2
+n="\" \\
+$padding\""
+if [ $# = 0 ]; then
+EOF
+
+pat=
+for x in $dirnames; do
+# p=`echo $x | sed -e 's,=!,/$=/,'`
+ p=`echo $x | sed -e 's/=//g'`
+# pat="$pat -e 's=^//$p='"
+ pat="$pat -e 's/$p/g'"
+done
+echo ' optstring=`echo "/$optstring" | sed '"$pat\`" >> print-sysroot-suffix2.sh
+cat >> print-sysroot-suffix2.sh <<\EOF
+ case $optstring in
+ //*)
+ ;;
+ *)
+ echo "$optstring"
+ ;;
+ esac
+else
+ thisopt="$1"
+ shift
+ bit=
+ lastcond=
+ result=
+ for x in `echo "$thisopt" | sed -e 's,/, ,g'`; do
+ case $x in
+EOF
+for x in `echo "$options" | sed -e 's,/, ,g'`; do
+ match=`./print-sysroot-suffix3.sh "$x"`
+ echo "$x) optmatch=\"$match\" ;;" >> print-sysroot-suffix2.sh
+done
+cat >> print-sysroot-suffix2.sh <<\EOF
+ esac
+ bit=`"$0" "$padding " "$optstring$x/" "$@"`
+ if [ -z "$lastopt" ]; then
+ lastopt="$optmatch"
+ else
+ if [ "$lastbit" = "$bit" ]; then
+ lastopt="$lastopt|$optmatch"
+ else
+ result="$result$lastopt:$lastbit;$n"
+ lastopt="$optmatch"
+ fi
+ fi
+ lastbit="$bit"
+ done
+ bit=`"$0" "$padding " "$optstring" "$@"`
+ if [ "$bit" = "$lastbit" ]; then
+ if [ -z "$result" ]; then
+ echo "$bit"
+ else
+ echo "$n%{$result:$bit}"
+ fi
+ else
+ echo "$n%{$result$lastopt:$lastbit;$n:$bit}"
+ fi
+fi
+EOF
+chmod +x ./print-sysroot-suffix2.sh
+result=`./print-sysroot-suffix2.sh \"\" \"\" $options`
+echo "#undef SYSROOT_SUFFIX_SPEC"
+echo "#define SYSROOT_SUFFIX_SPEC \"$result\""
+rm print-sysroot-suffix2.sh
+rm print-sysroot-suffix3.sh
diff --git a/gcc/config/csky/t-csky b/gcc/config/csky/t-csky
new file mode 100644
index 0000000..ab9be18
--- /dev/null
+++ b/gcc/config/csky/t-csky
@@ -0,0 +1,29 @@
+# Make rules for all C-SKY targets.
+#
+# Copyright (C) 2018 Free Software Foundation, Inc.
+# Contributed by C-SKY Microsystems and Mentor Graphics.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+TM_H += $(srcdir)/config/csky/csky_cores.def
+OPTIONS_H_EXTRA += $(srcdir)/config/csky/csky_cores.def
+
+
+$(srcdir)/config/csky/csky_tables.opt: $(srcdir)/config/csky/csky_genopt.sh \
+ $(srcdir)/config/csky/csky_cores.def
+ $(SHELL) $(srcdir)/config/csky/csky_genopt.sh $(srcdir)/config/csky > \
+ $(srcdir)/config/csky/csky_tables.opt
diff --git a/gcc/config/csky/t-csky-elf b/gcc/config/csky/t-csky-elf
new file mode 100644
index 0000000..6864544
--- /dev/null
+++ b/gcc/config/csky/t-csky-elf
@@ -0,0 +1,107 @@
+# Multilib configuration for csky*-elf.
+#
+# Copyright (C) 2018 Free Software Foundation, Inc.
+# Contributed by C-SKY Microsystems and Mentor Graphics.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# Endiannesses.
+MULTILIB_OPTIONS = mlittle-endian/mbig-endian
+MULTILIB_DIRNAMES = little big
+MULTILIB_MATCHES = mlittle-endian=EL
+MULTILIB_MATCHES = mbig-endian=EB
+MULTILIB_EXCEPTIONS =
+
+# Arch variants.
+MULTILIB_OPTIONS += mcpu=ck802/mcpu=ck801/mcpu=ck803f/mcpu=ck807f/mcpu=ck810f
+MULTILIB_DIRNAMES += ck802 ck801 ck803 ck807 ck810
+
+# For arch ck802.
+MULTILIB_MATCHES += mcpu?ck802=march?ck802
+MULTILIB_MATCHES += mcpu?ck802=mcpu?ck802t
+MULTILIB_MATCHES += mcpu?ck802=mcpu?ck802j
+
+# For arch ck801.
+MULTILIB_MATCHES += mcpu?ck801=march?ck801
+MULTILIB_MATCHES += mcpu?ck801=mcpu?ck801t
+
+# For arch ck803.
+MULTILIB_MATCHES += mcpu?ck803f=march?ck803
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803fh
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803h
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803t
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803ht
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803e
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803eh
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803et
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803eht
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803ef
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803efh
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803ft
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803eft
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803efht
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803r1
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803fr1
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803fhr1
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803hr1
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803tr1
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803htr1
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803er1
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803ehr1
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803etr1
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803ehtr1
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803efr1
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803efhr1
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803ftr1
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803eftr1
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803efhtr1
+
+# For arch ck803s.
+MULTILIB_MATCHES += mcpu?ck803f=march?ck803s
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803s
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803st
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803se
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803sf
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803sef
+MULTILIB_MATCHES += mcpu?ck803f=mcpu?ck803seft
+
+# For arch ck810.
+MULTILIB_MATCHES += mcpu?ck810f=mcpu?ck810e
+MULTILIB_MATCHES += mcpu?ck810f=mcpu?ck810et
+MULTILIB_MATCHES += mcpu?ck810f=mcpu?ck810ef
+MULTILIB_MATCHES += mcpu?ck810f=mcpu?ck810eft
+MULTILIB_MATCHES += mcpu?ck810f=march?ck810
+MULTILIB_MATCHES += mcpu?ck810f=mcpu?ck810
+MULTILIB_MATCHES += mcpu?ck810f=mcpu?ck810v
+MULTILIB_MATCHES += mcpu?ck810f=mcpu?ck810t
+MULTILIB_MATCHES += mcpu?ck810f=mcpu?ck810vf
+MULTILIB_MATCHES += mcpu?ck810f=mcpu?ck810tv
+MULTILIB_MATCHES += mcpu?ck810f=mcpu?ck810ft
+MULTILIB_MATCHES += mcpu?ck810f=mcpu?ck810ftv
+
+# For arch ck807.
+MULTILIB_MATCHES += mcpu?ck807f=march?ck807e
+MULTILIB_MATCHES += mcpu?ck807f=march?ck807ef
+MULTILIB_MATCHES += mcpu?ck807f=march?ck807
+MULTILIB_MATCHES += mcpu?ck807f=mcpu?ck807
+
+# For option -msoft-float/-mhard-float.
+MULTILIB_OPTIONS += msoft-float/mhard-float
+MULTILIB_DIRNAMES += soft-fp hard-fp
+MULTILIB_EXCEPTIONS += *mcpu=ck801/*mhard-float*
+MULTILIB_EXCEPTIONS += *mcpu=ck802/*mhard-float*
diff --git a/gcc/config/csky/t-csky-linux b/gcc/config/csky/t-csky-linux
new file mode 100644
index 0000000..4a145a6
--- /dev/null
+++ b/gcc/config/csky/t-csky-linux
@@ -0,0 +1,52 @@
+# Multilib configuration for csky*-linux-*.
+#
+# Copyright (C) 2018 Free Software Foundation, Inc.
+# Contributed by C-SKY Microsystems and Mentor Graphics.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+
+# Endiannesses.
+MULTILIB_OPTIONS = mlittle-endian/mbig-endian
+MULTILIB_DIRNAMES = little big
+MULTILIB_MATCHES = mlittle-endian=EL
+MULTILIB_MATCHES = mbig-endian=EB
+
+MULTILIB_EXCEPTIONS =
+CSKY_MULTILIB_OSDIRNAMES = mbig-endian=/big mlittle-endian=/. mhard-float=/hard-fp msoft-float=/. mcpu.ck810f=/. mcpu.ck807f=/ck807
+
+# Arch variants.
+MULTILIB_OPTIONS += mcpu=ck810f/mcpu=ck807f
+MULTILIB_DIRNAMES += ck810 ck807
+
+# For ck807.
+MULTILIB_MATCHES += mcpu?ck807f=march?ck807
+MULTILIB_MATCHES += mcpu?ck807f=mcpu?ck807
+
+# For arch ck810.
+MULTILIB_MATCHES += mcpu?ck810f=march?ck810
+MULTILIB_MATCHES += mcpu?ck810f=mcpu?ck810
+MULTILIB_MATCHES += mcpu?ck810f=mcpu?ck810v
+MULTILIB_MATCHES += mcpu?ck810f=mcpu?ck810t
+MULTILIB_MATCHES += mcpu?ck810f=mcpu?ck810vt
+MULTILIB_MATCHES += mcpu?ck810f=mcpu?ck810vf
+MULTILIB_MATCHES += mcpu?ck810f=mcpu?ck810ft
+MULTILIB_MATCHES += mcpu?ck810f=mcpu?ck810vft
+
+# For option -msoft-float/-mhard-float.
+MULTILIB_OPTIONS += msoft-float/mhard-float
+MULTILIB_DIRNAMES += soft-fp hard-fp
diff --git a/gcc/config/csky/t-sysroot-suffix b/gcc/config/csky/t-sysroot-suffix
new file mode 100644
index 0000000..97c03d3
--- /dev/null
+++ b/gcc/config/csky/t-sysroot-suffix
@@ -0,0 +1,28 @@
+# Makefile fragment for C-SKY sysroot suffix.
+#
+# Copyright (C) 2018 Free Software Foundation, Inc.
+# Contributed by C-SKY Microsystems and Mentor Graphics.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# Generate SYSROOT_SUFFIX_SPEC from MULTILIB_OSDIRNAMES.
+
+sysroot-suffix.h: $(srcdir)/config/csky/print-sysroot-suffix.sh
+ $(SHELL) $(srcdir)/config/csky/print-sysroot-suffix.sh \
+ "$(CSKY_MULTILIB_OSDIRNAMES)" "$(MULTILIB_OPTIONS)" \
+ "$(MULTILIB_MATCHES)" > tmp-sysroot-suffix.h
+ mv tmp-sysroot-suffix.h $@
diff --git a/gcc/config/darwin.c b/gcc/config/darwin.c
index a31cb08..233076a 100644
--- a/gcc/config/darwin.c
+++ b/gcc/config/darwin.c
@@ -3176,6 +3176,14 @@ darwin_override_options (void)
if (!global_options_set.x_dwarf_version)
dwarf_version = 2;
+ if (global_options_set.x_dwarf_split_debug_info)
+ {
+ inform (input_location,
+ "-gsplit-dwarf is not supported on this platform, ignored");
+ dwarf_split_debug_info = 0;
+ global_options_set.x_dwarf_split_debug_info = 0;
+ }
+
/* Do not allow unwind tables to be generated by default for m32.
fnon-call-exceptions will override this, regardless of what we do. */
if (generating_for_darwin_version < 10
diff --git a/gcc/config/darwin.h b/gcc/config/darwin.h
index 166c3c7..05c8cf7 100644
--- a/gcc/config/darwin.h
+++ b/gcc/config/darwin.h
@@ -122,7 +122,9 @@ extern GTY(()) int darwin_ms_struct;
"%{gfull:-g -fno-eliminate-unused-debug-symbols} %<gfull", \
"%{gused:-g -feliminate-unused-debug-symbols} %<gused", \
"%{fapple-kext|mkernel:-static}", \
- "%{shared:-Zdynamiclib} %<shared"
+ "%{shared:-Zdynamiclib} %<shared", \
+ "%{gsplit-dwarf:%ngsplit-dwarf is not supported on this platform } \
+ %<gsplit-dwarf"
#define DARWIN_CC1_SPEC \
"%{findirect-virtual-calls: -fapple-kext} %<findirect-virtual-calls " \
@@ -421,6 +423,8 @@ extern GTY(()) int darwin_ms_struct;
debugging data. */
#define ASM_DEBUG_SPEC "%{g*:%{%:debug-level-gt(0):%{!gdwarf*:--gstabs}}}"
+#define ASM_FINAL_SPEC \
+ "%{gsplit-dwarf:%ngsplit-dwarf is not supported on this platform } %<gsplit-dwarf"
/* We still allow output of STABS if the assembler supports it. */
#ifdef HAVE_AS_STABS_DIRECTIVE
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 3548de2..0b2b1b7 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -40554,7 +40554,7 @@ ix86_rtx_costs (rtx x, machine_mode mode, int outer_code_i, int opno,
{
case SET:
if (register_operand (SET_DEST (x), VOIDmode)
- && reg_or_0_operand (SET_SRC (x), VOIDmode))
+ && register_operand (SET_SRC (x), VOIDmode))
{
*total = ix86_set_reg_reg_cost (GET_MODE (SET_DEST (x)));
return true;
@@ -40581,20 +40581,10 @@ ix86_rtx_costs (rtx x, machine_mode mode, int outer_code_i, int opno,
case CONST:
case LABEL_REF:
case SYMBOL_REF:
- if (TARGET_64BIT && !x86_64_immediate_operand (x, VOIDmode))
- *total = 3;
- else if (TARGET_64BIT && !x86_64_zext_immediate_operand (x, VOIDmode))
- *total = 2;
- else if (flag_pic && SYMBOLIC_CONST (x)
- && !(TARGET_64BIT
- && (GET_CODE (x) == LABEL_REF
- || (GET_CODE (x) == SYMBOL_REF
- && SYMBOL_REF_LOCAL_P (x))))
- /* Use 0 cost for CONST to improve its propagation. */
- && (TARGET_64BIT || GET_CODE (x) != CONST))
- *total = 1;
- else
+ if (x86_64_immediate_operand (x, VOIDmode))
*total = 0;
+ else
+ *total = 1;
return true;
case CONST_DOUBLE:
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index c691952..d34fcf0 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -12254,11 +12254,10 @@
(const_string "12")
(const_string "16")))])
-;; Define both directions of branch and return. If we need a reload
-;; register, we'd rather use CR0 since it is much easier to copy a
-;; register CC value to there.
+;; Conditional branches.
+;; These either are a single bc insn, or a bc around a b.
-(define_insn ""
+(define_insn "*cbranch"
[(set (pc)
(if_then_else (match_operator 1 "branch_comparison_operator"
[(match_operand 2 "cc_reg_operand" "y")
@@ -12278,7 +12277,8 @@
(const_int 4)
(const_int 8)))])
-(define_insn ""
+;; Conditional return.
+(define_insn "*creturn"
[(set (pc)
(if_then_else (match_operator 0 "branch_comparison_operator"
[(match_operand 1 "cc_reg_operand" "y")
diff --git a/gcc/configure b/gcc/configure
index 80ac4a3..b7a8e36 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -27838,7 +27838,7 @@ esac
# ??? Once 2.11 is released, probably need to add first known working
# version to the per-target configury.
case "$cpu_type" in
- aarch64 | alpha | arc | arm | avr | bfin | cris | i386 | m32c | m68k \
+ aarch64 | alpha | arc | arm | avr | bfin | cris | csky | i386 | m32c | m68k \
| microblaze | mips | nios2 | pa | riscv | rs6000 | score | sparc | spu \
| tilegx | tilepro | visium | xstormy16 | xtensa)
insn="nop"
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 4fc851c..65f9c92 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -4932,7 +4932,7 @@ esac
# ??? Once 2.11 is released, probably need to add first known working
# version to the per-target configury.
case "$cpu_type" in
- aarch64 | alpha | arc | arm | avr | bfin | cris | i386 | m32c | m68k \
+ aarch64 | alpha | arc | arm | avr | bfin | cris | csky | i386 | m32c | m68k \
| microblaze | mips | nios2 | pa | riscv | rs6000 | score | sparc | spu \
| tilegx | tilepro | visium | xstormy16 | xtensa)
insn="nop"
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 0b69590..d8be9308 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,8 @@
+2018-08-17 David Malcolm <dmalcolm@redhat.com>
+
+ * typeck.c (string_conv_p): Extract location from EXP and use it
+ in preference to input_location when issuing warnings.
+
2018-08-15 David Malcolm <dmalcolm@redhat.com>
* call.c: Include "gcc-rich-location.h".
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 64b3d58..8c13ae9 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -2208,6 +2208,8 @@ string_conv_p (const_tree totype, const_tree exp, int warn)
&& !same_type_p (t, wchar_type_node))
return 0;
+ location_t loc = EXPR_LOC_OR_LOC (exp, input_location);
+
STRIP_ANY_LOCATION_WRAPPER (exp);
if (TREE_CODE (exp) == STRING_CST)
@@ -2230,13 +2232,13 @@ string_conv_p (const_tree totype, const_tree exp, int warn)
if (warn)
{
if (cxx_dialect >= cxx11)
- pedwarn (input_location, OPT_Wwrite_strings,
+ pedwarn (loc, OPT_Wwrite_strings,
"ISO C++ forbids converting a string constant to %qT",
totype);
else
- warning (OPT_Wwrite_strings,
- "deprecated conversion from string constant to %qT",
- totype);
+ warning_at (loc, OPT_Wwrite_strings,
+ "deprecated conversion from string constant to %qT",
+ totype);
}
return 1;
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 130f6a6..e3312aa 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -2324,6 +2324,7 @@ GCC plugins may provide their own attributes.
* AVR Function Attributes::
* Blackfin Function Attributes::
* CR16 Function Attributes::
+* C-SKY Function Attributes::
* Epiphany Function Attributes::
* H8/300 Function Attributes::
* IA-64 Function Attributes::
@@ -4147,6 +4148,38 @@ function entry and exit sequences suitable for use in an interrupt handler
when this attribute is present.
@end table
+@node C-SKY Function Attributes
+@subsection C-SKY Function Attributes
+
+These function attributes are supported by the C-SKY back end:
+
+@table @code
+@item interrupt
+@itemx isr
+@cindex @code{interrupt} function attribute, C-SKY
+@cindex @code{isr} function attribute, C-SKY
+Use these attributes to indicate that the specified function
+is an interrupt handler.
+The compiler generates function entry and exit sequences suitable for
+use in an interrupt handler when either of these attributes are present.
+
+Use of these options requires the @option{-mistack} command-line option
+to enable support for the necessary interrupt stack instructions. They
+are ignored with a warning otherwise. @xref{C-SKY Options}.
+
+@item naked
+@cindex @code{naked} function attribute, C-SKY
+This attribute allows the compiler to construct the
+requisite function declaration, while allowing the body of the
+function to be assembly code. The specified function will not have
+prologue/epilogue sequences generated by the compiler. Only basic
+@code{asm} statements can safely be included in naked functions
+(@pxref{Basic Asm}). While using extended @code{asm} or a mixture of
+basic @code{asm} and C code may appear to work, they cannot be
+depended upon to work reliably and are not supported.
+@end table
+
+
@node Epiphany Function Attributes
@subsection Epiphany Function Attributes
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index d91e6c5..f828715 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -723,6 +723,16 @@ Objective-C and Objective-C++ Dialects}.
-msim -mint32 -mbit-ops
-mdata-model=@var{model}}
+@emph{C-SKY Options}
+@gccoptlist{-march=@var{arch} -mcpu=@var{cpu} @gol
+-mbig-endian -EB -mlittle-endian -EL @gol
+-mhard-float -msoft-float -mfpu=@var{fpu} -mdouble-float -mfdivdu @gol
+-melrw -mistack -mmp -mcp -mcache -msecurity -mtrust @gol
+-mdsp -medsp -mvdsp @gol
+-mdiv -msmart -mhigh-registers -manchor @gol
+-mpushpop -mmultiple-stld -mconstpool -mstack-size -mccrt @gol
+-mbranch-cost=@var{n} -mcse-cc -msched-prolog}
+
@emph{Darwin Options}
@gccoptlist{-all_load -allowable_client -arch -arch_errors_fatal @gol
-arch_only -bind_at_load -bundle -bundle_loader @gol
@@ -14633,6 +14643,7 @@ platform.
* C6X Options::
* CRIS Options::
* CR16 Options::
+* C-SKY Options::
* Darwin Options::
* DEC Alpha Options::
* FR30 Options::
@@ -17757,6 +17768,198 @@ However, @samp{far} is not valid with @option{-mcr16c}, as the
CR16C architecture does not support the far data model.
@end table
+@node C-SKY Options
+@subsection C-SKY Options
+@cindex C-SKY Options
+
+GCC supports these options when compiling for C-SKY V2 processors.
+
+@table @gcctabopt
+
+@item -march=@var{arch}
+@opindex march=
+Specify the C-SKY target architecture. Valid values for @var{arch} are:
+@samp{ck801}, @samp{ck802}, @samp{ck803}, @samp{ck807}, and @samp{ck810}.
+The default is @samp{ck810}.
+
+@item -mcpu=@var{cpu}
+@opindex mcpu=
+Specify the C-SKY target processor. Valid values for @var{cpu} are:
+@samp{ck801}, @samp{ck801t},
+@samp{ck802}, @samp{ck802t}, @samp{ck802j},
+@samp{ck803}, @samp{ck803h}, @samp{ck803t}, @samp{ck803ht},
+@samp{ck803f}, @samp{ck803fh}, @samp{ck803e}, @samp{ck803eh},
+@samp{ck803et}, @samp{ck803eht}, @samp{ck803ef}, @samp{ck803efh},
+@samp{ck803ft}, @samp{ck803eft}, @samp{ck803efht}, @samp{ck803r1},
+@samp{ck803hr1}, @samp{ck803tr1}, @samp{ck803htr1}, @samp{ck803fr1},
+@samp{ck803fhr1}, @samp{ck803er1}, @samp{ck803ehr1}, @samp{ck803etr1},
+@samp{ck803ehtr1}, @samp{ck803efr1}, @samp{ck803efhr1}, @samp{ck803ftr1},
+@samp{ck803eftr1}, @samp{ck803efhtr1},
+@samp{ck803s}, @samp{ck803st}, @samp{ck803se}, @samp{ck803sf},
+@samp{ck803sef}, @samp{ck803seft},
+@samp{ck807e}, @samp{ck807ef}, @samp{ck807}, @samp{ck807f},
+@samp{ck810e}, @samp{ck810et}, @samp{ck810ef}, @samp{ck810eft},
+@samp{ck810}, @samp{ck810v}, @samp{ck810f}, @samp{ck810t}, @samp{ck810fv},
+@samp{ck810tv}, @samp{ck810ft}, and @samp{ck810ftv}.
+
+@item -mbig-endian
+@opindex mbig-endian
+@itemx -EB
+@opindex -EB
+@itemx -mlittle-endian
+@opindex mlittle-endian
+@itemx -EL
+@opindex -EL
+
+Select big- or little-endian code. The default is little-endian.
+
+@item -mhard-float
+@opindex mhard-float
+@itemx -msoft-float
+@opindex msoft-float
+
+Select hardware or software floating-point implementations.
+The default is soft float.
+
+@item -mdouble-float
+@itemx -mno-double-float
+@opindex mdouble-float
+When @option{-mhard-float} is in effect, enable generation of
+double-precision float instructions. This is the default except
+when compiling for CK803.
+
+@item -mfdivdu
+@itemx -mno-fdivdu
+@opindex mfdivdu
+When @option{-mhard-float} is in effect, enable generation of
+@code{frecipd}, @code{fsqrtd}, and @code{fdivd} instructions.
+This is the default except when compiling for CK803.
+
+@item -mfpu=@var{fpu}
+@opindex mfpu=
+Select the floating-point processor. This option can only be used with
+@option{-mhard-float}.
+Values for @var{fpu} are
+@samp{fpv2_sf} (equivalent to @samp{-mno-double-float -mno-fdivdu}),
+@samp{fpv2} (@samp{-mdouble-float -mno-divdu}), and
+@samp{fpv2_divd} (@samp{-mdouble-float -mdivdu}).
+
+@item -melrw
+@itemx -mno-elrw
+@opindex melrw
+Enable the extended @code{lrw} instruction. This option defaults to on
+for CK801 and off otherwise.
+
+@item -mistack
+@itemx -mno-istack
+@opindex mistack
+Enable interrupt stack instructions; the default is off.
+
+The @option{-mistack} option is required to handle the
+@code{interrupt} and @code{isr} function attributes
+(@pxref{C-SKY Function Attributes}).
+
+@item -mmp
+@opindex mmp
+Enable multiprocessor instructions; the default is off.
+
+@item -mcp
+@opindex mcp
+Enable coprocessor instructions; the default is off.
+
+@item -mcache
+@opindex mcache
+Enable coprocessor instructions; the default is off.
+
+@item -msecurity
+@opindex msecurity
+Enable C-SKY security instructions; the default is off.
+
+@item -mtrust
+@opindex mtrust
+Enable C-SKY trust instructions; the default is off.
+
+@item -mdsp
+@opindex mdsp
+@itemx -medsp
+@opindex medsp
+@itemx -mvdsp
+@opindex mvdsp
+Enable C-SKY DSP, Enhanced DSP, or Vector DSP instructions, respectively.
+All of these options default to off.
+
+@item -mdiv
+@itemx -mno-div
+@opindex mdiv
+Generate divide instructions. Default is off.
+
+@item -msmart
+@itemx -mno-smart
+@opindex msmart
+Generate code for Smart Mode, using only registers numbered 0-7 to allow
+use of 16-bit instructions. This option is ignored for CK801 where this
+is the required behavior, and it defaults to on for CK802.
+For other targets, the default is off.
+
+@item -mhigh-registers
+@itemx -mno-high-registers
+@opindex mhigh-registers
+Generate code using the high registers numbered 16-31. This option
+is not supported on CK801, CK802, or CK803, and is enabled by default
+for other processors.
+
+@item -manchor
+@itemx -mno-anchor
+@opindex manchor
+Generate code using global anchor symbol addresses.
+
+@item -mpushpop
+@itemx -mno-pushpop
+@opindex mpushpop
+Generate code using @code{push} and @code{pop} instructions. This option
+defaults to on.
+
+@item -mmultiple-stld
+@itemx -mstm
+@itemx -mno-multiple-stld
+@itemx -mno-stm
+@opindex mmultiple-stld
+Generate code using @code{stm} and @code{ldm} instructions. This option
+isn't supported on CK801 but is enabled by default on other processors.
+
+@item -mconstpool
+@itemx -mno-constpool
+@opindex mconstpool
+Create constant pools in the compiler instead of deferring it to the
+assembler. This option is the default and required for correct code
+generation on CK801 and CK802, and is optional on other processors.
+
+@item -mstack-size
+@item -mno-stack-size
+@opindex mstack-size
+Emit @code{.stack_size} directives for each function in the assembly
+output. This option defaults to off.
+
+@item -mccrt
+@itemx -mno-ccrt
+@opindex mccrt
+Generate code for the C-SKY compiler runtime instead of libgcc. This
+option defaults to off.
+
+@item -mbranch-cost=@var{n}
+@opindex mbranch-cost=
+Set the branch costs to roughly @code{n} instructions. The default is 1.
+
+@item -msched-prolog
+@itemx -mno-sched-prolog
+@opindex msched-prolog
+Permit scheduling of function prologue and epilogue sequences. Using
+this option can result in code that is not compliant with the C-SKY V2 ABI
+prologue requirements and that cannot be debugged or backtraced.
+It is disabled by default.
+
+@end table
+
@node Darwin Options
@subsection Darwin Options
@cindex Darwin options
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 02f9e1e..4801d68 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -144,7 +144,7 @@ a nameless pattern for all other purposes. Names beginning with the
The name may also have the form @samp{@@@var{n}}. This has the same
effect as a name @samp{@var{n}}, but in addition tells the compiler to
-generate further helper functions; see @xref{Parameterized Names} for details.
+generate further helper functions; see @ref{Parameterized Names} for details.
@item
The @dfn{RTL template}: This is a vector of incomplete RTL expressions
@@ -2132,6 +2132,42 @@ Check for 64 bits wide constants for add/sub instructions
Floating point constant that is legal for store immediate
@end table
+@item C-SKY---@file{config/csky/constraints.md}
+@table @code
+
+@item a
+The mini registers r0 - r7.
+
+@item b
+The low registers r0 - r15.
+
+@item c
+C register.
+
+@item y
+HI and LO registers.
+
+@item l
+LO register.
+
+@item h
+HI register.
+
+@item v
+Vector registers.
+
+@item z
+Stack pointer register (SP).
+@end table
+
+@ifset INTERNALS
+The C-SKY back end supports a large set of additional constraints
+that are only useful for instruction selection or splitting rather
+than inline asm, such as constraints representing constant integer
+ranges accepted by particular instruction encodings.
+Refer to the source code for details.
+@end ifset
+
@item Epiphany---@file{config/epiphany/constraints.md}
@table @code
@item U16
diff --git a/gcc/dump-context.h b/gcc/dump-context.h
index f40ea14..5ac9dd6 100644
--- a/gcc/dump-context.h
+++ b/gcc/dump-context.h
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_DUMP_CONTEXT_H
#define GCC_DUMP_CONTEXT_H 1
+#include "dumpfile.h"
#include "pretty-print.h"
/* A class for handling the various dump_* calls.
@@ -73,11 +74,11 @@ class dump_context
tree t);
void dump_printf_va (dump_flags_t dump_kind, const char *format,
- va_list ap) ATTRIBUTE_PRINTF (3, 0);
+ va_list *ap) ATTRIBUTE_GCC_DUMP_PRINTF (3, 0);
void dump_printf_loc_va (dump_flags_t dump_kind, const dump_location_t &loc,
- const char *format, va_list ap)
- ATTRIBUTE_PRINTF (4, 0);
+ const char *format, va_list *ap)
+ ATTRIBUTE_GCC_DUMP_PRINTF (4, 0);
template<unsigned int N, typename C>
void dump_dec (dump_flags_t dump_kind, const poly_int<N, C> &value);
diff --git a/gcc/dumpfile.c b/gcc/dumpfile.c
index 76a2ee8..a81ab3e 100644
--- a/gcc/dumpfile.c
+++ b/gcc/dumpfile.c
@@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see
#include "cgraph.h"
#include "tree-pass.h" /* for "current_pass". */
#include "optinfo-emit-json.h"
+#include "stringpool.h" /* for get_identifier. */
/* If non-NULL, return one past-the-end of the matching SUBPART of
the WHOLE string. */
@@ -681,56 +682,262 @@ dump_context::dump_generic_expr_loc (dump_flags_t dump_kind,
dump_generic_expr (dump_kind, extra_dump_flags, t);
}
-/* Make an item for the given dump call. */
+/* A subclass of pretty_printer for implementing dump_context::dump_printf_va.
+ In particular, the formatted chunks are captured as optinfo_item instances,
+ thus retaining metadata about the entities being dumped (e.g. source
+ locations), rather than just as plain text. */
-static optinfo_item *
-make_item_for_dump_printf_va (const char *format, va_list ap)
- ATTRIBUTE_PRINTF (1, 0);
+class dump_pretty_printer : public pretty_printer
+{
+public:
+ dump_pretty_printer (dump_context *context, dump_flags_t dump_kind);
-static optinfo_item *
-make_item_for_dump_printf_va (const char *format, va_list ap)
+ void emit_items (optinfo *dest);
+
+private:
+ /* Information on an optinfo_item that was generated during phase 2 of
+ formatting. */
+ struct stashed_item
+ {
+ stashed_item (const char **buffer_ptr_, optinfo_item *item_)
+ : buffer_ptr (buffer_ptr_), item (item_) {}
+ const char **buffer_ptr;
+ optinfo_item *item;
+ };
+
+ static bool format_decoder_cb (pretty_printer *pp, text_info *text,
+ const char *spec, int /*precision*/,
+ bool /*wide*/, bool /*set_locus*/,
+ bool /*verbose*/, bool */*quoted*/,
+ const char **buffer_ptr);
+
+ bool decode_format (text_info *text, const char *spec,
+ const char **buffer_ptr);
+
+ void stash_item (const char **buffer_ptr, optinfo_item *item);
+
+ void emit_any_pending_textual_chunks (optinfo *dest);
+
+ void emit_item (optinfo_item *item, optinfo *dest);
+
+ dump_context *m_context;
+ dump_flags_t m_dump_kind;
+ auto_vec<stashed_item> m_stashed_items;
+};
+
+/* dump_pretty_printer's ctor. */
+
+dump_pretty_printer::dump_pretty_printer (dump_context *context,
+ dump_flags_t dump_kind)
+: pretty_printer (), m_context (context), m_dump_kind (dump_kind),
+ m_stashed_items ()
+{
+ pp_format_decoder (this) = format_decoder_cb;
+}
+
+/* Phase 3 of formatting; compare with pp_output_formatted_text.
+
+ Emit optinfo_item instances for the various formatted chunks from phases
+ 1 and 2 (i.e. pp_format).
+
+ Some chunks may already have had their items built (during decode_format).
+ These chunks have been stashed into m_stashed_items; we emit them here.
+
+ For all other purely textual chunks, they are printed into
+ buffer->formatted_obstack, and then emitted as a textual optinfo_item.
+ This consolidates multiple adjacent text chunks into a single text
+ optinfo_item. */
+
+void
+dump_pretty_printer::emit_items (optinfo *dest)
+{
+ output_buffer *buffer = pp_buffer (this);
+ struct chunk_info *chunk_array = buffer->cur_chunk_array;
+ const char **args = chunk_array->args;
+
+ gcc_assert (buffer->obstack == &buffer->formatted_obstack);
+ gcc_assert (buffer->line_length == 0);
+
+ unsigned stashed_item_idx = 0;
+ for (unsigned chunk = 0; args[chunk]; chunk++)
+ {
+ if (stashed_item_idx < m_stashed_items.length ()
+ && args[chunk] == *m_stashed_items[stashed_item_idx].buffer_ptr)
+ {
+ emit_any_pending_textual_chunks (dest);
+ /* This chunk has a stashed item: use it. */
+ emit_item (m_stashed_items[stashed_item_idx++].item, dest);
+ }
+ else
+ /* This chunk is purely textual. Print it (to
+ buffer->formatted_obstack), so that we can consolidate adjacent
+ chunks into one textual optinfo_item. */
+ pp_string (this, args[chunk]);
+ }
+
+ emit_any_pending_textual_chunks (dest);
+
+ /* Ensure that we consumed all of stashed_items. */
+ gcc_assert (stashed_item_idx == m_stashed_items.length ());
+
+ /* Deallocate the chunk structure and everything after it (i.e. the
+ associated series of formatted strings). */
+ buffer->cur_chunk_array = chunk_array->prev;
+ obstack_free (&buffer->chunk_obstack, chunk_array);
+}
+
+/* Subroutine of dump_pretty_printer::emit_items
+ for consolidating multiple adjacent pure-text chunks into single
+ optinfo_items (in phase 3). */
+
+void
+dump_pretty_printer::emit_any_pending_textual_chunks (optinfo *dest)
{
- char *formatted_text = xvasprintf (format, ap);
+ gcc_assert (buffer->obstack == &buffer->formatted_obstack);
+
+ /* Don't emit an item if the pending text is empty. */
+ if (output_buffer_last_position_in_text (buffer) == NULL)
+ return;
+
+ char *formatted_text = xstrdup (pp_formatted_text (this));
optinfo_item *item
= new optinfo_item (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION,
formatted_text);
- return item;
+ emit_item (item, dest);
+
+ /* Clear the pending text by unwinding formatted_text back to the start
+ of the buffer (without deallocating). */
+ obstack_free (&buffer->formatted_obstack,
+ buffer->formatted_obstack.object_base);
}
-/* Make an item for the given dump call. */
+/* Emit ITEM and take ownership of it. If DEST is non-NULL, add ITEM
+ to DEST; otherwise delete ITEM. */
-static optinfo_item *
-make_item_for_dump_printf (const char *format, ...)
- ATTRIBUTE_PRINTF (1, 2);
+void
+dump_pretty_printer::emit_item (optinfo_item *item, optinfo *dest)
+{
+ m_context->emit_item (item, m_dump_kind);
+ if (dest)
+ dest->add_item (item);
+ else
+ delete item;
+}
-static optinfo_item *
-make_item_for_dump_printf (const char *format, ...)
+/* Record that ITEM (generated in phase 2 of formatting) is to be used for
+ the chunk at BUFFER_PTR in phase 3 (by emit_items). */
+
+void
+dump_pretty_printer::stash_item (const char **buffer_ptr, optinfo_item *item)
{
- va_list ap;
- va_start (ap, format);
- optinfo_item *item
- = make_item_for_dump_printf_va (format, ap);
- va_end (ap);
- return item;
+ gcc_assert (buffer_ptr);
+ gcc_assert (item);
+
+ m_stashed_items.safe_push (stashed_item (buffer_ptr, item));
+}
+
+/* pp_format_decoder callback for dump_pretty_printer, and thus for
+ dump_printf and dump_printf_loc.
+
+ A wrapper around decode_format, for type-safety. */
+
+bool
+dump_pretty_printer::format_decoder_cb (pretty_printer *pp, text_info *text,
+ const char *spec, int /*precision*/,
+ bool /*wide*/, bool /*set_locus*/,
+ bool /*verbose*/, bool */*quoted*/,
+ const char **buffer_ptr)
+{
+ dump_pretty_printer *opp = static_cast <dump_pretty_printer *> (pp);
+ return opp->decode_format (text, spec, buffer_ptr);
+}
+
+/* Format decoder for dump_pretty_printer, and thus for dump_printf and
+ dump_printf_loc.
+
+ Supported format codes (in addition to the standard pretty_printer ones)
+ are:
+
+ %E: gimple *:
+ Equivalent to: dump_gimple_expr (MSG_*, TDF_SLIM, stmt, 0)
+ %G: gimple *:
+ Equivalent to: dump_gimple_stmt (MSG_*, TDF_SLIM, stmt, 0)
+ %T: tree:
+ Equivalent to: dump_generic_expr (MSG_*, arg, TDF_SLIM).
+
+ FIXME: add symtab_node?
+
+ These format codes build optinfo_item instances, thus capturing metadata
+ about the arguments being dumped, as well as the textual output. */
+
+bool
+dump_pretty_printer::decode_format (text_info *text, const char *spec,
+ const char **buffer_ptr)
+{
+ /* Various format codes that imply making an optinfo_item and stashed it
+ for later use (to capture metadata, rather than plain text). */
+ switch (*spec)
+ {
+ case 'E':
+ {
+ gimple *stmt = va_arg (*text->args_ptr, gimple *);
+
+ /* Make an item for the stmt, and stash it. */
+ optinfo_item *item = make_item_for_dump_gimple_expr (stmt, 0, TDF_SLIM);
+ stash_item (buffer_ptr, item);
+ return true;
+ }
+
+ case 'G':
+ {
+ gimple *stmt = va_arg (*text->args_ptr, gimple *);
+
+ /* Make an item for the stmt, and stash it. */
+ optinfo_item *item = make_item_for_dump_gimple_stmt (stmt, 0, TDF_SLIM);
+ stash_item (buffer_ptr, item);
+ return true;
+ }
+
+ case 'T':
+ {
+ tree t = va_arg (*text->args_ptr, tree);
+
+ /* Make an item for the tree, and stash it. */
+ optinfo_item *item = make_item_for_dump_generic_expr (t, TDF_SLIM);
+ stash_item (buffer_ptr, item);
+ return true;
+ }
+
+ default:
+ return false;
+ }
}
/* Output a formatted message using FORMAT on appropriate dump streams. */
void
dump_context::dump_printf_va (dump_flags_t dump_kind, const char *format,
- va_list ap)
+ va_list *ap)
{
- optinfo_item *item = make_item_for_dump_printf_va (format, ap);
- emit_item (item, dump_kind);
+ dump_pretty_printer pp (this, dump_kind);
+ text_info text;
+ text.err_no = errno;
+ text.args_ptr = ap;
+ text.format_spec = format;
+
+ /* Phases 1 and 2, using pp_format. */
+ pp_format (&pp, &text);
+
+ /* Phase 3. */
if (optinfo_enabled_p ())
{
optinfo &info = ensure_pending_optinfo ();
info.handle_dump_file_kind (dump_kind);
- info.add_item (item);
+ pp.emit_items (&info);
}
else
- delete item;
+ pp.emit_items (NULL);
}
/* Similar to dump_printf, except source location is also printed, and
@@ -739,7 +946,7 @@ dump_context::dump_printf_va (dump_flags_t dump_kind, const char *format,
void
dump_context::dump_printf_loc_va (dump_flags_t dump_kind,
const dump_location_t &loc,
- const char *format, va_list ap)
+ const char *format, va_list *ap)
{
dump_loc (dump_kind, loc);
dump_printf_va (dump_kind, format, ap);
@@ -851,7 +1058,11 @@ dump_context::begin_scope (const char *name, const dump_location_t &loc)
if (m_test_pp)
::dump_loc (MSG_NOTE, m_test_pp, loc.get_location_t ());
- optinfo_item *item = make_item_for_dump_printf ("=== %s ===\n", name);
+ pretty_printer pp;
+ pp_printf (&pp, "=== %s ===\n", name);
+ optinfo_item *item
+ = new optinfo_item (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION,
+ xstrdup (pp_formatted_text (&pp)));
emit_item (item, MSG_NOTE);
if (optinfo_enabled_p ())
@@ -859,7 +1070,6 @@ dump_context::begin_scope (const char *name, const dump_location_t &loc)
optinfo &info = begin_next_optinfo (loc);
info.m_kind = OPTINFO_KIND_SCOPE;
info.add_item (item);
- end_any_optinfo ();
}
else
delete item;
@@ -1006,7 +1216,7 @@ dump_printf (dump_flags_t dump_kind, const char *format, ...)
{
va_list ap;
va_start (ap, format);
- dump_context::get ().dump_printf_va (dump_kind, format, ap);
+ dump_context::get ().dump_printf_va (dump_kind, format, &ap);
va_end (ap);
}
@@ -1019,7 +1229,7 @@ dump_printf_loc (dump_flags_t dump_kind, const dump_location_t &loc,
{
va_list ap;
va_start (ap, format);
- dump_context::get ().dump_printf_loc_va (dump_kind, loc, format, ap);
+ dump_context::get ().dump_printf_loc_va (dump_kind, loc, format, &ap);
va_end (ap);
}
@@ -1808,9 +2018,12 @@ test_capture_of_dump_calls (const line_table_case &case_)
dump_location_t loc = dump_location_t::from_location_t (where);
- greturn *stmt = gimple_build_return (NULL);
+ gimple *stmt = gimple_build_return (NULL);
gimple_set_location (stmt, where);
+ tree test_decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+ get_identifier ("test_decl"),
+ integer_type_node);
/* Run all tests twice, with and then without optinfo enabled, to ensure
that immediate destinations vs optinfo-based destinations both
work, independently of each other, with no leaks. */
@@ -1834,6 +2047,89 @@ test_capture_of_dump_calls (const line_table_case &case_)
}
}
+ /* Test of dump_printf with %T. */
+ {
+ temp_dump_context tmp (with_optinfo, MSG_ALL);
+ dump_printf (MSG_NOTE, "tree: %T", integer_zero_node);
+
+ ASSERT_DUMPED_TEXT_EQ (tmp, "tree: 0");
+ if (with_optinfo)
+ {
+ optinfo *info = tmp.get_pending_optinfo ();
+ ASSERT_TRUE (info != NULL);
+ ASSERT_EQ (info->get_kind (), OPTINFO_KIND_NOTE);
+ ASSERT_EQ (info->num_items (), 2);
+ ASSERT_IS_TEXT (info->get_item (0), "tree: ");
+ ASSERT_IS_TREE (info->get_item (1), UNKNOWN_LOCATION, "0");
+ }
+ }
+
+ /* Test of dump_printf with %E. */
+ {
+ temp_dump_context tmp (with_optinfo, MSG_ALL);
+ dump_printf (MSG_NOTE, "gimple: %E", stmt);
+
+ ASSERT_DUMPED_TEXT_EQ (tmp, "gimple: return;");
+ if (with_optinfo)
+ {
+ optinfo *info = tmp.get_pending_optinfo ();
+ ASSERT_TRUE (info != NULL);
+ ASSERT_EQ (info->get_kind (), OPTINFO_KIND_NOTE);
+ ASSERT_EQ (info->num_items (), 2);
+ ASSERT_IS_TEXT (info->get_item (0), "gimple: ");
+ ASSERT_IS_GIMPLE (info->get_item (1), where, "return;");
+ }
+ }
+
+ /* Test of dump_printf with %G. */
+ {
+ temp_dump_context tmp (with_optinfo, MSG_ALL);
+ dump_printf (MSG_NOTE, "gimple: %G", stmt);
+
+ ASSERT_DUMPED_TEXT_EQ (tmp, "gimple: return;\n");
+ if (with_optinfo)
+ {
+ optinfo *info = tmp.get_pending_optinfo ();
+ ASSERT_TRUE (info != NULL);
+ ASSERT_EQ (info->get_kind (), OPTINFO_KIND_NOTE);
+ ASSERT_EQ (info->num_items (), 2);
+ ASSERT_IS_TEXT (info->get_item (0), "gimple: ");
+ ASSERT_IS_GIMPLE (info->get_item (1), where, "return;\n");
+ }
+ }
+
+ /* dump_print_loc with multiple format codes. This tests various
+ things:
+ - intermingling of text, format codes handled by the base
+ pretty_printer, and dump-specific format codes
+ - multiple dump-specific format codes: some consecutive, others
+ separated by text, trailing text after the final one. */
+ {
+ temp_dump_context tmp (with_optinfo, MSG_ALL);
+ dump_printf_loc (MSG_NOTE, loc, "before %T and %T"
+ " %i consecutive %E%E after\n",
+ integer_zero_node, test_decl, 42, stmt, stmt);
+
+ ASSERT_DUMPED_TEXT_EQ (tmp,
+ "test.txt:5:10: note: before 0 and test_decl"
+ " 42 consecutive return;return; after\n");
+ if (with_optinfo)
+ {
+ optinfo *info = tmp.get_pending_optinfo ();
+ ASSERT_TRUE (info != NULL);
+ ASSERT_EQ (info->get_kind (), OPTINFO_KIND_NOTE);
+ ASSERT_EQ (info->num_items (), 8);
+ ASSERT_IS_TEXT (info->get_item (0), "before ");
+ ASSERT_IS_TREE (info->get_item (1), UNKNOWN_LOCATION, "0");
+ ASSERT_IS_TEXT (info->get_item (2), " and ");
+ ASSERT_IS_TREE (info->get_item (3), UNKNOWN_LOCATION, "test_decl");
+ ASSERT_IS_TEXT (info->get_item (4), " 42 consecutive ");
+ ASSERT_IS_GIMPLE (info->get_item (5), where, "return;");
+ ASSERT_IS_GIMPLE (info->get_item (6), where, "return;");
+ ASSERT_IS_TEXT (info->get_item (7), " after\n");
+ }
+ }
+
/* Tree, via dump_generic_expr. */
{
temp_dump_context tmp (with_optinfo, MSG_ALL);
diff --git a/gcc/dumpfile.h b/gcc/dumpfile.h
index 8de001d..0305d36 100644
--- a/gcc/dumpfile.h
+++ b/gcc/dumpfile.h
@@ -23,6 +23,19 @@ along with GCC; see the file COPYING3. If not see
#include "profile-count.h"
+/* An attribute for annotating formatting printing functions that use
+ the dumpfile/optinfo formatting codes. These are the pretty_printer
+ format codes (see pretty-print.c), with additional codes for middle-end
+ specific entities (see dumpfile.c). */
+
+#if GCC_VERSION >= 3005
+#define ATTRIBUTE_GCC_DUMP_PRINTF(m, n) \
+ __attribute__ ((__format__ (__gcc_dump_printf__, m ,n))) \
+ ATTRIBUTE_NONNULL(m)
+#else
+#define ATTRIBUTE_GCC_DUMP_PRINTF(m, n) ATTRIBUTE_NONNULL(m)
+#endif
+
/* Different tree dump places. When you add new tree dump places,
extend the DUMP_FILES array in dumpfile.c. */
enum tree_dump_index
@@ -476,9 +489,12 @@ dump_enabled_p (void)
to minimize the work done for the common case where dumps
are disabled. */
-extern void dump_printf (dump_flags_t, const char *, ...) ATTRIBUTE_PRINTF_2;
+extern void dump_printf (dump_flags_t, const char *, ...)
+ ATTRIBUTE_GCC_DUMP_PRINTF (2, 3);
+
extern void dump_printf_loc (dump_flags_t, const dump_location_t &,
- const char *, ...) ATTRIBUTE_PRINTF_3;
+ const char *, ...)
+ ATTRIBUTE_GCC_DUMP_PRINTF (3, 0);
extern void dump_function (int phase, tree fn);
extern void dump_basic_block (dump_flags_t, basic_block, int);
extern void dump_generic_expr_loc (dump_flags_t, const dump_location_t &,
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 341079b..e89f4a4 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,60 @@
+2018-08-18 Iain Sandoe <iain@sandoe.co.uk>
+
+ * gcc.dg/debug/dwarf2/pr80263.c: Suppress pubtypes output
+ for Darwin.
+
+2018-08-18 Iain Sandoe <iain@sandoe.co.uk>
+
+ * g++.dg/debug/dwarf2/pr85302.C: Skip unsupported split DWARF
+ test on Darwin.
+ * g++.dg/debug/dwarf2/pr85302.C: Likewise.
+ * gcc.dg/lto/pr83719_0.c: Likewise.
+
+2018-08-17 Martin Sebor <msebor@redhat.com>
+
+ PR testsuite/86996
+ * gcc.dg/tree-ssa/builtin-sprintf-warn-1.c: Adjust.
+
+2018-08-17 David Malcolm <dmalcolm@redhat.com>
+
+ * g++.dg/conversion/Wwrite-strings.C: New test.
+
+2018-08-17 Sandra Loosemore <sandra@codesourcery.com>
+ Chung-Lin Tang <cltang@codesourcery.com>
+ Xianmiao Qu <xianmiao_qu@c-sky.com>
+
+ C-SKY port: Testsuite
+
+ * g++.dg/Wno-frame-address.C: Adjust for C-SKY.
+ * g++.dg/torture/type-generic-1.C: Likewise.
+ * gcc.c-torture/compile/20000804-1.c: Likewise.
+ * gcc.c-torture/execute/20101011-1.c: Likewise.
+ * gcc.c-torture/execute/ieee/mul-subnormal-single-1.x: Likewise.
+ * gcc.dg/20020312-2.c: Likewise.
+ * gcc.dg/Wno-frame-address.c: Likewise.
+ * gcc.dg/c11-true_min-1.c: Likewise.
+ * gcc.dg/sibcall-10.c: Likewise.
+ * gcc.dg/sibcall-9.c: Likewise.
+ * gcc.dg/stack-usage-1.c: Likewise.
+ * gcc.dg/torture/float32-tg-3.c: Likewise.
+ * gcc.dg/torture/float32x-tg-3.c: Likewise.
+ * gcc.dg/torture/float64-tg-3.c: Likewise.
+ * gcc.dg/torture/float64x-tg-3.c: Likewise.
+ * gcc.dg/torture/type-generic-1.c: Likewise.
+ * gcc.target/csky/*: New.
+ * lib/target-supports.exp (check_profiling_available): Add
+ csky-*-elf.
+ (check_effective_target_hard_float): Handle C-SKY targets with
+ single-precision hard float only.
+ (check_effective_target_logical_op_short_circuit): Handle C-SKY.
+
+2018-08-17 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.dg/format/gcc_diag-1.c: Fix typo. Add test coverage for
+ gcc_dump_printf.
+ * gcc.dg/format/gcc_diag-10.c: Add gimple typedef. Add test
+ coverage for gcc_dump_printf.
+
2018-08-17 Martin Liska <mliska@suse.cz>
* g++.dg/opt/mpx.C: Fix scanned pattern.
diff --git a/gcc/testsuite/g++.dg/Wno-frame-address.C b/gcc/testsuite/g++.dg/Wno-frame-address.C
index a2df034..54a02fe 100644
--- a/gcc/testsuite/g++.dg/Wno-frame-address.C
+++ b/gcc/testsuite/g++.dg/Wno-frame-address.C
@@ -1,5 +1,5 @@
// { dg-do compile }
-// { dg-skip-if "Cannot access arbitrary stack frames." { arm*-*-* hppa*-*-* ia64-*-* } }
+// { dg-skip-if "Cannot access arbitrary stack frames." { arm*-*-* hppa*-*-* ia64-*-* csky*-*-* } }
// { dg-options "-Werror" }
// { dg-additional-options "-mbackchain" { target s390*-*-* } }
diff --git a/gcc/testsuite/g++.dg/conversion/Wwrite-strings.C b/gcc/testsuite/g++.dg/conversion/Wwrite-strings.C
new file mode 100644
index 0000000..f6dbb15
--- /dev/null
+++ b/gcc/testsuite/g++.dg/conversion/Wwrite-strings.C
@@ -0,0 +1,24 @@
+// { dg-options "-fdiagnostics-show-caret" }
+
+/* Verify that -Wwrite-strings underlines the string literal in question. */
+
+extern int callee (const char *one, char *two, const char *three);
+
+int test_1 ()
+{
+ return callee ("first", "second", "third"); // { dg-warning "string constant to 'char\\*'" }
+ /* { dg-begin-multiline-output "" }
+ return callee ("first", "second", "third");
+ ^~~~~~~~
+ { dg-end-multiline-output "" } */
+ // TODO: underline the pertinent param in the decl of callee
+}
+
+char *test_2 (void)
+{
+ return "foo"; // { dg-warning "string constant to 'char\\*'" }
+ /* { dg-begin-multiline-output "" }
+ return "foo";
+ ^~~~~
+ { dg-end-multiline-output "" } */
+}
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/pr85302.C b/gcc/testsuite/g++.dg/debug/dwarf2/pr85302.C
index 97ac302..457508d 100644
--- a/gcc/testsuite/g++.dg/debug/dwarf2/pr85302.C
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/pr85302.C
@@ -1,5 +1,6 @@
// PR debug/85302
// { dg-do compile }
+// { dg-skip-if "split DWARF unsupported" { *-*-darwin* } }
// { dg-options "-std=c++11 -gsplit-dwarf -O1" }
// { dg-additional-options "-fPIE" { target pie } }
diff --git a/gcc/testsuite/g++.dg/torture/type-generic-1.C b/gcc/testsuite/g++.dg/torture/type-generic-1.C
index 4d82592..7708724 100644
--- a/gcc/testsuite/g++.dg/torture/type-generic-1.C
+++ b/gcc/testsuite/g++.dg/torture/type-generic-1.C
@@ -4,6 +4,7 @@
/* { dg-do run } */
/* { dg-add-options ieee } */
/* { dg-skip-if "No Inf/NaN support" { spu-*-* } } */
+/* { dg-skip-if "No subnormal support" { csky-*-* } { "-mhard-float" } } */
#include "../../gcc.dg/tg-tests.h"
diff --git a/gcc/testsuite/gcc.c-torture/compile/20000804-1.c b/gcc/testsuite/gcc.c-torture/compile/20000804-1.c
index 5c6b731..35464c2 100644
--- a/gcc/testsuite/gcc.c-torture/compile/20000804-1.c
+++ b/gcc/testsuite/gcc.c-torture/compile/20000804-1.c
@@ -4,6 +4,7 @@
/* { dg-skip-if "" { { i?86-*-* x86_64-*-* } && { ia32 && { ! nonpic } } } } */
/* { dg-skip-if "No 64-bit registers" { m32c-*-* } } */
/* { dg-skip-if "Not enough 64-bit registers" { pdp11-*-* } { "-O0" } { "" } } */
+/* { dg-xfail-if "Inconsistent constraint on asm" { csky-*-* } { "-O0" } { "" } } */
/* { dg-xfail-if "" { h8300-*-* } } */
/* Copyright (C) 2000, 2003 Free Software Foundation */
diff --git a/gcc/testsuite/gcc.c-torture/execute/20101011-1.c b/gcc/testsuite/gcc.c-torture/execute/20101011-1.c
index dda49a5..f95d900 100644
--- a/gcc/testsuite/gcc.c-torture/execute/20101011-1.c
+++ b/gcc/testsuite/gcc.c-torture/execute/20101011-1.c
@@ -93,6 +93,10 @@ __aeabi_idiv0 (int return_value)
#elif defined (__nvptx__)
/* There isn't even a signal function. */
# define DO_TEST 0
+#elif defined (__csky__)
+ /* This presently doesn't raise SIGFPE even on csky-linux-gnu, much
+ less bare metal. See the implementation of __divsi3 in libgcc. */
+# define DO_TEST 0
#else
# define DO_TEST 1
#endif
diff --git a/gcc/testsuite/gcc.c-torture/execute/ieee/mul-subnormal-single-1.x b/gcc/testsuite/gcc.c-torture/execute/ieee/mul-subnormal-single-1.x
index 16df951..ee40863 100644
--- a/gcc/testsuite/gcc.c-torture/execute/ieee/mul-subnormal-single-1.x
+++ b/gcc/testsuite/gcc.c-torture/execute/ieee/mul-subnormal-single-1.x
@@ -1,3 +1,8 @@
+if {[istarget "csky-*-*"] && [check_effective_target_hard_float]} {
+ # The C-SKY hardware FPU only supports flush-to-zero mode.
+ set torture_execute_xfail "csky-*-*"
+ return 1
+}
if [istarget "epiphany-*-*"] {
# The Epiphany single-precision floating point format does not
# support subnormals.
diff --git a/gcc/testsuite/gcc.dg/20020312-2.c b/gcc/testsuite/gcc.dg/20020312-2.c
index f5929e0..f8be3ce 100644
--- a/gcc/testsuite/gcc.dg/20020312-2.c
+++ b/gcc/testsuite/gcc.dg/20020312-2.c
@@ -111,6 +111,11 @@ extern void abort (void);
/* No pic register. */
#elif defined (__nvptx__)
/* No pic register. */
+#elif defined (__csky__)
+/* Pic register is r28, but some cores only have r0-r15. */
+# if defined (__CK807__) || defined (__CK810__)
+# define PIC_REG "r28"
+# endif
#else
# error "Modify the test for your target."
#endif
diff --git a/gcc/testsuite/gcc.dg/Wno-frame-address.c b/gcc/testsuite/gcc.dg/Wno-frame-address.c
index e6dfe52..9fe4d07 100644
--- a/gcc/testsuite/gcc.dg/Wno-frame-address.c
+++ b/gcc/testsuite/gcc.dg/Wno-frame-address.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-skip-if "Cannot access arbitrary stack frames" { arm*-*-* avr-*-* hppa*-*-* ia64-*-* visium-*-* } } */
+/* { dg-skip-if "Cannot access arbitrary stack frames" { arm*-*-* avr-*-* hppa*-*-* ia64-*-* visium-*-* csky-*-* } } */
/* { dg-options "-Werror" } */
/* { dg-additional-options "-mbackchain" { target { s390*-*-* } } } */
diff --git a/gcc/testsuite/gcc.dg/c11-true_min-1.c b/gcc/testsuite/gcc.dg/c11-true_min-1.c
index f666c72..1fbf514 100644
--- a/gcc/testsuite/gcc.dg/c11-true_min-1.c
+++ b/gcc/testsuite/gcc.dg/c11-true_min-1.c
@@ -1,6 +1,7 @@
/* { dg-do run } */
/* { dg-options "-std=c11" } */
/* { dg-xfail-run-if "PR58757 -mieee is required to compare denormals" { alpha*-*-* } } */
+/* { dg-skip-if "No subnormal support" { csky-*-* } { "-mhard-float" } } */
/* Test that the smallest positive value is not 0. This needs to be true
even when denormals are not supported, so we do not pass any flag
diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/pr80263.c b/gcc/testsuite/gcc.dg/debug/dwarf2/pr80263.c
index 57633b4..f1a6a33 100644
--- a/gcc/testsuite/gcc.dg/debug/dwarf2/pr80263.c
+++ b/gcc/testsuite/gcc.dg/debug/dwarf2/pr80263.c
@@ -1,6 +1,8 @@
/* PR debug/80263 */
/* { dg-do compile } */
/* { dg-options "-g -dA" } */
+/* Darwin emits pubnames/types by default - suppress this for the test. */
+/* { dg-additional-options "-gno-pubnames" { target *-*-darwin* } } */
char array[1];
diff --git a/gcc/testsuite/gcc.dg/format/gcc_diag-1.c b/gcc/testsuite/gcc.dg/format/gcc_diag-1.c
index 034e097..8761456 100644
--- a/gcc/testsuite/gcc.dg/format/gcc_diag-1.c
+++ b/gcc/testsuite/gcc.dg/format/gcc_diag-1.c
@@ -1,4 +1,4 @@
-/* Test for GCC diagnositc formats. */
+/* Test for GCC diagnostic formats. */
/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
/* { dg-do compile } */
/* { dg-options "-Wformat" } */
@@ -24,6 +24,7 @@ extern int diag (const char *, ...) ATTRIBUTE_DIAG(__gcc_diag__);
extern int tdiag (const char *, ...) ATTRIBUTE_DIAG(__gcc_tdiag__);
extern int cdiag (const char *, ...) ATTRIBUTE_DIAG(__gcc_cdiag__);
extern int cxxdiag (const char *, ...) ATTRIBUTE_DIAG(__gcc_cxxdiag__);
+extern int dump (const char *, ...) ATTRIBUTE_DIAG(__gcc_dump_printf__);
void
foo (int i, int i1, int i2, unsigned int u, double d, char *s, void *p,
@@ -39,36 +40,44 @@ foo (int i, int i1, int i2, unsigned int u, double d, char *s, void *p,
tdiag ("%%");
cdiag ("%%");
cxxdiag ("%%");
+ dump ("%%");
diag ("%d%i%o%u%x%c%s%p%%", i, i, u, u, u, i, s, p);
tdiag ("%d%i%o%u%x%c%s%p%%", i, i, u, u, u, i, s, p);
cdiag ("%d%i%o%u%x%c%s%p%%", i, i, u, u, u, i, s, p);
cxxdiag ("%d%i%o%u%x%c%s%p%%", i, i, u, u, u, i, s, p);
+ dump ("%d%i%o%u%x%c%s%p%%", i, i, u, u, u, i, s, p);
diag ("%qd%qi%qo%qu%qx%qc%qs%qp%<%%%'%>", i, i, u, u, u, i, s, p);
tdiag ("%qd%qi%qo%qu%qx%qc%qs%qp%<%%%'%>", i, i, u, u, u, i, s, p);
cdiag ("%qd%qi%qo%qu%qx%qc%qs%qp%<%%%'%>", i, i, u, u, u, i, s, p);
cxxdiag ("%qd%qi%qo%qu%qx%qc%qs%qp%<%%%'%>", i, i, u, u, u, i, s, p);
+ dump ("%qd%qi%qo%qu%qx%qc%qs%qp%<%%%'%>", i, i, u, u, u, i, s, p);
diag ("%ld%li%lo%lu%lx", l, l, ul, ul, ul);
tdiag ("%ld%li%lo%lu%lx", l, l, ul, ul, ul);
cdiag ("%ld%li%lo%lu%lx", l, l, ul, ul, ul);
cxxdiag ("%ld%li%lo%lu%lx", l, l, ul, ul, ul);
+ dump ("%ld%li%lo%lu%lx", l, l, ul, ul, ul);
diag ("%lld%lli%llo%llu%llx", ll, ll, ull, ull, ull);
tdiag ("%lld%lli%llo%llu%llx", ll, ll, ull, ull, ull);
cdiag ("%lld%lli%llo%llu%llx", ll, ll, ull, ull, ull);
cxxdiag ("%lld%lli%llo%llu%llx", ll, ll, ull, ull, ull);
+ dump ("%lld%lli%llo%llu%llx", ll, ll, ull, ull, ull);
diag ("%wd%wi%wo%wu%wx", ll, ll, ull, ull, ull);
tdiag ("%wd%wi%wo%wu%wx", ll, ll, ull, ull, ull);
cdiag ("%wd%wi%wo%wu%wx", ll, ll, ull, ull, ull);
cxxdiag ("%wd%wi%wo%wu%wx", ll, ll, ull, ull, ull);
+ dump ("%wd%wi%wo%wu%wx", ll, ll, ull, ull, ull);
diag ("%.*s", i, s);
tdiag ("%.*s", i, s);
cdiag ("%.*s", i, s);
cxxdiag ("%.*s", i, s);
+ dump ("%.*s", i, s);
/* Extensions provided in the diagnostic framework. */
diag ("%m");
tdiag ("%m");
cdiag ("%m");
cxxdiag ("%m");
+ dump ("%m");
/* Quote directives to avoid "warning: conversion used unquoted." */
tdiag ("%<%D%F%T%V%>", t1, t1, t1, t1);
@@ -94,20 +103,24 @@ foo (int i, int i1, int i2, unsigned int u, double d, char *s, void *p,
tdiag ("%Z", v, v_len);
cdiag ("%Z", v, v_len);
cxxdiag ("%Z", v, v_len);
+ dump ("%Z", v, v_len);
/* Bad stuff with extensions. */
diag ("%m", i); /* { dg-warning "format" "extra arg" } */
tdiag ("%m", i); /* { dg-warning "format" "extra arg" } */
cdiag ("%m", i); /* { dg-warning "format" "extra arg" } */
cxxdiag ("%m", i); /* { dg-warning "format" "extra arg" } */
+ dump ("%m", i); /* { dg-warning "format" "extra arg" } */
diag ("%#m"); /* { dg-warning "format" "bogus modifier" } */
tdiag ("%#m"); /* { dg-warning "format" "bogus modifier" } */
cdiag ("%#m"); /* { dg-warning "format" "bogus modifier" } */
cxxdiag ("%#m"); /* { dg-warning "format" "bogus modifier" } */
+ dump ("%#m"); /* { dg-warning "format" "bogus modifier" } */
diag ("%+m"); /* { dg-warning "format" "bogus modifier" } */
tdiag ("%+m"); /* { dg-warning "format" "bogus modifier" } */
cdiag ("%+m"); /* { dg-warning "format" "bogus modifier" } */
cxxdiag ("%+m"); /* { dg-warning "format" "bogus modifier" } */
+ dump ("%+m"); /* { dg-warning "format" "bogus modifier" } */
diag ("%D", t1); /* { dg-warning "format" "bogus tree" } */
tdiag ("%A", t1); /* { dg-warning "format" "bogus tree" } */
tdiag ("%E", t1);
diff --git a/gcc/testsuite/gcc.dg/format/gcc_diag-10.c b/gcc/testsuite/gcc.dg/format/gcc_diag-10.c
index 2965509..2f6a002 100644
--- a/gcc/testsuite/gcc.dg/format/gcc_diag-10.c
+++ b/gcc/testsuite/gcc.dg/format/gcc_diag-10.c
@@ -19,12 +19,16 @@ typedef union tree_node *tree;
the C test to find the symbol. */
typedef struct gimple gimple;
+/* Likewise for gimple. */
+typedef struct gimple gimple;
+
#define FORMAT(kind) __attribute__ ((format (__gcc_## kind ##__, 1, 2)))
void diag (const char*, ...) FORMAT (diag);
void cdiag (const char*, ...) FORMAT (cdiag);
void tdiag (const char*, ...) FORMAT (tdiag);
void cxxdiag (const char*, ...) FORMAT (cxxdiag);
+void dump (const char*, ...) FORMAT (dump_printf);
void test_diag (tree t, gimple *gc)
{
@@ -157,3 +161,25 @@ void test_cxxdiag (tree t, gimple *gc)
cxxdiag ("%<%V%>", t);
cxxdiag ("%<%X%>", t);
}
+
+void test_dump (tree t, gimple *stmt)
+{
+ dump ("%<"); /* { dg-warning "unterminated quoting directive" } */
+ dump ("%>"); /* { dg-warning "unmatched quoting directive " } */
+ dump ("%<foo%<bar%>%>"); /* { dg-warning "nested quoting directive" } */
+
+ dump ("%R"); /* { dg-warning "unmatched color reset directive" } */
+ dump ("%r", ""); /* { dg-warning "unterminated color directive" } */
+ dump ("%r%r", "", ""); /* { dg-warning "unterminated color directive" } */
+ dump ("%r%R", "");
+ dump ("%r%r%R", "", "");
+ dump ("%r%R%r%R", "", "");
+
+ dump ("%<%R%>"); /* { dg-warning "unmatched color reset directive" } */
+ dump ("%<%r%>", ""); /* { dg-warning "unterminated color directive" } */
+ dump ("%<%r%R%>", "");
+
+ dump ("%E", stmt);
+ dump ("%T", t);
+ dump ("%G", stmt);
+}
diff --git a/gcc/testsuite/gcc.dg/lto/pr83719_0.c b/gcc/testsuite/gcc.dg/lto/pr83719_0.c
index 6d5c16d..cd4cab3 100644
--- a/gcc/testsuite/gcc.dg/lto/pr83719_0.c
+++ b/gcc/testsuite/gcc.dg/lto/pr83719_0.c
@@ -1,4 +1,5 @@
/* { dg-lto-do assemble } */
+/* { dg-skip-if "split DWARF unsupported" { *-*-darwin* } } */
/* { dg-lto-options { { -flto -g -gsplit-dwarf } } } */
/* Empty. */
diff --git a/gcc/testsuite/gcc.dg/pr86064.c b/gcc/testsuite/gcc.dg/pr86064.c
index 5be820c..3397427 100644
--- a/gcc/testsuite/gcc.dg/pr86064.c
+++ b/gcc/testsuite/gcc.dg/pr86064.c
@@ -1,4 +1,5 @@
/* { dg-do compile } */
+/* { dg-skip-if "split DWARF unsupported" { *-*-darwin* } } */
/* { dg-options "-g -O2 -fno-var-tracking-assignments -gsplit-dwarf" } */
/* This used to fail with location views (implicitly) enabled, because
diff --git a/gcc/testsuite/gcc.dg/sibcall-10.c b/gcc/testsuite/gcc.dg/sibcall-10.c
index d89909a..54cc604 100644
--- a/gcc/testsuite/gcc.dg/sibcall-10.c
+++ b/gcc/testsuite/gcc.dg/sibcall-10.c
@@ -5,7 +5,7 @@
Copyright (C) 2002 Free Software Foundation Inc.
Contributed by Hans-Peter Nilsson <hp@bitrange.com> */
-/* { dg-do run { xfail { { cris-*-* crisv32-*-* h8300-*-* hppa*64*-*-* m32r-*-* mcore-*-* mn10300-*-* msp430*-*-* nds32*-*-* xstormy16-*-* v850*-*-* vax-*-* xtensa*-*-* } || { arm*-*-* && { ! arm32 } } } } } */
+/* { dg-do run { xfail { { cris-*-* crisv32-*-* csky-*-* h8300-*-* hppa*64*-*-* m32r-*-* mcore-*-* mn10300-*-* msp430*-*-* nds32*-*-* xstormy16-*-* v850*-*-* vax-*-* xtensa*-*-* } || { arm*-*-* && { ! arm32 } } } } } */
/* -mlongcall disables sibcall patterns. */
/* { dg-skip-if "" { powerpc*-*-* } { "-mlongcall" } { "" } } */
/* -msave-restore disables sibcall patterns. */
diff --git a/gcc/testsuite/gcc.dg/sibcall-9.c b/gcc/testsuite/gcc.dg/sibcall-9.c
index 8e30952..fc3bd9d 100644
--- a/gcc/testsuite/gcc.dg/sibcall-9.c
+++ b/gcc/testsuite/gcc.dg/sibcall-9.c
@@ -5,7 +5,7 @@
Copyright (C) 2002 Free Software Foundation Inc.
Contributed by Hans-Peter Nilsson <hp@bitrange.com> */
-/* { dg-do run { xfail { { cris-*-* crisv32-*-* h8300-*-* hppa*64*-*-* m32r-*-* mcore-*-* mn10300-*-* msp430*-*-* nds32*-*-* nvptx-*-* xstormy16-*-* v850*-*-* vax-*-* xtensa*-*-* } || { arm*-*-* && { ! arm32 } } } } } */
+/* { dg-do run { xfail { { cris-*-* crisv32-*-* csky-*-* h8300-*-* hppa*64*-*-* m32r-*-* mcore-*-* mn10300-*-* msp430*-*-* nds32*-*-* nvptx-*-* xstormy16-*-* v850*-*-* vax-*-* xtensa*-*-* } || { arm*-*-* && { ! arm32 } } } } } */
/* -mlongcall disables sibcall patterns. */
/* { dg-skip-if "" { powerpc*-*-* } { "-mlongcall" } { "" } } */
/* -msave-restore disables sibcall patterns. */
diff --git a/gcc/testsuite/gcc.dg/stack-usage-1.c b/gcc/testsuite/gcc.dg/stack-usage-1.c
index 038bd4e..e644014 100644
--- a/gcc/testsuite/gcc.dg/stack-usage-1.c
+++ b/gcc/testsuite/gcc.dg/stack-usage-1.c
@@ -101,6 +101,8 @@
#define SIZE 252
#elif defined (__M32R__)
#define SIZE 252
+#elif defined (__csky__)
+# define SIZE 252
#else
# define SIZE 256
#endif
diff --git a/gcc/testsuite/gcc.dg/torture/float32-tg-3.c b/gcc/testsuite/gcc.dg/torture/float32-tg-3.c
index b07c07a..e478a23 100644
--- a/gcc/testsuite/gcc.dg/torture/float32-tg-3.c
+++ b/gcc/testsuite/gcc.dg/torture/float32-tg-3.c
@@ -4,6 +4,7 @@
/* { dg-add-options float32 } */
/* { dg-add-options ieee } */
/* { dg-require-effective-target float32_runtime } */
+/* { dg-skip-if "No subnormal support" { csky-*-* } { "-mhard-float" } } */
#define WIDTH 32
#define EXT 0
diff --git a/gcc/testsuite/gcc.dg/torture/float32x-tg-3.c b/gcc/testsuite/gcc.dg/torture/float32x-tg-3.c
index 9f9f982..6f55779 100644
--- a/gcc/testsuite/gcc.dg/torture/float32x-tg-3.c
+++ b/gcc/testsuite/gcc.dg/torture/float32x-tg-3.c
@@ -4,6 +4,7 @@
/* { dg-add-options float32x } */
/* { dg-add-options ieee } */
/* { dg-require-effective-target float32x_runtime } */
+/* { dg-skip-if "No subnormal support" { csky-*-* } { "-mhard-float" } } */
#define WIDTH 32
#define EXT 1
diff --git a/gcc/testsuite/gcc.dg/torture/float64-tg-3.c b/gcc/testsuite/gcc.dg/torture/float64-tg-3.c
index a83e781..a1fead7 100644
--- a/gcc/testsuite/gcc.dg/torture/float64-tg-3.c
+++ b/gcc/testsuite/gcc.dg/torture/float64-tg-3.c
@@ -4,6 +4,7 @@
/* { dg-add-options float64 } */
/* { dg-add-options ieee } */
/* { dg-require-effective-target float64_runtime } */
+/* { dg-skip-if "No subnormal support" { csky-*-* } { "-mhard-float" } } */
#define WIDTH 64
#define EXT 0
diff --git a/gcc/testsuite/gcc.dg/torture/float64x-tg-3.c b/gcc/testsuite/gcc.dg/torture/float64x-tg-3.c
index 195c4fd..3cdd933 100644
--- a/gcc/testsuite/gcc.dg/torture/float64x-tg-3.c
+++ b/gcc/testsuite/gcc.dg/torture/float64x-tg-3.c
@@ -4,6 +4,7 @@
/* { dg-add-options float64x } */
/* { dg-add-options ieee } */
/* { dg-require-effective-target float64x_runtime } */
+/* { dg-skip-if "No subnormal support" { csky-*-* } { "-mhard-float" } } */
#define WIDTH 64
#define EXT 1
diff --git a/gcc/testsuite/gcc.dg/torture/type-generic-1.c b/gcc/testsuite/gcc.dg/torture/type-generic-1.c
index ef32b78..a5fa8e8 100644
--- a/gcc/testsuite/gcc.dg/torture/type-generic-1.c
+++ b/gcc/testsuite/gcc.dg/torture/type-generic-1.c
@@ -3,6 +3,7 @@
/* { dg-do run } */
/* { dg-skip-if "No Inf/NaN support" { spu-*-* } } */
+/* { dg-skip-if "No subnormal support" { csky-*-* } { "-mhard-float" } } */
/* { dg-options "-DUNSAFE" { target tic6x*-*-* visium-*-* nvptx-*-* } } */
/* { dg-add-options ieee } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-1.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-1.c
index 3fb3e6d..a94d123 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-1.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-1.c
@@ -1558,9 +1558,10 @@ void test_snprintf_c_const (char *d)
T (3, "%lc%c", (wint_t)'1', '2');
/* Here %lc may result in anywhere between 0 and MB_CUR_MAX characters
- so the minimum number of bytes on output is 2 (plus the terminating
- nul), but the likely number is 3 (plus the nul). */
- T (3, "%lc%c%c", (wint_t)'\x80', '2', '3'); /* { dg-warning ".%c. directive output may be truncated writing 1 byte into a region of size between 0 and 2" } */
+ so the output range is [0, 2, 6, 6] with the middle being used for
+ the diagnostic (and the extremes for optimization). The cast is
+ to prevent sign extension. */
+ T (3, "%lc%c%c", (wint_t)(unsigned char)'\x80', '2', '3'); /* { dg-warning ".%c. directive output may be truncated writing 1 byte into a region of size between 0 and 2" } */
/* It's reasonably safe that L'1' converts into the single byte '1'. */
T (3, "%lc%c%c", (wint_t)'1', '2', '3'); /* { dg-warning "output may be truncated" } */
T (3, "%lc%lc%c", (wint_t)'1', (wint_t)'2', '3'); /* { dg-warning "output may be truncated" } */
diff --git a/gcc/testsuite/gcc.target/csky/and1.c b/gcc/testsuite/gcc.target/csky/and1.c
new file mode 100644
index 0000000..14ce11a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/csky/and1.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-csky-options "-O1" } */
+
+/* Test special code generation patterns for bit operators. */
+
+int and1 (int x)
+{
+ return x & 0xfff7ffff;
+}
+
+/* { dg-final { scan-assembler "bclri" } } */
+
diff --git a/gcc/testsuite/gcc.target/csky/and2.c b/gcc/testsuite/gcc.target/csky/and2.c
new file mode 100644
index 0000000..c661199
--- /dev/null
+++ b/gcc/testsuite/gcc.target/csky/and2.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-csky-options "-O1" } */
+
+/* Test special code generation patterns for bit operators. */
+
+int and2 (int x)
+{
+ return x & 0xfff00000;
+}
+
+/* { dg-final { scan-assembler "lsri" } } */
+/* { dg-final { scan-assembler "lsli" } } */
diff --git a/gcc/testsuite/gcc.target/csky/and3a.c b/gcc/testsuite/gcc.target/csky/and3a.c
new file mode 100644
index 0000000..3d706f6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/csky/and3a.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-csky-options "-mcpu=ck801 -O1" } */
+
+/* Test special code generation patterns for bit operators. */
+
+int and3 (int x)
+{
+ return x & 0x000fffff;
+}
+
+/* { dg-final { scan-assembler "lsli" } } */
+/* { dg-final { scan-assembler "lsri" } } */
diff --git a/gcc/testsuite/gcc.target/csky/and3b.c b/gcc/testsuite/gcc.target/csky/and3b.c
new file mode 100644
index 0000000..127207d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/csky/and3b.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-csky-options "-mcpu=ck810f -O1" } */
+
+/* Test special code generation patterns for bit operators. */
+
+int and3 (int x)
+{
+ return x & 0x000fffff;
+}
+
+/* { dg-final { scan-assembler "zext" } } */
diff --git a/gcc/testsuite/gcc.target/csky/ck801-branch.c b/gcc/testsuite/gcc.target/csky/ck801-branch.c
new file mode 100644
index 0000000..95e6962
--- /dev/null
+++ b/gcc/testsuite/gcc.target/csky/ck801-branch.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-csky-options "-mcpu=ck801 -O1 -fno-reorder-blocks" } */
+
+/* Test branch generation on CK801, which cannot rely on assembler
+ branch relaxation because long branches clobber lr. */
+
+#define nop8 asm ("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop")
+#define nop64 nop8; nop8; nop8; nop8; nop8; nop8; nop8; nop8
+#define nop512 nop64; nop64; nop64; nop64; nop64; nop64; nop64; nop64
+#define nop4k nop512; nop512; nop512; nop512; nop512; nop512; nop512; nop512
+#define nop32k nop4k; nop4k; nop4k; nop4k; nop4k; nop4k; nop4k; nop4k
+
+extern void g (int);
+int f (int x, int y, int z)
+{
+ if (x == 0) // cmpnei; jbt
+ {
+ nop64;
+ x = y;
+ }
+ if (y == 0) // cmpnei; jbf; jbr
+ {
+ nop512;
+ y = z;
+ }
+ if (z == 0) // cmpnei; jbf; bsr
+ {
+ nop32k;
+ z = x;
+ }
+ return x + y + z;
+}
+
+/* { dg-final { scan-assembler "push.*lr" } } */
+/* { dg-final { scan-assembler "pop.*lr" } } */
+/* { dg-final { scan-assembler-times "cmpnei" 3 } } */
+/* { dg-final { scan-assembler-times "jbt" 1 } } */
+/* { dg-final { scan-assembler-times "jbf" 2 } } */
+/* { dg-final { scan-assembler-times "jbr" 1 } } */
+/* { dg-final { scan-assembler-times "bsr" 1 } } */
diff --git a/gcc/testsuite/gcc.target/csky/constpool-1.c b/gcc/testsuite/gcc.target/csky/constpool-1.c
new file mode 100644
index 0000000..5c7cfdc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/csky/constpool-1.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-csky-options "-mcpu=ck801 -O1" } */
+
+/* Make sure that constant pools are emitted by the compiler for ck801.
+ If this is deferred to the assembler, the compiler will compute
+ incorrect branch offsets. */
+
+void f (unsigned int *u, long long int *l, float *f, double *d)
+{
+ *u = 0xdeadbeef;
+ *l = 0xcafef00dc0ffeeULL;
+ *f = 3.14159F;
+ *d = 2.718281828459;
+}
+
+/* { dg-final { scan-assembler-times "\\.long" 6 } } */
diff --git a/gcc/testsuite/gcc.target/csky/constpool-2.c b/gcc/testsuite/gcc.target/csky/constpool-2.c
new file mode 100644
index 0000000..d654420
--- /dev/null
+++ b/gcc/testsuite/gcc.target/csky/constpool-2.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-csky-options "-mcpu=ck810f -O1 -mconstpool" } */
+
+/* Make sure that constant pools are emitted by the compiler when
+ -mconstpool is provided. */
+
+void f (unsigned int *u, long long int *l, float *f, double *d)
+{
+ *u = 0xdeadbeef;
+ *l = 0xcafef00dc0ffeeULL;
+ *f = 3.14159F;
+ *d = 2.718281828459;
+}
+
+/* { dg-final { scan-assembler-times "\\.long" 6 } } */
diff --git a/gcc/testsuite/gcc.target/csky/constpool-3.c b/gcc/testsuite/gcc.target/csky/constpool-3.c
new file mode 100644
index 0000000..e3a6e09
--- /dev/null
+++ b/gcc/testsuite/gcc.target/csky/constpool-3.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-csky-options "-mcpu=ck810f -O1 -mno-constpool" } */
+
+/* Make sure that constant pools are not emitted by the compiler when
+ -mno-constpool is provided. */
+
+void f (unsigned int *u, long long int *l, float *f, double *d)
+{
+ *u = 0xdeadbeef;
+ *l = 0xcafef00dc0ffeeULL;
+ *f = 3.14159F;
+ *d = 2.718281828459;
+}
+
+/* { dg-final { scan-assembler-not "\\.long" } } */
diff --git a/gcc/testsuite/gcc.target/csky/cse-cc.c b/gcc/testsuite/gcc.target/csky/cse-cc.c
new file mode 100644
index 0000000..b97a16e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/csky/cse-cc.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-csky-options "-O2" } */
+
+/* Test that the two comparisons are combined. This was formerly handled
+ by a no-longer-present target-specific pass and is now supposed to
+ be handled by generic CSE. */
+
+int e1, e2;
+
+void func (int a, int b, int c, int d, int f, int g)
+{
+ e1 = a > b ? f : g;
+ e2 = a > b ? c : d;
+
+ return;
+}
+
+/* { dg-final { scan-assembler-times "cmp" 1 } } */
+
diff --git a/gcc/testsuite/gcc.target/csky/csky.exp b/gcc/testsuite/gcc.target/csky/csky.exp
new file mode 100644
index 0000000..9569490
--- /dev/null
+++ b/gcc/testsuite/gcc.target/csky/csky.exp
@@ -0,0 +1,79 @@
+# GCC testsuite for C-SKY targets.
+# Copyright (C) 2012-2018 Free Software Foundation, Inc.
+# Contributed by C-SKY Microsystems and Mentor Graphics.
+#
+# This program 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 of the License, or
+# (at your option) any later version.
+#
+# This program 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/>.
+
+# Exit immediately if this isn't a C-SKY target.
+if ![istarget csky*-*-*] then {
+ return
+}
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# Like dg-options, but treats certain C-SKY-specific options specially:
+#
+# -mcpu=*
+# Select the target cpu. Skip the test if the multilib flags force
+# a different cpu.
+proc dg-csky-options {args} {
+ upvar dg-extra-tool-flags extra_tool_flags
+ upvar dg-do-what do_what
+
+ set multilib_cpu ""
+ set multilib_hf ""
+ set cpu ""
+
+ foreach flag [target_info multilib_flags] {
+ regexp "^-mcpu=(.*)" $flag dummy multilib_cpu
+ regexp "^-mhard-float" $flag multilib_hf
+ }
+
+ set flags [lindex $args 1]
+
+ foreach flag $flags {
+ regexp "^-mcpu=(.*)" $flag dummy cpu
+ }
+
+ if {$cpu == ""} then {
+ set extra_tool_flags $flags
+ } elseif {$multilib_cpu == "" || $multilib_cpu == $cpu} then {
+ if { ($cpu == "ck801" || $cpu == "ck802")
+ && $multilib_hf != "" } then {
+ set do_what [list [lindex $do_what 0] "N" "P"]
+ } else {
+ set extra_tool_flags $flags
+ }
+ } else {
+ set do_what [list [lindex $do_what 0] "N" "P"]
+ }
+}
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+ set DEFAULT_CFLAGS " -ansi -pedantic-errors"
+}
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cCS\]]] \
+ "" $DEFAULT_CFLAGS
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/gcc.target/csky/fnargs-1.c b/gcc/testsuite/gcc.target/csky/fnargs-1.c
new file mode 100644
index 0000000..5cc85b6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/csky/fnargs-1.c
@@ -0,0 +1,38 @@
+/* { dg-do run } */
+
+/* Check that a structure argument passed partially in registers and
+ partially on the stack works. */
+
+#include <stdlib.h>
+#include <string.h>
+
+struct s {
+ unsigned int i;
+ double d;
+ char s[16];
+};
+
+/* Note specifically that, since there are 4 argument registers, the
+ value of ss.d is split between the last argument register and the
+ stack. */
+void
+f (struct s *sp, int j, struct s ss, int k)
+{
+ if (sp->i != ss.i
+ || sp->d != ss.d
+ || strcmp (sp->s, ss.s))
+ abort ();
+ if (j != -k)
+ abort ();
+}
+
+int
+main (void)
+{
+ struct s ss;
+ ss.i = 0xdeadbeef;
+ ss.d = 2.71828;
+ strcpy (ss.s, "shazam!");
+ f (&ss, 42, ss, -42);
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/csky/fnargs-2.c b/gcc/testsuite/gcc.target/csky/fnargs-2.c
new file mode 100644
index 0000000..d4e1b71
--- /dev/null
+++ b/gcc/testsuite/gcc.target/csky/fnargs-2.c
@@ -0,0 +1,52 @@
+/* { dg-do run } */
+
+/* Check that varargs passed partially in registers and
+ partially on the stack works. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+struct s {
+ unsigned int i;
+ double d;
+ char s[16];
+};
+
+/* Note specifically that, as there are 4 argument registers,
+ the value of ss.d is split between the last argument register
+ and the stack. */
+void
+f (struct s *sp, ...)
+{
+ int j, k;
+ unsigned int i;
+ double d;
+ char *s;
+ va_list ap;
+ va_start (ap, sp);
+ j = va_arg (ap, int);
+ i = va_arg (ap, unsigned int);
+ d = va_arg (ap, double);
+ s = va_arg (ap, char *);
+ k = va_arg (ap, int);
+ va_end (ap);
+
+ if (sp->i != i
+ || sp->d != d
+ || strcmp (sp->s, s))
+ abort ();
+ if (j != -k)
+ abort ();
+}
+
+int
+main (void)
+{
+ struct s ss;
+ ss.i = 0xdeadbeef;
+ ss.d = 2.71828;
+ strcpy (ss.s, "shazam!");
+ f (&ss, 42, ss.i, ss.d, ss.s, -42);
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/csky/fnargs-3.c b/gcc/testsuite/gcc.target/csky/fnargs-3.c
new file mode 100644
index 0000000..8cf3e5c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/csky/fnargs-3.c
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+
+/* Check that sub-word sized elements of structures passed in in
+ registers are handled correctly with respect to the current endianness. */
+
+#include <stdlib.h>
+#include <string.h>
+
+struct s {
+ short h;
+ char s[8];
+};
+
+void
+f (struct s *sp, struct s ss)
+{
+ if (sp->h != ss.h
+ || strcmp (sp->s, ss.s))
+ abort ();
+}
+
+int
+main (void)
+{
+ struct s ss;
+ ss.h = 42;
+ strcpy (ss.s, "shazam!");
+ f (&ss, ss);
+ return 0;
+}
+
diff --git a/gcc/testsuite/gcc.target/csky/land1.c b/gcc/testsuite/gcc.target/csky/land1.c
new file mode 100644
index 0000000..e5ca51c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/csky/land1.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-csky-options "-O1" } */
+
+/* Test special code generation patterns for bit operators. */
+
+long long int land1 (long long int x)
+{
+ return x & 0xffffffff00000000LL;
+}
+
+/* { dg-final { scan-assembler "movi.*, 0" } } */
diff --git a/gcc/testsuite/gcc.target/csky/land2.c b/gcc/testsuite/gcc.target/csky/land2.c
new file mode 100644
index 0000000..b45e7b6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/csky/land2.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-csky-options "-O1" } */
+
+/* Test special code generation patterns for bit operators. */
+
+long long int land2 (long long int x)
+{
+ return x & 0x00000000ffffffffLL;
+}
+
+/* { dg-final { scan-assembler "movi.*, 0" } } */
diff --git a/gcc/testsuite/gcc.target/csky/naked.c b/gcc/testsuite/gcc.target/csky/naked.c
new file mode 100644
index 0000000..f81984c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/csky/naked.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-final { scan-assembler-not "push" } } */
+/* { dg-final { scan-assembler-not "pop" } } */
+
+/* Check that there is no prologue/epilogue code emitted for a function
+ with the naked attribute. Without the attribute, this function would
+ push/pop lr. */
+
+extern void g (int);
+
+int __attribute__((naked))
+f (int x)
+{
+ g (x);
+ return 42;
+}
diff --git a/gcc/testsuite/gcc.target/csky/or1.c b/gcc/testsuite/gcc.target/csky/or1.c
new file mode 100644
index 0000000..24918bc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/csky/or1.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-csky-options "-O1" } */
+
+/* Test special code generation patterns for bit operators. */
+
+int or1 (int x)
+{
+ return x | 0x00100000;
+}
+
+/* { dg-final { scan-assembler "bseti" } } */
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index c2d814c..b04ceb6 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -669,6 +669,7 @@ proc check_profiling_available { test_what } {
|| [istarget bfin-*-*]
|| [istarget cris-*-*]
|| [istarget crisv32-*-*]
+ || [istarget csky-*-elf]
|| [istarget fido-*-elf]
|| [istarget h8300-*-*]
|| [istarget lm32-*-*]
@@ -1228,6 +1229,16 @@ proc check_effective_target_hard_float { } {
# }]
}
+ # The generic test doesn't work for C-SKY because some cores have
+ # hard float for single precision only.
+ if { [istarget csky*-*-*] } {
+ return [check_no_compiler_messages hard_float assembly {
+ #if defined __csky_soft_float__
+ #error __csky_soft_float__
+ #endif
+ }]
+ }
+
# The generic test equates hard_float with "no call for adding doubles".
return [check_no_messages_and_pattern hard_float "!\\(call" rtl-expand {
double a (double b, double c) { return b + c; }
@@ -8843,6 +8854,7 @@ proc check_effective_target_logical_op_short_circuit {} {
|| [istarget arc*-*-*]
|| [istarget avr*-*-*]
|| [istarget crisv32-*-*] || [istarget cris-*-*]
+ || [istarget csky*-*-*]
|| [istarget mmix-*-*]
|| [istarget s390*-*-*]
|| [istarget powerpc*-*-*]
@@ -8861,6 +8873,7 @@ proc check_effective_target_logical_op_short_circuit {} {
proc check_effective_target_branch_cost {} {
if { [ istarget arm*-*-*]
|| [istarget avr*-*-*]
+ || [istarget csky*-*-*]
|| [istarget epiphany*-*-*]
|| [istarget frv*-*-*]
|| [istarget i?86-*-*] || [istarget x86_64-*-*]
diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c
index e20b502..d70d207 100644
--- a/gcc/tree-vect-data-refs.c
+++ b/gcc/tree-vect-data-refs.c
@@ -74,8 +74,7 @@ vect_lanes_optab_supported_p (const char *name, convert_optab optab,
{
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "no array mode for %s["
- HOST_WIDE_INT_PRINT_DEC "]\n",
+ "no array mode for %s[%wu]\n",
GET_MODE_NAME (mode), count);
return false;
}
@@ -1249,9 +1248,8 @@ vector_alignment_reachable_p (dr_vec_info *dr_info)
if (dump_enabled_p ())
{
dump_printf_loc (MSG_NOTE, vect_location,
- "data size =" HOST_WIDE_INT_PRINT_DEC, elmsize);
- dump_printf (MSG_NOTE,
- ". misalignment = %d.\n", DR_MISALIGNMENT (dr_info));
+ "data size = %wd. misalignment = %d.\n", elmsize,
+ DR_MISALIGNMENT (dr_info));
}
if (DR_MISALIGNMENT (dr_info) % elmsize)
{
diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c
index c167aec..db92f76 100644
--- a/gcc/tree-vect-loop.c
+++ b/gcc/tree-vect-loop.c
@@ -1958,7 +1958,7 @@ start_over:
dump_printf_loc (MSG_NOTE, vect_location,
"vectorization_factor = ");
dump_dec (MSG_NOTE, vectorization_factor);
- dump_printf (MSG_NOTE, ", niters = " HOST_WIDE_INT_PRINT_DEC "\n",
+ dump_printf (MSG_NOTE, ", niters = %wd\n",
LOOP_VINFO_INT_NITERS (loop_vinfo));
}
diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c
index 367945b..0a9ce24 100644
--- a/gcc/tree-vect-slp.c
+++ b/gcc/tree-vect-slp.c
@@ -2984,8 +2984,7 @@ vect_slp_bb (basic_block bb)
unsigned HOST_WIDE_INT bytes;
if (current_vector_size.is_constant (&bytes))
dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, vect_location,
- "basic block part vectorized using "
- HOST_WIDE_INT_PRINT_UNSIGNED " byte "
+ "basic block part vectorized using %wu byte "
"vectors\n", bytes);
else
dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, vect_location,
diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c
index d58729b..db4fb76 100644
--- a/gcc/tree-vectorizer.c
+++ b/gcc/tree-vectorizer.c
@@ -935,9 +935,7 @@ try_vectorize_loop_1 (hash_table<simduid_to_vf> *&simduid_to_vf_htab,
unsigned HOST_WIDE_INT bytes;
if (current_vector_size.is_constant (&bytes))
dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, vect_location,
- "loop vectorized vectorized using "
- HOST_WIDE_INT_PRINT_UNSIGNED " byte "
- "vectors\n", bytes);
+ "loop vectorized using %wu byte vectors\n", bytes);
else
dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, vect_location,
"loop vectorized using variable length vectors\n");
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index c79866f..2e347db 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -1,5 +1,36 @@
+2018-08-20 Nathan Sidwell <nathan@acm.org>
+
+ * include/cpp-id-data.h (struct answer): Delete.
+ * include/cpplib.h (struct answer): Don't forward-declare.
+ (enum cpp_macro_kind): Add cmk_assert.
+ (struct cpp_macro): Union parms and next assert chain.
+ (union _cpp_hashnode_value): 'answer' field is cpp_macro.
+ * directives.c (parse_answer): Convert to use cpp_macro. Return
+ true on success.
+ (parse_assertion, find_answer, _cpp_test_assertion, cpp_do_assert)
+ (cpp_do_unassert): Convert to use cpp_macro.
+ * macro.c (warn_of_redefinition, _cpp_new_macro)
+ (check_trad_stringification, cpp_macro_definition): Adjust macro
+ parm access.
+ * traditional.c (_cpp_replacement_text_len)
+ (_cpp_copy_replacement_text, _cpp_create_trad_definition): Likewise.
+
2018-08-17 Nathan Sidwell <nathan@acm.org>
+ * include/cpplib.h (struct cpp_callbacks): Replace
+ user_builtin_macro with user_lazy_macro.
+ (struct cpp_macro): add lazy field.
+ (enum cpp_builtin_type): Remove BT_FIRST_USER, BT_LAST_USER.
+ (cpp_define_lazily): Declare.
+ * macro.c (enter_macro_context) Use _cpp_maybe_notify_macro_use.
+ (warn_of_redefinition): Use cpp_builtin_macro_p, directly call
+ user_lazy_macro hook.
+ (_cpp_new_macro): Clear lazy field.
+ (cpp_define_lazily): Define.
+ (_cpp_notify_macro_use): Adjust lazy definition code.
+ (cpp_macro_definition): No need to do lazy definition here.
+ * pch.c (write_macdef, save_macros): Likewise.
+
* include/cpplib.h (enum cpp_macro_kind): New.
(struct cpp_macro): Make body trailing array. Add kind field,
delete traditional flag.
diff --git a/libcpp/directives.c b/libcpp/directives.c
index 0ccbf06..3425138 100644
--- a/libcpp/directives.c
+++ b/libcpp/directives.c
@@ -126,7 +126,7 @@ static void destringize_and_run (cpp_reader *, const cpp_string *,
source_location);
static bool parse_answer (cpp_reader *, int, source_location, cpp_macro **);
static cpp_hashnode *parse_assertion (cpp_reader *, int, cpp_macro **);
-static cpp_macro **find_assert (cpp_hashnode *, const cpp_macro *);
+static cpp_macro **find_answer (cpp_hashnode *, const cpp_macro *);
static void handle_assertion (cpp_reader *, const char *, int);
static void do_pragma_push_macro (cpp_reader *);
static void do_pragma_pop_macro (cpp_reader *);
@@ -696,7 +696,7 @@ undefine_macros (cpp_reader *pfile ATTRIBUTE_UNUSED, cpp_hashnode *h,
Macros and assertions no longer have anything to free. */
h->type = NT_VOID;
h->flags &= ~(NODE_POISONED|NODE_DISABLED|NODE_USED);
- h->value.assert = NULL;
+ h->value.answers = NULL;
return 1;
}
@@ -2256,12 +2256,12 @@ parse_assertion (cpp_reader *pfile, int type, cpp_macro **answer_ptr)
/* Returns a pointer to the pointer to CANDIDATE in the answer chain,
or a pointer to NULL if the answer is not in the chain. */
static cpp_macro **
-find_assert (cpp_hashnode *node, const cpp_macro *candidate)
+find_answer (cpp_hashnode *node, const cpp_macro *candidate)
{
unsigned int i;
cpp_macro **result = NULL;
- for (result = &node->value.assert; *result; result = &(*result)->parm.next)
+ for (result = &node->value.answers; *result; result = &(*result)->parm.next)
{
cpp_macro *answer = *result;
@@ -2295,8 +2295,8 @@ _cpp_test_assertion (cpp_reader *pfile, unsigned int *value)
if (node)
{
- if (node->value.assert)
- *value = !answer || *find_assert (node, answer);
+ if (node->value.answers)
+ *value = !answer || *find_answer (node, answer);
}
else if (pfile->cur_token[-1].type == CPP_EOF)
_cpp_backup_tokens (pfile, 1);
@@ -2316,7 +2316,7 @@ do_assert (cpp_reader *pfile)
{
/* Place the new answer in the answer list. First check there
is not a duplicate. */
- if (*find_assert (node, answer))
+ if (*find_answer (node, answer))
{
cpp_error (pfile, CPP_DL_WARNING, "\"%s\" re-asserted",
NODE_NAME (node) + 1);
@@ -2328,9 +2328,9 @@ do_assert (cpp_reader *pfile)
(pfile, sizeof (cpp_macro) - sizeof (cpp_token)
+ sizeof (cpp_token) * answer->count);
- answer->parm.next = node->value.assert;
-
- node->value.assert = answer;
+ /* Chain into the list. */
+ answer->parm.next = node->value.answers;
+ node->value.answers = answer;
check_eol (pfile, false);
}
@@ -2348,7 +2348,7 @@ do_unassert (cpp_reader *pfile)
{
if (answer)
{
- cpp_macro **p = find_assert (node, answer);
+ cpp_macro **p = find_answer (node, answer);
/* Remove the assert from the list. */
if (cpp_macro *temp = *p)
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index e1810f7..c9524a3 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -790,7 +790,7 @@ enum cpp_builtin_type
union GTY(()) _cpp_hashnode_value {
/* Assert (maybe NULL) */
- cpp_macro * GTY((tag ("NT_VOID"))) assert;
+ cpp_macro * GTY((tag ("NT_VOID"))) answers;
/* Macro (never NULL) */
cpp_macro * GTY((tag ("NT_USER_MACRO"))) macro;
/* Code for a builtin macro. */
diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog
index d499020..e800b36 100644
--- a/libgcc/ChangeLog
+++ b/libgcc/ChangeLog
@@ -1,3 +1,13 @@
+2018-08-17 Jojo <jijie_rong@c-sky.com>
+ Huibin Wang <huibin_wang@c-sky.com>
+ Sandra Loosemore <sandra@codesourcery.com>
+ Chung-Lin Tang <cltang@codesourcery.com>
+
+ C-SKY port: libgcc
+
+ * config.host: Add C-SKY support.
+ * config/csky/*: New.
+
2018-08-12 Chung-Ju Wu <jasonwucj@gmail.com>
* config/nds32/t-nds32-isr: Rearrange object dependency.
diff --git a/libgcc/config.host b/libgcc/config.host
index 18cabaf..bd4ef1e 100644
--- a/libgcc/config.host
+++ b/libgcc/config.host
@@ -108,6 +108,9 @@ cr16-*-*)
crisv32-*-*)
cpu_type=cris
;;
+csky*-*-*)
+ cpu_type=csky
+ ;;
fido-*-*)
cpu_type=m68k
;;
@@ -507,6 +510,15 @@ cris-*-elf)
cris-*-linux* | crisv32-*-linux*)
tmake_file="$tmake_file cris/t-cris t-softfp-sfdf t-softfp cris/t-linux"
;;
+csky-*-elf*)
+ tmake_file="csky/t-csky t-fdpbit"
+ extra_parts="$extra_parts crti.o crtn.o"
+ ;;
+csky-*-linux*)
+ tmake_file="$tmake_file csky/t-csky t-slibgcc-libgcc t-fdpbit csky/t-linux-csky"
+ extra_parts="$extra_parts crti.o crtn.o"
+ md_unwind_header=csky/linux-unwind.h
+ ;;
epiphany-*-elf* | epiphany-*-rtems*)
tmake_file="$tmake_file epiphany/t-epiphany t-fdpbit epiphany/t-custom-eqsf"
extra_parts="$extra_parts crti.o crtint.o crtrunc.o crtm1reg-r43.o crtm1reg-r63.o crtn.o"
diff --git a/libgcc/config/csky/crti.S b/libgcc/config/csky/crti.S
new file mode 100644
index 0000000..3e4beb9
--- /dev/null
+++ b/libgcc/config/csky/crti.S
@@ -0,0 +1,140 @@
+# Define _init and _fini entry points for C-SKY.
+# Copyright (C) 2018 Free Software Foundation, Inc.
+# Contributed by C-SKY Microsystems and Mentor Graphics.
+#
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 3, or (at your option) any
+# later version.
+#
+# This file is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# Under Section 7 of GPL version 3, you are granted additional
+# permissions described in the GCC Runtime Library Exception, version
+# 3.1, as published by the Free Software Foundation.
+#
+# You should have received a copy of the GNU General Public License and
+# a copy of the GCC Runtime Library Exception along with this program;
+# see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+# <http://www.gnu.org/licenses/>.
+
+
+# This file just makes a stack frame for the contents of the .fini and
+# .init sections. Users may put any desired instructions in those
+# sections.
+
+ .file "crti.S"
+
+/* We use more complicated versions of this code with GLIBC. */
+#if defined(__gnu_linux__)
+
+#ifndef PREINIT_FUNCTION
+# define PREINIT_FUNCTION __gmon_start__
+#endif
+
+#ifndef PREINIT_FUNCTION_WEAK
+# define PREINIT_FUNCTION_WEAK 1
+#endif
+
+#if PREINIT_FUNCTION_WEAK
+ .global PREINIT_FUNCTION
+ .weak PREINIT_FUNCTION
+ .align 4
+ .type call_weak_fn, %function
+call_weak_fn:
+ // push lr
+ subi sp, 4
+ stw lr, (sp)
+#ifdef __PIC__
+ lrw a2, PREINIT_FUNCTION@GOT
+ addu a2, gb
+ ldw a2, (a2)
+#else
+ lrw a2, PREINIT_FUNCTION
+#endif
+ cmpnei a2, 0
+ bf 1f
+ jsr a2
+1:
+ // pop lr
+ ldw lr, (sp)
+ addi sp, 4
+ rts
+
+ .align 4
+#else
+ .hidden PREINIT_FUNCTION
+#endif /* PREINIT_FUNCTION_WEAK */
+
+ .section .init,"ax",@progbits
+ .align 4
+ .globl _init
+ .type _init, @function
+_init:
+ subi sp, 8
+ stw lr, (sp, 0)
+#ifdef __PIC__
+ // stw gb, (sp, 4)
+ bsr .Lgetpc
+.Lgetpc:
+ lrw gb, .Lgetpc@GOTPC
+ add gb, lr
+#endif
+#if PREINIT_FUNCTION_WEAK
+#ifdef __PIC__
+ lrw a2, call_weak_fn@GOTOFF
+ add a2, gb
+ jsr a2
+#else
+ jsri call_weak_fn
+#endif
+#else /* !PREINIT_FUNCTION_WEAK */
+#ifdef __PIC__
+ lrw a2, PREINIT_FUNCTION@PLT
+ addu a2, gb
+ ldw a2, (a2)
+ jsr a2
+#else
+ jsri PREINIT_FUNCTION
+#endif
+#endif /* PREINIT_FUNCTION_WEAK */
+
+ br 2f
+ .literals
+ .align 4
+2:
+ .section .fini,"ax",@progbits
+ .align 4
+ .globl _fini
+ .type _fini, @function
+_fini:
+ subi sp,8
+ stw lr, (sp, 0)
+ br 2f
+ .literals
+ .align 4
+2:
+
+/* These are the non-GLIBC versions. */
+#else /* !defined(__gnu_linux__) */
+ .section ".init"
+ .global _init
+ .type _init,@function
+ .align 2
+_init:
+ subi sp, 16
+ st.w lr, (sp, 12)
+ mov r0, r0
+
+ .section ".fini"
+ .global _fini
+ .type _fini,@function
+ .align 2
+_fini:
+ subi sp, 16
+ st.w lr, (sp, 12)
+ mov r0, r0
+#endif /* defined(__gnu_linux__) */
diff --git a/libgcc/config/csky/crtn.S b/libgcc/config/csky/crtn.S
new file mode 100644
index 0000000..8bef996
--- /dev/null
+++ b/libgcc/config/csky/crtn.S
@@ -0,0 +1,55 @@
+# Terminate C-SKY .init and .fini sections.
+# Copyright (C) 2018 Free Software Foundation, Inc.
+# Contributed by C-SKY Microsystems and Mentor Graphics.
+#
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 3, or (at your option) any
+# later version.
+#
+# This file is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# Under Section 7 of GPL version 3, you are granted additional
+# permissions described in the GCC Runtime Library Exception, version
+# 3.1, as published by the Free Software Foundation.
+#
+# You should have received a copy of the GNU General Public License and
+# a copy of the GCC Runtime Library Exception along with this program;
+# see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+# <http://www.gnu.org/licenses/>.
+
+
+# This file just makes sure that the .fini and .init sections do in
+# fact return. Users may put any desired instructions in those sections.
+# This file is the last thing linked into any executable.
+
+ .file "crtn.S"
+
+# Is this the GLIBC version?
+#if defined(__gnu_linux__)
+ .section .init,"ax",@progbits
+ ldw lr, (sp, 0)
+ addi sp, 8
+ rts
+
+ .section .fini,"ax",@progbits
+ ldw lr, (sp, 0)
+ addi sp, 8
+ rts
+
+#else /* !defined(__gnu_linux__) */
+ .section ".init"
+ ldw lr, (sp, 12)
+ addi sp, 16
+ jmp lr
+
+ .section ".fini"
+ ldw lr, (sp, 12)
+ addi sp, 16
+ jmp lr
+
+# Th-th-th-that is all folks!
+#endif /* defined(__gnu_linux__) */
diff --git a/libgcc/config/csky/lib1funcs.S b/libgcc/config/csky/lib1funcs.S
new file mode 100644
index 0000000..a0a3c73
--- /dev/null
+++ b/libgcc/config/csky/lib1funcs.S
@@ -0,0 +1,675 @@
+/* libgcc routines 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.
+
+ This file is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+
+/* Use the right prefix for global labels. */
+#define CONCAT1(a, b) CONCAT2(a, b)
+#define CONCAT2(a, b) a ## b
+#define SYM(x) CONCAT1 (__, x)
+
+#ifndef __CSKYBE__
+#define xl r0
+#define xh r1
+#define yl r2
+#define yh r3
+#else
+#define xh r0
+#define xl r1
+#define yh r2
+#define yl r3
+#endif
+
+
+#ifdef __ELF__
+#define TYPE(x) .type SYM (x),@function
+#define SIZE(x) .size SYM (x), . - SYM (x)
+#else
+#define TYPE(x)
+#define SIZE(x)
+#endif
+
+.macro FUNC_START name
+ .text
+ .align 2
+ .globl SYM (\name)
+ TYPE (\name)
+SYM (\name):
+.endm
+
+.macro FUNC_END name
+ SIZE (\name)
+.endm
+
+
+/* Emulate FF1 ("fast find 1") instruction on ck801.
+ Result goes in rx, clobbering ry. */
+#if defined(__CK801__)
+.macro FF1_M rx, ry
+ movi \rx, 32
+10:
+ cmphsi \ry, 1
+ bf 11f
+ subi \rx, \rx, 1
+ lsri \ry, \ry, 1
+ br 10b
+11:
+.endm
+#else
+.macro FF1_M rx, ry
+ ff1 \rx, \ry
+.endm
+#endif
+
+/* Likewise emulate lslc instruction ("logical left shift to C") on CK801. */
+#if defined(__CK801__)
+.macro LSLC_M rx
+ cmpne \rx, \rx
+ addc \rx, \rx
+.endm
+#else
+.macro LSLC_M rx
+ lslc \rx
+.endm
+#endif
+
+/* Emulate the abs instruction. */
+#if defined(__CK802__)
+.macro ABS_M rx
+ btsti \rx, 31
+ bf 10f
+ not \rx
+ addi \rx, 1
+10:
+.endm
+#elif defined(__CK801__)
+.macro ABS_M rx
+ cmplti \rx, 1
+ bf 10f
+ not \rx
+ addi \rx, 1
+10:
+.endm
+#else
+.macro ABS_M rx
+ abs \rx
+.endm
+#endif
+
+/* Emulate the ld.hs ("load signed halfword and extend") instruction
+ on ck801 and ck802. */
+#if defined(__CK801__)
+.macro LDBS_M rx, ry
+ ld.b \rx, (\ry, 0x0)
+ sextb \rx, \rx
+.endm
+#else
+.macro LDBS_M rx, ry
+ ld.bs \rx, (\ry, 0x0)
+.endm
+#endif
+
+#if defined(__CK801__)
+.macro LDHS_M rx, ry
+ ld.h \rx, (\ry, 0x0)
+ sexth \rx, \rx
+.endm
+#else
+.macro LDHS_M rx, ry
+ ld.hs \rx, (\ry, 0x0)
+.endm
+#endif
+
+
+/* Signed and unsigned div/mod/rem functions. */
+
+#ifdef L_udivsi3
+FUNC_START udiv32
+FUNC_START udivsi3
+ cmpnei a1, 0 // look for 0 divisor
+ bt 9f
+ trap 3 // divide by 0
+9:
+ // control iterations, skip across high order 0 bits in dividend
+ cmpnei a0, 0
+ bt 8f
+ jmp lr // 0 dividend quick return
+8:
+ push l0
+ movi a2, 1 // a2 is quotient (1 for a sentinel)
+ mov a3, a0
+ FF1_M l0, a3 // figure distance to skip
+ lsl a2, l0 // move the sentinel along (with 0's behind)
+ lsl a0, l0 // and the low 32 bits of numerator
+
+ // FIXME: Is this correct?
+ mov a3, a1 // looking at divisor
+ FF1_M l0, a3 // I can move 32-l0 more bits to left.
+ addi l0, 1 // ok, one short of that...
+ mov a3, a0
+ lsr a3, l0 // bits that came from low order...
+ not l0 // l0 == "32-n" == LEFT distance
+ addi l0, 33 // this is (32-n)
+ lsl a2,l0 // fixes the high 32 (quotient)
+ lsl a0,l0
+ cmpnei a2,0
+ bf 4f // the sentinel went away...
+
+ // run the remaining bits
+1:
+ LSLC_M a0 // 1 bit left shift of a3-a0
+ addc a3, a3
+ cmphs a3, a1 // upper 32 of dividend >= divisor?
+ bf 2f
+ subu a3, a1 // if yes, subtract divisor
+2:
+ addc a2, a2 // shift by 1 and count subtracts
+ bf 1b // if sentinel falls out of quotient, stop
+
+4:
+ mov a0, a2 // return quotient
+ mov a1, a3 // and piggyback the remainder
+ pop l0
+FUNC_END udiv32
+FUNC_END udivsi3
+#endif
+
+#ifdef L_umodsi3
+FUNC_START urem32
+FUNC_START umodsi3
+ cmpnei a1, 0 // look for 0 divisor
+ bt 9f
+ trap 3 // divide by 0
+9:
+ // control iterations, skip across high order 0 bits in dividend
+ cmpnei a0, 0
+ bt 8f
+ jmp lr // 0 dividend quick return
+8:
+ mov a2, a0
+ FF1_M a3, a2 // figure distance to skip
+ movi a2, 1 // a2 is quotient (1 for a sentinel)
+ lsl a2, a3 // move the sentinel along (with 0's behind)
+ lsl a0, a3 // and the low 32 bits of numerator
+ movi a3, 0
+
+1:
+ LSLC_M a0 // 1 bit left shift of a3-a0
+ addc a3, a3
+ cmphs a3, a1 // upper 32 of dividend >= divisor?
+ bf 2f
+ subu a3, a1 // if yes, subtract divisor
+2:
+ addc a2, a2 // shift by 1 and count subtracts
+ bf 1b // if sentinel falls out of quotient, stop
+
+4:
+ mov a0, a3 // and piggyback the remainder
+ jmp lr
+FUNC_END urem32
+FUNC_END umodsi3
+#endif
+
+
+#ifdef L_divsi3
+FUNC_START div32
+FUNC_START divsi3
+ cmpnei a1, 0 // look for 0 divisor
+ bt 9f
+ trap 3 // divide by 0
+9:
+ // control iterations, skip across high order 0 bits in dividend
+ cmpnei a0, 0
+ bt 8f
+ jmp lr // 0 dividend quick return
+8:
+ push l0, l1
+ mov l1, a0
+ xor l1, a1 // calc sign of quotient
+ ABS_M a0
+ ABS_M a1
+ movi a2, 1 // a2 is quotient (1 for a sentinel)
+ mov a3, a0
+ FF1_M l0, a3 // figure distance to skip
+ lsl a2, l0 // move the sentinel along (with 0's behind)
+ lsl a0, l0 // and the low 32 bits of numerator
+
+ // FIXME: is this correct?
+ mov a3, a1 // looking at divisor
+ FF1_M l0, a3 // I can move 32-l0 more bits to left.
+ addi l0, 1 // ok, one short of that...
+ mov a3, a0
+ lsr a3, l0 // bits that came from low order...
+ not l0 // l0 == "32-n" == LEFT distance
+ addi l0, 33 // this is (32-n)
+ lsl a2,l0 // fixes the high 32 (quotient)
+ lsl a0,l0
+ cmpnei a2,0
+ bf 4f // the sentinel went away...
+
+ // run the remaining bits
+1:
+ LSLC_M a0 // 1 bit left shift of a3-a0
+ addc a3, a3
+ cmphs a3, a1 // upper 32 of dividend >= divisor?
+ bf 2f
+ subu a3, a1 // if yes, subtract divisor
+2:
+ addc a2, a2 // shift by 1 and count subtracts
+ bf 1b // if sentinel falls out of quotient, stop
+
+4:
+ mov a0, a2 // return quotient
+ mov a1, a3 // and piggyback the remainder
+ LSLC_M l1 // after adjusting for sign
+ bf 3f
+ not a0
+ addi a0, 1
+ not a1
+ addi a1, 1
+3:
+ pop l0, l1
+FUNC_END div32
+FUNC_END divsi3
+#endif
+
+#ifdef L_modsi3
+FUNC_START rem32
+FUNC_START modsi3
+ push l0
+ cmpnei a1, 0 // look for 0 divisor
+ bt 9f
+ trap 3 // divide by 0
+9:
+ // control iterations, skip across high order 0 bits in dividend
+ cmpnei a0, 0
+ bt 8f
+ pop l0 // 0 dividend quick return
+8:
+ mov l0, a0
+ ABS_M a0
+ ABS_M a1
+ mov a2, a0
+ FF1_M a3, a2 // figure distance to skip
+ movi a2, 1 // a2 is quotient (1 for a sentinel)
+ lsl a2, a3 // move the sentinel along (with 0's behind)
+ lsl a0, a3 // and the low 32 bits of numerator
+ movi a3, 0
+
+ // run the remaining bits
+1:
+ LSLC_M a0 // 1 bit left shift of a3-a0
+ addc a3, a3
+ cmphs a3, a1 // upper 32 of dividend >= divisor?
+ bf 2f
+ subu a3, a1 // if yes, subtract divisor
+2:
+ addc a2, a2 // shift by 1 and count subtracts
+ bf 1b // if sentinel falls out of quotient, stop
+
+4:
+ mov a0, a3 // and piggyback the remainder
+ LSLC_M l0 // after adjusting for sign
+ bf 3f
+ not a0
+ addi a0, 1
+3:
+ pop l0
+FUNC_END rem32
+FUNC_END modsi3
+#endif
+
+/* Unordered comparisons for single and double float. */
+
+#ifdef L_unordsf2
+FUNC_START unordsf2
+#if defined(__CK801__)
+ subi sp, 4
+ st.w r4, (sp, 0x0)
+ lsli r2, r0, 1
+ lsli r3, r1, 1
+ asri r4, r2, 24
+ not r4
+ cmpnei r4, 0
+ bt 1f
+ lsli r4, r0, 9
+ cmpnei r4, 0
+ bt 3f
+1:
+ asri r4, r3, 24
+ not r4
+ cmpnei r4, 0
+ bt 2f
+ lsli r4, r1, 9
+ cmpnei r4, 0
+ bt 3f
+2:
+ ld.w r4, (sp, 0x0)
+ addi sp, 4
+ movi r0, 0
+ rts
+3:
+ ld.w r4, (sp, 0x0)
+ addi sp, 4
+ movi r0, 1
+ rts
+#elif defined(__CK802__)
+ lsli r2, r0, 1
+ lsli r3, r1, 1
+ asri r2, r2, 24
+ not r13, r2
+ cmpnei r13, 0
+ bt 1f
+ lsli r13, r0, 9
+ cmpnei r13, 0
+ bt 3f
+1:
+ asri r3, r3, 24
+ not r13, r3
+ cmpnei r13, 0
+ bt 2f
+ lsli r13, r1, 9
+ cmpnei r13, 0
+ bt 3f
+2:
+ movi r0, 0
+ rts
+3:
+ movi r0, 1
+ rts
+#else
+ lsli r2, r0, 1
+ lsli r3, r1, 1
+ asri r2, r2, 24
+ not r13, r2
+ bnez r13, 1f
+ lsli r13, r0, 9
+ bnez r13, 3f
+1:
+ asri r3, r3, 24
+ not r13, r3
+ bnez r13, 2f
+ lsli r13, r1, 9
+ bnez r13, 3f
+2:
+ movi r0, 0
+ rts
+3:
+ movi r0, 1
+ rts
+#endif
+FUNC_END unordsf2
+#endif
+
+#ifdef L_unorddf2
+FUNC_START unorddf2
+#if defined(__CK801__)
+ subi sp, 8
+ st.w r4, (sp, 0x0)
+ st.w r5, (sp, 0x4)
+ lsli r4, xh, 1
+ asri r4, r4, 21
+ not r4
+ cmpnei r4, 0
+ bt 1f
+ mov r4, xl
+ lsli r5, xh, 12
+ or r4, r5
+ cmpnei r4, 0
+ bt 3f
+1:
+ lsli r4, yh, 1
+ asri r4, r4, 21
+ not r4
+ cmpnei r4, 0
+ bt 2f
+ mov r4,yl
+ lsli r5, yh, 12
+ or r4, r5
+ cmpnei r4, 0
+ bt 3f
+2:
+ ld.w r4, (sp, 0x0)
+ ld.w r5, (sp, 0x4)
+ addi sp, 8
+ movi r0, 0
+ rts
+3:
+ ld.w r4, (sp, 0x0)
+ ld.w r5, (sp, 0x4)
+ addi sp, 8
+ movi r0, 1
+ rts
+#elif defined(__CK802__)
+ lsli r13, xh, 1
+ asri r13, r13, 21
+ not r13
+ cmpnei r13, 0
+ bt 1f
+ lsli xh, xh, 12
+ or r13, xl, xh
+ cmpnei r13, 0
+ bt 3f
+1:
+ lsli r13, yh, 1
+ asri r13, r13, 21
+ not r13
+ cmpnei r13, 0
+ bt 2f
+ lsli yh, yh, 12
+ or r13, yl, yh
+ cmpnei r13, 0
+ bt 3f
+2:
+ movi r0, 0
+ rts
+3:
+ movi r0, 1
+ rts
+#else
+ lsli r13, xh, 1
+ asri r13, r13, 21
+ not r13
+ bnez r13, 1f
+ lsli xh, xh, 12
+ or r13, xl, xh
+ bnez r13, 3f
+1:
+ lsli r13, yh, 1
+ asri r13, r13, 21
+ not r13
+ bnez r13, 2f
+ lsli yh, yh, 12
+ or r13, yl, yh
+ bnez r13, 3f
+2:
+ movi r0, 0
+ rts
+3:
+ movi r0, 1
+ rts
+#endif
+FUNC_END unorddf2
+#endif
+
+/* When optimizing for size on ck801 and ck802, GCC emits calls to the
+ following helper functions when expanding casesi, instead of emitting
+ the table lookup and jump inline. Note that in these functions the
+ jump is handled by tweaking the value of lr before rts. */
+#ifdef L_csky_case_sqi
+FUNC_START _gnu_csky_case_sqi
+ subi sp, 4
+ st.w a1, (sp, 0x0)
+ mov a1, lr
+ add a1, a1, a0
+ LDBS_M a1, a1
+ lsli a1, a1, 1
+ add lr, lr, a1
+ ld.w a1, (sp, 0x0)
+ addi sp, 4
+ rts
+FUNC_END _gnu_csky_case_sqi
+#endif
+
+#ifdef L_csky_case_uqi
+FUNC_START _gnu_csky_case_uqi
+ subi sp, 4
+ st.w a1, (sp, 0x0)
+ mov a1, lr
+ add a1, a1, a0
+ ld.b a1, (a1, 0x0)
+ lsli a1, a1, 1
+ add lr, lr, a1
+ ld.w a1, (sp, 0x0)
+ addi sp, 4
+ rts
+FUNC_END _gnu_csky_case_uqi
+#endif
+
+#ifdef L_csky_case_shi
+FUNC_START _gnu_csky_case_shi
+ subi sp, 8
+ st.w a0, (sp, 0x4)
+ st.w a1, (sp, 0x0)
+ mov a1, lr
+ lsli a0, a0, 1
+ add a1, a1, a0
+ LDHS_M a1, a1
+ lsli a1, a1, 1
+ add lr, lr, a1
+ ld.w a0, (sp, 0x4)
+ ld.w a1, (sp, 0x0)
+ addi sp, 8
+ rts
+FUNC_END _gnu_csky_case_shi
+#endif
+
+#ifdef L_csky_case_uhi
+FUNC_START _gnu_csky_case_uhi
+ subi sp, 8
+ st.w a0, (sp, 0x4)
+ st.w a1, (sp, 0x0)
+ mov a1, lr
+ lsli a0, a0, 1
+ add a1, a1, a0
+ ld.h a1, (a1, 0x0)
+ lsli a1, a1, 1
+ add lr, lr, a1
+ ld.w a0, (sp, 0x4)
+ ld.w a1, (sp, 0x0)
+ addi sp, 8
+ rts
+FUNC_END _gnu_csky_case_uhi
+#endif
+
+#ifdef L_csky_case_si
+FUNC_START _gnu_csky_case_si
+ subi sp, 8
+ st.w a0, (sp, 0x4)
+ st.w a1, (sp, 0x0)
+ mov a1, lr
+ addi a1, a1, 2 // Align to word.
+ bclri a1, a1, 1
+ mov lr, a1
+ lsli a0, a0, 2
+ add a1, a1, a0
+ ld.w a0, (a1, 0x0)
+ add lr, lr, a0
+ ld.w a0, (sp, 0x4)
+ ld.w a1, (sp, 0x0)
+ addi sp, 8
+ rts
+FUNC_END _gnu_csky_case_si
+#endif
+
+/* GCC expects that {__eq,__ne,__gt,__ge,__le,__lt}{df2,sf2}
+ will behave as __cmpdf2. So, we stub the implementations to
+ jump on to __cmpdf2 and __cmpsf2.
+
+ All of these short-circuit the return path so that __cmp{sd}f2
+ will go directly back to the caller. */
+
+.macro COMPARE_DF_JUMP name
+ .import SYM (cmpdf2)
+FUNC_START \name
+ jmpi SYM (cmpdf2)
+FUNC_END \name
+.endm
+
+#ifdef L_eqdf2
+COMPARE_DF_JUMP eqdf2
+#endif /* L_eqdf2 */
+
+#ifdef L_nedf2
+COMPARE_DF_JUMP nedf2
+#endif /* L_nedf2 */
+
+#ifdef L_gtdf2
+COMPARE_DF_JUMP gtdf2
+#endif /* L_gtdf2 */
+
+#ifdef L_gedf2
+COMPARE_DF_JUMP gedf2
+#endif /* L_gedf2 */
+
+#ifdef L_ltdf2
+COMPARE_DF_JUMP ltdf2
+#endif /* L_ltdf2 */
+
+#ifdef L_ledf2
+COMPARE_DF_JUMP ledf2
+#endif /* L_ledf2 */
+
+/* Single-precision floating point stubs. */
+
+.macro COMPARE_SF_JUMP name
+ .import SYM (cmpsf2)
+FUNC_START \name
+ jmpi SYM (cmpsf2)
+FUNC_END \name
+.endm
+
+#ifdef L_eqsf2
+COMPARE_SF_JUMP eqsf2
+#endif /* L_eqsf2 */
+
+#ifdef L_nesf2
+COMPARE_SF_JUMP nesf2
+#endif /* L_nesf2 */
+
+#ifdef L_gtsf2
+COMPARE_SF_JUMP gtsf2
+#endif /* L_gtsf2 */
+
+#ifdef L_gesf2
+COMPARE_SF_JUMP __gesf2
+#endif /* L_gesf2 */
+
+#ifdef L_ltsf2
+COMPARE_SF_JUMP __ltsf2
+#endif /* L_ltsf2 */
+
+#ifdef L_lesf2
+COMPARE_SF_JUMP lesf2
+#endif /* L_lesf2 */
diff --git a/libgcc/config/csky/linux-atomic.c b/libgcc/config/csky/linux-atomic.c
new file mode 100644
index 0000000..03cf2c0
--- /dev/null
+++ b/libgcc/config/csky/linux-atomic.c
@@ -0,0 +1,299 @@
+/* Linux-specific atomic operations 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.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* Kernel helper for compare-and-exchange. */
+inline int
+__kernel_cmpxchg (int oldval, int newval, volatile int *ptr)
+{
+ register int _a0 asm ("a0") = oldval;
+ register int _a1 asm ("a1") = newval;
+ register volatile int *_a2 asm ("a2") = ptr;
+ __asm__ __volatile__ ("trap 2\n" \
+ :"+r" (_a0) :"r" (_a1) , "r" (_a2) \
+ : "a3", "memory"); \
+ return _a0;
+}
+
+
+/* Kernel helper for memory barrier. */
+inline void __kernel_dmb (void)
+{
+ asm ("sync":::"memory");
+}
+
+/* Note: we implement byte, short and int versions of atomic operations using
+ the above kernel helpers, but there is no support for "long long" (64-bit)
+ operations as yet. */
+
+#define HIDDEN __attribute__ ((visibility ("hidden")))
+
+#ifdef __CSKYLE__
+#define INVERT_MASK_1 0
+#define INVERT_MASK_2 0
+#else
+#define INVERT_MASK_1 24
+#define INVERT_MASK_2 16
+#endif
+
+#define MASK_1 0xffu
+#define MASK_2 0xffffu
+
+#define FETCH_AND_OP_WORD(OP, PFX_OP, INF_OP) \
+ int HIDDEN \
+ __sync_fetch_and_##OP##_4 (int *ptr, int val) \
+ { \
+ int failure, tmp; \
+ \
+ do \
+ { \
+ tmp = *ptr; \
+ failure = __kernel_cmpxchg (tmp, PFX_OP (tmp INF_OP val), ptr); \
+ } \
+ while (failure != 0); \
+ \
+ return tmp; \
+ }
+
+FETCH_AND_OP_WORD (add, , +)
+FETCH_AND_OP_WORD (sub, , -)
+FETCH_AND_OP_WORD (or, , |)
+FETCH_AND_OP_WORD (and, , &)
+FETCH_AND_OP_WORD (xor, , ^)
+FETCH_AND_OP_WORD (nand, ~, &)
+
+#define NAME_oldval(OP, WIDTH) __sync_fetch_and_##OP##_##WIDTH
+#define NAME_newval(OP, WIDTH) __sync_##OP##_and_fetch_##WIDTH
+
+/* Implement both __sync_<op>_and_fetch and __sync_fetch_and_<op> for
+ subword-sized quantities. */
+
+#define SUBWORD_SYNC_OP(OP, PFX_OP, INF_OP, TYPE, WIDTH, RETURN) \
+ TYPE HIDDEN \
+ NAME##_##RETURN (OP, WIDTH) (TYPE *ptr, TYPE val) \
+ { \
+ int *wordptr = (int *) ((unsigned int) ptr & ~3); \
+ unsigned int mask, shift, oldval, newval; \
+ int failure; \
+ \
+ shift = (((unsigned int) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \
+ mask = MASK_##WIDTH << shift; \
+ \
+ do \
+ { \
+ oldval = *wordptr; \
+ newval = ((PFX_OP (((oldval & mask) >> shift) \
+ INF_OP (unsigned int) val)) << shift) & mask; \
+ newval |= oldval & ~mask; \
+ failure = __kernel_cmpxchg (oldval, newval, wordptr); \
+ } \
+ while (failure != 0); \
+ \
+ return (RETURN & mask) >> shift; \
+ }
+
+SUBWORD_SYNC_OP (add, , +, unsigned short, 2, oldval)
+SUBWORD_SYNC_OP (sub, , -, unsigned short, 2, oldval)
+SUBWORD_SYNC_OP (or, , |, unsigned short, 2, oldval)
+SUBWORD_SYNC_OP (and, , &, unsigned short, 2, oldval)
+SUBWORD_SYNC_OP (xor, , ^, unsigned short, 2, oldval)
+SUBWORD_SYNC_OP (nand, ~, &, unsigned short, 2, oldval)
+
+SUBWORD_SYNC_OP (add, , +, unsigned char, 1, oldval)
+SUBWORD_SYNC_OP (sub, , -, unsigned char, 1, oldval)
+SUBWORD_SYNC_OP (or, , |, unsigned char, 1, oldval)
+SUBWORD_SYNC_OP (and, , &, unsigned char, 1, oldval)
+SUBWORD_SYNC_OP (xor, , ^, unsigned char, 1, oldval)
+SUBWORD_SYNC_OP (nand, ~, &, unsigned char, 1, oldval)
+
+#define OP_AND_FETCH_WORD(OP, PFX_OP, INF_OP) \
+ int HIDDEN \
+ __sync_##OP##_and_fetch_4 (int *ptr, int val) \
+ { \
+ int tmp, failure; \
+ \
+ do \
+ { \
+ tmp = *ptr; \
+ failure = __kernel_cmpxchg (tmp, PFX_OP tmp INF_OP val, ptr); \
+ } \
+ while (failure != 0); \
+ \
+ return PFX_OP tmp INF_OP val; \
+ }
+
+OP_AND_FETCH_WORD (add, , +)
+OP_AND_FETCH_WORD (sub, , -)
+OP_AND_FETCH_WORD (or, , |)
+OP_AND_FETCH_WORD (and, , &)
+OP_AND_FETCH_WORD (xor, , ^)
+OP_AND_FETCH_WORD (nand, ~, &)
+
+SUBWORD_SYNC_OP (add, , +, unsigned short, 2, newval)
+SUBWORD_SYNC_OP (sub, , -, unsigned short, 2, newval)
+SUBWORD_SYNC_OP (or, , |, unsigned short, 2, newval)
+SUBWORD_SYNC_OP (and, , &, unsigned short, 2, newval)
+SUBWORD_SYNC_OP (xor, , ^, unsigned short, 2, newval)
+SUBWORD_SYNC_OP (nand, ~, &, unsigned short, 2, newval)
+
+SUBWORD_SYNC_OP (add, , +, unsigned char, 1, newval)
+SUBWORD_SYNC_OP (sub, , -, unsigned char, 1, newval)
+SUBWORD_SYNC_OP (or, , |, unsigned char, 1, newval)
+SUBWORD_SYNC_OP (and, , &, unsigned char, 1, newval)
+SUBWORD_SYNC_OP (xor, , ^, unsigned char, 1, newval)
+SUBWORD_SYNC_OP (nand, ~, &, unsigned char, 1, newval)
+
+int HIDDEN
+__sync_val_compare_and_swap_4 (int *ptr, int oldval, int newval)
+{
+ int actual_oldval, fail;
+
+ while (1)
+ {
+ actual_oldval = *ptr;
+
+ if (oldval != actual_oldval)
+ return actual_oldval;
+
+ fail = __kernel_cmpxchg (actual_oldval, newval, ptr);
+
+ if (!fail)
+ return oldval;
+ }
+}
+
+#define SUBWORD_VAL_CAS(TYPE, WIDTH) \
+ TYPE HIDDEN \
+ __sync_val_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \
+ TYPE newval) \
+ { \
+ int *wordptr = (int *)((unsigned int) ptr & ~3), fail; \
+ unsigned int mask, shift, actual_oldval, actual_newval; \
+ \
+ shift = (((unsigned int) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \
+ mask = MASK_##WIDTH << shift; \
+ \
+ while (1) \
+ { \
+ actual_oldval = *wordptr; \
+ \
+ if (((actual_oldval & mask) >> shift) != (unsigned int) oldval) \
+ return (actual_oldval & mask) >> shift; \
+ \
+ actual_newval = (actual_oldval & ~mask) \
+ | (((unsigned int) newval << shift) & mask); \
+ \
+ fail = __kernel_cmpxchg (actual_oldval, actual_newval, \
+ wordptr); \
+ \
+ if (!fail) \
+ return oldval; \
+ } \
+ }
+
+SUBWORD_VAL_CAS (unsigned short, 2)
+SUBWORD_VAL_CAS (unsigned char, 1)
+
+typedef unsigned char bool;
+
+bool HIDDEN
+__sync_bool_compare_and_swap_4 (int *ptr, int oldval, int newval)
+{
+ int failure = __kernel_cmpxchg (oldval, newval, ptr);
+ return (failure == 0);
+}
+
+#define SUBWORD_BOOL_CAS(TYPE, WIDTH) \
+ bool HIDDEN \
+ __sync_bool_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \
+ TYPE newval) \
+ { \
+ TYPE actual_oldval \
+ = __sync_val_compare_and_swap_##WIDTH (ptr, oldval, newval); \
+ return (oldval == actual_oldval); \
+ }
+
+SUBWORD_BOOL_CAS (unsigned short, 2)
+SUBWORD_BOOL_CAS (unsigned char, 1)
+
+void HIDDEN
+__sync_synchronize (void)
+{
+ __kernel_dmb ();
+}
+
+int HIDDEN
+__sync_lock_test_and_set_4 (int *ptr, int val)
+{
+ int failure, oldval;
+
+ do
+ {
+ oldval = *ptr;
+ failure = __kernel_cmpxchg (oldval, val, ptr);
+ }
+ while (failure != 0);
+
+ return oldval;
+}
+
+#define SUBWORD_TEST_AND_SET(TYPE, WIDTH) \
+ TYPE HIDDEN \
+ __sync_lock_test_and_set_##WIDTH (TYPE *ptr, TYPE val) \
+ { \
+ int failure; \
+ unsigned int oldval, newval, shift, mask; \
+ int *wordptr = (int *) ((unsigned int) ptr & ~3); \
+ \
+ shift = (((unsigned int) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \
+ mask = MASK_##WIDTH << shift; \
+ \
+ do \
+ { \
+ oldval = *wordptr; \
+ newval = ((oldval & ~mask) \
+ | (((unsigned int) val << shift) & mask)); \
+ failure = __kernel_cmpxchg (oldval, newval, wordptr); \
+ } \
+ while (failure != 0); \
+ \
+ return (oldval & mask) >> shift; \
+ }
+
+SUBWORD_TEST_AND_SET (unsigned short, 2)
+SUBWORD_TEST_AND_SET (unsigned char, 1)
+
+#define SYNC_LOCK_RELEASE(TYPE, WIDTH) \
+ void HIDDEN \
+ __sync_lock_release_##WIDTH (TYPE *ptr) \
+ { \
+ /* All writes before this point must be seen before we release \
+ the lock itself. */ \
+ __kernel_dmb (); \
+ *ptr = 0; \
+ }
+
+SYNC_LOCK_RELEASE (int, 4)
+SYNC_LOCK_RELEASE (short, 2)
+SYNC_LOCK_RELEASE (char, 1)
diff --git a/libgcc/config/csky/linux-unwind.h b/libgcc/config/csky/linux-unwind.h
new file mode 100644
index 0000000..24638de
--- /dev/null
+++ b/libgcc/config/csky/linux-unwind.h
@@ -0,0 +1,131 @@
+/* DWARF2 EH unwinding support for C-SKY 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.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef inhibit_libc
+
+/* Do code reading to identify a signal frame, and set the frame
+ state data appropriately. See unwind-dw2.c for the structs. */
+
+#include <signal.h>
+#include <asm/unistd.h>
+
+/* The third parameter to the signal handler points to something with
+ this structure defined in asm/ucontext.h, but the name clashes with
+ struct ucontext from sys/ucontext.h so this private copy is used. */
+typedef struct _sig_ucontext {
+ unsigned long uc_flags;
+ struct _sig_ucontext *uc_link;
+ stack_t uc_stack;
+ struct sigcontext uc_mcontext;
+ sigset_t uc_sigmask;
+} _sig_ucontext_t;
+
+#define MD_FALLBACK_FRAME_STATE_FOR csky_fallback_frame_state
+
+static _Unwind_Reason_Code
+csky_fallback_frame_state (struct _Unwind_Context *context,
+ _Unwind_FrameState *fs)
+{
+ u_int16_t *pc = (u_int16_t *) context->ra;
+ struct sigcontext *sc;
+ _Unwind_Ptr new_cfa;
+ int i;
+
+ /* movi r7, __NR_rt_sigreturn; trap 0 */
+ if ((*(pc+0) == 0xea07) && (*(pc+1) == 119)
+ && (*(pc+2) == 0xc000) && (*(pc+3) == 0x2020))
+ {
+ struct sigframe
+ {
+ int sig;
+ int code;
+ struct sigcontext *psc;
+ unsigned long extramask[2]; /* _NSIG_WORDS */
+ struct sigcontext sc;
+ } *_rt = context->cfa;
+ sc = _rt->psc; // &(_rt->sc);
+ }
+ /* movi r7, __NR_rt_sigreturn; trap 0 */
+ else if ((*(pc+0) == 0xea07) && (*(pc+1) == 173)
+ && (*(pc+2) == 0xc000) && (*(pc+3) == 0x2020))
+ {
+ struct rt_sigframe
+ {
+ int sig;
+ struct siginfo *pinfo;
+ void* puc;
+ siginfo_t info;
+ struct ucontext uc;
+ } *_rt = context->cfa;
+ sc = &(_rt->uc.uc_mcontext);
+ }
+ else
+ return _URC_END_OF_STACK;
+
+ new_cfa = (_Unwind_Ptr) sc->sc_usp;
+ fs->regs.cfa_how = CFA_REG_OFFSET;
+ fs->regs.cfa_reg = STACK_POINTER_REGNUM;
+ fs->regs.cfa_offset = new_cfa - (_Unwind_Ptr) context->cfa;
+
+ fs->regs.reg[0].how = REG_SAVED_OFFSET;
+ fs->regs.reg[0].loc.offset = (_Unwind_Ptr)&(sc->sc_a0) - new_cfa;
+
+ fs->regs.reg[1].how = REG_SAVED_OFFSET;
+ fs->regs.reg[1].loc.offset = (_Unwind_Ptr)&(sc->sc_a1) - new_cfa;
+
+ fs->regs.reg[2].how = REG_SAVED_OFFSET;
+ fs->regs.reg[2].loc.offset = (_Unwind_Ptr)&(sc->sc_a2) - new_cfa;
+
+ fs->regs.reg[3].how = REG_SAVED_OFFSET;
+ fs->regs.reg[3].loc.offset = (_Unwind_Ptr)&(sc->sc_a3) - new_cfa;
+
+ for (i = 4; i < 14; i++)
+ {
+ fs->regs.reg[i].how = REG_SAVED_OFFSET;
+ fs->regs.reg[i].loc.offset = ((_Unwind_Ptr)&(sc->sc_regs[i - 4])
+ - new_cfa);
+ }
+
+ for (i = 16; i < 32; i++)
+ {
+ fs->regs.reg[i].how = REG_SAVED_OFFSET;
+ fs->regs.reg[i].loc.offset = ((_Unwind_Ptr)&(sc->sc_exregs[i - 16])
+ - new_cfa);
+ }
+
+ /* FIXME : hi lo ? */
+ fs->regs.reg[15].how = REG_SAVED_OFFSET;
+ fs->regs.reg[15].loc.offset = (_Unwind_Ptr)&(sc->sc_r15) - new_cfa;
+
+ fs->regs.reg[56].how = REG_SAVED_OFFSET;
+ fs->regs.reg[56].loc.offset = (_Unwind_Ptr)&(sc->sc_pc) - new_cfa;
+ fs->retaddr_column = 56;
+ fs->signal_frame = 1;
+
+ return _URC_NO_REASON;
+}
+
+
+#endif
diff --git a/libgcc/config/csky/t-csky b/libgcc/config/csky/t-csky
new file mode 100644
index 0000000..06aa1c1
--- /dev/null
+++ b/libgcc/config/csky/t-csky
@@ -0,0 +1,28 @@
+# Makefile fragment 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/>.
+
+LIB1ASMSRC = csky/lib1funcs.S
+LIB1ASMFUNCS = _divsi3 _udivsi3 _modsi3 _umodsi3 _unorddf2 _unordsf2 \
+ _csky_case_sqi _csky_case_uqi _csky_case_shi _csky_case_uhi _csky_case_si
+
+LIB2FUNCS_EXCLUDE += _unord_df
+LIB2FUNCS_EXCLUDE += _unord_sf
+
+TARGET_LIBGCC2_CFLAGS=-O3 -DNO_FLOATLIB_FIXUNSDFSI
diff --git a/libgcc/config/csky/t-linux-csky b/libgcc/config/csky/t-linux-csky
new file mode 100644
index 0000000..1f5c4ce
--- /dev/null
+++ b/libgcc/config/csky/t-linux-csky
@@ -0,0 +1,21 @@
+# Makefile fragment 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/>.
+
+LIB2ADD_ST += $(srcdir)/config/csky/linux-atomic.c
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 9477a33..39855d9 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,54 @@
+2018-08-20 Jonathan Wakely <jwakely@redhat.com>
+
+ * include/std/optional (_Optional_payload): Use variable templates
+ for conditions in default template arguments and exception
+ specifications.
+ (optional): Likewise. Adjust indentation.
+ (optional::__not_self, optional::__not_tag, optional::_Requires): New
+ SFINAE helpers.
+ (optional::optional): Use new helpers in constructor constraints.
+ * include/std/type_traits (__or_v, __and_v): New variable templates.
+ * testsuite/20_util/optional/cons/value_neg.cc: Change dg-error to
+ dg-prune-output. Remove unused header.
+
+2018-08-18 François Dumont <fdumont@gcc.gnu.org>
+
+ * testsuite/25_algorithms/copy/86658.cc: Use dg-options to define
+ _GLIBCXX_DEBUG.
+
+2018-08-17 Jonathan Wakely <jwakely@redhat.com>
+
+ PR libstdc++/86963
+ * include/std/tuple (__tuple_base): New class template with deleted
+ copy assignment operator.
+ (tuple, tuple<_T1, _T2>): Derive from __tuple_base<tuple> so that
+ implicit copy/move assignment operator will be deleted/suppressed.
+ (tuple::__assignable, tuple<_T1, _T2>::__assignable): New helper
+ functions for SFINAE constraints on assignment operators.
+ (tuple::__nothrow_assignable, tuple<_T1, _T2>::__nothrow_assignable):
+ New helper functions for exception specifications.
+ (tuple::operator=(const tuple&), tuple::operator=(tuple&&))
+ (tuple<_T1, _T2>::operator=(const tuple&))
+ (tuple<_T1, _T2>::operator=(tuple&&)): Change parameter types to
+ __nonesuch_no_braces when the operator should be defined implicitly.
+ Use __nothrow_assignable for exception specifications.
+ (tuple::operator=(const tuple<_UElements...>&))
+ (tuple::operator=(tuple<_UElements...>&&))
+ (tuple<_T1, _T2>::operator=(const tuple<_U1, _U2>&))
+ (tuple<_T1, _T2>::operator=(tuple<_U1, _U2>&&))
+ (tuple<_T1, _T2>::operator=(const pair<_U1, _U2>&))
+ (tuple<_T1, _T2>::operator=(pair<_U1, _U2>&&)): Constrain using
+ __assignable and use __nothrow_assignable for exception
+ specifications.
+ * python/libstdcxx/v6/printers.py (is_specialization_of): Accept
+ gdb.Type as first argument, instead of a string.
+ (StdTuplePrinter._iterator._is_nonempty_tuple): New method to check
+ tuple for expected structure.
+ (StdTuplePrinter._iterator.__init__): Use _is_nonempty_tuple.
+ * testsuite/20_util/tuple/dr2729.cc: New test.
+ * testsuite/20_util/tuple/element_access/get_neg.cc: Change dg-error
+ to dg-prune-output.
+
2018-08-16 Jonathan Wakely <jwakely@redhat.com>
* include/tr1/legendre_function.tcc (__sph_legendre): Avoid warning
diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional
index 746ee2f..d0257c0 100644
--- a/libstdc++-v3/include/std/optional
+++ b/libstdc++-v3/include/std/optional
@@ -102,11 +102,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Payload for optionals with non-trivial destructor.
template <typename _Tp,
bool /*_HasTrivialDestructor*/ =
- is_trivially_destructible<_Tp>::value,
+ is_trivially_destructible_v<_Tp>,
bool /*_HasTrivialCopyAssignment*/ =
- is_trivially_copy_assignable<_Tp>::value,
+ is_trivially_copy_assignable_v<_Tp>,
bool /*_HasTrivialMoveAssignment*/ =
- is_trivially_move_assignable<_Tp>::value>
+ is_trivially_move_assignable_v<_Tp>>
struct _Optional_payload
{
constexpr _Optional_payload() noexcept : _M_empty() { }
@@ -165,8 +165,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_Optional_payload&
operator=(_Optional_payload&& __other)
- noexcept(__and_<is_nothrow_move_constructible<_Tp>,
- is_nothrow_move_assignable<_Tp>>())
+ noexcept(__and_v<is_nothrow_move_constructible<_Tp>,
+ is_nothrow_move_assignable<_Tp>>)
{
if (this->_M_engaged && __other._M_engaged)
this->_M_get() = std::move(__other._M_get());
@@ -199,7 +199,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename... _Args>
void
_M_construct(_Args&&... __args)
- noexcept(is_nothrow_constructible<_Stored_type, _Args...>())
+ noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>)
{
::new ((void *) std::__addressof(this->_M_payload))
_Stored_type(std::forward<_Args>(__args)...);
@@ -377,7 +377,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename... _Args>
void
_M_construct(_Args&&... __args)
- noexcept(is_nothrow_constructible<_Stored_type, _Args...>())
+ noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>)
{
::new ((void *) std::__addressof(this->_M_payload))
_Stored_type(std::forward<_Args>(__args)...);
@@ -468,8 +468,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_Optional_payload&
operator=(_Optional_payload&& __other)
- noexcept(__and_<is_nothrow_move_constructible<_Tp>,
- is_nothrow_move_assignable<_Tp>>())
+ noexcept(__and_v<is_nothrow_move_constructible<_Tp>,
+ is_nothrow_move_assignable<_Tp>>)
{
if (this->_M_engaged && __other._M_engaged)
this->_M_get() = std::move(__other._M_get());
@@ -496,7 +496,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename... _Args>
void
_M_construct(_Args&&... __args)
- noexcept(is_nothrow_constructible<_Stored_type, _Args...>())
+ noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>)
{
::new ((void *) std::__addressof(this->_M_payload))
_Stored_type(std::forward<_Args>(__args)...);
@@ -598,8 +598,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_Optional_payload&
operator=(_Optional_payload&& __other)
- noexcept(__and_<is_nothrow_move_constructible<_Tp>,
- is_nothrow_move_assignable<_Tp>>())
+ noexcept(__and_v<is_nothrow_move_constructible<_Tp>,
+ is_nothrow_move_assignable<_Tp>>)
{
if (this->_M_engaged && __other._M_engaged)
this->_M_get() = std::move(__other._M_get());
@@ -626,7 +626,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename... _Args>
void
_M_construct(_Args&&... __args)
- noexcept(is_nothrow_constructible<_Stored_type, _Args...>())
+ noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>)
{
::new ((void *) std::__addressof(this->_M_payload))
_Stored_type(std::forward<_Args>(__args)...);
@@ -665,7 +665,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename... _Args>
void
_M_construct(_Args&&... __args)
- noexcept(is_nothrow_constructible<_Stored_type, _Args...>())
+ noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>)
{
::new
(std::__addressof(static_cast<_Dp*>(this)->_M_payload._M_payload))
@@ -735,7 +735,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ }
constexpr _Optional_base(_Optional_base&& __other)
- noexcept(is_nothrow_move_constructible<_Tp>())
+ noexcept(is_nothrow_move_constructible_v<_Tp>)
: _M_payload(__other._M_payload._M_engaged,
std::move(__other._M_payload))
{ }
@@ -864,7 +864,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr _Optional_base(const _Optional_base& __other) = default;
constexpr _Optional_base(_Optional_base&& __other)
- noexcept(is_nothrow_move_constructible<_Tp>())
+ noexcept(is_nothrow_move_constructible_v<_Tp>)
: _M_payload(__other._M_payload._M_engaged,
std::move(__other._M_payload))
{ }
@@ -985,16 +985,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
class optional
: private _Optional_base<_Tp>,
private _Enable_copy_move<
- // Copy constructor.
- is_copy_constructible<_Tp>::value,
- // Copy assignment.
- __and_<is_copy_constructible<_Tp>, is_copy_assignable<_Tp>>::value,
- // Move constructor.
- is_move_constructible<_Tp>::value,
- // Move assignment.
- __and_<is_move_constructible<_Tp>, is_move_assignable<_Tp>>::value,
- // Unique tag type.
- optional<_Tp>>
+ // Copy constructor.
+ is_copy_constructible_v<_Tp>,
+ // Copy assignment.
+ __and_v<is_copy_constructible<_Tp>, is_copy_assignable<_Tp>>,
+ // Move constructor.
+ is_move_constructible_v<_Tp>,
+ // Move assignment.
+ __and_v<is_move_constructible<_Tp>, is_move_assignable<_Tp>>,
+ // Unique tag type.
+ optional<_Tp>>
{
static_assert(!is_same_v<remove_cv_t<_Tp>, nullopt_t>);
static_assert(!is_same_v<remove_cv_t<_Tp>, in_place_t>);
@@ -1003,6 +1003,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
private:
using _Base = _Optional_base<_Tp>;
+ // SFINAE helpers
+ template<typename _Up>
+ using __not_self = __not_<is_same<optional, __remove_cvref_t<_Up>>>;
+ template<typename _Up>
+ using __not_tag = __not_<is_same<in_place_t, __remove_cvref_t<_Up>>>;
+ template<typename... _Cond>
+ using _Requires = enable_if_t<__and_v<_Cond...>, bool>;
+
public:
using value_type = _Tp;
@@ -1011,171 +1019,158 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr optional(nullopt_t) noexcept { }
// Converting constructors for engaged optionals.
- template <typename _Up = _Tp,
- enable_if_t<__and_<
- __not_<is_same<optional<_Tp>, decay_t<_Up>>>,
- __not_<is_same<in_place_t, decay_t<_Up>>>,
- is_constructible<_Tp, _Up&&>,
- is_convertible<_Up&&, _Tp>
- >::value, bool> = true>
- constexpr optional(_Up&& __t)
- : _Base(std::in_place, std::forward<_Up>(__t)) { }
-
- template <typename _Up = _Tp,
- enable_if_t<__and_<
- __not_<is_same<optional<_Tp>, decay_t<_Up>>>,
- __not_<is_same<in_place_t, decay_t<_Up>>>,
- is_constructible<_Tp, _Up&&>,
- __not_<is_convertible<_Up&&, _Tp>>
- >::value, bool> = false>
- explicit constexpr optional(_Up&& __t)
+ template<typename _Up = _Tp,
+ _Requires<__not_self<_Up>, __not_tag<_Up>,
+ is_constructible<_Tp, _Up&&>,
+ is_convertible<_Up&&, _Tp>> = true>
+ constexpr
+ optional(_Up&& __t)
+ : _Base(std::in_place, std::forward<_Up>(__t)) { }
+
+ template<typename _Up = _Tp,
+ _Requires<__not_self<_Up>, __not_tag<_Up>,
+ is_constructible<_Tp, _Up&&>,
+ __not_<is_convertible<_Up&&, _Tp>>> = false>
+ explicit constexpr
+ optional(_Up&& __t)
: _Base(std::in_place, std::forward<_Up>(__t)) { }
- template <typename _Up,
- enable_if_t<__and_<
- __not_<is_same<_Tp, _Up>>,
- is_constructible<_Tp, const _Up&>,
- is_convertible<const _Up&, _Tp>,
- __not_<__converts_from_optional<_Tp, _Up>>
- >::value, bool> = true>
- constexpr optional(const optional<_Up>& __t)
- {
- if (__t)
- emplace(*__t);
- }
+ template<typename _Up,
+ _Requires<__not_<is_same<_Tp, _Up>>,
+ is_constructible<_Tp, const _Up&>,
+ is_convertible<const _Up&, _Tp>,
+ __not_<__converts_from_optional<_Tp, _Up>>> = true>
+ constexpr
+ optional(const optional<_Up>& __t)
+ {
+ if (__t)
+ emplace(*__t);
+ }
- template <typename _Up,
- enable_if_t<__and_<
- __not_<is_same<_Tp, _Up>>,
- is_constructible<_Tp, const _Up&>,
- __not_<is_convertible<const _Up&, _Tp>>,
- __not_<__converts_from_optional<_Tp, _Up>>
- >::value, bool> = false>
- explicit constexpr optional(const optional<_Up>& __t)
- {
- if (__t)
- emplace(*__t);
- }
+ template<typename _Up,
+ _Requires<__not_<is_same<_Tp, _Up>>,
+ is_constructible<_Tp, const _Up&>,
+ __not_<is_convertible<const _Up&, _Tp>>,
+ __not_<__converts_from_optional<_Tp, _Up>>> = false>
+ explicit constexpr
+ optional(const optional<_Up>& __t)
+ {
+ if (__t)
+ emplace(*__t);
+ }
template <typename _Up,
- enable_if_t<__and_<
- __not_<is_same<_Tp, _Up>>,
- is_constructible<_Tp, _Up&&>,
- is_convertible<_Up&&, _Tp>,
- __not_<__converts_from_optional<_Tp, _Up>>
- >::value, bool> = true>
- constexpr optional(optional<_Up>&& __t)
- {
- if (__t)
- emplace(std::move(*__t));
- }
+ _Requires<__not_<is_same<_Tp, _Up>>,
+ is_constructible<_Tp, _Up&&>,
+ is_convertible<_Up&&, _Tp>,
+ __not_<__converts_from_optional<_Tp, _Up>>> = true>
+ constexpr
+ optional(optional<_Up>&& __t)
+ {
+ if (__t)
+ emplace(std::move(*__t));
+ }
template <typename _Up,
- enable_if_t<__and_<
- __not_<is_same<_Tp, _Up>>,
- is_constructible<_Tp, _Up&&>,
- __not_<is_convertible<_Up&&, _Tp>>,
- __not_<__converts_from_optional<_Tp, _Up>>
- >::value, bool> = false>
- explicit constexpr optional(optional<_Up>&& __t)
- {
- if (__t)
- emplace(std::move(*__t));
- }
+ _Requires<__not_<is_same<_Tp, _Up>>,
+ is_constructible<_Tp, _Up&&>,
+ __not_<is_convertible<_Up&&, _Tp>>,
+ __not_<__converts_from_optional<_Tp, _Up>>> = false>
+ explicit constexpr
+ optional(optional<_Up>&& __t)
+ {
+ if (__t)
+ emplace(std::move(*__t));
+ }
template<typename... _Args,
- enable_if_t<is_constructible_v<_Tp, _Args&&...>, bool> = false>
- explicit constexpr optional(in_place_t, _Args&&... __args)
- : _Base(std::in_place, std::forward<_Args>(__args)...) { }
+ _Requires<is_constructible<_Tp, _Args&&...>> = false>
+ explicit constexpr
+ optional(in_place_t, _Args&&... __args)
+ : _Base(std::in_place, std::forward<_Args>(__args)...) { }
template<typename _Up, typename... _Args,
- enable_if_t<is_constructible_v<_Tp,
- initializer_list<_Up>&,
- _Args&&...>, bool> = false>
- explicit constexpr optional(in_place_t,
- initializer_list<_Up> __il,
- _Args&&... __args)
- : _Base(std::in_place, __il, std::forward<_Args>(__args)...) { }
+ _Requires<is_constructible<_Tp,
+ initializer_list<_Up>&,
+ _Args&&...>> = false>
+ explicit constexpr
+ optional(in_place_t, initializer_list<_Up> __il, _Args&&... __args)
+ : _Base(std::in_place, __il, std::forward<_Args>(__args)...) { }
// Assignment operators.
optional&
operator=(nullopt_t) noexcept
{
- this->_M_reset();
- return *this;
+ this->_M_reset();
+ return *this;
}
template<typename _Up = _Tp>
- enable_if_t<__and_<
- __not_<is_same<optional<_Tp>, decay_t<_Up>>>,
- is_constructible<_Tp, _Up>,
- __not_<__and_<is_scalar<_Tp>,
- is_same<_Tp, decay_t<_Up>>>>,
- is_assignable<_Tp&, _Up>>::value,
+ enable_if_t<__and_v<__not_self<_Up>,
+ __not_<__and_<is_scalar<_Tp>,
+ is_same<_Tp, decay_t<_Up>>>>,
+ is_constructible<_Tp, _Up>,
+ is_assignable<_Tp&, _Up>>,
optional&>
- operator=(_Up&& __u)
- {
- if (this->_M_is_engaged())
- this->_M_get() = std::forward<_Up>(__u);
- else
- this->_M_construct(std::forward<_Up>(__u));
+ operator=(_Up&& __u)
+ {
+ if (this->_M_is_engaged())
+ this->_M_get() = std::forward<_Up>(__u);
+ else
+ this->_M_construct(std::forward<_Up>(__u));
- return *this;
- }
+ return *this;
+ }
template<typename _Up>
- enable_if_t<__and_<
- __not_<is_same<_Tp, _Up>>,
- is_constructible<_Tp, const _Up&>,
- is_assignable<_Tp&, _Up>,
- __not_<__converts_from_optional<_Tp, _Up>>,
- __not_<__assigns_from_optional<_Tp, _Up>>
- >::value,
+ enable_if_t<__and_v<__not_<is_same<_Tp, _Up>>,
+ is_constructible<_Tp, const _Up&>,
+ is_assignable<_Tp&, _Up>,
+ __not_<__converts_from_optional<_Tp, _Up>>,
+ __not_<__assigns_from_optional<_Tp, _Up>>>,
optional&>
- operator=(const optional<_Up>& __u)
- {
- if (__u)
- {
- if (this->_M_is_engaged())
- this->_M_get() = *__u;
- else
- this->_M_construct(*__u);
- }
- else
- {
- this->_M_reset();
- }
- return *this;
- }
+ operator=(const optional<_Up>& __u)
+ {
+ if (__u)
+ {
+ if (this->_M_is_engaged())
+ this->_M_get() = *__u;
+ else
+ this->_M_construct(*__u);
+ }
+ else
+ {
+ this->_M_reset();
+ }
+ return *this;
+ }
template<typename _Up>
- enable_if_t<__and_<
- __not_<is_same<_Tp, _Up>>,
- is_constructible<_Tp, _Up>,
- is_assignable<_Tp&, _Up>,
- __not_<__converts_from_optional<_Tp, _Up>>,
- __not_<__assigns_from_optional<_Tp, _Up>>
- >::value,
+ enable_if_t<__and_v<__not_<is_same<_Tp, _Up>>,
+ is_constructible<_Tp, _Up>,
+ is_assignable<_Tp&, _Up>,
+ __not_<__converts_from_optional<_Tp, _Up>>,
+ __not_<__assigns_from_optional<_Tp, _Up>>>,
optional&>
- operator=(optional<_Up>&& __u)
- {
- if (__u)
- {
- if (this->_M_is_engaged())
- this->_M_get() = std::move(*__u);
- else
- this->_M_construct(std::move(*__u));
- }
- else
- {
- this->_M_reset();
- }
-
- return *this;
- }
+ operator=(optional<_Up>&& __u)
+ {
+ if (__u)
+ {
+ if (this->_M_is_engaged())
+ this->_M_get() = std::move(*__u);
+ else
+ this->_M_construct(std::move(*__u));
+ }
+ else
+ {
+ this->_M_reset();
+ }
+
+ return *this;
+ }
template<typename... _Args>
- enable_if_t<is_constructible<_Tp, _Args&&...>::value, _Tp&>
+ enable_if_t<is_constructible_v<_Tp, _Args&&...>, _Tp&>
emplace(_Args&&... __args)
{
this->_M_reset();
@@ -1184,8 +1179,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _Up, typename... _Args>
- enable_if_t<is_constructible<_Tp, initializer_list<_Up>&,
- _Args&&...>::value, _Tp&>
+ enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&,
+ _Args&&...>, _Tp&>
emplace(initializer_list<_Up> __il, _Args&&... __args)
{
this->_M_reset();
@@ -1198,19 +1193,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Swap.
void
swap(optional& __other)
- noexcept(is_nothrow_move_constructible<_Tp>()
- && is_nothrow_swappable_v<_Tp>)
+ noexcept(is_nothrow_move_constructible_v<_Tp>
+ && is_nothrow_swappable_v<_Tp>)
{
- using std::swap;
+ using std::swap;
- if (this->_M_is_engaged() && __other._M_is_engaged())
- swap(this->_M_get(), __other._M_get());
- else if (this->_M_is_engaged())
+ if (this->_M_is_engaged() && __other._M_is_engaged())
+ swap(this->_M_get(), __other._M_get());
+ else if (this->_M_is_engaged())
{
__other._M_construct(std::move(this->_M_get()));
this->_M_destruct();
}
- else if (__other._M_is_engaged())
+ else if (__other._M_is_engaged())
{
this->_M_construct(std::move(__other._M_get()));
__other._M_destruct();
@@ -1307,12 +1302,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
? std::move(this->_M_get())
: static_cast<_Tp>(std::forward<_Up>(__u));
}
+
void reset() noexcept { this->_M_reset(); }
};
template<typename _Tp>
using __optional_relop_t =
- enable_if_t<is_convertible<_Tp, bool>::value, bool>;
+ enable_if_t<is_convertible<_Tp, bool>::value, bool>;
// Comparisons between optional values.
template<typename _Tp, typename _Up>
diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple
index dd7daf7..955b853 100644
--- a/libstdc++-v3/include/std/tuple
+++ b/libstdc++-v3/include/std/tuple
@@ -551,9 +551,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
};
+ // The tag parameter ensures that in nested tuples each __tuple_base
+ // is a different type and can use the empty base-class optimisation.
+ template<typename _Tag>
+ class __tuple_base
+ {
+ template<typename...> friend struct tuple;
+ __tuple_base() = default;
+ ~__tuple_base() = default;
+ __tuple_base(const __tuple_base&) = default;
+ __tuple_base& operator=(const __tuple_base&) = delete;
+ };
+
/// Primary class template, tuple
template<typename... _Elements>
- class tuple : public _Tuple_impl<0, _Elements...>
+ class tuple
+ : public _Tuple_impl<0, _Elements...>,
+ private __tuple_base<tuple<_Elements...>>
{
typedef _Tuple_impl<0, _Elements...> _Inherited;
@@ -573,6 +587,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
};
+ template<typename... _UElements>
+ static constexpr
+ __enable_if_t<sizeof...(_UElements) == sizeof...(_Elements), bool>
+ __assignable()
+ { return __and_<is_assignable<_Elements&, _UElements>...>::value; }
+
+ template<typename... _UElements>
+ static constexpr bool __nothrow_assignable()
+ {
+ return
+ __and_<is_nothrow_assignable<_Elements&, _UElements>...>::value;
+ }
+
public:
template<typename _Dummy = void,
typename enable_if<_TC2<_Dummy>::
@@ -832,36 +859,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ }
tuple&
- operator=(const tuple& __in)
+ operator=(typename conditional<__assignable<const _Elements&...>(),
+ const tuple&,
+ const __nonesuch_no_braces&>::type __in)
+ noexcept(__nothrow_assignable<const _Elements&...>())
{
static_cast<_Inherited&>(*this) = __in;
return *this;
}
tuple&
- operator=(tuple&& __in)
- noexcept(is_nothrow_move_assignable<_Inherited>::value)
+ operator=(typename conditional<__assignable<_Elements...>(),
+ tuple&&,
+ __nonesuch_no_braces&&>::type __in)
+ noexcept(__nothrow_assignable<_Elements...>())
{
static_cast<_Inherited&>(*this) = std::move(__in);
return *this;
}
template<typename... _UElements>
- typename
- enable_if<sizeof...(_UElements)
- == sizeof...(_Elements), tuple&>::type
- operator=(const tuple<_UElements...>& __in)
- {
+ __enable_if_t<__assignable<const _UElements&...>(), tuple&>
+ operator=(const tuple<_UElements...>& __in)
+ noexcept(__nothrow_assignable<const _UElements&...>())
+ {
static_cast<_Inherited&>(*this) = __in;
return *this;
}
template<typename... _UElements>
- typename
- enable_if<sizeof...(_UElements)
- == sizeof...(_Elements), tuple&>::type
- operator=(tuple<_UElements...>&& __in)
- {
+ __enable_if_t<__assignable<_UElements...>(), tuple&>
+ operator=(tuple<_UElements...>&& __in)
+ noexcept(__nothrow_assignable<_UElements...>())
+ {
static_cast<_Inherited&>(*this) = std::move(__in);
return *this;
}
@@ -904,10 +934,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// Partial specialization, 2-element tuple.
/// Includes construction and assignment from a pair.
template<typename _T1, typename _T2>
- class tuple<_T1, _T2> : public _Tuple_impl<0, _T1, _T2>
+ class tuple<_T1, _T2>
+ : public _Tuple_impl<0, _T1, _T2>,
+ private __tuple_base<tuple<_T1, _T2>>
{
typedef _Tuple_impl<0, _T1, _T2> _Inherited;
+ template<typename _U1, typename _U2>
+ static constexpr bool __assignable()
+ {
+ return __and_<is_assignable<_T1&, _U1>,
+ is_assignable<_T2&, _U2>>::value;
+ }
+
+ template<typename _U1, typename _U2>
+ static constexpr bool __nothrow_assignable()
+ {
+ return __and_<is_nothrow_assignable<_T1&, _U1>,
+ is_nothrow_assignable<_T2&, _U2>>::value;
+ }
+
public:
template <typename _U1 = _T1,
typename _U2 = _T2,
@@ -915,9 +961,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__is_implicitly_default_constructible<_U1>,
__is_implicitly_default_constructible<_U2>>
::value, bool>::type = true>
-
- constexpr tuple()
- : _Inherited() { }
+ constexpr tuple()
+ : _Inherited() { }
template <typename _U1 = _T1,
typename _U2 = _T2,
@@ -929,9 +974,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__and_<__is_implicitly_default_constructible<_U1>,
__is_implicitly_default_constructible<_U2>>>>
::value, bool>::type = false>
-
- explicit constexpr tuple()
- : _Inherited() { }
+ explicit constexpr tuple()
+ : _Inherited() { }
// Shortcut for the cases where constructors taking _T1, _T2
// need to be constrained.
@@ -1206,49 +1250,58 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
std::forward<_U2>(__in.second)) { }
tuple&
- operator=(const tuple& __in)
+ operator=(typename conditional<__assignable<const _T1&, const _T2&>(),
+ const tuple&,
+ const __nonesuch_no_braces&>::type __in)
+ noexcept(__nothrow_assignable<const _T1&, const _T2&>())
{
static_cast<_Inherited&>(*this) = __in;
return *this;
}
tuple&
- operator=(tuple&& __in)
- noexcept(is_nothrow_move_assignable<_Inherited>::value)
+ operator=(typename conditional<__assignable<_T1, _T2>(),
+ tuple&&,
+ __nonesuch_no_braces&&>::type __in)
+ noexcept(__nothrow_assignable<_T1, _T2>())
{
static_cast<_Inherited&>(*this) = std::move(__in);
return *this;
}
template<typename _U1, typename _U2>
- tuple&
- operator=(const tuple<_U1, _U2>& __in)
- {
+ __enable_if_t<__assignable<const _U1&, const _U2&>(), tuple&>
+ operator=(const tuple<_U1, _U2>& __in)
+ noexcept(__nothrow_assignable<const _U1&, const _U2&>())
+ {
static_cast<_Inherited&>(*this) = __in;
return *this;
}
template<typename _U1, typename _U2>
- tuple&
- operator=(tuple<_U1, _U2>&& __in)
- {
+ __enable_if_t<__assignable<_U1, _U2>(), tuple&>
+ operator=(tuple<_U1, _U2>&& __in)
+ noexcept(__nothrow_assignable<_U1, _U2>())
+ {
static_cast<_Inherited&>(*this) = std::move(__in);
return *this;
}
template<typename _U1, typename _U2>
- tuple&
- operator=(const pair<_U1, _U2>& __in)
- {
+ __enable_if_t<__assignable<const _U1&, const _U2&>(), tuple&>
+ operator=(const pair<_U1, _U2>& __in)
+ noexcept(__nothrow_assignable<const _U1&, const _U2&>())
+ {
this->_M_head(*this) = __in.first;
this->_M_tail(*this)._M_head(*this) = __in.second;
return *this;
}
template<typename _U1, typename _U2>
- tuple&
- operator=(pair<_U1, _U2>&& __in)
- {
+ __enable_if_t<__assignable<_U1, _U2>(), tuple&>
+ operator=(pair<_U1, _U2>&& __in)
+ noexcept(__nothrow_assignable<_U1, _U2>())
+ {
this->_M_head(*this) = std::forward<_U1>(__in.first);
this->_M_tail(*this)._M_head(*this) = std::forward<_U2>(__in.second);
return *this;
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 4f89723..86b58cc 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -144,6 +144,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#if __cplusplus >= 201703L
+ template<typename... _Bn>
+ inline constexpr bool __or_v = __or_<_Bn...>::value;
+ template<typename... _Bn>
+ inline constexpr bool __and_v = __and_<_Bn...>::value;
+
#define __cpp_lib_logical_traits 201510
template<typename... _Bn>
diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py
index 43d459e..afe1b32 100644
--- a/libstdc++-v3/python/libstdcxx/v6/printers.py
+++ b/libstdc++-v3/python/libstdcxx/v6/printers.py
@@ -101,12 +101,14 @@ def find_type(orig, name):
_versioned_namespace = '__8::'
-def is_specialization_of(type, template_name):
+def is_specialization_of(x, template_name):
"Test if a type is a given template instantiation."
global _versioned_namespace
+ if type(x) is gdb.Type:
+ x = x.tag
if _versioned_namespace:
- return re.match('^std::(%s)?%s<.*>$' % (_versioned_namespace, template_name), type) is not None
- return re.match('^std::%s<.*>$' % template_name, type) is not None
+ return re.match('^std::(%s)?%s<.*>$' % (_versioned_namespace, template_name), x) is not None
+ return re.match('^std::%s<.*>$' % template_name, x) is not None
def strip_versioned_namespace(typename):
global _versioned_namespace
@@ -413,17 +415,26 @@ class StdTuplePrinter:
"Print a std::tuple"
class _iterator(Iterator):
+ @staticmethod
+ def _is_nonempty_tuple (nodes):
+ if len (nodes) == 2:
+ if is_specialization_of (nodes[1].type, '__tuple_base'):
+ return True
+ elif len (nodes) == 1:
+ return True
+ elif len (nodes) == 0:
+ return False
+ raise ValueError("Top of tuple tree does not consist of a single node.")
+
def __init__ (self, head):
self.head = head
# Set the base class as the initial head of the
# tuple.
nodes = self.head.type.fields ()
- if len (nodes) == 1:
+ if self._is_nonempty_tuple (nodes):
# Set the actual head to the first pair.
self.head = self.head.cast (nodes[0].type)
- elif len (nodes) != 0:
- raise ValueError("Top of tuple tree does not consist of a single node.")
self.count = 0
def __iter__ (self):
diff --git a/libstdc++-v3/testsuite/20_util/optional/cons/value_neg.cc b/libstdc++-v3/testsuite/20_util/optional/cons/value_neg.cc
index e9171ef..020cb26 100644
--- a/libstdc++-v3/testsuite/20_util/optional/cons/value_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/optional/cons/value_neg.cc
@@ -19,8 +19,6 @@
// <http://www.gnu.org/licenses/>.
#include <optional>
-#include <testsuite_hooks.h>
-
#include <string>
#include <memory>
@@ -37,8 +35,6 @@ int main()
std::optional<std::unique_ptr<int>> oup2 = new int; // { dg-error "conversion" }
struct U { explicit U(std::in_place_t); };
std::optional<U> ou(std::in_place); // { dg-error "no matching" }
- // { dg-error "no type" "" { target { *-*-* } } 1020 }
- // { dg-error "no type" "" { target { *-*-* } } 1030 }
- // { dg-error "no type" "" { target { *-*-* } } 1087 }
}
}
+// { dg-prune-output "no type .*enable_if" }
diff --git a/libstdc++-v3/testsuite/20_util/tuple/dr2729.cc b/libstdc++-v3/testsuite/20_util/tuple/dr2729.cc
new file mode 100644
index 0000000..c386355
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/tuple/dr2729.cc
@@ -0,0 +1,179 @@
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library 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.
+
+// This library 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 this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do compile { target c++11 } }
+
+#include <tuple>
+#include <testsuite_tr1.h>
+
+using std::tuple;
+using std::pair;
+using __gnu_test::assign::AnyAssign;
+using __gnu_test::assign::DelAnyAssign;
+using __gnu_test::assign::DelCopyAssign;
+using __gnu_test::CopyConsOnlyType;
+
+// Copy assignment:
+template<typename T>
+constexpr bool copy() { return std::is_copy_assignable<T>::value; }
+
+// Move assigmment:
+template<typename T>
+constexpr bool move() { return std::is_move_assignable<T>::value; }
+
+static_assert( copy<tuple<>>(), "");
+static_assert( move<tuple<>>(), "");
+
+static_assert( copy<tuple<int>>(), "");
+static_assert( copy<tuple<AnyAssign>>(), "");
+static_assert( copy<tuple<int, int>>(), "");
+static_assert( copy<tuple<AnyAssign, AnyAssign>>(), "");
+static_assert( copy<tuple<int, AnyAssign>>(), "");
+static_assert( copy<tuple<AnyAssign, int>>(), "");
+static_assert( copy<tuple<int, int, int>>(), "");
+static_assert( copy<tuple<AnyAssign, AnyAssign, AnyAssign>>(), "");
+static_assert( copy<tuple<int, AnyAssign, AnyAssign>>(), "");
+static_assert( copy<tuple<AnyAssign, int, AnyAssign>>(), "");
+static_assert( copy<tuple<AnyAssign, AnyAssign, int>>(), "");
+
+static_assert( move<tuple<int>>(), "");
+static_assert( move<tuple<AnyAssign>>(), "");
+static_assert( move<tuple<int, int>>(), "");
+static_assert( move<tuple<AnyAssign, AnyAssign>>(), "");
+static_assert( move<tuple<int, AnyAssign>>(), "");
+static_assert( move<tuple<AnyAssign, int>>(), "");
+static_assert( move<tuple<int, int, int>>(), "");
+static_assert( move<tuple<AnyAssign, AnyAssign, AnyAssign>>(), "");
+static_assert( move<tuple<int, AnyAssign, AnyAssign>>(), "");
+static_assert( move<tuple<AnyAssign, int, AnyAssign>>(), "");
+static_assert( move<tuple<AnyAssign, AnyAssign, int>>(), "");
+
+static_assert( ! copy<tuple<DelCopyAssign>>(), "");
+static_assert( ! copy<tuple<DelCopyAssign, int>>(), "");
+static_assert( ! copy<tuple<int, DelCopyAssign>>(), "");
+static_assert( ! copy<tuple<DelCopyAssign, int, int>>(), "");
+static_assert( ! copy<tuple<int, DelCopyAssign, int>>(), "");
+static_assert( ! copy<tuple<int, int, DelCopyAssign>>(), "");
+
+static_assert( move<tuple<DelCopyAssign>>(), "");
+static_assert( move<tuple<DelCopyAssign, int>>(), "");
+static_assert( move<tuple<int, DelCopyAssign>>(), "");
+static_assert( move<tuple<DelCopyAssign, int, int>>(), "");
+static_assert( move<tuple<int, DelCopyAssign, int>>(), "");
+static_assert( move<tuple<int, int, DelCopyAssign>>(), "");
+
+static_assert( ! move<tuple<CopyConsOnlyType>>(), "");
+static_assert( ! move<tuple<CopyConsOnlyType, int>>(), "");
+static_assert( ! move<tuple<int, CopyConsOnlyType>>(), "");
+static_assert( ! move<tuple<CopyConsOnlyType, int, int>>(), "");
+static_assert( ! move<tuple<int, CopyConsOnlyType, int>>(), "");
+static_assert( ! move<tuple<int, int, CopyConsOnlyType>>(), "");
+
+// Assignment from different types of tuple (and pair):
+template<typename To, typename From>
+constexpr bool assign() { return std::is_assignable<To&, From>::value; }
+
+// 0-tuples
+static_assert( ! assign<tuple<>, tuple<int>>(), "" );
+static_assert( ! assign<tuple<>, const tuple<int>&>(), "" );
+
+// 1-tuples
+static_assert( ! assign<tuple<int>, tuple<>>(), "" );
+static_assert( ! assign<tuple<int>, const tuple<>&>(), "" );
+static_assert( ! assign<tuple<AnyAssign>, tuple<>>(), "" );
+static_assert( ! assign<tuple<AnyAssign>, tuple<int, int>>(), "" );
+static_assert( ! assign<tuple<AnyAssign>, pair<int, int>>(), "" );
+
+static_assert( ! assign<tuple<void*>, tuple<int>>(), "" );
+static_assert( ! assign<tuple<void*>, const tuple<int>&>(), "" );
+
+static_assert( assign<tuple<long>, tuple<int>>(), "" );
+static_assert( assign<tuple<long>, tuple<int>&>(), "" );
+static_assert( assign<tuple<long>, const tuple<int>>(), "" );
+static_assert( assign<tuple<long>, const tuple<int>&>(), "" );
+
+// 2-tuples
+static_assert( assign<tuple<long, long>, tuple<int, int>>(), "" );
+static_assert( assign<tuple<long, long>, tuple<int, int>&>(), "" );
+static_assert( assign<tuple<long, long>, const tuple<int, int>>(), "" );
+static_assert( assign<tuple<long, long>, const tuple<int, int>&>(), "" );
+
+static_assert( assign<tuple<long, long>, pair<int, int>>(), "" );
+static_assert( assign<tuple<long, long>, const pair<int, int>&>(), "" );
+static_assert( assign<tuple<long, long>, pair<int, int>>(), "" );
+static_assert( assign<tuple<long, long>, const pair<int, int>&&>(), "" );
+
+static_assert( assign<tuple<DelCopyAssign, AnyAssign>,
+ tuple<DelCopyAssign, int>>(), "" );
+static_assert( ! assign<tuple<DelCopyAssign, AnyAssign>,
+ tuple<DelCopyAssign, int>&>(), "" );
+static_assert( ! assign<tuple<DelCopyAssign, AnyAssign>,
+ const tuple<DelCopyAssign, int>&>(), "" );
+static_assert( ! assign<tuple<DelCopyAssign, AnyAssign>,
+ const tuple<DelCopyAssign, int>&&>(), "" );
+
+static_assert( assign<tuple<AnyAssign, DelCopyAssign>,
+ tuple<int, DelCopyAssign>>(), "" );
+static_assert( ! assign<tuple<AnyAssign, DelCopyAssign>,
+ tuple<int, DelCopyAssign>&>(), "" );
+static_assert( ! assign<tuple<AnyAssign, DelCopyAssign>,
+ const tuple<int, DelCopyAssign>&>(), "" );
+static_assert( ! assign<tuple<AnyAssign, DelCopyAssign>,
+ const tuple<int, DelCopyAssign>&&>(), "" );
+
+static_assert( ! assign<tuple<void*, int>,
+ tuple<int, int>>(), "" );
+static_assert( ! assign<tuple<void*, int>,
+ const tuple<int, int>&>(), "" );
+
+static_assert( assign<tuple<DelCopyAssign, AnyAssign>,
+ pair<DelCopyAssign, int>>(), "" );
+static_assert( ! assign<tuple<DelCopyAssign, AnyAssign>,
+ pair<DelCopyAssign, int>&>(), "" );
+static_assert( ! assign<tuple<DelCopyAssign, AnyAssign>,
+ const pair<DelCopyAssign, int>&>(), "" );
+static_assert( ! assign<tuple<DelCopyAssign, AnyAssign>,
+ const pair<DelCopyAssign, int>&&>(), "" );
+
+static_assert( assign<tuple<AnyAssign, DelCopyAssign>,
+ pair<int, DelCopyAssign>>(), "" );
+static_assert( ! assign<tuple<AnyAssign, DelCopyAssign>,
+ pair<int, DelCopyAssign>&>(), "" );
+static_assert( ! assign<tuple<AnyAssign, DelCopyAssign>,
+ const pair<int, DelCopyAssign>&>(), "" );
+static_assert( ! assign<tuple<AnyAssign, DelCopyAssign>,
+ const pair<int, DelCopyAssign>&&>(), "" );
+
+static_assert( ! assign<tuple<void*, int>,
+ pair<int, int>>(), "" );
+static_assert( ! assign<tuple<void*, int>,
+ const pair<int, int>&>(), "" );
+
+// 3-tuples
+static_assert( assign<tuple<AnyAssign, DelCopyAssign, AnyAssign>,
+ tuple<int, DelCopyAssign, int>>(), "" );
+static_assert( ! assign<tuple<AnyAssign, DelCopyAssign, AnyAssign>,
+ tuple<int, DelCopyAssign, int>&>(), "" );
+static_assert( ! assign<tuple<AnyAssign, DelCopyAssign, AnyAssign>,
+ const tuple<int, DelCopyAssign, int>&>(), "" );
+static_assert( ! assign<tuple<AnyAssign, DelCopyAssign, AnyAssign>,
+ const tuple<int, DelCopyAssign, int>&&>(), "" );
+
+static_assert( ! assign<tuple<int, void*, int>,
+ tuple<int, int, int>>(), "" );
+static_assert( ! assign<tuple<int, void*, int>,
+ const tuple<int, int, int>&>(), "" );
diff --git a/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc b/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc
index e76f53a..d550282 100644
--- a/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc
@@ -17,7 +17,7 @@
// { dg-options "-fno-show-column" }
// { dg-do compile { target c++14 } }
-// { dg-error "in range" "" { target *-*-* } 1297 }
+// { dg-prune-output "tuple index is in range" }
#include <tuple>
diff --git a/libstdc++-v3/testsuite/25_algorithms/copy/86658.cc b/libstdc++-v3/testsuite/25_algorithms/copy/86658.cc
index 600747a..dd4f7ba 100644
--- a/libstdc++-v3/testsuite/25_algorithms/copy/86658.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/copy/86658.cc
@@ -15,9 +15,9 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
+// { dg-options "-D_GLIBCXX_DEBUG" }
// { dg-do run }
-#define _GLIBCXX_DEBUG
#include <algorithm>
#include <vector>