summaryrefslogtreecommitdiff
path: root/gcc/config/mn10300
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/mn10300')
-rw-r--r--gcc/config/mn10300/constraints.md107
-rw-r--r--gcc/config/mn10300/linux.h90
-rw-r--r--gcc/config/mn10300/mn10300-modes.def24
-rw-r--r--gcc/config/mn10300/mn10300-protos.h57
-rw-r--r--gcc/config/mn10300/mn10300.c3254
-rw-r--r--gcc/config/mn10300/mn10300.h766
-rw-r--r--gcc/config/mn10300/mn10300.md2154
-rw-r--r--gcc/config/mn10300/mn10300.opt56
-rw-r--r--gcc/config/mn10300/predicates.md69
-rw-r--r--gcc/config/mn10300/t-linux29
-rw-r--r--gcc/config/mn10300/t-mn1030036
11 files changed, 6642 insertions, 0 deletions
diff --git a/gcc/config/mn10300/constraints.md b/gcc/config/mn10300/constraints.md
new file mode 100644
index 000000000..c8ee2d4e2
--- /dev/null
+++ b/gcc/config/mn10300/constraints.md
@@ -0,0 +1,107 @@
+;; Constraint definitions for the MN10300.
+;; Copyright (C) 2007, 2008 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/>.
+
+(define_register_constraint "d" "DATA_REGS"
+ "A data register.")
+
+(define_register_constraint "a" "ADDRESS_REGS"
+ "An address register.")
+
+;; This can be used for QI/HImode memory operations, and most arithmetic.
+;; AM33 supports these on all registers, where MN103 needs DATA_REGS.
+(define_register_constraint "D" "TARGET_AM33 ? GENERAL_REGS : DATA_REGS"
+ "A general register for AM33, and a data register otherwise.")
+
+;; Similarly for ADDRESS_REGS vs GENERAL_REGS.
+(define_register_constraint "A" "TARGET_AM33 ? GENERAL_REGS : ADDRESS_REGS"
+ "A general register for AM33, and an address register otherwise.")
+
+(define_register_constraint "y" "SP_REGS"
+ "An SP register (if available).")
+
+(define_register_constraint "z" "MDR_REGS"
+ "The MDR register.")
+
+(define_register_constraint "x" "TARGET_AM33 ? EXTENDED_REGS : NO_REGS"
+ "An extended register.")
+
+(define_register_constraint "f" "TARGET_AM33_2 ? FP_REGS : NO_REGS"
+ "A floating point register.")
+
+(define_register_constraint "c" "TARGET_AM33_2 ? FP_ACC_REGS : NO_REGS"
+ "A floating point accumulator register.")
+
+(define_memory_constraint "Q"
+ "@internal"
+ (and (match_code "mem")
+ (match_test "!CONSTANT_ADDRESS_P (XEXP (op, 0))")))
+
+(define_constraint "S"
+ "@internal"
+ (if_then_else (match_test "flag_pic")
+ (and (match_test "GET_CODE (op) == UNSPEC")
+ (ior (match_test "XINT (op, 1) == UNSPEC_PLT")
+ (match_test "XINT (op, 1) == UNSPEC_PIC")
+ (match_test "XINT (op, 1) == UNSPEC_GOTSYM_OFF")))
+ (match_test "GET_CODE (op) == SYMBOL_REF")))
+
+;; Integer constraints
+
+(define_constraint "I"
+ "An integer zero."
+ (and (match_code "const_int")
+ (match_test "ival == 0")))
+
+(define_constraint "J"
+ "An integer one."
+ (and (match_code "const_int")
+ (match_test "ival == 1")))
+
+(define_constraint "K"
+ "An integer two."
+ (and (match_code "const_int")
+ (match_test "ival == 2")))
+
+(define_constraint "L"
+ "An integer four."
+ (and (match_code "const_int")
+ (match_test "ival == 4")))
+
+(define_constraint "M"
+ "An integer three."
+ (and (match_code "const_int")
+ (match_test "ival == 3")))
+
+(define_constraint "N"
+ "An integer of either 255 or 65535."
+ (and (match_code "const_int")
+ (ior (match_test "ival == 255")
+ (match_test "ival == 65535"))))
+
+(define_constraint "O"
+ "An integer between -8 and +7 inclusive."
+ (and (match_code "const_int")
+ (and (match_test "ival >= -8")
+ (match_test "ival <= 7"))))
+
+;; Floating-point constraints
+(define_constraint "G"
+ "Floating-point zero."
+ (and (match_code "const_double")
+ (match_test "op == CONST0_RTX (mode)")))
diff --git a/gcc/config/mn10300/linux.h b/gcc/config/mn10300/linux.h
new file mode 100644
index 000000000..ca0e10a65
--- /dev/null
+++ b/gcc/config/mn10300/linux.h
@@ -0,0 +1,90 @@
+/* Definitions of taret machine for GNU compiler.
+ Matsushita AM33/2.0
+ Copyright 2001, 2002, 2005, 2006, 2007, 2010 Free Software Foundation, Inc.
+ Contributed by Alexandre Oliva <aoliva@redhat.com>
+
+ 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/>. */
+
+#undef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
+
+#define TARGET_OS_CPP_BUILTINS() LINUX_TARGET_OS_CPP_BUILTINS()
+
+#undef CPP_SPEC
+#define CPP_SPEC "%{mam33:-D__AM33__} %{!mam33:-D__AM33__=2 -D__AM33_2__} \
+ %{posix:-D_POSIX_SOURCE} \
+ %{pthread:-D_REENTRANT -D_PTHREADS}"
+
+#undef ASM_SPEC
+#define ASM_SPEC ""
+
+#define GLIBC_DYNAMIC_LINKER "/lib/ld.so.1"
+
+#undef LINK_SPEC
+#define LINK_SPEC "%{mrelax:--relax} %{shared:-shared} \
+ %{!static: \
+ %{rdynamic:-export-dynamic} \
+ -dynamic-linker " LINUX_DYNAMIC_LINKER "} \
+ %{static:-static}"
+
+#undef PROCESSOR_DEFAULT
+#define PROCESSOR_DEFAULT PROCESSOR_AM33_2
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (AM33/2.0 GNU/Linux)");
+
+#define DBX_REGISTER_NUMBER(REGNO) (REGNO)
+
+extern int mn10300_protect_label;
+
+#undef PRINT_OPERAND
+#define PRINT_OPERAND(FILE, X, CODE) \
+ do \
+ { \
+ mn10300_protect_label = 1; \
+ mn10300_print_operand ((FILE), (X), (CODE)); \
+ mn10300_protect_label = 0; \
+ } \
+ while (0)
+
+#undef PRINT_OPERAND_ADDRESS
+#define PRINT_OPERAND_ADDRESS(FILE, X) \
+ do \
+ { \
+ mn10300_protect_label = 1; \
+ mn10300_print_operand_address ((FILE), (X)); \
+ mn10300_protect_label = 0; \
+ } \
+ while (0)
+
+#undef ASM_OUTPUT_LABELREF
+#define ASM_OUTPUT_LABELREF(FILE, NAME) \
+ do \
+ { \
+ const char * real_name; \
+ \
+ real_name = (*targetm.strip_name_encoding) (NAME); \
+ if (mn10300_protect_label) \
+ asm_fprintf (FILE, "+"); \
+ asm_fprintf (FILE, "%U%s", real_name); \
+ } \
+ while (0)
+
+#undef SIZE_TYPE
+#undef PTRDIFF_TYPE
+#undef WCHAR_TYPE
+#undef WCHAR_TYPE_SIZE
diff --git a/gcc/config/mn10300/mn10300-modes.def b/gcc/config/mn10300/mn10300-modes.def
new file mode 100644
index 000000000..832663edb
--- /dev/null
+++ b/gcc/config/mn10300/mn10300-modes.def
@@ -0,0 +1,24 @@
+/* Definitions of target machine for GNU compiler, for MN10300.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+ Contributed by Red Hat Inc.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING. If not, write to
+ the Free Software Foundation, , Inc., 51 Franklin Street - Fifth
+ Floor, Boston, MA 02110-1301, USA. */
+
+CC_MODE (CCZN);
+CC_MODE (CCZNC);
+CC_MODE (CC_FLOAT);
diff --git a/gcc/config/mn10300/mn10300-protos.h b/gcc/config/mn10300/mn10300-protos.h
new file mode 100644
index 000000000..058f5df87
--- /dev/null
+++ b/gcc/config/mn10300/mn10300-protos.h
@@ -0,0 +1,57 @@
+/* Definitions of target machine for GNU compiler. Matsushita MN10300 series
+ Copyright (C) 2000, 2003, 2004, 2005, 2007, 2009, 2010
+ Free Software Foundation, Inc.
+ Contributed by Jeff Law (law@cygnus.com).
+
+ 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 Mmode enum machine_mode
+#define Cstar const char *
+#define Rclas enum reg_class
+
+#ifdef RTX_CODE
+extern rtx mn10300_legitimize_pic_address (rtx, rtx);
+extern int mn10300_legitimate_pic_operand_p (rtx);
+extern rtx mn10300_legitimize_reload_address (rtx, Mmode, int, int, int);
+extern bool mn10300_function_value_regno_p (const unsigned int);
+extern int mn10300_get_live_callee_saved_regs (void);
+extern bool mn10300_hard_regno_mode_ok (unsigned int, Mmode);
+extern bool mn10300_legitimate_constant_p (rtx);
+extern bool mn10300_modes_tieable (Mmode, Mmode);
+extern Cstar mn10300_output_add (rtx[3], bool);
+extern void mn10300_print_operand (FILE *, rtx, int);
+extern void mn10300_print_operand_address (FILE *, rtx);
+extern void mn10300_print_reg_list (FILE *, int);
+extern Mmode mn10300_select_cc_mode (enum rtx_code, rtx, rtx);
+extern int mn10300_store_multiple_operation (rtx, Mmode);
+extern int mn10300_symbolic_operand (rtx, Mmode);
+extern void mn10300_split_cbranch (Mmode, rtx, rtx);
+extern int mn10300_split_and_operand_count (rtx);
+extern bool mn10300_match_ccmode (rtx, Mmode);
+#endif /* RTX_CODE */
+
+extern bool mn10300_regno_in_class_p (unsigned, int, bool);
+extern bool mn10300_can_use_rets_insn (void);
+extern bool mn10300_can_use_retf_insn (void);
+extern void mn10300_expand_prologue (void);
+extern void mn10300_expand_epilogue (void);
+extern int mn10300_initial_offset (int, int);
+extern int mn10300_frame_size (void);
+
+#undef Mmode
+#undef Cstar
+#undef Rclas
diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
new file mode 100644
index 000000000..e3c417e46
--- /dev/null
+++ b/gcc/config/mn10300/mn10300.c
@@ -0,0 +1,3254 @@
+/* Subroutines for insn-output.c for Matsushita MN10300 series
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+ 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+ Contributed by Jeff Law (law@cygnus.com).
+
+ 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 "rtl.h"
+#include "tree.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "insn-config.h"
+#include "conditions.h"
+#include "output.h"
+#include "insn-attr.h"
+#include "flags.h"
+#include "recog.h"
+#include "reload.h"
+#include "expr.h"
+#include "optabs.h"
+#include "function.h"
+#include "obstack.h"
+#include "diagnostic-core.h"
+#include "tm_p.h"
+#include "tm-constrs.h"
+#include "target.h"
+#include "target-def.h"
+#include "df.h"
+
+/* This is used in the am33_2.0-linux-gnu port, in which global symbol
+ names are not prefixed by underscores, to tell whether to prefix a
+ label with a plus sign or not, so that the assembler can tell
+ symbol names from register names. */
+int mn10300_protect_label;
+
+/* The selected processor. */
+enum processor_type mn10300_processor = PROCESSOR_DEFAULT;
+
+/* Processor type to select for tuning. */
+static const char * mn10300_tune_string = NULL;
+
+/* Selected processor type for tuning. */
+enum processor_type mn10300_tune_cpu = PROCESSOR_DEFAULT;
+
+/* The size of the callee register save area. Right now we save everything
+ on entry since it costs us nothing in code size. It does cost us from a
+ speed standpoint, so we want to optimize this sooner or later. */
+#define REG_SAVE_BYTES (4 * df_regs_ever_live_p (2) \
+ + 4 * df_regs_ever_live_p (3) \
+ + 4 * df_regs_ever_live_p (6) \
+ + 4 * df_regs_ever_live_p (7) \
+ + 16 * (df_regs_ever_live_p (14) \
+ || df_regs_ever_live_p (15) \
+ || df_regs_ever_live_p (16) \
+ || df_regs_ever_live_p (17)))
+
+/* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */
+static const struct default_options mn10300_option_optimization_table[] =
+ {
+ { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 },
+ { OPT_LEVELS_NONE, 0, NULL, 0 }
+ };
+
+#define CC_FLAG_Z 1
+#define CC_FLAG_N 2
+#define CC_FLAG_C 4
+#define CC_FLAG_V 8
+
+static int cc_flags_for_mode(enum machine_mode);
+static int cc_flags_for_code(enum rtx_code);
+
+/* Implement TARGET_HANDLE_OPTION. */
+
+static bool
+mn10300_handle_option (size_t code,
+ const char *arg ATTRIBUTE_UNUSED,
+ int value)
+{
+ switch (code)
+ {
+ case OPT_mam33:
+ mn10300_processor = value ? PROCESSOR_AM33 : PROCESSOR_MN10300;
+ return true;
+
+ case OPT_mam33_2:
+ mn10300_processor = (value
+ ? PROCESSOR_AM33_2
+ : MIN (PROCESSOR_AM33, PROCESSOR_DEFAULT));
+ return true;
+
+ case OPT_mam34:
+ mn10300_processor = (value ? PROCESSOR_AM34 : PROCESSOR_DEFAULT);
+ return true;
+
+ case OPT_mtune_:
+ mn10300_tune_string = arg;
+ return true;
+
+ default:
+ return true;
+ }
+}
+
+/* Implement TARGET_OPTION_OVERRIDE. */
+
+static void
+mn10300_option_override (void)
+{
+ if (TARGET_AM33)
+ target_flags &= ~MASK_MULT_BUG;
+ else
+ {
+ /* Disable scheduling for the MN10300 as we do
+ not have timing information available for it. */
+ flag_schedule_insns = 0;
+ flag_schedule_insns_after_reload = 0;
+
+ /* Force enable splitting of wide types, as otherwise it is trivial
+ to run out of registers. Indeed, this works so well that register
+ allocation problems are now more common *without* optimization,
+ when this flag is not enabled by default. */
+ flag_split_wide_types = 1;
+ }
+
+ if (mn10300_tune_string)
+ {
+ if (strcasecmp (mn10300_tune_string, "mn10300") == 0)
+ mn10300_tune_cpu = PROCESSOR_MN10300;
+ else if (strcasecmp (mn10300_tune_string, "am33") == 0)
+ mn10300_tune_cpu = PROCESSOR_AM33;
+ else if (strcasecmp (mn10300_tune_string, "am33-2") == 0)
+ mn10300_tune_cpu = PROCESSOR_AM33_2;
+ else if (strcasecmp (mn10300_tune_string, "am34") == 0)
+ mn10300_tune_cpu = PROCESSOR_AM34;
+ else
+ error ("-mtune= expects mn10300, am33, am33-2, or am34");
+ }
+}
+
+static void
+mn10300_file_start (void)
+{
+ default_file_start ();
+
+ if (TARGET_AM33_2)
+ fprintf (asm_out_file, "\t.am33_2\n");
+ else if (TARGET_AM33)
+ fprintf (asm_out_file, "\t.am33\n");
+}
+
+/* Note: This list must match the liw_op attribute in mn10300.md. */
+
+static const char *liw_op_names[] =
+{
+ "add", "cmp", "sub", "mov",
+ "and", "or", "xor",
+ "asr", "lsr", "asl",
+ "none", "max"
+};
+
+/* Print operand X using operand code CODE to assembly language output file
+ FILE. */
+
+void
+mn10300_print_operand (FILE *file, rtx x, int code)
+{
+ switch (code)
+ {
+ case 'W':
+ {
+ unsigned int liw_op = UINTVAL (x);
+
+ gcc_assert (TARGET_ALLOW_LIW);
+ gcc_assert (liw_op < LIW_OP_MAX);
+ fputs (liw_op_names[liw_op], file);
+ break;
+ }
+
+ case 'b':
+ case 'B':
+ {
+ enum rtx_code cmp = GET_CODE (x);
+ enum machine_mode mode = GET_MODE (XEXP (x, 0));
+ const char *str;
+ int have_flags;
+
+ if (code == 'B')
+ cmp = reverse_condition (cmp);
+ have_flags = cc_flags_for_mode (mode);
+
+ switch (cmp)
+ {
+ case NE:
+ str = "ne";
+ break;
+ case EQ:
+ str = "eq";
+ break;
+ case GE:
+ /* bge is smaller than bnc. */
+ str = (have_flags & CC_FLAG_V ? "ge" : "nc");
+ break;
+ case LT:
+ str = (have_flags & CC_FLAG_V ? "lt" : "ns");
+ break;
+ case GT:
+ str = "gt";
+ break;
+ case LE:
+ str = "le";
+ break;
+ case GEU:
+ str = "cc";
+ break;
+ case GTU:
+ str = "hi";
+ break;
+ case LEU:
+ str = "ls";
+ break;
+ case LTU:
+ str = "cs";
+ break;
+ case ORDERED:
+ str = "lge";
+ break;
+ case UNORDERED:
+ str = "uo";
+ break;
+ case LTGT:
+ str = "lg";
+ break;
+ case UNEQ:
+ str = "ue";
+ break;
+ case UNGE:
+ str = "uge";
+ break;
+ case UNGT:
+ str = "ug";
+ break;
+ case UNLE:
+ str = "ule";
+ break;
+ case UNLT:
+ str = "ul";
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ gcc_checking_assert ((cc_flags_for_code (cmp) & ~have_flags) == 0);
+ fputs (str, file);
+ }
+ break;
+
+ case 'C':
+ /* This is used for the operand to a call instruction;
+ if it's a REG, enclose it in parens, else output
+ the operand normally. */
+ if (REG_P (x))
+ {
+ fputc ('(', file);
+ mn10300_print_operand (file, x, 0);
+ fputc (')', file);
+ }
+ else
+ mn10300_print_operand (file, x, 0);
+ break;
+
+ case 'D':
+ switch (GET_CODE (x))
+ {
+ case MEM:
+ fputc ('(', file);
+ output_address (XEXP (x, 0));
+ fputc (')', file);
+ break;
+
+ case REG:
+ fprintf (file, "fd%d", REGNO (x) - 18);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ break;
+
+ /* These are the least significant word in a 64bit value. */
+ case 'L':
+ switch (GET_CODE (x))
+ {
+ case MEM:
+ fputc ('(', file);
+ output_address (XEXP (x, 0));
+ fputc (')', file);
+ break;
+
+ case REG:
+ fprintf (file, "%s", reg_names[REGNO (x)]);
+ break;
+
+ case SUBREG:
+ fprintf (file, "%s", reg_names[subreg_regno (x)]);
+ break;
+
+ case CONST_DOUBLE:
+ {
+ long val[2];
+ REAL_VALUE_TYPE rv;
+
+ switch (GET_MODE (x))
+ {
+ case DFmode:
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
+ REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
+ fprintf (file, "0x%lx", val[0]);
+ break;;
+ case SFmode:
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
+ REAL_VALUE_TO_TARGET_SINGLE (rv, val[0]);
+ fprintf (file, "0x%lx", val[0]);
+ break;;
+ case VOIDmode:
+ case DImode:
+ mn10300_print_operand_address (file,
+ GEN_INT (CONST_DOUBLE_LOW (x)));
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ case CONST_INT:
+ {
+ rtx low, high;
+ split_double (x, &low, &high);
+ fprintf (file, "%ld", (long)INTVAL (low));
+ break;
+ }
+
+ default:
+ gcc_unreachable ();
+ }
+ break;
+
+ /* Similarly, but for the most significant word. */
+ case 'H':
+ switch (GET_CODE (x))
+ {
+ case MEM:
+ fputc ('(', file);
+ x = adjust_address (x, SImode, 4);
+ output_address (XEXP (x, 0));
+ fputc (')', file);
+ break;
+
+ case REG:
+ fprintf (file, "%s", reg_names[REGNO (x) + 1]);
+ break;
+
+ case SUBREG:
+ fprintf (file, "%s", reg_names[subreg_regno (x) + 1]);
+ break;
+
+ case CONST_DOUBLE:
+ {
+ long val[2];
+ REAL_VALUE_TYPE rv;
+
+ switch (GET_MODE (x))
+ {
+ case DFmode:
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
+ REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
+ fprintf (file, "0x%lx", val[1]);
+ break;;
+ case SFmode:
+ gcc_unreachable ();
+ case VOIDmode:
+ case DImode:
+ mn10300_print_operand_address (file,
+ GEN_INT (CONST_DOUBLE_HIGH (x)));
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ case CONST_INT:
+ {
+ rtx low, high;
+ split_double (x, &low, &high);
+ fprintf (file, "%ld", (long)INTVAL (high));
+ break;
+ }
+
+ default:
+ gcc_unreachable ();
+ }
+ break;
+
+ case 'A':
+ fputc ('(', file);
+ if (REG_P (XEXP (x, 0)))
+ output_address (gen_rtx_PLUS (SImode, XEXP (x, 0), const0_rtx));
+ else
+ output_address (XEXP (x, 0));
+ fputc (')', file);
+ break;
+
+ case 'N':
+ gcc_assert (INTVAL (x) >= -128 && INTVAL (x) <= 255);
+ fprintf (file, "%d", (int)((~INTVAL (x)) & 0xff));
+ break;
+
+ case 'U':
+ gcc_assert (INTVAL (x) >= -128 && INTVAL (x) <= 255);
+ fprintf (file, "%d", (int)(INTVAL (x) & 0xff));
+ break;
+
+ /* For shift counts. The hardware ignores the upper bits of
+ any immediate, but the assembler will flag an out of range
+ shift count as an error. So we mask off the high bits
+ of the immediate here. */
+ case 'S':
+ if (CONST_INT_P (x))
+ {
+ fprintf (file, "%d", (int)(INTVAL (x) & 0x1f));
+ break;
+ }
+ /* FALL THROUGH */
+
+ default:
+ switch (GET_CODE (x))
+ {
+ case MEM:
+ fputc ('(', file);
+ output_address (XEXP (x, 0));
+ fputc (')', file);
+ break;
+
+ case PLUS:
+ output_address (x);
+ break;
+
+ case REG:
+ fprintf (file, "%s", reg_names[REGNO (x)]);
+ break;
+
+ case SUBREG:
+ fprintf (file, "%s", reg_names[subreg_regno (x)]);
+ break;
+
+ /* This will only be single precision.... */
+ case CONST_DOUBLE:
+ {
+ unsigned long val;
+ REAL_VALUE_TYPE rv;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
+ REAL_VALUE_TO_TARGET_SINGLE (rv, val);
+ fprintf (file, "0x%lx", val);
+ break;
+ }
+
+ case CONST_INT:
+ case SYMBOL_REF:
+ case CONST:
+ case LABEL_REF:
+ case CODE_LABEL:
+ case UNSPEC:
+ mn10300_print_operand_address (file, x);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ break;
+ }
+}
+
+/* Output assembly language output for the address ADDR to FILE. */
+
+void
+mn10300_print_operand_address (FILE *file, rtx addr)
+{
+ switch (GET_CODE (addr))
+ {
+ case POST_INC:
+ mn10300_print_operand (file, XEXP (addr, 0), 0);
+ fputc ('+', file);
+ break;
+
+ case POST_MODIFY:
+ mn10300_print_operand (file, XEXP (addr, 0), 0);
+ fputc ('+', file);
+ fputc (',', file);
+ mn10300_print_operand (file, XEXP (addr, 1), 0);
+ break;
+
+ case REG:
+ mn10300_print_operand (file, addr, 0);
+ break;
+ case PLUS:
+ {
+ rtx base = XEXP (addr, 0);
+ rtx index = XEXP (addr, 1);
+
+ if (REG_P (index) && !REG_OK_FOR_INDEX_P (index))
+ {
+ rtx x = base;
+ base = index;
+ index = x;
+
+ gcc_assert (REG_P (index) && REG_OK_FOR_INDEX_P (index));
+ }
+ gcc_assert (REG_OK_FOR_BASE_P (base));
+
+ mn10300_print_operand (file, index, 0);
+ fputc (',', file);
+ mn10300_print_operand (file, base, 0);
+ break;
+ }
+ case SYMBOL_REF:
+ output_addr_const (file, addr);
+ break;
+ default:
+ output_addr_const (file, addr);
+ break;
+ }
+}
+
+/* Implement TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA.
+
+ Used for PIC-specific UNSPECs. */
+
+static bool
+mn10300_asm_output_addr_const_extra (FILE *file, rtx x)
+{
+ if (GET_CODE (x) == UNSPEC)
+ {
+ switch (XINT (x, 1))
+ {
+ case UNSPEC_PIC:
+ /* GLOBAL_OFFSET_TABLE or local symbols, no suffix. */
+ output_addr_const (file, XVECEXP (x, 0, 0));
+ break;
+ case UNSPEC_GOT:
+ output_addr_const (file, XVECEXP (x, 0, 0));
+ fputs ("@GOT", file);
+ break;
+ case UNSPEC_GOTOFF:
+ output_addr_const (file, XVECEXP (x, 0, 0));
+ fputs ("@GOTOFF", file);
+ break;
+ case UNSPEC_PLT:
+ output_addr_const (file, XVECEXP (x, 0, 0));
+ fputs ("@PLT", file);
+ break;
+ case UNSPEC_GOTSYM_OFF:
+ assemble_name (file, GOT_SYMBOL_NAME);
+ fputs ("-(", file);
+ output_addr_const (file, XVECEXP (x, 0, 0));
+ fputs ("-.)", file);
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+ else
+ return false;
+}
+
+/* Count the number of FP registers that have to be saved. */
+static int
+fp_regs_to_save (void)
+{
+ int i, n = 0;
+
+ if (! TARGET_AM33_2)
+ return 0;
+
+ for (i = FIRST_FP_REGNUM; i <= LAST_FP_REGNUM; ++i)
+ if (df_regs_ever_live_p (i) && ! call_really_used_regs[i])
+ ++n;
+
+ return n;
+}
+
+/* Print a set of registers in the format required by "movm" and "ret".
+ Register K is saved if bit K of MASK is set. The data and address
+ registers can be stored individually, but the extended registers cannot.
+ We assume that the mask already takes that into account. For instance,
+ bits 14 to 17 must have the same value. */
+
+void
+mn10300_print_reg_list (FILE *file, int mask)
+{
+ int need_comma;
+ int i;
+
+ need_comma = 0;
+ fputc ('[', file);
+
+ for (i = 0; i < FIRST_EXTENDED_REGNUM; i++)
+ if ((mask & (1 << i)) != 0)
+ {
+ if (need_comma)
+ fputc (',', file);
+ fputs (reg_names [i], file);
+ need_comma = 1;
+ }
+
+ if ((mask & 0x3c000) != 0)
+ {
+ gcc_assert ((mask & 0x3c000) == 0x3c000);
+ if (need_comma)
+ fputc (',', file);
+ fputs ("exreg1", file);
+ need_comma = 1;
+ }
+
+ fputc (']', file);
+}
+
+/* If the MDR register is never clobbered, we can use the RETF instruction
+ which takes the address from the MDR register. This is 3 cycles faster
+ than having to load the address from the stack. */
+
+bool
+mn10300_can_use_retf_insn (void)
+{
+ /* Don't bother if we're not optimizing. In this case we won't
+ have proper access to df_regs_ever_live_p. */
+ if (!optimize)
+ return false;
+
+ /* EH returns alter the saved return address; MDR is not current. */
+ if (crtl->calls_eh_return)
+ return false;
+
+ /* Obviously not if MDR is ever clobbered. */
+ if (df_regs_ever_live_p (MDR_REG))
+ return false;
+
+ /* ??? Careful not to use this during expand_epilogue etc. */
+ gcc_assert (!in_sequence_p ());
+ return leaf_function_p ();
+}
+
+bool
+mn10300_can_use_rets_insn (void)
+{
+ return !mn10300_initial_offset (ARG_POINTER_REGNUM, STACK_POINTER_REGNUM);
+}
+
+/* Returns the set of live, callee-saved registers as a bitmask. The
+ callee-saved extended registers cannot be stored individually, so
+ all of them will be included in the mask if any one of them is used. */
+
+int
+mn10300_get_live_callee_saved_regs (void)
+{
+ int mask;
+ int i;
+
+ mask = 0;
+ for (i = 0; i <= LAST_EXTENDED_REGNUM; i++)
+ if (df_regs_ever_live_p (i) && ! call_really_used_regs[i])
+ mask |= (1 << i);
+ if ((mask & 0x3c000) != 0)
+ mask |= 0x3c000;
+
+ return mask;
+}
+
+static rtx
+F (rtx r)
+{
+ RTX_FRAME_RELATED_P (r) = 1;
+ return r;
+}
+
+/* Generate an instruction that pushes several registers onto the stack.
+ Register K will be saved if bit K in MASK is set. The function does
+ nothing if MASK is zero.
+
+ To be compatible with the "movm" instruction, the lowest-numbered
+ register must be stored in the lowest slot. If MASK is the set
+ { R1,...,RN }, where R1...RN are ordered least first, the generated
+ instruction will have the form:
+
+ (parallel
+ (set (reg:SI 9) (plus:SI (reg:SI 9) (const_int -N*4)))
+ (set (mem:SI (plus:SI (reg:SI 9)
+ (const_int -1*4)))
+ (reg:SI RN))
+ ...
+ (set (mem:SI (plus:SI (reg:SI 9)
+ (const_int -N*4)))
+ (reg:SI R1))) */
+
+static void
+mn10300_gen_multiple_store (unsigned int mask)
+{
+ /* The order in which registers are stored, from SP-4 through SP-N*4. */
+ static const unsigned int store_order[8] = {
+ /* e2, e3: never saved */
+ FIRST_EXTENDED_REGNUM + 4,
+ FIRST_EXTENDED_REGNUM + 5,
+ FIRST_EXTENDED_REGNUM + 6,
+ FIRST_EXTENDED_REGNUM + 7,
+ /* e0, e1, mdrq, mcrh, mcrl, mcvf: never saved. */
+ FIRST_DATA_REGNUM + 2,
+ FIRST_DATA_REGNUM + 3,
+ FIRST_ADDRESS_REGNUM + 2,
+ FIRST_ADDRESS_REGNUM + 3,
+ /* d0, d1, a0, a1, mdr, lir, lar: never saved. */
+ };
+
+ rtx x, elts[9];
+ unsigned int i;
+ int count;
+
+ if (mask == 0)
+ return;
+
+ for (i = count = 0; i < ARRAY_SIZE(store_order); ++i)
+ {
+ unsigned regno = store_order[i];
+
+ if (((mask >> regno) & 1) == 0)
+ continue;
+
+ ++count;
+ x = plus_constant (stack_pointer_rtx, count * -4);
+ x = gen_frame_mem (SImode, x);
+ x = gen_rtx_SET (VOIDmode, x, gen_rtx_REG (SImode, regno));
+ elts[count] = F(x);
+
+ /* Remove the register from the mask so that... */
+ mask &= ~(1u << regno);
+ }
+
+ /* ... we can make sure that we didn't try to use a register
+ not listed in the store order. */
+ gcc_assert (mask == 0);
+
+ /* Create the instruction that updates the stack pointer. */
+ x = plus_constant (stack_pointer_rtx, count * -4);
+ x = gen_rtx_SET (VOIDmode, stack_pointer_rtx, x);
+ elts[0] = F(x);
+
+ /* We need one PARALLEL element to update the stack pointer and
+ an additional element for each register that is stored. */
+ x = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (count + 1, elts));
+ F (emit_insn (x));
+}
+
+void
+mn10300_expand_prologue (void)
+{
+ HOST_WIDE_INT size = mn10300_frame_size ();
+
+ /* If we use any of the callee-saved registers, save them now. */
+ mn10300_gen_multiple_store (mn10300_get_live_callee_saved_regs ());
+
+ if (TARGET_AM33_2 && fp_regs_to_save ())
+ {
+ int num_regs_to_save = fp_regs_to_save (), i;
+ HOST_WIDE_INT xsize;
+ enum
+ {
+ save_sp_merge,
+ save_sp_no_merge,
+ save_sp_partial_merge,
+ save_a0_merge,
+ save_a0_no_merge
+ } strategy;
+ unsigned int strategy_size = (unsigned)-1, this_strategy_size;
+ rtx reg;
+
+ /* We have several different strategies to save FP registers.
+ We can store them using SP offsets, which is beneficial if
+ there are just a few registers to save, or we can use `a0' in
+ post-increment mode (`a0' is the only call-clobbered address
+ register that is never used to pass information to a
+ function). Furthermore, if we don't need a frame pointer, we
+ can merge the two SP adds into a single one, but this isn't
+ always beneficial; sometimes we can just split the two adds
+ so that we don't exceed a 16-bit constant size. The code
+ below will select which strategy to use, so as to generate
+ smallest code. Ties are broken in favor or shorter sequences
+ (in terms of number of instructions). */
+
+#define SIZE_ADD_AX(S) ((((S) >= (1 << 15)) || ((S) < -(1 << 15))) ? 6 \
+ : (((S) >= (1 << 7)) || ((S) < -(1 << 7))) ? 4 : 2)
+#define SIZE_ADD_SP(S) ((((S) >= (1 << 15)) || ((S) < -(1 << 15))) ? 6 \
+ : (((S) >= (1 << 7)) || ((S) < -(1 << 7))) ? 4 : 3)
+
+/* We add 0 * (S) in two places to promote to the type of S,
+ so that all arms of the conditional have the same type. */
+#define SIZE_FMOV_LIMIT(S,N,L,SIZE1,SIZE2,ELSE) \
+ (((S) >= (L)) ? 0 * (S) + (SIZE1) * (N) \
+ : ((S) + 4 * (N) >= (L)) ? (((L) - (S)) / 4 * (SIZE2) \
+ + ((S) + 4 * (N) - (L)) / 4 * (SIZE1)) \
+ : 0 * (S) + (ELSE))
+#define SIZE_FMOV_SP_(S,N) \
+ (SIZE_FMOV_LIMIT ((S), (N), (1 << 24), 7, 6, \
+ SIZE_FMOV_LIMIT ((S), (N), (1 << 8), 6, 4, \
+ (S) ? 4 * (N) : 3 + 4 * ((N) - 1))))
+#define SIZE_FMOV_SP(S,N) (SIZE_FMOV_SP_ ((unsigned HOST_WIDE_INT)(S), (N)))
+
+ /* Consider alternative save_sp_merge only if we don't need the
+ frame pointer and size is nonzero. */
+ if (! frame_pointer_needed && size)
+ {
+ /* Insn: add -(size + 4 * num_regs_to_save), sp. */
+ this_strategy_size = SIZE_ADD_SP (-(size + 4 * num_regs_to_save));
+ /* Insn: fmov fs#, (##, sp), for each fs# to be saved. */
+ this_strategy_size += SIZE_FMOV_SP (size, num_regs_to_save);
+
+ if (this_strategy_size < strategy_size)
+ {
+ strategy = save_sp_merge;
+ strategy_size = this_strategy_size;
+ }
+ }
+
+ /* Consider alternative save_sp_no_merge unconditionally. */
+ /* Insn: add -4 * num_regs_to_save, sp. */
+ this_strategy_size = SIZE_ADD_SP (-4 * num_regs_to_save);
+ /* Insn: fmov fs#, (##, sp), for each fs# to be saved. */
+ this_strategy_size += SIZE_FMOV_SP (0, num_regs_to_save);
+ if (size)
+ {
+ /* Insn: add -size, sp. */
+ this_strategy_size += SIZE_ADD_SP (-size);
+ }
+
+ if (this_strategy_size < strategy_size)
+ {
+ strategy = save_sp_no_merge;
+ strategy_size = this_strategy_size;
+ }
+
+ /* Consider alternative save_sp_partial_merge only if we don't
+ need a frame pointer and size is reasonably large. */
+ if (! frame_pointer_needed && size + 4 * num_regs_to_save > 128)
+ {
+ /* Insn: add -128, sp. */
+ this_strategy_size = SIZE_ADD_SP (-128);
+ /* Insn: fmov fs#, (##, sp), for each fs# to be saved. */
+ this_strategy_size += SIZE_FMOV_SP (128 - 4 * num_regs_to_save,
+ num_regs_to_save);
+ if (size)
+ {
+ /* Insn: add 128-size, sp. */
+ this_strategy_size += SIZE_ADD_SP (128 - size);
+ }
+
+ if (this_strategy_size < strategy_size)
+ {
+ strategy = save_sp_partial_merge;
+ strategy_size = this_strategy_size;
+ }
+ }
+
+ /* Consider alternative save_a0_merge only if we don't need a
+ frame pointer, size is nonzero and the user hasn't
+ changed the calling conventions of a0. */
+ if (! frame_pointer_needed && size
+ && call_really_used_regs [FIRST_ADDRESS_REGNUM]
+ && ! fixed_regs[FIRST_ADDRESS_REGNUM])
+ {
+ /* Insn: add -(size + 4 * num_regs_to_save), sp. */
+ this_strategy_size = SIZE_ADD_SP (-(size + 4 * num_regs_to_save));
+ /* Insn: mov sp, a0. */
+ this_strategy_size++;
+ if (size)
+ {
+ /* Insn: add size, a0. */
+ this_strategy_size += SIZE_ADD_AX (size);
+ }
+ /* Insn: fmov fs#, (a0+), for each fs# to be saved. */
+ this_strategy_size += 3 * num_regs_to_save;
+
+ if (this_strategy_size < strategy_size)
+ {
+ strategy = save_a0_merge;
+ strategy_size = this_strategy_size;
+ }
+ }
+
+ /* Consider alternative save_a0_no_merge if the user hasn't
+ changed the calling conventions of a0. */
+ if (call_really_used_regs [FIRST_ADDRESS_REGNUM]
+ && ! fixed_regs[FIRST_ADDRESS_REGNUM])
+ {
+ /* Insn: add -4 * num_regs_to_save, sp. */
+ this_strategy_size = SIZE_ADD_SP (-4 * num_regs_to_save);
+ /* Insn: mov sp, a0. */
+ this_strategy_size++;
+ /* Insn: fmov fs#, (a0+), for each fs# to be saved. */
+ this_strategy_size += 3 * num_regs_to_save;
+ if (size)
+ {
+ /* Insn: add -size, sp. */
+ this_strategy_size += SIZE_ADD_SP (-size);
+ }
+
+ if (this_strategy_size < strategy_size)
+ {
+ strategy = save_a0_no_merge;
+ strategy_size = this_strategy_size;
+ }
+ }
+
+ /* Emit the initial SP add, common to all strategies. */
+ switch (strategy)
+ {
+ case save_sp_no_merge:
+ case save_a0_no_merge:
+ F (emit_insn (gen_addsi3 (stack_pointer_rtx,
+ stack_pointer_rtx,
+ GEN_INT (-4 * num_regs_to_save))));
+ xsize = 0;
+ break;
+
+ case save_sp_partial_merge:
+ F (emit_insn (gen_addsi3 (stack_pointer_rtx,
+ stack_pointer_rtx,
+ GEN_INT (-128))));
+ xsize = 128 - 4 * num_regs_to_save;
+ size -= xsize;
+ break;
+
+ case save_sp_merge:
+ case save_a0_merge:
+ F (emit_insn (gen_addsi3 (stack_pointer_rtx,
+ stack_pointer_rtx,
+ GEN_INT (-(size + 4 * num_regs_to_save)))));
+ /* We'll have to adjust FP register saves according to the
+ frame size. */
+ xsize = size;
+ /* Since we've already created the stack frame, don't do it
+ again at the end of the function. */
+ size = 0;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ /* Now prepare register a0, if we have decided to use it. */
+ switch (strategy)
+ {
+ case save_sp_merge:
+ case save_sp_no_merge:
+ case save_sp_partial_merge:
+ reg = 0;
+ break;
+
+ case save_a0_merge:
+ case save_a0_no_merge:
+ reg = gen_rtx_REG (SImode, FIRST_ADDRESS_REGNUM);
+ F (emit_insn (gen_movsi (reg, stack_pointer_rtx)));
+ if (xsize)
+ F (emit_insn (gen_addsi3 (reg, reg, GEN_INT (xsize))));
+ reg = gen_rtx_POST_INC (SImode, reg);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ /* Now actually save the FP registers. */
+ for (i = FIRST_FP_REGNUM; i <= LAST_FP_REGNUM; ++i)
+ if (df_regs_ever_live_p (i) && ! call_really_used_regs [i])
+ {
+ rtx addr;
+
+ if (reg)
+ addr = reg;
+ else
+ {
+ /* If we aren't using `a0', use an SP offset. */
+ if (xsize)
+ {
+ addr = gen_rtx_PLUS (SImode,
+ stack_pointer_rtx,
+ GEN_INT (xsize));
+ }
+ else
+ addr = stack_pointer_rtx;
+
+ xsize += 4;
+ }
+
+ F (emit_insn (gen_movsf (gen_rtx_MEM (SFmode, addr),
+ gen_rtx_REG (SFmode, i))));
+ }
+ }
+
+ /* Now put the frame pointer into the frame pointer register. */
+ if (frame_pointer_needed)
+ F (emit_move_insn (frame_pointer_rtx, stack_pointer_rtx));
+
+ /* Allocate stack for this frame. */
+ if (size)
+ F (emit_insn (gen_addsi3 (stack_pointer_rtx,
+ stack_pointer_rtx,
+ GEN_INT (-size))));
+
+ if (flag_pic && df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM))
+ emit_insn (gen_load_pic ());
+}
+
+void
+mn10300_expand_epilogue (void)
+{
+ HOST_WIDE_INT size = mn10300_frame_size ();
+ int reg_save_bytes = REG_SAVE_BYTES;
+
+ if (TARGET_AM33_2 && fp_regs_to_save ())
+ {
+ int num_regs_to_save = fp_regs_to_save (), i;
+ rtx reg = 0;
+
+ /* We have several options to restore FP registers. We could
+ load them from SP offsets, but, if there are enough FP
+ registers to restore, we win if we use a post-increment
+ addressing mode. */
+
+ /* If we have a frame pointer, it's the best option, because we
+ already know it has the value we want. */
+ if (frame_pointer_needed)
+ reg = gen_rtx_REG (SImode, FRAME_POINTER_REGNUM);
+ /* Otherwise, we may use `a1', since it's call-clobbered and
+ it's never used for return values. But only do so if it's
+ smaller than using SP offsets. */
+ else
+ {
+ enum { restore_sp_post_adjust,
+ restore_sp_pre_adjust,
+ restore_sp_partial_adjust,
+ restore_a1 } strategy;
+ unsigned int this_strategy_size, strategy_size = (unsigned)-1;
+
+ /* Consider using sp offsets before adjusting sp. */
+ /* Insn: fmov (##,sp),fs#, for each fs# to be restored. */
+ this_strategy_size = SIZE_FMOV_SP (size, num_regs_to_save);
+ /* If size is too large, we'll have to adjust SP with an
+ add. */
+ if (size + 4 * num_regs_to_save + reg_save_bytes > 255)
+ {
+ /* Insn: add size + 4 * num_regs_to_save, sp. */
+ this_strategy_size += SIZE_ADD_SP (size + 4 * num_regs_to_save);
+ }
+ /* If we don't have to restore any non-FP registers,
+ we'll be able to save one byte by using rets. */
+ if (! reg_save_bytes)
+ this_strategy_size--;
+
+ if (this_strategy_size < strategy_size)
+ {
+ strategy = restore_sp_post_adjust;
+ strategy_size = this_strategy_size;
+ }
+
+ /* Consider using sp offsets after adjusting sp. */
+ /* Insn: add size, sp. */
+ this_strategy_size = SIZE_ADD_SP (size);
+ /* Insn: fmov (##,sp),fs#, for each fs# to be restored. */
+ this_strategy_size += SIZE_FMOV_SP (0, num_regs_to_save);
+ /* We're going to use ret to release the FP registers
+ save area, so, no savings. */
+
+ if (this_strategy_size < strategy_size)
+ {
+ strategy = restore_sp_pre_adjust;
+ strategy_size = this_strategy_size;
+ }
+
+ /* Consider using sp offsets after partially adjusting sp.
+ When size is close to 32Kb, we may be able to adjust SP
+ with an imm16 add instruction while still using fmov
+ (d8,sp). */
+ if (size + 4 * num_regs_to_save + reg_save_bytes > 255)
+ {
+ /* Insn: add size + 4 * num_regs_to_save
+ + reg_save_bytes - 252,sp. */
+ this_strategy_size = SIZE_ADD_SP (size + 4 * num_regs_to_save
+ + reg_save_bytes - 252);
+ /* Insn: fmov (##,sp),fs#, fo each fs# to be restored. */
+ this_strategy_size += SIZE_FMOV_SP (252 - reg_save_bytes
+ - 4 * num_regs_to_save,
+ num_regs_to_save);
+ /* We're going to use ret to release the FP registers
+ save area, so, no savings. */
+
+ if (this_strategy_size < strategy_size)
+ {
+ strategy = restore_sp_partial_adjust;
+ strategy_size = this_strategy_size;
+ }
+ }
+
+ /* Consider using a1 in post-increment mode, as long as the
+ user hasn't changed the calling conventions of a1. */
+ if (call_really_used_regs [FIRST_ADDRESS_REGNUM + 1]
+ && ! fixed_regs[FIRST_ADDRESS_REGNUM+1])
+ {
+ /* Insn: mov sp,a1. */
+ this_strategy_size = 1;
+ if (size)
+ {
+ /* Insn: add size,a1. */
+ this_strategy_size += SIZE_ADD_AX (size);
+ }
+ /* Insn: fmov (a1+),fs#, for each fs# to be restored. */
+ this_strategy_size += 3 * num_regs_to_save;
+ /* If size is large enough, we may be able to save a
+ couple of bytes. */
+ if (size + 4 * num_regs_to_save + reg_save_bytes > 255)
+ {
+ /* Insn: mov a1,sp. */
+ this_strategy_size += 2;
+ }
+ /* If we don't have to restore any non-FP registers,
+ we'll be able to save one byte by using rets. */
+ if (! reg_save_bytes)
+ this_strategy_size--;
+
+ if (this_strategy_size < strategy_size)
+ {
+ strategy = restore_a1;
+ strategy_size = this_strategy_size;
+ }
+ }
+
+ switch (strategy)
+ {
+ case restore_sp_post_adjust:
+ break;
+
+ case restore_sp_pre_adjust:
+ emit_insn (gen_addsi3 (stack_pointer_rtx,
+ stack_pointer_rtx,
+ GEN_INT (size)));
+ size = 0;
+ break;
+
+ case restore_sp_partial_adjust:
+ emit_insn (gen_addsi3 (stack_pointer_rtx,
+ stack_pointer_rtx,
+ GEN_INT (size + 4 * num_regs_to_save
+ + reg_save_bytes - 252)));
+ size = 252 - reg_save_bytes - 4 * num_regs_to_save;
+ break;
+
+ case restore_a1:
+ reg = gen_rtx_REG (SImode, FIRST_ADDRESS_REGNUM + 1);
+ emit_insn (gen_movsi (reg, stack_pointer_rtx));
+ if (size)
+ emit_insn (gen_addsi3 (reg, reg, GEN_INT (size)));
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ }
+
+ /* Adjust the selected register, if any, for post-increment. */
+ if (reg)
+ reg = gen_rtx_POST_INC (SImode, reg);
+
+ for (i = FIRST_FP_REGNUM; i <= LAST_FP_REGNUM; ++i)
+ if (df_regs_ever_live_p (i) && ! call_really_used_regs [i])
+ {
+ rtx addr;
+
+ if (reg)
+ addr = reg;
+ else if (size)
+ {
+ /* If we aren't using a post-increment register, use an
+ SP offset. */
+ addr = gen_rtx_PLUS (SImode,
+ stack_pointer_rtx,
+ GEN_INT (size));
+ }
+ else
+ addr = stack_pointer_rtx;
+
+ size += 4;
+
+ emit_insn (gen_movsf (gen_rtx_REG (SFmode, i),
+ gen_rtx_MEM (SFmode, addr)));
+ }
+
+ /* If we were using the restore_a1 strategy and the number of
+ bytes to be released won't fit in the `ret' byte, copy `a1'
+ to `sp', to avoid having to use `add' to adjust it. */
+ if (! frame_pointer_needed && reg && size + reg_save_bytes > 255)
+ {
+ emit_move_insn (stack_pointer_rtx, XEXP (reg, 0));
+ size = 0;
+ }
+ }
+
+ /* Maybe cut back the stack, except for the register save area.
+
+ If the frame pointer exists, then use the frame pointer to
+ cut back the stack.
+
+ If the stack size + register save area is more than 255 bytes,
+ then the stack must be cut back here since the size + register
+ save size is too big for a ret/retf instruction.
+
+ Else leave it alone, it will be cut back as part of the
+ ret/retf instruction, or there wasn't any stack to begin with.
+
+ Under no circumstances should the register save area be
+ deallocated here, that would leave a window where an interrupt
+ could occur and trash the register save area. */
+ if (frame_pointer_needed)
+ {
+ emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
+ size = 0;
+ }
+ else if (size + reg_save_bytes > 255)
+ {
+ emit_insn (gen_addsi3 (stack_pointer_rtx,
+ stack_pointer_rtx,
+ GEN_INT (size)));
+ size = 0;
+ }
+
+ /* Adjust the stack and restore callee-saved registers, if any. */
+ if (mn10300_can_use_rets_insn ())
+ emit_jump_insn (gen_rtx_RETURN (VOIDmode));
+ else
+ emit_jump_insn (gen_return_ret (GEN_INT (size + REG_SAVE_BYTES)));
+}
+
+/* Recognize the PARALLEL rtx generated by mn10300_gen_multiple_store().
+ This function is for MATCH_PARALLEL and so assumes OP is known to be
+ parallel. If OP is a multiple store, return a mask indicating which
+ registers it saves. Return 0 otherwise. */
+
+int
+mn10300_store_multiple_operation (rtx op,
+ enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+ int count;
+ int mask;
+ int i;
+ unsigned int last;
+ rtx elt;
+
+ count = XVECLEN (op, 0);
+ if (count < 2)
+ return 0;
+
+ /* Check that first instruction has the form (set (sp) (plus A B)) */
+ elt = XVECEXP (op, 0, 0);
+ if (GET_CODE (elt) != SET
+ || (! REG_P (SET_DEST (elt)))
+ || REGNO (SET_DEST (elt)) != STACK_POINTER_REGNUM
+ || GET_CODE (SET_SRC (elt)) != PLUS)
+ return 0;
+
+ /* Check that A is the stack pointer and B is the expected stack size.
+ For OP to match, each subsequent instruction should push a word onto
+ the stack. We therefore expect the first instruction to create
+ COUNT-1 stack slots. */
+ elt = SET_SRC (elt);
+ if ((! REG_P (XEXP (elt, 0)))
+ || REGNO (XEXP (elt, 0)) != STACK_POINTER_REGNUM
+ || (! CONST_INT_P (XEXP (elt, 1)))
+ || INTVAL (XEXP (elt, 1)) != -(count - 1) * 4)
+ return 0;
+
+ mask = 0;
+ for (i = 1; i < count; i++)
+ {
+ /* Check that element i is a (set (mem M) R). */
+ /* ??? Validate the register order a-la mn10300_gen_multiple_store.
+ Remember: the ordering is *not* monotonic. */
+ elt = XVECEXP (op, 0, i);
+ if (GET_CODE (elt) != SET
+ || (! MEM_P (SET_DEST (elt)))
+ || (! REG_P (SET_SRC (elt))))
+ return 0;
+
+ /* Remember which registers are to be saved. */
+ last = REGNO (SET_SRC (elt));
+ mask |= (1 << last);
+
+ /* Check that M has the form (plus (sp) (const_int -I*4)) */
+ elt = XEXP (SET_DEST (elt), 0);
+ if (GET_CODE (elt) != PLUS
+ || (! REG_P (XEXP (elt, 0)))
+ || REGNO (XEXP (elt, 0)) != STACK_POINTER_REGNUM
+ || (! CONST_INT_P (XEXP (elt, 1)))
+ || INTVAL (XEXP (elt, 1)) != -i * 4)
+ return 0;
+ }
+
+ /* All or none of the callee-saved extended registers must be in the set. */
+ if ((mask & 0x3c000) != 0
+ && (mask & 0x3c000) != 0x3c000)
+ return 0;
+
+ return mask;
+}
+
+/* Implement TARGET_PREFERRED_RELOAD_CLASS. */
+
+static reg_class_t
+mn10300_preferred_reload_class (rtx x, reg_class_t rclass)
+{
+ if (x == stack_pointer_rtx && rclass != SP_REGS)
+ return (TARGET_AM33 ? GENERAL_REGS : ADDRESS_REGS);
+ else if (MEM_P (x)
+ || (REG_P (x)
+ && !HARD_REGISTER_P (x))
+ || (GET_CODE (x) == SUBREG
+ && REG_P (SUBREG_REG (x))
+ && !HARD_REGISTER_P (SUBREG_REG (x))))
+ return LIMIT_RELOAD_CLASS (GET_MODE (x), rclass);
+ else
+ return rclass;
+}
+
+/* Implement TARGET_PREFERRED_OUTPUT_RELOAD_CLASS. */
+
+static reg_class_t
+mn10300_preferred_output_reload_class (rtx x, reg_class_t rclass)
+{
+ if (x == stack_pointer_rtx && rclass != SP_REGS)
+ return (TARGET_AM33 ? GENERAL_REGS : ADDRESS_REGS);
+ return rclass;
+}
+
+/* Implement TARGET_SECONDARY_RELOAD. */
+
+static reg_class_t
+mn10300_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i,
+ enum machine_mode mode, secondary_reload_info *sri)
+{
+ enum reg_class rclass = (enum reg_class) rclass_i;
+ enum reg_class xclass = NO_REGS;
+ unsigned int xregno = INVALID_REGNUM;
+
+ if (REG_P (x))
+ {
+ xregno = REGNO (x);
+ if (xregno >= FIRST_PSEUDO_REGISTER)
+ xregno = true_regnum (x);
+ if (xregno != INVALID_REGNUM)
+ xclass = REGNO_REG_CLASS (xregno);
+ }
+
+ if (!TARGET_AM33)
+ {
+ /* Memory load/stores less than a full word wide can't have an
+ address or stack pointer destination. They must use a data
+ register as an intermediate register. */
+ if (rclass != DATA_REGS
+ && (mode == QImode || mode == HImode)
+ && xclass == NO_REGS)
+ return DATA_REGS;
+
+ /* We can only move SP to/from an address register. */
+ if (in_p
+ && rclass == SP_REGS
+ && xclass != ADDRESS_REGS)
+ return ADDRESS_REGS;
+ if (!in_p
+ && xclass == SP_REGS
+ && rclass != ADDRESS_REGS
+ && rclass != SP_OR_ADDRESS_REGS)
+ return ADDRESS_REGS;
+ }
+
+ /* We can't directly load sp + const_int into a register;
+ we must use an address register as an scratch. */
+ if (in_p
+ && rclass != SP_REGS
+ && rclass != SP_OR_ADDRESS_REGS
+ && rclass != SP_OR_GENERAL_REGS
+ && GET_CODE (x) == PLUS
+ && (XEXP (x, 0) == stack_pointer_rtx
+ || XEXP (x, 1) == stack_pointer_rtx))
+ {
+ sri->icode = CODE_FOR_reload_plus_sp_const;
+ return NO_REGS;
+ }
+
+ /* We can only move MDR to/from a data register. */
+ if (rclass == MDR_REGS && xclass != DATA_REGS)
+ return DATA_REGS;
+ if (xclass == MDR_REGS && rclass != DATA_REGS)
+ return DATA_REGS;
+
+ /* We can't load/store an FP register from a constant address. */
+ if (TARGET_AM33_2
+ && (rclass == FP_REGS || xclass == FP_REGS)
+ && (xclass == NO_REGS || rclass == NO_REGS))
+ {
+ rtx addr = NULL;
+
+ if (xregno >= FIRST_PSEUDO_REGISTER && xregno != INVALID_REGNUM)
+ {
+ addr = reg_equiv_mem [xregno];
+ if (addr)
+ addr = XEXP (addr, 0);
+ }
+ else if (MEM_P (x))
+ addr = XEXP (x, 0);
+
+ if (addr && CONSTANT_ADDRESS_P (addr))
+ return GENERAL_REGS;
+ }
+
+ /* Otherwise assume no secondary reloads are needed. */
+ return NO_REGS;
+}
+
+int
+mn10300_frame_size (void)
+{
+ /* size includes the fixed stack space needed for function calls. */
+ int size = get_frame_size () + crtl->outgoing_args_size;
+
+ /* And space for the return pointer. */
+ size += crtl->outgoing_args_size ? 4 : 0;
+
+ return size;
+}
+
+int
+mn10300_initial_offset (int from, int to)
+{
+ int diff = 0;
+
+ gcc_assert (from == ARG_POINTER_REGNUM || from == FRAME_POINTER_REGNUM);
+ gcc_assert (to == FRAME_POINTER_REGNUM || to == STACK_POINTER_REGNUM);
+
+ if (to == STACK_POINTER_REGNUM)
+ diff = mn10300_frame_size ();
+
+ /* The difference between the argument pointer and the frame pointer
+ is the size of the callee register save area. */
+ if (from == ARG_POINTER_REGNUM)
+ {
+ diff += REG_SAVE_BYTES;
+ diff += 4 * fp_regs_to_save ();
+ }
+
+ return diff;
+}
+
+/* Worker function for TARGET_RETURN_IN_MEMORY. */
+
+static bool
+mn10300_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
+{
+ /* Return values > 8 bytes in length in memory. */
+ return (int_size_in_bytes (type) > 8
+ || int_size_in_bytes (type) == 0
+ || TYPE_MODE (type) == BLKmode);
+}
+
+/* Flush the argument registers to the stack for a stdarg function;
+ return the new argument pointer. */
+static rtx
+mn10300_builtin_saveregs (void)
+{
+ rtx offset, mem;
+ tree fntype = TREE_TYPE (current_function_decl);
+ int argadj = ((!stdarg_p (fntype))
+ ? UNITS_PER_WORD : 0);
+ alias_set_type set = get_varargs_alias_set ();
+
+ if (argadj)
+ offset = plus_constant (crtl->args.arg_offset_rtx, argadj);
+ else
+ offset = crtl->args.arg_offset_rtx;
+
+ mem = gen_rtx_MEM (SImode, crtl->args.internal_arg_pointer);
+ set_mem_alias_set (mem, set);
+ emit_move_insn (mem, gen_rtx_REG (SImode, 0));
+
+ mem = gen_rtx_MEM (SImode,
+ plus_constant (crtl->args.internal_arg_pointer, 4));
+ set_mem_alias_set (mem, set);
+ emit_move_insn (mem, gen_rtx_REG (SImode, 1));
+
+ return copy_to_reg (expand_binop (Pmode, add_optab,
+ crtl->args.internal_arg_pointer,
+ offset, 0, 0, OPTAB_LIB_WIDEN));
+}
+
+static void
+mn10300_va_start (tree valist, rtx nextarg)
+{
+ nextarg = expand_builtin_saveregs ();
+ std_expand_builtin_va_start (valist, nextarg);
+}
+
+/* Return true when a parameter should be passed by reference. */
+
+static bool
+mn10300_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
+ enum machine_mode mode, const_tree type,
+ bool named ATTRIBUTE_UNUSED)
+{
+ unsigned HOST_WIDE_INT size;
+
+ if (type)
+ size = int_size_in_bytes (type);
+ else
+ size = GET_MODE_SIZE (mode);
+
+ return (size > 8 || size == 0);
+}
+
+/* Return an RTX to represent where a value with mode MODE will be returned
+ from a function. If the result is NULL_RTX, the argument is pushed. */
+
+static rtx
+mn10300_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+ const_tree type, bool named ATTRIBUTE_UNUSED)
+{
+ rtx result = NULL_RTX;
+ int size;
+
+ /* We only support using 2 data registers as argument registers. */
+ int nregs = 2;
+
+ /* Figure out the size of the object to be passed. */
+ if (mode == BLKmode)
+ size = int_size_in_bytes (type);
+ else
+ size = GET_MODE_SIZE (mode);
+
+ cum->nbytes = (cum->nbytes + 3) & ~3;
+
+ /* Don't pass this arg via a register if all the argument registers
+ are used up. */
+ if (cum->nbytes > nregs * UNITS_PER_WORD)
+ return result;
+
+ /* Don't pass this arg via a register if it would be split between
+ registers and memory. */
+ if (type == NULL_TREE
+ && cum->nbytes + size > nregs * UNITS_PER_WORD)
+ return result;
+
+ switch (cum->nbytes / UNITS_PER_WORD)
+ {
+ case 0:
+ result = gen_rtx_REG (mode, FIRST_ARGUMENT_REGNUM);
+ break;
+ case 1:
+ result = gen_rtx_REG (mode, FIRST_ARGUMENT_REGNUM + 1);
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+/* Update the data in CUM to advance over an argument
+ of mode MODE and data type TYPE.
+ (TYPE is null for libcalls where that information may not be available.) */
+
+static void
+mn10300_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+ const_tree type, bool named ATTRIBUTE_UNUSED)
+{
+ cum->nbytes += (mode != BLKmode
+ ? (GET_MODE_SIZE (mode) + 3) & ~3
+ : (int_size_in_bytes (type) + 3) & ~3);
+}
+
+/* Return the number of bytes of registers to use for an argument passed
+ partially in registers and partially in memory. */
+
+static int
+mn10300_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+ tree type, bool named ATTRIBUTE_UNUSED)
+{
+ int size;
+
+ /* We only support using 2 data registers as argument registers. */
+ int nregs = 2;
+
+ /* Figure out the size of the object to be passed. */
+ if (mode == BLKmode)
+ size = int_size_in_bytes (type);
+ else
+ size = GET_MODE_SIZE (mode);
+
+ cum->nbytes = (cum->nbytes + 3) & ~3;
+
+ /* Don't pass this arg via a register if all the argument registers
+ are used up. */
+ if (cum->nbytes > nregs * UNITS_PER_WORD)
+ return 0;
+
+ if (cum->nbytes + size <= nregs * UNITS_PER_WORD)
+ return 0;
+
+ /* Don't pass this arg via a register if it would be split between
+ registers and memory. */
+ if (type == NULL_TREE
+ && cum->nbytes + size > nregs * UNITS_PER_WORD)
+ return 0;
+
+ return nregs * UNITS_PER_WORD - cum->nbytes;
+}
+
+/* Return the location of the function's value. This will be either
+ $d0 for integer functions, $a0 for pointers, or a PARALLEL of both
+ $d0 and $a0 if the -mreturn-pointer-on-do flag is set. Note that
+ we only return the PARALLEL for outgoing values; we do not want
+ callers relying on this extra copy. */
+
+static rtx
+mn10300_function_value (const_tree valtype,
+ const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
+ bool outgoing)
+{
+ rtx rv;
+ enum machine_mode mode = TYPE_MODE (valtype);
+
+ if (! POINTER_TYPE_P (valtype))
+ return gen_rtx_REG (mode, FIRST_DATA_REGNUM);
+ else if (! TARGET_PTR_A0D0 || ! outgoing
+ || cfun->returns_struct)
+ return gen_rtx_REG (mode, FIRST_ADDRESS_REGNUM);
+
+ rv = gen_rtx_PARALLEL (mode, rtvec_alloc (2));
+ XVECEXP (rv, 0, 0)
+ = gen_rtx_EXPR_LIST (VOIDmode,
+ gen_rtx_REG (mode, FIRST_ADDRESS_REGNUM),
+ GEN_INT (0));
+
+ XVECEXP (rv, 0, 1)
+ = gen_rtx_EXPR_LIST (VOIDmode,
+ gen_rtx_REG (mode, FIRST_DATA_REGNUM),
+ GEN_INT (0));
+ return rv;
+}
+
+/* Implements TARGET_LIBCALL_VALUE. */
+
+static rtx
+mn10300_libcall_value (enum machine_mode mode,
+ const_rtx fun ATTRIBUTE_UNUSED)
+{
+ return gen_rtx_REG (mode, FIRST_DATA_REGNUM);
+}
+
+/* Implements FUNCTION_VALUE_REGNO_P. */
+
+bool
+mn10300_function_value_regno_p (const unsigned int regno)
+{
+ return (regno == FIRST_DATA_REGNUM || regno == FIRST_ADDRESS_REGNUM);
+}
+
+/* Output an addition operation. */
+
+const char *
+mn10300_output_add (rtx operands[3], bool need_flags)
+{
+ rtx dest, src1, src2;
+ unsigned int dest_regnum, src1_regnum, src2_regnum;
+ enum reg_class src1_class, src2_class, dest_class;
+
+ dest = operands[0];
+ src1 = operands[1];
+ src2 = operands[2];
+
+ dest_regnum = true_regnum (dest);
+ src1_regnum = true_regnum (src1);
+
+ dest_class = REGNO_REG_CLASS (dest_regnum);
+ src1_class = REGNO_REG_CLASS (src1_regnum);
+
+ if (CONST_INT_P (src2))
+ {
+ gcc_assert (dest_regnum == src1_regnum);
+
+ if (src2 == const1_rtx && !need_flags)
+ return "inc %0";
+ if (INTVAL (src2) == 4 && !need_flags && dest_class != DATA_REGS)
+ return "inc4 %0";
+
+ gcc_assert (!need_flags || dest_class != SP_REGS);
+ return "add %2,%0";
+ }
+ else if (CONSTANT_P (src2))
+ return "add %2,%0";
+
+ src2_regnum = true_regnum (src2);
+ src2_class = REGNO_REG_CLASS (src2_regnum);
+
+ if (dest_regnum == src1_regnum)
+ return "add %2,%0";
+ if (dest_regnum == src2_regnum)
+ return "add %1,%0";
+
+ /* The rest of the cases are reg = reg+reg. For AM33, we can implement
+ this directly, as below, but when optimizing for space we can sometimes
+ do better by using a mov+add. For MN103, we claimed that we could
+ implement a three-operand add because the various move and add insns
+ change sizes across register classes, and we can often do better than
+ reload in choosing which operand to move. */
+ if (TARGET_AM33 && optimize_insn_for_speed_p ())
+ return "add %2,%1,%0";
+
+ /* Catch cases where no extended register was used. */
+ if (src1_class != EXTENDED_REGS
+ && src2_class != EXTENDED_REGS
+ && dest_class != EXTENDED_REGS)
+ {
+ /* We have to copy one of the sources into the destination, then
+ add the other source to the destination.
+
+ Carefully select which source to copy to the destination; a
+ naive implementation will waste a byte when the source classes
+ are different and the destination is an address register.
+ Selecting the lowest cost register copy will optimize this
+ sequence. */
+ if (src1_class == dest_class)
+ return "mov %1,%0\n\tadd %2,%0";
+ else
+ return "mov %2,%0\n\tadd %1,%0";
+ }
+
+ /* At least one register is an extended register. */
+
+ /* The three operand add instruction on the am33 is a win iff the
+ output register is an extended register, or if both source
+ registers are extended registers. */
+ if (dest_class == EXTENDED_REGS || src1_class == src2_class)
+ return "add %2,%1,%0";
+
+ /* It is better to copy one of the sources to the destination, then
+ perform a 2 address add. The destination in this case must be
+ an address or data register and one of the sources must be an
+ extended register and the remaining source must not be an extended
+ register.
+
+ The best code for this case is to copy the extended reg to the
+ destination, then emit a two address add. */
+ if (src1_class == EXTENDED_REGS)
+ return "mov %1,%0\n\tadd %2,%0";
+ else
+ return "mov %2,%0\n\tadd %1,%0";
+}
+
+/* Return 1 if X contains a symbolic expression. We know these
+ expressions will have one of a few well defined forms, so
+ we need only check those forms. */
+
+int
+mn10300_symbolic_operand (rtx op,
+ enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+ switch (GET_CODE (op))
+ {
+ case SYMBOL_REF:
+ case LABEL_REF:
+ return 1;
+ case CONST:
+ op = XEXP (op, 0);
+ return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
+ || GET_CODE (XEXP (op, 0)) == LABEL_REF)
+ && CONST_INT_P (XEXP (op, 1)));
+ default:
+ return 0;
+ }
+}
+
+/* Try machine dependent ways of modifying an illegitimate address
+ to be legitimate. If we find one, return the new valid address.
+ This macro is used in only one place: `memory_address' in explow.c.
+
+ OLDX is the address as it was before break_out_memory_refs was called.
+ In some cases it is useful to look at this to decide what needs to be done.
+
+ Normally it is always safe for this macro to do nothing. It exists to
+ recognize opportunities to optimize the output.
+
+ But on a few ports with segmented architectures and indexed addressing
+ (mn10300, hppa) it is used to rewrite certain problematical addresses. */
+
+static rtx
+mn10300_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+ if (flag_pic && ! mn10300_legitimate_pic_operand_p (x))
+ x = mn10300_legitimize_pic_address (oldx, NULL_RTX);
+
+ /* Uh-oh. We might have an address for x[n-100000]. This needs
+ special handling to avoid creating an indexed memory address
+ with x-100000 as the base. */
+ if (GET_CODE (x) == PLUS
+ && mn10300_symbolic_operand (XEXP (x, 1), VOIDmode))
+ {
+ /* Ugly. We modify things here so that the address offset specified
+ by the index expression is computed first, then added to x to form
+ the entire address. */
+
+ rtx regx1, regy1, regy2, y;
+
+ /* Strip off any CONST. */
+ y = XEXP (x, 1);
+ if (GET_CODE (y) == CONST)
+ y = XEXP (y, 0);
+
+ if (GET_CODE (y) == PLUS || GET_CODE (y) == MINUS)
+ {
+ regx1 = force_reg (Pmode, force_operand (XEXP (x, 0), 0));
+ regy1 = force_reg (Pmode, force_operand (XEXP (y, 0), 0));
+ regy2 = force_reg (Pmode, force_operand (XEXP (y, 1), 0));
+ regx1 = force_reg (Pmode,
+ gen_rtx_fmt_ee (GET_CODE (y), Pmode, regx1,
+ regy2));
+ return force_reg (Pmode, gen_rtx_PLUS (Pmode, regx1, regy1));
+ }
+ }
+ return x;
+}
+
+/* Convert a non-PIC address in `orig' to a PIC address using @GOT or
+ @GOTOFF in `reg'. */
+
+rtx
+mn10300_legitimize_pic_address (rtx orig, rtx reg)
+{
+ rtx x;
+
+ if (GET_CODE (orig) == LABEL_REF
+ || (GET_CODE (orig) == SYMBOL_REF
+ && (CONSTANT_POOL_ADDRESS_P (orig)
+ || ! MN10300_GLOBAL_P (orig))))
+ {
+ if (reg == NULL)
+ reg = gen_reg_rtx (Pmode);
+
+ x = gen_rtx_UNSPEC (SImode, gen_rtvec (1, orig), UNSPEC_GOTOFF);
+ x = gen_rtx_CONST (SImode, x);
+ emit_move_insn (reg, x);
+
+ x = emit_insn (gen_addsi3 (reg, reg, pic_offset_table_rtx));
+ }
+ else if (GET_CODE (orig) == SYMBOL_REF)
+ {
+ if (reg == NULL)
+ reg = gen_reg_rtx (Pmode);
+
+ x = gen_rtx_UNSPEC (SImode, gen_rtvec (1, orig), UNSPEC_GOT);
+ x = gen_rtx_CONST (SImode, x);
+ x = gen_rtx_PLUS (SImode, pic_offset_table_rtx, x);
+ x = gen_const_mem (SImode, x);
+
+ x = emit_move_insn (reg, x);
+ }
+ else
+ return orig;
+
+ set_unique_reg_note (x, REG_EQUAL, orig);
+ return reg;
+}
+
+/* Return zero if X references a SYMBOL_REF or LABEL_REF whose symbol
+ isn't protected by a PIC unspec; nonzero otherwise. */
+
+int
+mn10300_legitimate_pic_operand_p (rtx x)
+{
+ const char *fmt;
+ int i;
+
+ if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
+ return 0;
+
+ if (GET_CODE (x) == UNSPEC
+ && (XINT (x, 1) == UNSPEC_PIC
+ || XINT (x, 1) == UNSPEC_GOT
+ || XINT (x, 1) == UNSPEC_GOTOFF
+ || XINT (x, 1) == UNSPEC_PLT
+ || XINT (x, 1) == UNSPEC_GOTSYM_OFF))
+ return 1;
+
+ 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 (! mn10300_legitimate_pic_operand_p (XVECEXP (x, i, j)))
+ return 0;
+ }
+ else if (fmt[i] == 'e'
+ && ! mn10300_legitimate_pic_operand_p (XEXP (x, i)))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Return TRUE if the address X, taken from a (MEM:MODE X) rtx, is
+ legitimate, and FALSE otherwise.
+
+ On the mn10300, the value in the address register must be
+ in the same memory space/segment as the effective address.
+
+ This is problematical for reload since it does not understand
+ that base+index != index+base in a memory reference.
+
+ Note it is still possible to use reg+reg addressing modes,
+ it's just much more difficult. For a discussion of a possible
+ workaround and solution, see the comments in pa.c before the
+ function record_unscaled_index_insn_codes. */
+
+static bool
+mn10300_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
+{
+ rtx base, index;
+
+ if (CONSTANT_ADDRESS_P (x))
+ return !flag_pic || mn10300_legitimate_pic_operand_p (x);
+
+ if (RTX_OK_FOR_BASE_P (x, strict))
+ return true;
+
+ if (TARGET_AM33 && (mode == SImode || mode == SFmode || mode == HImode))
+ {
+ if (GET_CODE (x) == POST_INC)
+ return RTX_OK_FOR_BASE_P (XEXP (x, 0), strict);
+ if (GET_CODE (x) == POST_MODIFY)
+ return (RTX_OK_FOR_BASE_P (XEXP (x, 0), strict)
+ && CONSTANT_ADDRESS_P (XEXP (x, 1)));
+ }
+
+ if (GET_CODE (x) != PLUS)
+ return false;
+
+ base = XEXP (x, 0);
+ index = XEXP (x, 1);
+
+ if (!REG_P (base))
+ return false;
+ if (REG_P (index))
+ {
+ /* ??? Without AM33 generalized (Ri,Rn) addressing, reg+reg
+ addressing is hard to satisfy. */
+ if (!TARGET_AM33)
+ return false;
+
+ return (REGNO_GENERAL_P (REGNO (base), strict)
+ && REGNO_GENERAL_P (REGNO (index), strict));
+ }
+
+ if (!REGNO_STRICT_OK_FOR_BASE_P (REGNO (base), strict))
+ return false;
+
+ if (CONST_INT_P (index))
+ return IN_RANGE (INTVAL (index), -1 - 0x7fffffff, 0x7fffffff);
+
+ if (CONSTANT_ADDRESS_P (index))
+ return !flag_pic || mn10300_legitimate_pic_operand_p (index);
+
+ return false;
+}
+
+bool
+mn10300_regno_in_class_p (unsigned regno, int rclass, bool strict)
+{
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ {
+ if (!strict)
+ return true;
+ if (!reg_renumber)
+ return false;
+ regno = reg_renumber[regno];
+ if (regno == INVALID_REGNUM)
+ return false;
+ }
+ return TEST_HARD_REG_BIT (reg_class_contents[rclass], regno);
+}
+
+rtx
+mn10300_legitimize_reload_address (rtx x,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int opnum, int type,
+ int ind_levels ATTRIBUTE_UNUSED)
+{
+ bool any_change = false;
+
+ /* See above re disabling reg+reg addressing for MN103. */
+ if (!TARGET_AM33)
+ return NULL_RTX;
+
+ if (GET_CODE (x) != PLUS)
+ return NULL_RTX;
+
+ if (XEXP (x, 0) == stack_pointer_rtx)
+ {
+ push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
+ GENERAL_REGS, GET_MODE (x), VOIDmode, 0, 0,
+ opnum, (enum reload_type) type);
+ any_change = true;
+ }
+ if (XEXP (x, 1) == stack_pointer_rtx)
+ {
+ push_reload (XEXP (x, 1), NULL_RTX, &XEXP (x, 1), NULL,
+ GENERAL_REGS, GET_MODE (x), VOIDmode, 0, 0,
+ opnum, (enum reload_type) type);
+ any_change = true;
+ }
+
+ return any_change ? x : NULL_RTX;
+}
+
+/* Used by LEGITIMATE_CONSTANT_P(). Returns TRUE if X is a valid
+ constant. Note that some "constants" aren't valid, such as TLS
+ symbols and unconverted GOT-based references, so we eliminate
+ those here. */
+
+bool
+mn10300_legitimate_constant_p (rtx x)
+{
+ switch (GET_CODE (x))
+ {
+ case CONST:
+ x = XEXP (x, 0);
+
+ if (GET_CODE (x) == PLUS)
+ {
+ if (! CONST_INT_P (XEXP (x, 1)))
+ return false;
+ x = XEXP (x, 0);
+ }
+
+ /* Only some unspecs are valid as "constants". */
+ if (GET_CODE (x) == UNSPEC)
+ {
+ switch (XINT (x, 1))
+ {
+ case UNSPEC_PIC:
+ case UNSPEC_GOT:
+ case UNSPEC_GOTOFF:
+ case UNSPEC_PLT:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /* We must have drilled down to a symbol. */
+ if (! mn10300_symbolic_operand (x, Pmode))
+ return false;
+ break;
+
+ default:
+ break;
+ }
+
+ return true;
+}
+
+/* Undo pic address legitimization for the benefit of debug info. */
+
+static rtx
+mn10300_delegitimize_address (rtx orig_x)
+{
+ rtx x = orig_x, ret, addend = NULL;
+ bool need_mem;
+
+ if (MEM_P (x))
+ x = XEXP (x, 0);
+ if (GET_CODE (x) != PLUS || GET_MODE (x) != Pmode)
+ return orig_x;
+
+ if (XEXP (x, 0) == pic_offset_table_rtx)
+ ;
+ /* With the REG+REG addressing of AM33, var-tracking can re-assemble
+ some odd-looking "addresses" that were never valid in the first place.
+ We need to look harder to avoid warnings being emitted. */
+ else if (GET_CODE (XEXP (x, 0)) == PLUS)
+ {
+ rtx x0 = XEXP (x, 0);
+ rtx x00 = XEXP (x0, 0);
+ rtx x01 = XEXP (x0, 1);
+
+ if (x00 == pic_offset_table_rtx)
+ addend = x01;
+ else if (x01 == pic_offset_table_rtx)
+ addend = x00;
+ else
+ return orig_x;
+
+ }
+ else
+ return orig_x;
+ x = XEXP (x, 1);
+
+ if (GET_CODE (x) != CONST)
+ return orig_x;
+ x = XEXP (x, 0);
+ if (GET_CODE (x) != UNSPEC)
+ return orig_x;
+
+ ret = XVECEXP (x, 0, 0);
+ if (XINT (x, 1) == UNSPEC_GOTOFF)
+ need_mem = false;
+ else if (XINT (x, 1) == UNSPEC_GOT)
+ need_mem = true;
+ else
+ return orig_x;
+
+ gcc_assert (GET_CODE (ret) == SYMBOL_REF);
+ if (need_mem != MEM_P (orig_x))
+ return orig_x;
+ if (need_mem && addend)
+ return orig_x;
+ if (addend)
+ ret = gen_rtx_PLUS (Pmode, addend, ret);
+ return ret;
+}
+
+/* For addresses, costs are relative to "MOV (Rm),Rn". For AM33 this is
+ the 3-byte fully general instruction; for MN103 this is the 2-byte form
+ with an address register. */
+
+static int
+mn10300_address_cost (rtx x, bool speed)
+{
+ HOST_WIDE_INT i;
+ rtx base, index;
+
+ switch (GET_CODE (x))
+ {
+ case CONST:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ /* We assume all of these require a 32-bit constant, even though
+ some symbol and label references can be relaxed. */
+ return speed ? 1 : 4;
+
+ case REG:
+ case SUBREG:
+ case POST_INC:
+ return 0;
+
+ case POST_MODIFY:
+ /* Assume any symbolic offset is a 32-bit constant. */
+ i = (CONST_INT_P (XEXP (x, 1)) ? INTVAL (XEXP (x, 1)) : 0x12345678);
+ if (IN_RANGE (i, -128, 127))
+ return speed ? 0 : 1;
+ if (speed)
+ return 1;
+ if (IN_RANGE (i, -0x800000, 0x7fffff))
+ return 3;
+ return 4;
+
+ case PLUS:
+ base = XEXP (x, 0);
+ index = XEXP (x, 1);
+ if (register_operand (index, SImode))
+ {
+ /* Attempt to minimize the number of registers in the address.
+ This is similar to what other ports do. */
+ if (register_operand (base, SImode))
+ return 1;
+
+ base = XEXP (x, 1);
+ index = XEXP (x, 0);
+ }
+
+ /* Assume any symbolic offset is a 32-bit constant. */
+ i = (CONST_INT_P (XEXP (x, 1)) ? INTVAL (XEXP (x, 1)) : 0x12345678);
+ if (IN_RANGE (i, -128, 127))
+ return speed ? 0 : 1;
+ if (IN_RANGE (i, -32768, 32767))
+ return speed ? 0 : 2;
+ return speed ? 2 : 6;
+
+ default:
+ return rtx_cost (x, MEM, speed);
+ }
+}
+
+/* Implement the TARGET_REGISTER_MOVE_COST hook.
+
+ Recall that the base value of 2 is required by assumptions elsewhere
+ in the body of the compiler, and that cost 2 is special-cased as an
+ early exit from reload meaning no work is required. */
+
+static int
+mn10300_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
+ reg_class_t ifrom, reg_class_t ito)
+{
+ enum reg_class from = (enum reg_class) ifrom;
+ enum reg_class to = (enum reg_class) ito;
+ enum reg_class scratch, test;
+
+ /* Simplify the following code by unifying the fp register classes. */
+ if (to == FP_ACC_REGS)
+ to = FP_REGS;
+ if (from == FP_ACC_REGS)
+ from = FP_REGS;
+
+ /* Diagnose invalid moves by costing them as two moves. */
+
+ scratch = NO_REGS;
+ test = from;
+ if (to == SP_REGS)
+ scratch = (TARGET_AM33 ? GENERAL_REGS : ADDRESS_REGS);
+ else if (to == MDR_REGS)
+ scratch = DATA_REGS;
+ else if (to == FP_REGS && to != from)
+ scratch = GENERAL_REGS;
+ else
+ {
+ test = to;
+ if (from == SP_REGS)
+ scratch = (TARGET_AM33 ? GENERAL_REGS : ADDRESS_REGS);
+ else if (from == MDR_REGS)
+ scratch = DATA_REGS;
+ else if (from == FP_REGS && to != from)
+ scratch = GENERAL_REGS;
+ }
+ if (scratch != NO_REGS && !reg_class_subset_p (test, scratch))
+ return (mn10300_register_move_cost (VOIDmode, from, scratch)
+ + mn10300_register_move_cost (VOIDmode, scratch, to));
+
+ /* From here on, all we need consider are legal combinations. */
+
+ if (optimize_size)
+ {
+ /* The scale here is bytes * 2. */
+
+ if (from == to && (to == ADDRESS_REGS || to == DATA_REGS))
+ return 2;
+
+ if (from == SP_REGS)
+ return (to == ADDRESS_REGS ? 2 : 6);
+
+ /* For MN103, all remaining legal moves are two bytes. */
+ if (TARGET_AM33)
+ return 4;
+
+ if (to == SP_REGS)
+ return (from == ADDRESS_REGS ? 4 : 6);
+
+ if ((from == ADDRESS_REGS || from == DATA_REGS)
+ && (to == ADDRESS_REGS || to == DATA_REGS))
+ return 4;
+
+ if (to == EXTENDED_REGS)
+ return (to == from ? 6 : 4);
+
+ /* What's left are SP_REGS, FP_REGS, or combinations of the above. */
+ return 6;
+ }
+ else
+ {
+ /* The scale here is cycles * 2. */
+
+ if (to == FP_REGS)
+ return 8;
+ if (from == FP_REGS)
+ return 4;
+
+ /* All legal moves between integral registers are single cycle. */
+ return 2;
+ }
+}
+
+/* Implement the TARGET_MEMORY_MOVE_COST hook.
+
+ Given lack of the form of the address, this must be speed-relative,
+ though we should never be less expensive than a size-relative register
+ move cost above. This is not a problem. */
+
+static int
+mn10300_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
+ reg_class_t iclass, bool in ATTRIBUTE_UNUSED)
+{
+ enum reg_class rclass = (enum reg_class) iclass;
+
+ if (rclass == FP_REGS)
+ return 8;
+ return 6;
+}
+
+/* Implement the TARGET_RTX_COSTS hook.
+
+ Speed-relative costs are relative to COSTS_N_INSNS, which is intended
+ to represent cycles. Size-relative costs are in bytes. */
+
+static bool
+mn10300_rtx_costs (rtx x, int code, int outer_code, int *ptotal, bool speed)
+{
+ /* This value is used for SYMBOL_REF etc where we want to pretend
+ we have a full 32-bit constant. */
+ HOST_WIDE_INT i = 0x12345678;
+ int total;
+
+ switch (code)
+ {
+ case CONST_INT:
+ i = INTVAL (x);
+ do_int_costs:
+ if (speed)
+ {
+ if (outer_code == SET)
+ {
+ /* 16-bit integer loads have latency 1, 32-bit loads 2. */
+ if (IN_RANGE (i, -32768, 32767))
+ total = COSTS_N_INSNS (1);
+ else
+ total = COSTS_N_INSNS (2);
+ }
+ else
+ {
+ /* 16-bit integer operands don't affect latency;
+ 24-bit and 32-bit operands add a cycle. */
+ if (IN_RANGE (i, -32768, 32767))
+ total = 0;
+ else
+ total = COSTS_N_INSNS (1);
+ }
+ }
+ else
+ {
+ if (outer_code == SET)
+ {
+ if (i == 0)
+ total = 1;
+ else if (IN_RANGE (i, -128, 127))
+ total = 2;
+ else if (IN_RANGE (i, -32768, 32767))
+ total = 3;
+ else
+ total = 6;
+ }
+ else
+ {
+ /* Reference here is ADD An,Dn, vs ADD imm,Dn. */
+ if (IN_RANGE (i, -128, 127))
+ total = 0;
+ else if (IN_RANGE (i, -32768, 32767))
+ total = 2;
+ else if (TARGET_AM33 && IN_RANGE (i, -0x01000000, 0x00ffffff))
+ total = 3;
+ else
+ total = 4;
+ }
+ }
+ goto alldone;
+
+ case CONST:
+ case LABEL_REF:
+ case SYMBOL_REF:
+ case CONST_DOUBLE:
+ /* We assume all of these require a 32-bit constant, even though
+ some symbol and label references can be relaxed. */
+ goto do_int_costs;
+
+ case UNSPEC:
+ switch (XINT (x, 1))
+ {
+ case UNSPEC_PIC:
+ case UNSPEC_GOT:
+ case UNSPEC_GOTOFF:
+ case UNSPEC_PLT:
+ case UNSPEC_GOTSYM_OFF:
+ /* The PIC unspecs also resolve to a 32-bit constant. */
+ goto do_int_costs;
+
+ default:
+ /* Assume any non-listed unspec is some sort of arithmetic. */
+ goto do_arith_costs;
+ }
+
+ case PLUS:
+ /* Notice the size difference of INC and INC4. */
+ if (!speed && outer_code == SET && CONST_INT_P (XEXP (x, 1)))
+ {
+ i = INTVAL (XEXP (x, 1));
+ if (i == 1 || i == 4)
+ {
+ total = 1 + rtx_cost (XEXP (x, 0), PLUS, speed);
+ goto alldone;
+ }
+ }
+ goto do_arith_costs;
+
+ case MINUS:
+ case AND:
+ case IOR:
+ case XOR:
+ case NOT:
+ case NEG:
+ case ZERO_EXTEND:
+ case SIGN_EXTEND:
+ case COMPARE:
+ case BSWAP:
+ case CLZ:
+ do_arith_costs:
+ total = (speed ? COSTS_N_INSNS (1) : 2);
+ break;
+
+ case ASHIFT:
+ /* Notice the size difference of ASL2 and variants. */
+ if (!speed && CONST_INT_P (XEXP (x, 1)))
+ switch (INTVAL (XEXP (x, 1)))
+ {
+ case 1:
+ case 2:
+ total = 1;
+ goto alldone;
+ case 3:
+ case 4:
+ total = 2;
+ goto alldone;
+ }
+ /* FALLTHRU */
+
+ case ASHIFTRT:
+ case LSHIFTRT:
+ total = (speed ? COSTS_N_INSNS (1) : 3);
+ goto alldone;
+
+ case MULT:
+ total = (speed ? COSTS_N_INSNS (3) : 2);
+ break;
+
+ case DIV:
+ case UDIV:
+ case MOD:
+ case UMOD:
+ total = (speed ? COSTS_N_INSNS (39)
+ /* Include space to load+retrieve MDR. */
+ : code == MOD || code == UMOD ? 6 : 4);
+ break;
+
+ case MEM:
+ total = mn10300_address_cost (XEXP (x, 0), speed);
+ if (speed)
+ total = COSTS_N_INSNS (2 + total);
+ goto alldone;
+
+ default:
+ /* Probably not implemented. Assume external call. */
+ total = (speed ? COSTS_N_INSNS (10) : 7);
+ break;
+ }
+
+ *ptotal = total;
+ return false;
+
+ alldone:
+ *ptotal = total;
+ return true;
+}
+
+/* If using PIC, mark a SYMBOL_REF for a non-global symbol so that we
+ may access it using GOTOFF instead of GOT. */
+
+static void
+mn10300_encode_section_info (tree decl, rtx rtl, int first)
+{
+ rtx symbol;
+
+ default_encode_section_info (decl, rtl, first);
+
+ if (! MEM_P (rtl))
+ return;
+
+ symbol = XEXP (rtl, 0);
+ if (GET_CODE (symbol) != SYMBOL_REF)
+ return;
+
+ if (flag_pic)
+ SYMBOL_REF_FLAG (symbol) = (*targetm.binds_local_p) (decl);
+}
+
+/* Dispatch tables on the mn10300 are extremely expensive in terms of code
+ and readonly data size. So we crank up the case threshold value to
+ encourage a series of if/else comparisons to implement many small switch
+ statements. In theory, this value could be increased much more if we
+ were solely optimizing for space, but we keep it "reasonable" to avoid
+ serious code efficiency lossage. */
+
+static unsigned int
+mn10300_case_values_threshold (void)
+{
+ return 6;
+}
+
+/* Worker function for TARGET_TRAMPOLINE_INIT. */
+
+static void
+mn10300_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
+{
+ rtx mem, disp, fnaddr = XEXP (DECL_RTL (fndecl), 0);
+
+ /* This is a strict alignment target, which means that we play
+ some games to make sure that the locations at which we need
+ to store <chain> and <disp> wind up at aligned addresses.
+
+ 0x28 0x00 add 0,d0
+ 0xfc 0xdd mov chain,a1
+ <chain>
+ 0xf8 0xed 0x00 btst 0,d1
+ 0xdc jmp fnaddr
+ <disp>
+
+ Note that the two extra insns are effectively nops; they
+ clobber the flags but do not affect the contents of D0 or D1. */
+
+ disp = expand_binop (SImode, sub_optab, fnaddr,
+ plus_constant (XEXP (m_tramp, 0), 11),
+ NULL_RTX, 1, OPTAB_DIRECT);
+
+ mem = adjust_address (m_tramp, SImode, 0);
+ emit_move_insn (mem, gen_int_mode (0xddfc0028, SImode));
+ mem = adjust_address (m_tramp, SImode, 4);
+ emit_move_insn (mem, chain_value);
+ mem = adjust_address (m_tramp, SImode, 8);
+ emit_move_insn (mem, gen_int_mode (0xdc00edf8, SImode));
+ mem = adjust_address (m_tramp, SImode, 12);
+ emit_move_insn (mem, disp);
+}
+
+/* Output the assembler code for a C++ thunk function.
+ THUNK_DECL is the declaration for the thunk function itself, FUNCTION
+ is the decl for the target function. DELTA is an immediate constant
+ offset to be added to the THIS parameter. If VCALL_OFFSET is nonzero
+ the word at the adjusted address *(*THIS' + VCALL_OFFSET) should be
+ additionally added to THIS. Finally jump to the entry point of
+ FUNCTION. */
+
+static void
+mn10300_asm_output_mi_thunk (FILE * file,
+ tree thunk_fndecl ATTRIBUTE_UNUSED,
+ HOST_WIDE_INT delta,
+ HOST_WIDE_INT vcall_offset,
+ tree function)
+{
+ const char * _this;
+
+ /* Get the register holding the THIS parameter. Handle the case
+ where there is a hidden first argument for a returned structure. */
+ if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
+ _this = reg_names [FIRST_ARGUMENT_REGNUM + 1];
+ else
+ _this = reg_names [FIRST_ARGUMENT_REGNUM];
+
+ fprintf (file, "\t%s Thunk Entry Point:\n", ASM_COMMENT_START);
+
+ if (delta)
+ fprintf (file, "\tadd %d, %s\n", (int) delta, _this);
+
+ if (vcall_offset)
+ {
+ const char * scratch = reg_names [FIRST_ADDRESS_REGNUM + 1];
+
+ fprintf (file, "\tmov %s, %s\n", _this, scratch);
+ fprintf (file, "\tmov (%s), %s\n", scratch, scratch);
+ fprintf (file, "\tadd %d, %s\n", (int) vcall_offset, scratch);
+ fprintf (file, "\tmov (%s), %s\n", scratch, scratch);
+ fprintf (file, "\tadd %s, %s\n", scratch, _this);
+ }
+
+ fputs ("\tjmp ", file);
+ assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0));
+ putc ('\n', file);
+}
+
+/* Return true if mn10300_output_mi_thunk would be able to output the
+ assembler code for the thunk function specified by the arguments
+ it is passed, and false otherwise. */
+
+static bool
+mn10300_can_output_mi_thunk (const_tree thunk_fndecl ATTRIBUTE_UNUSED,
+ HOST_WIDE_INT delta ATTRIBUTE_UNUSED,
+ HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
+ const_tree function ATTRIBUTE_UNUSED)
+{
+ return true;
+}
+
+bool
+mn10300_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
+{
+ if (REGNO_REG_CLASS (regno) == FP_REGS
+ || REGNO_REG_CLASS (regno) == FP_ACC_REGS)
+ /* Do not store integer values in FP registers. */
+ return GET_MODE_CLASS (mode) == MODE_FLOAT && ((regno & 1) == 0);
+
+ if (((regno) & 1) == 0 || GET_MODE_SIZE (mode) == 4)
+ return true;
+
+ if (REGNO_REG_CLASS (regno) == DATA_REGS
+ || (TARGET_AM33 && REGNO_REG_CLASS (regno) == ADDRESS_REGS)
+ || REGNO_REG_CLASS (regno) == EXTENDED_REGS)
+ return GET_MODE_SIZE (mode) <= 4;
+
+ return false;
+}
+
+bool
+mn10300_modes_tieable (enum machine_mode mode1, enum machine_mode mode2)
+{
+ if (GET_MODE_CLASS (mode1) == MODE_FLOAT
+ && GET_MODE_CLASS (mode2) != MODE_FLOAT)
+ return false;
+
+ if (GET_MODE_CLASS (mode2) == MODE_FLOAT
+ && GET_MODE_CLASS (mode1) != MODE_FLOAT)
+ return false;
+
+ if (TARGET_AM33
+ || mode1 == mode2
+ || (GET_MODE_SIZE (mode1) <= 4 && GET_MODE_SIZE (mode2) <= 4))
+ return true;
+
+ return false;
+}
+
+static int
+cc_flags_for_mode (enum machine_mode mode)
+{
+ switch (mode)
+ {
+ case CCmode:
+ return CC_FLAG_Z | CC_FLAG_N | CC_FLAG_C | CC_FLAG_V;
+ case CCZNCmode:
+ return CC_FLAG_Z | CC_FLAG_N | CC_FLAG_C;
+ case CCZNmode:
+ return CC_FLAG_Z | CC_FLAG_N;
+ case CC_FLOATmode:
+ return -1;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+static int
+cc_flags_for_code (enum rtx_code code)
+{
+ switch (code)
+ {
+ case EQ: /* Z */
+ case NE: /* ~Z */
+ return CC_FLAG_Z;
+
+ case LT: /* N */
+ case GE: /* ~N */
+ return CC_FLAG_N;
+ break;
+
+ case GT: /* ~(Z|(N^V)) */
+ case LE: /* Z|(N^V) */
+ return CC_FLAG_Z | CC_FLAG_N | CC_FLAG_V;
+
+ case GEU: /* ~C */
+ case LTU: /* C */
+ return CC_FLAG_C;
+
+ case GTU: /* ~(C | Z) */
+ case LEU: /* C | Z */
+ return CC_FLAG_Z | CC_FLAG_C;
+
+ case ORDERED:
+ case UNORDERED:
+ case LTGT:
+ case UNEQ:
+ case UNGE:
+ case UNGT:
+ case UNLE:
+ case UNLT:
+ return -1;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+enum machine_mode
+mn10300_select_cc_mode (enum rtx_code code, rtx x, rtx y ATTRIBUTE_UNUSED)
+{
+ int req;
+
+ if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
+ return CC_FLOATmode;
+
+ req = cc_flags_for_code (code);
+
+ if (req & CC_FLAG_V)
+ return CCmode;
+ if (req & CC_FLAG_C)
+ return CCZNCmode;
+ return CCZNmode;
+}
+
+static inline bool
+is_load_insn (rtx insn)
+{
+ if (GET_CODE (PATTERN (insn)) != SET)
+ return false;
+
+ return MEM_P (SET_SRC (PATTERN (insn)));
+}
+
+static inline bool
+is_store_insn (rtx insn)
+{
+ if (GET_CODE (PATTERN (insn)) != SET)
+ return false;
+
+ return MEM_P (SET_DEST (PATTERN (insn)));
+}
+
+/* Update scheduling costs for situations that cannot be
+ described using the attributes and DFA machinery.
+ DEP is the insn being scheduled.
+ INSN is the previous insn.
+ COST is the current cycle cost for DEP. */
+
+static int
+mn10300_adjust_sched_cost (rtx insn, rtx link, rtx dep, int cost)
+{
+ int timings = get_attr_timings (insn);
+
+ if (!TARGET_AM33)
+ return 1;
+
+ if (GET_CODE (insn) == PARALLEL)
+ insn = XVECEXP (insn, 0, 0);
+
+ if (GET_CODE (dep) == PARALLEL)
+ dep = XVECEXP (dep, 0, 0);
+
+ /* For the AM34 a load instruction that follows a
+ store instruction incurs an extra cycle of delay. */
+ if (mn10300_tune_cpu == PROCESSOR_AM34
+ && is_load_insn (dep)
+ && is_store_insn (insn))
+ cost += 1;
+
+ /* For the AM34 a non-store, non-branch FPU insn that follows
+ another FPU insn incurs a one cycle throughput increase. */
+ else if (mn10300_tune_cpu == PROCESSOR_AM34
+ && ! is_store_insn (insn)
+ && ! JUMP_P (insn)
+ && GET_CODE (PATTERN (dep)) == SET
+ && GET_CODE (PATTERN (insn)) == SET
+ && GET_MODE_CLASS (GET_MODE (SET_SRC (PATTERN (dep)))) == MODE_FLOAT
+ && GET_MODE_CLASS (GET_MODE (SET_SRC (PATTERN (insn)))) == MODE_FLOAT)
+ cost += 1;
+
+ /* Resolve the conflict described in section 1-7-4 of
+ Chapter 3 of the MN103E Series Instruction Manual
+ where it says:
+
+ "When the preceeding instruction is a CPU load or
+ store instruction, a following FPU instruction
+ cannot be executed until the CPU completes the
+ latency period even though there are no register
+ or flag dependencies between them." */
+
+ /* Only the AM33-2 (and later) CPUs have FPU instructions. */
+ if (! TARGET_AM33_2)
+ return cost;
+
+ /* If a data dependence already exists then the cost is correct. */
+ if (REG_NOTE_KIND (link) == 0)
+ return cost;
+
+ /* Check that the instruction about to scheduled is an FPU instruction. */
+ if (GET_CODE (PATTERN (dep)) != SET)
+ return cost;
+
+ if (GET_MODE_CLASS (GET_MODE (SET_SRC (PATTERN (dep)))) != MODE_FLOAT)
+ return cost;
+
+ /* Now check to see if the previous instruction is a load or store. */
+ if (! is_load_insn (insn) && ! is_store_insn (insn))
+ return cost;
+
+ /* XXX: Verify: The text of 1-7-4 implies that the restriction
+ only applies when an INTEGER load/store preceeds an FPU
+ instruction, but is this true ? For now we assume that it is. */
+ if (GET_MODE_CLASS (GET_MODE (SET_SRC (PATTERN (insn)))) != MODE_INT)
+ return cost;
+
+ /* Extract the latency value from the timings attribute. */
+ return timings < 100 ? (timings % 10) : (timings % 100);
+}
+
+static void
+mn10300_conditional_register_usage (void)
+{
+ unsigned int i;
+
+ if (!TARGET_AM33)
+ {
+ for (i = FIRST_EXTENDED_REGNUM;
+ i <= LAST_EXTENDED_REGNUM; i++)
+ fixed_regs[i] = call_used_regs[i] = 1;
+ }
+ if (!TARGET_AM33_2)
+ {
+ for (i = FIRST_FP_REGNUM;
+ i <= LAST_FP_REGNUM; i++)
+ fixed_regs[i] = call_used_regs[i] = 1;
+ }
+ if (flag_pic)
+ fixed_regs[PIC_OFFSET_TABLE_REGNUM] =
+ call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
+}
+
+/* Worker function for TARGET_MD_ASM_CLOBBERS.
+ We do this in the mn10300 backend to maintain source compatibility
+ with the old cc0-based compiler. */
+
+static tree
+mn10300_md_asm_clobbers (tree outputs ATTRIBUTE_UNUSED,
+ tree inputs ATTRIBUTE_UNUSED,
+ tree clobbers)
+{
+ clobbers = tree_cons (NULL_TREE, build_string (5, "EPSW"),
+ clobbers);
+ return clobbers;
+}
+
+/* A helper function for splitting cbranch patterns after reload. */
+
+void
+mn10300_split_cbranch (enum machine_mode cmp_mode, rtx cmp_op, rtx label_ref)
+{
+ rtx flags, x;
+
+ flags = gen_rtx_REG (cmp_mode, CC_REG);
+ x = gen_rtx_COMPARE (cmp_mode, XEXP (cmp_op, 0), XEXP (cmp_op, 1));
+ x = gen_rtx_SET (VOIDmode, flags, x);
+ emit_insn (x);
+
+ x = gen_rtx_fmt_ee (GET_CODE (cmp_op), VOIDmode, flags, const0_rtx);
+ x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, label_ref, pc_rtx);
+ x = gen_rtx_SET (VOIDmode, pc_rtx, x);
+ emit_jump_insn (x);
+}
+
+/* A helper function for matching parallels that set the flags. */
+
+bool
+mn10300_match_ccmode (rtx insn, enum machine_mode cc_mode)
+{
+ rtx op1, flags;
+ enum machine_mode flags_mode;
+
+ gcc_checking_assert (XVECLEN (PATTERN (insn), 0) == 2);
+
+ op1 = XVECEXP (PATTERN (insn), 0, 1);
+ gcc_checking_assert (GET_CODE (SET_SRC (op1)) == COMPARE);
+
+ flags = SET_DEST (op1);
+ flags_mode = GET_MODE (flags);
+
+ if (GET_MODE (SET_SRC (op1)) != flags_mode)
+ return false;
+ if (GET_MODE_CLASS (flags_mode) != MODE_CC)
+ return false;
+
+ /* Ensure that the mode of FLAGS is compatible with CC_MODE. */
+ if (cc_flags_for_mode (flags_mode) & ~cc_flags_for_mode (cc_mode))
+ return false;
+
+ return true;
+}
+
+int
+mn10300_split_and_operand_count (rtx op)
+{
+ HOST_WIDE_INT val = INTVAL (op);
+ int count;
+
+ if (val < 0)
+ {
+ /* High bit is set, look for bits clear at the bottom. */
+ count = exact_log2 (-val);
+ if (count < 0)
+ return 0;
+ /* This is only size win if we can use the asl2 insn. Otherwise we
+ would be replacing 1 6-byte insn with 2 3-byte insns. */
+ if (count > (optimize_insn_for_speed_p () ? 2 : 4))
+ return 0;
+ return -count;
+ }
+ else
+ {
+ /* High bit is clear, look for bits set at the bottom. */
+ count = exact_log2 (val + 1);
+ count = 32 - count;
+ /* Again, this is only a size win with asl2. */
+ if (count > (optimize_insn_for_speed_p () ? 2 : 4))
+ return 0;
+ return -count;
+ }
+}
+
+struct liw_data
+{
+ enum attr_liw slot;
+ enum attr_liw_op op;
+ rtx dest;
+ rtx src;
+};
+
+/* Decide if the given insn is a candidate for LIW bundling. If it is then
+ extract the operands and LIW attributes from the insn and use them to fill
+ in the liw_data structure. Return true upon success or false if the insn
+ cannot be bundled. */
+
+static bool
+extract_bundle (rtx insn, struct liw_data * pdata)
+{
+ bool allow_consts = true;
+ rtx p,s;
+
+ gcc_assert (pdata != NULL);
+
+ if (insn == NULL_RTX)
+ return false;
+ /* Make sure that we are dealing with a simple SET insn. */
+ p = single_set (insn);
+ if (p == NULL_RTX)
+ return false;
+
+ /* Make sure that it could go into one of the LIW pipelines. */
+ pdata->slot = get_attr_liw (insn);
+ if (pdata->slot == LIW_BOTH)
+ return false;
+
+ pdata->op = get_attr_liw_op (insn);
+
+ s = SET_SRC (p);
+
+ switch (pdata->op)
+ {
+ case LIW_OP_MOV:
+ pdata->dest = SET_DEST (p);
+ pdata->src = SET_SRC (p);
+ break;
+ case LIW_OP_CMP:
+ pdata->dest = XEXP (SET_SRC (p), 0);
+ pdata->src = XEXP (SET_SRC (p), 1);
+ break;
+ case LIW_OP_NONE:
+ return false;
+ case LIW_OP_AND:
+ case LIW_OP_OR:
+ case LIW_OP_XOR:
+ /* The AND, OR and XOR long instruction words only accept register arguments. */
+ allow_consts = false;
+ /* Fall through. */
+ default:
+ pdata->dest = SET_DEST (p);
+ pdata->src = XEXP (SET_SRC (p), 1);
+ break;
+ }
+
+ if (! REG_P (pdata->dest))
+ return false;
+
+ if (REG_P (pdata->src))
+ return true;
+
+ return allow_consts && satisfies_constraint_O (pdata->src);
+}
+
+/* Make sure that it is OK to execute LIW1 and LIW2 in parallel. GCC generated
+ the instructions with the assumption that LIW1 would be executed before LIW2
+ so we must check for overlaps between their sources and destinations. */
+
+static bool
+check_liw_constraints (struct liw_data * pliw1, struct liw_data * pliw2)
+{
+ /* Check for slot conflicts. */
+ if (pliw2->slot == pliw1->slot && pliw1->slot != LIW_EITHER)
+ return false;
+
+ /* If either operation is a compare, then "dest" is really an input; the real
+ destination is CC_REG. So these instructions need different checks. */
+
+ /* Changing "CMP ; OP" into "CMP | OP" is OK because the comparison will
+ check its values prior to any changes made by OP. */
+ if (pliw1->op == LIW_OP_CMP)
+ {
+ /* Two sequential comparisons means dead code, which ought to
+ have been eliminated given that bundling only happens with
+ optimization. We cannot bundle them in any case. */
+ gcc_assert (pliw1->op != pliw2->op);
+ return true;
+ }
+
+ /* Changing "OP ; CMP" into "OP | CMP" does not work if the value being compared
+ is the destination of OP, as the CMP will look at the old value, not the new
+ one. */
+ if (pliw2->op == LIW_OP_CMP)
+ {
+ if (REGNO (pliw2->dest) == REGNO (pliw1->dest))
+ return false;
+
+ if (REG_P (pliw2->src))
+ return REGNO (pliw2->src) != REGNO (pliw1->dest);
+
+ return true;
+ }
+
+ /* Changing "OP1 ; OP2" into "OP1 | OP2" does not work if they both write to the
+ same destination register. */
+ if (REGNO (pliw2->dest) == REGNO (pliw1->dest))
+ return false;
+
+ /* Changing "OP1 ; OP2" into "OP1 | OP2" generally does not work if the destination
+ of OP1 is the source of OP2. The exception is when OP1 is a MOVE instruction when
+ we can replace the source in OP2 with the source of OP1. */
+ if (REG_P (pliw2->src) && REGNO (pliw2->src) == REGNO (pliw1->dest))
+ {
+ if (pliw1->op == LIW_OP_MOV && REG_P (pliw1->src))
+ {
+ if (! REG_P (pliw1->src)
+ && (pliw2->op == LIW_OP_AND
+ || pliw2->op == LIW_OP_OR
+ || pliw2->op == LIW_OP_XOR))
+ return false;
+
+ pliw2->src = pliw1->src;
+ return true;
+ }
+ return false;
+ }
+
+ /* Everything else is OK. */
+ return true;
+}
+
+/* Combine pairs of insns into LIW bundles. */
+
+static void
+mn10300_bundle_liw (void)
+{
+ rtx r;
+
+ for (r = get_insns (); r != NULL_RTX; r = next_nonnote_nondebug_insn (r))
+ {
+ rtx insn1, insn2;
+ struct liw_data liw1, liw2;
+
+ insn1 = r;
+ if (! extract_bundle (insn1, & liw1))
+ continue;
+
+ insn2 = next_nonnote_nondebug_insn (insn1);
+ if (! extract_bundle (insn2, & liw2))
+ continue;
+
+ /* Check for source/destination overlap. */
+ if (! check_liw_constraints (& liw1, & liw2))
+ continue;
+
+ if (liw1.slot == LIW_OP2 || liw2.slot == LIW_OP1)
+ {
+ struct liw_data temp;
+
+ temp = liw1;
+ liw1 = liw2;
+ liw2 = temp;
+ }
+
+ delete_insn (insn2);
+
+ if (liw1.op == LIW_OP_CMP)
+ insn2 = gen_cmp_liw (liw2.dest, liw2.src, liw1.dest, liw1.src,
+ GEN_INT (liw2.op));
+ else if (liw2.op == LIW_OP_CMP)
+ insn2 = gen_liw_cmp (liw1.dest, liw1.src, liw2.dest, liw2.src,
+ GEN_INT (liw1.op));
+ else
+ insn2 = gen_liw (liw1.dest, liw2.dest, liw1.src, liw2.src,
+ GEN_INT (liw1.op), GEN_INT (liw2.op));
+
+ insn2 = emit_insn_after (insn2, insn1);
+ delete_insn (insn1);
+ r = insn2;
+ }
+}
+
+static void
+mn10300_reorg (void)
+{
+ if (TARGET_AM33)
+ {
+ if (TARGET_ALLOW_LIW)
+ mn10300_bundle_liw ();
+ }
+}
+
+/* Initialize the GCC target structure. */
+
+#undef TARGET_MACHINE_DEPENDENT_REORG
+#define TARGET_MACHINE_DEPENDENT_REORG mn10300_reorg
+
+#undef TARGET_EXCEPT_UNWIND_INFO
+#define TARGET_EXCEPT_UNWIND_INFO sjlj_except_unwind_info
+
+#undef TARGET_ASM_ALIGNED_HI_OP
+#define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
+
+#undef TARGET_LEGITIMIZE_ADDRESS
+#define TARGET_LEGITIMIZE_ADDRESS mn10300_legitimize_address
+
+#undef TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST mn10300_address_cost
+#undef TARGET_REGISTER_MOVE_COST
+#define TARGET_REGISTER_MOVE_COST mn10300_register_move_cost
+#undef TARGET_MEMORY_MOVE_COST
+#define TARGET_MEMORY_MOVE_COST mn10300_memory_move_cost
+#undef TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS mn10300_rtx_costs
+
+#undef TARGET_ASM_FILE_START
+#define TARGET_ASM_FILE_START mn10300_file_start
+#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
+#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
+
+#undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA
+#define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA mn10300_asm_output_addr_const_extra
+
+#undef TARGET_DEFAULT_TARGET_FLAGS
+#define TARGET_DEFAULT_TARGET_FLAGS MASK_MULT_BUG | MASK_PTR_A0D0 | MASK_ALLOW_LIW
+#undef TARGET_HANDLE_OPTION
+#define TARGET_HANDLE_OPTION mn10300_handle_option
+#undef TARGET_OPTION_OVERRIDE
+#define TARGET_OPTION_OVERRIDE mn10300_option_override
+#undef TARGET_OPTION_OPTIMIZATION_TABLE
+#define TARGET_OPTION_OPTIMIZATION_TABLE mn10300_option_optimization_table
+
+#undef TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO mn10300_encode_section_info
+
+#undef TARGET_PROMOTE_PROTOTYPES
+#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY mn10300_return_in_memory
+#undef TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE mn10300_pass_by_reference
+#undef TARGET_CALLEE_COPIES
+#define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true
+#undef TARGET_ARG_PARTIAL_BYTES
+#define TARGET_ARG_PARTIAL_BYTES mn10300_arg_partial_bytes
+#undef TARGET_FUNCTION_ARG
+#define TARGET_FUNCTION_ARG mn10300_function_arg
+#undef TARGET_FUNCTION_ARG_ADVANCE
+#define TARGET_FUNCTION_ARG_ADVANCE mn10300_function_arg_advance
+
+#undef TARGET_EXPAND_BUILTIN_SAVEREGS
+#define TARGET_EXPAND_BUILTIN_SAVEREGS mn10300_builtin_saveregs
+#undef TARGET_EXPAND_BUILTIN_VA_START
+#define TARGET_EXPAND_BUILTIN_VA_START mn10300_va_start
+
+#undef TARGET_CASE_VALUES_THRESHOLD
+#define TARGET_CASE_VALUES_THRESHOLD mn10300_case_values_threshold
+
+#undef TARGET_LEGITIMATE_ADDRESS_P
+#define TARGET_LEGITIMATE_ADDRESS_P mn10300_legitimate_address_p
+#undef TARGET_DELEGITIMIZE_ADDRESS
+#define TARGET_DELEGITIMIZE_ADDRESS mn10300_delegitimize_address
+
+#undef TARGET_PREFERRED_RELOAD_CLASS
+#define TARGET_PREFERRED_RELOAD_CLASS mn10300_preferred_reload_class
+#undef TARGET_PREFERRED_OUTPUT_RELOAD_CLASS
+#define TARGET_PREFERRED_OUTPUT_RELOAD_CLASS \
+ mn10300_preferred_output_reload_class
+#undef TARGET_SECONDARY_RELOAD
+#define TARGET_SECONDARY_RELOAD mn10300_secondary_reload
+
+#undef TARGET_TRAMPOLINE_INIT
+#define TARGET_TRAMPOLINE_INIT mn10300_trampoline_init
+
+#undef TARGET_FUNCTION_VALUE
+#define TARGET_FUNCTION_VALUE mn10300_function_value
+#undef TARGET_LIBCALL_VALUE
+#define TARGET_LIBCALL_VALUE mn10300_libcall_value
+
+#undef TARGET_ASM_OUTPUT_MI_THUNK
+#define TARGET_ASM_OUTPUT_MI_THUNK mn10300_asm_output_mi_thunk
+#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
+#define TARGET_ASM_CAN_OUTPUT_MI_THUNK mn10300_can_output_mi_thunk
+
+#undef TARGET_SCHED_ADJUST_COST
+#define TARGET_SCHED_ADJUST_COST mn10300_adjust_sched_cost
+
+#undef TARGET_CONDITIONAL_REGISTER_USAGE
+#define TARGET_CONDITIONAL_REGISTER_USAGE mn10300_conditional_register_usage
+
+#undef TARGET_MD_ASM_CLOBBERS
+#define TARGET_MD_ASM_CLOBBERS mn10300_md_asm_clobbers
+
+#undef TARGET_FLAGS_REGNUM
+#define TARGET_FLAGS_REGNUM CC_REG
+
+struct gcc_target targetm = TARGET_INITIALIZER;
diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h
new file mode 100644
index 000000000..2e97ca4ff
--- /dev/null
+++ b/gcc/config/mn10300/mn10300.h
@@ -0,0 +1,766 @@
+/* Definitions of target machine for GNU compiler.
+ Matsushita MN10300 series
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+ Contributed by Jeff Law (law@cygnus.com).
+
+ 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/>. */
+
+#undef ASM_SPEC
+#undef LIB_SPEC
+#undef ENDFILE_SPEC
+#undef LINK_SPEC
+#define LINK_SPEC "%{mrelax:--relax}"
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "%{!mno-crt0:%{!shared:%{pg:gcrt0%O%s}%{!pg:%{p:mcrt0%O%s}%{!p:crt0%O%s}}}}"
+
+/* Names to predefine in the preprocessor for this target machine. */
+
+#define TARGET_CPU_CPP_BUILTINS() \
+ do \
+ { \
+ builtin_define ("__mn10300__"); \
+ builtin_define ("__MN10300__"); \
+ builtin_assert ("cpu=mn10300"); \
+ builtin_assert ("machine=mn10300"); \
+ \
+ if (TARGET_AM34) \
+ { \
+ builtin_define ("__AM33__=4"); \
+ builtin_define ("__AM34__"); \
+ } \
+ else if (TARGET_AM33_2) \
+ { \
+ builtin_define ("__AM33__=2"); \
+ builtin_define ("__AM33_2__"); \
+ } \
+ else if (TARGET_AM33) \
+ builtin_define ("__AM33__=1"); \
+ \
+ builtin_define (TARGET_ALLOW_LIW ? \
+ "__LIW__" : "__NO_LIW__");\
+ \
+ } \
+ while (0)
+
+enum processor_type
+{
+ PROCESSOR_MN10300,
+ PROCESSOR_AM33,
+ PROCESSOR_AM33_2,
+ PROCESSOR_AM34
+};
+
+extern enum processor_type mn10300_processor;
+extern enum processor_type mn10300_tune_cpu;
+
+#define TARGET_AM33 (mn10300_processor >= PROCESSOR_AM33)
+#define TARGET_AM33_2 (mn10300_processor >= PROCESSOR_AM33_2)
+#define TARGET_AM34 (mn10300_processor >= PROCESSOR_AM34)
+
+#ifndef PROCESSOR_DEFAULT
+#define PROCESSOR_DEFAULT PROCESSOR_MN10300
+#endif
+
+/* Print subsidiary information on the compiler version in use. */
+
+#define TARGET_VERSION fprintf (stderr, " (MN10300)");
+
+
+/* Target machine storage layout */
+
+/* Define this if most significant bit is lowest numbered
+ in instructions that operate on numbered bit-fields.
+ This is not true on the Matsushita MN1003. */
+#define BITS_BIG_ENDIAN 0
+
+/* Define this if most significant byte of a word is the lowest numbered. */
+/* This is not true on the Matsushita MN10300. */
+#define BYTES_BIG_ENDIAN 0
+
+/* Define this if most significant word of a multiword number is lowest
+ numbered.
+ This is not true on the Matsushita MN10300. */
+#define WORDS_BIG_ENDIAN 0
+
+/* Width of a word, in units (bytes). */
+#define UNITS_PER_WORD 4
+
+/* Allocation boundary (in *bits*) for storing arguments in argument list. */
+#define PARM_BOUNDARY 32
+
+/* The stack goes in 32-bit lumps. */
+#define STACK_BOUNDARY 32
+
+/* Allocation boundary (in *bits*) for the code of a function.
+ 8 is the minimum boundary; it's unclear if bigger alignments
+ would improve performance. */
+#define FUNCTION_BOUNDARY 8
+
+/* No data type wants to be aligned rounder than this. */
+#define BIGGEST_ALIGNMENT 32
+
+/* Alignment of field after `int : 0' in a structure. */
+#define EMPTY_FIELD_BOUNDARY 32
+
+/* Define this if move instructions will actually fail to work
+ when given unaligned data. */
+#define STRICT_ALIGNMENT 1
+
+/* Define this as 1 if `char' should by default be signed; else as 0. */
+#define DEFAULT_SIGNED_CHAR 0
+
+#undef SIZE_TYPE
+#define SIZE_TYPE "unsigned int"
+
+#undef PTRDIFF_TYPE
+#define PTRDIFF_TYPE "int"
+
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "long int"
+
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE BITS_PER_WORD
+
+/* Standard register usage. */
+
+/* Number of actual hardware registers.
+ The hardware registers are assigned numbers for the compiler
+ from 0 to just below FIRST_PSEUDO_REGISTER.
+
+ All registers that the compiler knows about must be given numbers,
+ even those that are not normally considered general registers. */
+
+#define FIRST_PSEUDO_REGISTER 52
+
+/* Specify machine-specific register numbers. The commented out entries
+ are defined in mn10300.md. */
+#define FIRST_DATA_REGNUM 0
+#define LAST_DATA_REGNUM 3
+#define FIRST_ADDRESS_REGNUM 4
+/* #define PIC_REG 6 */
+#define LAST_ADDRESS_REGNUM 8
+/* #define SP_REG 9 */
+#define FIRST_EXTENDED_REGNUM 10
+#define LAST_EXTENDED_REGNUM 17
+#define FIRST_FP_REGNUM 18
+#define LAST_FP_REGNUM 49
+/* #define MDR_REG 50 */
+/* #define CC_REG 51 */
+#define FIRST_ARGUMENT_REGNUM 0
+
+/* Specify the registers used for certain standard purposes.
+ The values of these macros are register numbers. */
+
+/* Register to use for pushing function arguments. */
+#define STACK_POINTER_REGNUM (LAST_ADDRESS_REGNUM + 1)
+
+/* Base register for access to local variables of the function. */
+#define FRAME_POINTER_REGNUM (LAST_ADDRESS_REGNUM - 1)
+
+/* Base register for access to arguments of the function. This
+ is a fake register and will be eliminated into either the frame
+ pointer or stack pointer. */
+#define ARG_POINTER_REGNUM LAST_ADDRESS_REGNUM
+
+/* Register in which static-chain is passed to a function. */
+#define STATIC_CHAIN_REGNUM (FIRST_ADDRESS_REGNUM + 1)
+
+/* 1 for registers that have pervasive standard uses
+ and are not available for the register allocator. */
+
+#define FIXED_REGISTERS \
+ { 0, 0, 0, 0, /* data regs */ \
+ 0, 0, 0, 0, /* addr regs */ \
+ 1, /* arg reg */ \
+ 1, /* sp reg */ \
+ 0, 0, 0, 0, 0, 0, 0, 0, /* extended regs */ \
+ 0, 0, /* fp regs (18-19) */ \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* fp regs (20-29) */ \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* fp regs (30-39) */ \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* fp regs (40-49) */ \
+ 0, /* mdr reg */ \
+ 1 /* cc reg */ \
+ }
+
+/* 1 for registers not available across function calls.
+ These must include the FIXED_REGISTERS and also any
+ registers that can be used without being saved.
+ The latter must include the registers where values are returned
+ and the register where structure-value addresses are passed.
+ Aside from that, you can include as many other registers as you
+ like. */
+
+#define CALL_USED_REGISTERS \
+ { 1, 1, 0, 0, /* data regs */ \
+ 1, 1, 0, 0, /* addr regs */ \
+ 1, /* arg reg */ \
+ 1, /* sp reg */ \
+ 1, 1, 1, 1, 0, 0, 0, 0, /* extended regs */ \
+ 1, 1, /* fp regs (18-19) */ \
+ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* fp regs (20-29) */ \
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, /* fp regs (30-39) */ \
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* fp regs (40-49) */ \
+ 1, /* mdr reg */ \
+ 1 /* cc reg */ \
+ }
+
+/* Note: The definition of CALL_REALLY_USED_REGISTERS is not
+ redundant. It is needed when compiling in PIC mode because
+ the a2 register becomes fixed (and hence must be marked as
+ call_used) but in order to preserve the ABI it is not marked
+ as call_really_used. */
+#define CALL_REALLY_USED_REGISTERS CALL_USED_REGISTERS
+
+#define REG_ALLOC_ORDER \
+ { 0, 1, 4, 5, 2, 3, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 8, 9 \
+ , 42, 43, 44, 45, 46, 47, 48, 49, 34, 35, 36, 37, 38, 39, 40, 41 \
+ , 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 50, 51 \
+ }
+
+/* Return number of consecutive hard regs needed starting at reg REGNO
+ to hold something of mode MODE.
+
+ This is ordinarily the length in words of a value of mode MODE
+ but can be less for certain modes in special long registers. */
+
+#define HARD_REGNO_NREGS(REGNO, MODE) \
+ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+
+/* Value is 1 if hard register REGNO can hold a value of machine-mode
+ MODE. */
+#define HARD_REGNO_MODE_OK(REGNO, MODE) \
+ mn10300_hard_regno_mode_ok ((REGNO), (MODE))
+
+/* Value is 1 if it is a good idea to tie two pseudo registers
+ when one has mode MODE1 and one has mode MODE2.
+ If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2,
+ for any hard reg, then this must be 0 for correct output. */
+#define MODES_TIEABLE_P(MODE1, MODE2) \
+ mn10300_modes_tieable ((MODE1), (MODE2))
+
+/* 4 data, and effectively 3 address registers is small as far as I'm
+ concerned. */
+#define TARGET_SMALL_REGISTER_CLASSES_FOR_MODE_P hook_bool_mode_true
+
+/* Define the classes of registers for register constraints in the
+ machine description. Also define ranges of constants.
+
+ One of the classes must always be named ALL_REGS and include all hard regs.
+ If there is more than one class, another class must be named NO_REGS
+ and contain no registers.
+
+ The name GENERAL_REGS must be the name of a class (or an alias for
+ another name such as ALL_REGS). This is the class of registers
+ that is allowed by "g" or "r" in a register constraint.
+ Also, registers outside this class are allocated only when
+ instructions express preferences for them.
+
+ The classes must be numbered in nondecreasing order; that is,
+ a larger-numbered class must never be contained completely
+ in a smaller-numbered class.
+
+ For any two classes, it is very desirable that there be another
+ class that represents their union. */
+
+enum reg_class
+{
+ NO_REGS, DATA_REGS, ADDRESS_REGS, SP_REGS, SP_OR_ADDRESS_REGS,
+ EXTENDED_REGS, FP_REGS, FP_ACC_REGS, CC_REGS, MDR_REGS,
+ GENERAL_REGS, SP_OR_GENERAL_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", "DATA_REGS", "ADDRESS_REGS", "SP_REGS", "SP_OR_ADDRESS_REGS", \
+ "EXTENDED_REGS", "FP_REGS", "FP_ACC_REGS", "CC_REGS", "MDR_REGS", \
+ "GENERAL_REGS", "SP_OR_GENERAL_REGS", "ALL_REGS", "LIM_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 \
+{ { 0, 0 }, /* No regs */ \
+ { 0x0000000f, 0 }, /* DATA_REGS */ \
+ { 0x000001f0, 0 }, /* ADDRESS_REGS */ \
+ { 0x00000200, 0 }, /* SP_REGS */ \
+ { 0x000003f0, 0 }, /* SP_OR_ADDRESS_REGS */ \
+ { 0x0003fc00, 0 }, /* EXTENDED_REGS */ \
+ { 0xfffc0000, 0x3ffff },/* FP_REGS */ \
+ { 0x03fc0000, 0 }, /* FP_ACC_REGS */ \
+ { 0x00000000, 0x80000 },/* CC_REGS */ \
+ { 0x00000000, 0x40000 },/* MDR_REGS */ \
+ { 0x0003fdff, 0 }, /* GENERAL_REGS */ \
+ { 0x0003ffff, 0 }, /* SP_OR_GENERAL_REGS */ \
+ { 0xffffffff, 0xfffff } /* ALL_REGS */ \
+}
+
+/* The following macro defines cover classes for Integrated Register
+ Allocator. Cover classes is a set of non-intersected register
+ classes covering all hard registers used for register allocation
+ purpose. Any move between two registers of a cover class should be
+ cheaper than load or store of the registers. The macro value is
+ array of register classes with LIM_REG_CLASSES used as the end
+ marker. */
+
+#define IRA_COVER_CLASSES \
+{ \
+ GENERAL_REGS, FP_REGS, MDR_REGS, LIM_REG_CLASSES \
+}
+
+/* The same information, inverted:
+ Return the class number of the smallest class containing
+ reg number REGNO. This could be a conditional expression
+ or could index an array. */
+
+#define REGNO_REG_CLASS(REGNO) \
+ ((REGNO) <= LAST_DATA_REGNUM ? DATA_REGS : \
+ (REGNO) <= LAST_ADDRESS_REGNUM ? ADDRESS_REGS : \
+ (REGNO) == STACK_POINTER_REGNUM ? SP_REGS : \
+ (REGNO) <= LAST_EXTENDED_REGNUM ? EXTENDED_REGS : \
+ (REGNO) <= LAST_FP_REGNUM ? FP_REGS : \
+ (REGNO) == MDR_REG ? MDR_REGS : \
+ (REGNO) == CC_REG ? CC_REGS : \
+ NO_REGS)
+
+/* The class value for index registers, and the one for base regs. */
+#define INDEX_REG_CLASS \
+ (TARGET_AM33 ? GENERAL_REGS : DATA_REGS)
+#define BASE_REG_CLASS \
+ (TARGET_AM33 ? SP_OR_GENERAL_REGS : SP_OR_ADDRESS_REGS)
+
+/* Macros to check register numbers against specific register classes. */
+
+/* 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. */
+
+/* These assume that REGNO is a hard or pseudo reg number.
+ They give nonzero only if REGNO is a hard reg of the suitable class
+ or a pseudo reg currently allocated to a suitable hard reg.
+ Since they use reg_renumber, they are safe only once reg_renumber
+ has been allocated, which happens in local-alloc.c. */
+
+#ifndef REG_OK_STRICT
+# define REG_STRICT 0
+#else
+# define REG_STRICT 1
+#endif
+
+#define REGNO_DATA_P(regno, strict) \
+ mn10300_regno_in_class_p (regno, DATA_REGS, strict)
+#define REGNO_ADDRESS_P(regno, strict) \
+ mn10300_regno_in_class_p (regno, ADDRESS_REGS, strict)
+#define REGNO_EXTENDED_P(regno, strict) \
+ mn10300_regno_in_class_p (regno, EXTENDED_REGS, strict)
+#define REGNO_GENERAL_P(regno, strict) \
+ mn10300_regno_in_class_p (regno, GENERAL_REGS, strict)
+
+#define REGNO_STRICT_OK_FOR_BASE_P(regno, strict) \
+ mn10300_regno_in_class_p (regno, BASE_REG_CLASS, strict)
+#define REGNO_OK_FOR_BASE_P(regno) \
+ (REGNO_STRICT_OK_FOR_BASE_P ((regno), REG_STRICT))
+#define REG_OK_FOR_BASE_P(X) \
+ (REGNO_OK_FOR_BASE_P (REGNO (X)))
+
+#define REGNO_STRICT_OK_FOR_BIT_BASE_P(regno, strict) \
+ mn10300_regno_in_class_p (regno, ADDRESS_REGS, strict)
+#define REGNO_OK_FOR_BIT_BASE_P(regno) \
+ (REGNO_STRICT_OK_FOR_BIT_BASE_P ((regno), REG_STRICT))
+#define REG_OK_FOR_BIT_BASE_P(X) \
+ (REGNO_OK_FOR_BIT_BASE_P (REGNO (X)))
+
+#define REGNO_STRICT_OK_FOR_INDEX_P(regno, strict) \
+ mn10300_regno_in_class_p (regno, INDEX_REG_CLASS, strict)
+#define REGNO_OK_FOR_INDEX_P(regno) \
+ (REGNO_STRICT_OK_FOR_INDEX_P ((regno), REG_STRICT))
+#define REG_OK_FOR_INDEX_P(X) \
+ (REGNO_OK_FOR_INDEX_P (REGNO (X)))
+
+#define LIMIT_RELOAD_CLASS(MODE, CLASS) \
+ (!TARGET_AM33 && (MODE == QImode || MODE == HImode) ? DATA_REGS : CLASS)
+
+/* Return the maximum number of consecutive registers
+ needed to represent mode MODE in a register of class CLASS. */
+
+#define CLASS_MAX_NREGS(CLASS, MODE) \
+ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+
+/* A class that contains registers which the compiler must always
+ access in a mode that is the same size as the mode in which it
+ loaded the register. */
+#define CLASS_CANNOT_CHANGE_SIZE FP_REGS
+
+/* Return 1 if VALUE is in the range specified. */
+
+#define INT_8_BITS(VALUE) ((unsigned) (VALUE) + 0x80 < 0x100)
+#define INT_16_BITS(VALUE) ((unsigned) (VALUE) + 0x8000 < 0x10000)
+
+
+/* Stack layout; function entry, exit and calling. */
+
+/* Define this if pushing a word on the stack
+ makes the stack pointer a smaller address. */
+
+#define STACK_GROWS_DOWNWARD
+
+/* 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 within stack frame to start allocating local variables at.
+ If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
+ first local allocated. Otherwise, it is the offset to the BEGINNING
+ of the first local allocated. */
+
+#define STARTING_FRAME_OFFSET 0
+
+/* Offset of first parameter from the argument pointer register value. */
+/* Is equal to the size of the saved fp + pc, even if an fp isn't
+ saved since the value is used before we know. */
+
+#define FIRST_PARM_OFFSET(FNDECL) 4
+
+/* But the CFA is at the arg pointer directly, not at the first argument. */
+#define ARG_POINTER_CFA_OFFSET(FNDECL) 0
+
+#define ELIMINABLE_REGS \
+{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ { ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \
+ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}}
+
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
+ OFFSET = mn10300_initial_offset (FROM, TO)
+
+/* We use d0/d1 for passing parameters, so allocate 8 bytes of space
+ for a register flushback area. */
+#define REG_PARM_STACK_SPACE(DECL) 8
+#define OUTGOING_REG_PARM_STACK_SPACE(FNTYPE) 1
+#define ACCUMULATE_OUTGOING_ARGS 1
+
+/* So we can allocate space for return pointers once for the function
+ instead of around every call. */
+#define STACK_POINTER_OFFSET 4
+
+/* 1 if N is a possible register number for function argument passing.
+ On the MN10300, d0 and d1 are used in this way. */
+
+#define FUNCTION_ARG_REGNO_P(N) ((N) <= 1)
+
+
+/* Define a data type for recording info about an argument list
+ during the scan of that argument list. This data type should
+ hold all necessary information about the function itself
+ and about the args processed so far, enough to enable macros
+ such as FUNCTION_ARG to determine where the next arg should go.
+
+ On the MN10300, this is a single integer, which is a number of bytes
+ of arguments scanned so far. */
+
+#define CUMULATIVE_ARGS struct cum_arg
+
+struct cum_arg
+{
+ int nbytes;
+};
+
+/* 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 the MN10300, the offset starts at 0. */
+
+#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) \
+ ((CUM).nbytes = 0)
+
+#define FUNCTION_VALUE_REGNO_P(N) mn10300_function_value_regno_p (N)
+
+#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. */
+
+#define EXIT_IGNORE_STACK 1
+
+/* Output assembler code to FILE to increment profiler label # LABELNO
+ for profiling a function entry. */
+
+#define FUNCTION_PROFILER(FILE, LABELNO) ;
+
+/* Length in units of the trampoline for entering a nested function. */
+
+#define TRAMPOLINE_SIZE 16
+#define TRAMPOLINE_ALIGNMENT 32
+
+/* A C expression whose value is RTL representing the value of the return
+ address for the frame COUNT steps up from the current frame.
+
+ On the mn10300, the return address is not at a constant location
+ due to the frame layout. Luckily, it is at a constant offset from
+ the argument pointer, so we define RETURN_ADDR_RTX to return a
+ MEM using arg_pointer_rtx. Reload will replace arg_pointer_rtx
+ with a reference to the stack/frame pointer + an appropriate offset. */
+
+#define RETURN_ADDR_RTX(COUNT, FRAME) \
+ ((COUNT == 0) \
+ ? gen_rtx_MEM (Pmode, arg_pointer_rtx) \
+ : (rtx) 0)
+
+/* The return address is saved both in the stack and in MDR. Using
+ the stack location is handiest for what unwinding needs. */
+#define INCOMING_RETURN_ADDR_RTX \
+ gen_rtx_MEM (VOIDmode, gen_rtx_REG (VOIDmode, STACK_POINTER_REGNUM))
+
+/* Maximum number of registers that can appear in a valid memory address. */
+
+#define MAX_REGS_PER_ADDRESS 2
+
+
+/* We have post-increments. */
+#define HAVE_POST_INCREMENT TARGET_AM33
+#define HAVE_POST_MODIFY_DISP TARGET_AM33
+
+/* ... But we don't want to use them for block moves. Small offsets are
+ just as effective, at least for inline block move sizes, and appears
+ to produce cleaner code. */
+#define USE_LOAD_POST_INCREMENT(M) 0
+#define USE_STORE_POST_INCREMENT(M) 0
+
+/* Accept either REG or SUBREG where a register is valid. */
+
+#define RTX_OK_FOR_BASE_P(X, strict) \
+ ((REG_P (X) && REGNO_STRICT_OK_FOR_BASE_P (REGNO (X), \
+ (strict))) \
+ || (GET_CODE (X) == SUBREG && REG_P (SUBREG_REG (X)) \
+ && REGNO_STRICT_OK_FOR_BASE_P (REGNO (SUBREG_REG (X)), \
+ (strict))))
+
+#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_L,WIN) \
+do { \
+ rtx new_x = mn10300_legitimize_reload_address (X, MODE, OPNUM, TYPE, IND_L); \
+ if (new_x) \
+ { \
+ X = new_x; \
+ goto WIN; \
+ } \
+} while (0)
+
+
+/* Nonzero if the constant value X is a legitimate general operand.
+ It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
+#define LEGITIMATE_CONSTANT_P(X) mn10300_legitimate_constant_p (X)
+
+/* Zero if this needs fixing up to become PIC. */
+
+#define LEGITIMATE_PIC_OPERAND_P(X) \
+ mn10300_legitimate_pic_operand_p (X)
+
+/* Register to hold the addressing base for
+ position independent code access to data items. */
+#define PIC_OFFSET_TABLE_REGNUM PIC_REG
+
+/* The name of the pseudo-symbol representing the Global Offset Table. */
+#define GOT_SYMBOL_NAME "*_GLOBAL_OFFSET_TABLE_"
+
+#define SYMBOLIC_CONST_P(X) \
+((GET_CODE (X) == SYMBOL_REF || GET_CODE (X) == LABEL_REF) \
+ && ! LEGITIMATE_PIC_OPERAND_P (X))
+
+/* Non-global SYMBOL_REFs have SYMBOL_REF_FLAG enabled. */
+#define MN10300_GLOBAL_P(X) (! SYMBOL_REF_FLAG (X))
+
+#define SELECT_CC_MODE(OP, X, Y) mn10300_select_cc_mode (OP, X, Y)
+#define REVERSIBLE_CC_MODE(MODE) 0
+
+/* Nonzero if access to memory by bytes or half words is no faster
+ than accessing full words. */
+#define SLOW_BYTE_ACCESS 1
+
+#define NO_FUNCTION_CSE
+
+/* According expr.c, a value of around 6 should minimize code size, and
+ for the MN10300 series, that's our primary concern. */
+#define MOVE_RATIO(speed) 6
+
+#define TEXT_SECTION_ASM_OP "\t.section .text"
+#define DATA_SECTION_ASM_OP "\t.section .data"
+#define BSS_SECTION_ASM_OP "\t.section .bss"
+
+#define ASM_COMMENT_START "#"
+
+/* Output to assembler file text saying following lines
+ may contain character constants, extra white space, comments, etc. */
+
+#define ASM_APP_ON "#APP\n"
+
+/* Output to assembler file text saying following lines
+ no longer contain unusual constructs. */
+
+#define ASM_APP_OFF "#NO_APP\n"
+
+#undef USER_LABEL_PREFIX
+#define USER_LABEL_PREFIX "_"
+
+/* This says how to output the assembler to define a global
+ uninitialized but not common symbol.
+ Try to use asm_output_bss to implement this macro. */
+
+#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \
+ asm_output_aligned_bss ((FILE), (DECL), (NAME), (SIZE), (ALIGN))
+
+/* Globalizing directive for a label. */
+#define GLOBAL_ASM_OP "\t.global "
+
+/* This is how to output a reference to a user-level label named NAME.
+ `assemble_name' uses this. */
+
+#undef ASM_OUTPUT_LABELREF
+#define ASM_OUTPUT_LABELREF(FILE, NAME) \
+ asm_fprintf (FILE, "%U%s", (*targetm.strip_name_encoding) (NAME))
+
+/* This is how we tell the assembler that two symbols have the same value. */
+
+#define ASM_OUTPUT_DEF(FILE,NAME1,NAME2) \
+ do \
+ { \
+ assemble_name (FILE, NAME1); \
+ fputs (" = ", FILE); \
+ assemble_name (FILE, NAME2); \
+ fputc ('\n', FILE); \
+ } \
+ while (0)
+
+/* How to refer to registers in assembler output.
+ This sequence is indexed by compiler's hard-register-number (see above). */
+
+#define REGISTER_NAMES \
+{ "d0", "d1", "d2", "d3", "a0", "a1", "a2", "a3", "ap", "sp", \
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" \
+, "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7" \
+, "fs8", "fs9", "fs10", "fs11", "fs12", "fs13", "fs14", "fs15" \
+, "fs16", "fs17", "fs18", "fs19", "fs20", "fs21", "fs22", "fs23" \
+, "fs24", "fs25", "fs26", "fs27", "fs28", "fs29", "fs30", "fs31" \
+, "mdr", "EPSW" \
+}
+
+#define ADDITIONAL_REGISTER_NAMES \
+{ {"r8", 4}, {"r9", 5}, {"r10", 6}, {"r11", 7}, \
+ {"r12", 0}, {"r13", 1}, {"r14", 2}, {"r15", 3}, \
+ {"e0", 10}, {"e1", 11}, {"e2", 12}, {"e3", 13}, \
+ {"e4", 14}, {"e5", 15}, {"e6", 16}, {"e7", 17} \
+, {"fd0", 18}, {"fd2", 20}, {"fd4", 22}, {"fd6", 24} \
+, {"fd8", 26}, {"fd10", 28}, {"fd12", 30}, {"fd14", 32} \
+, {"fd16", 34}, {"fd18", 36}, {"fd20", 38}, {"fd22", 40} \
+, {"fd24", 42}, {"fd26", 44}, {"fd28", 46}, {"fd30", 48} \
+, {"cc", CC_REG} \
+}
+
+/* Print an instruction operand X on file FILE.
+ look in mn10300.c for details */
+
+#define PRINT_OPERAND(FILE, X, CODE) \
+ mn10300_print_operand (FILE, X, CODE)
+
+/* Print a memory operand whose address is X, on file FILE.
+ This uses a function in output-vax.c. */
+
+#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \
+ mn10300_print_operand_address (FILE, ADDR)
+
+/* This is how to output an element of a case-vector that is absolute. */
+
+#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
+ fprintf (FILE, "\t%s .L%d\n", ".long", VALUE)
+
+/* This is how to output an element of a case-vector that is relative. */
+
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
+ fprintf (FILE, "\t%s .L%d-.L%d\n", ".long", VALUE, REL)
+
+#define ASM_OUTPUT_ALIGN(FILE,LOG) \
+ if ((LOG) != 0) \
+ fprintf (FILE, "\t.align %d\n", (LOG))
+
+/* We don't have to worry about dbx compatibility for the mn10300. */
+#define DEFAULT_GDB_EXTENSIONS 1
+
+/* Use dwarf2 debugging info by default. */
+#undef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
+#define DWARF2_DEBUGGING_INFO 1
+#define DWARF2_ASM_LINE_DEBUG_INFO 1
+
+/* Specify the machine mode that this machine uses
+ for the index in the tablejump instruction. */
+#define CASE_VECTOR_MODE Pmode
+
+/* Define if operations between registers always perform the operation
+ on the full register even if a narrower mode is specified. */
+#define WORD_REGISTER_OPERATIONS
+
+#define LOAD_EXTEND_OP(MODE) ZERO_EXTEND
+
+/* This flag, if defined, says the same insns that convert to a signed fixnum
+ also convert validly to an unsigned one. */
+#define FIXUNS_TRUNC_LIKE_FIX_TRUNC
+
+/* Max number of bytes we can move from memory to memory
+ in one reasonably fast instruction. */
+#define MOVE_MAX 4
+
+/* Define if shifts truncate the shift count
+ which implies one can omit a sign-extension or zero-extension
+ of a shift count. */
+#define SHIFT_COUNT_TRUNCATED 1
+
+/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits
+ is done just by pretending it is already truncated. */
+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
+
+/* Specify the machine mode that pointers have.
+ After generation of rtl, the compiler makes no further distinction
+ between pointers and any other objects of this machine mode. */
+#define Pmode SImode
+
+/* A function address in a call instruction
+ is a byte address (for indexing purposes)
+ so give the MEM rtx a byte's mode. */
+#define FUNCTION_MODE QImode
+
+/* The assembler op to get a word. */
+
+#define FILE_ASM_OP "\t.file\n"
+
diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
new file mode 100644
index 000000000..3d8e91470
--- /dev/null
+++ b/gcc/config/mn10300/mn10300.md
@@ -0,0 +1,2154 @@
+;; GCC machine description for Matsushita MN10300
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+;; 2005, 2006, 2007, 2008, 2009, 2010, 2011
+;; Free Software Foundation, Inc.
+;; Contributed by Jeff Law (law@cygnus.com).
+
+;; 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/>.
+
+;; The original PO technology requires these to be ordered by speed,
+;; so that assigner will pick the fastest.
+
+;; See file "rtl.def" for documentation on define_insn, match_*, et. al.
+
+(define_constants [
+ (PIC_REG 6)
+ (SP_REG 9)
+ (MDR_REG 50)
+ (CC_REG 51)
+
+ (UNSPEC_PIC 1)
+ (UNSPEC_GOT 2)
+ (UNSPEC_GOTOFF 3)
+ (UNSPEC_PLT 4)
+ (UNSPEC_GOTSYM_OFF 5)
+
+ (UNSPEC_EXT 6)
+ (UNSPEC_BSCH 7)
+
+ ;; This is used to encode LIW patterns.
+ (UNSPEC_LIW 8)
+])
+
+(include "predicates.md")
+(include "constraints.md")
+
+;; Processor type. This attribute must exactly match the processor_type
+;; enumeration in mn10300.h.
+(define_attr "cpu" "mn10300,am33,am33_2,am34"
+ (const (symbol_ref "(enum attr_cpu) mn10300_tune_cpu")))
+
+;; Used to control the "enabled" attribute on a per-instruction basis.
+(define_attr "isa" "base,am33,am33_2,am34"
+ (const_string "base"))
+
+(define_attr "enabled" ""
+ (cond [(eq_attr "isa" "base")
+ (const_int 1)
+
+ (and (eq_attr "isa" "am33")
+ (ne (symbol_ref "TARGET_AM33") (const_int 0)))
+ (const_int 1)
+
+ (and (eq_attr "isa" "am33_2")
+ (ne (symbol_ref "TARGET_AM33_2") (const_int 0)))
+ (const_int 1)
+
+ (and (eq_attr "isa" "am34")
+ (ne (symbol_ref "TARGET_AM34") (const_int 0)))
+ (const_int 1)
+ ]
+ (const_int 0))
+)
+
+(define_mode_iterator INT [QI HI SI])
+
+
+;; Bundling of smaller insns into a long instruction word (LIW)
+(define_automaton "liw_bundling")
+(automata_option "ndfa")
+
+(define_cpu_unit "liw_op1_u,liw_op2_u" "liw_bundling")
+
+(define_attr "liw" "op1,op2,both,either"
+ (const_string "both"))
+;; Note: this list must match the one defined for liw_op_names[].
+(define_attr "liw_op" "add,cmp,sub,mov,and,or,xor,asr,lsr,asl,none,max"
+ (const_string "none"))
+
+(define_insn_reservation "liw_op1" 1
+ (and (ior (eq_attr "cpu" "am33")
+ (eq_attr "cpu" "am33_2")
+ (eq_attr "cpu" "am34"))
+ (eq_attr "liw" "op1"))
+ "liw_op1_u");
+(define_insn_reservation "liw_op2" 1
+ (and (ior (eq_attr "cpu" "am33")
+ (eq_attr "cpu" "am33_2")
+ (eq_attr "cpu" "am34"))
+ (eq_attr "liw" "op2"))
+ "liw_op2_u");
+(define_insn_reservation "liw_both" 1
+ (and (ior (eq_attr "cpu" "am33")
+ (eq_attr "cpu" "am33_2")
+ (eq_attr "cpu" "am34"))
+ (eq_attr "liw" "both"))
+ "liw_op1_u + liw_op2_u");
+(define_insn_reservation "liw_either" 1
+ (and (ior (eq_attr "cpu" "am33")
+ (eq_attr "cpu" "am33_2")
+ (eq_attr "cpu" "am34"))
+ (eq_attr "liw" "either"))
+ "liw_op1_u | liw_op2_u");
+
+;; ----------------------------------------------------------------------
+;; Pipeline description.
+;; ----------------------------------------------------------------------
+
+;; The AM33 only has a single pipeline. It has five stages (fetch,
+;; decode, execute, memory access, writeback) each of which normally
+;; takes a single CPU clock cycle.
+
+;; The timings attribute consists of two numbers, the first is the
+;; throughput, which is the number of cycles the instruction takes
+;; to execute and generate a result. The second is the latency
+;; which is the effective number of cycles the instruction takes to
+;; execute if its result is used by the following instruction. The
+;; latency is always greater than or equal to the throughput.
+;; These values were taken from the Appendix of the "MN103E Series
+;; Instruction Manual" and the timings for the AM34.
+
+;; Note - it would be nice to use strings rather than integers for
+;; the possible values of this attribute, so that we can have the
+;; gcc build mechanism check for values that are not supported by
+;; the reservations below. But this will not work because the code
+;; in mn10300_adjust_sched_cost() needs integers not strings.
+
+(define_attr "timings" "" (const_int 11))
+
+(define_automaton "pipelining")
+(define_cpu_unit "throughput" "pipelining")
+
+(define_insn_reservation "throughput__1_latency__1" 1
+ (eq_attr "timings" "11") "throughput")
+(define_insn_reservation "throughput__1_latency__2" 2
+ (eq_attr "timings" "12") "throughput,nothing")
+(define_insn_reservation "throughput__1_latency__3" 3
+ (eq_attr "timings" "13") "throughput,nothing*2")
+(define_insn_reservation "throughput__1_latency__4" 4
+ (eq_attr "timings" "14") "throughput,nothing*3")
+(define_insn_reservation "throughput__2_latency__2" 2
+ (eq_attr "timings" "22") "throughput*2")
+(define_insn_reservation "throughput__2_latency__3" 3
+ (eq_attr "timings" "23") "throughput*2,nothing")
+(define_insn_reservation "throughput__2_latency__4" 4
+ (eq_attr "timings" "24") "throughput*2,nothing*2")
+(define_insn_reservation "throughput__2_latency__5" 5
+ (eq_attr "timings" "25") "throughput*2,nothing*3")
+(define_insn_reservation "throughput__3_latency__3" 3
+ (eq_attr "timings" "33") "throughput*3")
+(define_insn_reservation "throughput__3_latency__7" 7
+ (eq_attr "timings" "37") "throughput*3,nothing*4")
+(define_insn_reservation "throughput__4_latency__4" 4
+ (eq_attr "timings" "44") "throughput*4")
+(define_insn_reservation "throughput__4_latency__7" 7
+ (eq_attr "timings" "47") "throughput*4,nothing*3")
+(define_insn_reservation "throughput__4_latency__8" 8
+ (eq_attr "timings" "48") "throughput*4,nothing*4")
+(define_insn_reservation "throughput__5_latency__5" 5
+ (eq_attr "timings" "55") "throughput*5")
+(define_insn_reservation "throughput__6_latency__6" 6
+ (eq_attr "timings" "66") "throughput*6")
+(define_insn_reservation "throughput__7_latency__7" 7
+ (eq_attr "timings" "77") "throughput*7")
+(define_insn_reservation "throughput__7_latency__8" 8
+ (eq_attr "timings" "78") "throughput*7,nothing")
+(define_insn_reservation "throughput__8_latency__8" 8
+ (eq_attr "timings" "88") "throughput*8")
+(define_insn_reservation "throughput__9_latency__9" 9
+ (eq_attr "timings" "99") "throughput*9")
+(define_insn_reservation "throughput__8_latency_14" 14
+ (eq_attr "timings" "814") "throughput*8,nothing*6")
+(define_insn_reservation "throughput__9_latency_10" 10
+ (eq_attr "timings" "910") "throughput*9,nothing")
+(define_insn_reservation "throughput_10_latency_10" 10
+ (eq_attr "timings" "1010") "throughput*10")
+(define_insn_reservation "throughput_12_latency_16" 16
+ (eq_attr "timings" "1216") "throughput*12,nothing*4")
+(define_insn_reservation "throughput_13_latency_13" 13
+ (eq_attr "timings" "1313") "throughput*13")
+(define_insn_reservation "throughput_14_latency_14" 14
+ (eq_attr "timings" "1414") "throughput*14")
+(define_insn_reservation "throughput_13_latency_17" 17
+ (eq_attr "timings" "1317") "throughput*13,nothing*4")
+(define_insn_reservation "throughput_23_latency_27" 27
+ (eq_attr "timings" "2327") "throughput*23,nothing*4")
+(define_insn_reservation "throughput_25_latency_31" 31
+ (eq_attr "timings" "2531") "throughput*25,nothing*6")
+(define_insn_reservation "throughput_38_latency_39" 39
+ (eq_attr "timings" "3839") "throughput*38,nothing")
+(define_insn_reservation "throughput_39_latency_40" 40
+ (eq_attr "timings" "3940") "throughput*39,nothing")
+(define_insn_reservation "throughput_40_latency_40" 40
+ (eq_attr "timings" "4040") "throughput*40")
+(define_insn_reservation "throughput_41_latency_42" 42
+ (eq_attr "timings" "4142") "throughput*41,nothing")
+(define_insn_reservation "throughput_42_latency_43" 44
+ (eq_attr "timings" "4243") "throughput*42,nothing")
+(define_insn_reservation "throughput_43_latency_44" 44
+ (eq_attr "timings" "4344") "throughput*43,nothing")
+(define_insn_reservation "throughput_45_latency_46" 46
+ (eq_attr "timings" "4546") "throughput*45,nothing")
+(define_insn_reservation "throughput_47_latency_53" 53
+ (eq_attr "timings" "4753") "throughput*47,nothing*6")
+
+;; Note - the conflict between memory load/store instructions
+;; and floating point instructions described in section 1-7-4
+;; of Chapter 3 of the MN103E Series Instruction Manual is
+;; handled by the mn10300_adjust_sched_cost function.
+
+;; ----------------------------------------------------------------------
+;; MOVE INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+;; movqi
+
+(define_expand "movqi"
+ [(set (match_operand:QI 0 "nonimmediate_operand")
+ (match_operand:QI 1 "general_operand"))]
+ ""
+{
+ /* One of the ops has to be in a register. */
+ if (!register_operand (operand0, QImode)
+ && !register_operand (operand1, QImode))
+ operands[1] = force_reg (QImode, operand1);
+})
+
+(define_insn "*movqi_internal"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=*r,D*r,D*r,D,m")
+ (match_operand:QI 1 "general_operand" " 0,D*r, i,m,D"))]
+ "(register_operand (operands[0], QImode)
+ || register_operand (operands[1], QImode))"
+{
+ switch (which_alternative)
+ {
+ case 0:
+ return "";
+ case 1:
+ case 2:
+ return "mov %1,%0";
+ case 3:
+ case 4:
+ return "movbu %1,%0";
+ default:
+ gcc_unreachable ();
+ }
+}
+ [(set_attr_alternative "timings"
+ [(const_int 11)
+ (const_int 11)
+ (const_int 11)
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 24))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 11) (const_int 22))
+ ])]
+)
+
+;; movhi
+
+(define_expand "movhi"
+ [(set (match_operand:HI 0 "nonimmediate_operand")
+ (match_operand:HI 1 "general_operand"))]
+ ""
+{
+ /* One of the ops has to be in a register. */
+ if (!register_operand (operand1, HImode)
+ && !register_operand (operand0, HImode))
+ operands[1] = force_reg (HImode, operand1);
+})
+
+(define_insn "*movhi_internal"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=*r,D*r,D*r,D,m")
+ (match_operand:HI 1 "general_operand" " 0, i,D*r,m,D"))]
+ "(register_operand (operands[0], HImode)
+ || register_operand (operands[1], HImode))"
+{
+ switch (which_alternative)
+ {
+ case 0:
+ return "";
+ case 1:
+ /* Note that "MOV imm8,An" is already zero-extending, and is 2 bytes.
+ We have "MOV imm16,Dn" at 3 bytes. The only win for the 4 byte
+ movu is for an 8-bit unsigned move into Rn. */
+ if (TARGET_AM33
+ && CONST_INT_P (operands[1])
+ && IN_RANGE (INTVAL (operands[1]), 0x80, 0xff)
+ && REGNO_EXTENDED_P (REGNO (operands[0]), 1))
+ return "movu %1,%0";
+ /* FALLTHRU */
+ case 2:
+ return "mov %1,%0";
+ case 3:
+ case 4:
+ return "movhu %1,%0";
+ default:
+ gcc_unreachable ();
+ }
+}
+ [(set_attr_alternative "timings"
+ [(const_int 11)
+ (const_int 11)
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 11) (const_int 22))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 24))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 11) (const_int 22))
+ ])]
+)
+
+;; movsi and helpers
+
+;; We use this to handle addition of two values when one operand is the
+;; stack pointer and the other is a memory reference of some kind. Reload
+;; does not handle them correctly without this expander.
+(define_expand "reload_plus_sp_const"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (match_operand:SI 1 "impossible_plus_operand" ""))
+ (clobber (match_operand:SI 2 "register_operand" "=&A"))]
+ ""
+{
+ rtx dest, scratch, other;
+
+ dest = operands[0];
+ scratch = operands[2];
+
+ other = XEXP (operands[1], 1);
+ if (other == stack_pointer_rtx)
+ other = XEXP (operands[1], 0);
+
+ if (true_regnum (other) == true_regnum (dest))
+ {
+ gcc_assert (true_regnum (scratch) != true_regnum (dest));
+ emit_move_insn (scratch, stack_pointer_rtx);
+ emit_insn (gen_addsi3 (dest, dest, scratch));
+ }
+ else if (TARGET_AM33 || REGNO_REG_CLASS (true_regnum (dest)) == ADDRESS_REGS)
+ {
+ emit_move_insn (dest, stack_pointer_rtx);
+ if (other == stack_pointer_rtx)
+ emit_insn (gen_addsi3 (dest, dest, dest));
+ else if (other != const0_rtx)
+ emit_insn (gen_addsi3 (dest, dest, other));
+ }
+ else
+ {
+ emit_move_insn (scratch, stack_pointer_rtx);
+ if (other == stack_pointer_rtx)
+ {
+ emit_move_insn (dest, scratch);
+ emit_insn (gen_addsi3 (dest, dest, dest));
+ }
+ else if (other != const0_rtx)
+ {
+ emit_move_insn (dest, other);
+ emit_insn (gen_addsi3 (dest, dest, scratch));
+ }
+ else
+ emit_move_insn (dest, scratch);
+ }
+ DONE;
+})
+
+(define_expand "movsi"
+ [(set (match_operand:SI 0 "nonimmediate_operand")
+ (match_operand:SI 1 "general_operand"))]
+ ""
+{
+ /* One of the ops has to be in a register. */
+ if (!register_operand (operand1, SImode)
+ && !register_operand (operand0, SImode))
+ operands[1] = force_reg (SImode, operand1);
+ if (flag_pic)
+ {
+ rtx temp;
+ if (SYMBOLIC_CONST_P (operands[1]))
+ {
+ if (MEM_P (operands[0]))
+ operands[1] = force_reg (Pmode, operands[1]);
+ else
+ {
+ temp = (!can_create_pseudo_p ()
+ ? operands[0]
+ : gen_reg_rtx (Pmode));
+ operands[1] = mn10300_legitimize_pic_address (operands[1], temp);
+ }
+ }
+ else if (GET_CODE (operands[1]) == CONST
+ && GET_CODE (XEXP (operands[1], 0)) == PLUS
+ && SYMBOLIC_CONST_P (XEXP (XEXP (operands[1], 0), 0)))
+ {
+ temp = !can_create_pseudo_p () ? operands[0] : gen_reg_rtx (Pmode);
+ temp = mn10300_legitimize_pic_address (XEXP (XEXP (operands[1], 0), 0),
+ temp);
+ operands[1] = expand_binop (SImode, add_optab, temp,
+ XEXP (XEXP (operands[1], 0), 1),
+ (!can_create_pseudo_p ()
+ ? temp
+ : gen_reg_rtx (Pmode)),
+ 0, OPTAB_LIB_WIDEN);
+ }
+ }
+})
+
+(define_insn "*movsi_internal"
+ [(set (match_operand:SI 0 "nonimmediate_operand"
+ "=r,r,r,r,m,r, A,*y,*y,*z,*d")
+ (match_operand:SI 1 "general_operand"
+ " 0,O,i,r,r,m,*y, A, i,*d,*z"))]
+ "register_operand (operands[0], SImode)
+ || register_operand (operands[1], SImode)"
+{
+ switch (which_alternative)
+ {
+ case 0:
+ return "";
+ case 1: /* imm-reg. */
+ case 2:
+ /* See movhi for a discussion of sizes for 8-bit movu. Note that the
+ 24-bit movu is 6 bytes, which is the same size as the full 32-bit
+ mov form for An and Dn. So again movu is only a win for Rn. */
+ if (TARGET_AM33
+ && CONST_INT_P (operands[1])
+ && REGNO_EXTENDED_P (REGNO (operands[0]), 1))
+ {
+ HOST_WIDE_INT val = INTVAL (operands[1]);
+ if (IN_RANGE (val, 0x80, 0xff)
+ || IN_RANGE (val, 0x800000, 0xffffff))
+ return "movu %1,%0";
+ }
+ /* FALLTHRU */
+ case 3: /* reg-reg */
+ case 4: /* reg-mem */
+ case 5: /* mem-reg */
+ case 6: /* sp-reg */
+ case 7: /* reg-sp */
+ case 8: /* imm-sp */
+ case 9: /* reg-mdr */
+ case 10: /* mdr-reg */
+ return "mov %1,%0";
+ default:
+ gcc_unreachable ();
+ }
+}
+ [(set_attr "isa" "*,*,*,*,*,*,*,*,am33,*,*")
+ (set_attr "liw" "*,either,*,either,*,*,*,*,*,*,*")
+ (set_attr "liw_op" "mov")
+ (set_attr_alternative "timings"
+ [(const_int 11)
+ (const_int 22)
+ (const_int 22)
+ (const_int 11)
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 11) (const_int 22))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 24))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 11) (const_int 22))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 24))
+ (const_int 11)
+ (const_int 11)
+ (const_int 11)
+ ])]
+)
+
+(define_expand "movsf"
+ [(set (match_operand:SF 0 "nonimmediate_operand")
+ (match_operand:SF 1 "general_operand"))]
+ "TARGET_AM33_2"
+{
+ /* One of the ops has to be in a register. */
+ if (!register_operand (operand1, SFmode)
+ && !register_operand (operand0, SFmode))
+ operands[1] = force_reg (SFmode, operand1);
+})
+
+(define_insn "*movsf_internal"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=rf,r,f,r,f,r,f,r,m,f,Q")
+ (match_operand:SF 1 "general_operand" " 0,F,F,r,f,f,r,m,r,Q,f"))]
+ "TARGET_AM33_2
+ && (register_operand (operands[0], SFmode)
+ || register_operand (operands[1], SFmode))"
+{
+ switch (which_alternative)
+ {
+ case 0:
+ return "";
+ case 1:
+ case 3:
+ case 7:
+ case 8:
+ return "mov %1,%0";
+ case 2:
+ case 4:
+ case 5:
+ case 6:
+ case 9:
+ case 10:
+ return "fmov %1,%0";
+ default:
+ gcc_unreachable ();
+ }
+}
+ [(set_attr_alternative "timings"
+ [(const_int 11)
+ (const_int 22)
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 47) (const_int 25))
+ (const_int 11)
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 14))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 12))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 14))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 24))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 24))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 24))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 24))
+ ])]
+)
+
+;; If the flags register is not live, generate CLR instead of MOV 0.
+;; For MN103, this is only legal for DATA_REGS; for AM33 this is legal
+;; but not a win for ADDRESS_REGS.
+(define_peephole2
+ [(set (match_operand:INT 0 "register_operand" "") (const_int 0))]
+ "peep2_regno_dead_p (0, CC_REG)
+ && (REGNO_DATA_P (REGNO (operands[0]), 1)
+ || REGNO_EXTENDED_P (REGNO (operands[0]), 1))"
+ [(parallel [(set (match_dup 0) (const_int 0))
+ (clobber (reg:CC CC_REG))])]
+)
+
+(define_insn "*mov<mode>_clr"
+ [(set (match_operand:INT 0 "register_operand" "=D")
+ (const_int 0))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "clr %0"
+)
+
+;; ----------------------------------------------------------------------
+;; ADD INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+(define_insn "addsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,!*y,!r")
+ (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0, 0, r")
+ (match_operand:SI 2 "nonmemory_operand" "r,O,i, i, r")))
+ (clobber (reg:CC CC_REG))]
+ ""
+ { return mn10300_output_add (operands, false); }
+ [(set_attr "timings" "11,11,11,11,22")
+ (set_attr "liw" "either,either,*,*,*")
+ (set_attr "liw_op" "add")]
+)
+
+;; Note that ADD IMM,SP does not set the flags, so omit that here.
+(define_insn "*addsi3_flags"
+ [(set (match_operand:SI 0 "register_operand" "=r,!r")
+ (plus:SI (match_operand:SI 1 "register_operand" "%0, r")
+ (match_operand:SI 2 "nonmemory_operand" "ri, r")))
+ (set (reg CC_REG)
+ (compare (plus:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))]
+ "reload_completed && mn10300_match_ccmode (insn, CCZNCmode)"
+ { return mn10300_output_add (operands, true); }
+ [(set_attr "timings" "11,22")]
+)
+
+;; A helper to expand the above, with the CC_MODE filled in.
+(define_expand "addsi3_flags"
+ [(parallel [(set (match_operand:SI 0 "register_operand")
+ (plus:SI (match_operand:SI 1 "register_operand")
+ (match_operand:SI 2 "nonmemory_operand")))
+ (set (reg:CCZNC CC_REG)
+ (compare:CCZNC (plus:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))])]
+ ""
+)
+
+(define_insn "addc_internal"
+ [(set (match_operand:SI 0 "register_operand" "=D,r,r")
+ (plus:SI
+ (plus:SI
+ (ltu:SI (reg:CC CC_REG) (const_int 0))
+ (match_operand:SI 1 "register_operand" "%0,0,r"))
+ (match_operand:SI 2 "reg_or_am33_const_operand" " D,i,r")))
+ (clobber (reg:CC CC_REG))]
+ "reload_completed"
+ "@
+ addc %2,%0
+ addc %2,%0
+ addc %2,%1,%0"
+ [(set_attr "isa" "*,am33,am33")]
+)
+
+(define_expand "adddi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "nonmemory_operand" "")))]
+ ""
+{
+ rtx op0l, op0h, op1l, op1h, op2l, op2h;
+
+ op0l = gen_lowpart (SImode, operands[0]);
+ op1l = gen_lowpart (SImode, operands[1]);
+ op2l = gen_lowpart (SImode, operands[2]);
+ op0h = gen_highpart (SImode, operands[0]);
+ op1h = gen_highpart (SImode, operands[1]);
+ op2h = gen_highpart_mode (SImode, DImode, operands[2]);
+
+ if (!reg_or_am33_const_operand (op2h, SImode))
+ op2h = force_reg (SImode, op2h);
+
+ emit_insn (gen_adddi3_internal (op0l, op0h, op1l, op2l, op1h, op2h));
+ DONE;
+})
+
+;; Note that reload only supports one commutative operand. Thus we cannot
+;; auto-swap both the high and low outputs with their matching constraints.
+;; For MN103, we're strapped for registers but thankfully the alternatives
+;; are few. For AM33, it becomes much easier to not represent the early
+;; clobber and 6 permutations of immediate and three-operand adds, but
+;; instead allocate a scratch register and do the expansion by hand.
+
+(define_insn_and_split "adddi3_internal"
+ [(set (match_operand:SI 0 "register_operand" "=r, r, r")
+ (plus:SI (match_operand:SI 2 "register_operand" "%0, 0, r")
+ (match_operand:SI 3 "nonmemory_operand" "ri,ri,ri")))
+ (set (match_operand:SI 1 "register_operand" "=D, D, r")
+ (plus:SI
+ (plus:SI
+ (ltu:SI (plus:SI (match_dup 2) (match_dup 3)) (match_dup 2))
+ (match_operand:SI 4 "register_operand" " 1, D, r"))
+ (match_operand:SI 5 "reg_or_am33_const_operand" " D, 1,ri")))
+ (clobber (match_scratch:SI 6 "=X, X,&r"))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+{
+ rtx op0l = operands[0];
+ rtx op0h = operands[1];
+ rtx op1l = operands[2];
+ rtx op2l = operands[3];
+ rtx op1h = operands[4];
+ rtx op2h = operands[5];
+ rtx scratch = operands[6];
+ rtx x;
+
+ if (reg_overlap_mentioned_p (op0l, op1h))
+ {
+ emit_move_insn (scratch, op0l);
+ op1h = scratch;
+ if (reg_overlap_mentioned_p (op0l, op2h))
+ op2h = scratch;
+ }
+ else if (reg_overlap_mentioned_p (op0l, op2h))
+ {
+ emit_move_insn (scratch, op0l);
+ op2h = scratch;
+ }
+
+ if (rtx_equal_p (op0l, op1l))
+ ;
+ else if (rtx_equal_p (op0l, op2l))
+ x = op1l, op1l = op2l, op2l = x;
+ else
+ {
+ gcc_assert (TARGET_AM33);
+ if (!REG_P (op2l))
+ {
+ emit_move_insn (op0l, op2l);
+ op2l = op1l;
+ op1l = op0l;
+ }
+ }
+ emit_insn (gen_addsi3_flags (op0l, op1l, op2l));
+
+ if (rtx_equal_p (op0h, op1h))
+ ;
+ else if (rtx_equal_p (op0h, op2h))
+ x = op1h, op1h = op2h, op2h = x;
+ else
+ {
+ gcc_assert (TARGET_AM33);
+ if (!REG_P (op2h))
+ {
+ emit_move_insn (op0h, op2h);
+ op2h = op1h;
+ op1h = op0h;
+ }
+ }
+ emit_insn (gen_addc_internal (op0h, op1h, op2h));
+ DONE;
+}
+ [(set_attr "isa" "*,*,am33")]
+)
+
+;; The following pattern is generated by combine when it proves that one
+;; of the inputs to the low-part of the double-word add is zero, and thus
+;; no carry is generated into the high-part.
+
+(define_insn_and_split "*adddi3_degenerate"
+ [(set (match_operand:SI 0 "register_operand" "=&r,&r")
+ (match_operand:SI 2 "nonmemory_operand" " 0, 0"))
+ (set (match_operand:SI 1 "register_operand" "=r , r")
+ (plus:SI (match_operand:SI 3 "register_operand" "%1 , r")
+ (match_operand:SI 4 "nonmemory_operand" "ri, r")))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "#"
+ ""
+ [(const_int 0)]
+{
+ rtx scratch = NULL_RTX;
+ if (!rtx_equal_p (operands[0], operands[2]))
+ {
+ gcc_assert (!reg_overlap_mentioned_p (operands[0], operands[1]));
+ if (reg_overlap_mentioned_p (operands[0], operands[3])
+ || reg_overlap_mentioned_p (operands[0], operands[4]))
+ {
+ scratch = gen_reg_rtx (SImode);
+ emit_move_insn (scratch, operands[2]);
+ }
+ else
+ emit_move_insn (operands[0], operands[2]);
+ }
+ emit_insn (gen_addsi3 (operands[1], operands[3], operands[4]));
+ if (scratch)
+ emit_move_insn (operands[0], scratch);
+ DONE;
+})
+
+;; ----------------------------------------------------------------------
+;; SUBTRACT INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+(define_insn "subsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+ (minus:SI (match_operand:SI 1 "register_operand" "0,0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" "r,O,i,r")))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "@
+ sub %2,%0
+ sub %2,%0
+ sub %2,%0
+ sub %2,%1,%0"
+ [(set_attr "isa" "*,*,*,am33")
+ (set_attr "liw" "either,either,*,*")
+ (set_attr "liw_op" "sub")
+ (set_attr "timings" "11,11,11,22")]
+)
+
+(define_insn "*subsi3_flags"
+ [(set (match_operand:SI 0 "register_operand" "=r, r")
+ (minus:SI (match_operand:SI 1 "register_operand" "0, r")
+ (match_operand:SI 2 "nonmemory_operand" "ri,r")))
+ (set (reg CC_REG)
+ (compare (minus:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))]
+ "reload_completed && mn10300_match_ccmode (insn, CCZNCmode)"
+ "@
+ sub %2,%0
+ sub %2,%1,%0"
+ [(set_attr "isa" "*,am33")
+ (set_attr "timings" "11,22")]
+)
+
+;; A helper to expand the above, with the CC_MODE filled in.
+(define_expand "subsi3_flags"
+ [(parallel [(set (match_operand:SI 0 "register_operand")
+ (minus:SI (match_operand:SI 1 "register_operand")
+ (match_operand:SI 2 "nonmemory_operand")))
+ (set (reg:CCZNC CC_REG)
+ (compare:CCZNC (minus:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))])]
+ ""
+)
+
+(define_insn "subc_internal"
+ [(set (match_operand:SI 0 "register_operand" "=D,r,r")
+ (minus:SI
+ (minus:SI (match_operand:SI 1 "register_operand" " 0,0,r")
+ (match_operand:SI 2 "reg_or_am33_const_operand" " D,i,r"))
+ (geu:SI (reg:CC CC_REG) (const_int 0))))
+ (clobber (reg:CC CC_REG))]
+ "reload_completed"
+ "@
+ subc %2,%0
+ subc %2,%0
+ subc %2,%1,%0"
+ [(set_attr "isa" "*,am33,am33")]
+)
+
+(define_expand "subdi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (minus:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "nonmemory_operand" "")))]
+ ""
+{
+ rtx op0l, op0h, op1l, op1h, op2l, op2h;
+
+ op0l = gen_lowpart (SImode, operands[0]);
+ op1l = gen_lowpart (SImode, operands[1]);
+ op2l = gen_lowpart (SImode, operands[2]);
+ op0h = gen_highpart (SImode, operands[0]);
+ op1h = gen_highpart (SImode, operands[1]);
+ op2h = gen_highpart_mode (SImode, DImode, operands[2]);
+
+ if (!reg_or_am33_const_operand (op2h, SImode))
+ op2h = force_reg (SImode, op2h);
+
+ emit_insn (gen_subdi3_internal (op0l, op0h, op1l, op1h, op2l, op2h));
+ DONE;
+})
+
+;; As with adddi3, the use of the scratch register helps reduce the
+;; number of permutations for AM33.
+;; ??? The early clobber on op0 avoids a reload bug wherein both output
+;; registers are set the same. Consider negate, where both op2 and op3
+;; are 0, are csed to the same input register, and reload fails to undo
+;; the cse when satisfying the matching constraints.
+
+(define_insn_and_split "subdi3_internal"
+ [(set (match_operand:SI 0 "register_operand" "=&r, r")
+ (minus:SI
+ (match_operand:SI 2 "register_operand" " 0, r")
+ (match_operand:SI 4 "nonmemory_operand" " ri,ri")))
+ (set (match_operand:SI 1 "register_operand" "=D , r")
+ (minus:SI
+ (minus:SI
+ (match_operand:SI 3 "register_operand" " 1, r")
+ (match_operand:SI 5 "reg_or_am33_const_operand" " D,ri"))
+ (ltu:SI (match_dup 2) (match_dup 4))))
+ (clobber (match_scratch:SI 6 "=X ,&r"))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+{
+ rtx op0l = operands[0];
+ rtx op0h = operands[1];
+ rtx op1l = operands[2];
+ rtx op1h = operands[3];
+ rtx op2l = operands[4];
+ rtx op2h = operands[5];
+ rtx scratch = operands[6];
+
+ if (reg_overlap_mentioned_p (op0l, op1h))
+ {
+ emit_move_insn (scratch, op0l);
+ op1h = scratch;
+ if (reg_overlap_mentioned_p (op0l, op2h))
+ op2h = scratch;
+ }
+ else if (reg_overlap_mentioned_p (op0l, op2h))
+ {
+ emit_move_insn (scratch, op0l);
+ op2h = scratch;
+ }
+
+ if (!rtx_equal_p (op0l, op1l))
+ {
+ gcc_assert (TARGET_AM33);
+ if (!REG_P (op2l))
+ {
+ emit_move_insn (op0l, op1l);
+ op1l = op0l;
+ }
+ }
+ emit_insn (gen_subsi3_flags (op0l, op1l, op2l));
+
+ if (!rtx_equal_p (op0h, op1h))
+ {
+ gcc_assert (TARGET_AM33);
+ if (!REG_P (op2h))
+ {
+ emit_move_insn (op0h, op1h);
+ op1h = op0h;
+ }
+ }
+ emit_insn (gen_subc_internal (op0h, op1h, op2h));
+ DONE;
+}
+ [(set_attr "isa" "*,am33")]
+)
+
+;; The following pattern is generated by combine when it proves that one
+;; of the inputs to the low-part of the double-word sub is zero, and thus
+;; no carry is generated into the high-part.
+
+(define_insn_and_split "*subdi3_degenerate"
+ [(set (match_operand:SI 0 "register_operand" "=&r,&r")
+ (match_operand:SI 2 "nonmemory_operand" " 0, 0"))
+ (set (match_operand:SI 1 "register_operand" "=r , r")
+ (minus:SI (match_operand:SI 3 "register_operand" " 1, r")
+ (match_operand:SI 4 "nonmemory_operand" " ri, r")))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "#"
+ ""
+ [(const_int 0)]
+{
+ rtx scratch = NULL_RTX;
+ if (!rtx_equal_p (operands[0], operands[2]))
+ {
+ gcc_assert (!reg_overlap_mentioned_p (operands[0], operands[1]));
+ if (reg_overlap_mentioned_p (operands[0], operands[3])
+ || reg_overlap_mentioned_p (operands[0], operands[4]))
+ {
+ scratch = gen_reg_rtx (SImode);
+ emit_move_insn (scratch, operands[2]);
+ }
+ else
+ emit_move_insn (operands[0], operands[2]);
+ }
+ emit_insn (gen_subsi3 (operands[1], operands[3], operands[4]));
+ if (scratch)
+ emit_move_insn (operands[0], scratch);
+ DONE;
+})
+
+(define_insn_and_split "negsi2"
+ [(set (match_operand:SI 0 "register_operand" "=D,&r")
+ (neg:SI (match_operand:SI 1 "register_operand" " 0, r")))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
+{
+ /* Recall that twos-compliment is ones-compliment plus one. When
+ allocated in DATA_REGS this is 2+1 bytes; otherwise (for am33)
+ this is 3+3 bytes.
+
+ For AM33, it would have been possible to load zero and use the
+ three-address subtract to have a total size of 3+4*N bytes for
+ multiple negations, plus increased throughput. Not attempted here. */
+
+ if (true_regnum (operands[0]) == true_regnum (operands[1]))
+ {
+ emit_insn (gen_one_cmplsi2 (operands[0], operands[0]));
+ emit_insn (gen_addsi3 (operands[0], operands[0], const1_rtx));
+ }
+ else
+ {
+ emit_move_insn (operands[0], const0_rtx);
+ emit_insn (gen_subsi3 (operands[0], operands[0], operands[1]));
+ }
+ DONE;
+})
+
+;; ----------------------------------------------------------------------
+;; MULTIPLY INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+;; ??? Note that AM33 has a third multiply variant that puts the high part
+;; into the MDRQ register, however this variant also constrains the inputs
+;; to be in DATA_REGS and thus isn't as helpful as it might be considering
+;; the existance of the 4-operand multiply. Nor is there a set of divide
+;; insns that use MDRQ. Given that there is an IMM->MDRQ insn, this would
+;; have been very handy for starting udivmodsi4...
+
+(define_expand "mulsidi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" ""))
+ (sign_extend:DI (match_operand:SI 2 "register_operand" ""))))]
+ ""
+{
+ emit_insn (gen_mulsidi3_internal (gen_lowpart (SImode, operands[0]),
+ gen_highpart (SImode, operands[0]),
+ operands[1], operands[2]));
+ DONE;
+})
+
+(define_insn "mulsidi3_internal"
+ [(set (match_operand:SI 0 "register_operand" "=D,r")
+ (mult:SI (match_operand:SI 2 "register_operand" "%0,r")
+ (match_operand:SI 3 "register_operand" " D,r")))
+ (set (match_operand:SI 1 "register_operand" "=z,r")
+ (truncate:SI
+ (ashiftrt:DI
+ (mult:DI (sign_extend:DI (match_dup 2))
+ (sign_extend:DI (match_dup 3)))
+ (const_int 32))))
+ (clobber (reg:CC CC_REG))]
+ ""
+{
+ if (which_alternative == 1)
+ return "mul %2,%3,%1,%0";
+ else if (TARGET_MULT_BUG)
+ return "nop\;nop\;mul %3,%0";
+ else
+ return "mul %3,%0";
+}
+ [(set_attr "isa" "*,am33")
+ (set (attr "timings")
+ (if_then_else (eq_attr "cpu" "am34") (const_int 24) (const_int 23)))]
+)
+
+(define_expand "umulsidi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" ""))
+ (zero_extend:DI (match_operand:SI 2 "register_operand" ""))))
+ (clobber (reg:CC CC_REG))]
+ ""
+{
+ emit_insn (gen_umulsidi3_internal (gen_lowpart (SImode, operands[0]),
+ gen_highpart (SImode, operands[0]),
+ operands[1], operands[2]));
+ DONE;
+})
+
+(define_insn "umulsidi3_internal"
+ [(set (match_operand:SI 0 "register_operand" "=D,r")
+ (mult:SI (match_operand:SI 2 "register_operand" "%0,r")
+ (match_operand:SI 3 "register_operand" " D,r")))
+ (set (match_operand:SI 1 "register_operand" "=z,r")
+ (truncate:SI
+ (lshiftrt:DI
+ (mult:DI (zero_extend:DI (match_dup 2))
+ (zero_extend:DI (match_dup 3)))
+ (const_int 32))))
+ (clobber (reg:CC CC_REG))]
+ ""
+{
+ if (which_alternative == 1)
+ return "mulu %2,%3,%1,%0";
+ else if (TARGET_MULT_BUG)
+ return "nop\;nop\;mulu %3,%0";
+ else
+ return "mulu %3,%0";
+}
+ [(set_attr "isa" "*,am33")
+ (set (attr "timings")
+ (if_then_else (eq_attr "cpu" "am34") (const_int 24) (const_int 23)))]
+)
+
+(define_expand "mulsi3"
+ [(parallel [(set (match_operand:SI 0 "register_operand")
+ (mult:SI (match_operand:SI 1 "register_operand")
+ (match_operand:SI 2 "reg_or_am33_const_operand")))
+ (clobber (match_scratch:SI 3))
+ (clobber (reg:CC CC_REG))])]
+ ""
+)
+
+(define_insn "*mulsi3"
+ [(set (match_operand:SI 0 "register_operand" "=D, r,r")
+ (mult:SI (match_operand:SI 2 "register_operand" "%0, 0,r")
+ (match_operand:SI 3 "reg_or_am33_const_operand" " D,ri,r")))
+ (clobber (match_scratch:SI 1 "=z, z,r"))
+ (clobber (reg:CC CC_REG))]
+ ""
+{
+ if (which_alternative == 2)
+ return "mul %2,%3,%1,%0";
+ else if (TARGET_MULT_BUG)
+ return "nop\;nop\;mul %3,%0";
+ else
+ return "mul %3,%0";
+}
+ [(set_attr "isa" "*,am33,am33")
+ (set (attr "timings")
+ (if_then_else (eq_attr "cpu" "am34") (const_int 24) (const_int 23)))]
+)
+
+(define_expand "udivmodsi4"
+ [(parallel [(set (match_operand:SI 0 "register_operand")
+ (udiv:SI (match_operand:SI 1 "register_operand")
+ (match_operand:SI 2 "register_operand")))
+ (set (match_operand:SI 3 "register_operand")
+ (umod:SI (match_dup 1) (match_dup 2)))
+ (use (const_int 0))
+ (clobber (reg:CC CC_REG))])]
+ ""
+)
+
+;; Note the trick to get reload to put the zero into the MDR register,
+;; rather than exposing the load early and letting CSE or someone try
+;; to share the zeros between division insns. Which tends to result
+;; in sequences like 0->r0->d0->mdr.
+
+(define_insn "*udivmodsi4"
+ [(set (match_operand:SI 0 "register_operand" "=D")
+ (udiv:SI (match_operand:SI 2 "register_operand" " 0")
+ (match_operand:SI 3 "register_operand" " D")))
+ (set (match_operand:SI 1 "register_operand" "=z")
+ (umod:SI (match_dup 2) (match_dup 3)))
+ (use (match_operand:SI 4 "nonmemory_operand" " 1"))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "divu %3,%0"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 3839) (const_int 4243)))]
+)
+
+(define_expand "divmodsi4"
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (div:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))
+ (set (match_operand:SI 3 "register_operand" "")
+ (mod:SI (match_dup 1) (match_dup 2)))
+ (use (match_dup 4))
+ (clobber (reg:CC CC_REG))])]
+ ""
+{
+ operands[4] = gen_reg_rtx (SImode);
+ emit_insn (gen_ext_internal (operands[4], operands[1]));
+})
+
+;; ??? Ideally we'd represent this via shift, but it seems like adding a
+;; special-case pattern for (ashiftrt x 31) is just as likely to result
+;; in poor register allocation choices.
+(define_insn "ext_internal"
+ [(set (match_operand:SI 0 "register_operand" "=z")
+ (unspec:SI [(match_operand:SI 1 "register_operand" "D")] UNSPEC_EXT))]
+ ""
+ "ext %1"
+)
+
+(define_insn "*divmodsi4"
+ [(set (match_operand:SI 0 "register_operand" "=D")
+ (div:SI (match_operand:SI 2 "register_operand" " 0")
+ (match_operand:SI 3 "register_operand" " D")))
+ (set (match_operand:SI 1 "register_operand" "=z")
+ (mod:SI (match_dup 2) (match_dup 3)))
+ (use (match_operand:SI 4 "register_operand" " 1"))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "div %3,%0";
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 3839) (const_int 4243)))]
+)
+
+
+;; ----------------------------------------------------------------------
+;; AND INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+(define_insn "andsi3"
+ [(set (match_operand:SI 0 "register_operand" "=D,D,r")
+ (and:SI (match_operand:SI 1 "register_operand" "%0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" " i,D,r")))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "@
+ and %2,%0
+ and %2,%0
+ and %2,%1,%0"
+ [(set_attr "isa" "*,*,am33")
+ (set_attr "liw" "*,op1,*")
+ (set_attr "liw_op" "and")
+ (set_attr "timings" "22,11,11")]
+)
+
+(define_insn "*andsi3_flags"
+ [(set (match_operand:SI 0 "register_operand" "=D,D,r")
+ (and:SI (match_operand:SI 1 "register_operand" "%0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" " i,D,r")))
+ (set (reg CC_REG)
+ (compare (and:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))]
+ "reload_completed && mn10300_match_ccmode (insn, CCZNmode)"
+ "@
+ and %2,%0
+ and %2,%0
+ and %2,%1,%0"
+ [(set_attr "isa" "*,*,am33")
+ (set_attr "timings" "22,11,11")]
+)
+
+;; Make sure we generate extensions instead of ANDs.
+
+(define_split
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (and:SI (match_operand:SI 1 "register_operand" "")
+ (const_int 255)))
+ (clobber (reg:CC CC_REG))])]
+ ""
+ [(set (match_dup 0) (zero_extend:SI (match_dup 1)))]
+ { operands[1] = gen_lowpart (QImode, operands[1]); }
+)
+
+(define_split
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (and:SI (match_operand:SI 1 "register_operand" "")
+ (const_int 65535)))
+ (clobber (reg:CC CC_REG))])]
+ ""
+ [(set (match_dup 0) (zero_extend:SI (match_dup 1)))]
+ { operands[1] = gen_lowpart (HImode, operands[1]); }
+)
+
+;; Split AND by an appropriate constant into two shifts. Recall that
+;; operations with a full 32-bit immediate require an extra cycle, so
+;; this is a size optimization with no speed penalty. This only applies
+;; do DATA_REGS; the shift insns that AM33 adds are too large for a win.
+
+(define_split
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (and:SI (match_dup 0)
+ (match_operand:SI 1 "const_int_operand" "")))
+ (clobber (reg:CC CC_REG))])]
+ "reload_completed
+ && REGNO_DATA_P (true_regnum (operands[0]), 1)
+ && mn10300_split_and_operand_count (operands[1]) != 0"
+ [(const_int 0)]
+{
+ int count = mn10300_split_and_operand_count (operands[1]);
+ if (count > 0)
+ {
+ emit_insn (gen_lshrsi3 (operands[0], operands[0], GEN_INT (count)));
+ emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (count)));
+ }
+ else
+ {
+ emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (-count)));
+ emit_insn (gen_lshrsi3 (operands[0], operands[0], GEN_INT (-count)));
+ }
+ DONE;
+})
+
+;; ----------------------------------------------------------------------
+;; OR INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+(define_insn "iorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=D,D,r")
+ (ior:SI (match_operand:SI 1 "register_operand" "%0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" " i,D,r")))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "@
+ or %2,%0
+ or %2,%0
+ or %2,%1,%0"
+ [(set_attr "isa" "*,*,am33")
+ (set_attr "liw" "*,op1,*")
+ (set_attr "liw_op" "or")
+ (set_attr "timings" "22,11,11")]
+)
+
+(define_insn "*iorsi3_flags"
+ [(set (match_operand:SI 0 "register_operand" "=D,D,r")
+ (ior:SI (match_operand:SI 1 "register_operand" "%0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" " i,D,r")))
+ (set (reg CC_REG)
+ (compare (ior:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))]
+ "reload_completed && mn10300_match_ccmode (insn, CCZNmode)"
+ "@
+ or %2,%0
+ or %2,%0
+ or %2,%1,%0"
+ [(set_attr "isa" "*,*,am33")
+ (set_attr "timings" "22,11,11")]
+)
+
+;; ----------------------------------------------------------------------
+;; XOR INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+(define_insn "xorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=D,D,r")
+ (xor:SI (match_operand:SI 1 "register_operand" "%0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" " i,D,r")))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "@
+ xor %2,%0
+ xor %2,%0
+ xor %2,%1,%0"
+ [(set_attr "isa" "*,*,am33")
+ (set_attr "liw" "*,op1,*")
+ (set_attr "liw_op" "xor")
+ (set_attr "timings" "22,11,11")]
+)
+
+(define_insn "*xorsi3_flags"
+ [(set (match_operand:SI 0 "register_operand" "=D,D,r")
+ (xor:SI (match_operand:SI 1 "register_operand" "%0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" " i,D,r")))
+ (set (reg CC_REG)
+ (compare (xor:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))]
+ "reload_completed && mn10300_match_ccmode (insn, CCZNmode)"
+ "@
+ xor %2,%0
+ xor %2,%0
+ xor %2,%1,%0"
+ [(set_attr "isa" "*,*,am33")
+ (set_attr "timings" "22,11,11")]
+)
+
+;; ----------------------------------------------------------------------
+;; NOT INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+(define_insn "one_cmplsi2"
+ [(set (match_operand:SI 0 "register_operand" "=D")
+ (not:SI (match_operand:SI 1 "register_operand" " 0")))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "not %0"
+)
+
+(define_insn "*one_cmplsi2_flags"
+ [(set (match_operand:SI 0 "register_operand" "=D")
+ (not:SI (match_operand:SI 1 "register_operand" " 0")))
+ (set (reg CC_REG)
+ (compare (not:SI (match_dup 1))
+ (const_int 0)))]
+ "reload_completed && mn10300_match_ccmode (insn, CCZNmode)"
+ "not %0"
+)
+
+;; ----------------------------------------------------------------------
+;; COMPARE AND BRANCH INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+;; We expand the comparison into a single insn so that it will not be split
+;; up by reload.
+(define_expand "cbranchsi4"
+ [(set (pc)
+ (if_then_else
+ (match_operator 0 "ordered_comparison_operator"
+ [(match_operand:SI 1 "register_operand")
+ (match_operand:SI 2 "nonmemory_operand")])
+ (label_ref (match_operand 3 ""))
+ (pc)))]
+ ""
+ ""
+)
+
+(define_insn_and_split "*cbranchsi4_cmp"
+ [(set (pc)
+ (if_then_else (match_operator 3 "ordered_comparison_operator"
+ [(match_operand:SI 0 "register_operand" "r")
+ (match_operand:SI 1 "nonmemory_operand" "ri")])
+ (match_operand 2 "label_ref_operand" "")
+ (pc)))]
+ ""
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+{
+ mn10300_split_cbranch (CCmode, operands[3], operands[2]);
+ DONE;
+})
+
+(define_insn "*cmpsi"
+ [(set (reg CC_REG)
+ (compare (match_operand:SI 0 "register_operand" "r,r,r")
+ (match_operand:SI 1 "nonmemory_operand" "r,O,i")))]
+ "reload_completed"
+{
+ /* The operands of CMP must be distinct registers. In the case where
+ we've failed to optimize the comparison of a register to itself, we
+ must use another method to set the Z flag. We can achieve this
+ effect with a BTST 0,D0. This will not alter the contents of D0;
+ the use of d0 is arbitrary; any data register would work. */
+ if (rtx_equal_p (operands[0], operands[1]))
+ return "btst 0,d0";
+ else
+ return "cmp %1,%0";
+}
+ [(set_attr_alternative "timings"
+ [(if_then_else (eq_attr "cpu" "am34") (const_int 11) (const_int 22))
+ (if_then_else (eq_attr "cpu" "am34") (const_int 11) (const_int 22))
+ (if_then_else (eq_attr "cpu" "am34") (const_int 11) (const_int 22))])
+ (set_attr "liw" "either,either,*")
+ (set_attr "liw_op" "cmp")]
+)
+
+(define_insn "*integer_conditional_branch"
+ [(set (pc)
+ (if_then_else (match_operator 0 "comparison_operator"
+ [(match_operand 2 "int_mode_flags" "")
+ (const_int 0)])
+ (label_ref (match_operand 1 "" ""))
+ (pc)))]
+ "reload_completed"
+ "b%b0 %1"
+)
+
+(define_insn_and_split "*cbranchsi4_btst"
+ [(set (pc)
+ (if_then_else
+ (match_operator 3 "CCZN_comparison_operator"
+ [(and:SI (match_operand:SI 0 "register_operand" "D")
+ (match_operand:SI 1 "immediate_operand" "i"))
+ (const_int 0)])
+ (match_operand 2 "label_ref_operand" "")
+ (pc)))]
+ ""
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+{
+ mn10300_split_cbranch (CCZNmode, operands[3], operands[2]);
+ DONE;
+})
+
+(define_insn "*btstsi"
+ [(set (reg:CCZN CC_REG)
+ (compare:CCZN
+ (and:SI (match_operand:SI 0 "register_operand" "D")
+ (match_operand:SI 1 "immediate_operand" "i"))
+ (const_int 0)))]
+ "reload_completed"
+ "btst %1,%0"
+)
+
+(define_expand "cbranchsf4"
+ [(set (pc)
+ (if_then_else
+ (match_operator 0 "ordered_comparison_operator"
+ [(match_operand:SF 1 "register_operand")
+ (match_operand:SF 2 "nonmemory_operand")])
+ (label_ref (match_operand 3 ""))
+ (pc)))]
+ "TARGET_AM33_2"
+ ""
+)
+
+(define_insn_and_split "*cbranchsf4_cmp"
+ [(set (pc)
+ (if_then_else (match_operator 3 "ordered_comparison_operator"
+ [(match_operand:SF 0 "register_operand" "f")
+ (match_operand:SF 1 "nonmemory_operand" "fF")])
+ (match_operand 2 "label_ref_operand" "")
+ (pc)))
+ ]
+ "TARGET_AM33_2"
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
+{
+ mn10300_split_cbranch (CC_FLOATmode, operands[3], operands[2]);
+ DONE;
+})
+
+(define_insn "*am33_cmpsf"
+ [(set (reg:CC_FLOAT CC_REG)
+ (compare:CC_FLOAT (match_operand:SF 0 "register_operand" "f")
+ (match_operand:SF 1 "nonmemory_operand" "fF")))]
+ "TARGET_AM33_2 && reload_completed"
+ "fcmp %1, %0"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 25)))]
+)
+
+(define_insn "*float_conditional_branch"
+ [(set (pc)
+ (if_then_else (match_operator 0 "comparison_operator"
+ [(reg:CC_FLOAT CC_REG) (const_int 0)])
+ (label_ref (match_operand 1 "" ""))
+ (pc)))]
+ "TARGET_AM33_2 && reload_completed"
+ "fb%b0 %1"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 44) (const_int 33)))]
+)
+
+;; Unconditional and other jump instructions.
+
+(define_insn "jump"
+ [(set (pc)
+ (label_ref (match_operand 0 "" "")))]
+ ""
+ "jmp %l0"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 11) (const_int 44)))]
+)
+
+(define_insn "indirect_jump"
+ [(set (pc) (match_operand:SI 0 "register_operand" "a"))]
+ ""
+ "jmp (%0)"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 11) (const_int 33)))]
+)
+
+(define_expand "builtin_setjmp_receiver"
+ [(match_operand 0 "" "")]
+ "flag_pic"
+{
+ emit_insn (gen_load_pic ());
+ DONE;
+})
+
+(define_expand "casesi"
+ [(match_operand:SI 0 "register_operand")
+ (match_operand:SI 1 "immediate_operand")
+ (match_operand:SI 2 "immediate_operand")
+ (match_operand 3 "" "") (match_operand 4 "")]
+ ""
+{
+ rtx table = gen_reg_rtx (SImode);
+ rtx index = gen_reg_rtx (SImode);
+ rtx addr = gen_reg_rtx (Pmode);
+ rtx test;
+
+ emit_move_insn (table, gen_rtx_LABEL_REF (VOIDmode, operands[3]));
+ emit_insn (gen_addsi3 (index, operands[0], GEN_INT (- INTVAL (operands[1]))));
+ test = gen_rtx_fmt_ee (GTU, VOIDmode, index, operands[2]);
+ emit_jump_insn (gen_cbranchsi4 (test, index, operands[2], operands[4]));
+
+ emit_insn (gen_ashlsi3 (index, index, const2_rtx));
+ emit_move_insn (addr, gen_rtx_MEM (SImode,
+ gen_rtx_PLUS (SImode, table, index)));
+ if (flag_pic)
+ emit_insn (gen_addsi3 (addr, addr, table));
+
+ emit_jump_insn (gen_tablejump (addr, operands[3]));
+ DONE;
+})
+
+(define_insn "tablejump"
+ [(set (pc) (match_operand:SI 0 "register_operand" "a"))
+ (use (label_ref (match_operand 1 "" "")))]
+ ""
+ "jmp (%0)"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 11) (const_int 33)))]
+)
+
+;; Call subroutine with no return value.
+
+(define_expand "call"
+ [(call (match_operand:QI 0 "general_operand")
+ (match_operand:SI 1 "general_operand"))]
+ ""
+{
+ rtx fn = XEXP (operands[0], 0);
+
+ if (flag_pic && GET_CODE (fn) == SYMBOL_REF)
+ {
+ if (MN10300_GLOBAL_P (fn))
+ {
+ /* The PLT code won't run on AM30, but then, there's no
+ shared library support for AM30 either, so we just assume
+ the linker is going to adjust all @PLT relocs to the
+ actual symbols. */
+ emit_use (pic_offset_table_rtx);
+ fn = gen_rtx_UNSPEC (SImode, gen_rtvec (1, fn), UNSPEC_PLT);
+ }
+ else
+ fn = gen_rtx_UNSPEC (SImode, gen_rtvec (1, fn), UNSPEC_PIC);
+ }
+ if (! call_address_operand (fn, VOIDmode))
+ fn = force_reg (SImode, fn);
+
+ XEXP (operands[0], 0) = fn;
+})
+
+(define_insn "*call_internal"
+ [(call (mem:QI (match_operand:SI 0 "call_address_operand" "a,S"))
+ (match_operand:SI 1 "" ""))]
+ ""
+ "@
+ calls %C0
+ call %C0,[],0"
+ [(set_attr_alternative "timings"
+ [(if_then_else (eq_attr "cpu" "am34")
+ (const_int 33) (const_int 44))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 55) (const_int 33))
+ ])
+ ]
+)
+
+;; Call subroutine, returning value in operand 0
+;; (which must be a hard register).
+
+(define_expand "call_value"
+ [(set (match_operand 0 "")
+ (call (match_operand:QI 1 "general_operand")
+ (match_operand:SI 2 "general_operand")))]
+ ""
+{
+ rtx fn = XEXP (operands[1], 0);
+
+ if (flag_pic && GET_CODE (fn) == SYMBOL_REF)
+ {
+ if (MN10300_GLOBAL_P (fn))
+ {
+ /* The PLT code won't run on AM30, but then, there's no
+ shared library support for AM30 either, so we just assume
+ the linker is going to adjust all @PLT relocs to the
+ actual symbols. */
+ emit_use (pic_offset_table_rtx);
+ fn = gen_rtx_UNSPEC (SImode, gen_rtvec (1, fn), UNSPEC_PLT);
+ }
+ else
+ fn = gen_rtx_UNSPEC (SImode, gen_rtvec (1, fn), UNSPEC_PIC);
+ }
+ if (! call_address_operand (fn, VOIDmode))
+ fn = force_reg (SImode, fn);
+
+ XEXP (operands[1], 0) = fn;
+})
+
+(define_insn "call_value_internal"
+ [(set (match_operand 0 "" "")
+ (call (mem:QI (match_operand:SI 1 "call_address_operand" "a,S"))
+ (match_operand:SI 2 "" "")))]
+ ""
+ "@
+ calls %C1
+ call %C1,[],0"
+ [(set_attr_alternative "timings"
+ [(if_then_else (eq_attr "cpu" "am34")
+ (const_int 33) (const_int 44))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 55) (const_int 33))
+ ])
+ ]
+)
+
+(define_expand "untyped_call"
+ [(parallel [(call (match_operand 0 "")
+ (const_int 0))
+ (match_operand 1 "")
+ (match_operand 2 "")])]
+ ""
+{
+ int i;
+
+ emit_call_insn (gen_call (operands[0], const0_rtx));
+
+ for (i = 0; i < XVECLEN (operands[2], 0); i++)
+ {
+ rtx set = XVECEXP (operands[2], 0, i);
+ emit_move_insn (SET_DEST (set), SET_SRC (set));
+ }
+ DONE;
+})
+
+(define_insn "nop"
+ [(const_int 0)]
+ ""
+ "nop"
+)
+
+;; ----------------------------------------------------------------------
+;; EXTEND INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+(define_insn "zero_extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "=D,D,r")
+ (zero_extend:SI
+ (match_operand:QI 1 "nonimmediate_operand" " 0,m,r")))]
+ ""
+ "@
+ extbu %0
+ movbu %1,%0
+ extbu %1,%0"
+ [(set_attr "isa" "*,*,am33")
+ (set_attr_alternative "timings"
+ [(const_int 11)
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 24))
+ (const_int 11)
+ ])]
+)
+
+(define_insn "zero_extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "=D,D,r")
+ (zero_extend:SI
+ (match_operand:HI 1 "nonimmediate_operand" " 0,m,r")))]
+ ""
+ "@
+ exthu %0
+ movhu %1,%0
+ exthu %1,%0"
+ [(set_attr "isa" "*,*,am33")
+ (set_attr_alternative "timings"
+ [(const_int 11)
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 24))
+ (const_int 11)])]
+)
+
+(define_insn "extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "=D,r")
+ (sign_extend:SI
+ (match_operand:QI 1 "register_operand" "0,r")))]
+ ""
+ "@
+ extb %0
+ extb %1,%0"
+ [(set_attr "isa" "*,am33")]
+)
+
+(define_insn "extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "=D,r")
+ (sign_extend:SI
+ (match_operand:HI 1 "register_operand" "0,r")))]
+ ""
+ "@
+ exth %0
+ exth %1,%0"
+ [(set_attr "isa" "*,am33")]
+)
+
+;; ----------------------------------------------------------------------
+;; SHIFTS
+;; ----------------------------------------------------------------------
+
+(define_insn "ashlsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,D,d,d,D,D,D,r")
+ (ashift:SI
+ (match_operand:SI 1 "register_operand" " 0,0,0,0,0,0,0,r")
+ (match_operand:QI 2 "nonmemory_operand" " J,K,M,L,D,O,i,r")))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "@
+ add %0,%0
+ asl2 %0
+ asl2 %0\;add %0,%0
+ asl2 %0\;asl2 %0
+ asl %S2,%0
+ asl %S2,%0
+ asl %S2,%0
+ asl %2,%1,%0"
+ [(set_attr "isa" "*,*,*,*,*,*,*,am33")
+ (set_attr "liw" "op2,op2,op2,op2,op2,op2,*,*")
+ (set_attr "liw_op" "asl")
+ (set_attr "timings" "11,11,22,22,11,11,11,11")]
+)
+
+(define_insn "lshrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=D,D,D,r")
+ (lshiftrt:SI
+ (match_operand:SI 1 "register_operand" "0,0,0,r")
+ (match_operand:QI 2 "nonmemory_operand" "D,O,i,r")))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "@
+ lsr %S2,%0
+ lsr %S2,%0
+ lsr %S2,%0
+ lsr %2,%1,%0"
+ [(set_attr "isa" "*,*,*,am33")
+ (set_attr "liw" "op2,op2,*,*")
+ (set_attr "liw_op" "lsr")]
+)
+
+(define_insn "ashrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=D,D,D,r")
+ (ashiftrt:SI
+ (match_operand:SI 1 "register_operand" "0,0,0,r")
+ (match_operand:QI 2 "nonmemory_operand" "D,O,i,r")))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "@
+ asr %S2,%0
+ asr %S2,%0
+ asr %S2,%0
+ asr %2,%1,%0"
+ [(set_attr "isa" "*,*,*,am33")
+ (set_attr "liw" "op2,op2,*,*")
+ (set_attr "liw_op" "asr")]
+)
+
+;; ----------------------------------------------------------------------
+;; MISCELANEOUS
+;; ----------------------------------------------------------------------
+
+(define_expand "clzsi2"
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (unspec:SI [(match_operand:SI 1 "register_operand" "")
+ (const_int 0)] UNSPEC_BSCH))
+ (clobber (reg:CC CC_REG))])]
+ "TARGET_AM33"
+)
+
+(define_insn "*bsch"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "nonmemory_operand" "0")]
+ UNSPEC_BSCH))
+ (clobber (reg:CC CC_REG))]
+ "TARGET_AM33"
+ "bsch %1,%0"
+)
+
+;; ----------------------------------------------------------------------
+;; FP INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+(define_insn "abssf2"
+ [(set (match_operand:SF 0 "register_operand" "=f,f")
+ (abs:SF (match_operand:SF 1 "register_operand" "0,?f")))]
+ "TARGET_AM33_2"
+ "@
+ fabs %0
+ fabs %1, %0"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 14)))]
+)
+
+(define_insn "negsf2"
+ [(set (match_operand:SF 0 "register_operand" "=f,f")
+ (neg:SF (match_operand:SF 1 "register_operand" "0,?f")))]
+ "TARGET_AM33_2"
+ "@
+ fneg %0
+ fneg %1, %0"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 14)))]
+)
+
+(define_expand "sqrtsf2"
+ [(set (match_operand:SF 0 "register_operand" "")
+ (sqrt:SF (match_operand:SF 1 "register_operand" "")))]
+ "TARGET_AM33_2 && flag_unsafe_math_optimizations"
+{
+ rtx scratch = gen_reg_rtx (SFmode);
+ emit_insn (gen_rsqrtsf2 (scratch, operands[1], CONST1_RTX (SFmode)));
+ emit_insn (gen_divsf3 (operands[0], force_reg (SFmode, CONST1_RTX (SFmode)),
+ scratch));
+ DONE;
+})
+
+(define_insn "rsqrtsf2"
+ [(set (match_operand:SF 0 "register_operand" "=f,f")
+ (div:SF (match_operand:SF 2 "const_1f_operand" "F,F")
+ (sqrt:SF (match_operand:SF 1 "register_operand" "0,?f"))))
+ (clobber (reg:CC_FLOAT CC_REG))]
+ "TARGET_AM33_2"
+ "@
+ frsqrt %0
+ frsqrt %1, %0"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 4753) (const_int 2327)))]
+)
+
+(define_insn "addsf3"
+ [(set (match_operand:SF 0 "register_operand" "=f,f")
+ (plus:SF (match_operand:SF 1 "register_operand" "%0,f")
+ (match_operand:SF 2 "nonmemory_operand" "f,?fF")))
+ (clobber (reg:CC_FLOAT CC_REG))]
+ "TARGET_AM33_2"
+ "@
+ fadd %2, %0
+ fadd %2, %1, %0"
+ [(set_attr_alternative "timings"
+ [(if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 14))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 25))
+ ])]
+)
+
+(define_insn "subsf3"
+ [(set (match_operand:SF 0 "register_operand" "=f,f")
+ (minus:SF (match_operand:SF 1 "register_operand" "0,f")
+ (match_operand:SF 2 "nonmemory_operand" "f,?fF")))
+ (clobber (reg:CC_FLOAT CC_REG))]
+ "TARGET_AM33_2"
+ "@
+ fsub %2, %0
+ fsub %2, %1, %0"
+ [(set_attr_alternative "timings"
+ [(if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 14))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 25))
+ ])]
+)
+
+(define_insn "mulsf3"
+ [(set (match_operand:SF 0 "register_operand" "=f,f")
+ (mult:SF (match_operand:SF 1 "register_operand" "%0,f")
+ (match_operand:SF 2 "nonmemory_operand" "f,?fF")))
+ (clobber (reg:CC_FLOAT CC_REG))
+ ]
+ "TARGET_AM33_2"
+ "@
+ fmul %2, %0
+ fmul %2, %1, %0"
+ [(set_attr_alternative "timings"
+ [(if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 14))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 25))
+ ])]
+)
+
+(define_insn "divsf3"
+ [(set (match_operand:SF 0 "register_operand" "=f,f")
+ (div:SF (match_operand:SF 1 "register_operand" "0,f")
+ (match_operand:SF 2 "nonmemory_operand" "f,?fF")))
+ (clobber (reg:CC_FLOAT CC_REG))]
+ "TARGET_AM33_2"
+ "@
+ fdiv %2, %0
+ fdiv %2, %1, %0"
+ [(set_attr_alternative "timings"
+ [(if_then_else (eq_attr "cpu" "am34")
+ (const_int 2531) (const_int 1216))
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 2531) (const_int 1317))
+ ])]
+)
+
+(define_insn "fmasf4"
+ [(set (match_operand:SF 0 "register_operand" "=c")
+ (fma:SF (match_operand:SF 1 "register_operand" "f")
+ (match_operand:SF 2 "register_operand" "f")
+ (match_operand:SF 3 "register_operand" "f")))
+ (clobber (reg:CC_FLOAT CC_REG))
+ ]
+ "TARGET_AM33_2"
+ "fmadd %1, %2, %3, %0"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 24)))]
+)
+
+(define_insn "fmssf4"
+ [(set (match_operand:SF 0 "register_operand" "=c")
+ (fma:SF (match_operand:SF 1 "register_operand" "f")
+ (match_operand:SF 2 "register_operand" "f")
+ (neg:SF (match_operand:SF 3 "register_operand" "f"))))
+ (clobber (reg:CC_FLOAT CC_REG))
+ ]
+ "TARGET_AM33_2"
+ "fmsub %1, %2, %3, %0"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 24)))]
+)
+
+(define_insn "fnmasf4"
+ [(set (match_operand:SF 0 "register_operand" "=c")
+ (fma:SF (neg:SF (match_operand:SF 1 "register_operand" "f"))
+ (match_operand:SF 2 "register_operand" "f")
+ (match_operand:SF 3 "register_operand" "f")))
+ (clobber (reg:CC_FLOAT CC_REG))
+ ]
+ "TARGET_AM33_2"
+ "fnmadd %1, %2, %3, %0"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 24)))]
+)
+
+(define_insn "fnmssf4"
+ [(set (match_operand:SF 0 "register_operand" "=c")
+ (fma:SF (neg:SF (match_operand:SF 1 "register_operand" "f"))
+ (match_operand:SF 2 "register_operand" "f")
+ (neg:SF (match_operand:SF 3 "register_operand" "f"))))
+ (clobber (reg:CC_FLOAT CC_REG))
+ ]
+ "TARGET_AM33_2"
+ "fnmsub %1, %2, %3, %0"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 17) (const_int 24)))]
+)
+
+;; ----------------------------------------------------------------------
+;; PROLOGUE/EPILOGUE
+;; ----------------------------------------------------------------------
+(define_expand "prologue"
+ [(const_int 0)]
+ ""
+ { mn10300_expand_prologue (); DONE; }
+)
+
+(define_expand "epilogue"
+ [(return)]
+ ""
+ { mn10300_expand_epilogue (); DONE; }
+)
+
+(define_insn "return"
+ [(return)]
+ "mn10300_can_use_rets_insn ()"
+{
+ /* The RETF insn is 4 cycles faster than RETS, though 1 byte larger. */
+ if (optimize_insn_for_speed_p () && mn10300_can_use_retf_insn ())
+ return "retf [],0";
+ else
+ return "rets";
+})
+
+(define_insn "return_ret"
+ [(return)
+ (use (match_operand:SI 0 "const_int_operand" ""))]
+ ""
+{
+ /* The RETF insn is up to 3 cycles faster than RET. */
+ fputs ((mn10300_can_use_retf_insn () ? "\tretf " : "\tret "), asm_out_file);
+ mn10300_print_reg_list (asm_out_file, mn10300_get_live_callee_saved_regs ());
+ fprintf (asm_out_file, ",%d\n", (int) INTVAL (operands[0]));
+ return "";
+})
+
+;; This instruction matches one generated by mn10300_gen_multiple_store()
+(define_insn "store_movm"
+ [(match_parallel 0 "mn10300_store_multiple_operation"
+ [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (match_operand 1 "" "")))])]
+ ""
+{
+ fputs ("\tmovm ", asm_out_file);
+ mn10300_print_reg_list (asm_out_file,
+ mn10300_store_multiple_operation (operands[0],
+ VOIDmode));
+ fprintf (asm_out_file, ",(sp)\n");
+ return "";
+}
+ ;; Assume that no more than 8 registers will be pushed.
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 99) (const_int 88)))]
+)
+
+(define_expand "load_pic"
+ [(const_int 0)]
+ "flag_pic"
+{
+ if (TARGET_AM33)
+ emit_insn (gen_am33_load_pic (pic_offset_table_rtx));
+ else if (mn10300_frame_size () == 0)
+ emit_insn (gen_mn10300_load_pic0 (pic_offset_table_rtx));
+ else
+ emit_insn (gen_mn10300_load_pic1 (pic_offset_table_rtx));
+ DONE;
+})
+
+(define_insn "am33_load_pic"
+ [(set (match_operand:SI 0 "register_operand" "=a")
+ (unspec:SI [(const_int 0)] UNSPEC_GOT))
+ (clobber (reg:CC CC_REG))]
+ "TARGET_AM33"
+{
+ operands[1] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);
+ return ".LPIC%=:\;mov pc,%0\;add %1-(.LPIC%=-.),%0";
+}
+ [(set_attr "timings" "33")]
+)
+
+;; Load pic register with push/pop of stack.
+(define_insn "mn10300_load_pic0"
+ [(set (match_operand:SI 0 "register_operand" "=a")
+ (unspec:SI [(const_int 0)] UNSPEC_GOT))
+ (clobber (reg:SI MDR_REG))
+ (clobber (reg:CC CC_REG))]
+ ""
+{
+ operands[1] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);
+ return ("add -4,sp\;"
+ "calls .LPIC%=\n"
+ ".LPIC%=:\;"
+ "movm (sp),[%0]\;"
+ "add %1-(.LPIC%=-.),%0");
+}
+ [(set_attr "timings" "88")]
+)
+
+;; Load pic register re-using existing stack space.
+(define_insn "mn10300_load_pic1"
+ [(set (match_operand:SI 0 "register_operand" "=a")
+ (unspec:SI [(const_int 0)] UNSPEC_GOT))
+ (clobber (mem:SI (reg:SI SP_REG)))
+ (clobber (reg:SI MDR_REG))
+ (clobber (reg:CC CC_REG))]
+ ""
+{
+ operands[1] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);
+ return ("calls .LPIC%=\n"
+ ".LPIC%=:\;"
+ "mov (sp),%0\;"
+ "add %1-(.LPIC%=-.),%0");
+}
+ [(set_attr "timings" "66")]
+)
+
+;; The mode on operand 3 has been deliberately omitted because it
+;; can be either SI (for arithmetic operations) or QI (for shifts).
+(define_insn "liw"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_dup 0)
+ (match_operand 2 "liw_operand" "rO")
+ (match_operand:SI 4 "const_int_operand" "")]
+ UNSPEC_LIW))
+ (set (match_operand:SI 1 "register_operand" "=r")
+ (unspec:SI [(match_dup 1)
+ (match_operand 3 "liw_operand" "rO")
+ (match_operand:SI 5 "const_int_operand" "")]
+ UNSPEC_LIW))]
+ "TARGET_ALLOW_LIW"
+ "%W4_%W5 %2, %0, %3, %1"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 12)))]
+)
+
+;; The mode on operand 1 has been deliberately omitted because it
+;; can be either SI (for arithmetic operations) or QI (for shifts).
+(define_insn "cmp_liw"
+ [(set (reg:CC CC_REG)
+ (compare:CC (match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "liw_operand" "rO")))
+ (set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_dup 0)
+ (match_operand 1 "liw_operand" "rO")
+ (match_operand:SI 4 "const_int_operand" "")]
+ UNSPEC_LIW))]
+ "TARGET_ALLOW_LIW"
+ "cmp_%W4 %3, %2, %1, %0"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 12)))]
+)
+
+(define_insn "liw_cmp"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_dup 0)
+ (match_operand 1 "liw_operand" "rO")
+ (match_operand:SI 4 "const_int_operand" "")]
+ UNSPEC_LIW))
+ (set (reg:CC CC_REG)
+ (compare:CC (match_operand:SI 2 "register_operand" "r")
+ (match_operand 3 "liw_operand" "rO")))]
+ "TARGET_ALLOW_LIW"
+ "%W4_cmp %1, %0, %3, %2"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 12)))]
+)
diff --git a/gcc/config/mn10300/mn10300.opt b/gcc/config/mn10300/mn10300.opt
new file mode 100644
index 000000000..8909d8bd1
--- /dev/null
+++ b/gcc/config/mn10300/mn10300.opt
@@ -0,0 +1,56 @@
+; Options for the Matsushita MN10300 port of the compiler.
+
+; Copyright (C) 2005, 2007, 2010, 2011 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/>.
+
+mam33
+Target
+Target the AM33 processor
+
+mam33-2
+Target
+Target the AM33/2.0 processor
+
+mam34
+Target Report
+Target the AM34 processor
+
+mtune=
+Target RejectNegative Joined
+Tune code for the given processor
+
+mmult-bug
+Target Report Mask(MULT_BUG)
+Work around hardware multiply bug
+
+; Ignored by the compiler
+mno-crt0
+Target RejectNegative
+
+; Ignored by the compiler
+mrelax
+Target RejectNegative
+Enable linker relaxations
+
+mreturn-pointer-on-d0
+Target Report Mask(PTR_A0D0)
+Return pointers in both a0 and d0
+
+mliw
+Target Report Mask(ALLOW_LIW)
+Allow gcc to generate LIW instructions
diff --git a/gcc/config/mn10300/predicates.md b/gcc/config/mn10300/predicates.md
new file mode 100644
index 000000000..4c78c51e4
--- /dev/null
+++ b/gcc/config/mn10300/predicates.md
@@ -0,0 +1,69 @@
+;; Predicate definitions for Matsushita MN10300.
+;; Copyright (C) 2005, 2007, 2010 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/>.
+
+;; Return true if the operand is the 1.0f constant.
+
+(define_predicate "const_1f_operand"
+ (match_code "const_int,const_double")
+{
+ return (op == CONST1_RTX (SFmode));
+})
+
+;; Return true if OP is a valid call operand.
+
+(define_predicate "call_address_operand"
+ (match_code "symbol_ref,reg,unspec")
+{
+ if (flag_pic)
+ return (satisfies_constraint_S (op) || GET_CODE (op) == REG);
+
+ return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == REG);
+})
+
+(define_predicate "impossible_plus_operand"
+ (match_code "plus")
+{
+ return XEXP (op, 0) == stack_pointer_rtx
+ || XEXP (op, 1) == stack_pointer_rtx;
+})
+
+(define_predicate "reg_or_am33_const_operand"
+ (ior (match_operand 0 "register_operand")
+ (and (match_test "TARGET_AM33")
+ (match_operand 0 "immediate_operand"))))
+
+(define_predicate "label_ref_operand"
+ (match_code "label_ref"))
+
+(define_special_predicate "int_mode_flags"
+ (match_code "reg")
+{
+ if (REGNO (op) != CC_REG)
+ return false;
+ if (GET_MODE (op) == CC_FLOATmode)
+ return false;
+ return GET_MODE_CLASS (GET_MODE (op)) == MODE_CC;
+})
+
+(define_predicate "CCZN_comparison_operator"
+ (match_code "eq,ne,lt,ge"))
+
+(define_predicate "liw_operand"
+ (ior (match_operand 0 "register_operand")
+ (match_test "satisfies_constraint_O (op)")))
diff --git a/gcc/config/mn10300/t-linux b/gcc/config/mn10300/t-linux
new file mode 100644
index 000000000..61ed88e66
--- /dev/null
+++ b/gcc/config/mn10300/t-linux
@@ -0,0 +1,29 @@
+# Copyright (C) 2003 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/>.
+
+# We want fine grained libraries, so use the new code to build the
+# floating point emulation libraries.
+FPBIT = fp-bit.c
+DPBIT = dp-bit.c
+
+dp-bit.c: $(srcdir)/config/fp-bit.c
+ cat $(srcdir)/config/fp-bit.c > dp-bit.c
+
+fp-bit.c: $(srcdir)/config/fp-bit.c
+ echo '#define FLOAT' > fp-bit.c
+ cat $(srcdir)/config/fp-bit.c >> fp-bit.c
diff --git a/gcc/config/mn10300/t-mn10300 b/gcc/config/mn10300/t-mn10300
new file mode 100644
index 000000000..eeefeb602
--- /dev/null
+++ b/gcc/config/mn10300/t-mn10300
@@ -0,0 +1,36 @@
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001,
+# 2003, 2010 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/>.
+
+# We want fine grained libraries, so use the new code to build the
+# floating point emulation libraries.
+FPBIT = fp-bit.c
+DPBIT = dp-bit.c
+
+dp-bit.c: $(srcdir)/config/fp-bit.c
+ cat $(srcdir)/config/fp-bit.c > dp-bit.c
+
+fp-bit.c: $(srcdir)/config/fp-bit.c
+ echo '#define FLOAT' > fp-bit.c
+ cat $(srcdir)/config/fp-bit.c >> fp-bit.c
+
+MULTILIB_OPTIONS = mam33/mam33-2/mam34
+MULTILIB_DIRNAMES = am33 am33-2 am34
+
+LIBGCC = stmp-multilib
+INSTALL_LIBGCC = install-multilib