Patchwork new port: msp430-elf, revision 2

login
register
mail settings
Submitter DJ Delorie
Date May 11, 2013, 12:31 a.m.
Message ID <201305110031.r4B0VaM0004313@greed.delorie.com>
Download mbox | patch
Permalink /patch/243102/
State New
Headers show

Comments

DJ Delorie - May 11, 2013, 12:31 a.m.
Second revision, hopefully I covered everything...  Two of the three
MI patches I posted separately, the third I wasn't able to reproduce
so I've withdrawn it for now.

	* 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

[libgcc]

	* config.host (msp*-*-elf): New.
	* config/msp430/: New port.

[contrib]

	* config-list.mk: Add msp430-elf.

[wwwdocs]

	* htdocs/index.html (News): Mention msp430.
	* htdocs/backends.html: Add msp430.
	* htdocs/readings.html: Add msp430.

[gcc]
Gerald Pfeifer - May 12, 2013, 6:56 p.m.
On Fri, 10 May 2013, DJ Delorie wrote:
> Index: MAINTAINERS
> ===================================================================
> +msp430 port		DJ Delorie		dj@redhat.com
> +msp430 port		Nick Clifton		nickc@redhat.com

I'll bring this up on the steering committee (not that I expect
a lot of discussion :-).

> Index: gcc/doc/invoke.texi
> ===================================================================
> +Link the simulator runtime libraries.

"run-time", according to my reading of
http://gcc.gnu.org/codingconventions.html .

> +@item -masm-hex
> +@opindex masm-hex
> +Force assembly output to always use hex constants instead of decimal.

Here I am wondering whether to simply omit "instead of decimal"?  (If
not, somehow that part of the sentence comes across as a bit odd, but
then I'm not a native speaker.)

> +@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.

What are the other legitimate options beyond these two?

> +@item -mrelax
> +@opindex mrelax
> +Perform link-time opcode relaxing.

Will everyone know what opcode relaxing is?

> Index: gcc/doc/md.texi
> ===================================================================
> +@item Ya
> +Memory reference, any type, but restricted 64k range of constants.

"restricted 64k range of constants", what's that?  And kBit or kByte?


The doc changes look fine modulo the above, and I assume you'll want
to add a note to the release notes htdocs/gcc-4.9/changes.html and a
news item to htdocs/index.html .

Gerald
Steven Bosscher - May 12, 2013, 6:59 p.m.
On Sun, May 12, 2013 at 8:56 PM, Gerald Pfeifer wrote:
> On Fri, 10 May 2013, DJ Delorie wrote:
>> Index: MAINTAINERS
>> ===================================================================
>> +msp430 port          DJ Delorie              dj@redhat.com
>> +msp430 port          Nick Clifton            nickc@redhat.com
>
> I'll bring this up on the steering committee (not that I expect
> a lot of discussion :-).

Actually I hope for some discussion:

Should new ports be allowed in if they rely so heavily on reload?

Ciao!
Steven
Gerald Pfeifer - May 12, 2013, 7:20 p.m.
On Sun, 12 May 2013, Steven Bosscher wrote:
>> I'll bring this up on the steering committee (not that I expect
>> a lot of discussion :-).
> Actually I hope for some discussion:
> 
> Should new ports be allowed in if they rely so heavily on reload?

That's a gcc(-patches)@gcc.gnu.org level discussion, though, not what 
you'd usually have (or expect) on the steering committee. ;-)

Gerald
Chung-Ju Wu - May 13, 2013, 2:11 p.m.
2013/5/13 Steven Bosscher <stevenb.gcc@gmail.com>:
> On Sun, May 12, 2013 at 8:56 PM, Gerald Pfeifer wrote:
>> On Fri, 10 May 2013, DJ Delorie wrote:
>>> Index: MAINTAINERS
>>> ===================================================================
>>> +msp430 port          DJ Delorie              dj@redhat.com
>>> +msp430 port          Nick Clifton            nickc@redhat.com
>>
>> I'll bring this up on the steering committee (not that I expect
>> a lot of discussion :-).
>
> Actually I hope for some discussion:
>
> Should new ports be allowed in if they rely so heavily on reload?
>
> Ciao!
> Steven

I have a new port 'nds32' target and I am going to
contribute some patches on mailing list recently.
We are glad that we eventually decided to enable LRA
rather than relying on reload.

To my experiences, it is much easier to design a new
port with LRA enabled.  We don't have to implement
a tons of reload target hook and we can still have satisfied
allocation result.  For the future GCC development
and target maintenance, IMHO it would be great to
have 'less reload' requirement for new ports.


Best regards,
jasonwucj
DJ Delorie - May 13, 2013, 11:27 p.m.
> "run-time", according to my reading of
> http://gcc.gnu.org/codingconventions.html .

I chenged it, but I note that "runtime" is used much more often than
"run-time" and "run time" in the docs.

However, "runtime" is preferred for "libraries and system support
present at run time", which is what this option controls.

> Here I am wondering whether to simply omit "instead of decimal"?  (If
> not, somehow that part of the sentence comes across as a bit odd, but
> then I'm not a native speaker.)

New text:

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.

> What are the other legitimate options beyond these two?

We're still discussing that with TI; historical non-fsf versions of
the msp-gcc allow the full chip number here (i.e. msp430F5438).
Ideally, such would still be allowed, but the community is talking
about switching to -mcpu= for the ISA and using -mmcu= only for the
linker scripts.  For now, we allow chip numbers but only look for the
'x' to determine the ISA.  We might allow for arbitrary chip numbers,
to be passed to the assembler/linker or to be used as filenames for
linker scripts, headers, or libraries.

So, I only documented the use I know is currently supported.

> > +@item -mrelax
> > +@opindex mrelax
> > +Perform link-time opcode relaxing.
> 
> Will everyone know what opcode relaxing is?

New text:

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.


> "restricted 64k range of constants", what's that?  And kBit or kByte?

New text:

Memory references which do not require an extended MOVX instruction.


> The doc changes look fine modulo the above, and I assume you'll want
> to add a note to the release notes htdocs/gcc-4.9/changes.html and a
> news item to htdocs/index.html .

I included index.html, I thought...

I didn't see changes.html in the file list I had, though, but I can
certainly add that too.
DJ Delorie - May 30, 2013, 12:20 a.m.
Are there any further comments on this?  Do I need to post a final
patch?  Can it be committed yet?

Patch

Index: contrib/config-list.mk
===================================================================
--- contrib/config-list.mk	(revision 198504)
+++ contrib/config-list.mk	(working copy)
@@ -41,12 +41,13 @@  LIST = aarch64-elf aarch64-linux-gnu \
   mips64el-st-linux-gnu mips64octeon-linux mipsisa64r2-linux \
   mipsisa32r2-linux-gnu mipsisa64r2-sde-elf mipsisa32-elfoabi \
   mipsisa64-elfoabi mipsisa64r2el-elf mipsisa64sr71k-elf mipsisa64sb1-elf \
   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 \
   powerpc-eabialtivec powerpc-xilinx-eabi powerpc-eabi \
   powerpc-rtems4.11OPT-enable-threads=yes powerpc-linux_spe \
   powerpc-linux_paired powerpc64-linux_altivec \
Index: MAINTAINERS
===================================================================
--- MAINTAINERS	(revision 198504)
+++ MAINTAINERS	(working copy)
@@ -84,12 +84,14 @@  microblaze		Michael Eager		eager@eagerco
 mips port		Eric Christopher	echristo@gmail.com
 mips port		Richard Sandiford	rdsandiford@googlemail.com
 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
 pdp11 port		Paul Koning		ni1d@arrl.net
 picochip port		Daniel Towner		dant@picochip.com
 rl78 port		DJ Delorie		dj@redhat.com
 rs6000/powerpc port	David Edelsohn		dje.gcc@gmail.com
 rs6000 vector extns	Aldy Hernandez		aldyh@redhat.com
 rx port	      		Nick Clifton		nickc@redhat.com
Index: libgcc/config.host
===================================================================
--- libgcc/config.host	(revision 198504)
+++ libgcc/config.host	(working copy)
@@ -811,12 +811,15 @@  moxie-*-elf | moxie-*-uclinux*)
 	;;
 moxie-*-rtems*)
 	tmake_file="$tmake_file moxie/t-moxie t-softfp-sfdf t-softfp-excl t-softfp"
 	# 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"
 	;;
 picochip-*-*)
 	tmake_file="picochip/t-picochip t-fpbit"
         ;;
Index: libgcc/config/msp430/floathidf.c
===================================================================
--- libgcc/config/msp430/floathidf.c	(revision 0)
+++ libgcc/config/msp430/floathidf.c	(revision 0)
@@ -0,0 +1,7 @@ 
+extern double __floatsidf (long);
+
+double
+__floathidf (int u)
+{
+  return __floatsidf ((long)u);
+}
Index: libgcc/config/msp430/floatunhidf.c
===================================================================
--- libgcc/config/msp430/floatunhidf.c	(revision 0)
+++ libgcc/config/msp430/floatunhidf.c	(revision 0)
@@ -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);
+}
Index: libgcc/config/msp430/mpy.c
===================================================================
--- libgcc/config/msp430/mpy.c	(revision 0)
+++ libgcc/config/msp430/mpy.c	(revision 0)
@@ -0,0 +1,14 @@ 
+extern int __mulhi3 (int, int);
+
+int
+__mulhi3 (int x, int y)
+{
+  volatile int rv = 0;
+
+  while (y > 0)
+    {
+      rv += x;
+      y --;
+    }
+  return rv;
+}
Index: libgcc/config/msp430/lib2mul.c
===================================================================
--- libgcc/config/msp430/lib2mul.c	(revision 0)
+++ libgcc/config/msp430/lib2mul.c	(revision 0)
@@ -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"
Index: libgcc/config/msp430/t-msp430
===================================================================
--- libgcc/config/msp430/t-msp430	(revision 0)
+++ libgcc/config/msp430/t-msp430	(revision 0)
@@ -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:
Index: libgcc/config/msp430/msp430-divmod.h
===================================================================
--- libgcc/config/msp430/msp430-divmod.h	(revision 0)
+++ libgcc/config/msp430/msp430-divmod.h	(revision 0)
@@ -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);
+}
Index: libgcc/config/msp430/eh_return.S
===================================================================
--- libgcc/config/msp430/eh_return.S	(revision 0)
+++ libgcc/config/msp430/eh_return.S	(revision 0)
@@ -0,0 +1,57 @@ 
+/* EH return helper for MSP430
+
+   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.
+
+   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	__msp430_eh_return
+__msp430_eh_return:
+
+	/* At this point, REG has the stack adjustment, and REG has
+	   the address to return to.  The stack looks like this:
+
+	   new_PC
+	   new_FP
+	   <- unwound sp
+	   ...
+	   new_SP
+	   r15
+	   through
+	   r4
+	   <- sp
+
+	   What we need to do is restore all the registers, update the
+	   stack, and return to the right place.
+	*/
+
+	/* add fixup to stack */
+
+	/* Store new SP in old stack */
+	/* Store new PC in new stack */
+
+	pop all
+	pop sp
+	ret
+	
\ No newline at end of file
Index: libgcc/config/msp430/lib2divHI.c
===================================================================
--- libgcc/config/msp430/lib2divHI.c	(revision 0)
+++ libgcc/config/msp430/lib2divHI.c	(revision 0)
@@ -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"
Index: libgcc/config/msp430/cmpsi2.S
===================================================================
--- libgcc/config/msp430/cmpsi2.S	(revision 0)
+++ libgcc/config/msp430/cmpsi2.S	(revision 0)
@@ -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
Index: libgcc/config/msp430/srai.S
===================================================================
--- libgcc/config/msp430/srai.S	(revision 0)
+++ libgcc/config/msp430/srai.S	(revision 0)
@@ -0,0 +1,114 @@ 
+/* Copyright (c) 2012 Red Hat Incorporated.
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met: 
+
+     Redistributions of source code must retain the above copyright 
+     notice, this list of conditions and the following disclaimer.
+
+     Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+
+     The name of Red Hat Incorporated may not be used to endorse 
+     or promote products derived from this software without specific 
+     prior written permission.
+
+   This software is provided by the copyright holders and contributors
+   "AS IS" and any express or implied warranties, including, but not
+   limited to, the implied warranties of merchantability and fitness for
+   a particular purpose are disclaimed.  In no event shall Red Hat
+   incorporated be liable for any direct, indirect, incidental, special,
+   exemplary, or consequential damages (including, but not limited to,
+   procurement of substitute goods or services; loss of use, data, or
+   profits; or business interruption) however caused and on any theory of
+   liability, whether in contract, strict liability, or tort (including
+   negligence or otherwise) arising in any way out of the use of this
+   software, even if advised of the possibility of such damage.  */
+	
+	.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
Index: libgcc/config/msp430/floathisf.c
===================================================================
--- libgcc/config/msp430/floathisf.c	(revision 0)
+++ libgcc/config/msp430/floathisf.c	(revision 0)
@@ -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);
+}
Index: libgcc/config/msp430/lib2bitcountHI.c
===================================================================
--- libgcc/config/msp430/lib2bitcountHI.c	(revision 0)
+++ libgcc/config/msp430/lib2bitcountHI.c	(revision 0)
@@ -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"
Index: libgcc/config/msp430/floatunhisf.c
===================================================================
--- libgcc/config/msp430/floatunhisf.c	(revision 0)
+++ libgcc/config/msp430/floatunhisf.c	(revision 0)
@@ -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);
+}
Index: libgcc/config/msp430/slli.S
===================================================================
--- libgcc/config/msp430/slli.S	(revision 0)
+++ libgcc/config/msp430/slli.S	(revision 0)
@@ -0,0 +1,116 @@ 
+/* Copyright (c) 2012 Red Hat Incorporated.
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met: 
+
+     Redistributions of source code must retain the above copyright 
+     notice, this list of conditions and the following disclaimer.
+
+     Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+
+     The name of Red Hat Incorporated may not be used to endorse 
+     or promote products derived from this software without specific 
+     prior written permission.
+
+   This software is provided by the copyright holders and contributors
+   "AS IS" and any express or implied warranties, including, but not
+   limited to, the implied warranties of merchantability and fitness for
+   a particular purpose are disclaimed.  In no event shall Red Hat
+   incorporated be liable for any direct, indirect, incidental, special,
+   exemplary, or consequential damages (including, but not limited to,
+   procurement of substitute goods or services; loss of use, data, or
+   profits; or business interruption) however caused and on any theory of
+   liability, whether in contract, strict liability, or tort (including
+   negligence or otherwise) arising in any way out of the use of this
+   software, even if advised of the possibility of such damage.  */
+	
+	.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
+
Index: libgcc/config/msp430/cmpd.c
===================================================================
--- libgcc/config/msp430/cmpd.c	(revision 0)
+++ libgcc/config/msp430/cmpd.c	(revision 0)
@@ -0,0 +1,18 @@ 
+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;
+}
Index: libgcc/config/msp430/lib2divQI.c
===================================================================
--- libgcc/config/msp430/lib2divQI.c	(revision 0)
+++ libgcc/config/msp430/lib2divQI.c	(revision 0)
@@ -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"
+
Index: libgcc/config/msp430/lib2shift.c
===================================================================
--- libgcc/config/msp430/lib2shift.c	(revision 0)
+++ libgcc/config/msp430/lib2shift.c	(revision 0)
@@ -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;
+}
Index: libgcc/config/msp430/msp430-mul.h
===================================================================
--- libgcc/config/msp430/msp430-mul.h	(revision 0)
+++ libgcc/config/msp430/msp430-mul.h	(revision 0)
@@ -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;
+}
Index: libgcc/config/msp430/lib2divSI.c
===================================================================
--- libgcc/config/msp430/lib2divSI.c	(revision 0)
+++ libgcc/config/msp430/lib2divSI.c	(revision 0)
@@ -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"
Index: libgcc/config/msp430/epilogue.S
===================================================================
--- libgcc/config/msp430/epilogue.S	(revision 0)
+++ libgcc/config/msp430/epilogue.S	(revision 0)
@@ -0,0 +1,59 @@ 
+/* Copyright (c) 2012 Red Hat Incorporated.
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met: 
+
+     Redistributions of source code must retain the above copyright 
+     notice, this list of conditions and the following disclaimer.
+
+     Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+
+     The name of Red Hat Incorporated may not be used to endorse 
+     or promote products derived from this software without specific 
+     prior written permission.
+
+   This software is provided by the copyright holders and contributors
+   "AS IS" and any express or implied warranties, including, but not
+   limited to, the implied warranties of merchantability and fitness for
+   a particular purpose are disclaimed.  In no event shall Red Hat
+   incorporated be liable for any direct, indirect, incidental, special,
+   exemplary, or consequential damages (including, but not limited to,
+   procurement of substitute goods or services; loss of use, data, or
+   profits; or business interruption) however caused and on any theory of
+   liability, whether in contract, strict liability, or tort (including
+   negligence or otherwise) arising in any way out of the use of this
+   software, even if advised of the possibility of such damage.  */
+	
+	.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
Index: libgcc/config/msp430/srli.S
===================================================================
--- libgcc/config/msp430/srli.S	(revision 0)
+++ libgcc/config/msp430/srli.S	(revision 0)
@@ -0,0 +1,118 @@ 
+/* Copyright (c) 2012 Red Hat Incorporated.
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met: 
+
+     Redistributions of source code must retain the above copyright 
+     notice, this list of conditions and the following disclaimer.
+
+     Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+
+     The name of Red Hat Incorporated may not be used to endorse 
+     or promote products derived from this software without specific 
+     prior written permission.
+
+   This software is provided by the copyright holders and contributors
+   "AS IS" and any express or implied warranties, including, but not
+   limited to, the implied warranties of merchantability and fitness for
+   a particular purpose are disclaimed.  In no event shall Red Hat
+   incorporated be liable for any direct, indirect, incidental, special,
+   exemplary, or consequential damages (including, but not limited to,
+   procurement of substitute goods or services; loss of use, data, or
+   profits; or business interruption) however caused and on any theory of
+   liability, whether in contract, strict liability, or tort (including
+   negligence or otherwise) arising in any way out of the use of this
+   software, even if advised of the possibility of such damage.  */
+	
+	.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
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 198591)
+++ gcc/doc/invoke.texi	(working copy)
@@ -792,12 +792,15 @@  Objective-C and Objective-C++ Dialects}.
 -mreturn-pointer-on-d0 @gol
 -mno-crt0  -mrelax -mliw -msetlb}
 
 @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
 -mint16  -mno-int32  -mfloat32  -mno-float64 @gol
 -mfloat64  -mno-float32  -mabshi  -mno-abshi @gol
 -mbranch-expensive  -mbranch-cheap @gol
@@ -10909,12 +10912,13 @@  platform.
 * MeP Options::
 * MicroBlaze Options::
 * MIPS Options::
 * MMIX Options::
 * MN10300 Options::
 * Moxie Options::
+* MSP430 Options::
 * PDP-11 Options::
 * picoChip Options::
 * PowerPC Options::
 * RL78 Options::
 * RS/6000 and PowerPC Options::
 * RX Options::
@@ -17041,12 +17045,48 @@  Generate little-endian code.
 @item -mno-crt0
 @opindex mno-crt0
 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 instead of decimal.
+
+@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
+Perform link-time opcode relaxing.
+
+@end table
+
 @node PDP-11 Options
 @subsection PDP-11 Options
 @cindex PDP-11 Options
 
 These options are defined for the PDP-11:
 
Index: gcc/doc/md.texi
===================================================================
--- gcc/doc/md.texi	(revision 198591)
+++ gcc/doc/md.texi	(working copy)
@@ -3050,12 +3050,41 @@  A constant in the range of 0 to 255.
 
 @item N
 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 reference, any type, but restricted 64k range of constants.
+
+@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
 Floating point registers AC0 through AC3.  These can be loaded from/to
 memory with a single instruction.
 
Index: gcc/doc/install.texi
===================================================================
--- gcc/doc/install.texi	(revision 198591)
+++ gcc/doc/install.texi	(working copy)
@@ -3946,12 +3946,19 @@  the O32 ABI.
 @heading @anchor{moxie-x-elf}moxie-*-elf
 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}}
 switch by using the configure option @option{--with-cpu-@var{cpu_type}}.
 
 You will need
Index: gcc/cfgexpand.c
===================================================================
--- gcc/cfgexpand.c	(revision 198591)
+++ gcc/cfgexpand.c	(working copy)
@@ -3090,13 +3090,17 @@  expand_debug_expr (tree exp)
 	 size_t, we need to check for mis-matched modes and correct
 	 the addend.  */
       if (op0 && op1
 	  && GET_MODE (op0) != VOIDmode && GET_MODE (op1) != VOIDmode
 	  && GET_MODE (op0) != GET_MODE (op1))
 	{
-	  if (GET_MODE_BITSIZE (GET_MODE (op0)) < GET_MODE_BITSIZE (GET_MODE (op1)))
+	  if (GET_MODE_BITSIZE (GET_MODE (op0)) < GET_MODE_BITSIZE (GET_MODE (op1))
+	      /* Don't try to sign-extend SImode to PSImode, for example.  */
+	      || (GET_MODE_BITSIZE (GET_MODE (op0)) == GET_MODE_BITSIZE (GET_MODE (op1))
+		  && GET_MODE_CLASS (GET_MODE (op0)) == MODE_PARTIAL_INT
+		  && GET_MODE_CLASS (GET_MODE (op1)) == MODE_INT))
 	    op1 = simplify_gen_unary (TRUNCATE, GET_MODE (op0), op1,
 				      GET_MODE (op1));
 	  else
 	    /* We always sign-extend, regardless of the signedness of
 	       the operand, because the operand is always unsigned
 	       here even if the original C expression is signed.  */
Index: gcc/simplify-rtx.c
===================================================================
--- gcc/simplify-rtx.c	(revision 198591)
+++ gcc/simplify-rtx.c	(working copy)
@@ -5787,12 +5787,22 @@  simplify_immed_subreg (enum machine_mode
 /* Simplify SUBREG:OUTERMODE(OP:INNERMODE, BYTE)
    Return 0 if no simplifications are possible.  */
 rtx
 simplify_subreg (enum machine_mode outermode, rtx op,
 		 enum machine_mode innermode, unsigned int byte)
 {
+  /* FIXME: hack to allow building of newlib/libc.a for msp430/430x/large multilib.
+     The problem is the var-tracking is generating paradoxical SUBREGs.  Not sure why...  */
+  if (!(GET_MODE (op) == innermode
+        || GET_MODE (op) == VOIDmode)
+      || (innermode == VOIDmode)
+      )
+    {
+      fprintf (stderr, "== DJ WAS HERE ==\n");
+    return NULL_RTX;
+    }
   /* Little bit of sanity checking.  */
   gcc_assert (innermode != VOIDmode);
   gcc_assert (outermode != VOIDmode);
   gcc_assert (innermode != BLKmode);
   gcc_assert (outermode != BLKmode);
 
Index: gcc/dwarf2cfi.c
===================================================================
--- gcc/dwarf2cfi.c	(revision 198591)
+++ gcc/dwarf2cfi.c	(working copy)
@@ -277,12 +277,19 @@  expand_builtin_init_dwarf_reg_sizes (tre
 	    {
 	      if (save_mode == VOIDmode)
 		continue;
 	      wrote_return_column = true;
 	    }
 	  size = GET_MODE_SIZE (save_mode);
+
+          /* Entries in the dwarf_reg_size_table must be big enough to hold an _Unwind_Word
+             even if this is bigger than reg_raw_mode.  This can happen on targets where the
+             pointer size is larger than the integer size, and not a power-of-two.  (Eg MSP430).  */
+          if (size < GET_MODE_SIZE (targetm.unwind_word_mode ()))
+            size = GET_MODE_SIZE (targetm.unwind_word_mode ());
+
 	  if (offset < 0)
 	    continue;
 
 	  emit_move_insn (adjust_address (mem, mode, offset),
 			  gen_int_mode (size, mode));
 	}
Index: gcc/config.gcc
===================================================================
--- gcc/config.gcc	(revision 198591)
+++ gcc/config.gcc	(working copy)
@@ -1980,12 +1980,19 @@  mn10300-*-*)
 	then
 		tm_file="${tm_file} dbx.h"
 	fi
 	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
 	;;
 picochip-*)
 	tm_file="${tm_file} newlib-stdint.h"
Index: gcc/config/msp430/msp430-protos.h
===================================================================
--- gcc/config/msp430/msp430-protos.h	(revision 0)
+++ gcc/config/msp430/msp430-protos.h	(revision 0)
@@ -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 */
Index: gcc/config/msp430/predicates.md
===================================================================
--- gcc/config/msp430/predicates.md	(revision 0)
+++ gcc/config/msp430/predicates.md	(revision 0)
@@ -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 "))))
Index: gcc/config/msp430/msp430.md
===================================================================
--- gcc/config/msp430/msp430.md	(revision 0)
+++ gcc/config/msp430/msp430.md	(revision 0)
@@ -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"
+)
+  
Index: gcc/config/msp430/constraints.md
===================================================================
--- gcc/config/msp430/constraints.md	(revision 0)
+++ gcc/config/msp430/constraints.md	(revision 0)
@@ -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")
+	)))
+  
+
Index: gcc/config/msp430/t-msp430
===================================================================
--- gcc/config/msp430/t-msp430	(revision 0)
+++ gcc/config/msp430/t-msp430	(revision 0)
@@ -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) $<
Index: gcc/config/msp430/msp430.c
===================================================================
--- gcc/config/msp430/msp430.c	(revision 0)
+++ gcc/config/msp430/msp430.c	(revision 0)
@@ -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"
Index: gcc/config/msp430/msp430-c.c
===================================================================
--- gcc/config/msp430/msp430-c.c	(revision 0)
+++ gcc/config/msp430/msp430-c.c	(revision 0)
@@ -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);
+}
Index: gcc/config/msp430/msp430.opt
===================================================================
--- gcc/config/msp430/msp430.opt	(revision 0)
+++ gcc/config/msp430/msp430.opt	(revision 0)
@@ -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)
Index: gcc/config/msp430/msp430-modes.def
===================================================================
--- gcc/config/msp430/msp430-modes.def	(revision 0)
+++ gcc/config/msp430/msp430-modes.def	(revision 0)
@@ -0,0 +1,3 @@ 
+/* 20-bit address */
+PARTIAL_INT_MODE (SI);
+
Index: gcc/config/msp430/README.txt
===================================================================
--- gcc/config/msp430/README.txt	(revision 0)
+++ gcc/config/msp430/README.txt	(revision 0)
@@ -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.
Index: gcc/config/msp430/msp430.h
===================================================================
--- gcc/config/msp430/msp430.h	(revision 0)
+++ gcc/config/msp430/msp430.h	(revision 0)
@@ -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

[wwwdocs]

Index: htdocs/backends.html
===================================================================
RCS file: /cvs/gcc/wwwdocs/htdocs/backends.html,v
retrieving revision 1.46
diff -p -U 5 -r1.46 backends.html
--- htdocs/backends.html	16 Jul 2012 21:19:20 -0000	1.46
+++ htdocs/backends.html	11 May 2013 00:27:49 -0000
@@ -90,10 +90,11 @@  mep      |       F C       p g  d t s
 microblaze         CB          bd   s
 mips     |     Q   CB   qr p   bda  s
 mmix     | HM  Q   C    q  p   b a e 
 mn10300  | ??             c  g      s
 ms1      |   S   F  B      p g bd
+msp430   |    L  FI    l   p g      s
 pa       |   ? Q   CBD  qr    m da e 
 pdp11    |    L   IC    qrcp       e 
 rs6000   |     Q   C    qr      da   
 s390     |   ? Q        qr p g bda e 
 sh       |     Q   CB   qr     bda   
Index: htdocs/index.html
===================================================================
RCS file: /cvs/gcc/wwwdocs/htdocs/index.html,v
retrieving revision 1.882
diff -p -U 5 -r1.882 index.html
--- htdocs/index.html	30 Apr 2013 16:19:33 -0000	1.882
+++ htdocs/index.html	11 May 2013 00:27:49 -0000
@@ -51,10 +51,14 @@  mission statement</a>.</p>
 
 <h2 style="margin-top:0pt;" id="news">News</h2>
 
 <dl class="news">
 
+<dt><span>TI MSP430 support</span>
+    <span class="date">[2013-05-09]</span></dt>
+<dd>A port for the TI MSP430 has been contributed by Red Hat Inc.</dd>
+
 <dt><span><a href="gcc-4.6/">GCC 4.6.4</a> released</span>
     <span class="date">[2013-04-12]</span></dt>
     <dd></dd>
 
 <dt><span><a href="gcc-4.7/">GCC 4.7.3</a> released</span>
Index: htdocs/readings.html
===================================================================
RCS file: /cvs/gcc/wwwdocs/htdocs/readings.html,v
retrieving revision 1.231
diff -p -U 5 -r1.231 readings.html
--- htdocs/readings.html	1 Apr 2013 10:49:54 -0000	1.231
+++ htdocs/readings.html	11 May 2013 00:27:49 -0000
@@ -213,10 +213,15 @@  Intel&reg;64 and IA-32 Architectures Sof
  <li>mn10300
   <br />Manufacturer: Matsushita
   <br />Alternate chip name: AM30
   <br />GDB includes a simulator.
  </li>
+
+ <li>msp430
+  <br />Manufacturer: Texas Instruments
+  <br />GDB includes a simulator.
+ </li>
  
  <li>ns32k
   <br />Manufacturer: National Semiconductor
   <br /><a href="http://www.national.com/pf/NS/NS32FX200.html">NS32FX200 Home Page</a>
  </li>