aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/gcc/config/msp430
diff options
context:
space:
mode:
authorBen Cheng <bccheng@google.com>2014-03-25 22:37:19 -0700
committerBen Cheng <bccheng@google.com>2014-03-25 22:37:19 -0700
commit1bc5aee63eb72b341f506ad058502cd0361f0d10 (patch)
treec607e8252f3405424ff15bc2d00aa38dadbb2518 /gcc-4.9/gcc/config/msp430
parent283a0bf58fcf333c58a2a92c3ebbc41fb9eb1fdb (diff)
downloadtoolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.tar.gz
toolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.tar.bz2
toolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.zip
Initial checkin of GCC 4.9.0 from trunk (r208799).
Change-Id: I48a3c08bb98542aa215912a75f03c0890e497dba
Diffstat (limited to 'gcc-4.9/gcc/config/msp430')
-rw-r--r--gcc-4.9/gcc/config/msp430/README.txt7
-rw-r--r--gcc-4.9/gcc/config/msp430/constraints.md85
-rw-r--r--gcc-4.9/gcc/config/msp430/msp430-c.c36
-rw-r--r--gcc-4.9/gcc/config/msp430/msp430-modes.def3
-rw-r--r--gcc-4.9/gcc/config/msp430/msp430-protos.h49
-rw-r--r--gcc-4.9/gcc/config/msp430/msp430.c2338
-rw-r--r--gcc-4.9/gcc/config/msp430/msp430.h411
-rw-r--r--gcc-4.9/gcc/config/msp430/msp430.md1370
-rw-r--r--gcc-4.9/gcc/config/msp430/msp430.opt38
-rw-r--r--gcc-4.9/gcc/config/msp430/predicates.md80
-rw-r--r--gcc-4.9/gcc/config/msp430/t-msp430257
11 files changed, 4674 insertions, 0 deletions
diff --git a/gcc-4.9/gcc/config/msp430/README.txt b/gcc-4.9/gcc/config/msp430/README.txt
new file mode 100644
index 000000000..e7343cfca
--- /dev/null
+++ b/gcc-4.9/gcc/config/msp430/README.txt
@@ -0,0 +1,7 @@
+Random Notes
+------------
+
+The MSP430 port does not use leading underscores. However, the
+assembler has no way of differentiating between, for example, register
+R12 and symbol R12. So, if you do "int r12;" in your C program, you
+may get an assembler error, and will certainly have runtime problems.
diff --git a/gcc-4.9/gcc/config/msp430/constraints.md b/gcc-4.9/gcc/config/msp430/constraints.md
new file mode 100644
index 000000000..055125f5b
--- /dev/null
+++ b/gcc-4.9/gcc/config/msp430/constraints.md
@@ -0,0 +1,85 @@
+;; Machine Description for TI MSP43* processors
+;; Copyright (C) 2013-2014 Free Software Foundation, Inc.
+;; Contributed by Red Hat.
+
+;; 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 "R12" "R12_REGS"
+ "Register R12.")
+
+(define_register_constraint "R13" "R13_REGS"
+ "Register R13.")
+
+(define_constraint "K"
+ "Integer constant 1."
+ (and (match_code "const_int")
+ (match_test "IN_RANGE (ival, 1, 1)")))
+
+(define_constraint "L"
+ "Integer constant -1^20..1^19."
+ (and (match_code "const_int")
+ (match_test "IN_RANGE (ival, -1 << 20, 1 << 19)")))
+
+(define_constraint "M"
+ "Integer constant 1-4."
+ (and (match_code "const_int")
+ (match_test "IN_RANGE (ival, 1, 4)")))
+
+;; We do not allow arbitrary constants, eg symbols or labels,
+;; because their address may be above the 16-bit address limit
+;; supported by the offset used in the MOVA instruction.
+(define_constraint "Ya"
+ "Memory reference, any type, but restricted range of constants"
+ (and (match_code "mem")
+ (ior (match_code "reg" "0")
+ (and (match_code "plus" "0")
+ (match_code "reg" "00")
+ (match_test ("CONST_INT_P (XEXP (XEXP (op, 0), 1))")))
+ (match_test "CONSTANT_P (XEXP (op, 0))")
+ )))
+
+(define_constraint "Yl"
+ "Memory reference, labels only."
+ (and (match_code "mem")
+ (match_code "label_ref" "0")))
+
+
+;; These are memory references that are safe to use with the X suffix,
+;; because we know/assume they need not index across the 64k boundary.
+(define_constraint "Ys"
+ "Memory reference, stack only."
+ (and (match_code "mem")
+ (ior
+ (and (match_code "plus" "0")
+ (and (match_code "reg" "00")
+ (match_test ("CONST_INT_P (XEXP (XEXP (op, 0), 1))"))
+ (match_test ("IN_RANGE (INTVAL (XEXP (XEXP (op, 0), 1)), -1 << 15, (1 << 15)-1)"))))
+ (match_code "reg" "0")
+ )))
+
+(define_constraint "Yc"
+ "Memory reference, for CALL - we can't use SP."
+ (and (match_code "mem")
+ (match_code "mem" "0")
+ (not (ior
+ (and (match_code "plus" "00")
+ (and (match_code "reg" "000")
+ (match_test ("REGNO (XEXP (XEXP (op, 0), 0)) != SP_REGNO"))))
+ (and (match_code "reg" "0")
+ (match_test ("REGNO (XEXP (XEXP (op, 0), 0)) != SP_REGNO")))
+ ))))
+
diff --git a/gcc-4.9/gcc/config/msp430/msp430-c.c b/gcc-4.9/gcc/config/msp430/msp430-c.c
new file mode 100644
index 000000000..b637192a0
--- /dev/null
+++ b/gcc-4.9/gcc/config/msp430/msp430-c.c
@@ -0,0 +1,36 @@
+/* MSP430 C-specific support
+ Copyright (C) 2013-2014 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 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 "tree.h"
+#include "c-family/c-common.h"
+#include "msp430-protos.h"
+
+/* Implements REGISTER_TARGET_PRAGMAS. */
+void
+msp430_register_pragmas (void)
+{
+ c_register_addr_space ("__near", ADDR_SPACE_NEAR);
+ if (msp430x)
+ c_register_addr_space ("__far", ADDR_SPACE_FAR);
+}
diff --git a/gcc-4.9/gcc/config/msp430/msp430-modes.def b/gcc-4.9/gcc/config/msp430/msp430-modes.def
new file mode 100644
index 000000000..4e94a6df5
--- /dev/null
+++ b/gcc-4.9/gcc/config/msp430/msp430-modes.def
@@ -0,0 +1,3 @@
+/* 20-bit address */
+PARTIAL_INT_MODE (SI, 20, PSI);
+
diff --git a/gcc-4.9/gcc/config/msp430/msp430-protos.h b/gcc-4.9/gcc/config/msp430/msp430-protos.h
new file mode 100644
index 000000000..7f999abbd
--- /dev/null
+++ b/gcc-4.9/gcc/config/msp430/msp430-protos.h
@@ -0,0 +1,49 @@
+/* Exported function prototypes from the TI MSP430 backend.
+ Copyright (C) 2012-2014 Free Software Foundation, Inc.
+ Contributed by Red Hat.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_MSP430_PROTOS_H
+#define GCC_MSP430_PROTOS_H
+
+rtx msp430_eh_return_stackadj_rtx (void);
+void msp430_expand_eh_return (rtx);
+void msp430_expand_epilogue (int);
+void msp430_expand_helper (rtx *operands, const char *, bool);
+void msp430_expand_prologue (void);
+const char * msp430x_extendhisi (rtx *);
+void msp430_fixup_compare_operands (enum machine_mode, rtx *);
+int msp430_hard_regno_mode_ok (int, enum machine_mode);
+int msp430_hard_regno_nregs (int, enum machine_mode);
+bool msp430_hwmult_enabled (void);
+rtx msp430_incoming_return_addr_rtx (void);
+void msp430_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int);
+int msp430_initial_elimination_offset (int, int);
+bool msp430_is_f5_mcu (void);
+bool msp430_is_interrupt_func (void);
+const char * msp430x_logical_shift_right (rtx);
+const char * msp430_mcu_name (void);
+bool msp430_modes_tieable_p (enum machine_mode, enum machine_mode);
+void msp430_output_labelref (FILE *, const char *);
+void msp430_register_pragmas (void);
+rtx msp430_return_addr_rtx (int);
+void msp430_split_movsi (rtx *);
+void msp430_start_function (FILE *, const char *, tree);
+rtx msp430_subreg (enum machine_mode, rtx, enum machine_mode, int);
+
+#endif /* GCC_MSP430_PROTOS_H */
diff --git a/gcc-4.9/gcc/config/msp430/msp430.c b/gcc-4.9/gcc/config/msp430/msp430.c
new file mode 100644
index 000000000..80a17a6e3
--- /dev/null
+++ b/gcc-4.9/gcc/config/msp430/msp430.c
@@ -0,0 +1,2338 @@
+/* Subroutines used for code generation on TI MSP430 processors.
+ Copyright (C) 2012-2014 Free Software Foundation, Inc.
+ Contributed by Red Hat.
+
+ 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 "tree.h"
+#include "stor-layout.h"
+#include "calls.h"
+#include "rtl.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 "function.h"
+#include "expr.h"
+#include "optabs.h"
+#include "libfuncs.h"
+#include "recog.h"
+#include "diagnostic-core.h"
+#include "toplev.h"
+#include "reload.h"
+#include "df.h"
+#include "ggc.h"
+#include "tm_p.h"
+#include "debug.h"
+#include "target.h"
+#include "target-def.h"
+#include "langhooks.h"
+#include "msp430-protos.h"
+#include "dumpfile.h"
+#include "opts.h"
+
+
+static void msp430_compute_frame_info (void);
+
+
+
+/* Run-time Target Specification. */
+
+bool msp430x = true;
+
+struct GTY(()) machine_function
+{
+ /* If set, the rest of the fields have been computed. */
+ int computed;
+ /* Which registers need to be saved in the pro/epilogue. */
+ int need_to_save [FIRST_PSEUDO_REGISTER];
+
+ /* These fields describe the frame layout... */
+ /* arg pointer */
+ /* 2/4 bytes for saved PC */
+ int framesize_regs;
+ /* frame pointer */
+ int framesize_locals;
+ int framesize_outgoing;
+ /* stack pointer */
+ int framesize;
+
+ /* How much we adjust the stack when returning from an exception
+ handler. */
+ rtx eh_stack_adjust;
+};
+
+/* This is our init_machine_status, as set in
+ msp_option_override. */
+static struct machine_function *
+msp430_init_machine_status (void)
+{
+ struct machine_function *m;
+
+ m = ggc_alloc_cleared_machine_function ();
+
+ return m;
+}
+
+#undef TARGET_HANDLE_OPTION
+#define TARGET_HANDLE_OPTION msp430_handle_option
+
+bool
+msp430_handle_option (struct gcc_options *opts ATTRIBUTE_UNUSED,
+ struct gcc_options *opts_set ATTRIBUTE_UNUSED,
+ const struct cl_decoded_option *decoded ATTRIBUTE_UNUSED,
+ location_t loc ATTRIBUTE_UNUSED)
+{
+ return true;
+}
+
+#undef TARGET_OPTION_OVERRIDE
+#define TARGET_OPTION_OVERRIDE msp430_option_override
+
+static const char * msp430_mcu_names [] =
+{
+"msp430afe221", "msp430afe222", "msp430afe223", "msp430afe231",
+"msp430afe232", "msp430afe233", "msp430afe251", "msp430afe252",
+"msp430afe253", "msp430c091", "msp430c092", "msp430c111",
+"msp430c1111", "msp430c112", "msp430c1121", "msp430c1331",
+"msp430c1351", "msp430c311s", "msp430c312", "msp430c313",
+"msp430c314", "msp430c315", "msp430c323", "msp430c325",
+"msp430c336", "msp430c337", "msp430c412", "msp430c413",
+"msp430e112", "msp430e313", "msp430e315", "msp430e325",
+"msp430e337", "msp430f110", "msp430f1101", "msp430f1101a",
+"msp430f1111", "msp430f1111a", "msp430f112", "msp430f1121",
+"msp430f1121a", "msp430f1122", "msp430f1132", "msp430f122",
+"msp430f1222", "msp430f123", "msp430f1232", "msp430f133",
+"msp430f135", "msp430f147", "msp430f1471", "msp430f148",
+"msp430f1481", "msp430f149", "msp430f1491", "msp430f155",
+"msp430f156", "msp430f157", "msp430f1610", "msp430f1611",
+"msp430f1612", "msp430f167", "msp430f168", "msp430f169",
+"msp430f2001", "msp430f2002", "msp430f2003", "msp430f2011",
+"msp430f2012", "msp430f2013", "msp430f2101", "msp430f2111",
+"msp430f2112", "msp430f2121", "msp430f2122", "msp430f2131",
+"msp430f2132", "msp430f2232", "msp430f2234", "msp430f2252",
+"msp430f2254", "msp430f2272", "msp430f2274", "msp430f233",
+"msp430f2330", "msp430f235", "msp430f2350", "msp430f2370",
+"msp430f2410", "msp430f247", "msp430f2471", "msp430f248",
+"msp430f2481", "msp430f249", "msp430f2491", "msp430f412",
+"msp430f413", "msp430f4132", "msp430f415", "msp430f4152",
+"msp430f417", "msp430f423", "msp430f423a", "msp430f425",
+"msp430f4250", "msp430f425a", "msp430f4260", "msp430f427",
+"msp430f4270", "msp430f427a", "msp430f435", "msp430f4351",
+"msp430f436", "msp430f4361", "msp430f437", "msp430f4371",
+"msp430f438", "msp430f439", "msp430f447", "msp430f448",
+"msp430f4481", "msp430f449", "msp430f4491", "msp430f477",
+"msp430f478", "msp430f4783", "msp430f4784", "msp430f479",
+"msp430f4793", "msp430f4794", "msp430fe423", "msp430fe4232",
+"msp430fe423a", "msp430fe4242", "msp430fe425", "msp430fe4252",
+"msp430fe425a", "msp430fe427", "msp430fe4272", "msp430fe427a",
+"msp430fg4250", "msp430fg4260", "msp430fg4270", "msp430fg437",
+"msp430fg438", "msp430fg439", "msp430fg477", "msp430fg478",
+"msp430fg479", "msp430fw423", "msp430fw425", "msp430fw427",
+"msp430fw428", "msp430fw429", "msp430g2001", "msp430g2101",
+"msp430g2102", "msp430g2111", "msp430g2112", "msp430g2113",
+"msp430g2121", "msp430g2131", "msp430g2132", "msp430g2152",
+"msp430g2153", "msp430g2201", "msp430g2202", "msp430g2203",
+"msp430g2210", "msp430g2211", "msp430g2212", "msp430g2213",
+"msp430g2221", "msp430g2230", "msp430g2231", "msp430g2232",
+"msp430g2233", "msp430g2252", "msp430g2253", "msp430g2302",
+"msp430g2303", "msp430g2312", "msp430g2313", "msp430g2332",
+"msp430g2333", "msp430g2352", "msp430g2353", "msp430g2402",
+"msp430g2403", "msp430g2412", "msp430g2413", "msp430g2432",
+"msp430g2433", "msp430g2444", "msp430g2452", "msp430g2453",
+"msp430g2513", "msp430g2533", "msp430g2544", "msp430g2553",
+"msp430g2744", "msp430g2755", "msp430g2855", "msp430g2955",
+"msp430i2020", "msp430i2021", "msp430i2030", "msp430i2031",
+"msp430i2040", "msp430i2041", "msp430l092", "msp430p112",
+"msp430p313", "msp430p315", "msp430p315s", "msp430p325",
+"msp430p337", "msp430tch5e"
+};
+
+/* Generate a C preprocessor symbol based upon the MCU selected by the user.
+ If a specific MCU has not been selected then return a generic symbol instead. */
+
+const char *
+msp430_mcu_name (void)
+{
+ if (target_mcu)
+ {
+ unsigned int i;
+ static char mcu_name [64];
+
+ snprintf (mcu_name, sizeof (mcu_name) - 1, "__%s__", target_mcu);
+ for (i = strlen (mcu_name); i--;)
+ mcu_name[i] = TOUPPER (mcu_name[i]);
+ return mcu_name;
+ }
+
+ return msp430x ? "__MSP430XGENERIC__" : "__MSP430GENERIC__";
+}
+
+static void
+msp430_option_override (void)
+{
+ init_machine_status = msp430_init_machine_status;
+
+ if (target_cpu)
+ {
+ if (strcasecmp (target_cpu, "msp430x") == 0
+ || strcasecmp (target_cpu, "msp430xv2") == 0
+ || strcasecmp (target_cpu, "430x") == 0
+ || strcasecmp (target_cpu, "430xv2") == 0)
+ msp430x = true;
+ else if (strcasecmp (target_cpu, "msp430") == 0
+ || strcasecmp (target_cpu, "430") == 0)
+ msp430x = false;
+ else
+ error ("unrecognised argument of -mcpu: %s", target_cpu);
+ }
+
+ if (target_mcu)
+ {
+ int i;
+
+ /* If we are given an MCU name, we assume that it supports 430X.
+ Then we check to see if it is one of the known MCUs that only
+ supports 430. */
+ msp430x = true;
+
+ /* For backwards compatibility we recognise two generic MCU
+ 430X names. However we want to be able to generate special C
+ preprocessor defines for them, which is why we set target_mcu
+ to NULL. */
+ if (strcasecmp (target_mcu, "msp430") == 0)
+ {
+ msp430x = false;
+ target_mcu = NULL;
+ }
+ else if (strcasecmp (target_mcu, "msp430x") == 0
+ || strcasecmp (target_mcu, "msp430xv2") == 0)
+ target_mcu = NULL;
+ else
+ for (i = ARRAY_SIZE (msp430_mcu_names); i--;)
+ if (strcasecmp (msp430_mcu_names[i], target_mcu) == 0)
+ {
+ msp430x = false;
+ break;
+ }
+ /* It is not an error if we do not match the MCU name. There are
+ hundreds of them. */
+ }
+
+ if (TARGET_LARGE && !msp430x)
+ error ("-mlarge requires a 430X-compatible -mmcu=");
+
+ if (flag_exceptions || flag_non_call_exceptions
+ || flag_unwind_tables || flag_asynchronous_unwind_tables)
+ flag_omit_frame_pointer = false;
+ else
+ flag_omit_frame_pointer = true;
+
+ /* This is a hack to work around a problem with the newlib build
+ mechanism. Newlib always appends CFLAGS to the end of the GCC
+ command line and always sets -O2 in CFLAGS. Thus it is not
+ possible to build newlib with -Os enabled. Until now... */
+ if (TARGET_OPT_SPACE && optimize < 3)
+ optimize_size = 1;
+}
+
+
+
+/* Storage Layout */
+
+#undef TARGET_MS_BITFIELD_LAYOUT_P
+#define TARGET_MS_BITFIELD_LAYOUT_P msp430_ms_bitfield_layout_p
+
+bool
+msp430_ms_bitfield_layout_p (const_tree record_type ATTRIBUTE_UNUSED)
+{
+ return false;
+}
+
+
+
+/* Register Usage */
+
+/* Implements HARD_REGNO_NREGS. MSP430X registers can hold a single
+ PSImode value, but not an SImode value. */
+int
+msp430_hard_regno_nregs (int regno ATTRIBUTE_UNUSED,
+ enum machine_mode mode)
+{
+ if (mode == PSImode && msp430x)
+ return 1;
+ return ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
+ / UNITS_PER_WORD);
+}
+
+/* Implements HARD_REGNO_MODE_OK. */
+int
+msp430_hard_regno_mode_ok (int regno ATTRIBUTE_UNUSED,
+ enum machine_mode mode)
+{
+ return regno <= (ARG_POINTER_REGNUM - msp430_hard_regno_nregs (regno, mode));
+}
+
+/* Implements MODES_TIEABLE_P. */
+bool
+msp430_modes_tieable_p (enum machine_mode mode1, enum machine_mode mode2)
+{
+ if ((mode1 == PSImode || mode2 == SImode)
+ || (mode1 == SImode || mode2 == PSImode))
+ return false;
+
+ return ((GET_MODE_CLASS (mode1) == MODE_FLOAT
+ || GET_MODE_CLASS (mode1) == MODE_COMPLEX_FLOAT)
+ == (GET_MODE_CLASS (mode2) == MODE_FLOAT
+ || GET_MODE_CLASS (mode2) == MODE_COMPLEX_FLOAT));
+}
+
+#undef TARGET_FRAME_POINTER_REQUIRED
+#define TARGET_FRAME_POINTER_REQUIRED msp430_frame_pointer_required
+
+static bool
+msp430_frame_pointer_required (void)
+{
+ return false;
+}
+
+#undef TARGET_CAN_ELIMINATE
+#define TARGET_CAN_ELIMINATE msp430_can_eliminate
+
+static bool
+msp430_can_eliminate (const int from_reg ATTRIBUTE_UNUSED,
+ const int to_reg ATTRIBUTE_UNUSED)
+{
+ return true;
+}
+
+/* Implements INITIAL_ELIMINATION_OFFSET. */
+int
+msp430_initial_elimination_offset (int from, int to)
+{
+ int rv = 0; /* As if arg to arg. */
+
+ msp430_compute_frame_info ();
+
+ switch (to)
+ {
+ case STACK_POINTER_REGNUM:
+ rv += cfun->machine->framesize_outgoing;
+ rv += cfun->machine->framesize_locals;
+ /* Fall through. */
+ case FRAME_POINTER_REGNUM:
+ rv += cfun->machine->framesize_regs;
+ /* Allow for the saved return address. */
+ rv += (TARGET_LARGE ? 4 : 2);
+ /* NB/ No need to allow for crtl->args.pretend_args_size.
+ GCC does that for us. */
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ switch (from)
+ {
+ case FRAME_POINTER_REGNUM:
+ /* Allow for the fall through above. */
+ rv -= (TARGET_LARGE ? 4 : 2);
+ rv -= cfun->machine->framesize_regs;
+ case ARG_POINTER_REGNUM:
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ return rv;
+}
+
+/* Named Address Space support */
+
+
+/* Return the appropriate mode for a named address pointer. */
+#undef TARGET_ADDR_SPACE_POINTER_MODE
+#define TARGET_ADDR_SPACE_POINTER_MODE msp430_addr_space_pointer_mode
+#undef TARGET_ADDR_SPACE_ADDRESS_MODE
+#define TARGET_ADDR_SPACE_ADDRESS_MODE msp430_addr_space_pointer_mode
+
+static enum machine_mode
+msp430_addr_space_pointer_mode (addr_space_t addrspace)
+{
+ switch (addrspace)
+ {
+ default:
+ case ADDR_SPACE_GENERIC:
+ return Pmode;
+ case ADDR_SPACE_NEAR:
+ return HImode;
+ case ADDR_SPACE_FAR:
+ return PSImode;
+ }
+}
+
+/* Function pointers are stored in unwind_word sized
+ variables, so make sure that unwind_word is big enough. */
+#undef TARGET_UNWIND_WORD_MODE
+#define TARGET_UNWIND_WORD_MODE msp430_unwind_word_mode
+
+static enum machine_mode
+msp430_unwind_word_mode (void)
+{
+ return TARGET_LARGE ? SImode : HImode;
+}
+
+/* Determine if one named address space is a subset of another. */
+#undef TARGET_ADDR_SPACE_SUBSET_P
+#define TARGET_ADDR_SPACE_SUBSET_P msp430_addr_space_subset_p
+static bool
+msp430_addr_space_subset_p (addr_space_t subset, addr_space_t superset)
+{
+ if (subset == superset)
+ return true;
+ else
+ return (subset != ADDR_SPACE_FAR && superset == ADDR_SPACE_FAR);
+}
+
+#undef TARGET_ADDR_SPACE_CONVERT
+#define TARGET_ADDR_SPACE_CONVERT msp430_addr_space_convert
+/* Convert from one address space to another. */
+static rtx
+msp430_addr_space_convert (rtx op, tree from_type, tree to_type)
+{
+ addr_space_t from_as = TYPE_ADDR_SPACE (TREE_TYPE (from_type));
+ addr_space_t to_as = TYPE_ADDR_SPACE (TREE_TYPE (to_type));
+ rtx result;
+
+ if (to_as != ADDR_SPACE_FAR && from_as == ADDR_SPACE_FAR)
+ {
+ /* This is unpredictable, as we're truncating off usable address
+ bits. */
+
+ if (CONSTANT_P (op))
+ return gen_rtx_CONST (HImode, op);
+
+ result = gen_reg_rtx (HImode);
+ emit_insn (gen_truncpsihi2 (result, op));
+ return result;
+ }
+ else if (to_as == ADDR_SPACE_FAR && from_as != ADDR_SPACE_FAR)
+ {
+ /* This always works. */
+
+ if (CONSTANT_P (op))
+ return gen_rtx_CONST (PSImode, op);
+
+ result = gen_reg_rtx (PSImode);
+ emit_insn (gen_zero_extendhipsi2 (result, op));
+ return result;
+ }
+ else
+ gcc_unreachable ();
+}
+
+/* Stack Layout and Calling Conventions. */
+
+/* For each function, we list the gcc version and the TI version on
+ each line, where we're converting the function names. */
+static char const * const special_convention_function_names [] =
+{
+ "__muldi3", "__mspabi_mpyll",
+ "__udivdi3", "__mspabi_divull",
+ "__umoddi3", "__mspabi_remull",
+ "__divdi3", "__mspabi_divlli",
+ "__moddi3", "__mspabi_remlli",
+ "__mspabi_srall",
+ "__mspabi_srlll",
+ "__mspabi_sllll",
+ "__adddf3", "__mspabi_addd",
+ "__subdf3", "__mspabi_subd",
+ "__muldf3", "__mspabi_mpyd",
+ "__divdf3", "__mspabi_divd",
+ "__mspabi_cmpd",
+ NULL
+};
+
+/* TRUE if the function passed is a "speical" function. Special
+ functions pass two DImode parameters in registers. */
+static bool
+msp430_special_register_convention_p (const char *name)
+{
+ int i;
+
+ for (i = 0; special_convention_function_names [i]; i++)
+ if (! strcmp (name, special_convention_function_names [i]))
+ return true;
+
+ return false;
+}
+
+#undef TARGET_FUNCTION_VALUE_REGNO_P
+#define TARGET_FUNCTION_VALUE_REGNO_P msp430_function_value_regno_p
+
+bool
+msp430_function_value_regno_p (unsigned int regno)
+{
+ return regno == 12;
+}
+
+
+#undef TARGET_FUNCTION_VALUE
+#define TARGET_FUNCTION_VALUE msp430_function_value
+
+rtx
+msp430_function_value (const_tree ret_type,
+ const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
+ bool outgoing ATTRIBUTE_UNUSED)
+{
+ return gen_rtx_REG (TYPE_MODE (ret_type), 12);
+}
+
+#undef TARGET_LIBCALL_VALUE
+#define TARGET_LIBCALL_VALUE msp430_libcall_value
+
+rtx
+msp430_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
+{
+ return gen_rtx_REG (mode, 12);
+}
+
+/* Implements INIT_CUMULATIVE_ARGS. */
+void
+msp430_init_cumulative_args (CUMULATIVE_ARGS *ca,
+ tree fntype ATTRIBUTE_UNUSED,
+ rtx libname ATTRIBUTE_UNUSED,
+ tree fndecl ATTRIBUTE_UNUSED,
+ int n_named_args ATTRIBUTE_UNUSED)
+{
+ const char *fname;
+ memset (ca, 0, sizeof(*ca));
+
+ ca->can_split = 1;
+
+ if (fndecl)
+ fname = IDENTIFIER_POINTER (DECL_NAME (fndecl));
+ else if (libname)
+ fname = XSTR (libname, 0);
+ else
+ fname = NULL;
+
+ if (fname && msp430_special_register_convention_p (fname))
+ ca->special_p = 1;
+}
+
+/* Helper function for argument passing; this function is the common
+ code that determines where an argument will be passed. */
+static void
+msp430_evaluate_arg (cumulative_args_t cap,
+ enum machine_mode mode,
+ const_tree type ATTRIBUTE_UNUSED,
+ bool named)
+{
+ CUMULATIVE_ARGS *ca = get_cumulative_args (cap);
+ int nregs = GET_MODE_SIZE (mode);
+ int i;
+
+ ca->reg_count = 0;
+ ca->mem_count = 0;
+
+ if (!named)
+ return;
+
+ if (mode == PSImode)
+ nregs = 1;
+ else
+ nregs = (nregs + 1) / 2;
+
+ if (ca->special_p)
+ {
+ /* Function is passed two DImode operands, in R8:R11 and
+ R12:15. */
+ ca->start_reg = 8;
+ ca->reg_count = 4;
+ return;
+ }
+
+ switch (nregs)
+ {
+ case 1:
+ for (i = 0; i < 4; i++)
+ if (! ca->reg_used [i])
+ {
+ ca->reg_count = 1;
+ ca->start_reg = CA_FIRST_REG + i;
+ return;
+ }
+ break;
+ case 2:
+ for (i = 0; i < 3; i++)
+ if (! ca->reg_used [i] && ! ca->reg_used [i + 1])
+ {
+ ca->reg_count = 2;
+ ca->start_reg = CA_FIRST_REG + i;
+ return;
+ }
+ if (! ca->reg_used [3] && ca->can_split)
+ {
+ ca->reg_count = 1;
+ ca->mem_count = 2;
+ ca->start_reg = CA_FIRST_REG + 3;
+ return;
+ }
+ break;
+ case 3:
+ case 4:
+ ca->can_split = 0;
+ if (! ca->reg_used [0]
+ && ! ca->reg_used [1]
+ && ! ca->reg_used [2]
+ && ! ca->reg_used [3])
+ {
+ ca->reg_count = 4;
+ ca->start_reg = CA_FIRST_REG;
+ return;
+ }
+ break;
+ }
+}
+
+#undef TARGET_PROMOTE_PROTOTYPES
+#define TARGET_PROMOTE_PROTOTYPES msp430_promote_prototypes
+
+bool
+msp430_promote_prototypes (const_tree fntype ATTRIBUTE_UNUSED)
+{
+ return false;
+}
+
+#undef TARGET_FUNCTION_ARG
+#define TARGET_FUNCTION_ARG msp430_function_arg
+
+rtx
+msp430_function_arg (cumulative_args_t cap,
+ enum machine_mode mode,
+ const_tree type,
+ bool named)
+{
+ CUMULATIVE_ARGS *ca = get_cumulative_args (cap);
+
+ msp430_evaluate_arg (cap, mode, type, named);
+
+ if (ca->reg_count)
+ return gen_rtx_REG (mode, ca->start_reg);
+
+ return 0;
+}
+
+#undef TARGET_ARG_PARTIAL_BYTES
+#define TARGET_ARG_PARTIAL_BYTES msp430_arg_partial_bytes
+
+int
+msp430_arg_partial_bytes (cumulative_args_t cap,
+ enum machine_mode mode,
+ tree type,
+ bool named)
+{
+ CUMULATIVE_ARGS *ca = get_cumulative_args (cap);
+
+ msp430_evaluate_arg (cap, mode, type, named);
+
+ if (ca->reg_count && ca->mem_count)
+ return ca->reg_count * UNITS_PER_WORD;
+
+ return 0;
+}
+
+#undef TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE msp430_pass_by_reference
+
+static bool
+msp430_pass_by_reference (cumulative_args_t cap ATTRIBUTE_UNUSED,
+ enum machine_mode mode,
+ const_tree type,
+ bool named ATTRIBUTE_UNUSED)
+{
+ return (mode == BLKmode
+ || (type && TREE_CODE (type) == RECORD_TYPE)
+ || (type && TREE_CODE (type) == UNION_TYPE));
+}
+
+#undef TARGET_CALLEE_COPIES
+#define TARGET_CALLEE_COPIES msp430_callee_copies
+
+static bool
+msp430_callee_copies (cumulative_args_t cap ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ const_tree type ATTRIBUTE_UNUSED,
+ bool named ATTRIBUTE_UNUSED)
+{
+ return true;
+}
+
+#undef TARGET_FUNCTION_ARG_ADVANCE
+#define TARGET_FUNCTION_ARG_ADVANCE msp430_function_arg_advance
+
+void
+msp430_function_arg_advance (cumulative_args_t cap,
+ enum machine_mode mode,
+ const_tree type,
+ bool named)
+{
+ CUMULATIVE_ARGS *ca = get_cumulative_args (cap);
+ int i;
+
+ msp430_evaluate_arg (cap, mode, type, named);
+
+ if (ca->start_reg >= CA_FIRST_REG)
+ for (i = 0; i < ca->reg_count; i ++)
+ ca->reg_used [i + ca->start_reg - CA_FIRST_REG] = 1;
+
+ ca->special_p = 0;
+}
+
+#undef TARGET_FUNCTION_ARG_BOUNDARY
+#define TARGET_FUNCTION_ARG_BOUNDARY msp430_function_arg_boundary
+
+static unsigned int
+msp430_function_arg_boundary (enum machine_mode mode, const_tree type)
+{
+ if (mode == BLKmode
+ && int_size_in_bytes (type) > 1)
+ return 16;
+ if (GET_MODE_BITSIZE (mode) > 8)
+ return 16;
+ return 8;
+}
+
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY msp430_return_in_memory
+
+static bool
+msp430_return_in_memory (const_tree ret_type, const_tree fntype ATTRIBUTE_UNUSED)
+{
+ enum machine_mode mode = TYPE_MODE (ret_type);
+
+ if (mode == BLKmode
+ || (fntype && TREE_CODE (TREE_TYPE (fntype)) == RECORD_TYPE)
+ || (fntype && TREE_CODE (TREE_TYPE (fntype)) == UNION_TYPE))
+ return true;
+
+ if (GET_MODE_SIZE (mode) > 8)
+ return true;
+
+ return false;
+}
+
+#undef TARGET_GET_RAW_ARG_MODE
+#define TARGET_GET_RAW_ARG_MODE msp430_get_raw_arg_mode
+
+static enum machine_mode
+msp430_get_raw_arg_mode (int regno)
+{
+ return (regno == ARG_POINTER_REGNUM) ? VOIDmode : Pmode;
+}
+
+#undef TARGET_GET_RAW_RESULT_MODE
+#define TARGET_GET_RAW_RESULT_MODE msp430_get_raw_result_mode
+
+static enum machine_mode
+msp430_get_raw_result_mode (int regno ATTRIBUTE_UNUSED)
+{
+ return Pmode;
+}
+
+/* Addressing Modes */
+
+#undef TARGET_LEGITIMATE_ADDRESS_P
+#define TARGET_LEGITIMATE_ADDRESS_P msp430_legitimate_address_p
+
+static bool
+reg_ok_for_addr (rtx r, bool strict)
+{
+ int rn = REGNO (r);
+
+ if (strict && rn >= FIRST_PSEUDO_REGISTER)
+ rn = reg_renumber [rn];
+ if (strict && 0 <= rn && rn < FIRST_PSEUDO_REGISTER)
+ return true;
+ if (!strict)
+ return true;
+ return false;
+}
+
+bool
+msp430_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
+ rtx x ATTRIBUTE_UNUSED,
+ bool strict ATTRIBUTE_UNUSED)
+{
+ switch (GET_CODE (x))
+ {
+ case MEM:
+ return false;
+
+ case PLUS:
+ if (REG_P (XEXP (x, 0)))
+ {
+ if (GET_MODE (x) != GET_MODE (XEXP (x, 0)))
+ return false;
+ if (!reg_ok_for_addr (XEXP (x, 0), strict))
+ return false;
+ switch (GET_CODE (XEXP (x, 1)))
+ {
+ case CONST:
+ case SYMBOL_REF:
+ case CONST_INT:
+ return true;
+ default:
+ return false;
+ }
+ }
+ return false;
+
+ case REG:
+ if (!reg_ok_for_addr (x, strict))
+ return false;
+ /* else... */
+ case CONST:
+ case SYMBOL_REF:
+ case CONST_INT:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+#undef TARGET_LEGITIMATE_CONSTANT_P
+#define TARGET_LEGITIMATE_CONSTANT_P msp430_legitimate_constant
+
+static bool
+msp430_legitimate_constant (enum machine_mode mode, rtx x)
+{
+ return ! CONST_INT_P (x)
+ || mode != PSImode
+ /* GCC does not know the width of the PSImode, so make
+ sure that it does not try to use a constant value that
+ is out of range. */
+ || (INTVAL (x) < (1 << 20) && INTVAL (x) >= (-1 << 20));
+}
+
+
+#undef TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS msp430_rtx_costs
+
+static bool msp430_rtx_costs (rtx x ATTRIBUTE_UNUSED,
+ int code,
+ int outer_code ATTRIBUTE_UNUSED,
+ int opno ATTRIBUTE_UNUSED,
+ int * total,
+ bool speed ATTRIBUTE_UNUSED)
+{
+ switch (code)
+ {
+ case SIGN_EXTEND:
+ if (GET_MODE (x) == SImode && outer_code == SET)
+ {
+ *total = COSTS_N_INSNS (4);
+ return true;
+ }
+ break;
+ case ASHIFT:
+ case ASHIFTRT:
+ case LSHIFTRT:
+ if (!msp430x)
+ {
+ *total = COSTS_N_INSNS (100);
+ return true;
+ }
+ break;
+ }
+ return false;
+}
+
+/* Function Entry and Exit */
+
+/* The MSP430 call frame looks like this:
+
+ <higher addresses>
+ +--------------------+
+ | |
+ | Stack Arguments |
+ | |
+ +--------------------+ <-- "arg pointer"
+ | |
+ | PC from call | (2 bytes for 430, 4 for TARGET_LARGE)
+ | |
+ +--------------------+
+ | SR if this func has|
+ | been called via an |
+ | interrupt. |
+ +--------------------+ <-- SP before prologue, also AP
+ | |
+ | Saved Regs | (2 bytes per reg for 430, 4 per for TARGET_LARGE)
+ | |
+ +--------------------+ <-- "frame pointer"
+ | |
+ | Locals |
+ | |
+ +--------------------+
+ | |
+ | Outgoing Args |
+ | |
+ +--------------------+ <-- SP during function
+ <lower addresses>
+
+*/
+
+/* We use this to wrap all emitted insns in the prologue, so they get
+ the "frame-related" (/f) flag set. */
+static rtx
+F (rtx x)
+{
+ RTX_FRAME_RELATED_P (x) = 1;
+ return x;
+}
+
+/* This is the one spot that decides if a register is to be saved and
+ restored in the prologue/epilogue. */
+static bool
+msp430_preserve_reg_p (int regno)
+{
+ /* PC, SP, SR, and the constant generator. */
+ if (regno <= 3)
+ return false;
+
+ /* FIXME: add interrupt, EH, etc. */
+ if (crtl->calls_eh_return)
+ return true;
+
+ /* Shouldn't be more than the above, but just in case... */
+ if (fixed_regs [regno])
+ return false;
+
+ /* Interrupt handlers save all registers they use, even
+ ones which are call saved. If they call other functions
+ then *every* register is saved. */
+ if (msp430_is_interrupt_func ())
+ return ! crtl->is_leaf || df_regs_ever_live_p (regno);
+
+ if (!call_used_regs [regno]
+ && df_regs_ever_live_p (regno))
+ return true;
+
+ return false;
+}
+
+/* Compute all the frame-related fields in our machine_function
+ structure. */
+static void
+msp430_compute_frame_info (void)
+{
+ int i;
+
+ cfun->machine->computed = 1;
+ cfun->machine->framesize_regs = 0;
+ cfun->machine->framesize_locals = get_frame_size ();
+ cfun->machine->framesize_outgoing = crtl->outgoing_args_size;
+
+ for (i = 0; i < ARG_POINTER_REGNUM; i ++)
+ if (msp430_preserve_reg_p (i))
+ {
+ cfun->machine->need_to_save [i] = 1;
+ cfun->machine->framesize_regs += (TARGET_LARGE ? 4 : 2);
+ }
+ else
+ cfun->machine->need_to_save [i] = 0;
+
+ if ((cfun->machine->framesize_locals + cfun->machine->framesize_outgoing) & 1)
+ cfun->machine->framesize_locals ++;
+
+ cfun->machine->framesize = (cfun->machine->framesize_regs
+ + cfun->machine->framesize_locals
+ + cfun->machine->framesize_outgoing);
+}
+
+static inline bool
+is_attr_func (const char * attr)
+{
+ return lookup_attribute (attr, DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE;
+}
+
+/* Returns true if the current function has the "interrupt" attribute. */
+
+bool
+msp430_is_interrupt_func (void)
+{
+ if (current_function_decl == NULL)
+ return false;
+ return is_attr_func ("interrupt");
+}
+
+static bool
+is_wakeup_func (void)
+{
+ return msp430_is_interrupt_func () && is_attr_func ("wakeup");
+}
+
+static inline bool
+is_naked_func (void)
+{
+ return is_attr_func ("naked");
+}
+
+static inline bool
+is_reentrant_func (void)
+{
+ return is_attr_func ("reentrant");
+}
+
+static inline bool
+is_critical_func (void)
+{
+ return is_attr_func ("critical");
+}
+
+#undef TARGET_ASM_FUNCTION_PROLOGUE
+#define TARGET_ASM_FUNCTION_PROLOGUE msp430_start_function
+
+static void
+msp430_start_function (FILE *outfile, HOST_WIDE_INT hwi_local ATTRIBUTE_UNUSED)
+{
+ int r, n;
+
+ fprintf (outfile, "; start of function\n");
+
+ if (DECL_ATTRIBUTES (current_function_decl) != NULL_TREE)
+ {
+ fprintf (outfile, "; attributes: ");
+ if (is_naked_func ())
+ fprintf (outfile, "naked ");
+ if (msp430_is_interrupt_func ())
+ fprintf (outfile, "interrupt ");
+ if (is_reentrant_func ())
+ fprintf (outfile, "reentrant ");
+ if (is_critical_func ())
+ fprintf (outfile, "critical ");
+ if (is_wakeup_func ())
+ fprintf (outfile, "wakeup ");
+ fprintf (outfile, "\n");
+ }
+
+ fprintf (outfile, "; framesize_regs: %d\n", cfun->machine->framesize_regs);
+ fprintf (outfile, "; framesize_locals: %d\n", cfun->machine->framesize_locals);
+ fprintf (outfile, "; framesize_outgoing: %d\n", cfun->machine->framesize_outgoing);
+ fprintf (outfile, "; framesize: %d\n", cfun->machine->framesize);
+ fprintf (outfile, "; elim ap -> fp %d\n", msp430_initial_elimination_offset (ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM));
+ fprintf (outfile, "; elim fp -> sp %d\n", msp430_initial_elimination_offset (FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM));
+
+ n = 0;
+ fprintf (outfile, "; saved regs:");
+ for (r = 0; r < ARG_POINTER_REGNUM; r++)
+ if (cfun->machine->need_to_save [r])
+ {
+ fprintf (outfile, " %s", reg_names [r]);
+ n = 1;
+ }
+ if (n == 0)
+ fprintf (outfile, "(none)");
+ fprintf (outfile, "\n");
+}
+
+/* Common code to change the stack pointer. */
+static void
+increment_stack (HOST_WIDE_INT amount)
+{
+ rtx inc;
+ rtx sp = stack_pointer_rtx;
+
+ if (amount == 0)
+ return;
+
+ if (amount < 0)
+ {
+ inc = GEN_INT (- amount);
+ if (TARGET_LARGE)
+ F (emit_insn (gen_subpsi3 (sp, sp, inc)));
+ else
+ F (emit_insn (gen_subhi3 (sp, sp, inc)));
+ }
+ else
+ {
+ inc = GEN_INT (amount);
+ if (TARGET_LARGE)
+ emit_insn (gen_addpsi3 (sp, sp, inc));
+ else
+ emit_insn (gen_addhi3 (sp, sp, inc));
+ }
+}
+
+/* Verify MSP430 specific attributes. */
+
+static tree
+msp430_attr (tree * node,
+ tree name,
+ tree args,
+ int flags ATTRIBUTE_UNUSED,
+ bool * no_add_attrs)
+{
+ gcc_assert (DECL_P (* node));
+
+ if (args != NULL)
+ {
+ tree value = TREE_VALUE (args);
+
+ switch (TREE_CODE (value))
+ {
+ case STRING_CST:
+ if ( strcmp (TREE_STRING_POINTER (value), "reset")
+ && strcmp (TREE_STRING_POINTER (value), "nmi")
+ && strcmp (TREE_STRING_POINTER (value), "watchdog"))
+ /* Allow the attribute to be added - the linker script
+ being used may still recognise this name. */
+ warning (OPT_Wattributes,
+ "unrecognised interrupt vector argument of %qE attribute",
+ name);
+ break;
+
+ case INTEGER_CST:
+ if (TREE_INT_CST_LOW (value) > 63)
+ /* Allow the attribute to be added - the linker script
+ being used may still recognise this value. */
+ warning (OPT_Wattributes,
+ "numeric argument of %qE attribute must be in range 0..63",
+ name);
+ break;
+
+ default:
+ warning (OPT_Wattributes,
+ "argument of %qE attribute is not a string constant or number",
+ name);
+ *no_add_attrs = true;
+ break;
+ }
+ }
+
+ if (TREE_CODE (* node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes,
+ "%qE attribute only applies to functions",
+ name);
+ * no_add_attrs = true;
+ }
+
+ /* FIXME: We ought to check that the interrupt handler
+ attribute has been applied to a void function. */
+ /* FIXME: We should check that reentrant and critical
+ functions are not naked and that critical functions
+ are not reentrant. */
+
+ return NULL_TREE;
+}
+
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE msp430_attribute_table
+
+/* Table of MSP430-specific attributes. */
+const struct attribute_spec msp430_attribute_table[] =
+{
+ /* Name min_len decl_req, fn_type_req, affects_type_identity
+ max_len, type_req, handler. */
+ { "interrupt", 0, 1, true, false, false, msp430_attr, false },
+ { "naked", 0, 0, true, false, false, msp430_attr, false },
+ { "reentrant", 0, 0, true, false, false, msp430_attr, false },
+ { "critical", 0, 0, true, false, false, msp430_attr, false },
+ { "wakeup", 0, 0, true, false, false, msp430_attr, false },
+ { NULL, 0, 0, false, false, false, NULL, false }
+};
+
+void
+msp430_start_function (FILE *file, const char *name, tree decl)
+{
+ tree int_attr;
+
+ int_attr = lookup_attribute ("interrupt", DECL_ATTRIBUTES (decl));
+ if (int_attr != NULL_TREE)
+ {
+ tree intr_vector = TREE_VALUE (int_attr);
+
+ if (intr_vector != NULL_TREE)
+ {
+ char buf[101];
+
+ intr_vector = TREE_VALUE (intr_vector);
+
+ /* The interrupt attribute has a vector value. Turn this into a
+ section name, switch to that section and put the address of
+ the current function into that vector slot. Note msp430_attr()
+ has already verified the vector name for us. */
+ if (TREE_CODE (intr_vector) == STRING_CST)
+ sprintf (buf, "__interrupt_vector_%.80s",
+ TREE_STRING_POINTER (intr_vector));
+ else /* TREE_CODE (intr_vector) == INTEGER_CST */
+ sprintf (buf, "__interrupt_vector_%u",
+ (unsigned int) TREE_INT_CST_LOW (intr_vector));
+
+ switch_to_section (get_section (buf, SECTION_CODE, decl));
+ fputs ("\t.word\t", file);
+ assemble_name (file, name);
+ fputc ('\n', file);
+ fputc ('\t', file);
+ }
+ }
+
+ switch_to_section (function_section (decl));
+ ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
+}
+
+static section *
+msp430_function_section (tree decl, enum node_frequency freq, bool startup, bool exit)
+{
+ /* In large mode we must make sure that interrupt handlers are put into
+ low memory as the vector table only accepts 16-bit addresses. */
+ if (TARGET_LARGE
+ && lookup_attribute ("interrupt", DECL_ATTRIBUTES (decl)))
+ return get_section (".lowtext", SECTION_CODE | SECTION_WRITE , decl);
+
+ /* Otherwise, use the default function section. */
+ return default_function_section (decl, freq, startup, exit);
+}
+
+#undef TARGET_ASM_FUNCTION_SECTION
+#define TARGET_ASM_FUNCTION_SECTION msp430_function_section
+
+enum msp430_builtin
+{
+ MSP430_BUILTIN_BIC_SR,
+ MSP430_BUILTIN_BIS_SR,
+ MSP430_BUILTIN_max
+};
+
+static GTY(()) tree msp430_builtins [(int) MSP430_BUILTIN_max];
+
+static void
+msp430_init_builtins (void)
+{
+ tree void_ftype_int = build_function_type_list (void_type_node, integer_type_node, NULL);
+
+ msp430_builtins[MSP430_BUILTIN_BIC_SR] =
+ add_builtin_function ( "__bic_SR_register_on_exit", void_ftype_int,
+ MSP430_BUILTIN_BIC_SR, BUILT_IN_MD, NULL, NULL_TREE);
+
+ msp430_builtins[MSP430_BUILTIN_BIS_SR] =
+ add_builtin_function ( "__bis_SR_register_on_exit", void_ftype_int,
+ MSP430_BUILTIN_BIS_SR, BUILT_IN_MD, NULL, NULL_TREE);
+}
+
+static tree
+msp430_builtin_decl (unsigned code, bool initialize ATTRIBUTE_UNUSED)
+{
+ switch (code)
+ {
+ case MSP430_BUILTIN_BIC_SR:
+ case MSP430_BUILTIN_BIS_SR:
+ return msp430_builtins[code];
+ default:
+ return error_mark_node;
+ }
+}
+
+static rtx
+msp430_expand_builtin (tree exp,
+ rtx target ATTRIBUTE_UNUSED,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+ unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
+ rtx arg1 = expand_normal (CALL_EXPR_ARG (exp, 0));
+
+ if (! msp430_is_interrupt_func ())
+ {
+ error ("MSP430 builtin functions only work inside interrupt handlers");
+ return NULL_RTX;
+ }
+
+ if (! REG_P (arg1) && ! CONSTANT_P (arg1))
+ arg1 = force_reg (mode, arg1);
+
+ switch (fcode)
+ {
+ case MSP430_BUILTIN_BIC_SR: emit_insn (gen_bic_SR (arg1)); break;
+ case MSP430_BUILTIN_BIS_SR: emit_insn (gen_bis_SR (arg1)); break;
+ default:
+ internal_error ("bad builtin code");
+ break;
+ }
+ return NULL_RTX;
+}
+
+#undef TARGET_INIT_BUILTINS
+#define TARGET_INIT_BUILTINS msp430_init_builtins
+
+#undef TARGET_EXPAND_BUILTIN
+#define TARGET_EXPAND_BUILTIN msp430_expand_builtin
+
+#undef TARGET_BUILTIN_DECL
+#define TARGET_BUILTIN_DECL msp430_builtin_decl
+
+void
+msp430_expand_prologue (void)
+{
+ int i, j;
+ int fs;
+ /* Always use stack_pointer_rtx instead of calling
+ rtx_gen_REG ourselves. Code elsewhere in GCC assumes
+ that there is a single rtx representing the stack pointer,
+ namely stack_pointer_rtx, and uses == to recognize it. */
+ rtx sp = stack_pointer_rtx;
+ rtx p;
+
+ if (is_naked_func ())
+ return;
+
+ emit_insn (gen_prologue_start_marker ());
+
+ if (is_critical_func ())
+ {
+ emit_insn (gen_push_intr_state ());
+ emit_insn (gen_disable_interrupts ());
+ }
+ else if (is_reentrant_func ())
+ emit_insn (gen_disable_interrupts ());
+
+ if (!cfun->machine->computed)
+ msp430_compute_frame_info ();
+
+ if (flag_stack_usage_info)
+ current_function_static_stack_size = cfun->machine->framesize;
+
+ if (crtl->args.pretend_args_size)
+ {
+ rtx note;
+
+ gcc_assert (crtl->args.pretend_args_size == 2);
+
+ p = emit_insn (gen_grow_and_swap ());
+
+ /* Document the stack decrement... */
+ note = F (gen_rtx_SET (Pmode, stack_pointer_rtx,
+ gen_rtx_MINUS (Pmode, stack_pointer_rtx, GEN_INT (2))));
+ add_reg_note (p, REG_FRAME_RELATED_EXPR, note);
+
+ /* ...and the establishment of a new location for the return address. */
+ note = F (gen_rtx_SET (Pmode, gen_rtx_MEM (Pmode,
+ gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (-2))),
+ pc_rtx));
+ add_reg_note (p, REG_CFA_OFFSET, note);
+ F (p);
+ }
+
+ for (i = 15; i >= 4; i--)
+ if (cfun->machine->need_to_save [i])
+ {
+ int seq, count;
+ rtx note;
+
+ for (seq = i - 1; seq >= 4 && cfun->machine->need_to_save[seq]; seq --)
+ ;
+ count = i - seq;
+
+ if (msp430x)
+ {
+ /* Note: with TARGET_LARGE we still use PUSHM as PUSHX.A is two bytes bigger. */
+ p = F (emit_insn (gen_pushm (gen_rtx_REG (Pmode, i),
+ GEN_INT (count))));
+
+ note = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (count + 1));
+
+ XVECEXP (note, 0, 0)
+ = F (gen_rtx_SET (VOIDmode,
+ stack_pointer_rtx,
+ gen_rtx_PLUS (Pmode,
+ stack_pointer_rtx,
+ GEN_INT (count * (TARGET_LARGE ? -4 : -2)))));
+
+ /* *sp-- = R[i-j] */
+ /* sp+N R10
+ ...
+ sp R4 */
+ for (j = 0; j < count; j ++)
+ {
+ rtx addr;
+ int ofs = (count - j - 1) * (TARGET_LARGE ? 4 : 2);
+
+ if (ofs)
+ addr = gen_rtx_PLUS (Pmode, sp, GEN_INT (ofs));
+ else
+ addr = stack_pointer_rtx;
+
+ XVECEXP (note, 0, j + 1) =
+ F (gen_rtx_SET (VOIDmode,
+ gen_rtx_MEM (Pmode, addr),
+ gen_rtx_REG (Pmode, i - j)) );
+ }
+
+ add_reg_note (p, REG_FRAME_RELATED_EXPR, note);
+ i -= count - 1;
+ }
+ else
+ F (emit_insn (gen_push (gen_rtx_REG (Pmode, i))));
+ }
+
+ if (frame_pointer_needed)
+ F (emit_move_insn (gen_rtx_REG (Pmode, FRAME_POINTER_REGNUM), sp));
+
+ fs = cfun->machine->framesize_locals + cfun->machine->framesize_outgoing;
+
+ increment_stack (- fs);
+
+ emit_insn (gen_prologue_end_marker ());
+}
+
+void
+msp430_expand_epilogue (int is_eh)
+{
+ int i;
+ int fs;
+ int helper_n = 0;
+
+ if (is_naked_func ())
+ return;
+
+ if (cfun->machine->need_to_save [10])
+ {
+ /* Check for a helper function. */
+ helper_n = 7; /* For when the loop below never sees a match. */
+ for (i = 9; i >= 4; i--)
+ if (!cfun->machine->need_to_save [i])
+ {
+ helper_n = 10 - i;
+ for (; i >= 4; i--)
+ if (cfun->machine->need_to_save [i])
+ {
+ helper_n = 0;
+ break;
+ }
+ break;
+ }
+ }
+
+ emit_insn (gen_epilogue_start_marker ());
+
+ if (cfun->decl && strcmp (IDENTIFIER_POINTER (DECL_NAME (cfun->decl)), "main") == 0)
+ emit_insn (gen_msp430_refsym_need_exit ());
+
+ if (is_wakeup_func ())
+ /* Clear the SCG1, SCG0, OSCOFF and CPUOFF bits in the saved copy of the
+ status register current residing on the stack. When this function
+ executes its RETI instruction the SR will be updated with this saved
+ value, thus ensuring that the processor is woken up from any low power
+ state in which it may be residing. */
+ emit_insn (gen_bic_SR (GEN_INT (0xf0)));
+
+ fs = cfun->machine->framesize_locals + cfun->machine->framesize_outgoing;
+
+ increment_stack (fs);
+
+ if (is_eh)
+ {
+ /* We need to add the right "SP" register save just after the
+ regular ones, so that when we pop it off we're in the EH
+ return frame, not this one. This overwrites our own return
+ address, but we're not going to be returning anyway. */
+ rtx r12 = gen_rtx_REG (Pmode, 12);
+ rtx (*addPmode)(rtx, rtx, rtx) = TARGET_LARGE ? gen_addpsi3 : gen_addhi3;
+
+ /* R12 will hold the new SP. */
+ i = cfun->machine->framesize_regs;
+ emit_move_insn (r12, stack_pointer_rtx);
+ emit_insn (addPmode (r12, r12, EH_RETURN_STACKADJ_RTX));
+ emit_insn (addPmode (r12, r12, GEN_INT (i)));
+ emit_move_insn (gen_rtx_MEM (Pmode, plus_constant (Pmode, stack_pointer_rtx, i)), r12);
+ }
+
+ for (i = 4; i <= 15; i++)
+ if (cfun->machine->need_to_save [i])
+ {
+ int seq, count;
+
+ for (seq = i + 1; seq <= 15 && cfun->machine->need_to_save[seq]; seq ++)
+ ;
+ count = seq - i;
+
+ if (msp430x)
+ {
+ /* Note: With TARGET_LARGE we still use
+ POPM as POPX.A is two bytes bigger. */
+ emit_insn (gen_popm (stack_pointer_rtx, GEN_INT (seq - 1),
+ GEN_INT (count)));
+ i += count - 1;
+ }
+ else if (i == 11 - helper_n
+ && ! msp430_is_interrupt_func ()
+ && ! is_reentrant_func ()
+ && ! is_critical_func ()
+ && crtl->args.pretend_args_size == 0
+ /* Calling the helper takes as many bytes as the POP;RET sequence. */
+ && helper_n > 1
+ && !is_eh)
+ {
+ emit_insn (gen_epilogue_helper (GEN_INT (helper_n)));
+ return;
+ }
+ else
+ emit_insn (gen_pop (gen_rtx_REG (Pmode, i)));
+ }
+
+ if (is_eh)
+ {
+ /* Also pop SP, which puts us into the EH return frame. Except
+ that you can't "pop" sp, you have to just load it off the
+ stack. */
+ emit_move_insn (stack_pointer_rtx, gen_rtx_MEM (Pmode, stack_pointer_rtx));
+ }
+
+ if (crtl->args.pretend_args_size)
+ emit_insn (gen_swap_and_shrink ());
+
+ if (is_critical_func ())
+ emit_insn (gen_pop_intr_state ());
+ else if (is_reentrant_func ())
+ emit_insn (gen_enable_interrupts ());
+
+ emit_jump_insn (gen_msp_return ());
+}
+
+/* Implements EH_RETURN_STACKADJ_RTX. Saved and used later in
+ m32c_emit_eh_epilogue. */
+rtx
+msp430_eh_return_stackadj_rtx (void)
+{
+ if (!cfun->machine->eh_stack_adjust)
+ {
+ rtx sa;
+
+ sa = gen_rtx_REG (Pmode, 15);
+ cfun->machine->eh_stack_adjust = sa;
+ }
+ return cfun->machine->eh_stack_adjust;
+}
+
+/* This function is called before reload, to "fix" the stack in
+ preparation for an EH return. */
+void
+msp430_expand_eh_return (rtx eh_handler)
+{
+ /* These are all Pmode */
+ rtx ap, sa, ra, tmp;
+
+ ap = arg_pointer_rtx;
+ sa = msp430_eh_return_stackadj_rtx ();
+ ra = eh_handler;
+
+ tmp = ap;
+ tmp = gen_rtx_PLUS (Pmode, ap, sa);
+ tmp = plus_constant (Pmode, tmp, TARGET_LARGE ? -4 : -2);
+ tmp = gen_rtx_MEM (Pmode, tmp);
+ emit_move_insn (tmp, ra);
+}
+
+/* This is a list of MD patterns that implement fixed-count shifts. */
+static struct
+{
+ const char *name;
+ int count;
+ int need_430x;
+ rtx (*genfunc)(rtx,rtx);
+}
+ const_shift_helpers[] =
+{
+#define CSH(N,C,X,G) { "__mspabi_"N, C, X, gen_##G }
+
+ CSH ("slli", 1, 1, slli_1),
+ CSH ("slll", 1, 1, slll_1),
+ CSH ("slll", 2, 1, slll_2),
+
+ CSH ("srai", 1, 0, srai_1),
+ CSH ("sral", 1, 0, sral_1),
+ CSH ("sral", 2, 0, sral_2),
+
+ CSH ("srll", 1, 0, srll_1),
+ CSH ("srll", 2, 1, srll_2x),
+ { 0, 0, 0, 0 }
+#undef CSH
+};
+
+/* The MSP430 ABI defines a number of helper functions that should be
+ used for, for example, 32-bit shifts. This function is called to
+ emit such a function, using the table above to optimize some
+ cases. */
+void
+msp430_expand_helper (rtx *operands, const char *helper_name, bool const_variants)
+{
+ rtx c, f;
+ char *helper_const = NULL;
+ int arg2 = 13;
+ int arg1sz = 1;
+ enum machine_mode arg0mode = GET_MODE (operands[0]);
+ enum machine_mode arg1mode = GET_MODE (operands[1]);
+ enum machine_mode arg2mode = GET_MODE (operands[2]);
+ int have_430x = msp430x ? 1 : 0;
+
+ if (CONST_INT_P (operands[2]))
+ {
+ int i;
+
+ for (i=0; const_shift_helpers[i].name; i++)
+ {
+ if (const_shift_helpers[i].need_430x <= have_430x
+ && strcmp (helper_name, const_shift_helpers[i].name) == 0
+ && INTVAL (operands[2]) == const_shift_helpers[i].count)
+ {
+ emit_insn (const_shift_helpers[i].genfunc (operands[0], operands[1]));
+ return;
+ }
+ }
+ }
+
+ if (arg1mode == VOIDmode)
+ arg1mode = arg0mode;
+ if (arg2mode == VOIDmode)
+ arg2mode = arg0mode;
+
+ if (arg1mode == SImode)
+ {
+ arg2 = 14;
+ arg1sz = 2;
+ }
+
+ if (const_variants
+ && CONST_INT_P (operands[2])
+ && INTVAL (operands[2]) >= 1
+ && INTVAL (operands[2]) <= 15)
+ {
+ /* Note that the INTVAL is limited in value and length by the conditional above. */
+ int len = strlen (helper_name) + 4;
+ helper_const = (char *) xmalloc (len);
+ snprintf (helper_const, len, "%s_%d", helper_name, (int) INTVAL (operands[2]));
+ }
+
+ emit_move_insn (gen_rtx_REG (arg1mode, 12),
+ operands[1]);
+ if (!helper_const)
+ emit_move_insn (gen_rtx_REG (arg2mode, arg2),
+ operands[2]);
+
+ c = gen_call_value_internal (gen_rtx_REG (arg0mode, 12),
+ gen_rtx_SYMBOL_REF (VOIDmode, helper_const ? helper_const : helper_name),
+ GEN_INT (0));
+ c = emit_call_insn (c);
+ RTL_CONST_CALL_P (c) = 1;
+
+ f = 0;
+ use_regs (&f, 12, arg1sz);
+ if (!helper_const)
+ use_regs (&f, arg2, 1);
+ add_function_usage_to (c, f);
+
+ emit_move_insn (operands[0],
+ gen_rtx_REG (arg0mode, 12));
+}
+
+/* Called by cbranch<mode>4 to coerce operands into usable forms. */
+void
+msp430_fixup_compare_operands (enum machine_mode my_mode, rtx * operands)
+{
+ /* constants we're looking for, not constants which are allowed. */
+ int const_op_idx = 1;
+
+ if (msp430_reversible_cmp_operator (operands[0], VOIDmode))
+ const_op_idx = 2;
+
+ if (GET_CODE (operands[const_op_idx]) != REG
+ && GET_CODE (operands[const_op_idx]) != MEM)
+ operands[const_op_idx] = copy_to_mode_reg (my_mode, operands[const_op_idx]);
+}
+
+/* Simplify_gen_subreg() doesn't handle memory references the way we
+ need it to below, so we use this function for when we must get a
+ valid subreg in a "natural" state. */
+rtx
+msp430_subreg (enum machine_mode mode, rtx r, enum machine_mode omode, int byte)
+{
+ rtx rv;
+
+ if (GET_CODE (r) == SUBREG
+ && SUBREG_BYTE (r) == 0)
+ {
+ rtx ireg = SUBREG_REG (r);
+ enum machine_mode imode = GET_MODE (ireg);
+
+ /* special case for (HI (SI (PSI ...), 0)) */
+ if (imode == PSImode
+ && mode == HImode
+ && byte == 0)
+ rv = gen_rtx_SUBREG (mode, ireg, byte);
+ else
+ rv = simplify_gen_subreg (mode, ireg, imode, byte);
+ }
+ else if (GET_CODE (r) == MEM)
+ rv = adjust_address (r, mode, byte);
+ else
+ rv = simplify_gen_subreg (mode, r, omode, byte);
+
+ if (!rv)
+ gcc_unreachable ();
+
+ return rv;
+}
+
+/* Called by movsi_x to generate the HImode operands. */
+void
+msp430_split_movsi (rtx *operands)
+{
+ rtx op00, op02, op10, op12;
+
+ op00 = msp430_subreg (HImode, operands[0], SImode, 0);
+ op02 = msp430_subreg (HImode, operands[0], SImode, 2);
+
+ if (GET_CODE (operands[1]) == CONST
+ || GET_CODE (operands[1]) == SYMBOL_REF)
+ {
+ op10 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (0));
+ op10 = gen_rtx_CONST (HImode, op10);
+ op12 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (16));
+ op12 = gen_rtx_CONST (HImode, op12);
+ }
+ else
+ {
+ op10 = msp430_subreg (HImode, operands[1], SImode, 0);
+ op12 = msp430_subreg (HImode, operands[1], SImode, 2);
+ }
+
+ if (rtx_equal_p (operands[0], operands[1]))
+ {
+ operands[2] = op02;
+ operands[4] = op12;
+ operands[3] = op00;
+ operands[5] = op10;
+ }
+ else if (rtx_equal_p (op00, op12)
+ /* Catch the case where we are loading (rN, rN+1) from mem (rN). */
+ || (REG_P (op00) && reg_mentioned_p (op00, op10))
+ /* Or storing (rN) into mem (rN). */
+ || (REG_P (op10) && reg_mentioned_p (op10, op00))
+ )
+ {
+ operands[2] = op02;
+ operands[4] = op12;
+ operands[3] = op00;
+ operands[5] = op10;
+ }
+ else
+ {
+ operands[2] = op00;
+ operands[4] = op10;
+ operands[3] = op02;
+ operands[5] = op12;
+ }
+}
+
+
+/* The MSPABI specifies the names of various helper functions, many of
+ which are compatible with GCC's helpers. This table maps the GCC
+ name to the MSPABI name. */
+static const struct
+{
+ char const * const gcc_name;
+ char const * const ti_name;
+}
+ helper_function_name_mappings [] =
+{
+ /* Floating point to/from integer conversions. */
+ { "__truncdfsf2", "__mspabi_cvtdf" },
+ { "__extendsfdf2", "__mspabi_cvtfd" },
+ { "__fixdfhi", "__mspabi_fixdi" },
+ { "__fixdfsi", "__mspabi_fixdli" },
+ { "__fixdfdi", "__mspabi_fixdlli" },
+ { "__fixunsdfhi", "__mspabi_fixdu" },
+ { "__fixunsdfsi", "__mspabi_fixdul" },
+ { "__fixunsdfdi", "__mspabi_fixdull" },
+ { "__fixsfhi", "__mspabi_fixfi" },
+ { "__fixsfsi", "__mspabi_fixfli" },
+ { "__fixsfdi", "__mspabi_fixflli" },
+ { "__fixunsfhi", "__mspabi_fixfu" },
+ { "__fixunsfsi", "__mspabi_fixful" },
+ { "__fixunsfdi", "__mspabi_fixfull" },
+ { "__floathisf", "__mspabi_fltif" },
+ { "__floatsisf", "__mspabi_fltlif" },
+ { "__floatdisf", "__mspabi_fltllif" },
+ { "__floathidf", "__mspabi_fltid" },
+ { "__floatsidf", "__mspabi_fltlid" },
+ { "__floatdidf", "__mspabi_fltllid" },
+ { "__floatunhisf", "__mspabi_fltuf" },
+ { "__floatunsisf", "__mspabi_fltulf" },
+ { "__floatundisf", "__mspabi_fltullf" },
+ { "__floatunhidf", "__mspabi_fltud" },
+ { "__floatunsidf", "__mspabi_fltuld" },
+ { "__floatundidf", "__mspabi_fltulld" },
+
+ /* Floating point comparisons. */
+ /* GCC uses individual functions for each comparison, TI uses one
+ compare <=> function. */
+
+ /* Floating point arithmatic */
+ { "__adddf3", "__mspabi_addd" },
+ { "__addsf3", "__mspabi_addf" },
+ { "__divdf3", "__mspabi_divd" },
+ { "__divsf3", "__mspabi_divf" },
+ { "__muldf3", "__mspabi_mpyd" },
+ { "__mulsf3", "__mspabi_mpyf" },
+ { "__subdf3", "__mspabi_subd" },
+ { "__subsf3", "__mspabi_subf" },
+ /* GCC does not use helper functions for negation */
+
+ /* Integer multiply, divide, remainder. */
+ { "__mulhi3", "__mspabi_mpyi" },
+ { "__mulsi3", "__mspabi_mpyl" },
+ { "__muldi3", "__mspabi_mpyll" },
+#if 0
+ /* Clarify signed vs unsigned first. */
+ { "__mulhisi3", "__mspabi_mpysl" }, /* gcc doesn't use widening multiply (yet?) */
+ { "__mulsidi3", "__mspabi_mpysll" }, /* gcc doesn't use widening multiply (yet?) */
+#endif
+
+ { "__divhi3", "__mspabi_divi" },
+ { "__divsi3", "__mspabi_divli" },
+ { "__divdi3", "__mspabi_divlli" },
+ { "__udivhi3", "__mspabi_divu" },
+ { "__udivsi3", "__mspabi_divlu" },
+ { "__udivdi3", "__mspabi_divllu" },
+ { "__modhi3", "__mspabi_remi" },
+ { "__modsi3", "__mspabi_remli" },
+ { "__moddi3", "__mspabi_remlli" },
+ { "__umodhi3", "__mspabi_remu" },
+ { "__umodsi3", "__mspabi_remul" },
+ { "__umoddi3", "__mspabi_remull" },
+
+ /* Bitwise operations. */
+ /* Rotation - no rotation support yet. */
+ /* Logical left shift - gcc already does these itself. */
+ /* Arithmetic left shift - gcc already does these itself. */
+ /* Arithmetic right shift - gcc already does these itself. */
+
+ { NULL, NULL }
+};
+
+/* Returns true if the current MCU is an F5xxx series. */
+bool
+msp430_is_f5_mcu (void)
+{
+ if (target_mcu == NULL)
+ return false;
+ return strncasecmp (target_mcu, "msp430f5", 8) == 0;
+}
+
+/* Returns true id the current MCU has a second generation 32-bit hardware multiplier. */
+static bool
+has_32bit_hw_mult (void)
+{
+ static const char * known_32bit_mult_mcus [] =
+ {
+ "msp430f4783", "msp430f4793", "msp430f4784",
+ "msp430f4794", "msp430f47126", "msp430f47127",
+ "msp430f47163", "msp430f47173", "msp430f47183",
+ "msp430f47193", "msp430f47166", "msp430f47176",
+ "msp430f47186", "msp430f47196", "msp430f47167",
+ "msp430f47177", "msp430f47187", "msp430f47197"
+ };
+ int i;
+ if (target_mcu == NULL)
+ return false;
+
+ for (i = ARRAY_SIZE (known_32bit_mult_mcus); i--;)
+ if (strcasecmp (target_mcu, known_32bit_mult_mcus[i]) == 0)
+ return true;
+
+ return false;
+}
+
+/* Returns true if hardware multiply is supported by the chosen MCU. */
+bool
+msp430_hwmult_enabled (void)
+{
+ if (target_mcu == NULL)
+ return false;
+
+ if (!ENABLE_HWMULT)
+ return false;
+
+ if (msp430_is_interrupt_func ())
+ return false;
+
+ if (msp430_is_f5_mcu () || has_32bit_hw_mult ())
+ return true;
+
+ return false;
+}
+
+/* This function does the same as the default, but it will replace GCC
+ function names with the MSPABI-specified ones. */
+void
+msp430_output_labelref (FILE *file, const char *name)
+{
+ int i;
+
+ for (i = 0; helper_function_name_mappings [i].gcc_name; i++)
+ if (strcmp (helper_function_name_mappings [i].gcc_name, name) == 0)
+ {
+ name = helper_function_name_mappings [i].ti_name;
+ break;
+ }
+
+ /* If we have been given a specific MCU name then we may be
+ able to make use of its hardware multiply capabilities. */
+ if (msp430_hwmult_enabled ())
+ {
+ if (strcmp ("__mspabi_mpyi", name) == 0)
+ {
+ if (msp430_is_f5_mcu ())
+ name = "__mulhi2_f5";
+ else
+ name = "__mulhi2";
+ }
+ else if (strcmp ("__mspabi_mpyl", name) == 0)
+ {
+ if (msp430_is_f5_mcu ())
+ name = "__mulsi2_f5";
+ else if (has_32bit_hw_mult ())
+ name = "__mulsi2_hw32";
+ else
+ name = "__mulsi2";
+ }
+ }
+
+ fputs (name, file);
+}
+
+/* Common code for msp430_print_operand... */
+
+static void
+msp430_print_operand_raw (FILE * file, rtx op)
+{
+ HOST_WIDE_INT i;
+
+ switch (GET_CODE (op))
+ {
+ case REG:
+ fprintf (file, "%s", reg_names [REGNO (op)]);
+ break;
+
+ case CONST_INT:
+ i = INTVAL (op);
+ if (TARGET_ASM_HEX)
+ fprintf (file, "%#" HOST_WIDE_INT_PRINT "x", i);
+ else
+ fprintf (file, "%" HOST_WIDE_INT_PRINT "d", i);
+ break;
+
+ case CONST:
+ case PLUS:
+ case MINUS:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ output_addr_const (file, op);
+ break;
+
+ default:
+ print_rtl (file, op);
+ break;
+ }
+}
+
+#undef TARGET_PRINT_OPERAND_ADDRESS
+#define TARGET_PRINT_OPERAND_ADDRESS msp430_print_operand_addr
+
+/* Output to stdio stream FILE the assembler syntax for an
+ instruction operand that is a memory reference whose address
+ is ADDR. */
+
+static void
+msp430_print_operand_addr (FILE * file, rtx addr)
+{
+ switch (GET_CODE (addr))
+ {
+ case PLUS:
+ msp430_print_operand_raw (file, XEXP (addr, 1));
+ gcc_assert (REG_P (XEXP (addr, 0)));
+ fprintf (file, "(%s)", reg_names [REGNO (XEXP (addr, 0))]);
+ return;
+
+ case REG:
+ fprintf (file, "@");
+ break;
+
+ case CONST:
+ case CONST_INT:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ fprintf (file, "&");
+ break;
+
+ default:
+ break;
+ }
+
+ msp430_print_operand_raw (file, addr);
+}
+
+#undef TARGET_PRINT_OPERAND
+#define TARGET_PRINT_OPERAND msp430_print_operand
+
+/* A low 16-bits of int/lower of register pair
+ B high 16-bits of int/higher of register pair
+ C bits 32-47 of a 64-bit value/reg 3 of a DImode value
+ D bits 48-63 of a 64-bit value/reg 4 of a DImode value
+ H like %B (for backwards compatibility)
+ I inverse of value
+ J an integer without a # prefix
+ L like %A (for backwards compatibility)
+ O offset of the top of the stack
+ Q like X but generates an A postfix
+ R inverse of condition code, unsigned.
+ X X instruction postfix in large mode
+ Y value - 4
+ Z value - 1
+ b .B or .W or .A, depending upon the mode
+ p bit position
+ r inverse of condition code
+ x like X but only for pointers. */
+
+static void
+msp430_print_operand (FILE * file, rtx op, int letter)
+{
+ rtx addr;
+
+ /* We can't use c, n, a, or l. */
+ switch (letter)
+ {
+ case 'Z':
+ gcc_assert (CONST_INT_P (op));
+ /* Print the constant value, less one. */
+ fprintf (file, "#%ld", INTVAL (op) - 1);
+ return;
+ case 'Y':
+ gcc_assert (CONST_INT_P (op));
+ /* Print the constant value, less four. */
+ fprintf (file, "#%ld", INTVAL (op) - 4);
+ return;
+ case 'I':
+ if (GET_CODE (op) == CONST_INT)
+ {
+ /* Inverse of constants */
+ int i = INTVAL (op);
+ fprintf (file, "%d", ~i);
+ return;
+ }
+ op = XEXP (op, 0);
+ break;
+ case 'r': /* Conditional jump where the condition is reversed. */
+ switch (GET_CODE (op))
+ {
+ case EQ: fprintf (file, "NE"); break;
+ case NE: fprintf (file, "EQ"); break;
+ case GEU: fprintf (file, "LO"); break;
+ case LTU: fprintf (file, "HS"); break;
+ case GE: fprintf (file, "L"); break;
+ case LT: fprintf (file, "GE"); break;
+ /* Assume these have reversed operands. */
+ case GTU: fprintf (file, "HS"); break;
+ case LEU: fprintf (file, "LO"); break;
+ case GT: fprintf (file, "GE"); break;
+ case LE: fprintf (file, "L"); break;
+ default:
+ msp430_print_operand_raw (file, op);
+ break;
+ }
+ return;
+ case 'R': /* Conditional jump where the operands are reversed. */
+ switch (GET_CODE (op))
+ {
+ case GTU: fprintf (file, "LO"); break;
+ case LEU: fprintf (file, "HS"); break;
+ case GT: fprintf (file, "L"); break;
+ case LE: fprintf (file, "GE"); break;
+ default:
+ msp430_print_operand_raw (file, op);
+ break;
+ }
+ return;
+ case 'p': /* Bit position. 0 == 0x01, 3 = 0x08 etc. */
+ gcc_assert (CONST_INT_P (op));
+ fprintf (file, "#%d", 1 << INTVAL (op));
+ return;
+ case 'b':
+ switch (GET_MODE (op))
+ {
+ case QImode: fprintf (file, ".B"); return;
+ case HImode: fprintf (file, ".W"); return;
+ case PSImode: fprintf (file, ".A"); return;
+ case SImode: fprintf (file, ".A"); return;
+ default:
+ return;
+ }
+ case 'A':
+ case 'L': /* Low half. */
+ switch (GET_CODE (op))
+ {
+ case MEM:
+ op = adjust_address (op, Pmode, 0);
+ break;
+ case REG:
+ break;
+ case CONST_INT:
+ op = GEN_INT (INTVAL (op) & 0xffff);
+ letter = 0;
+ break;
+ default:
+ /* If you get here, figure out a test case :-) */
+ gcc_unreachable ();
+ }
+ break;
+ case 'B':
+ case 'H': /* high half */
+ switch (GET_CODE (op))
+ {
+ case MEM:
+ op = adjust_address (op, Pmode, 2);
+ break;
+ case REG:
+ op = gen_rtx_REG (Pmode, REGNO (op) + 1);
+ break;
+ case CONST_INT:
+ op = GEN_INT (INTVAL (op) >> 16);
+ letter = 0;
+ break;
+ default:
+ /* If you get here, figure out a test case :-) */
+ gcc_unreachable ();
+ }
+ break;
+ case 'C':
+ switch (GET_CODE (op))
+ {
+ case MEM:
+ op = adjust_address (op, Pmode, 3);
+ break;
+ case REG:
+ op = gen_rtx_REG (Pmode, REGNO (op) + 2);
+ break;
+ case CONST_INT:
+ op = GEN_INT ((long long) INTVAL (op) >> 32);
+ letter = 0;
+ break;
+ default:
+ /* If you get here, figure out a test case :-) */
+ gcc_unreachable ();
+ }
+ break;
+ case 'D':
+ switch (GET_CODE (op))
+ {
+ case MEM:
+ op = adjust_address (op, Pmode, 4);
+ break;
+ case REG:
+ op = gen_rtx_REG (Pmode, REGNO (op) + 3);
+ break;
+ case CONST_INT:
+ op = GEN_INT ((long long) INTVAL (op) >> 48);
+ letter = 0;
+ break;
+ default:
+ /* If you get here, figure out a test case :-) */
+ gcc_unreachable ();
+ }
+ break;
+
+ case 'X':
+ /* This is used to turn, for example, an ADD opcode into an ADDX
+ opcode when we're using 20-bit addresses. */
+ if (TARGET_LARGE)
+ fprintf (file, "X");
+ /* We don't care which operand we use, but we want 'X' in the MD
+ file, so we do it this way. */
+ return;
+
+ case 'x':
+ /* Similarly, but only for PSImodes. BIC, for example, needs this. */
+ if (TARGET_LARGE && GET_MODE (op) == PSImode)
+ fprintf (file, "X");
+ return;
+
+ case 'Q':
+ /* Likewise, for BR -> BRA. */
+ if (TARGET_LARGE)
+ fprintf (file, "A");
+ return;
+
+ case 'O':
+ /* Computes the offset to the top of the stack for the current frame.
+ This has to be done here rather than in, say, msp430_expand_builtin()
+ because builtins are expanded before the frame layout is determined. */
+ fprintf (file, "%d",
+ msp430_initial_elimination_offset (ARG_POINTER_REGNUM, STACK_POINTER_REGNUM)
+ - 2);
+ return;
+
+ case 'J':
+ gcc_assert (GET_CODE (op) == CONST_INT);
+ case 0:
+ break;
+ default:
+ output_operand_lossage ("invalid operand prefix");
+ return;
+ }
+
+ switch (GET_CODE (op))
+ {
+ case REG:
+ msp430_print_operand_raw (file, op);
+ break;
+
+ case MEM:
+ addr = XEXP (op, 0);
+ msp430_print_operand_addr (file, addr);
+ break;
+
+ case CONST_INT:
+ case CONST:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ if (letter == 0)
+ fprintf (file, "#");
+ msp430_print_operand_raw (file, op);
+ break;
+
+ case EQ: fprintf (file, "EQ"); break;
+ case NE: fprintf (file, "NE"); break;
+ case GEU: fprintf (file, "HS"); break;
+ case LTU: fprintf (file, "LO"); break;
+ case GE: fprintf (file, "GE"); break;
+ case LT: fprintf (file, "L"); break;
+
+ default:
+ print_rtl (file, op);
+ break;
+ }
+}
+
+
+/* Frame stuff. */
+
+rtx
+msp430_return_addr_rtx (int count)
+{
+ int ra_size;
+ if (count)
+ return NULL_RTX;
+
+ ra_size = TARGET_LARGE ? 4 : 2;
+ if (crtl->args.pretend_args_size)
+ ra_size += 2;
+
+ return gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, arg_pointer_rtx, GEN_INT (- ra_size)));
+}
+
+rtx
+msp430_incoming_return_addr_rtx (void)
+{
+ return gen_rtx_MEM (Pmode, stack_pointer_rtx);
+}
+
+/* Instruction generation stuff. */
+
+/* Generate a sequence of instructions to sign-extend an HI
+ value into an SI value. Handles the tricky case where
+ we are overwriting the destination. */
+
+const char *
+msp430x_extendhisi (rtx * operands)
+{
+ if (REGNO (operands[0]) == REGNO (operands[1]))
+ /* Low word of dest == source word. */
+ return "BIT.W\t#0x8000, %L0 { SUBC.W\t%H0, %H0 { INV.W\t%H0, %H0"; /* 8-bytes. */
+
+ if (! msp430x)
+ /* Note: This sequence is approximately the same length as invoking a helper
+ function to perform the sign-extension, as in:
+
+ MOV.W %1, %L0
+ MOV.W %1, r12
+ CALL __mspabi_srai_15
+ MOV.W r12, %H0
+
+ but this version does not involve any function calls or using argument
+ registers, so it reduces register pressure. */
+ return "MOV.W\t%1, %L0 { BIT.W\t#0x8000, %L0 { SUBC.W\t%H0, %H0 { INV.W\t%H0, %H0"; /* 10-bytes. */
+
+ if (REGNO (operands[0]) + 1 == REGNO (operands[1]))
+ /* High word of dest == source word. */
+ return "MOV.W\t%1, %L0 { RPT\t#15 { RRAX.W\t%H0"; /* 6-bytes. */
+
+ /* No overlap between dest and source. */
+ return "MOV.W\t%1, %L0 { MOV.W\t%1, %H0 { RPT\t#15 { RRAX.W\t%H0"; /* 8-bytes. */
+}
+
+/* Likewise for logical right shifts. */
+const char *
+msp430x_logical_shift_right (rtx amount)
+{
+ /* The MSP430X's logical right shift instruction - RRUM - does
+ not use an extension word, so we cannot encode a repeat count.
+ Try various alternatives to work around this. If the count
+ is in a register we are stuck, hence the assert. */
+ gcc_assert (CONST_INT_P (amount));
+
+ if (INTVAL (amount) <= 0
+ || INTVAL (amount) >= 16)
+ return "# nop logical shift.";
+
+ if (INTVAL (amount) > 0
+ && INTVAL (amount) < 5)
+ return "rrum.w\t%2, %0"; /* Two bytes. */
+
+ if (INTVAL (amount) > 4
+ && INTVAL (amount) < 9)
+ return "rrum.w\t#4, %0 { rrum.w\t%Y2, %0 "; /* Four bytes. */
+
+ /* First we logically shift right by one. Now we know
+ that the top bit is zero and we can use the arithmetic
+ right shift instruction to perform the rest of the shift. */
+ return "rrum.w\t#1, %0 { rpt\t%Z2 { rrax.w\t%0"; /* Six bytes. */
+}
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+
+#include "gt-msp430.h"
diff --git a/gcc-4.9/gcc/config/msp430/msp430.h b/gcc-4.9/gcc/config/msp430/msp430.h
new file mode 100644
index 000000000..65d6ad66d
--- /dev/null
+++ b/gcc-4.9/gcc/config/msp430/msp430.h
@@ -0,0 +1,411 @@
+/* GCC backend definitions for the TI MSP430 Processor
+ Copyright (C) 2012-2014 Free Software Foundation, Inc.
+ Contributed by Red Hat.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+
+/* Run-time Target Specification */
+
+/* True if the MSP430x extensions are enabled. */
+#ifndef IN_LIBGCC2
+extern bool msp430x;
+#endif
+
+#define TARGET_CPU_CPP_BUILTINS() \
+ do \
+ { \
+ builtin_define ("NO_TRAMPOLINES"); \
+ builtin_define ("__MSP430__"); \
+ builtin_define (msp430_mcu_name ()); \
+ if (msp430x) \
+ { \
+ builtin_define ("__MSP430X__"); \
+ builtin_assert ("cpu=MSP430X"); \
+ if (TARGET_LARGE) \
+ builtin_define ("__MSP430X_LARGE__"); \
+ } \
+ else \
+ builtin_assert ("cpu=MSP430"); \
+ } \
+ while (0)
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "%{pg:gcrt0.o%s}%{!pg:%{minrt:crt0-minrt.o%s}%{!minrt:crt0.o%s}} %{!minrt:crtbegin.o%s}"
+
+/* -lgcc is included because crtend.o needs __mspabi_func_epilog_1. */
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC "%{!minrt:crtend.o%s} %{minrt:crtn-minrt.o%s}%{!minrt:crtn.o%s} -lgcc"
+
+#define ASM_SPEC "-mP " /* Enable polymorphic instructions. */ \
+ "%{mcpu=*:-mcpu=%*}%{!mcpu=*:%{mmcu=*:-mmcu=%*}} " /* Pass the CPU type on to the assembler. */ \
+ "%{mrelax=-mQ} " /* Pass the relax option on to the assembler. */ \
+ "%{mlarge:-ml} " /* Tell the assembler if we are building for the LARGE pointer model. */ \
+ "%{!msim:-md} %{msim:%{mlarge:-md}}" /* Copy data from ROM to RAM if necessary. */ \
+ "%{ffunction-sections:-gdwarf-sections}" /* If function sections are being created then create DWARF line number sections as well. */
+
+/* Enable linker section garbage collection by default, unless we
+ are creating a relocatable binary (gc does not work) or debugging
+ is enabled (the GDB testsuite relies upon unused entities not being deleted). */
+#define LINK_SPEC "%{mrelax:--relax} %{mlarge:%{!r:%{!g:--gc-sections}}}"
+
+#undef LIB_SPEC
+#define LIB_SPEC " \
+--start-group \
+-lc \
+-lgcc \
+-lcrt \
+%{msim:-lsim} \
+%{!msim:-lnosys} \
+--end-group \
+%{!T*:%{!msim:%{mmcu=*:--script=%*.ld}}} \
+%{!T*:%{!msim:%{!mmcu=*:%Tmsp430.ld}}} \
+%{!T*:%{msim:%{mlarge:%Tmsp430xl-sim.ld}%{!mlarge:%Tmsp430-sim.ld}}} \
+"
+
+/* Storage Layout */
+
+#define BITS_BIG_ENDIAN 0
+#define BYTES_BIG_ENDIAN 0
+#define WORDS_BIG_ENDIAN 0
+
+
+#ifdef IN_LIBGCC2
+/* This is to get correct SI and DI modes in libgcc2.c (32 and 64 bits). */
+#define UNITS_PER_WORD 4
+/* We have a problem with libgcc2. It only defines two versions of
+ each function, one for "int" and one for "long long". Ie it assumes
+ that "sizeof (int) == sizeof (long)". For the MSP430 this is not true
+ and we need a third set of functions. We explicitly define
+ LIBGCC2_UNITS_PER_WORD here so that it is clear that we are expecting
+ to get the SI and DI versions from the libgcc2.c sources, and we
+ provide our own set of HI functions, which is why this
+ definition is surrounded by #ifndef..#endif. */
+#ifndef LIBGCC2_UNITS_PER_WORD
+#define LIBGCC2_UNITS_PER_WORD 4
+#endif
+#else
+/* Actual width of a word, in units (bytes). */
+#define UNITS_PER_WORD 2
+#endif
+
+#define SHORT_TYPE_SIZE 16
+#define INT_TYPE_SIZE 16
+#define LONG_TYPE_SIZE 32
+#define LONG_LONG_TYPE_SIZE 64
+
+#define FLOAT_TYPE_SIZE 32
+#define DOUBLE_TYPE_SIZE 64
+#define LONG_DOUBLE_TYPE_SIZE 64 /*DOUBLE_TYPE_SIZE*/
+
+#define LIBGCC2_HAS_DF_MODE 1
+#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 64
+
+#define DEFAULT_SIGNED_CHAR 0
+
+#define STRICT_ALIGNMENT 1
+#define FUNCTION_BOUNDARY 16
+#define BIGGEST_ALIGNMENT 16
+#define STACK_BOUNDARY 16
+#define PARM_BOUNDARY 8
+#define PCC_BITFIELD_TYPE_MATTERS 1
+
+#define STACK_GROWS_DOWNWARD 1
+#define FRAME_GROWS_DOWNWARD 1
+#define FIRST_PARM_OFFSET(FNDECL) 0
+
+#define MAX_REGS_PER_ADDRESS 1
+
+#define Pmode (TARGET_LARGE ? PSImode : HImode)
+/* Note: 32 is a lie. Large pointers are actually 20-bits wide. But gcc
+ thinks that any non-power-of-2 pointer size equates to BLKmode, which
+ causes all kinds of problems... */
+#define POINTER_SIZE (TARGET_LARGE ? 32 : 16)
+#define POINTERS_EXTEND_UNSIGNED 1
+
+#define ADDR_SPACE_NEAR 1
+#define ADDR_SPACE_FAR 2
+
+#define REGISTER_TARGET_PRAGMAS() msp430_register_pragmas()
+
+#if 1 /* XXX */
+/* Define this macro if it is advisable to hold scalars in registers
+ in a wider mode than that declared by the program. In such cases,
+ the value is constrained to be within the bounds of the declared
+ type, but kept valid in the wider mode. The signedness of the
+ extension may differ from that of the type. */
+
+#define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE) \
+ if (GET_MODE_CLASS (MODE) == MODE_INT \
+ && GET_MODE_SIZE (MODE) < 2) \
+ (MODE) = HImode;
+#endif
+
+/* Layout of Source Language Data Types */
+
+#undef SIZE_TYPE
+#define SIZE_TYPE (TARGET_LARGE ? "long unsigned int" : "unsigned int")
+#undef PTRDIFF_TYPE
+#define PTRDIFF_TYPE (TARGET_LARGE ? "long int" : "int")
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "long int"
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE BITS_PER_WORD
+#define FUNCTION_MODE HImode
+#define CASE_VECTOR_MODE Pmode
+#define HAS_LONG_COND_BRANCH 0
+#define HAS_LONG_UNCOND_BRANCH 0
+
+#define LOAD_EXTEND_OP(M) ZERO_EXTEND
+/*#define WORD_REGISTER_OPERATIONS 1*/
+
+#define MOVE_MAX 8
+#define STARTING_FRAME_OFFSET 0
+
+#define INCOMING_RETURN_ADDR_RTX \
+ msp430_incoming_return_addr_rtx ()
+
+#define RETURN_ADDR_RTX(COUNT, FA) \
+ msp430_return_addr_rtx (COUNT)
+
+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
+
+#define SLOW_BYTE_ACCESS 0
+
+
+/* Register Usage */
+
+/* gas doesn't recognize PC (R0), SP (R1), and SR (R2) as register
+ names. */
+#define REGISTER_NAMES \
+{ \
+ "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", \
+ "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", \
+ "argptr" \
+}
+
+enum reg_class
+{
+ NO_REGS,
+ R12_REGS,
+ R13_REGS,
+ GEN_REGS,
+ ALL_REGS,
+ LIM_REG_CLASSES
+};
+
+#define REG_CLASS_NAMES \
+{ \
+ "NO_REGS", \
+ "R12_REGS", \
+ "R13_REGS", \
+ "GEN_REGS", \
+ "ALL_REGS" \
+}
+
+#define REG_CLASS_CONTENTS \
+{ \
+ 0x00000000, \
+ 0x00001000, \
+ 0x00002000, \
+ 0x0000fff2, \
+ 0x0001ffff \
+}
+
+#define GENERAL_REGS GEN_REGS
+#define BASE_REG_CLASS GEN_REGS
+#define INDEX_REG_CLASS GEN_REGS
+#define N_REG_CLASSES (int) LIM_REG_CLASSES
+
+#define PC_REGNUM 0
+#define STACK_POINTER_REGNUM 1
+#define CC_REGNUM 2
+#define FRAME_POINTER_REGNUM 4 /* not usually used, call preserved */
+#define ARG_POINTER_REGNUM 16
+#define STATIC_CHAIN_REGNUM 5 /* FIXME */
+
+#define FIRST_PSEUDO_REGISTER 17
+
+#define REGNO_REG_CLASS(REGNO) ((REGNO) < 17 \
+ ? GEN_REGS : NO_REGS)
+
+#define TRAMPOLINE_SIZE 4 /* FIXME */
+#define TRAMPOLINE_ALIGNMENT 16 /* FIXME */
+
+#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) = msp430_initial_elimination_offset ((FROM), (TO))
+
+
+#define FUNCTION_ARG_REGNO_P(N) ((N) >= 8 && (N) < ARG_POINTER_REGNUM)
+#define DEFAULT_PCC_STRUCT_RETURN 0
+
+/* 1 == register can't be used by gcc, in general
+ 0 == register can be used by gcc, in general */
+#define FIXED_REGISTERS \
+{ \
+ 1,0,1,1, 0,0,0,0, \
+ 0,0,0,0, 0,0,0,0, \
+ 1, \
+}
+
+/* 1 == value changes across function calls
+ 0 == value is the same after a call */
+/* R4 through R10 are callee-saved */
+#define CALL_USED_REGISTERS \
+{ \
+ 1,0,1,1, 0,0,0,0, \
+ 0,0,0,1, 1,1,1,1, \
+ 1, \
+}
+
+#define REG_ALLOC_ORDER \
+ { 12, 13, 14, 15, 10, 9, 8, 7, 6, 5, 4, 11, 0, 1, 2, 3, 16 }
+/* { 11, 15, 14, 13, 12, 10, 9, 8, 7, 6, 5, 4, 0, 1, 2, 3, 16 }*/
+
+#define REGNO_OK_FOR_BASE_P(regno) 1
+#define REGNO_OK_FOR_INDEX_P(regno) 1
+
+
+
+typedef struct
+{
+ /* These two are the current argument status. */
+ char reg_used[4];
+#define CA_FIRST_REG 12
+ char can_split;
+ /* These two are temporaries used internally. */
+ char start_reg;
+ char reg_count;
+ char mem_count;
+ char special_p;
+} CUMULATIVE_ARGS;
+
+#define INIT_CUMULATIVE_ARGS(CA, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) \
+ msp430_init_cumulative_args (&CA, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS)
+
+
+/* FIXME */
+#define NO_PROFILE_COUNTERS 1
+#define PROFILE_BEFORE_PROLOGUE 1
+
+#define FUNCTION_PROFILER(FILE, LABELNO) \
+ fprintf (FILE, "\tcall\t__mcount\n");
+
+#define HARD_REGNO_NREGS(REGNO, MODE) \
+ msp430_hard_regno_nregs (REGNO, MODE)
+
+#define HARD_REGNO_MODE_OK(REGNO, MODE) \
+ msp430_hard_regno_mode_ok (REGNO, MODE)
+
+#define MODES_TIEABLE_P(MODE1, MODE2) \
+ msp430_modes_tieable_p (MODE1, MODE2)
+
+/* Exception Handling */
+
+/* R12,R13,R14 - EH data
+ R15 - stack adjustment */
+
+#define EH_RETURN_DATA_REGNO(N) \
+ (((N) < 3) ? ((N) + 12) : INVALID_REGNUM)
+
+#define EH_RETURN_HANDLER_RTX \
+ gen_rtx_MEM(Pmode, gen_rtx_PLUS (Pmode, gen_rtx_REG(Pmode, SP_REGNO), gen_rtx_REG (Pmode, 15)))
+
+#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, 15)
+
+#define ASM_PREFERRED_EH_DATA_FORMAT(CODE,GLOBAL) DW_EH_PE_udata4
+
+
+/* Stack Layout and Calling Conventions */
+
+
+/* Addressing Modes */
+
+
+
+#define TEXT_SECTION_ASM_OP ".text"
+#define DATA_SECTION_ASM_OP ".data"
+#define BSS_SECTION_ASM_OP "\t.section .bss"
+
+#define ASM_COMMENT_START " ;"
+#define ASM_APP_ON ""
+#define ASM_APP_OFF ""
+#define LOCAL_LABEL_PREFIX ".L"
+#undef USER_LABEL_PREFIX
+#define USER_LABEL_PREFIX ""
+
+#define GLOBAL_ASM_OP "\t.global\t"
+
+#define ASM_OUTPUT_LABELREF(FILE, SYM) msp430_output_labelref ((FILE), (SYM))
+
+#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
+ fprintf (FILE, "\t.long .L%d\n", VALUE)
+
+/* This is how to output an element of a case-vector that is relative.
+ Note: The local label referenced by the "3b" below is emitted by
+ the tablejump insn. */
+
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
+ fprintf (FILE, "\t.long .L%d - 1b\n", VALUE)
+
+
+#define ASM_OUTPUT_ALIGN(STREAM, LOG) \
+ do \
+ { \
+ if ((LOG) == 0) \
+ break; \
+ fprintf (STREAM, "\t.balign %d\n", 1 << (LOG)); \
+ } \
+ while (0)
+
+#define JUMP_TABLES_IN_TEXT_SECTION 1
+
+#undef DWARF2_ADDR_SIZE
+#define DWARF2_ADDR_SIZE 4
+
+#define INCOMING_FRAME_SP_OFFSET (POINTER_SIZE / BITS_PER_UNIT)
+
+#undef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
+
+#define DWARF2_ASM_LINE_DEBUG_INFO 1
+
+/* Prevent reload (and others) from choosing HImode stack slots
+ when spilling hard registers when they may contain PSImode values. */
+#define HARD_REGNO_CALLER_SAVE_MODE(REGNO,NREGS,MODE) \
+ ((TARGET_LARGE && ((NREGS) <= 2)) ? PSImode : choose_hard_reg_mode ((REGNO), (NREGS), false))
+
+/* Also stop GCC from thinking that it can eliminate (SUBREG:PSI (SI)). */
+#define CANNOT_CHANGE_MODE_CLASS(FROM,TO,CLASS) \
+ ( ((TO) == PSImode && (FROM) == SImode) \
+ || ((TO) == SImode && (FROM) == PSImode) \
+ || ((TO) == DImode && (FROM) == PSImode) \
+ || ((TO) == PSImode && (FROM) == DImode) \
+ )
+
+#define ACCUMULATE_OUTGOING_ARGS 1
+
+#undef ASM_DECLARE_FUNCTION_NAME
+#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \
+ msp430_start_function ((FILE), (NAME), (DECL))
+
+#define TARGET_HAS_NO_HW_DIVIDE (! TARGET_HWMULT)
diff --git a/gcc-4.9/gcc/config/msp430/msp430.md b/gcc-4.9/gcc/config/msp430/msp430.md
new file mode 100644
index 000000000..c0c97dae6
--- /dev/null
+++ b/gcc-4.9/gcc/config/msp430/msp430.md
@@ -0,0 +1,1370 @@
+;; Machine Description for TI MSP43* processors
+;; Copyright (C) 2013-2014 Free Software Foundation, Inc.
+;; Contributed by Red Hat.
+
+;; 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_constants
+ [
+ (PC_REGNO 0)
+ (SP_REGNO 1)
+ (CARRY 2)
+ ])
+
+(define_c_enum "unspec"
+ [
+ UNS_PROLOGUE_START_MARKER
+ UNS_PROLOGUE_END_MARKER
+ UNS_EPILOGUE_START_MARKER
+ UNS_EPILOGUE_HELPER
+
+ UNS_PUSHM
+ UNS_POPM
+
+ UNS_GROW_AND_SWAP
+ UNS_SWAP_AND_SHRINK
+
+ UNS_DINT
+ UNS_EINT
+ UNS_PUSH_INTR
+ UNS_POP_INTR
+ UNS_BIC_SR
+ UNS_BIS_SR
+
+ UNS_REFSYM_NEED_EXIT
+ ])
+
+(include "predicates.md")
+(include "constraints.md")
+
+(define_mode_iterator QHI [QI HI PSI])
+
+;; There are two basic "family" tests we do here:
+;;
+;; msp430x - true if 430X instructions are available.
+;; TARGET_LARGE - true if pointers are 20-bits
+;;
+;; Note that there are three supported cases, since the base 430
+;; doesn't have 20-bit pointers:
+;;
+;; 1. MSP430 cpu, small model
+;; 2. MSP430X cpu, small model.
+;; 3. MSP430X cpu, large model.
+
+;;------------------------------------------------------------
+;; Moves
+
+;; Push/Pop must be before the generic move patterns
+
+(define_insn "push"
+ [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNO)))
+ (match_operand:HI 0 "register_operand" "r"))]
+ ""
+ "PUSH\t%0"
+ )
+
+(define_insn "pusha"
+ [(set (mem:PSI (pre_dec:PSI (reg:PSI SP_REGNO)))
+ (match_operand:PSI 0 "register_operand" "r"))]
+ "TARGET_LARGE"
+ "PUSHX.A\t%0"
+ )
+
+(define_insn "pushm"
+ [(unspec_volatile [(match_operand 0 "register_operand" "r")
+ (match_operand 1 "immediate_operand" "n")] UNS_PUSHM)]
+ ""
+ "PUSHM%b0\t%1, %0"
+ )
+
+(define_insn "pop"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (mem:HI (post_inc:HI (reg:HI SP_REGNO))))]
+ ""
+ "POP\t%0"
+ )
+
+(define_insn "popa"
+ [(set (match_operand:PSI 0 "register_operand" "=r")
+ (mem:PSI (post_inc:PSI (reg:PSI SP_REGNO))))]
+ "TARGET_LARGE"
+ "POPX.A\t%0"
+ )
+
+;; This is nasty. Operand0 is bogus. It is only there so that we can get a
+;; mode for the %b0 to work. We should use operand1 for this, but that does
+;; not have a mode.
+;;
+;; Operand1 is actually a register, but we cannot accept (REG...) because the
+;; cprop_hardreg pass can and will renumber registers even inside
+;; unspec_volatiles. So we take an integer register number parameter and
+;; fudge it to be a register name when we generate the assembler.
+;;
+;; The pushm pattern does not have this problem because of all of the
+;; frame info cruft attached to it, so cprop_hardreg leaves it alone.
+(define_insn "popm"
+ [(unspec_volatile [(match_operand 0 "register_operand" "r")
+ (match_operand 1 "immediate_operand" "i")
+ (match_operand 2 "immediate_operand" "i")] UNS_POPM)]
+ ""
+ "POPM%b0\t%2, r%J1"
+ )
+
+;; The next two patterns are here to support a "feature" of how GCC implements
+;; varargs. When a function uses varargs and the *second* to last named
+;; argument is split between argument registers and the stack, gcc expects the
+;; callee to allocate space on the stack that can contain the register-based
+;; part of the argument. This space *has* to be just before the remaining
+;; arguments (ie the ones that are fully on the stack).
+;;
+;; The problem is that the MSP430 CALL instruction pushes the return address
+;; onto the stack in the exact place where the callee wants to allocate
+;; this extra space. So we need a sequence of instructions that can allocate
+;; the extra space and then move the return address down the stack, so that
+;; the extra space is now adjacent to the remaining arguments.
+;;
+;; This could be constructed through regular insns, but they might be split up
+;; by a misguided optimization, so an unspec volatile is used instead.
+
+(define_insn "grow_and_swap"
+ [(unspec_volatile [(const_int 0)] UNS_GROW_AND_SWAP)]
+ ""
+ "*
+ if (TARGET_LARGE)
+ return \"SUBA\t#2, r1 { MOVX.A\t2(r1), 0(r1)\";
+ return \"SUB\t#2, r1 { MOV.W\t2(r1), 0(r1)\";
+ "
+)
+
+(define_insn "swap_and_shrink"
+ [(unspec_volatile [(const_int 0)] UNS_SWAP_AND_SHRINK)]
+ ""
+ "* return TARGET_LARGE
+ ? \"MOVX.A\t0(r1), 2(r1) { ADDA\t#2, SP\"
+ : \"MOV.W\t0(r1), 2(r1) { ADD\t#2, SP\";
+ ")
+
+; I set LOAD_EXTEND_OP and WORD_REGISTER_OPERATIONS, but gcc puts in a
+; zero_extend anyway. Catch it here.
+(define_insn "movqihi"
+ [(set (match_operand:HI 0 "register_operand" "=r,r")
+ (zero_extend:HI (match_operand:QI 1 "memory_operand" "Ys,m")))]
+ ""
+ "@
+ MOV.B\t%1, %0
+ MOV%X1.B\t%1, %0"
+)
+
+(define_insn "movqi"
+ [(set (match_operand:QI 0 "msp_nonimmediate_operand" "=rYs,rm")
+ (match_operand:QI 1 "msp_general_operand" "riYs,rmi"))]
+ ""
+ "@
+ MOV.B\t%1, %0
+ MOV%X0.B\t%1, %0"
+)
+
+(define_insn "movhi"
+ [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rYs,rm")
+ (match_operand:HI 1 "msp_general_operand" "riYs,rmi"))]
+ ""
+ "@
+ MOV.W\t%1, %0
+ MOV%X0.W\t%1, %0"
+)
+
+(define_expand "movsi"
+ [(set (match_operand:SI 0 "nonimmediate_operand")
+ (match_operand:SI 1 "general_operand"))]
+ ""
+ ""
+ )
+
+(define_insn_and_split "movsi_x"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+ (match_operand:SI 1 "general_operand" "rmi"))]
+ ""
+ "#"
+ "reload_completed"
+ [(set (match_operand:HI 2 "nonimmediate_operand")
+ (match_operand:HI 4 "general_operand"))
+ (set (match_operand:HI 3 "nonimmediate_operand")
+ (match_operand:HI 5 "general_operand"))]
+ "msp430_split_movsi (operands);"
+)
+
+;; Some MOVX.A cases can be done with MOVA, this is only a few of them.
+(define_insn "movpsi"
+ [(set (match_operand:PSI 0 "msp_nonimmediate_operand" "=r,Ya,rm")
+ (match_operand:PSI 1 "msp_general_operand" "riYa,r,rmi"))]
+ ""
+ "@
+ MOV%Q0\t%1, %0
+ MOV%Q0\t%1, %0
+ MOV%X0.%Q0\t%1, %0")
+
+; This pattern is identical to the truncsipsi2 pattern except
+; that it uses a SUBREG instead of a TRUNC. It is needed in
+; order to prevent reload from converting (set:SI (SUBREG:PSI (SI)))
+; into (SET:PSI (PSI)).
+;
+; Note: using POPM.A #1 is two bytes smaller than using POPX.A....
+
+(define_insn "movsipsi2"
+ [(set (match_operand:PSI 0 "register_operand" "=r")
+ (subreg:PSI (match_operand:SI 1 "register_operand" "r") 0))]
+ "TARGET_LARGE"
+ "PUSH.W\t%H1 { PUSH.W\t%L1 { POPM.A #1, %0 ; Move reg-pair %L1:%H1 into pointer %0"
+)
+
+;;------------------------------------------------------------
+;; Math
+
+(define_insn "addpsi3"
+ [(set (match_operand:PSI 0 "msp_nonimmediate_operand" "=r,rm")
+ (plus:PSI (match_operand:PSI 1 "msp_nonimmediate_operand" "%0,0")
+ (match_operand:PSI 2 "msp_general_operand" "rLs,rmi")))]
+ ""
+ "@
+ ADDA\t%2, %0
+ ADDX.A\t%2, %0"
+)
+
+(define_insn "addqi3"
+ [(set (match_operand:QI 0 "msp_nonimmediate_operand" "=rYs,rm")
+ (plus:QI (match_operand:QI 1 "msp_nonimmediate_operand" "%0,0")
+ (match_operand:QI 2 "msp_general_operand" "riYs,rmi")))]
+ ""
+ "@
+ ADD.B\t%2, %0
+ ADD%X0.B\t%2, %0"
+)
+
+(define_insn "addhi3"
+ [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rYs,rm")
+ (plus:HI (match_operand:HI 1 "msp_nonimmediate_operand" "%0,0")
+ (match_operand:HI 2 "msp_general_operand" "riYs,rmi")))]
+ ""
+ "@
+ ADD.W\t%2, %0
+ ADD%X0.W\t%2, %0"
+)
+
+; This pattern is needed in order to avoid reload problems.
+; It takes an SI pair of registers, adds a value to them, and
+; then converts them into a single PSI register.
+
+(define_insn "addsipsi3"
+ [(set (subreg:SI (match_operand:PSI 0 "register_operand" "=&r") 0)
+ (plus:SI (match_operand:SI 1 "register_operand" "0")
+ (match_operand 2 "general_operand" "rmi")))]
+ ""
+ "ADD.W\t%L2, %L0 { ADDC.W\t%H2, %H0 { PUSH.W\t%H0 { PUSH.W\t%L0 { POPM.A\t#1, %0"
+)
+
+(define_insn "addsi3"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=&r,rm")
+ (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:SI 2 "general_operand" "r,mi")))]
+ ""
+ "@
+ ADD\t%L2, %L0 { ADDC\t%H2, %H0
+ ADD%X0\t%L2, %L0 { ADDC%X0\t%H2, %H0"
+)
+
+; Version of addhi that exposes the carry operations, for SImode adds.
+;
+; NOTE - we are playing a dangerous game with GCC here. We have these two
+; add patterns and the splitter that follows because our tests have shown
+; that this results in a significant reduction in code size - because GCC is
+; able to discard any unused part of the addition. We have to annotate the
+; patterns with the set and use of the carry flag because otherwise GCC will
+; discard parts of the addition when they are actually needed. But we have
+; not annotated all the other patterns that set the CARRY flag as doing so
+; results in an overall increase in code size[1]. Instead we just *hope*
+; that GCC will not move a carry-setting instruction in between the first
+; and second adds.
+;
+; So far our experiments have shown that GCC is likely to move MOV and CMP
+; instructions in between the two adds, but not other instructions. MOV is
+; safe, CMP is not. So we have annotated the CMP patterns and left the
+; subtract, shift and other add patterns alone. At the moment this is
+; working, but with future changes to the generic parts of GCC that might
+; change.
+;
+; [1] It is not clear exactly why the code size increases. The cause appears
+; to be that reload is more prevelent to spilling a variable onto the stack
+; but why it does this is unknown. Possibly the additional CLOBBERs necessary
+; to correctly annotate the other patterns makes reload think that there is
+; increased register pressure. Or possibly reload does not handle ADD patterns
+; that are not single_set() very well.
+
+(define_insn "addhi3_cy"
+ [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=r,rm")
+ (plus:HI (match_operand:HI 1 "msp_nonimmediate_operand" "%0,0")
+ (match_operand:HI 2 "msp_nonimmediate_operand" "r,rm")))
+ (set (reg:BI CARRY)
+ (truncate:BI (lshiftrt:SI (plus:SI (zero_extend:SI (match_dup 1))
+ (zero_extend:SI (match_dup 2)))
+ (const_int 16))))
+ ]
+ ""
+ "@
+ ADD\t%2, %1 ; cy
+ ADD%X0\t%2, %1 ; cy"
+ )
+
+(define_insn "addhi3_cy_i"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=r,rm")
+ (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:HI 2 "immediate_operand" "i,i")))
+ (set (reg:BI CARRY)
+ (truncate:BI (lshiftrt:SI (plus:SI (zero_extend:SI (match_dup 1))
+ (match_operand 3 "immediate_operand" "i,i"))
+ (const_int 16))))
+ ]
+ ""
+ "@
+ ADD\t%2, %1 ; cy
+ ADD%X0\t%2, %1 ; cy"
+ )
+
+; Version of addhi that adds the carry, for SImode adds.
+(define_insn "addchi4_cy"
+ [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=r,rm")
+ (plus:HI (plus:HI (match_operand:HI 1 "msp_nonimmediate_operand" "%0,0")
+ (match_operand:HI 2 "msp_general_operand" "ri,rmi"))
+ (zero_extend:HI (reg:BI CARRY))))
+ ]
+ ""
+ "@
+ ADDC\t%2, %1
+ ADDC%X0\t%2, %1"
+ )
+
+; Split an SImode add into two HImode adds, keeping track of the carry
+; so that gcc knows when it can and can't optimize away the two
+; halves.
+(define_split
+ [(set (match_operand:SI 0 "msp430_nonsubreg_operand")
+ (plus:SI (match_operand:SI 1 "nonimmediate_operand")
+ (match_operand:SI 2 "general_operand")))
+ ]
+ ""
+ [(parallel [(set (match_operand:HI 3 "nonimmediate_operand" "=&rm")
+ (plus:HI (match_dup 4)
+ (match_dup 5)))
+ (set (reg:BI CARRY)
+ (truncate:BI (lshiftrt:SI (plus:SI (zero_extend:SI (match_dup 4))
+ (match_dup 9))
+ (const_int 16))))
+ ])
+ (set (match_operand:HI 6 "nonimmediate_operand" "=&rm")
+ (plus:HI (plus:HI (match_dup 7)
+ (match_dup 8))
+ (zero_extend:HI (reg:BI CARRY))))
+ ]
+ "
+ operands[3] = msp430_subreg (HImode, operands[0], SImode, 0);
+ operands[4] = msp430_subreg (HImode, operands[1], SImode, 0);
+ operands[5] = msp430_subreg (HImode, operands[2], SImode, 0);
+ operands[6] = msp430_subreg (HImode, operands[0], SImode, 2);
+ operands[7] = msp430_subreg (HImode, operands[1], SImode, 2);
+ operands[8] = msp430_subreg (HImode, operands[2], SImode, 2);
+ if (GET_CODE (operands[5]) == CONST_INT)
+ {
+ operands[9] = GEN_INT (INTVAL (operands[5]) & 0xffff);
+ }
+ else
+ {
+ operands[9] = gen_rtx_ZERO_EXTEND (SImode, operands[5]);
+ }
+ "
+ )
+
+
+;; Alternatives 2 and 3 are to handle cases generated by reload.
+(define_insn "subpsi3"
+ [(set (match_operand:PSI 0 "nonimmediate_operand" "=r, rm, &?r, ?&r")
+ (minus:PSI (match_operand:PSI 1 "general_operand" "0, 0, !r, !i")
+ (match_operand:PSI 2 "general_operand" "rLs, rmi, rmi, r")))]
+ ""
+ "@
+ SUBA\t%2, %0
+ SUBX.A\t%2, %0
+ MOVX.A\t%1, %0 { SUBX.A\t%2, %0
+ MOVX.A\t%1, %0 { SUBA\t%2, %0"
+)
+
+;; Alternatives 2 and 3 are to handle cases generated by reload.
+(define_insn "subqi3"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=rYs, rm, &?r, ?&r")
+ (minus:QI (match_operand:QI 1 "general_operand" "0, 0, !r, !i")
+ (match_operand:QI 2 "general_operand" " riYs, rmi, rmi, r")))]
+ ""
+ "@
+ SUB.B\t%2, %0
+ SUB%X0.B\t%2, %0
+ MOV%X0.B\t%1, %0 { SUB%X0.B\t%2, %0
+ MOV%X0.B\t%1, %0 { SUB%X0.B\t%2, %0"
+)
+
+;; Alternatives 2 and 3 are to handle cases generated by reload.
+(define_insn "subhi3"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rYs, rm, &?r, ?&r")
+ (minus:HI (match_operand:HI 1 "general_operand" "0, 0, !r, !i")
+ (match_operand:HI 2 "general_operand" " riYs, rmi, rmi, r")))]
+ ""
+ "@
+ SUB.W\t%2, %0
+ SUB%X0.W\t%2, %0
+ MOV%X0.W\t%1, %0 { SUB%X0.W\t%2, %0
+ MOV%X0.W\t%1, %0 { SUB%X0.W\t%2, %0"
+)
+
+(define_insn "subsi3"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=&rm")
+ (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0")
+ (match_operand:SI 2 "general_operand" "rmi")))]
+ ""
+ "SUB%X0\t%L2, %L0 { SUBC%X0\t%H2, %H0"
+)
+
+(define_insn "*bic<mode>_cg"
+ [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,m")
+ (and:QHI (match_operand:QHI 1 "msp_general_operand" "0,0")
+ (match_operand 2 "msp430_inv_constgen_operator" "n,n")))]
+ ""
+ "@
+ BIC%x0%b0\t#%I2, %0
+ BIC%X0%b0\t#%I2, %0"
+)
+
+(define_insn "bic<mode>3"
+ [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,rm")
+ (and:QHI (not:QHI (match_operand:QHI 1 "msp_general_operand" "rYs,rmn"))
+ (match_operand:QHI 2 "msp_nonimmediate_operand" "0,0")))]
+ ""
+ "@
+ BIC%x0%b0\t%1, %0
+ BIC%X0%b0\t%1, %0"
+)
+
+(define_insn "and<mode>3"
+ [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,rm")
+ (and:QHI (match_operand:QHI 1 "msp_nonimmediate_operand" "%0,0")
+ (match_operand:QHI 2 "msp_general_operand" "riYs,rmi")))]
+ ""
+ "@
+ AND%x0%b0\t%2, %0
+ AND%X0%b0\t%2, %0"
+)
+
+(define_insn "ior<mode>3"
+ [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,rm")
+ (ior:QHI (match_operand:QHI 1 "msp_nonimmediate_operand" "%0,0")
+ (match_operand:QHI 2 "msp_general_operand" "riYs,rmi")))]
+ ""
+ "@
+ BIS%x0%b0\t%2, %0
+ BIS%X0%b0\t%2, %0"
+)
+
+(define_insn "xor<mode>3"
+ [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,rm")
+ (xor:QHI (match_operand:QHI 1 "msp_nonimmediate_operand" "%0,0")
+ (match_operand:QHI 2 "msp_general_operand" "riYs,rmi")))]
+ ""
+ "@
+ XOR%x0%b0\t%2, %0
+ XOR%X0%b0\t%2, %0"
+)
+
+;; Macro : XOR #~0, %0
+(define_insn "one_cmpl<mode>2"
+ [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,m")
+ (not:QHI (match_operand:QHI 1 "msp_nonimmediate_operand" "0,0")))]
+ ""
+ "@
+ INV%x0%b0\t%0
+ INV%X0%b0\t%0"
+)
+
+(define_insn "extendqihi2"
+ [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rYs,m")
+ (sign_extend:HI (match_operand:QI 1 "msp_nonimmediate_operand" "0,0")))]
+ ""
+ "@
+ SXT%X0\t%0
+ SXT%X0\t%0"
+)
+
+(define_insn "zero_extendqihi2"
+ [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rYs,m")
+ (zero_extend:HI (match_operand:QI 1 "msp_nonimmediate_operand" "0,0")))]
+ ""
+ "@
+ AND\t#0xff, %0
+ AND%X0\t#0xff, %0"
+)
+
+;; Eliminate extraneous zero-extends mysteriously created by gcc.
+(define_peephole2
+ [(set (match_operand:HI 0 "register_operand")
+ (zero_extend:HI (match_operand:QI 1 "general_operand")))
+ (set (match_operand:HI 2 "register_operand")
+ (zero_extend:HI (match_operand:QI 3 "register_operand")))]
+ "REGNO (operands[0]) == REGNO (operands[2]) && REGNO (operands[2]) == REGNO (operands[3])"
+ [(set (match_dup 0)
+ (zero_extend:HI (match_dup 1)))]
+)
+
+(define_insn "zero_extendhipsi2"
+ [(set (match_operand:PSI 0 "msp_nonimmediate_operand" "=r,m")
+ (zero_extend:PSI (match_operand:HI 1 "msp_nonimmediate_operand" "rm,r")))]
+ ""
+ "MOVX\t%1, %0"
+)
+
+(define_insn "truncpsihi2"
+ [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rm")
+ (truncate:HI (match_operand:PSI 1 "register_operand" "r")))]
+ ""
+ "MOVX\t%1, %0"
+)
+
+(define_insn "extendhisi2"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r")
+ (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r")))]
+ ""
+ { return msp430x_extendhisi (operands); }
+)
+
+(define_insn "extendhipsi2"
+ [(set (match_operand:PSI 0 "nonimmediate_operand" "=r")
+ (subreg:PSI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0")) 0))]
+ "TARGET_LARGE"
+ "RLAM #4, %0 { RRAM #4, %0"
+)
+
+;; Look for cases where integer/pointer conversions are suboptimal due
+;; to missing patterns, despite us not having opcodes for these
+;; patterns. Doing these manually allows for alternate optimization
+;; paths.
+(define_insn "zero_extendhisi2"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0")))]
+ "TARGET_LARGE"
+ "MOV.W\t#0,%H0"
+)
+
+(define_insn "zero_extendhisipsi2"
+ [(set (match_operand:PSI 0 "nonimmediate_operand" "=r,r")
+ (subreg:PSI (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0,r")) 0))]
+ "TARGET_LARGE"
+ "@
+ AND.W\t#-1,%0
+ MOV.W\t%1,%0"
+)
+
+(define_insn "extend_and_shift1_hipsi2"
+ [(set (subreg:SI (match_operand:PSI 0 "nonimmediate_operand" "=r") 0)
+ (ashift:SI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0"))
+ (const_int 1)))]
+ "TARGET_LARGE"
+ "RLAM #4, %0 { RRAM #3, %0"
+)
+
+(define_insn "extend_and_shift2_hipsi2"
+ [(set (subreg:SI (match_operand:PSI 0 "nonimmediate_operand" "=r") 0)
+ (ashift:SI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0"))
+ (const_int 2)))]
+ "TARGET_LARGE"
+ "RLAM #4, %0 { RRAM #2, %0"
+)
+
+; Nasty - we are sign-extending a 20-bit PSI value in one register into
+; two adjacent 16-bit registers to make an SI value. There is no MSP430X
+; instruction that will do this, so we push the 20-bit value onto the stack
+; and then pop it off as two 16-bit values.
+;
+; FIXME: The MSP430X documentation does not specify if zero-extension or
+; sign-extension happens when the 20-bit value is pushed onto the stack.
+; It is probably zero-extension, but if not this pattern will not work
+; when the PSI value is negative..
+;
+; Note: using PUSHM.A #1 is two bytes smaller than using PUSHX.A....
+
+(define_insn "zero_extendpsisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extend:SI (match_operand:PSI 1 "register_operand" "r")))]
+ ""
+ "*
+ if (REGNO (operands[1]) == SP_REGNO)
+ /* If the source register is the stack pointer, the value
+ stored in the stack slot will be the value *after* the
+ stack pointer has been decremented. So allow for that
+ here. */
+ return \"PUSHM.A\t#1, %1 { ADDX.W\t#4, @r1 { POPX.W\t%L0 { POPX.W\t%H0 ; get stack pointer into %L0:%H0\";
+ else
+ return \"PUSHM.A\t#1, %1 { POPX.W\t%L0 { POPX.W\t%H0 ; move pointer in %1 into reg-pair %L0:%H0\";
+ "
+)
+
+;; We also need to be able to sign-extend pointer types (eg ptrdiff_t).
+;; Since (we assume) pushing a 20-bit value onto the stack zero-extends
+;; it, we use a different method here.
+
+(define_insn "extendpsisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (match_operand:PSI 1 "register_operand" "r")))]
+ "TARGET_LARGE"
+ "*
+ /* The intention here is that we copy the bottom 16-bits of
+ %1 into %L0 (zeroing the top four bits). Then we copy the
+ entire 20-bits of %1 into %H0 and then arithmetically shift
+ it right by 16 bits, to get the top four bits of the pointer
+ sign-extended in %H0. */
+ if (REGNO (operands[0]) == REGNO (operands[1]))
+ return \"MOVX.A\t%1, %H0 { MOV.W\t%1, %L0 { RPT\t#16 { RRAX.A\t%H0 ; sign extend pointer in %1 into %L0:%H0\";
+ else
+ return \"MOV.W\t%1, %L0 { MOVX.A\t%1, %H0 { RPT\t#16 { RRAX.A\t%H0 ; sign extend pointer in %1 into %L0:%H0\";
+ "
+)
+
+; See the movsipsi2 pattern above for another way that GCC performs this
+; conversion.
+(define_insn "truncsipsi2"
+ [(set (match_operand:PSI 0 "register_operand" "=r")
+ (truncate:PSI (match_operand:SI 1 "register_operand" "r")))]
+ ""
+ "PUSH.W\t%H1 { PUSH.W\t%L1 { POPM.A\t#1, %L0"
+)
+
+;;------------------------------------------------------------
+;; Shift Functions
+
+;; Note: We do not use the RPT ... SHIFT instruction sequence
+;; when the repeat count is in a register, because even though RPT
+;; accepts counts in registers, it does not work if the count is
+;; zero, and the actual count in the register has to be one less
+;; than the required number of iterations. We could encode a
+;; seqeunce like this:
+;;
+;; bit #0xf, Rn
+;; bz 1f
+;; dec Rn
+;; rpt Rn
+;; <shift> Rm
+;; inc Rn
+;; 1:
+;;
+;; But is longer than calling a helper function, and we are mostly
+;; concerned with code size. FIXME: Maybe enable a sequence like
+;; this at -O3 and above ?
+;;
+;; Note - we ignore shift counts of less than one or more than 15.
+;; This is permitted by the ISO C99 standard as such shifts result
+;; in "undefined" behaviour. [6.5.7 (3)]
+
+;; signed A << C
+
+(define_expand "ashlhi3"
+ [(set (match_operand:HI 0 "nonimmediate_operand")
+ (ashift:HI (match_operand:HI 1 "general_operand")
+ (match_operand:HI 2 "general_operand")))]
+ ""
+ {
+ if (msp430x
+ && REG_P (operands[0])
+ && REG_P (operands[1])
+ && CONST_INT_P (operands[2]))
+ emit_insn (gen_430x_shift_left (operands[0], operands[1], operands[2]));
+ else
+ msp430_expand_helper (operands, \"__mspabi_slli\", true);
+ DONE;
+ }
+)
+
+(define_insn "slli_1"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
+ (ashift:HI (match_operand:HI 1 "general_operand" "0")
+ (const_int 1)))]
+ ""
+ "RLA.W\t%0" ;; Note - this is a macro for ADD
+)
+
+(define_insn "430x_shift_left"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (ashift:HI (match_operand:HI 1 "register_operand" "0")
+ (match_operand 2 "immediate_operand" "n")))]
+ "msp430x"
+ "*
+ if (INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 16)
+ return \"rpt\t%2 { rlax.w\t%0\";
+ return \"# nop left shift\";
+ "
+)
+
+(define_insn "slll_1"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+ (ashift:SI (match_operand:SI 1 "general_operand" "0")
+ (const_int 1)))]
+ ""
+ "RLA.W\t%L0 { RLC.W\t%H0"
+)
+
+(define_insn "slll_2"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+ (ashift:SI (match_operand:SI 1 "general_operand" "0")
+ (const_int 2)))]
+ ""
+ "RLA.W\t%L0 { RLC.W\t%H0 { RLA.W\t%L0 { RLC.W\t%H0"
+)
+
+(define_expand "ashlsi3"
+ [(set (match_operand:SI 0 "nonimmediate_operand")
+ (ashift:SI (match_operand:SI 1 "general_operand")
+ (match_operand:SI 2 "general_operand")))]
+ ""
+ "msp430_expand_helper (operands, \"__mspabi_slll\", true);
+ DONE;"
+)
+
+;;----------
+
+;; signed A >> C
+
+(define_expand "ashrhi3"
+ [(set (match_operand:HI 0 "nonimmediate_operand")
+ (ashiftrt:HI (match_operand:HI 1 "general_operand")
+ (match_operand:HI 2 "general_operand")))]
+ ""
+ {
+ if (msp430x
+ && REG_P (operands[0])
+ && REG_P (operands[1])
+ && CONST_INT_P (operands[2]))
+ emit_insn (gen_430x_arithmetic_shift_right (operands[0], operands[1], operands[2]));
+ else
+ msp430_expand_helper (operands, \"__mspabi_srai\", true);
+ DONE;
+ }
+)
+
+(define_insn "srai_1"
+ [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rm")
+ (ashiftrt:HI (match_operand:HI 1 "msp_general_operand" "0")
+ (const_int 1)))]
+ ""
+ "RRA.W\t%0"
+)
+
+(define_insn "430x_arithmetic_shift_right"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (ashiftrt:HI (match_operand:HI 1 "register_operand" "0")
+ (match_operand 2 "immediate_operand" "n")))]
+ "msp430x"
+ "*
+ if (INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 16)
+ return \"rpt\t%2 { rrax.w\t%0\";
+ return \"# nop arith right shift\";
+ "
+)
+
+(define_insn "srap_1"
+ [(set (match_operand:PSI 0 "register_operand" "=r")
+ (ashiftrt:PSI (match_operand:PSI 1 "general_operand" "0")
+ (const_int 1)))]
+ "msp430x"
+ "RRAM.A #1,%0"
+)
+
+(define_insn "srap_2"
+ [(set (match_operand:PSI 0 "register_operand" "=r")
+ (ashiftrt:PSI (match_operand:PSI 1 "general_operand" "0")
+ (const_int 2)))]
+ "msp430x"
+ "RRAM.A #2,%0"
+)
+
+(define_insn "sral_1"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+ (ashiftrt:SI (match_operand:SI 1 "general_operand" "0")
+ (const_int 1)))]
+ ""
+ "RRA.W\t%H0 { RRC.W\t%L0"
+)
+
+(define_insn "sral_2"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+ (ashiftrt:SI (match_operand:SI 1 "general_operand" "0")
+ (const_int 2)))]
+ ""
+ "RRA.W\t%H0 { RRC.W\t%L0 { RRA.W\t%H0 { RRC.W\t%L0"
+)
+
+(define_expand "ashrsi3"
+ [(set (match_operand:SI 0 "nonimmediate_operand")
+ (ashiftrt:SI (match_operand:SI 1 "general_operand")
+ (match_operand:SI 2 "general_operand")))]
+ ""
+ "msp430_expand_helper (operands, \"__mspabi_sral\", true);
+ DONE;"
+)
+
+;;----------
+
+;; unsigned A >> C
+
+(define_expand "lshrhi3"
+ [(set (match_operand:HI 0 "nonimmediate_operand")
+ (lshiftrt:HI (match_operand:HI 1 "general_operand")
+ (match_operand:HI 2 "general_operand")))]
+ ""
+ {
+ if (msp430x
+ && REG_P (operands[0])
+ && REG_P (operands[1])
+ && CONST_INT_P (operands[2]))
+ emit_insn (gen_430x_logical_shift_right (operands[0], operands[1], operands[2]));
+ else
+ msp430_expand_helper (operands, \"__mspabi_srli\", true);
+ DONE;
+ }
+)
+
+(define_insn "srli_1"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
+ (lshiftrt:HI (match_operand:HI 1 "general_operand" "0")
+ (const_int 1)))]
+ ""
+ "CLRC { RRC.W\t%0"
+)
+
+(define_insn "430x_logical_shift_right"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (lshiftrt:HI (match_operand:HI 1 "register_operand" "0")
+ (match_operand 2 "immediate_operand" "n")))]
+ "msp430x"
+ {
+ return msp430x_logical_shift_right (operands[2]);
+ }
+)
+
+(define_insn "srlp_1"
+ [(set (match_operand:PSI 0 "register_operand" "=r")
+ (lshiftrt:PSI (match_operand:PSI 1 "general_operand" "0")
+ (const_int 1)))]
+ ""
+ "RRUM.A #1,%0"
+)
+
+(define_insn "srll_1"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+ (lshiftrt:SI (match_operand:SI 1 "general_operand" "0")
+ (const_int 1)))]
+ ""
+ "CLRC { RRC.W\t%H0 { RRC.W\t%L0"
+)
+
+(define_insn "srll_2x"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r")
+ (lshiftrt:SI (match_operand:SI 1 "general_operand" "0")
+ (const_int 2)))]
+ "msp430x"
+ "RRUX.W\t%H0 { RRC.W\t%L0 { RRUX.W\t%H0 { RRC.W\t%L0"
+)
+
+(define_expand "lshrsi3"
+ [(set (match_operand:SI 0 "nonimmediate_operand")
+ (lshiftrt:SI (match_operand:SI 1 "general_operand")
+ (match_operand:SI 2 "general_operand")))]
+ ""
+ "msp430_expand_helper (operands, \"__mspabi_srll\", true);
+ DONE;"
+)
+
+;;------------------------------------------------------------
+;; Function Entry/Exit
+
+(define_expand "prologue"
+ [(const_int 0)]
+ ""
+ "msp430_expand_prologue (); DONE;"
+ )
+
+(define_expand "epilogue"
+ [(const_int 0)]
+ ""
+ "msp430_expand_epilogue (0); DONE;"
+ )
+
+
+(define_insn "epilogue_helper"
+ [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] UNS_EPILOGUE_HELPER)]
+ ""
+ "BR%Q0\t#__mspabi_func_epilog_%J0"
+ )
+
+
+(define_insn "prologue_start_marker"
+ [(unspec_volatile [(const_int 0)] UNS_PROLOGUE_START_MARKER)]
+ ""
+ "; start of prologue"
+ )
+
+(define_insn "prologue_end_marker"
+ [(unspec_volatile [(const_int 0)] UNS_PROLOGUE_END_MARKER)]
+ ""
+ "; end of prologue"
+ )
+
+(define_insn "epilogue_start_marker"
+ [(unspec_volatile [(const_int 0)] UNS_EPILOGUE_START_MARKER)]
+ ""
+ "; start of epilogue"
+ )
+
+;; This makes the linker add a call to exit() after the call to main()
+;; in crt0
+(define_insn "msp430_refsym_need_exit"
+ [(unspec_volatile [(const_int 0)] UNS_REFSYM_NEED_EXIT)]
+ ""
+ ".refsym\t__crt0_call_exit"
+ )
+
+;;------------------------------------------------------------
+;; Jumps
+
+(define_expand "call"
+ [(call:HI (match_operand 0 "")
+ (match_operand 1 ""))]
+ ""
+ ""
+)
+
+(define_insn "call_internal"
+ [(call (mem:HI (match_operand 0 "general_operand" "rYci"))
+ (match_operand 1 ""))]
+ ""
+ "CALL%Q0\t%0"
+)
+
+(define_expand "call_value"
+ [(set (match_operand 0 "register_operand")
+ (call:HI (match_operand 1 "general_operand")
+ (match_operand 2 "")))]
+ ""
+ ""
+)
+
+(define_insn "call_value_internal"
+ [(set (match_operand 0 "register_operand" "=r")
+ (call (mem:HI (match_operand 1 "general_operand" "rYci"))
+ (match_operand 2 "")))]
+ ""
+ "CALL%Q0\t%1"
+)
+
+(define_insn "msp_return"
+ [(return)]
+ ""
+ { return msp430_is_interrupt_func () ? "RETI" : (TARGET_LARGE ? "RETA" : "RET"); }
+)
+
+;; This pattern is NOT, as expected, a return pattern. It's called
+;; before reload and must only store its operands, and emit a
+;; placeholder where the epilog needs to be. AFTER reload, the
+;; placeholder should get expanded into a regular-type epilogue that
+;; also does the EH return.
+(define_expand "eh_return"
+ [(match_operand:HI 0 "")]
+ ""
+ "msp430_expand_eh_return (operands[0]);
+ emit_jump_insn (gen_msp430_eh_epilogue ());
+ emit_barrier ();
+ DONE;"
+)
+
+;; This is the actual EH epilogue. We emit it in the pattern above,
+;; before reload, and convert it to a real epilogue after reload.
+(define_insn_and_split "msp430_eh_epilogue"
+ [(eh_return)]
+ ""
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+ "msp430_expand_epilogue (1); DONE;"
+ )
+
+(define_insn "jump"
+ [(set (pc)
+ (label_ref (match_operand 0 "" "")))]
+ ""
+ "BR%Q0\t#%l0"
+)
+
+;; FIXME: GCC currently (8/feb/2013) cannot handle symbol_refs
+;; in indirect jumps (cf gcc.c-torture/compile/991213-3.c).
+(define_insn "indirect_jump"
+ [(set (pc)
+ (match_operand 0 "nonimmediate_operand" "rYl"))]
+ ""
+ "BR%Q0\t%0"
+)
+
+;;------------------------------------------------------------
+;; Various Conditionals
+
+(define_expand "cbranch<mode>4"
+ [(parallel [(set (pc) (if_then_else
+ (match_operator 0 ""
+ [(match_operand:QHI 1 "nonimmediate_operand")
+ (match_operand:QHI 2 "general_operand")])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))
+ (clobber (reg:BI CARRY))]
+ )]
+ ""
+ "msp430_fixup_compare_operands (<MODE>mode, operands);"
+ )
+
+(define_insn "cbranchpsi4_real"
+ [(set (pc) (if_then_else
+ (match_operator 0 "msp430_cmp_operator"
+ [(match_operand:PSI 1 "nonimmediate_operand" "r,rYs,rm")
+ (match_operand:PSI 2 "general_operand" "rLs,rYsi,rmi")])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))
+ (clobber (reg:BI CARRY))
+ ]
+ ""
+ "@
+ CMP%Q0\t%2, %1 { J%0\t%l3
+ CMPX.A\t%2, %1 { J%0\t%l3
+ CMPX.A\t%2, %1 { J%0\t%l3"
+ )
+
+(define_insn "cbranchqi4_real"
+ [(set (pc) (if_then_else
+ (match_operator 0 "msp430_cmp_operator"
+ [(match_operand:QI 1 "nonimmediate_operand" "rYs,rm")
+ (match_operand:QI 2 "general_operand" "rYsi,rmi")])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))
+ (clobber (reg:BI CARRY))
+ ]
+ ""
+ "@
+ CMP.B\t%2, %1 { J%0\t%l3
+ CMP%X0.B\t%2, %1 { J%0\t%l3"
+ )
+
+(define_insn "cbranchhi4_real"
+ [(set (pc) (if_then_else
+ (match_operator 0 "msp430_cmp_operator"
+ [(match_operand:HI 1 "nonimmediate_operand" "rYs,rm")
+ (match_operand:HI 2 "general_operand" "rYsi,rmi")])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))
+ (clobber (reg:BI CARRY))
+ ]
+ ""
+ "@
+ CMP.W\t%2, %1 { J%0\t%l3
+ CMP%X0.W\t%2, %1 { J%0\t%l3"
+ )
+
+(define_insn "cbranchpsi4_reversed"
+ [(set (pc) (if_then_else
+ (match_operator 0 "msp430_reversible_cmp_operator"
+ [(match_operand:PSI 1 "general_operand" "rLs,rYsi,rmi")
+ (match_operand:PSI 2 "general_operand" "r,rYs,rm")])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))
+ (clobber (reg:BI CARRY))
+ ]
+ ""
+ "@
+ CMP%Q0\t%1, %2 { J%R0\t%l3
+ CMPX.A\t%1, %2 { J%R0\t%l3
+ CMPX.A\t%1, %2 { J%R0\t%l3"
+ )
+
+(define_insn "cbranchqi4_reversed"
+ [(set (pc) (if_then_else
+ (match_operator 0 "msp430_reversible_cmp_operator"
+ [(match_operand:QI 1 "general_operand" "rYsi,rmi")
+ (match_operand:QI 2 "general_operand" "rYs,rm")])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))
+ (clobber (reg:BI CARRY))
+ ]
+ ""
+ "@
+ CMP.B\t%1, %2 { J%R0\t%l3
+ CMP%X0.B\t%1, %2 { J%R0\t%l3"
+ )
+
+(define_insn "cbranchhi4_reversed"
+ [(set (pc) (if_then_else
+ (match_operator 0 "msp430_reversible_cmp_operator"
+ [(match_operand:HI 1 "general_operand" "rYsi,rmi")
+ (match_operand:HI 2 "general_operand" "rYs,rm")])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))
+ (clobber (reg:BI CARRY))
+ ]
+ ""
+ "@
+ CMP.W\t%1, %2 { J%R0\t%l3
+ CMP%X0.W\t%1, %2 { J%R0\t%l3"
+ )
+
+(define_insn "*bitbranch<mode>4"
+ [(set (pc) (if_then_else
+ (ne (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rYs,rm")
+ (match_operand:QHI 1 "msp_general_operand" "rYsi,rmi"))
+ (const_int 0))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))
+ (clobber (reg:BI CARRY))
+ ]
+ ""
+ "@
+ BIT%x0%b0\t%1, %0 { JNE\t%l2
+ BIT%X0%b0\t%1, %0 { JNE\t%l2"
+ )
+
+(define_insn "*bitbranch<mode>4"
+ [(set (pc) (if_then_else
+ (eq (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm")
+ (match_operand:QHI 1 "msp_general_operand" "rmi"))
+ (const_int 0))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))
+ (clobber (reg:BI CARRY))
+ ]
+ ""
+ "BIT%x0%X0%b0\t%1, %0 { JEQ\t%l2"
+ )
+
+(define_insn "*bitbranch<mode>4"
+ [(set (pc) (if_then_else
+ (eq (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm")
+ (match_operand:QHI 1 "msp_general_operand" "rmi"))
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 2 "" ""))))
+ (clobber (reg:BI CARRY))
+ ]
+ ""
+ "BIT%X0%b0\t%1, %0 { JNE\t%l2"
+ )
+
+(define_insn "*bitbranch<mode>4"
+ [(set (pc) (if_then_else
+ (ne (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm")
+ (match_operand:QHI 1 "msp_general_operand" "rmi"))
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 2 "" ""))))
+ (clobber (reg:BI CARRY))
+ ]
+ ""
+ "BIT%X0%b0\t%1, %0 { JEQ\t%l2"
+ )
+
+;;------------------------------------------------------------
+;; zero-extract versions of the above
+
+(define_insn "*bitbranch<mode>4_z"
+ [(set (pc) (if_then_else
+ (ne (zero_extract:HI (match_operand:QHI 0 "msp_nonimmediate_operand" "rYs,rm")
+ (const_int 1)
+ (match_operand 1 "msp430_bitpos" "i,i"))
+ (const_int 0))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))
+ (clobber (reg:BI CARRY))
+ ]
+ ""
+ "@
+ BIT%x0%b0\t%p1, %0 { JNE\t%l2
+ BIT%X0%b0\t%p1, %0 { JNE\t%l2"
+ )
+
+(define_insn "*bitbranch<mode>4_z"
+ [(set (pc) (if_then_else
+ (eq (zero_extract:HI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm")
+ (const_int 1)
+ (match_operand 1 "msp430_bitpos" "i"))
+ (const_int 0))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))
+ (clobber (reg:BI CARRY))
+ ]
+ ""
+ "BIT%x0%X0%b0\t%p1, %0 { JEQ\t%l2"
+ )
+
+(define_insn "*bitbranch<mode>4_z"
+ [(set (pc) (if_then_else
+ (eq (zero_extract:HI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm")
+ (const_int 1)
+ (match_operand 1 "msp430_bitpos" "i"))
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 2 "" ""))))
+ (clobber (reg:BI CARRY))
+ ]
+ ""
+ "BIT%X0%b0\t%p1, %0 { JNE\t%l2"
+ )
+
+(define_insn "*bitbranch<mode>4_z"
+ [(set (pc) (if_then_else
+ (ne (zero_extract:HI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm")
+ (const_int 1)
+ (match_operand 1 "msp430_bitpos" "i"))
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 2 "" ""))))
+ (clobber (reg:BI CARRY))
+ ]
+ ""
+ "BIT%X0%b0\t%p1, %0 { JEQ\t%l2"
+ )
+
+;;------------------------------------------------------------
+;; Misc
+
+(define_insn "nop"
+ [(const_int 0)]
+ "1"
+ "NOP"
+)
+
+(define_insn "disable_interrupts"
+ [(unspec_volatile [(const_int 0)] UNS_DINT)]
+ ""
+ "DINT \; NOP"
+ )
+
+(define_insn "enable_interrupts"
+ [(unspec_volatile [(const_int 0)] UNS_EINT)]
+ ""
+ "EINT"
+ )
+
+(define_insn "push_intr_state"
+ [(unspec_volatile [(const_int 0)] UNS_PUSH_INTR)]
+ ""
+ "PUSH\tSR"
+ )
+
+(define_insn "pop_intr_state"
+ [(unspec_volatile [(const_int 0)] UNS_POP_INTR)]
+ ""
+ "POP\tSR"
+ )
+
+;; Clear bits in the copy of the status register that is currently
+;; saved on the stack at the top of the interrupt handler.
+(define_insn "bic_SR"
+ [(unspec_volatile [(match_operand 0 "nonmemory_operand" "ir")] UNS_BIC_SR)]
+ ""
+ "BIC.W\t%0, %O0(SP)"
+ )
+
+;; Set bits in the copy of the status register that is currently
+;; saved on the stack at the top of the interrupt handler.
+(define_insn "bis_SR"
+ [(unspec_volatile [(match_operand 0 "nonmemory_operand" "ir")] UNS_BIS_SR)]
+ ""
+ "BIS.W\t%0, %O0(SP)"
+ )
+
+;; For some reason GCC is generating (set (reg) (and (neg (reg)) (int)))
+;; very late on in the compilation and not splitting it into separate
+;; instructions, so we provide a pattern to support it here.
+(define_insn "andneghi3"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (and:HI (neg:HI (match_operand:HI 1 "register_operand" "r"))
+ (match_operand 2 "immediate_operand" "n")))]
+ ""
+ "*
+ if (REGNO (operands[0]) != REGNO (operands[1]))
+ return \"MOV.W\t%1, %0 { SUB.W\t#0, %0 { AND.W\t%2, %0\";
+ else
+ return \"SUB.W\t#0, %0 { AND.W\t%2, %0\";
+ "
+ )
+
+(define_insn "mulhisi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0"))
+ (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
+ "optimize > 2 && msp430_hwmult_enabled ()"
+ "*
+ if (msp430_is_f5_mcu ())
+ return \"MOV.W %1, &0x04C2 { MOV.W %2, &0x04C8 { MOV.W &0x04CA, %L0 { MOV.W &0x04CC, %H0\";
+ else
+ return \"MOV.W %1, &0x0132 { MOV.W %2, &0x0138 { MOV.W &0x013A, %L0 { MOV.W &0x013C, %H0\";
+ "
+)
+
+(define_insn "umulhisi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "%0"))
+ (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
+ "optimize > 2 && msp430_hwmult_enabled ()"
+ "*
+ if (msp430_is_f5_mcu ())
+ return \"MOV.W %1, &0x04C0 { MOV.W %2, &0x04C8 { MOV.W &0x04CA, %L0 { MOV.W &0x04CC, %H0\";
+ else
+ return \"MOV.W %1, &0x0130 { MOV.W %2, &0x0138 { MOV.W &0x013A, %L0 { MOV.W &0x013C, %H0\";
+ "
+)
+
+(define_insn "mulsidi3"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%0"))
+ (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
+ "optimize > 2 && msp430_hwmult_enabled ()"
+ "*
+ if (msp430_is_f5_mcu ())
+ return \"MOV.W %L1, &0x04D4 { MOV.W %H1, &0x04D6 { MOV.W %L2, &0x04E0 { MOV.W %H2, &0x04E2 { MOV.W &0x04E4, %A0 { MOV.W &0x04E6, %B0 { MOV.W &0x04E8, %C0 { MOV.W &0x04EA, %D0\";
+ else
+ return \"MOV.W %L1, &0x0144 { MOV.W %H1, &0x0146 { MOV.W %L2, &0x0150 { MOV.W %H2, &0x0152 { MOV.W &0x0154, %A0 { MOV.W &0x0156, %B0 { MOV.W &0x0158, %C0 { MOV.W &0x015A, %D0\";
+ "
+)
+
+(define_insn "umulsidi3"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%0"))
+ (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
+ "optimize > 2 && msp430_hwmult_enabled ()"
+ "*
+ if (msp430_is_f5_mcu ())
+ return \"MOV.W %L1, &0x04D0 { MOV.W %H1, &0x04D2 { MOV.W %L2, &0x04E0 { MOV.W %H2, &0x04E2 { MOV.W &0x04E4, %A0 { MOV.W &0x04E6, %B0 { MOV.W &0x04E8, %C0 { MOV.W &0x04EA, %D0\";
+ else
+ return \"MOV.W %L1, &0x0140 { MOV.W %H1, &0x0141 { MOV.W %L2, &0x0150 { MOV.W %H2, &0x0152 { MOV.W &0x0154, %A0 { MOV.W &0x0156, %B0 { MOV.W &0x0158, %C0 { MOV.W &0x015A, %D0\";
+ "
+)
diff --git a/gcc-4.9/gcc/config/msp430/msp430.opt b/gcc-4.9/gcc/config/msp430/msp430.opt
new file mode 100644
index 000000000..5a447c0d2
--- /dev/null
+++ b/gcc-4.9/gcc/config/msp430/msp430.opt
@@ -0,0 +1,38 @@
+msim
+Target
+Use simulator runtime
+
+masm-hex
+Target Mask(ASM_HEX)
+Force assembly output to always use hex constants
+
+mmcu=
+Target ToLower Joined RejectNegative Var(target_mcu)
+Specify the MCU to build for.
+
+mcpu=
+Target Joined RejectNegative Var(target_cpu)
+Specify the ISA to build for: msp430, mdsp430x, msp430xv2
+
+mlarge
+Target Mask(LARGE) RejectNegative
+Select large model - 20-bit addresses/pointers
+
+msmall
+Target InverseMask(LARGE) RejectNegative
+Select small model - 16-bit addresses/pointers (default)
+
+mrelax
+Target Report
+Optimize opcode sizes at link time
+
+mOs
+Target Undocumented Mask(OPT_SPACE)
+
+minrt
+Target Report Mask(MINRT) RejectNegative
+Use a minimum runtime (no static initializers or ctors) for memory-constrained devices.
+
+mhwmult
+Target Report Var(ENABLE_HWMULT, 1) Init(1)
+Enable hardware multiply (except in interrupt routines)
diff --git a/gcc-4.9/gcc/config/msp430/predicates.md b/gcc-4.9/gcc/config/msp430/predicates.md
new file mode 100644
index 000000000..9a8e2da0a
--- /dev/null
+++ b/gcc-4.9/gcc/config/msp430/predicates.md
@@ -0,0 +1,80 @@
+;; Machine Description for TI MSP43* processors
+;; Copyright (C) 2013-2014 Free Software Foundation, Inc.
+;; Contributed by Red Hat.
+
+;; 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_predicate "msp_volatile_memory_operand"
+ (and (match_code "mem")
+ (match_test ("memory_address_addr_space_p (GET_MODE (op), XEXP (op, 0), MEM_ADDR_SPACE (op))")))
+)
+
+; TRUE for any valid general operand. We do this because
+; general_operand refuses to match volatile memory refs.
+
+(define_predicate "msp_general_operand"
+ (ior (match_operand 0 "general_operand")
+ (match_operand 0 "msp_volatile_memory_operand"))
+)
+
+; Likewise for nonimmediate_operand.
+
+(define_predicate "msp_nonimmediate_operand"
+ (ior (match_operand 0 "nonimmediate_operand")
+ (match_operand 0 "msp_volatile_memory_operand"))
+)
+
+(define_predicate "ubyte_operand"
+ (and (match_code "const_int")
+ (match_test "IN_RANGE (INTVAL (op), 0, 255)")))
+
+; TRUE for comparisons we support.
+(define_predicate "msp430_cmp_operator"
+ (match_code "eq,ne,lt,ltu,ge,geu"))
+
+; TRUE for comparisons we need to reverse.
+(define_predicate "msp430_reversible_cmp_operator"
+ (match_code "gt,gtu,le,leu"))
+
+; TRUE for constants the constant generator can produce
+(define_predicate "msp430_constgen_operator"
+ (and (match_code "const_int")
+ (match_test (" INTVAL (op) == 0
+ || INTVAL (op) == 1
+ || INTVAL (op) == 2
+ || INTVAL (op) == 4
+ || INTVAL (op) == 8
+ || INTVAL (op) == -1 "))))
+
+; TRUE for constants the constant generator can produce
+(define_predicate "msp430_inv_constgen_operator"
+ (and (match_code "const_int")
+ (match_test (" INTVAL (op) == ~0
+ || INTVAL (op) == ~1
+ || INTVAL (op) == ~2
+ || INTVAL (op) == ~4
+ || INTVAL (op) == ~8
+ || INTVAL (op) == ~(-1) "))))
+
+(define_predicate "msp430_nonsubreg_operand"
+ (match_code "reg,mem"))
+
+; TRUE for constants which are bit positions for zero_extract
+(define_predicate "msp430_bitpos"
+ (and (match_code "const_int")
+ (match_test (" INTVAL (op) >= 0
+ && INTVAL (op) <= 15 "))))
diff --git a/gcc-4.9/gcc/config/msp430/t-msp430 b/gcc-4.9/gcc/config/msp430/t-msp430
new file mode 100644
index 000000000..74a3c529f
--- /dev/null
+++ b/gcc-4.9/gcc/config/msp430/t-msp430
@@ -0,0 +1,257 @@
+# Makefile fragment for building GCC for the TI MSP430 target.
+# Copyright (C) 2012-2014 Free Software Foundation, Inc.
+# Contributed by Red Hat.
+#
+# 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/>.
+
+# Enable multilibs:
+
+MULTILIB_OPTIONS = mcpu=msp430 mlarge
+MULTILIB_DIRNAMES = 430 large
+
+# Match -mcpu=430
+MULTILIB_MATCHES = mcpu?msp430=mcpu?430
+
+# Match the known 430 ISA mcu names.
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430afe221
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430afe222
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430afe223
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430afe231
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430afe232
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430afe233
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430afe251
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430afe252
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430afe253
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430c091
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430c092
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430c111
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430c1111
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430c112
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430c1121
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430c1331
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430c1351
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430c311s
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430c312
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430c313
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430c314
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430c315
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430c323
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430c325
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430c336
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430c337
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430c412
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430c413
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430e112
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430e313
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430e315
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430e325
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430e337
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f110
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f1101
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f1101a
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f1111
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f1111a
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f112
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f1121
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f1121a
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f1122
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f1132
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f122
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f1222
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f123
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f1232
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f133
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f135
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f147
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f1471
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f148
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f1481
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f149
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f1491
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f155
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f156
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f157
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f1610
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f1611
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f1612
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f167
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f168
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f169
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2001
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2002
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2003
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2011
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2012
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2013
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2101
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2111
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2112
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2121
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2122
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2131
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2132
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2232
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2234
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2252
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2254
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2272
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2274
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f233
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2330
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f235
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2350
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2370
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2410
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f247
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2471
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f248
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2481
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f249
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f2491
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f412
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f413
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f4132
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f415
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f4152
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f417
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f423
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f423a
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f425
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f4250
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f425a
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f4260
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f427
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f4270
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f427a
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f435
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f4351
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f436
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f4361
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f437
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f4371
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f438
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f439
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f447
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f448
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f4481
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f449
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f4491
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f477
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f478
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f4783
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f4784
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f479
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f4793
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430f4794
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430fe423
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430fe4232
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430fe423a
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430fe4242
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430fe425
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430fe4252
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430fe425a
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430fe427
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430fe4272
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430fe427a
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430fg4250
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430fg4260
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430fg4270
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430fg437
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430fg438
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430fg439
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430fg477
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430fg478
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430fg479
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430fw423
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430fw425
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430fw427
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430fw428
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430fw429
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2001
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2101
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2102
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2111
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2112
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2113
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2121
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2131
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2132
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2152
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2153
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2201
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2202
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2203
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2210
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2211
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2212
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2213
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2221
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2230
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2231
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2232
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2233
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2252
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2253
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2302
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2303
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2312
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2313
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2332
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2333
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2352
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2353
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2402
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2403
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2412
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2413
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2432
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2433
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2444
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2452
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2453
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2513
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2533
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2544
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2553
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2744
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2755
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2855
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430g2955
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430i2020
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430i2021
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430i2030
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430i2031
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430i2040
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430i2041
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430l092
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430p112
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430p313
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430p315
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430p315s
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430p325
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430p337
+MULTILIB_MATCHES += mcpu?msp430=mmcu?msp430tch5e
+
+# Add additional MCU matches like this:
+# MULTILIB_MATCHES += mcpu?msp430x=mmcu?xxxxxxxxxx
+
+MULTILIB_EXCEPTIONS = mcpu=msp430/mlarge
+
+MULTILIB_EXTRA_OPTS =
+
+msp430-c.o: $(srcdir)/config/msp430/msp430-c.c $(RTL_H) $(TREE_H) $(CONFIG_H) $(TM_H)
+ $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $<