diff mbox

msp430 port

Message ID 201307232208.r6NM8QpY018297@greed.delorie.com
State New
Headers show

Commit Message

DJ Delorie July 23, 2013, 10:08 p.m. UTC
Ok, I think I covered everything...


[gcc]

Comments

Jeff Law July 30, 2013, 6:24 p.m. UTC | #1
On 07/23/2013 04:08 PM, DJ Delorie wrote:

> Index: gcc/cfgexpand.c
> ===================================================================
> --- gcc/cfgexpand.c	(revision 201184)
> +++ gcc/cfgexpand.c	(working copy)
I thought I already approved this.  Go ahead and install it.

> Index: gcc/simplify-rtx.c
> ===================================================================
> --- gcc/simplify-rtx.c	(revision 201184)
> +++ gcc/simplify-rtx.c	(working copy)
Testcase?  Explanation?  This seems like you're papering over a bug.

> Index: gcc/dwarf2cfi.c
> ===================================================================
> --- gcc/dwarf2cfi.c	(revision 201184)
> +++ 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 ());
So was there a discussion of this patch?  Presumably BITS_PER_WORD is 16 
and you've got 20 bit pointers which causes this problem, right?

I think you should go ahead and install this patch as well.

> +; 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"
> +)
So how is this different fram
(set (psi) (truncate:psi (si)))?




  +)
> +
> +; 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")))
> +   (clobber (reg:CC CARRY))
> +   ]
> +  ""
> +  "ADD.W\t%L2, %L0 { ADDC.W\t%H2, %H0 { PUSH.W %H0 { PUSH.W %L0 { POPM.A #1, %0"
> +
Is it possible the insns which resulted in adding this pattern came from 
trying to zero/sign extend the frame pointer, then the frame pointer 
gets eliminated and turns into a (plus (sp) (const_int)?

I dealt with this by having a special alternative to the 
zero_extendpsisi2 and extendpsi_si2 patterns.  I used a constraint which 
matched sp + offset.  Feels cleaner as we don't have the subreg in there.


Jeff
DJ Delorie July 30, 2013, 6:47 p.m. UTC | #2
> > Index: gcc/cfgexpand.c
> > ===================================================================
> > --- gcc/cfgexpand.c	(revision 201184)
> > +++ gcc/cfgexpand.c	(working copy)
> I thought I already approved this.  Go ahead and install it.

Sorry, I forgot to split out those three patches when I diffed.

> > Index: gcc/simplify-rtx.c
> > ===================================================================
> > --- gcc/simplify-rtx.c	(revision 201184)
> > +++ gcc/simplify-rtx.c	(working copy)
> Testcase?  Explanation?  This seems like you're papering over a bug.

Likewise.

> > Index: gcc/dwarf2cfi.c
> So was there a discussion of this patch?  Presumably BITS_PER_WORD is 16 
> and you've got 20 bit pointers which causes this problem, right?

I don't recall any discussion.  Right, pointers are bigger than words.

> I think you should go ahead and install this patch as well.

Ok.

> > +; 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"
> > +)
> So how is this different fram
> (set (psi) (truncate:psi (si)))?

It should be the same, of course.  I typically look at what gcc *is*
generating, not what it *should* be generating, though ;-)

GCC does a lot of silly things these days.

> > +; 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")))
> > +   (clobber (reg:CC CARRY))
> > +   ]
> > +  ""
> > +  "ADD.W\t%L2, %L0 { ADDC.W\t%H2, %H0 { PUSH.W %H0 { PUSH.W %L0 { POPM.A #1, %0"
> > +
> Is it possible the insns which resulted in adding this pattern came from 
> trying to zero/sign extend the frame pointer, then the frame pointer 
> gets eliminated and turns into a (plus (sp) (const_int)?

It's possible that's one case, but *all* pointer math happens in
SImode since the pointer_plus change went in.  So this pattern happens
a lot.
Richard Henderson July 30, 2013, 8:18 p.m. UTC | #3
On 07/23/2013 12:08 PM, DJ Delorie wrote:
> ===================================================================
> --- gcc/simplify-rtx.c	(revision 201184)
> +++ gcc/simplify-rtx.c	(working copy)
> @@ -5884,12 +5884,23 @@ 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)
> +      )
> +    {
> +      debug_rtx (op);
> +      return NULL_RTX;
> +    }

Jeff asked about this one.
Certainly this sort of hack could never go in as-is.

> +(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))")))
> +)

The name could be better here.  Alternately,

> +; 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"))
> +)

... define these as

(define_predicate "msp_general_operand"
  (match_code "mem,reg,subreg,const_int,const,symbol_ref,label_ref"
{
  int save_volatile_ok = volatile_ok;
  volatile_ok = 1;
  int ret = general_operand (op, mode);
  volatile_ok = save_volatile_ok;
  return ret;
})

That said, why do they exist?

> +; 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 "))))

IN_RANGE?

> +;; This is nasty.  Operand0 is bogus.  It is only there so that we can get a
> +;; mode for the %B0 to work.  We should use operand1 for this, but that does
> +;; not have a mode.
> +;; 
> +;; Operand1 is actually a register, but we cannot accept (REG...) because the
> +;; cprop_hardreg pass can and will renumber registers even inside
> +;; unspec_volatiles.  So we take an integer register number parameter and
> +;; fudge it to be a register name when we generate the assembler.
> +;;
> +;; The pushm pattern does not have this problem because of all of the
> +;; frame info cruft attached to it, so cprop_hardreg leaves it alone.
> +(define_insn "popm"
> +  [(unspec_volatile [(match_operand 0 "register_operand" "r")
> +		     (match_operand 1 "immediate_operand" "i")
> +		     (match_operand 2 "immediate_operand" "i")] UNS_POPM)]
> +  ""
> +  "POPM%B0\t%2, r%D1"
> +  )

That's because the insn is mis-defined.  Even with unspec_volatile, you must
respect the form of rtl.  Above, operand 1 is positioned as an input, which is
wrong.  It must be positioned as an output, e.g.

  [(set (match_operand 0 "register_operand" "=r")
        (unspec_volatile [(match_operand 1 "immediate_operand" "i")]
                         UNS_POPM))]
  "POPM%B0\t%1, %0

> +;; 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).

Ug.  We ought to have been able to convince the compiler to copy the other
direction.  I.e. create storage for that argument as if it were a regular local
variable, spill the register portion into it, and also copy in the fragment
from the stack.

That sort of solution seems better than fiddling the location of the return
address in both directions.

> +; 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")))
> +   (clobber (reg:CC CARRY))

Do you really need the subreg here?  Or would you be better off with
a truncate pattern on the RHS?  Alternately, Jeff's solution.

> +(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")))

No constraints on splits.

> +   (clobber (reg:CC CARRY))
> +   ]
> +  ""
> +  [(parallel [(set (match_operand:HI 3 "nonimmediate_operand" "=&rm")

Nor here.

> +;; 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")))
> +   (clobber (reg:CC CARRY))

Under what conditions does reload generate 2 & 3?
We don't handle these cases for i386, so I question why
you'd have to handle them here.

> +(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"
> +)

This really should be an alternative of

> +(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")))
> +   (clobber (reg:CC CARRY))
> +   ]
> +  ""
> +  "@
> +   AND%x0%B0\t%2, %0
> +   AND%X0%B0\t%2, %0"
> +)

... this.

> +(define_insn "msp_return"
> +  [(return)]
> +  ""
> +  { return TARGET_LARGE ? "RETA" : "RET"; }
> +)

I suppose shrink-wrapping results in larger prologues and epilogues
in general?  Otherwise I'd suggest using simple_return here.

> +(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:CC CARRY))
> +   ]

Do you find these "reversed" patterns actually used?  In the deep dark past
one needed to provide them, but I thought we'd fixed the middle-end not to
generate them anymore...

> +;; 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")
> +	)))

"stack-only" isn't a good description here, surely, since it supports any base
register with minimal offset.

Also, maybe better to use define_memory_constraint, since that way reload is
told that it can reduce any address to a bare base register in order to satisfy
the constraint?

Or does that tend to get in the way of using Ys in alternative 0, and m in
alternative 1?  If so, that fact deserves a comment because it looks like a
mistake otherwise.

> +  /* Which registers need to be saved in the pro/epilogue.  */
> +  int need_to_save [FIRST_PSEUDO_REGISTER];

HARD_REG_SET, surely.

> +#undef  TARGET_FRAME_POINTER_REQUIRED
> +#define TARGET_FRAME_POINTER_REQUIRED msp430_frame_pointer_required
> +
> +static bool
> +msp430_frame_pointer_required (void)
> +{
> +  return false;
> +}

hook_bool_void_false.

> +bool
> +msp430_promote_prototypes (const_tree fntype ATTRIBUTE_UNUSED)
> +{
> +  return false;
> +}

hook_bool_const_tree_false

> +static enum machine_mode
> +msp430_get_raw_arg_mode (int regno)
> +{
> +  return (regno == ARG_POINTER_REGNUM) ? VOIDmode : Pmode;
> +}

How can the raw mode of AP be VOID?


r~
Jeff Law July 30, 2013, 8:21 p.m. UTC | #4
On 07/30/2013 12:47 PM, DJ Delorie wrote:
>
>>> +; 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"
>>> +)
>> So how is this different fram
>> (set (psi) (truncate:psi (si)))?
>
> It should be the same, of course.  I typically look at what gcc *is*
> generating, not what it *should* be generating, though ;-)
>
> GCC does a lot of silly things these days.
Well, you need to show why GCC is generating this and we need to 
evaluate whether or not it's safe.  I'm very leery of anything using a 
PSImode SUBREG on a port where truncation is not a nop.

>
>>> +; 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")))
>>> +   (clobber (reg:CC CARRY))
>>> +   ]
>>> +  ""
>>> +  "ADD.W\t%L2, %L0 { ADDC.W\t%H2, %H0 { PUSH.W %H0 { PUSH.W %L0 { POPM.A #1, %0"
>>> +
>> Is it possible the insns which resulted in adding this pattern came from
>> trying to zero/sign extend the frame pointer, then the frame pointer
>> gets eliminated and turns into a (plus (sp) (const_int)?
>
> It's possible that's one case, but *all* pointer math happens in
> SImode since the pointer_plus change went in.  So this pattern happens
> a lot.
I'm very aware that all pointer math happens in SImode.   My point is 
you need to find out *why* pattern was needed, explain it to this list 
so that we can evaluate if it's the right solution.  I brought up the 
issue from the mn102 port because there's some reasonable chance it's 
the same problem.  If it is the same problem, then we can discuss which 
is the better solution or if we hate them both, look at what it might 
take to fix reload.


jeff
DJ Delorie July 31, 2013, 3:24 a.m. UTC | #5
[nickc added for comments about the bits he wrote]

> ... define these as
> 
> (define_predicate "msp_general_operand"
>   (match_code "mem,reg,subreg,const_int,const,symbol_ref,label_ref"
> {
>   int save_volatile_ok = volatile_ok;
>   volatile_ok = 1;
>   int ret = general_operand (op, mode);
>   volatile_ok = save_volatile_ok;
>   return ret;
> })
> 
> That said, why do they exist?

Because gcc refuses to optimize operations with volatile memory
references, even when the target has opcodes that follow the volatile
memory rules.  "set bit in memory" for example.  I've had to do
something like this for every port I've written, for the same reason,
despite arguing against gcc's pedantry about volatile memory accesses.

> > +;; 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).
> 
> Ug.  We ought to have been able to convince the compiler to copy the other
> direction.  I.e. create storage for that argument as if it were a regular local
> variable, spill the register portion into it, and also copy in the fragment
> from the stack.
> 
> That sort of solution seems better than fiddling the location of the return
> address in both directions.

Nick, this one is yours.

> No constraints on splits.
> 
> Nor here.

Fixed.  Perhaps gen* could error on those?  I know they're ignored, I
just keep forgetting that splits are special.

(alternately, why can't they be included in the matching logic?)

> > +;; 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")))
> > +   (clobber (reg:CC CARRY))
> 
> Under what conditions does reload generate 2 & 3?
> We don't handle these cases for i386, so I question why
> you'd have to handle them here.

Hmmm... I took those alternatives out, and was still able to build
everything and test with no regressions.  Very strange.  Anyway, I'll
take those out.

> > +(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"
> > +)
> 
> This really should be an alternative of
> 
> > +(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")))
> > +   (clobber (reg:CC CARRY))
> > +   ]
> > +  ""
> > +  "@
> > +   AND%x0%B0\t%2, %0
> > +   AND%X0%B0\t%2, %0"
> > +)
> 
> ... this.

The first doesn't have a clobber, though...

> I suppose shrink-wrapping results in larger prologues and epilogues
> in general?  Otherwise I'd suggest using simple_return here.

../../gcc-trunkb/gcc/function.c: In function 'vec<edge_def*, va_heap, vl_ptr> convert_jumps_to_returns(basic_block_def*, bool, vec<edge_def*, va_heap, vl_ptr>)':
../../gcc-trunkb/gcc/function.c:5765: error: 'emit_use_return_register_into_block' was not declared in this scope
../../gcc-trunkb/gcc/function.c:5767: error: 'emit_return_into_block' was not declared in this scope
../../gcc-trunkb/gcc/function.c:5797: error: 'emit_use_return_register_into_block' was not declared in this scope
../../gcc-trunkb/gcc/function.c: In function 'basic_block_def* emit_return_for_exit(edge_def*, bool)':
../../gcc-trunkb/gcc/function.c:5839: error: 'emit_return_into_block' was not declared in this scope
../../gcc-trunkb/gcc/function.c: In function 'void thread_prologue_and_epilogue_insns()':
../../gcc-trunkb/gcc/function.c:6594: error: 'emit_return_into_block' was not declared in this scope
../../gcc-trunkb/gcc/function.c:6625: error: 'emit_return_into_block' was not declared in this scope

> Do you find these "reversed" patterns actually used?  In the deep
> dark past one needed to provide them, but I thought we'd fixed the
> middle-end not to generate them anymore...

It's not that kind of reverse.  The MSP430 doesn't have a full
complement of comparisons; sometimes we need to use a reversed-operand
comparison to make up for a missing one:

	; TRUE for comparisons we need to reverse.
	(define_predicate "msp430_reversible_cmp_operator"
	  (match_code "gt,gtu,le,leu"))

> > +; 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 "))))
> 
> IN_RANGE?

Ok.


> That's because the insn is mis-defined.  Even with unspec_volatile, you must
> respect the form of rtl.  Above, operand 1 is positioned as an input, which is
> wrong.  It must be positioned as an output, e.g.
> 
>   [(set (match_operand 0 "register_operand" "=r")
>         (unspec_volatile [(match_operand 1 "immediate_operand" "i")]
>                          UNS_POPM))]
>   "POPM%B0\t%1, %0

operand 1 indicates *one* of the registers that is popped, but not all
of them.  POPM pops a variable number of registers.  How do you
specifiy that in RTL?

> > +;; 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")
> > +	)))
> 
> "stack-only" isn't a good description here, surely, since it supports any base
> register with minimal offset.

It's not the stack register, it's the *stack*.  We know the stack is
in the first 64k, but other objects may not be.  The MSP430X has a
feature in silicon that, if a register 'happens' to be less than 64k,
will truncate a (reg+int16) address to 64k, but if the register is
already above 64k, no truncation occurs.  I.e. the 64k wrap depends on
the *value* in the register, not the addressing mode or opcode
encoding.

So, for example, if R6 has 0xffe0 and you use [R6+0x0100], you will
get [0x00e0] not [0x100e0], but if R6 has 0x1ffe0 you get [0x200e0].

We can avoid this if we think a wrap is possible by using an int20
displacement instead, which is the other variant.

> Also, maybe better to use define_memory_constraint, since that way
> reload is told that it can reduce any address to a bare base
> register in order to satisfy the constraint?

Maybe.  Not sure if it's a win though.  For example, if you're
referencing a struct, you don't want to be doing pointer math over and
over again when a simple [reg+ofs20] will do.

> > +  /* Which registers need to be saved in the pro/epilogue.  */
> > +  int need_to_save [FIRST_PSEUDO_REGISTER];
> 
> HARD_REG_SET, surely.

Does it really matter, or is this just convention?  An array is faster
for a small fixed number of registers.

> > +#undef  TARGET_FRAME_POINTER_REQUIRED
> > +#define TARGET_FRAME_POINTER_REQUIRED msp430_frame_pointer_required
> > +
> > +static bool
> > +msp430_frame_pointer_required (void)
> > +{
> > +  return false;
> > +}
> 
> hook_bool_void_false.

Will do.

> > +bool
> > +msp430_promote_prototypes (const_tree fntype ATTRIBUTE_UNUSED)
> > +{
> > +  return false;
> > +}
> 
> hook_bool_const_tree_false

Will do.

> > +static enum machine_mode
> > +msp430_get_raw_arg_mode (int regno)
> > +{
> > +  return (regno == ARG_POINTER_REGNUM) ? VOIDmode : Pmode;
> > +}
> 
> How can the raw mode of AP be VOID?

Nick, this one's yours.
Nick Clifton July 31, 2013, 1:40 p.m. UTC | #6
Hi DJ, Hi Richard,

>>> +;; 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).
>>
>> Ug.  We ought to have been able to convince the compiler to copy the other
>> direction.  I.e. create storage for that argument as if it were a regular local
>> variable, spill the register portion into it, and also copy in the fragment
>> from the stack.
>>
>> That sort of solution seems better than fiddling the location of the return
>> address in both directions.

I agree - but I just do not have the GCC-fu skills to do this.  Hence I 
created the two patterns.


>>> +static enum machine_mode
>>> +msp430_get_raw_arg_mode (int regno)
>>> +{
>>> +  return (regno == ARG_POINTER_REGNUM) ? VOIDmode : Pmode;
>>> +}
>>
>> How can the raw mode of AP be VOID?

It cannot.  This was a bit of debugging that I put in whilst trying to 
track down problems with __builtin_apply_args().  Sorry - it should have 
been removed.

Cheers
   Nick
Richard Henderson July 31, 2013, 4:50 p.m. UTC | #7
On 07/30/2013 05:24 PM, DJ Delorie wrote:
> Fixed.  Perhaps gen* could error on those?  I know they're ignored, I
> just keep forgetting that splits are special.
> 
> (alternately, why can't they be included in the matching logic?)

(Because pre-reload, pseudos don't have register classes, mostly)

>>> +(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"
>>> +)
>>
>> This really should be an alternative of
>>
>>> +(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")))
>>> +   (clobber (reg:CC CARRY))
>>> +   ]
>>> +  ""
>>> +  "@
>>> +   AND%x0%B0\t%2, %0
>>> +   AND%X0%B0\t%2, %0"
>>> +)
>>
>> ... this.
> 
> The first doesn't have a clobber, though...

Hmm.  Missed that.  So the only reason you'd care to include the bic
in the regular and pattern is if it were a smaller encoding than the
regular r/0/i alternative.

>> I suppose shrink-wrapping results in larger prologues and epilogues
>> in general?  Otherwise I'd suggest using simple_return here.
> 
> ../../gcc-trunkb/gcc/function.c: In function 'vec<edge_def*, va_heap, vl_ptr> convert_jumps_to_returns(basic_block_def*, bool, vec<edge_def*, va_heap, vl_ptr>)':
> ../../gcc-trunkb/gcc/function.c:5765: error: 'emit_use_return_register_into_block' was not declared in this scope
> ../../gcc-trunkb/gcc/function.c:5767: error: 'emit_return_into_block' was not declared in this scope
> ../../gcc-trunkb/gcc/function.c:5797: error: 'emit_use_return_register_into_block' was not declared in this scope
> ../../gcc-trunkb/gcc/function.c: In function 'basic_block_def* emit_return_for_exit(edge_def*, bool)':
> ../../gcc-trunkb/gcc/function.c:5839: error: 'emit_return_into_block' was not declared in this scope
> ../../gcc-trunkb/gcc/function.c: In function 'void thread_prologue_and_epilogue_insns()':
> ../../gcc-trunkb/gcc/function.c:6594: error: 'emit_return_into_block' was not declared in this scope
> ../../gcc-trunkb/gcc/function.c:6625: error: 'emit_return_into_block' was not declared in this scope

You need to implement the "return" pattern as well as "simple_return".
They don't actually have to be different, implementation-wise.  See
the i386 version, where both named patterns expand to the same insn.

>> That's because the insn is mis-defined.  Even with unspec_volatile, you must
>> respect the form of rtl.  Above, operand 1 is positioned as an input, which is
>> wrong.  It must be positioned as an output, e.g.
>>
>>   [(set (match_operand 0 "register_operand" "=r")
>>         (unspec_volatile [(match_operand 1 "immediate_operand" "i")]
>>                          UNS_POPM))]
>>   "POPM%B0\t%1, %0
> 
> operand 1 indicates *one* of the registers that is popped, but not all
> of them.  POPM pops a variable number of registers.  How do you
> specifiy that in RTL?

It depends on your requirements.  Is it strictly 1, 2, 4 registers?  In
which case it's easiest to use HI, SI, DImode with one output.

Is it odd, or large numbers of registers?  Do you need these patterns
before reload (e.g. as part of your block move expansion)?

If you only need them post-reload, follow the lead of the s390 port.
See the "load_multiple" and "store_multiple" expanders, and their
associated insns.  In this case, everything folds nicely down with
a match_parallel.

If you need them pre-reload, you'll have to use the more complicated
scheme used by the ARM port.  There, you have a set of patterns for
every distinct number of registers, since reload can't see through
a match_parallel in order to do replacement.

> It's not the stack register, it's the *stack*.  We know the stack is
> in the first 64k, but other objects may not be.  The MSP430X has a
> feature in silicon that, if a register 'happens' to be less than 64k,
> will truncate a (reg+int16) address to 64k, but if the register is
> already above 64k, no truncation occurs.  I.e. the 64k wrap depends on
> the *value* in the register, not the addressing mode or opcode
> encoding.
> 
> So, for example, if R6 has 0xffe0 and you use [R6+0x0100], you will
> get [0x00e0] not [0x100e0], but if R6 has 0x1ffe0 you get [0x200e0].

Oh my.  Ew.


r~
DJ Delorie July 31, 2013, 5:08 p.m. UTC | #8
> > The first doesn't have a clobber, though...
> 
> Hmm.  Missed that.  So the only reason you'd care to include the bic
> in the regular and pattern is if it were a smaller encoding than the
> regular r/0/i alternative.

It is, but the separate pattern picks that out just fine.

> You need to implement the "return" pattern as well as "simple_return".
> They don't actually have to be different, implementation-wise.  See
> the i386 version, where both named patterns expand to the same insn.

How is this an advantage from just building the return from the epilog
expander?

> It depends on your requirements.  Is it strictly 1, 2, 4 registers?  In
> which case it's easiest to use HI, SI, DImode with one output.

It's an arbitrary number of registers, used only by the epilogue
expander.

> If you only need them post-reload, follow the lead of the s390 port.
> See the "load_multiple" and "store_multiple" expanders, and their
> associated insns.  In this case, everything folds nicely down with
> a match_parallel.

Will do.
Mike Stump July 31, 2013, 5:49 p.m. UTC | #9
On Jul 30, 2013, at 8:24 PM, DJ Delorie <dj@redhat.com> wrote:
> [nickc added for comments about the bits he wrote]
> 
>> ... define these as
>> 
>> (define_predicate "msp_general_operand"
>>  (match_code "mem,reg,subreg,const_int,const,symbol_ref,label_ref"
>> {
>>  int save_volatile_ok = volatile_ok;
>>  volatile_ok = 1;
>>  int ret = general_operand (op, mode);
>>  volatile_ok = save_volatile_ok;
>>  return ret;
>> })
>> 
>> That said, why do they exist?
> 
> Because gcc refuses to optimize operations with volatile memory
> references, even when the target has opcodes that follow the volatile
> memory rules.  "set bit in memory" for example.  I've had to do
> something like this for every port I've written, for the same reason,
> despite arguing against gcc's pedantry about volatile memory accesses.

So, I prefer having a target hook that says, this port is volatile clean, go ahead and fully optimize volatile.  Then, a port that would want to do this, can simply turn it on, fix all the bugs, and get on with life.  The default for a port, should be to say, this port is volatile clean.  All the old ports can say, unclean.  In time, hopefully they will all be deleted (for fixed).  :-)
Richard Henderson July 31, 2013, 8:20 p.m. UTC | #10
On 07/31/2013 07:08 AM, DJ Delorie wrote:
>>> The first doesn't have a clobber, though...
>>
>> Hmm.  Missed that.  So the only reason you'd care to include the bic
>> in the regular and pattern is if it were a smaller encoding than the
>> regular r/0/i alternative.
> 
> It is, but the separate pattern picks that out just fine.

That depends on how we get here.  Consider an AND insn with r/0/r
operands, and the second register gets spilled, and reload proves
that it held an immediate.  In that case reload will only consider
the r/0/i alternative, and the shorter bic sequence.

One can always split away the clobber post-reload.  Not that your
port currently makes significant use of the flags register to
worry about it.

>> You need to implement the "return" pattern as well as "simple_return".
>> They don't actually have to be different, implementation-wise.  See
>> the i386 version, where both named patterns expand to the same insn.
> 
> How is this an advantage from just building the return from the epilog
> expander?

The code in function.c might transform

	saves
	if arg == 0 return;
	something
	restores
	return

to

	if arg == 0 return;
	saves
	something
	restores
	return

Of course... now that I think about it, that transform really only applies
to saves using a move-like insn, not a push-like insn.  So ignore me here
and don't define simple_return.

OTOH, a normal "return" insn can still be helpful, usually predicated on
not having a stack frame.  See i386 "return" for an example here.  The
benefit will be branch-to-return will be replaced with a plain return.

>> If you only need them post-reload, follow the lead of the s390 port.
>> See the "load_multiple" and "store_multiple" expanders, and their
>> associated insns.  In this case, everything folds nicely down with
>> a match_parallel.
> 
> Will do.

See also m68k, if you'd like another example.


r~
Gerald Pfeifer Aug. 4, 2013, 6:15 p.m. UTC | #11
On Tue, 23 Jul 2013, DJ Delorie wrote:
> Ok, I think I covered everything...

...except one comma. ;-)

> Index: gcc/doc/contrib.texi
> ===================================================================
> -Nick Clifton for arm, mcore, fr30, v850, m32r, rx work,
> +Nick Clifton for arm, mcore, fr30, v850, m32r, msp430 rx work,
                                                       ^^^

Gerald
DJ Delorie Aug. 5, 2013, 5:39 p.m. UTC | #12
comma comma comma comma comma comma

got it ;-)
Jeff Law Aug. 19, 2013, 8:21 p.m. UTC | #13
On 07/30/2013 09:24 PM, DJ Delorie wrote:
> [nickc added for comments about the bits he wrote]
>
>> ... define these as
>>
>> (define_predicate "msp_general_operand"
>>    (match_code "mem,reg,subreg,const_int,const,symbol_ref,label_ref"
>> {
>>    int save_volatile_ok = volatile_ok;
>>    volatile_ok = 1;
>>    int ret = general_operand (op, mode);
>>    volatile_ok = save_volatile_ok;
>>    return ret;
>> })
>>
>> That said, why do they exist?
>
> Because gcc refuses to optimize operations with volatile memory
> references, even when the target has opcodes that follow the volatile
> memory rules.  "set bit in memory" for example.  I've had to do
> something like this for every port I've written, for the same reason,
> despite arguing against gcc's pedantry about volatile memory accesses.
I'd say it's not as simple as you make it out to be.  You can't blindly 
combine operations on volatile memory.  ie, the programmer may have 
written them as separate statements and if they're volatile you should 
leave them alone.  With this change a series of statements involving 
volatiles might be combined into a single insn.  That's not good.

So while you will get better optimization in the presence of volatile, 
you'll also eventually get a mis-optimization of a volatile reference. 
And debugging it will be an absolute nightmare because whether or not it 
causes a visible problem will be dependent on the state of some hardware 
widget.

I'll note that *NO* ports in the official GCC sources do this and that's 
because it's wrong.  Unfortunately, I missed this when looking at the 
port or I would have called it out earlier.  What you may have done for 
ports that are still in private trees is not pertinent.



Jeff
DJ Delorie Aug. 19, 2013, 8:49 p.m. UTC | #14
> I'd say it's not as simple as you make it out to be.  You can't blindly 
> combine operations on volatile memory.

I'm not blindly combining them, I'm combining them when I know the
hardware will do the volatile-correct thing.

> ie, the programmer may have written them as separate statements and
> if they're volatile you should leave them alone.

Most of the programmers I know would expect "port |= 0x80;" to do a
hardware-specific "set bits" operation, not a series of
volatile-pedantic operations, especially when the ISA has a set of
insns specifically designed to do bit operations on volatile I/O
registers.

> With this change a series of statements involving 
> volatiles might be combined into a single insn.  That's not good.

If the insn does exactly the same thing as the operations, just
faster, why is it not good?

> I'll note that *NO* ports in the official GCC sources do this and that's 
> because it's wrong.

m32c, rl78, and sh do this (to varying degrees) in the official
sources.
Jeff Law Aug. 19, 2013, 8:54 p.m. UTC | #15
On 08/19/2013 02:49 PM, DJ Delorie wrote:
>> I'd say it's not as simple as you make it out to be.  You can't blindly
>> combine operations on volatile memory.
>
> I'm not blindly combining them, I'm combining them when I know the
> hardware will do the volatile-correct thing.
You're missing the point.  If the programmer wrote two statements which 
hit volatile memory and you've got some pattern which matches those two 
statements, then with your change you'll end up combining them, that's 
wrong.

>
>> ie, the programmer may have written them as separate statements and
>> if they're volatile you should leave them alone.
>
> Most of the programmers I know would expect "port |= 0x80;" to do a
> hardware-specific "set bits" operation, not a series of
> volatile-pedantic operations, especially when the ISA has a set of
> insns specifically designed to do bit operations on volatile I/O
> registers.
I fully understand that.  But that doesn't change the fact that if the 
programmer wrote separate statements with volatile operands you can't 
combine them.  Your change allows such combinations as far as I can tell.

You simply don't have enough context at any point to know if what you're 
doing is safe or not.


Jeff
DJ Delorie Aug. 19, 2013, 9:21 p.m. UTC | #16
> You're missing the point.  If the programmer wrote two statements
> which hit volatile memory and you've got some pattern which matches
> those two statements, then with your change you'll end up combining
> them, that's wrong.

I see nothing in the ISO spec that says you can't combine a volatile
read/modify/write cycle into a single insn.  The spec requires that
the volatile value is stable at sequence points, but does not (AFAICT)
require that the sequence point be between insns.

So even if the programmer wrote:

	register int a;
	extern volatile int b;

	a = b;
	a |= 0x54;
	b = a;

The ISO spec seems to allow gcc to perform those operations in a
single physical insn, as long as the operations on 'b' are all
performed, and in the correct sequence.
Richard Kenner Aug. 19, 2013, 9:23 p.m. UTC | #17
> 	register int a;
> 	extern volatile int b;
> 
> 	a = b;
> 	a |= 0x54;
> 	b = a;
> 
> The ISO spec seems to allow gcc to perform those operations in a
> single physical insn, as long as the operations on 'b' are all
> performed, and in the correct sequence.

And I believe it's also consistent with the "traditional" view
of volatile if that were done with a single read-modify-write insn.
Oleg Endo Aug. 19, 2013, 9:39 p.m. UTC | #18
On Mon, 2013-08-19 at 16:49 -0400, DJ Delorie wrote:
> > I'd say it's not as simple as you make it out to be.  You can't blindly 
> > combine operations on volatile memory.
> 
> I'm not blindly combining them, I'm combining them when I know the
> hardware will do the volatile-correct thing.
> 
> > ie, the programmer may have written them as separate statements and
> > if they're volatile you should leave them alone.
> 
> Most of the programmers I know would expect "port |= 0x80;" to do a
> hardware-specific "set bits" operation, not a series of
> volatile-pedantic operations, especially when the ISA has a set of
> insns specifically designed to do bit operations on volatile I/O
> registers.
> 
> > With this change a series of statements involving 
> > volatiles might be combined into a single insn.  That's not good.
> 
> If the insn does exactly the same thing as the operations, just
> faster, why is it not good?
> 
> > I'll note that *NO* ports in the official GCC sources do this and that's 
> > because it's wrong.
> 
> m32c, rl78, and sh do this (to varying degrees) in the official
> sources.

Just a note regarding the issue in SH:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52483

In this case, the problem is that the volatile handling in
'general_operand' prevents matching of 'complex' addresses and sign
extending mem loads.

The recent SH volatile mem load fix doesn't play with the 'volatile_ok'
variable before invoking 'general_operand', but rather avoids it
altogether, by not using 'general_operand' for matching mems.  In this
case it should be fine, since it's done in the predicate
'general_movsrc_operand' which is used for mem loads only and not in
arithmetic insns.  Maybe it would be better to handle this in a general
way somehow instead of having to do workarounds in each target.

Cheers,
Oleg
Mike Stump Aug. 20, 2013, 1:04 a.m. UTC | #19
On Aug 19, 2013, at 1:54 PM, Jeff Law <law@redhat.com> wrote:
> On 08/19/2013 02:49 PM, DJ Delorie wrote:
>>> I'd say it's not as simple as you make it out to be.  You can't blindly
>>> combine operations on volatile memory.
>> 
>> I'm not blindly combining them, I'm combining them when I know the
>> hardware will do the volatile-correct thing.
> You're missing the point.  If the programmer wrote two statements which hit volatile memory and you've got some pattern which matches those two statements, then with your change you'll end up combining them, that's wrong.

Give a specific example.  I don't buy this.  Support your position with the semantics of the code given the change, and the semantics as required by the language standard.

> I fully understand that.  But that doesn't change the fact that if the programmer wrote separate statements with volatile operands you can't combine them.

Again you say this with no backing what-so-ever.

> You simply don't have enough context at any point to know if what you're doing is safe or not.

Then, you can give a concrete example of code that will fail.
Jeff Law Aug. 20, 2013, 8:40 a.m. UTC | #20
On 08/19/2013 07:04 PM, Mike Stump wrote:
> On Aug 19, 2013, at 1:54 PM, Jeff Law <law@redhat.com> wrote:
>> On 08/19/2013 02:49 PM, DJ Delorie wrote:
>>>> I'd say it's not as simple as you make it out to be.  You can't blindly
>>>> combine operations on volatile memory.
>>>
>>> I'm not blindly combining them, I'm combining them when I know the
>>> hardware will do the volatile-correct thing.
>> You're missing the point.  If the programmer wrote two statements which hit volatile memory and you've got some pattern which matches those two statements, then with your change you'll end up combining them, that's wrong.
>
> Give a specific example.  I don't buy this.  Support your position with the semantics of the code given the change, and the semantics as required by the language standard.
>
>> I fully understand that.  But that doesn't change the fact that if the programmer wrote separate statements with volatile operands you can't combine them.
>
> Again you say this with no backing what-so-ever.
>
>> You simply don't have enough context at any point to know if what you're doing is safe or not.
>
> Then, you can give a concrete example of code that will fail.
I'd have to dig out mail archives from the early 90s and hope I kept the 
discussion.  That involves pulling an HP R390 out from under the stairs 
to fire it up, at which point I tend to lose interest right quick due to 
its weight.  Not to mention that last time I fired it up I couldn't 
remember any of the passwords to login ;(

My recollection is I suggested or was investigating something similar 
back in the early 90s.  I can't recall if someone shot me down or my own 
investigations came up with a testcase which failed.

I'll withdraw my objection to the msp port's hacking of volatile_ok.  If 
someone is going to push for the change in a more general sense, we'll 
need to discuss further.





jeff
DJ Delorie Aug. 23, 2013, 7:52 p.m. UTC | #21
so... can I get an official "ok to commit with you and Nick as maintainers" then?
Jeff Law Aug. 24, 2013, 5:09 a.m. UTC | #22
On 08/23/2013 01:52 PM, DJ Delorie wrote:
> so... can I get an official "ok to commit with you and Nick as maintainers" then?
Just need to clear it with the steering committee, which for this sort 
of thing has been pretty trivial.  Basically it has to pass the 
technical review (which y'all have already done) and if y'all become 
unresponsive, then the port will be deprecated.

Jeff
diff mbox

Patch

Index: contrib/config-list.mk
===================================================================
--- contrib/config-list.mk	(revision 201184)
+++ 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 201184)
+++ 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
 nds32 port		Chung-Ju Wu		jasonwucj@gmail.com
 nds32 port		Shiva Chen		shiva0217@gmail.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
Index: libgcc/config.host
===================================================================
--- libgcc/config.host	(revision 201184)
+++ libgcc/config.host	(working copy)
@@ -829,12 +829,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,33 @@ 
+/* libgcc routines 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/>.  */
+
+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,37 @@ 
+/* libgcc routines 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/>.  */
+
+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
===================================================================
Index: libgcc/config/msp430/t-msp430
===================================================================
--- libgcc/config/msp430/t-msp430	(revision 0)
+++ libgcc/config/msp430/t-msp430	(revision 0)
@@ -0,0 +1,47 @@ 
+# 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/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/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/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/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,106 @@ 
+;   Copyright (C) 2012, 2013 Free Software Foundation, Inc.
+;   Contributed by Red Hat.
+; 
+; This file is free software; you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by the
+; Free Software Foundation; either version 3, or (at your option) any
+; later version.
+; 
+; This file is distributed in the hope that it will be useful, but
+; WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+; General Public License for more details.
+; 
+; Under Section 7 of GPL version 3, you are granted additional
+; permissions described in the GCC Runtime Library Exception, version
+; 3.1, as published by the Free Software Foundation.
+;
+; You should have received a copy of the GNU General Public License and
+; a copy of the GCC Runtime Library Exception along with this program;
+; see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+; <http://www.gnu.org/licenses/>.
+	
+	.text
+
+	.macro	_srai n
+	.global __mspabi_srai_\n
+__mspabi_srai_\n:
+	RRA.W	R12
+	.endm
+
+/* Logical Right Shift - R12 -> R12 */
+	_srai	15
+	_srai	14
+	_srai	13
+	_srai	12
+	_srai	11
+	_srai	10
+	_srai	9
+	_srai	8
+	_srai	7
+	_srai	6
+	_srai	5
+	_srai	4
+	_srai	3
+	_srai	2
+	_srai	1
+#ifdef __MSP430X_LARGE__
+	RETA
+#else
+	RET
+#endif
+
+1:	ADD.W	#-1,R13
+	RRA.W	R12,R12
+	.global	__mspabi_srai
+__mspabi_srai:
+	CMP	#0,R13
+	JNZ	1b
+#ifdef __MSP430X_LARGE__
+	RETA
+#else
+	RET
+#endif
+
+/* Logical Right Shift - R12:R13 -> R12:R13 */
+
+	.macro	_sral	n
+	.global	__mspabi_sral_\n
+__mspabi_sral_\n:
+	RRA.W	R13
+	RRC.W	R12
+	.endm
+
+	_sral	15
+	_sral	14
+	_sral	13
+	_sral	12
+	_sral	11
+	_sral	10
+	_sral	9
+	_sral	8
+	_sral	7
+	_sral	6
+	_sral	5
+	_sral	4
+	_sral	3
+	_sral	2
+	_sral	1
+#ifdef __MSP430X_LARGE__
+	RETA
+#else
+	RET
+#endif
+
+1:	ADD.W	#-1,R14
+	RRA.W	R13
+	RRC.W	R12
+	.global	__mspabi_sral
+__mspabi_sral:
+	CMP	#0,R14
+	JNZ	1b
+#ifdef __MSP430X_LARGE__
+	RETA
+#else
+	RET
+#endif
Index: libgcc/config/msp430/floathisf.c
===================================================================
--- libgcc/config/msp430/floathisf.c	(revision 0)
+++ libgcc/config/msp430/floathisf.c	(revision 0)
@@ -0,0 +1,36 @@ 
+/* libgcc routines 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/>.  */
+
+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,37 @@ 
+/* libgcc routines 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/>.  */
+
+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/cmpd.c
===================================================================
--- libgcc/config/msp430/cmpd.c	(revision 0)
+++ libgcc/config/msp430/cmpd.c	(revision 0)
@@ -0,0 +1,44 @@ 
+/* libgcc routines 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/>.  */
+
+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/slli.S
===================================================================
--- libgcc/config/msp430/slli.S	(revision 0)
+++ libgcc/config/msp430/slli.S	(revision 0)
@@ -0,0 +1,108 @@ 
+;   Copyright (C) 2012, 2013 Free Software Foundation, Inc.
+;   Contributed by Red Hat.
+; 
+; This file is free software; you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by the
+; Free Software Foundation; either version 3, or (at your option) any
+; later version.
+; 
+; This file is distributed in the hope that it will be useful, but
+; WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+; General Public License for more details.
+; 
+; Under Section 7 of GPL version 3, you are granted additional
+; permissions described in the GCC Runtime Library Exception, version
+; 3.1, as published by the Free Software Foundation.
+;
+; You should have received a copy of the GNU General Public License and
+; a copy of the GCC Runtime Library Exception along with this program;
+; see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+; <http://www.gnu.org/licenses/>.
+	
+	.text
+
+/* Logical Left Shift - R12 -> R12 */
+
+	.macro	_slli n
+	.global __mspabi_slli_\n
+__mspabi_slli_\n:
+	ADD.W	R12,R12
+	.endm
+
+	_slli	15
+	_slli	14
+	_slli	13
+	_slli	12
+	_slli	11
+	_slli	10
+	_slli	9
+	_slli	8
+	_slli	7
+	_slli	6
+	_slli	5
+	_slli	4
+	_slli	3
+	_slli	2
+	_slli	1
+#ifdef __MSP430X_LARGE__
+	RETA
+#else
+	RET
+#endif
+
+1:	ADD.W	#-1,R13
+	ADD.W	R12,R12
+	.global	__mspabi_slli
+__mspabi_slli:
+	CMP	#0,R13
+	JNZ	1b
+#ifdef __MSP430X_LARGE__
+	RETA
+#else
+	RET
+#endif
+
+/* Logical Left Shift - R12:R13 -> R12:R13 */
+
+	.macro	_slll	n
+	.global	__mspabi_slll_\n
+__mspabi_slll_\n:
+	ADD.W	R12,R12
+	ADDC.W	R13,R13
+	.endm
+
+	_slll	15
+	_slll	14
+	_slll	13
+	_slll	12
+	_slll	11
+	_slll	10
+	_slll	9
+	_slll	8
+	_slll	7
+	_slll	6
+	_slll	5
+	_slll	4
+	_slll	3
+	_slll	2
+	_slll	1
+#ifdef __MSP430X_LARGE__
+	RETA
+#else
+	RET
+#endif
+
+1:	ADD.W	#-1,R14
+	ADD.W	R12,R12
+	ADDC.W	R13,R13
+	.global	__mspabi_slll
+__mspabi_slll:
+	CMP	#0,R14
+	JNZ	1b
+#ifdef __MSP430X_LARGE__
+	RETA
+#else
+	RET
+#endif
+
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,51 @@ 
+;   Copyright (C) 2012, 2013 Free Software Foundation, Inc.
+;   Contributed by Red Hat.
+; 
+; This file is free software; you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by the
+; Free Software Foundation; either version 3, or (at your option) any
+; later version.
+; 
+; This file is distributed in the hope that it will be useful, but
+; WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+; General Public License for more details.
+; 
+; Under Section 7 of GPL version 3, you are granted additional
+; permissions described in the GCC Runtime Library Exception, version
+; 3.1, as published by the Free Software Foundation.
+;
+; You should have received a copy of the GNU General Public License and
+; a copy of the GCC Runtime Library Exception along with this program;
+; see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+; <http://www.gnu.org/licenses/>.
+
+	.text
+
+	.global	__mspabi_func_epilog_7
+	.global	__mspabi_func_epilog_6
+	.global	__mspabi_func_epilog_5
+	.global	__mspabi_func_epilog_4
+	.global	__mspabi_func_epilog_3
+	.global	__mspabi_func_epilog_2
+	.global	__mspabi_func_epilog_1
+
+__mspabi_func_epilog_7:
+	POP	R4
+__mspabi_func_epilog_6:
+	POP	R5
+__mspabi_func_epilog_5:
+	POP	R6
+__mspabi_func_epilog_4:
+	POP	R7
+__mspabi_func_epilog_3:
+	POP	R8
+__mspabi_func_epilog_2:
+	POP	R9
+__mspabi_func_epilog_1:
+	POP	R10
+#ifdef __MSP430X_LARGE__
+	RETA
+#else
+	RET
+#endif
Index: libgcc/config/msp430/srli.S
===================================================================
--- libgcc/config/msp430/srli.S	(revision 0)
+++ libgcc/config/msp430/srli.S	(revision 0)
@@ -0,0 +1,110 @@ 
+;   Copyright (C) 2012, 2013 Free Software Foundation, Inc.
+;   Contributed by Red Hat.
+; 
+; This file is free software; you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by the
+; Free Software Foundation; either version 3, or (at your option) any
+; later version.
+; 
+; This file is distributed in the hope that it will be useful, but
+; WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+; General Public License for more details.
+; 
+; Under Section 7 of GPL version 3, you are granted additional
+; permissions described in the GCC Runtime Library Exception, version
+; 3.1, as published by the Free Software Foundation.
+;
+; You should have received a copy of the GNU General Public License and
+; a copy of the GCC Runtime Library Exception along with this program;
+; see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+; <http://www.gnu.org/licenses/>.
+	
+	.text
+
+	.macro	_srli n
+	.global __mspabi_srli_\n
+__mspabi_srli_\n:
+	CLRC
+	RRC.W	R12
+	.endm
+
+/* Logical Right Shift - R12 -> R12 */
+	_srli	15
+	_srli	14
+	_srli	13
+	_srli	12
+	_srli	11
+	_srli	10
+	_srli	9
+	_srli	8
+	_srli	7
+	_srli	6
+	_srli	5
+	_srli	4
+	_srli	3
+	_srli	2
+	_srli	1
+#ifdef __MSP430X_LARGE__
+	RETA
+#else
+	RET
+#endif
+
+1:	ADD.W	#-1,R13
+	CLRC
+	RRC.W	R12,R12
+	.global	__mspabi_srli
+__mspabi_srli:
+	CMP	#0,R13
+	JNZ	1b
+#ifdef __MSP430X_LARGE__
+	RETA
+#else
+	RET
+#endif
+
+/* Logical Right Shift - R12:R13 -> R12:R13 */
+
+	.macro	_srll	n
+	.global	__mspabi_srll_\n
+__mspabi_srll_\n:
+	CLRC
+	RRC.W	R13
+	RRC.W	R12
+	.endm
+
+	_srll	15
+	_srll	14
+	_srll	13
+	_srll	12
+	_srll	11
+	_srll	10
+	_srll	9
+	_srll	8
+	_srll	7
+	_srll	6
+	_srll	5
+	_srll	4
+	_srll	3
+	_srll	2
+	_srll	1
+#ifdef __MSP430X_LARGE__
+	RETA
+#else
+	RET
+#endif
+
+1:	ADD.W	#-1,R14
+	CLRC
+	RRC.W	R13
+	RRC.W	R12
+	.global	__mspabi_srll
+__mspabi_srll:
+	CMP	#0,R14
+	JNZ	1b
+#ifdef __MSP430X_LARGE__
+	RETA
+#else
+	RET
+#endif
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 201184)
+++ gcc/doc/invoke.texi	(working copy)
@@ -794,12 +794,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
@@ -10936,12 +10939,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::
@@ -15872,13 +15876,13 @@  compatibility with other tools, like @co
 @item -msdram
 @opindex msdram
 Link the SDRAM-based runtime instead of the default ROM-based runtime.
 
 @item -msim
 @opindex msim
-Link the simulator runtime libraries.
+Link the simulator run-time libraries.
 
 @item -msimnovec
 @opindex msimnovec
 Link the simulator runtime libraries, excluding built-in support
 for reset and exception vectors and tables.
 
@@ -17094,12 +17098,52 @@  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.  Normally such
+constants are signed decimals, but this option is available for
+testsuite and/or aesthetic purposes.
+
+@item -mmcu=
+@opindex mmcu=
+Select the MCU to target.  Note that there are two ``generic'' MCUs,
+@code{msp430} and @code{msp430x}, which should be used most of the
+time.  This option is also passed to the assembler.
+
+@item -mlarge
+@opindex mlarge
+Use large-model addressing (20-bit pointers, 32-bit @code{size_t}).
+
+@item -msmall
+@opindex msmall
+Use small-model addressing (16-bit pointers, 16-bit @code{size_t}).
+
+@item -mrelax
+@opindex mrelax
+This option is passed to the assembler and linker, and allows the
+linker to perform certain optimizations that cannot be done until
+the final link.
+
+@end table
+
 @node PDP-11 Options
 @subsection PDP-11 Options
 @cindex PDP-11 Options
 
 These options are defined for the PDP-11:
 
Index: gcc/doc/contrib.texi
===================================================================
--- gcc/doc/contrib.texi	(revision 201184)
+++ gcc/doc/contrib.texi	(working copy)
@@ -173,13 +173,13 @@  Branko Cibej for more warning contributi
 
 @item
 The @uref{http://www.gnu.org/software/classpath/,,GNU Classpath project}
 for all of their merged runtime code.
 
 @item
-Nick Clifton for arm, mcore, fr30, v850, m32r, rx work,
+Nick Clifton for arm, mcore, fr30, v850, m32r, msp430 rx work,
 @option{--help}, and other random hacking.
 
 @item
 Michael Cook for libstdc++ cleanup patches to reduce warnings.
 
 @item
@@ -215,13 +215,13 @@  Bud Davis for work on the G77 and GNU Fo
 
 @item
 Mo DeJong for GCJ and libgcj bug fixes.
 
 @item
 DJ Delorie for the DJGPP port, build and libiberty maintenance,
-various bug fixes, and the M32C, MeP, and RL78 ports.
+various bug fixes, and the M32C, MeP, MSP430, and RL78 ports.
 
 @item
 Arnaud Desitter for helping to debug GNU Fortran.
 
 @item
 Gabriel Dos Reis for contributions to G++, contributions and
Index: gcc/doc/md.texi
===================================================================
--- gcc/doc/md.texi	(revision 201184)
+++ gcc/doc/md.texi	(working copy)
@@ -3060,12 +3060,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 references which do not require an extended MOVX instruction.
+
+@item Yl
+Memory reference, labels only.
+
+@item Ys
+Memory reference, stack only.
+
+@end table
+
 @item PDP-11---@file{config/pdp11/constraints.md}
 @table @code
 @item a
 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 201184)
+++ gcc/doc/install.texi	(working copy)
@@ -3951,12 +3951,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 201184)
+++ gcc/cfgexpand.c	(working copy)
@@ -3151,13 +3151,20 @@  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.  The sign extension code in simplify_unary_operation_1()
+		 asserts extension to a larger bit size.  */
+	      || (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 201184)
+++ gcc/simplify-rtx.c	(working copy)
@@ -5884,12 +5884,23 @@  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)
+      )
+    {
+      debug_rtx (op);
+      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 201184)
+++ 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 201184)
+++ gcc/config.gcc	(working copy)
@@ -2034,12 +2034,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,1287 @@ 
+;;  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.
+;;
+;; 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%D1"
+  )
+
+;; 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)
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  { 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)
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  { 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";
+  })
+
+(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")))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "@
+  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")))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "@
+   ADD.B\t%2, %0
+   ADD%X0.B\t%2, %0"
+)
+
+(define_insn "addqi3_ze"
+  [(set (match_operand:HI          0 "nonimmediate_operand" "=r,r")
+	(zero_extend:HI (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
+				 (match_operand:QI 2 "general_operand"      "riYs,rmi"))))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "@
+   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")))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "@
+   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")))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "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")))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "@
+   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.
+;
+; 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.
+
+(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" "ri,rmi")))
+   (set (reg:CC CARRY)
+   	(compare (plus:SI (match_dup 1) (match_dup 2))
+		 (const_int 0)))
+   ]
+  ""
+  "@
+   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"))
+		 (ltu:HI (reg:CC CARRY) (const_int 0))))
+   (clobber (reg:CC 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")))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  [(parallel [(set (match_operand:HI 3 "nonimmediate_operand" "=&rm")
+		   (plus:HI (match_dup 4)
+			    (match_dup 5)))
+	      (set (reg:CC CARRY)
+		   (compare (plus:SI (match_dup 4) (match_dup 5))
+			    (const_int 0)))]
+
+	      )
+   (parallel [(set (match_operand:HI 6 "nonimmediate_operand" "=&rm")
+		   (plus:HI (plus:HI (match_dup 7)
+				     (match_dup 8))
+			    (ltu:HI (reg:CC CARRY) (const_int 0))))
+	      (clobber (reg:CC 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")))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "@
+  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")))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "@
+  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")))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "@
+  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")))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "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")))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "@
+   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")))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "@
+   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")))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "@
+   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")))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "@
+   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")))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "@
+   SXT%X0\t%0
+   SXT%X0\t%0"
+)
+
+;; Note: QImode moves to registers clear the top byte
+(define_insn "zero_extendqihi2"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=rYs,m,r,r")
+	(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0,0,rYs,m")))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "@
+   AND\t#0xff, %0
+   AND%X0\t#0xff, %0
+   MOV.B\t%1,%0
+   MOV%X0.B\t%1,%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")))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  { 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))
+   (clobber (reg:CC CARRY))
+   ]
+  "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))
+   (clobber (reg:CC CARRY))
+   ]
+  "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)))
+   (clobber (reg:CC CARRY))
+   ]
+  "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)))
+   (clobber (reg:CC CARRY))
+   ]
+  "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")))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "*
+    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")))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  {
+    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)))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "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")))
+   (clobber (reg:CC CARRY))
+   ]
+  "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)))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "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)))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "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")))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "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")))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  {
+    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)))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "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")))
+   (clobber (reg:CC CARRY))
+   ]
+  "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)))
+   (clobber (reg:CC CARRY))
+   ]
+  "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)))
+   (clobber (reg:CC CARRY))
+   ]
+  "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)))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "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)))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "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")))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "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")))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  {
+    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)))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "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")))
+   (clobber (reg:CC CARRY))
+   ]
+  "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)))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "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)))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "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)))
+   (clobber (reg:CC CARRY))
+   ]
+  "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")))
+   (clobber (reg:CC CARRY))
+   ]
+  ""
+  "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:CC 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:CC 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:CC 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:CC 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:CC 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:CC 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:CC 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:CC 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:CC 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:CC 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:CC 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:CC 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:CC 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:CC 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:CC 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,1754 @@ 
+/* 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':
+      /* print a decimal value without a leading '#'.  */
+      if (GET_CODE (op) == CONST_INT)
+	{
+	  int i = INTVAL (op);
+	  fprintf (file, "%d", i);
+	  return;
+	}
+      break;
+    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]

? htdocs/.#index.html.1.882
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	23 Jul 2013 21:17:58 -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.887
diff -p -U 5 -r1.887 index.html
--- htdocs/index.html	31 May 2013 11:41:08 -0000	1.887
+++ htdocs/index.html	23 Jul 2013 21:17:58 -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.8/">GCC 4.8.1</a> released</span>
     <span class="date">[2013-05-31]</span></dt>
     <dd></dd>
 
 <dt><span><a href="gcc-4.6/">GCC 4.6.4</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	23 Jul 2013 21:17:58 -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>