> 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 > >