summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordj <dj@138bc75d-0d04-0410-961f-82ee72b054a4>2013-09-12 17:52:41 +0000
committerdj <dj@138bc75d-0d04-0410-961f-82ee72b054a4>2013-09-12 17:52:41 +0000
commite4a25868849c6594513a795a26be9da85b8b6ceb (patch)
treed690c25f951ef2f8c504a45d87bfd262e3ab226f
parent5acc9e335016d4ea5300af2d6884b2d489187654 (diff)
downloadppe42-gcc-e4a25868849c6594513a795a26be9da85b8b6ceb.tar.gz
ppe42-gcc-e4a25868849c6594513a795a26be9da85b8b6ceb.zip
* MAINTAINERS: Add Nick Clifton and DJ Delorie as msp430
maintainers. [gcc] * config/msp430/: New port. * config.gcc (msp430): Added. * doc/invoke.texi: Document MSP430 options. * doc/install.texi: Document msp430-elf * doc/md.texi: Document msp430-elf * doc/contrib.texi: Document msp430-elf [libgcc] * config.host (msp*-*-elf): New. * config/msp430/: New port. [contrib] * config-list.mk: Add msp430-elf. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@202535 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--ChangeLog5
-rw-r--r--MAINTAINERS2
-rw-r--r--contrib/ChangeLog4
-rw-r--r--contrib/config-list.mk1
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/config.gcc7
-rw-r--r--gcc/config/msp430/README.txt7
-rw-r--r--gcc/config/msp430/constraints.md74
-rw-r--r--gcc/config/msp430/msp430-c.c36
-rw-r--r--gcc/config/msp430/msp430-modes.def3
-rw-r--r--gcc/config/msp430/msp430-protos.h44
-rw-r--r--gcc/config/msp430/msp430.c1746
-rw-r--r--gcc/config/msp430/msp430.h399
-rw-r--r--gcc/config/msp430/msp430.md1229
-rw-r--r--gcc/config/msp430/msp430.opt26
-rw-r--r--gcc/config/msp430/predicates.md80
-rw-r--r--gcc/config/msp430/t-msp43043
-rw-r--r--gcc/doc/contrib.texi4
-rw-r--r--gcc/doc/install.texi7
-rw-r--r--gcc/doc/invoke.texi46
-rw-r--r--gcc/doc/md.texi29
-rw-r--r--libgcc/ChangeLog5
-rw-r--r--libgcc/config.host3
-rw-r--r--libgcc/config/msp430/cmpd.c19
-rw-r--r--libgcc/config/msp430/cmpsi2.S98
-rw-r--r--libgcc/config/msp430/epilogue.S51
-rw-r--r--libgcc/config/msp430/floathidf.c8
-rw-r--r--libgcc/config/msp430/floathisf.c11
-rw-r--r--libgcc/config/msp430/floatunhidf.c12
-rw-r--r--libgcc/config/msp430/floatunhisf.c12
-rw-r--r--libgcc/config/msp430/lib2bitcountHI.c50
-rw-r--r--libgcc/config/msp430/lib2divHI.c43
-rw-r--r--libgcc/config/msp430/lib2divQI.c44
-rw-r--r--libgcc/config/msp430/lib2divSI.c43
-rw-r--r--libgcc/config/msp430/lib2mul.c59
-rw-r--r--libgcc/config/msp430/lib2shift.c113
-rw-r--r--libgcc/config/msp430/mpy.c15
-rw-r--r--libgcc/config/msp430/msp430-divmod.h118
-rw-r--r--libgcc/config/msp430/msp430-mul.h43
-rw-r--r--libgcc/config/msp430/slli.S108
-rw-r--r--libgcc/config/msp430/srai.S106
-rw-r--r--libgcc/config/msp430/srli.S110
-rw-r--r--libgcc/config/msp430/t-msp43048
43 files changed, 4915 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index 1c74171eb2e..5db944c9d4a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2013-09-12 DJ Delorie <dj@redhat.com>
+
+ * MAINTAINERS: Add Nick Clifton and DJ Delorie as msp430
+ maintainers.
+
2013-09-03 Richard Biener <rguenther@suse.de>
* configure.ac: Also allow ISL 0.12.
diff --git a/MAINTAINERS b/MAINTAINERS
index 1e9e25475ad..48b7246b49a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -87,6 +87,8 @@ mmix port Hans-Peter Nilsson hp@bitrange.com
mn10300 port Jeff Law law@redhat.com
mn10300 port Alexandre Oliva aoliva@redhat.com
moxie port Anthony Green green@moxielogic.com
+msp430 port DJ Delorie dj@redhat.com
+msp430 port Nick Clifton nickc@redhat.com
nds32 port Chung-Ju Wu jasonwucj@gmail.com
nds32 port Shiva Chen shiva0217@gmail.com
pdp11 port Paul Koning ni1d@arrl.net
diff --git a/contrib/ChangeLog b/contrib/ChangeLog
index d99dc3417bb..931bb87bc24 100644
--- a/contrib/ChangeLog
+++ b/contrib/ChangeLog
@@ -1,3 +1,7 @@
+2013-09-12 DJ Delorie <dj@redhat.com>
+
+ * config-list.mk: Add msp430-elf.
+
2013-08-31 Diego Novillo <dnovillo@google.com>
* testsuite-management/x86_64-unknown-linux-gnu.xfail: Update.
diff --git a/contrib/config-list.mk b/contrib/config-list.mk
index 9a141c26be5..85ca6ad13e0 100644
--- a/contrib/config-list.mk
+++ b/contrib/config-list.mk
@@ -44,6 +44,7 @@ LIST = aarch64-elf aarch64-linux-gnu \
mipsel-elf mips64-elf mips64vr-elf mips64orion-elf mips-rtems \
mips-wrs-vxworks mipstx39-elf mmix-knuth-mmixware mn10300-elf moxie-elf \
moxie-uclinux moxie-rtems pdp11-aout picochip-elfOPT-enable-obsolete \
+ msp430-elf \
powerpc-darwin8 \
powerpc-darwin7 powerpc64-darwin powerpc-freebsd6 powerpc-netbsd \
powerpc-eabispe powerpc-eabisimaltivec powerpc-eabisim ppc-elf \
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index de4bb3d0aa2..a4440a01c89 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,12 @@
2013-09-12 DJ Delorie <dj@redhat.com>
+ * config/msp430/: New port.
+ * config.gcc (msp430): Added.
+ * doc/invoke.texi: Document MSP430 options.
+ * doc/install.texi: Document msp430-elf
+ * doc/md.texi: Document msp430-elf
+ * doc/contrib.texi: Document msp430-elf
+
* cfgexpand.c (expand_debug_expr): Avoid sign-extending SImode to
PSImode.
diff --git a/gcc/config.gcc b/gcc/config.gcc
index 36d5ae82dd1..f56f738d8ee 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -2030,6 +2030,13 @@ mn10300-*-*)
use_collect2=no
use_gcc_stdint=wrap
;;
+msp430*-*-*)
+ tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file}"
+ c_target_objs="msp430-c.o"
+ cxx_target_objs="msp430-c.o"
+ target_has_targetm_common=no
+ tmake_file="${tmake_file} msp430/t-msp430"
+ ;;
pdp11-*-*)
tm_file="${tm_file} newlib-stdint.h"
use_gcc_stdint=wrap
diff --git a/gcc/config/msp430/README.txt b/gcc/config/msp430/README.txt
new file mode 100644
index 00000000000..e7343cfcaf1
--- /dev/null
+++ b/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/config/msp430/constraints.md b/gcc/config/msp430/constraints.md
new file mode 100644
index 00000000000..baacf923bd3
--- /dev/null
+++ b/gcc/config/msp430/constraints.md
@@ -0,0 +1,74 @@
+;; Machine Description for TI MSP43* processors
+;; Copyright (C) 2013 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")
+ )))
+
+
diff --git a/gcc/config/msp430/msp430-c.c b/gcc/config/msp430/msp430-c.c
new file mode 100644
index 00000000000..808e02c5ffd
--- /dev/null
+++ b/gcc/config/msp430/msp430-c.c
@@ -0,0 +1,36 @@
+/* MSP430 C-specific support
+ Copyright (C) 2013 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/config/msp430/msp430-modes.def b/gcc/config/msp430/msp430-modes.def
new file mode 100644
index 00000000000..9e7b70127fd
--- /dev/null
+++ b/gcc/config/msp430/msp430-modes.def
@@ -0,0 +1,3 @@
+/* 20-bit address */
+PARTIAL_INT_MODE (SI);
+
diff --git a/gcc/config/msp430/msp430-protos.h b/gcc/config/msp430/msp430-protos.h
new file mode 100644
index 00000000000..df90d95c36e
--- /dev/null
+++ b/gcc/config/msp430/msp430-protos.h
@@ -0,0 +1,44 @@
+/* Exported function prototypes from the TI MSP430 backend.
+ Copyright (C) 2012-2013 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
+
+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);
+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);
+const char * msp430x_logical_shift_right (rtx);
+void msp430_output_labelref (FILE *, const char *);
+void msp430_register_pragmas (void);
+rtx msp430_return_addr_rtx (int);
+void msp430_split_movsi (rtx *);
+rtx msp430_subreg (enum machine_mode, rtx, enum machine_mode, int);
+rtx msp430_eh_return_stackadj_rtx (void);
+bool msp430_modes_tieable_p (enum machine_mode, enum machine_mode);
+
+#endif /* GCC_MSP430_PROTOS_H */
diff --git a/gcc/config/msp430/msp430.c b/gcc/config/msp430/msp430.c
new file mode 100644
index 00000000000..2e6705dad9b
--- /dev/null
+++ b/gcc/config/msp430/msp430.c
@@ -0,0 +1,1746 @@
+/* Subroutines used for code generation on TI MSP430 processors.
+ Copyright (C) 2012-2013 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 "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 = false;
+
+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 void
+msp430_option_override (void)
+{
+ init_machine_status = msp430_init_machine_status;
+
+ if (target_cpu
+ && (strstr (target_cpu, "430x")
+ || strstr (target_cpu, "430X")))
+ msp430x = true;
+
+ if (TARGET_LARGE && !msp430x)
+ error ("-mlarge requires a 430X-compatible -mcpu=");
+
+ 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 ATTRIBUTE_UNUSED,
+ int to ATTRIBUTE_UNUSED)
+{
+ 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)
+ | |
+ +--------------------+ <-- 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;
+
+ 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 < 16; 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);
+}
+
+#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");
+ 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 < 16; 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));
+ }
+}
+
+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;
+
+ emit_insn (gen_prologue_start_marker ());
+
+ 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 (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 ());
+
+ 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.
+ Note: See the popm pattern for the explanation of the strange
+ arguments. */
+ emit_insn (gen_popm (stack_pointer_rtx, GEN_INT (~(seq - 1)),
+ GEN_INT (count)));
+ i += count - 1;
+ }
+ else if (i == 11 - helper_n
+ && 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 ());
+
+ 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_%ld", 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. */
+ /* Note: gcc doesn't know about hardware multiply options (yet?) */
+ { "__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 }
+};
+
+/* 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))
+ {
+ fputs (helper_function_name_mappings [i].ti_name, file);
+ return;
+ }
+
+ fputs (name, file);
+}
+
+#undef TARGET_PRINT_OPERAND
+#define TARGET_PRINT_OPERAND msp430_print_operand
+
+/* Common code for msp430_print_operand(). */
+static void
+msp430_print_operand_raw (FILE * file, rtx op, int letter ATTRIBUTE_UNUSED)
+{
+ 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, "%#x", i);
+ else
+ fprintf (file, "%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;
+ }
+}
+
+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 'D': used for "decimal without '#'" */
+ 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, letter);
+ 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, letter);
+ 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 '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 '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 '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 'A':
+ /* Likewise, for BR -> BRA. */
+ if (TARGET_LARGE)
+ fprintf (file, "A");
+ return;
+ }
+
+ switch (GET_CODE (op))
+ {
+ case REG:
+ msp430_print_operand_raw (file, op, letter);
+ break;
+
+ case MEM:
+ addr = XEXP (op, 0);
+ switch (GET_CODE (addr))
+ {
+ case REG:
+ fprintf (file, "@%s", reg_names [REGNO (addr)]);
+ break;
+ case PLUS:
+ msp430_print_operand_raw (file, XEXP (addr, 1), letter);
+ fprintf (file, "(%s)", reg_names [REGNO (XEXP (addr, 0))]);
+ break;
+ case CONST:
+ case CONST_INT:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ fprintf (file, "&");
+ msp430_print_operand_raw (file, addr, letter);
+ break;
+
+ default:
+ print_rtl (file, addr);
+ break;
+ }
+ break;
+
+ case CONST_INT:
+ case CONST:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ if (letter == 0)
+ fprintf (file, "#");
+ msp430_print_operand_raw (file, op, letter);
+ 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 #0x8000, %L0 { SUBC.W %H0, %H0 { INV.W %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 %1, %L0 { BIT.W #0x8000, %L0 { SUBC.W %H0, %H0 { INV.W %H0, %H0"; /* 10-bytes. */
+
+ if (REGNO (operands[0]) + 1 == REGNO (operands[1]))
+ /* High word of dest == source word. */
+ return "MOV.W %1, %L0 { RPT #15 { RRAX.W %H0"; /* 6-bytes. */
+
+ /* No overlap between dest and source. */
+ return "MOV.W %1, %L0 { MOV.W %1, %H0 { RPT #15 { RRAX.W %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/config/msp430/msp430.h b/gcc/config/msp430/msp430.h
new file mode 100644
index 00000000000..bf3b15c0efb
--- /dev/null
+++ b/gcc/config/msp430/msp430.h
@@ -0,0 +1,399 @@
+/* GCC backend definitions for the TI MSP430 Processor
+ Copyright (C) 2012 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 ("__MSP430__"); \
+ 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:crt0.o%s} crtbegin.o%s"
+
+/* -lgcc is included because crtend.o needs __mspabi_func_epilog_1. */
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC "crtend.o%s crtn.o%s -lgcc"
+
+#define ASM_SPEC "-mP " /* Enable polymorphic instructions. */ \
+ "%{mmcu=msp430x:-mmcu=msp430X;mmcu=*:-mmcu=%*} " /* Pass the MCU 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. */ \
+ "%{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 \
+%{msim:-lsim} \
+%{!msim:-lnosys} \
+--end-group \
+%{!T*: %{msim: %{mlarge:%Tmsp430xl-sim.ld}%{!mlarge:%Tmsp430-sim.ld}}%{!msim:%Tmsp430.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
diff --git a/gcc/config/msp430/msp430.md b/gcc/config/msp430/msp430.md
new file mode 100644
index 00000000000..4324503a1b7
--- /dev/null
+++ b/gcc/config/msp430/msp430.md
@@ -0,0 +1,1229 @@
+;; Machine Description for TI MSP43* processors
+;; Copyright (C) 2013 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
+ ])
+
+(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" "i")] 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. We use %I
+;; because that is the only operator that will omit the # prefix to an
+;; integer value. Unfortunately it also inverts the integer value, so we
+;; have pre-invert it when generating this insn. (We could of course add a
+;; new operator, eg %D, just for this pattern...)
+;;
+;; 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%I1"
+ )
+
+;; 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 \n MOVX.A\t2(r1), 0(r1)";
+ return "SUB\t#2, r1 \n 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) \n ADDA\t#2, SP"
+ : "MOV.W\t0(r1), 2(r1) \n 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 "nonimmediate_operand" "=rYs,rm")
+ (match_operand:QI 1 "general_operand" "riYs,rmi"))]
+ ""
+ "@
+ MOV.B\t%1, %0
+ MOV%X0.B\t%1, %0"
+)
+
+(define_insn "movhi"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rYs,rm")
+ (match_operand:HI 1 "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 "nonimmediate_operand" "=r,Ya,rm")
+ (match_operand:PSI 1 "general_operand" "riYa,r,rmi"))]
+ ""
+ "@
+ MOV%A0\t%1, %0
+ MOV%A0\t%1, %0
+ MOV%X0.%A0\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 %H1 { PUSH.W %1 { POPM.A #1, %0"
+)
+
+;;------------------------------------------------------------
+;; Math
+
+(define_insn "addpsi3"
+ [(set (match_operand:PSI 0 "nonimmediate_operand" "=r,rm")
+ (plus:PSI (match_operand:PSI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:PSI 2 "general_operand" "rLs,rmi")))]
+ ""
+ "@
+ ADDA\t%2, %0
+ ADDX.A\t%2, %0"
+)
+
+(define_insn "addqi3"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=rYs,rm")
+ (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:QI 2 "general_operand" "riYs,rmi")))]
+ ""
+ "@
+ ADD.B\t%2, %0
+ ADD%X0.B\t%2, %0"
+)
+
+(define_insn "addhi3"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rYs,rm")
+ (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:HI 2 "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 %H0 { PUSH.W %L0 { POPM.A #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 "nonimmediate_operand" "=r,rm")
+ (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:HI 2 "general_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 %2, %1 ; cy
+ ADD%X0 %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 "general_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 %2, %1 ; cy
+ ADD%X0 %2, %1 ; cy"
+ )
+
+; Version of addhi that adds the carry, for SImode adds.
+(define_insn "addchi4_cy"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=r,rm")
+ (plus:HI (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:HI 2 "general_operand" "ri,rmi"))
+ (zero_extend:HI (reg:BI CARRY))))
+ ]
+ ""
+ "@
+ ADDC %2, %1
+ ADDC%X0 %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" "=&rm")
+ (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0")
+ (match_operand:SI 2 "general_operand" "rmi")))
+ ]
+ ""
+ [(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 "nonimmediate_operand" "=rYs,rm")
+ (xor:QHI (match_operand:QHI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:QHI 2 "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 "nonimmediate_operand" "=rYs,m")
+ (not:QHI (match_operand:QHI 1 "nonimmediate_operand" "0,0")))]
+ ""
+ "@
+ INV%x0%B0\t%0
+ INV%X0%B0\t%0"
+)
+
+(define_insn "extendqihi2"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rYs,m")
+ (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0,0")))]
+ ""
+ "@
+ SXT%X0\t%0
+ SXT%X0\t%0"
+)
+
+(define_insn "zero_extendqihi2"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rYs,m")
+ (zero_extend:HI (match_operand:QI 1 "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 "nonimmediate_operand" "=r,m")
+ (zero_extend:PSI (match_operand:HI 1 "nonimmediate_operand" "rm,r")))]
+ ""
+ "MOVX\t%1, %0"
+)
+
+(define_insn "truncpsihi2"
+ [(set (match_operand:HI 0 "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 #1, %1 { ADDX.W #4, @r1 { POPX.W %0 { POPX.W %H0\";
+ else
+ return \"PUSHM.A #1, %1 { POPX.W %0 { POPX.W %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 %H1 { PUSH.W %1 { POPM.A #1, %0"
+)
+
+;;------------------------------------------------------------
+;; 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 "nonimmediate_operand" "=rm")
+ (ashiftrt:HI (match_operand:HI 1 "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%A0\t#__mspabi_func_epilog_%D0"
+ )
+
+
+(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"
+ )
+
+;;------------------------------------------------------------
+;; Jumps
+
+(define_expand "call"
+ [(call:HI (match_operand 0 "")
+ (match_operand 1 ""))]
+ ""
+ ""
+)
+
+(define_insn "call_internal"
+ [(call (mem:HI (match_operand 0 "general_operand" "rmi"))
+ (match_operand 1 ""))]
+ ""
+ "CALL%A0\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" "rmi"))
+ (match_operand 2 "")))]
+ ""
+ "CALL%A0\t%1"
+)
+
+(define_insn "msp_return"
+ [(return)]
+ ""
+ { return 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%A0\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%A0\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%A0\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%A0\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-extend 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"
+)
+
diff --git a/gcc/config/msp430/msp430.opt b/gcc/config/msp430/msp430.opt
new file mode 100644
index 00000000000..6d4fc347e1a
--- /dev/null
+++ b/gcc/config/msp430/msp430.opt
@@ -0,0 +1,26 @@
+msim
+Target
+Use simulator runtime
+
+masm-hex
+Target Mask(ASM_HEX)
+Force assembly output to always use hex constants
+
+mmcu=
+Target Joined RejectNegative Var(target_cpu)
+Specify the cpu to build for. If the name begins with 'msp430x' then the 430X instructions are enabled
+
+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)
diff --git a/gcc/config/msp430/predicates.md b/gcc/config/msp430/predicates.md
new file mode 100644
index 00000000000..6f99caa94eb
--- /dev/null
+++ b/gcc/config/msp430/predicates.md
@@ -0,0 +1,80 @@
+;; Machine Description for TI MSP43* processors
+;; Copyright (C) 2013 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/config/msp430/t-msp430 b/gcc/config/msp430/t-msp430
new file mode 100644
index 00000000000..c7048378da4
--- /dev/null
+++ b/gcc/config/msp430/t-msp430
@@ -0,0 +1,43 @@
+# Makefile fragment for building GCC for the TI MSP430 target.
+# Copyright (C) 2012-2013 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 = mmcu=msp430x mlarge
+MULTILIB_DIRNAMES = 430x large
+
+# Match msp430X with msp430x.
+MULTILIB_MATCHES = mmcu?msp430x=mmcu?msp430X
+
+# each supported MCU needs a line like this:
+# MULTILIB_MATCHES += mmcu?msp430x123=mmcu?msp430x
+
+# The only way I figured this out was to hack the script to SHOW me
+# what it's doing. It's non-obvious, but it matches the directory
+# structure of the multilib tree, but using the options, not the
+# directory names. A shell CASE statement is generated from these, so
+# the usual CASE wildcards are supported.
+
+MULTILIB_EXCEPTIONS = 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) $<
diff --git a/gcc/doc/contrib.texi b/gcc/doc/contrib.texi
index 5577c04f011..9dd2c26287c 100644
--- a/gcc/doc/contrib.texi
+++ b/gcc/doc/contrib.texi
@@ -176,7 +176,7 @@ The @uref{http://www.gnu.org/software/classpath/,,GNU Classpath project}
for all of their merged runtime code.
@item
-Nick Clifton for arm, mcore, fr30, v850, m32r, rx work,
+Nick Clifton for arm, mcore, fr30, v850, m32r, msp430 rx work,
@option{--help}, and other random hacking.
@item
@@ -218,7 +218,7 @@ Mo DeJong for GCJ and libgcj bug fixes.
@item
DJ Delorie for the DJGPP port, build and libiberty maintenance,
-various bug fixes, and the M32C, MeP, and RL78 ports.
+various bug fixes, and the M32C, MeP, MSP430, and RL78 ports.
@item
Arnaud Desitter for helping to debug GNU Fortran.
diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi
index 82306251177..0011b68065b 100644
--- a/gcc/doc/install.texi
+++ b/gcc/doc/install.texi
@@ -3992,6 +3992,13 @@ The moxie processor.
@html
<hr />
@end html
+@heading @anchor{msp430-x-elf}msp430-*-elf
+TI MSP430 processor.
+This configuration is intended for embedded systems.
+
+@html
+<hr />
+@end html
@heading @anchor{powerpc-x-x}powerpc-*-*
You can specify a default version for the @option{-mcpu=@var{cpu_type}}
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index bb6338ed47b..caca7444090 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -804,6 +804,9 @@ Objective-C and Objective-C++ Dialects}.
@emph{Moxie Options}
@gccoptlist{-meb -mel -mno-crt0}
+@emph{MSP430 Options}
+@gccoptlist{-msim -masm-hex -mmcu= -mlarge -msmall -mrelax}
+
@emph{PDP-11 Options}
@gccoptlist{-mfpu -msoft-float -mac0 -mno-ac0 -m40 -m45 -m10 @gol
-mbcopy -mbcopy-builtin -mint32 -mno-int16 @gol
@@ -11036,6 +11039,7 @@ platform.
* MMIX Options::
* MN10300 Options::
* Moxie Options::
+* MSP430 Options::
* PDP-11 Options::
* picoChip Options::
* PowerPC Options::
@@ -16026,7 +16030,7 @@ Link the SDRAM-based runtime instead of the default ROM-based runtime.
@item -msim
@opindex msim
-Link the simulator runtime libraries.
+Link the simulator run-time libraries.
@item -msimnovec
@opindex msimnovec
@@ -17290,6 +17294,46 @@ Do not link in the C run-time initialization object file.
@end table
+@node MSP430 Options
+@subsection MSP430 Options
+@cindex MSP430 Options
+
+These options are defined for the MSP430:
+
+@table @gcctabopt
+
+@item -msim
+@opindex msim
+Link the simulator runtime libraries.
+
+@item -masm-hex
+@opindex masm-hex
+Force assembly output to always use hex constants. Normally such
+constants are signed decimals, but this option is available for
+testsuite and/or aesthetic purposes.
+
+@item -mmcu=
+@opindex mmcu=
+Select the MCU to target. Note that there are two ``generic'' MCUs,
+@code{msp430} and @code{msp430x}, which should be used most of the
+time. This option is also passed to the assembler.
+
+@item -mlarge
+@opindex mlarge
+Use large-model addressing (20-bit pointers, 32-bit @code{size_t}).
+
+@item -msmall
+@opindex msmall
+Use small-model addressing (16-bit pointers, 16-bit @code{size_t}).
+
+@item -mrelax
+@opindex mrelax
+This option is passed to the assembler and linker, and allows the
+linker to perform certain optimizations that cannot be done until
+the final link.
+
+@end table
+
@node PDP-11 Options
@subsection PDP-11 Options
@cindex PDP-11 Options
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 04f76fe901e..57760469d33 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -3063,6 +3063,35 @@ A constant in the range of 0 to @minus{}255.
@end table
+@item MSP430--@file{config/msp430/constraints.md}
+@table @code
+
+@item R12
+Register R12.
+
+@item R13
+Register R13.
+
+@item K
+Integer constant 1.
+
+@item L
+Integer constant -1^20..1^19.
+
+@item M
+Integer constant 1-4.
+
+@item Ya
+Memory references which do not require an extended MOVX instruction.
+
+@item Yl
+Memory reference, labels only.
+
+@item Ys
+Memory reference, stack only.
+
+@end table
+
@item PDP-11---@file{config/pdp11/constraints.md}
@table @code
@item a
diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog
index 2f415bfc80a..2d9c7d4f763 100644
--- a/libgcc/ChangeLog
+++ b/libgcc/ChangeLog
@@ -1,3 +1,8 @@
+2013-09-12 DJ Delorie <dj@redhat.com>
+
+ * config.host (msp*-*-elf): New.
+ * config/msp430/: New port.
+
2013-08-18 Iain Sandoe <iain@codesourcery.com>
PR gcov-profile/58127
diff --git a/libgcc/config.host b/libgcc/config.host
index 187391e9a2e..1fa3a654131 100644
--- a/libgcc/config.host
+++ b/libgcc/config.host
@@ -831,6 +831,9 @@ moxie-*-rtems*)
# Don't use default.
extra_parts=
;;
+msp430*-*-elf)
+ tmake_file="$tm_file t-crtstuff t-fdpbit msp430/t-msp430"
+ ;;
pdp11-*-*)
tmake_file="pdp11/t-pdp11 t-fdpbit"
;;
diff --git a/libgcc/config/msp430/cmpd.c b/libgcc/config/msp430/cmpd.c
new file mode 100644
index 00000000000..03e690dff53
--- /dev/null
+++ b/libgcc/config/msp430/cmpd.c
@@ -0,0 +1,19 @@
+/* Public domain. */
+int
+__mspabi_cmpf (float x, float y)
+{
+ if (x < y)
+ return -1;
+ if (x > y)
+ return 1;
+ return 0;
+}
+int
+__mspabi_cmpd (double x, double y)
+{
+ if (x < y)
+ return -1;
+ if (x > y)
+ return 1;
+ return 0;
+}
diff --git a/libgcc/config/msp430/cmpsi2.S b/libgcc/config/msp430/cmpsi2.S
new file mode 100644
index 00000000000..e8e5b3935a4
--- /dev/null
+++ b/libgcc/config/msp430/cmpsi2.S
@@ -0,0 +1,98 @@
+; Copyright (C) 2012, 2013 Free Software Foundation, Inc.
+; Contributed by Red Hat.
+;
+; This file is free software; you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by the
+; Free Software Foundation; either version 3, or (at your option) any
+; later version.
+;
+; This file is distributed in the hope that it will be useful, but
+; WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+; General Public License for more details.
+;
+; Under Section 7 of GPL version 3, you are granted additional
+; permissions described in the GCC Runtime Library Exception, version
+; 3.1, as published by the Free Software Foundation.
+;
+; You should have received a copy of the GNU General Public License and
+; a copy of the GCC Runtime Library Exception along with this program;
+; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+; <http://www.gnu.org/licenses/>.
+
+#ifdef __MSP430X_LARGE__
+#define ret_ RETA
+#else
+#define ret_ RET
+#endif
+
+ .text
+
+ ;; int __cmpsi2 (signed long A, signed long B)
+ ;;
+ ;; Performs a signed comparison of A and B.
+ ;; If A is less than B it returns 0. If A is greater
+ ;; than B it returns 2. If they are equal it returns 1.
+
+ ;; Note - this code is also used by the __ucmpsi2 routine below.
+
+ .global __cmpsi2
+ .type __cmpsi2, @function
+__cmpsi2:
+ ;; A is in r12 (low), r13 (high)
+ ;; B is in r14 (low), r15 (high)
+ ;; Result put in r12
+
+ cmp.w r13, r15
+ jeq .L_compare_low
+ jge .L_less_than
+.L_greater_than:
+ mov.w #2, r12
+ ret_
+.L_less_than:
+ mov.w #0, r12
+ ret_
+
+.L_compare_low:
+ cmp.w r12, r14
+ jl .L_greater_than
+ jne .L_less_than
+ mov.w #1, r12
+ ret_
+
+ .size __cmpsi2, . - __cmpsi2
+
+
+ ;; int __ucmpsi2 (unsigned long A, unsigned long B)
+ ;;
+ ;; Performs an unsigned comparison of A and B.
+ ;; If A is less than B it returns 0. If A is greater
+ ;; than B it returns 2. If they are equal it returns 1.
+
+;;; Note - this function branches into the __cmpsi2 code above.
+
+ .global __ucmpsi2
+ .type __ucmpsi2, @function
+__ucmpsi2:
+ ;; A is in r12 (low), r13 (high)
+ ;; B is in r14 (low), r15 (high)
+ ;; Result put in r12
+
+ tst r13
+ jn .L_top_bit_set_in_A
+ tst r15
+;;; If the top bit of B is set, but A's is clear we know that A < B.
+ jn .L_less_than
+;;; Neither A nor B has their top bit set so we can use the __cmpsi2 routine.
+;;; Note we use Jc rather than BR as that saves two bytes. The TST insn always
+;;; sets the C bit.
+ jc __cmpsi2
+
+.L_top_bit_set_in_A:
+ tst r15
+;;; If both A and B have their top bit set we can use the __cmpsi2 routine.
+ jn __cmpsi2
+;;; Otherwise A has its top bit set and B does not so A > B.
+ jc .L_greater_than
+
+ .size __ucmpsi2, . - __ucmpsi2
diff --git a/libgcc/config/msp430/epilogue.S b/libgcc/config/msp430/epilogue.S
new file mode 100644
index 00000000000..2e86decafc1
--- /dev/null
+++ b/libgcc/config/msp430/epilogue.S
@@ -0,0 +1,51 @@
+; Copyright (C) 2012, 2013 Free Software Foundation, Inc.
+; Contributed by Red Hat.
+;
+; This file is free software; you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by the
+; Free Software Foundation; either version 3, or (at your option) any
+; later version.
+;
+; This file is distributed in the hope that it will be useful, but
+; WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+; General Public License for more details.
+;
+; Under Section 7 of GPL version 3, you are granted additional
+; permissions described in the GCC Runtime Library Exception, version
+; 3.1, as published by the Free Software Foundation.
+;
+; You should have received a copy of the GNU General Public License and
+; a copy of the GCC Runtime Library Exception along with this program;
+; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+; <http://www.gnu.org/licenses/>.
+
+ .text
+
+ .global __mspabi_func_epilog_7
+ .global __mspabi_func_epilog_6
+ .global __mspabi_func_epilog_5
+ .global __mspabi_func_epilog_4
+ .global __mspabi_func_epilog_3
+ .global __mspabi_func_epilog_2
+ .global __mspabi_func_epilog_1
+
+__mspabi_func_epilog_7:
+ POP R4
+__mspabi_func_epilog_6:
+ POP R5
+__mspabi_func_epilog_5:
+ POP R6
+__mspabi_func_epilog_4:
+ POP R7
+__mspabi_func_epilog_3:
+ POP R8
+__mspabi_func_epilog_2:
+ POP R9
+__mspabi_func_epilog_1:
+ POP R10
+#ifdef __MSP430X_LARGE__
+ RETA
+#else
+ RET
+#endif
diff --git a/libgcc/config/msp430/floathidf.c b/libgcc/config/msp430/floathidf.c
new file mode 100644
index 00000000000..304731d518b
--- /dev/null
+++ b/libgcc/config/msp430/floathidf.c
@@ -0,0 +1,8 @@
+/* Public domain. */
+extern double __floatsidf (long);
+
+double
+__floathidf (int u)
+{
+ return __floatsidf ((long)u);
+}
diff --git a/libgcc/config/msp430/floathisf.c b/libgcc/config/msp430/floathisf.c
new file mode 100644
index 00000000000..64e5d805d21
--- /dev/null
+++ b/libgcc/config/msp430/floathisf.c
@@ -0,0 +1,11 @@
+/* Public domain. */
+typedef int HItype __attribute__ ((mode (HI)));
+typedef float SFtype __attribute__ ((mode (SF)));
+
+extern SFtype __floatsisf (unsigned long);
+
+SFtype
+__floathisf (HItype u)
+{
+ return __floatsisf ((unsigned long)u);
+}
diff --git a/libgcc/config/msp430/floatunhidf.c b/libgcc/config/msp430/floatunhidf.c
new file mode 100644
index 00000000000..f13b5507692
--- /dev/null
+++ b/libgcc/config/msp430/floatunhidf.c
@@ -0,0 +1,12 @@
+/* Public domain. */
+typedef int HItype __attribute__ ((mode (HI)));
+typedef unsigned int UHItype __attribute__ ((mode (HI)));
+typedef float DFtype __attribute__ ((mode (DF)));
+
+extern DFtype __floatunsidf (unsigned long);
+
+DFtype
+__floatunhidf (UHItype u)
+{
+ return __floatunsidf ((unsigned long)u);
+}
diff --git a/libgcc/config/msp430/floatunhisf.c b/libgcc/config/msp430/floatunhisf.c
new file mode 100644
index 00000000000..ea920bd853a
--- /dev/null
+++ b/libgcc/config/msp430/floatunhisf.c
@@ -0,0 +1,12 @@
+/* Public domain. */
+typedef int HItype __attribute__ ((mode (HI)));
+typedef unsigned int UHItype __attribute__ ((mode (HI)));
+typedef float SFtype __attribute__ ((mode (SF)));
+
+extern SFtype __floatunsisf (unsigned long);
+
+SFtype
+__floatunhisf (UHItype u)
+{
+ return __floatunsisf ((unsigned long)u);
+}
diff --git a/libgcc/config/msp430/lib2bitcountHI.c b/libgcc/config/msp430/lib2bitcountHI.c
new file mode 100644
index 00000000000..f0291ad60b0
--- /dev/null
+++ b/libgcc/config/msp430/lib2bitcountHI.c
@@ -0,0 +1,50 @@
+/* libgcc routines for MSP430
+ Copyright (C) 2012
+ 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.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+typedef int sint32_type __attribute__ ((mode (SI)));
+typedef unsigned int uint32_type __attribute__ ((mode (SI)));
+typedef int sint16_type __attribute__ ((mode (HI)));
+typedef unsigned int uint16_type __attribute__ ((mode (HI)));
+typedef int sint08_type __attribute__ ((mode (QI)));
+typedef unsigned int uint08_type __attribute__ ((mode (QI)));
+typedef int word_type __attribute__ ((mode (__word__)));
+
+#define C3B(a,b,c) a##b##c
+#define C3(a,b,c) C3B(a,b,c)
+
+/* See the comment by the definition of LIBGCC2_UNITS_PER_WORD in
+ msp430.h for why we are creating extra versions of some of the
+ functions defined in libgcc2.c. */
+
+#define LIBGCC2_UNITS_PER_WORD 2
+
+#define L_clzsi2
+#define L_ctzsi2
+#define L_ffssi2
+#define L_paritysi2
+#define L_popcountsi2
+
+#include "libgcc2.c"
diff --git a/libgcc/config/msp430/lib2divHI.c b/libgcc/config/msp430/lib2divHI.c
new file mode 100644
index 00000000000..e70ed400513
--- /dev/null
+++ b/libgcc/config/msp430/lib2divHI.c
@@ -0,0 +1,43 @@
+/* HI mode divide routines for libgcc for MSP430
+ Copyright (C) 2012
+ 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.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+typedef int sint32_type __attribute__ ((mode (SI)));
+typedef unsigned int uint32_type __attribute__ ((mode (SI)));
+typedef int sint16_type __attribute__ ((mode (HI)));
+typedef unsigned int uint16_type __attribute__ ((mode (HI)));
+typedef int sint08_type __attribute__ ((mode (QI)));
+typedef unsigned int uint08_type __attribute__ ((mode (QI)));
+typedef int word_type __attribute__ ((mode (__word__)));
+
+#define C3B(a,b,c) a##b##c
+#define C3(a,b,c) C3B(a,b,c)
+
+#define UINT_TYPE uint16_type
+#define SINT_TYPE sint16_type
+#define BITS_MINUS_1 15
+#define NAME_MODE hi
+
+#include "msp430-divmod.h"
diff --git a/libgcc/config/msp430/lib2divQI.c b/libgcc/config/msp430/lib2divQI.c
new file mode 100644
index 00000000000..fe341fc2fdc
--- /dev/null
+++ b/libgcc/config/msp430/lib2divQI.c
@@ -0,0 +1,44 @@
+/* QI mode divide routines for libgcc for MSP430
+ Copyright (C) 2012
+ 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.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+typedef int sint32_type __attribute__ ((mode (SI)));
+typedef unsigned int uint32_type __attribute__ ((mode (SI)));
+typedef int sint16_type __attribute__ ((mode (HI)));
+typedef unsigned int uint16_type __attribute__ ((mode (HI)));
+typedef int sint08_type __attribute__ ((mode (QI)));
+typedef unsigned int uint08_type __attribute__ ((mode (QI)));
+typedef int word_type __attribute__ ((mode (__word__)));
+
+#define C3B(a,b,c) a##b##c
+#define C3(a,b,c) C3B(a,b,c)
+
+#define UINT_TYPE uint08_type
+#define SINT_TYPE sint08_type
+#define BITS_MINUS_1 7
+#define NAME_MODE qi
+
+#include "msp430-divmod.h"
+
diff --git a/libgcc/config/msp430/lib2divSI.c b/libgcc/config/msp430/lib2divSI.c
new file mode 100644
index 00000000000..bc1dacaf51f
--- /dev/null
+++ b/libgcc/config/msp430/lib2divSI.c
@@ -0,0 +1,43 @@
+/* SI mode divide routines for libgcc for MSP430
+ Copyright (C) 2012
+ 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.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+typedef int sint32_type __attribute__ ((mode (SI)));
+typedef unsigned int uint32_type __attribute__ ((mode (SI)));
+typedef int sint16_type __attribute__ ((mode (HI)));
+typedef unsigned int uint16_type __attribute__ ((mode (HI)));
+typedef int sint08_type __attribute__ ((mode (QI)));
+typedef unsigned int uint08_type __attribute__ ((mode (QI)));
+typedef int word_type __attribute__ ((mode (__word__)));
+
+#define C3B(a,b,c) a##b##c
+#define C3(a,b,c) C3B(a,b,c)
+
+#define UINT_TYPE uint32_type
+#define SINT_TYPE sint32_type
+#define BITS_MINUS_1 31
+#define NAME_MODE si
+
+#include "msp430-divmod.h"
diff --git a/libgcc/config/msp430/lib2mul.c b/libgcc/config/msp430/lib2mul.c
new file mode 100644
index 00000000000..9f68f4c5e67
--- /dev/null
+++ b/libgcc/config/msp430/lib2mul.c
@@ -0,0 +1,59 @@
+/* libgcc routines for MSP430
+ Copyright (C) 2005, 2009, 2011
+ 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.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+typedef unsigned int uint32_type __attribute__ ((mode (SI)));
+typedef unsigned int uint16_type __attribute__ ((mode (HI)));
+typedef unsigned int uint08_type __attribute__ ((mode (QI)));
+
+#define C3B(a,b,c) a##b##c
+#define C3(a,b,c) C3B(a,b,c)
+
+
+#define UINT_TYPE uint16_type
+#define BITS_MINUS_1 15
+#define NAME_MODE hi
+
+#include "msp430-mul.h"
+
+#undef UINT_TYPE
+#undef BITS_MINUS_1
+#undef NAME_MODE
+
+#define UINT_TYPE uint08_type
+#define BITS_MINUS_1 7
+#define NAME_MODE qi
+
+#include "msp430-mul.h"
+
+#undef UINT_TYPE
+#undef BITS_MINUS_1
+#undef NAME_MODE
+
+#define UINT_TYPE uint32_type
+#define BITS_MINUS_1 31
+#define NAME_MODE si
+
+#include "msp430-mul.h"
diff --git a/libgcc/config/msp430/lib2shift.c b/libgcc/config/msp430/lib2shift.c
new file mode 100644
index 00000000000..53d7eaec682
--- /dev/null
+++ b/libgcc/config/msp430/lib2shift.c
@@ -0,0 +1,113 @@
+/* Shift functions for the GCC support library for the MSP430
+ Copyright (C) 2011 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.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+typedef int sint32_type __attribute__ ((mode (SI)));
+typedef unsigned int uint32_type __attribute__ ((mode (SI)));
+typedef int sint16_type __attribute__ ((mode (HI)));
+typedef unsigned int uint16_type __attribute__ ((mode (HI)));
+
+uint32_type __ashlsi3 (uint32_type in, char bit);
+sint32_type __ashrsi3 (sint32_type in, char bit);
+int __clrsbhi2 (sint16_type x);
+extern int __clrsbsi2 (sint32_type x);
+
+typedef struct
+{
+ union
+ {
+ uint32_type u;
+ uint16_type h[2];
+ } u;
+} dd;
+
+uint32_type
+__ashlsi3 (uint32_type in, char bit)
+{
+ uint16_type h, l;
+ dd d;
+
+ if (bit > 32)
+ return 0;
+ if (bit < 0)
+ return in;
+
+ d.u.u = in;
+ h = d.u.h[1];
+ l = d.u.h[0];
+
+ if (bit > 15)
+ {
+ h = l;
+ l = 0;
+ bit -= 16;
+ }
+
+ while (bit)
+ {
+ h = (h << 1) | (l >> 15);
+ l <<= 1;
+ bit --;
+ }
+
+ d.u.h[1] = h;
+ d.u.h[0] = l;
+ return d.u.u;
+}
+
+sint32_type
+__ashrsi3 (sint32_type in, char bit)
+{
+ sint16_type h;
+ uint16_type l;
+ dd d;
+
+ if (bit > 32)
+ return 0;
+ if (bit < 0)
+ return in;
+
+ d.u.u = in;
+ h = d.u.h[1];
+ l = d.u.h[0];
+
+ while (bit)
+ {
+ l = (h << 15) | (l >> 1);
+ h >>= 1;
+ bit --;
+ }
+
+ d.u.h[1] = h;
+ d.u.h[0] = l;
+ return d.u.u;
+}
+
+int
+__clrsbhi2 (sint16_type x)
+{
+ if (x == 0)
+ return 15;
+ return __clrsbsi2 ((sint32_type) x) - 16;
+}
diff --git a/libgcc/config/msp430/mpy.c b/libgcc/config/msp430/mpy.c
new file mode 100644
index 00000000000..57cffd0ba2a
--- /dev/null
+++ b/libgcc/config/msp430/mpy.c
@@ -0,0 +1,15 @@
+/* Public domain. */
+extern int __mulhi3 (int, int);
+
+int
+__mulhi3 (int x, int y)
+{
+ volatile int rv = 0;
+
+ while (y > 0)
+ {
+ rv += x;
+ y --;
+ }
+ return rv;
+}
diff --git a/libgcc/config/msp430/msp430-divmod.h b/libgcc/config/msp430/msp430-divmod.h
new file mode 100644
index 00000000000..206c7516c3e
--- /dev/null
+++ b/libgcc/config/msp430/msp430-divmod.h
@@ -0,0 +1,118 @@
+/* libgcc routines for MSP430
+ Copyright (C) 2005, 2009, 2011
+ 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.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+UINT_TYPE C3(udivmod,NAME_MODE,4) (UINT_TYPE, UINT_TYPE, word_type);
+SINT_TYPE C3(__div,NAME_MODE,3) (SINT_TYPE, SINT_TYPE);
+SINT_TYPE C3(__mod,NAME_MODE,3) (SINT_TYPE, SINT_TYPE);
+UINT_TYPE C3(__udiv,NAME_MODE,3) (UINT_TYPE, UINT_TYPE);
+UINT_TYPE C3(__umod,NAME_MODE,3) (UINT_TYPE, UINT_TYPE);
+
+UINT_TYPE
+C3(udivmod,NAME_MODE,4) (UINT_TYPE num, UINT_TYPE den, word_type modwanted)
+{
+ UINT_TYPE bit = 1;
+ UINT_TYPE res = 0;
+
+ while (den < num && bit && !(den & (1L << BITS_MINUS_1)))
+ {
+ den <<= 1;
+ bit <<= 1;
+ }
+ while (bit)
+ {
+ if (num >= den)
+ {
+ num -= den;
+ res |= bit;
+ }
+ bit >>= 1;
+ den >>= 1;
+ }
+ if (modwanted)
+ return num;
+ return res;
+}
+
+SINT_TYPE
+C3(__div,NAME_MODE,3) (SINT_TYPE a, SINT_TYPE b)
+{
+ word_type neg = 0;
+ SINT_TYPE res;
+
+ if (a < 0)
+ {
+ a = -a;
+ neg = !neg;
+ }
+
+ if (b < 0)
+ {
+ b = -b;
+ neg = !neg;
+ }
+
+ res = C3(udivmod,NAME_MODE,4) (a, b, 0);
+
+ if (neg)
+ res = -res;
+
+ return res;
+}
+
+SINT_TYPE
+C3(__mod,NAME_MODE,3) (SINT_TYPE a, SINT_TYPE b)
+{
+ word_type neg = 0;
+ SINT_TYPE res;
+
+ if (a < 0)
+ {
+ a = -a;
+ neg = 1;
+ }
+
+ if (b < 0)
+ b = -b;
+
+ res = C3(udivmod,NAME_MODE,4) (a, b, 1);
+
+ if (neg)
+ res = -res;
+
+ return res;
+}
+
+UINT_TYPE
+C3(__udiv,NAME_MODE,3) (UINT_TYPE a, UINT_TYPE b)
+{
+ return C3(udivmod,NAME_MODE,4) (a, b, 0);
+}
+
+UINT_TYPE
+C3(__umod,NAME_MODE,3) (UINT_TYPE a, UINT_TYPE b)
+{
+ return C3(udivmod,NAME_MODE,4) (a, b, 1);
+}
diff --git a/libgcc/config/msp430/msp430-mul.h b/libgcc/config/msp430/msp430-mul.h
new file mode 100644
index 00000000000..fc2cd6c6ebb
--- /dev/null
+++ b/libgcc/config/msp430/msp430-mul.h
@@ -0,0 +1,43 @@
+/* libgcc routines for RL78
+ Copyright (C) 2005, 2009, 2011
+ 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.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+UINT_TYPE C3(__mul,NAME_MODE,3) (UINT_TYPE, UINT_TYPE);
+UINT_TYPE
+C3(__mul,NAME_MODE,3) (UINT_TYPE a, UINT_TYPE b)
+{
+ UINT_TYPE rv = 0;
+
+ char bit;
+
+ for (bit=0; b && bit<sizeof(UINT_TYPE)*8; bit++)
+ {
+ if (b & 1)
+ rv += a;
+ a <<= 1;
+ b >>= 1;
+ }
+ return rv;
+}
diff --git a/libgcc/config/msp430/slli.S b/libgcc/config/msp430/slli.S
new file mode 100644
index 00000000000..48ed15d3ec3
--- /dev/null
+++ b/libgcc/config/msp430/slli.S
@@ -0,0 +1,108 @@
+; Copyright (C) 2012, 2013 Free Software Foundation, Inc.
+; Contributed by Red Hat.
+;
+; This file is free software; you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by the
+; Free Software Foundation; either version 3, or (at your option) any
+; later version.
+;
+; This file is distributed in the hope that it will be useful, but
+; WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+; General Public License for more details.
+;
+; Under Section 7 of GPL version 3, you are granted additional
+; permissions described in the GCC Runtime Library Exception, version
+; 3.1, as published by the Free Software Foundation.
+;
+; You should have received a copy of the GNU General Public License and
+; a copy of the GCC Runtime Library Exception along with this program;
+; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+; <http://www.gnu.org/licenses/>.
+
+ .text
+
+/* Logical Left Shift - R12 -> R12 */
+
+ .macro _slli n
+ .global __mspabi_slli_\n
+__mspabi_slli_\n:
+ ADD.W R12,R12
+ .endm
+
+ _slli 15
+ _slli 14
+ _slli 13
+ _slli 12
+ _slli 11
+ _slli 10
+ _slli 9
+ _slli 8
+ _slli 7
+ _slli 6
+ _slli 5
+ _slli 4
+ _slli 3
+ _slli 2
+ _slli 1
+#ifdef __MSP430X_LARGE__
+ RETA
+#else
+ RET
+#endif
+
+1: ADD.W #-1,R13
+ ADD.W R12,R12
+ .global __mspabi_slli
+__mspabi_slli:
+ CMP #0,R13
+ JNZ 1b
+#ifdef __MSP430X_LARGE__
+ RETA
+#else
+ RET
+#endif
+
+/* Logical Left Shift - R12:R13 -> R12:R13 */
+
+ .macro _slll n
+ .global __mspabi_slll_\n
+__mspabi_slll_\n:
+ ADD.W R12,R12
+ ADDC.W R13,R13
+ .endm
+
+ _slll 15
+ _slll 14
+ _slll 13
+ _slll 12
+ _slll 11
+ _slll 10
+ _slll 9
+ _slll 8
+ _slll 7
+ _slll 6
+ _slll 5
+ _slll 4
+ _slll 3
+ _slll 2
+ _slll 1
+#ifdef __MSP430X_LARGE__
+ RETA
+#else
+ RET
+#endif
+
+1: ADD.W #-1,R14
+ ADD.W R12,R12
+ ADDC.W R13,R13
+ .global __mspabi_slll
+__mspabi_slll:
+ CMP #0,R14
+ JNZ 1b
+#ifdef __MSP430X_LARGE__
+ RETA
+#else
+ RET
+#endif
+
diff --git a/libgcc/config/msp430/srai.S b/libgcc/config/msp430/srai.S
new file mode 100644
index 00000000000..8f841229fde
--- /dev/null
+++ b/libgcc/config/msp430/srai.S
@@ -0,0 +1,106 @@
+; Copyright (C) 2012, 2013 Free Software Foundation, Inc.
+; Contributed by Red Hat.
+;
+; This file is free software; you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by the
+; Free Software Foundation; either version 3, or (at your option) any
+; later version.
+;
+; This file is distributed in the hope that it will be useful, but
+; WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+; General Public License for more details.
+;
+; Under Section 7 of GPL version 3, you are granted additional
+; permissions described in the GCC Runtime Library Exception, version
+; 3.1, as published by the Free Software Foundation.
+;
+; You should have received a copy of the GNU General Public License and
+; a copy of the GCC Runtime Library Exception along with this program;
+; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+; <http://www.gnu.org/licenses/>.
+
+ .text
+
+ .macro _srai n
+ .global __mspabi_srai_\n
+__mspabi_srai_\n:
+ RRA.W R12
+ .endm
+
+/* Logical Right Shift - R12 -> R12 */
+ _srai 15
+ _srai 14
+ _srai 13
+ _srai 12
+ _srai 11
+ _srai 10
+ _srai 9
+ _srai 8
+ _srai 7
+ _srai 6
+ _srai 5
+ _srai 4
+ _srai 3
+ _srai 2
+ _srai 1
+#ifdef __MSP430X_LARGE__
+ RETA
+#else
+ RET
+#endif
+
+1: ADD.W #-1,R13
+ RRA.W R12,R12
+ .global __mspabi_srai
+__mspabi_srai:
+ CMP #0,R13
+ JNZ 1b
+#ifdef __MSP430X_LARGE__
+ RETA
+#else
+ RET
+#endif
+
+/* Logical Right Shift - R12:R13 -> R12:R13 */
+
+ .macro _sral n
+ .global __mspabi_sral_\n
+__mspabi_sral_\n:
+ RRA.W R13
+ RRC.W R12
+ .endm
+
+ _sral 15
+ _sral 14
+ _sral 13
+ _sral 12
+ _sral 11
+ _sral 10
+ _sral 9
+ _sral 8
+ _sral 7
+ _sral 6
+ _sral 5
+ _sral 4
+ _sral 3
+ _sral 2
+ _sral 1
+#ifdef __MSP430X_LARGE__
+ RETA
+#else
+ RET
+#endif
+
+1: ADD.W #-1,R14
+ RRA.W R13
+ RRC.W R12
+ .global __mspabi_sral
+__mspabi_sral:
+ CMP #0,R14
+ JNZ 1b
+#ifdef __MSP430X_LARGE__
+ RETA
+#else
+ RET
+#endif
diff --git a/libgcc/config/msp430/srli.S b/libgcc/config/msp430/srli.S
new file mode 100644
index 00000000000..3ec33df343f
--- /dev/null
+++ b/libgcc/config/msp430/srli.S
@@ -0,0 +1,110 @@
+; Copyright (C) 2012, 2013 Free Software Foundation, Inc.
+; Contributed by Red Hat.
+;
+; This file is free software; you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by the
+; Free Software Foundation; either version 3, or (at your option) any
+; later version.
+;
+; This file is distributed in the hope that it will be useful, but
+; WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+; General Public License for more details.
+;
+; Under Section 7 of GPL version 3, you are granted additional
+; permissions described in the GCC Runtime Library Exception, version
+; 3.1, as published by the Free Software Foundation.
+;
+; You should have received a copy of the GNU General Public License and
+; a copy of the GCC Runtime Library Exception along with this program;
+; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+; <http://www.gnu.org/licenses/>.
+
+ .text
+
+ .macro _srli n
+ .global __mspabi_srli_\n
+__mspabi_srli_\n:
+ CLRC
+ RRC.W R12
+ .endm
+
+/* Logical Right Shift - R12 -> R12 */
+ _srli 15
+ _srli 14
+ _srli 13
+ _srli 12
+ _srli 11
+ _srli 10
+ _srli 9
+ _srli 8
+ _srli 7
+ _srli 6
+ _srli 5
+ _srli 4
+ _srli 3
+ _srli 2
+ _srli 1
+#ifdef __MSP430X_LARGE__
+ RETA
+#else
+ RET
+#endif
+
+1: ADD.W #-1,R13
+ CLRC
+ RRC.W R12,R12
+ .global __mspabi_srli
+__mspabi_srli:
+ CMP #0,R13
+ JNZ 1b
+#ifdef __MSP430X_LARGE__
+ RETA
+#else
+ RET
+#endif
+
+/* Logical Right Shift - R12:R13 -> R12:R13 */
+
+ .macro _srll n
+ .global __mspabi_srll_\n
+__mspabi_srll_\n:
+ CLRC
+ RRC.W R13
+ RRC.W R12
+ .endm
+
+ _srll 15
+ _srll 14
+ _srll 13
+ _srll 12
+ _srll 11
+ _srll 10
+ _srll 9
+ _srll 8
+ _srll 7
+ _srll 6
+ _srll 5
+ _srll 4
+ _srll 3
+ _srll 2
+ _srll 1
+#ifdef __MSP430X_LARGE__
+ RETA
+#else
+ RET
+#endif
+
+1: ADD.W #-1,R14
+ CLRC
+ RRC.W R13
+ RRC.W R12
+ .global __mspabi_srll
+__mspabi_srll:
+ CMP #0,R14
+ JNZ 1b
+#ifdef __MSP430X_LARGE__
+ RETA
+#else
+ RET
+#endif
diff --git a/libgcc/config/msp430/t-msp430 b/libgcc/config/msp430/t-msp430
new file mode 100644
index 00000000000..a4d4158e199
--- /dev/null
+++ b/libgcc/config/msp430/t-msp430
@@ -0,0 +1,48 @@
+# Makefile fragment for building LIBGCC for the TI MSP430 processor.
+# Copyright (C) 2011 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/>.
+
+# Note - we have separate versions of the lib2div<mode> files
+# as the functions are quite large and we do not want to pull
+# in unneeded division routines.
+
+LIB2ADD = \
+ $(srcdir)/config/msp430/lib2divQI.c \
+ $(srcdir)/config/msp430/lib2divHI.c \
+ $(srcdir)/config/msp430/lib2divSI.c \
+ $(srcdir)/config/msp430/lib2bitcountHI.c \
+ $(srcdir)/config/msp430/lib2mul.c \
+ $(srcdir)/config/msp430/lib2shift.c \
+ $(srcdir)/config/msp430/epilogue.S \
+ $(srcdir)/config/msp430/mpy.c \
+ $(srcdir)/config/msp430/slli.S \
+ $(srcdir)/config/msp430/srai.S \
+ $(srcdir)/config/msp430/srli.S \
+ $(srcdir)/config/msp430/cmpsi2.S \
+ $(srcdir)/config/msp430/floatunhisf.c \
+ $(srcdir)/config/msp430/floatunhidf.c \
+ $(srcdir)/config/msp430/floathidf.c \
+ $(srcdir)/config/msp430/floathisf.c \
+ $(srcdir)/config/msp430/cmpd.c
+
+HOST_LIBGCC2_CFLAGS += -Os -ffunction-sections -fdata-sections
+
+# Local Variables:
+# mode: Makefile
+# End:
OpenPOWER on IntegriCloud