__intN patch 5/5: msp430-specific changes
diff mbox

Message ID 201408132211.s7DMBqaQ016409@greed.delorie.com
State New
Headers show

Commit Message

DJ Delorie Aug. 13, 2014, 10:11 p.m. UTC
This is the MSP430-specific use of the new intN framework to enable
true 20-bit pointers.  Since I'm one of the MSP430 maintainers, this
patch is being posted for reference, not for approval.

gcc/config/msp430
	* config/msp430/msp430-modes.def (PSI): Add.

	* config/msp430/msp430-protos.h (msp430_hard_regno_nregs_has_padding): New.
	(msp430_hard_regno_nregs_with_padding): New.
	* config/msp430/msp430.c (msp430_scalar_mode_supported_p): New.
	(msp430_hard_regno_nregs_has_padding): New.
	(msp430_hard_regno_nregs_with_padding): New.
	(msp430_unwind_word_mode): Use PSImode instead of SImode.
	(msp430_addr_space_legitimate_address_p): New.
	(msp430_asm_integer): New.
	(msp430_init_dwarf_reg_sizes_extra): New.
	(msp430_print_operand): Use X suffix for PSImode even in small model.
	* config/msp430/msp430.h (POINTER_SIZE): Use 20 bits, not 32.
	(PTR_SIZE): ...but 4 bytes for EH.
	(SIZE_TYPE): Use __int20.
	(PTRDIFF_TYPE): Likewise.
	(INCOMING_FRAME_SP_OFFSET): Adjust.
	* config/msp430/msp430.md (movqi_topbyte): New.
	(movpsi): Use fixed suffixes.
	(movsipsi2): Enable for 430X, not large model.
	(extendhipsi2): Likewise.
	(zero_extendhisi2): Likewise.
	(zero_extendhisipsi2): Likewise.
	(extend_and_shift1_hipsi2): Likewise.
	(extendpsisi2): Likewise.
	(*bitbranch<mode>4_z): Fix suffix logic.

Comments

DJ Delorie Oct. 14, 2014, 9:35 p.m. UTC | #1
> This is the MSP430-specific use of the new intN framework to enable
> true 20-bit pointers.  Since I'm one of the MSP430 maintainers, this
> patch is being posted for reference, not for approval.

Now that the other parts are committed, I'm checking this one in too.

> gcc/config/msp430
> 	* config/msp430/msp430-modes.def (PSI): Add.
> 
> 	* config/msp430/msp430-protos.h (msp430_hard_regno_nregs_has_padding): New.
> 	(msp430_hard_regno_nregs_with_padding): New.
> 	* config/msp430/msp430.c (msp430_scalar_mode_supported_p): New.
> 	(msp430_hard_regno_nregs_has_padding): New.
> 	(msp430_hard_regno_nregs_with_padding): New.
> 	(msp430_unwind_word_mode): Use PSImode instead of SImode.
> 	(msp430_addr_space_legitimate_address_p): New.
> 	(msp430_asm_integer): New.
> 	(msp430_init_dwarf_reg_sizes_extra): New.
> 	(msp430_print_operand): Use X suffix for PSImode even in small model.
> 	* config/msp430/msp430.h (POINTER_SIZE): Use 20 bits, not 32.
> 	(PTR_SIZE): ...but 4 bytes for EH.
> 	(SIZE_TYPE): Use __int20.
> 	(PTRDIFF_TYPE): Likewise.
> 	(INCOMING_FRAME_SP_OFFSET): Adjust.
> 	* config/msp430/msp430.md (movqi_topbyte): New.
> 	(movpsi): Use fixed suffixes.
> 	(movsipsi2): Enable for 430X, not large model.
> 	(extendhipsi2): Likewise.
> 	(zero_extendhisi2): Likewise.
> 	(zero_extendhisipsi2): Likewise.
> 	(extend_and_shift1_hipsi2): Likewise.
> 	(extendpsisi2): Likewise.
> 	(*bitbranch<mode>4_z): Fix suffix logic.
> 
> 
> Index: gcc/config/msp430/msp430-protos.h
> ===================================================================
> --- gcc/config/msp430/msp430-protos.h	(revision 213886)
> +++ gcc/config/msp430/msp430-protos.h	(working copy)
> @@ -27,12 +27,15 @@ 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);
> +int	msp430_hard_regno_nregs_has_padding (int, enum machine_mode);
> +int	msp430_hard_regno_nregs_with_padding (int, enum machine_mode);
> +bool    msp430_hwmult_enabled (void);
>  rtx	msp430_incoming_return_addr_rtx (void);
>  void	msp430_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int);
>  int	msp430_initial_elimination_offset (int, int);
>  bool    msp430_is_interrupt_func (void);
>  const char * msp430x_logical_shift_right (rtx);
>  const char * msp430_mcu_name (void);
> Index: gcc/config/msp430/msp430.md
> ===================================================================
> --- gcc/config/msp430/msp430.md	(revision 213886)
> +++ gcc/config/msp430/msp430.md	(working copy)
> @@ -176,12 +176,19 @@
>    ""
>    "@
>     MOV.B\t%1, %0
>     MOV%X1.B\t%1, %0"
>  )
>  
> +(define_insn "movqi_topbyte"
> +  [(set (match_operand:QI 0 "msp_nonimmediate_operand" "=r")
> +	(subreg:QI (match_operand:PSI 1 "msp_general_operand" "r") 2))]
> +  "msp430x"
> +  "PUSHM.A\t#1,%1 { POPM.W\t#1,%0 { POPM.W\t#1,%0"
> +)
> +
>  (define_insn "movqi"
>    [(set (match_operand:QI 0 "msp_nonimmediate_operand" "=rYs,rm")
>  	(match_operand:QI 1 "msp_general_operand" "riYs,rmi"))]
>    ""
>    "@
>    MOV.B\t%1, %0
> @@ -220,27 +227,27 @@
>  ;; Some MOVX.A cases can be done with MOVA, this is only a few of them.
>  (define_insn "movpsi"
>    [(set (match_operand:PSI 0 "msp_nonimmediate_operand" "=r,Ya,rm")
>  	(match_operand:PSI 1 "msp_general_operand" "riYa,r,rmi"))]
>    ""
>    "@
> -  MOV%Q0\t%1, %0
> -  MOV%Q0\t%1, %0
> -  MOV%X0.%Q0\t%1, %0")
> +  MOVA\t%1, %0
> +  MOVA\t%1, %0
> +  MOVX.A\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"
> +  "msp430x"
>    "PUSH.W\t%H1 { PUSH.W\t%L1 { POPM.A #1, %0 ; Move reg-pair %L1:%H1 into pointer %0"
>  )
>  
>  ;;------------------------------------------------------------
>  ;; Math
>  
> @@ -564,49 +571,49 @@
>    { return msp430x_extendhisi (operands); }
>  )
>  
>  (define_insn "extendhipsi2"
>    [(set (match_operand:PSI 0 "nonimmediate_operand" "=r")
>  	(subreg:PSI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0")) 0))]
> -  "TARGET_LARGE"
> +  "msp430x"
>    "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"
> +  "msp430x"
>    "MOV.W\t#0,%H0"
>  )
>  
>  (define_insn "zero_extendhisipsi2"
>    [(set (match_operand:PSI 0 "nonimmediate_operand" "=r,r")
>  	(subreg:PSI (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0,r")) 0))]
> -  "TARGET_LARGE"
> +  "msp430x"
>    "@
>     AND.W\t#-1,%0
>     MOV.W\t%1,%0"
>  )
>  
>  (define_insn "extend_and_shift1_hipsi2"
>    [(set (subreg:SI (match_operand:PSI 0 "nonimmediate_operand" "=r") 0)
>  	(ashift:SI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0"))
>  		   (const_int 1)))]
> -  "TARGET_LARGE"
> +  "msp430x"
>    "RLAM #4, %0 { RRAM #3, %0"
>  )
>  
>  (define_insn "extend_and_shift2_hipsi2"
>    [(set (subreg:SI (match_operand:PSI 0 "nonimmediate_operand" "=r") 0)
>  	(ashift:SI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0"))
>  		   (const_int 2)))]
> -  "TARGET_LARGE"
> +  "msp430x"
>    "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
> @@ -645,13 +652,13 @@
>  ;; Since (we assume) pushing a 20-bit value onto the stack zero-extends
>  ;; it, we use a different method here.
>  
>  (define_insn "extendpsisi2"
>    [(set (match_operand:SI                  0 "register_operand" "=r")
>  	(sign_extend:SI (match_operand:PSI 1 "register_operand" "r")))]
> -  "TARGET_LARGE"
> +  "msp430x"
>    "*
>      /* The intention here is that we copy the bottom 16-bits of
>         %1 into %L0 (zeroing the top four bits).  Then we copy the
>         entire 20-bits of %1 into %H0 and then arithmetically shift
>         it right by 16 bits, to get the top four bits of the pointer
>         sign-extended in %H0.  */
> @@ -1174,13 +1181,13 @@
>  		  (const_int 0))
>                (label_ref (match_operand 2 "" ""))
>  	      (pc)))
>     (clobber (reg:BI CARRY))
>     ]
>    ""
> -  "BIT%x0%X0%b0\t%1, %0 { JEQ\t%l2"
> +  "BIT%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"))
> Index: gcc/config/msp430/msp430.c
> ===================================================================
> --- gcc/config/msp430/msp430.c	(revision 213886)
> +++ gcc/config/msp430/msp430.c	(working copy)
> @@ -225,12 +225,27 @@ msp430_option_override (void)
>       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;
>  }
>  
> +#undef  TARGET_SCALAR_MODE_SUPPORTED_P
> +#define TARGET_SCALAR_MODE_SUPPORTED_P msp430_scalar_mode_supported_p
> +
> +static bool
> +msp430_scalar_mode_supported_p (enum machine_mode m)
> +{
> +  if (m == PSImode && msp430x)
> +    return true;
> +#if 0
> +  if (m == TImode)
> +    return true;
> +#endif
> +  return default_scalar_mode_supported_p (m);
> +}
> +
>  
>  
>  /* Storage Layout */
>  
>  #undef  TARGET_MS_BITFIELD_LAYOUT_P
>  #define TARGET_MS_BITFIELD_LAYOUT_P msp430_ms_bitfield_layout_p
> @@ -254,12 +269,33 @@ msp430_hard_regno_nregs (int regno ATTRI
>    if (mode == PSImode && msp430x)
>      return 1;
>    return ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
>  	  / UNITS_PER_WORD);
>  }
>  
> +/* Implements HARD_REGNO_NREGS_HAS_PADDING.  */
> +int
> +msp430_hard_regno_nregs_has_padding (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_NREGS_WITH_PADDING.  */
> +int
> +msp430_hard_regno_nregs_with_padding (int regno ATTRIBUTE_UNUSED,
> +				     enum machine_mode mode)
> +{
> +  if (mode == PSImode)
> +    return 2;
> +  return msp430_hard_regno_nregs (regno, mode);
> +}
> +
>  /* 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));
> @@ -367,13 +403,13 @@ msp430_addr_space_pointer_mode (addr_spa
>  #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;
> +  return TARGET_LARGE ? PSImode : 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
> @@ -882,12 +918,58 @@ msp430_legitimate_address_p (enum machin
>  
>      default:
>        return false;
>      }
>  }
>  
> +#undef  TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P
> +#define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P msp430_addr_space_legitimate_address_p
> +
> +bool
> +msp430_addr_space_legitimate_address_p (enum machine_mode mode,
> +					rtx x,
> +					bool strict,
> +					addr_space_t as ATTRIBUTE_UNUSED)
> +{
> +  return msp430_legitimate_address_p (mode, x, strict);
> +}
> +
> +#undef  TARGET_ASM_INTEGER
> +#define TARGET_ASM_INTEGER msp430_asm_integer
> +static bool
> +msp430_asm_integer (rtx x, unsigned int size, int aligned_p)
> +{
> +  int c = GET_CODE (x);
> +
> +  if (size == 3 && GET_MODE (x) == PSImode)
> +    size = 4;
> +
> +  switch (size)
> +    {
> +    case 4:
> +      if (c == SYMBOL_REF || c == CONST || c == LABEL_REF || c == CONST_INT)
> +	{
> +	  fprintf (asm_out_file, "\t.long\t");
> +	  output_addr_const (asm_out_file, x);
> +	  fputc ('\n', asm_out_file);
> +	  return true;
> +	}
> +      break;
> +    }
> +  return default_assemble_integer (x, size, aligned_p);
> +}
> +
> +#undef  TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA
> +#define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA msp430_asm_output_addr_const_extra
> +static bool
> +msp430_asm_output_addr_const_extra (FILE *file, rtx x)
> +{
> +  debug_rtx(x);
> +  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)
>  {
> @@ -1740,12 +1822,39 @@ msp430_expand_eh_return (rtx eh_handler)
>    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);
>  }
>  
> +#undef  TARGET_INIT_DWARF_REG_SIZES_EXTRA
> +#define TARGET_INIT_DWARF_REG_SIZES_EXTRA msp430_init_dwarf_reg_sizes_extra
> +void
> +msp430_init_dwarf_reg_sizes_extra (tree address)
> +{
> +  int i;
> +  rtx addr = expand_normal (address);
> +  rtx mem = gen_rtx_MEM (BLKmode, addr);
> +
> +  if (!msp430x)
> +    return;
> +
> +  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
> +    {
> +      unsigned int dnum = DWARF_FRAME_REGNUM (i);
> +      unsigned int rnum = DWARF2_FRAME_REG_OUT (dnum, 1);
> +
> +      if (rnum < DWARF_FRAME_REGISTERS)
> +	{
> +	  HOST_WIDE_INT offset = rnum * GET_MODE_SIZE (QImode);
> +
> +	  emit_move_insn (adjust_address (mem, QImode, offset),
> +			  gen_int_mode (4, QImode));
> +	}
> +    }
> +}
> +
>  /* This is a list of MD patterns that implement fixed-count shifts.  */
>  static struct
>  {
>    const char *name;
>    int count;
>    int need_430x;
> @@ -2350,13 +2459,13 @@ msp430_print_operand (FILE * file, rtx o
>  	}
>        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)
> +      if (TARGET_LARGE || GET_MODE (op) == PSImode)
>  	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':
> Index: gcc/config/msp430/msp430.h
> ===================================================================
> --- gcc/config/msp430/msp430.h	(revision 213886)
> +++ gcc/config/msp430/msp430.h	(working copy)
> @@ -128,16 +128,15 @@ extern bool msp430x;
>  #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 POINTER_SIZE			(TARGET_LARGE ? 20 : 16)
> +/* This is just for .eh_frame, to match bfd.  */
> +#define PTR_SIZE			(TARGET_LARGE ? 4 : 2)
>  #define	POINTERS_EXTEND_UNSIGNED	1
>  
>  #define ADDR_SPACE_NEAR	1
>  #define ADDR_SPACE_FAR	2
>  
>  #define REGISTER_TARGET_PRAGMAS() msp430_register_pragmas()
> @@ -155,15 +154,15 @@ extern bool msp430x;
>      (MODE) = HImode;
>  #endif
>  
>  /* Layout of Source Language Data Types */
>  
>  #undef  SIZE_TYPE
> -#define SIZE_TYPE			(TARGET_LARGE ? "long unsigned int" : "unsigned int")
> +#define SIZE_TYPE			(TARGET_LARGE ? "__int20 unsigned" : "unsigned int")
>  #undef  PTRDIFF_TYPE
> -#define PTRDIFF_TYPE			(TARGET_LARGE ? "long int" : "int")
> +#define PTRDIFF_TYPE			(TARGET_LARGE ? "__int20" : "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
> @@ -379,13 +378,13 @@ typedef struct
>  
>  #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)
> +#define INCOMING_FRAME_SP_OFFSET		(TARGET_LARGE ? 4 : 2)
>  
>  #undef  PREFERRED_DEBUGGING_TYPE
>  #define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
>  
>  #define DWARF2_ASM_LINE_DEBUG_INFO		1
>  
>

Patch
diff mbox

Index: gcc/config/msp430/msp430-protos.h
===================================================================
--- gcc/config/msp430/msp430-protos.h	(revision 213886)
+++ gcc/config/msp430/msp430-protos.h	(working copy)
@@ -27,12 +27,15 @@  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);
+int	msp430_hard_regno_nregs_has_padding (int, enum machine_mode);
+int	msp430_hard_regno_nregs_with_padding (int, enum machine_mode);
+bool    msp430_hwmult_enabled (void);
 rtx	msp430_incoming_return_addr_rtx (void);
 void	msp430_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int);
 int	msp430_initial_elimination_offset (int, int);
 bool    msp430_is_interrupt_func (void);
 const char * msp430x_logical_shift_right (rtx);
 const char * msp430_mcu_name (void);
Index: gcc/config/msp430/msp430.md
===================================================================
--- gcc/config/msp430/msp430.md	(revision 213886)
+++ gcc/config/msp430/msp430.md	(working copy)
@@ -176,12 +176,19 @@ 
   ""
   "@
    MOV.B\t%1, %0
    MOV%X1.B\t%1, %0"
 )
 
+(define_insn "movqi_topbyte"
+  [(set (match_operand:QI 0 "msp_nonimmediate_operand" "=r")
+	(subreg:QI (match_operand:PSI 1 "msp_general_operand" "r") 2))]
+  "msp430x"
+  "PUSHM.A\t#1,%1 { POPM.W\t#1,%0 { POPM.W\t#1,%0"
+)
+
 (define_insn "movqi"
   [(set (match_operand:QI 0 "msp_nonimmediate_operand" "=rYs,rm")
 	(match_operand:QI 1 "msp_general_operand" "riYs,rmi"))]
   ""
   "@
   MOV.B\t%1, %0
@@ -220,27 +227,27 @@ 
 ;; Some MOVX.A cases can be done with MOVA, this is only a few of them.
 (define_insn "movpsi"
   [(set (match_operand:PSI 0 "msp_nonimmediate_operand" "=r,Ya,rm")
 	(match_operand:PSI 1 "msp_general_operand" "riYa,r,rmi"))]
   ""
   "@
-  MOV%Q0\t%1, %0
-  MOV%Q0\t%1, %0
-  MOV%X0.%Q0\t%1, %0")
+  MOVA\t%1, %0
+  MOVA\t%1, %0
+  MOVX.A\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"
+  "msp430x"
   "PUSH.W\t%H1 { PUSH.W\t%L1 { POPM.A #1, %0 ; Move reg-pair %L1:%H1 into pointer %0"
 )
 
 ;;------------------------------------------------------------
 ;; Math
 
@@ -564,49 +571,49 @@ 
   { return msp430x_extendhisi (operands); }
 )
 
 (define_insn "extendhipsi2"
   [(set (match_operand:PSI 0 "nonimmediate_operand" "=r")
 	(subreg:PSI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0")) 0))]
-  "TARGET_LARGE"
+  "msp430x"
   "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"
+  "msp430x"
   "MOV.W\t#0,%H0"
 )
 
 (define_insn "zero_extendhisipsi2"
   [(set (match_operand:PSI 0 "nonimmediate_operand" "=r,r")
 	(subreg:PSI (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0,r")) 0))]
-  "TARGET_LARGE"
+  "msp430x"
   "@
    AND.W\t#-1,%0
    MOV.W\t%1,%0"
 )
 
 (define_insn "extend_and_shift1_hipsi2"
   [(set (subreg:SI (match_operand:PSI 0 "nonimmediate_operand" "=r") 0)
 	(ashift:SI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0"))
 		   (const_int 1)))]
-  "TARGET_LARGE"
+  "msp430x"
   "RLAM #4, %0 { RRAM #3, %0"
 )
 
 (define_insn "extend_and_shift2_hipsi2"
   [(set (subreg:SI (match_operand:PSI 0 "nonimmediate_operand" "=r") 0)
 	(ashift:SI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0"))
 		   (const_int 2)))]
-  "TARGET_LARGE"
+  "msp430x"
   "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
@@ -645,13 +652,13 @@ 
 ;; Since (we assume) pushing a 20-bit value onto the stack zero-extends
 ;; it, we use a different method here.
 
 (define_insn "extendpsisi2"
   [(set (match_operand:SI                  0 "register_operand" "=r")
 	(sign_extend:SI (match_operand:PSI 1 "register_operand" "r")))]
-  "TARGET_LARGE"
+  "msp430x"
   "*
     /* The intention here is that we copy the bottom 16-bits of
        %1 into %L0 (zeroing the top four bits).  Then we copy the
        entire 20-bits of %1 into %H0 and then arithmetically shift
        it right by 16 bits, to get the top four bits of the pointer
        sign-extended in %H0.  */
@@ -1174,13 +1181,13 @@ 
 		  (const_int 0))
               (label_ref (match_operand 2 "" ""))
 	      (pc)))
    (clobber (reg:BI CARRY))
    ]
   ""
-  "BIT%x0%X0%b0\t%1, %0 { JEQ\t%l2"
+  "BIT%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"))
Index: gcc/config/msp430/msp430.c
===================================================================
--- gcc/config/msp430/msp430.c	(revision 213886)
+++ gcc/config/msp430/msp430.c	(working copy)
@@ -225,12 +225,27 @@  msp430_option_override (void)
      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;
 }
 
+#undef  TARGET_SCALAR_MODE_SUPPORTED_P
+#define TARGET_SCALAR_MODE_SUPPORTED_P msp430_scalar_mode_supported_p
+
+static bool
+msp430_scalar_mode_supported_p (enum machine_mode m)
+{
+  if (m == PSImode && msp430x)
+    return true;
+#if 0
+  if (m == TImode)
+    return true;
+#endif
+  return default_scalar_mode_supported_p (m);
+}
+
 
 
 /* Storage Layout */
 
 #undef  TARGET_MS_BITFIELD_LAYOUT_P
 #define TARGET_MS_BITFIELD_LAYOUT_P msp430_ms_bitfield_layout_p
@@ -254,12 +269,33 @@  msp430_hard_regno_nregs (int regno ATTRI
   if (mode == PSImode && msp430x)
     return 1;
   return ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
 	  / UNITS_PER_WORD);
 }
 
+/* Implements HARD_REGNO_NREGS_HAS_PADDING.  */
+int
+msp430_hard_regno_nregs_has_padding (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_NREGS_WITH_PADDING.  */
+int
+msp430_hard_regno_nregs_with_padding (int regno ATTRIBUTE_UNUSED,
+				     enum machine_mode mode)
+{
+  if (mode == PSImode)
+    return 2;
+  return msp430_hard_regno_nregs (regno, mode);
+}
+
 /* 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));
@@ -367,13 +403,13 @@  msp430_addr_space_pointer_mode (addr_spa
 #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;
+  return TARGET_LARGE ? PSImode : 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
@@ -882,12 +918,58 @@  msp430_legitimate_address_p (enum machin
 
     default:
       return false;
     }
 }
 
+#undef  TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P
+#define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P msp430_addr_space_legitimate_address_p
+
+bool
+msp430_addr_space_legitimate_address_p (enum machine_mode mode,
+					rtx x,
+					bool strict,
+					addr_space_t as ATTRIBUTE_UNUSED)
+{
+  return msp430_legitimate_address_p (mode, x, strict);
+}
+
+#undef  TARGET_ASM_INTEGER
+#define TARGET_ASM_INTEGER msp430_asm_integer
+static bool
+msp430_asm_integer (rtx x, unsigned int size, int aligned_p)
+{
+  int c = GET_CODE (x);
+
+  if (size == 3 && GET_MODE (x) == PSImode)
+    size = 4;
+
+  switch (size)
+    {
+    case 4:
+      if (c == SYMBOL_REF || c == CONST || c == LABEL_REF || c == CONST_INT)
+	{
+	  fprintf (asm_out_file, "\t.long\t");
+	  output_addr_const (asm_out_file, x);
+	  fputc ('\n', asm_out_file);
+	  return true;
+	}
+      break;
+    }
+  return default_assemble_integer (x, size, aligned_p);
+}
+
+#undef  TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA
+#define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA msp430_asm_output_addr_const_extra
+static bool
+msp430_asm_output_addr_const_extra (FILE *file, rtx x)
+{
+  debug_rtx(x);
+  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)
 {
@@ -1740,12 +1822,39 @@  msp430_expand_eh_return (rtx eh_handler)
   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);
 }
 
+#undef  TARGET_INIT_DWARF_REG_SIZES_EXTRA
+#define TARGET_INIT_DWARF_REG_SIZES_EXTRA msp430_init_dwarf_reg_sizes_extra
+void
+msp430_init_dwarf_reg_sizes_extra (tree address)
+{
+  int i;
+  rtx addr = expand_normal (address);
+  rtx mem = gen_rtx_MEM (BLKmode, addr);
+
+  if (!msp430x)
+    return;
+
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    {
+      unsigned int dnum = DWARF_FRAME_REGNUM (i);
+      unsigned int rnum = DWARF2_FRAME_REG_OUT (dnum, 1);
+
+      if (rnum < DWARF_FRAME_REGISTERS)
+	{
+	  HOST_WIDE_INT offset = rnum * GET_MODE_SIZE (QImode);
+
+	  emit_move_insn (adjust_address (mem, QImode, offset),
+			  gen_int_mode (4, QImode));
+	}
+    }
+}
+
 /* This is a list of MD patterns that implement fixed-count shifts.  */
 static struct
 {
   const char *name;
   int count;
   int need_430x;
@@ -2350,13 +2459,13 @@  msp430_print_operand (FILE * file, rtx o
 	}
       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)
+      if (TARGET_LARGE || GET_MODE (op) == PSImode)
 	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':
Index: gcc/config/msp430/msp430.h
===================================================================
--- gcc/config/msp430/msp430.h	(revision 213886)
+++ gcc/config/msp430/msp430.h	(working copy)
@@ -128,16 +128,15 @@  extern bool msp430x;
 #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 POINTER_SIZE			(TARGET_LARGE ? 20 : 16)
+/* This is just for .eh_frame, to match bfd.  */
+#define PTR_SIZE			(TARGET_LARGE ? 4 : 2)
 #define	POINTERS_EXTEND_UNSIGNED	1
 
 #define ADDR_SPACE_NEAR	1
 #define ADDR_SPACE_FAR	2
 
 #define REGISTER_TARGET_PRAGMAS() msp430_register_pragmas()
@@ -155,15 +154,15 @@  extern bool msp430x;
     (MODE) = HImode;
 #endif
 
 /* Layout of Source Language Data Types */
 
 #undef  SIZE_TYPE
-#define SIZE_TYPE			(TARGET_LARGE ? "long unsigned int" : "unsigned int")
+#define SIZE_TYPE			(TARGET_LARGE ? "__int20 unsigned" : "unsigned int")
 #undef  PTRDIFF_TYPE
-#define PTRDIFF_TYPE			(TARGET_LARGE ? "long int" : "int")
+#define PTRDIFF_TYPE			(TARGET_LARGE ? "__int20" : "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
@@ -379,13 +378,13 @@  typedef struct
 
 #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)
+#define INCOMING_FRAME_SP_OFFSET		(TARGET_LARGE ? 4 : 2)
 
 #undef  PREFERRED_DEBUGGING_TYPE
 #define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
 
 #define DWARF2_ASM_LINE_DEBUG_INFO		1