Message ID | 20200721182953.wh2sprenianogipq@jozef-acer-manjaro |
---|---|
State | New |
Headers | show |
Series | MSP430: Improve code-generation for shift instructions | expand |
Pinging for this patch. Thanks, Jozef On Tue, Jul 21, 2020 at 07:29:53PM +0100, Jozef Lawrynowicz wrote: > The implementation of define_expand and define_insn patterns to handle > shifts in the MSP430 backend is inconsistent, resulting in missed > opportunities to make best use of the architecture's features. > > There's now a single define_expand used as the entry point for all valid > shifts, and the decision to either use a helper function to perform the > shift (often required for the 430 ISA), or fall through to the > define_insn patterns can be made from that expander function. > > Shifts by a constant amount have been grouped into one define_insn for > each type of shift, instead of having different define_insn patterns for > shifts by different amounts. > > A new target option "-mmax-inline-shift=" has been added to allow tuning > of the number of shift instructions to emit inline, instead of using > a library helper function. > > Successfully regtested on trunk for msp430-elf, ok to apply? > From a3c62c448c7f359bad85c86c35f712ca1fccf219 Mon Sep 17 00:00:00 2001 > From: Jozef Lawrynowicz <jozef.l@mittosystems.com> > Date: Wed, 15 Jul 2020 11:43:36 +0100 > Subject: [PATCH 3/3] MSP430: Simplify and extend shift instruction patterns > > The implementation of define_expand and define_insn patterns to handle > shifts in the MSP430 backend is inconsistent, resulting in missed > opportunities to make best use of the architecture's features. > > There's now a single define_expand used as the entry point for all valid > shifts, and the decision to either use a helper function to perform the > shift (often required for the 430 ISA), or fall through to the > define_insn patterns can be made from that expander function. > > Shifts by a constant amount have been grouped into one define_insn for > each type of shift, instead of having different define_insn patterns for > shifts by different amounts. > > A new target option "-mmax-inline-shift=" has been added to allow tuning > of the number of shift instructions to emit inline, instead of using > a library helper function. > > gcc/ChangeLog: > > * config/msp430/constraints.md (K): Change unused constraint to > constraint to a const_int between 1 and 19. > (P): New constraint. > * config/msp430/msp430-protos.h (msp430x_logical_shift_right): Remove. > (msp430_expand_shift): New. > (msp430_output_asm_shift_insns): New. > * config/msp430/msp430.c (msp430_rtx_costs): Remove shift costs. > (CSH): Remove. > (msp430_expand_helper): Remove hard-coded generation of some inline > shift insns. > (use_helper_for_const_shift): New. > (msp430_expand_shift): New. > (msp430_output_asm_shift_insns): New. > (msp430_print_operand): Add new 'W' operand selector. > (msp430x_logical_shift_right): Remove. > * config/msp430/msp430.md (HPSI): New define_mode_iterator. > (HDI): Likewise. > (any_shift): New define_code_iterator. > (shift_insn): New define_code_attr. > Adjust unnamed insn patterns searched for by combine. > (ashlhi3): Remove. > (slli_1): Remove. > (430x_shift_left): Remove. > (slll_1): Remove. > (slll_2): Remove. > (ashlsi3): Remove. > (ashldi3): Remove. > (ashrhi3): Remove. > (srai_1): Remove. > (430x_arithmetic_shift_right): Remove. > (srap_1): Remove. > (srap_2): Remove. > (sral_1): Remove. > (sral_2): Remove. > (ashrsi3): Remove. > (ashrdi3): Remove. > (lshrhi3): Remove. > (srli_1): Remove. > (430x_logical_shift_right): Remove. > (srlp_1): Remove. > (srll_1): Remove. > (srll_2x): Remove. > (lshrsi3): Remove. > (lshrdi3): Remove. > (<shift_insn><mode>3): New define_expand. > (<shift_insn>hi3_430): New define_insn. > (<shift_insn>si3_const): Likewise. > (ashl<mode>3_430x): Likewise. > (ashr<mode>3_430x): Likewise. > (lshr<mode>3_430x): Likewise. > (*bitbranch<mode>4_z): Replace renamed predicate msp430_bitpos with > const_0_to_15_operand. > * config/msp430/msp430.opt: New option -mmax-inline-shift=. > * config/msp430/predicates.md (const_1_to_8_operand): New predicate. > (const_0_to_15_operand): Rename msp430_bitpos predicate. > (const_1_to_19_operand): New predicate. > * doc/invoke.texi: Document -mmax-inline-shift=. > > libgcc/ChangeLog: > > * config/msp430/slli.S (__gnu_mspabi_sllp): New. > * config/msp430/srai.S (__gnu_mspabi_srap): New. > * config/msp430/srli.S (__gnu_mspabi_srlp): New. > > gcc/testsuite/ChangeLog: > > * gcc.target/msp430/emulate-srli.c: Fix expected assembler text. > * gcc.target/msp430/max-inline-shift-430-no-opt.c: New test. > * gcc.target/msp430/max-inline-shift-430.c: New test. > * gcc.target/msp430/max-inline-shift-430x.c: New test. > > --- > gcc/config/msp430/constraints.md | 10 +- > gcc/config/msp430/msp430-protos.h | 6 +- > gcc/config/msp430/msp430.c | 272 +++++++++---- > gcc/config/msp430/msp430.md | 381 +++++------------- > gcc/config/msp430/msp430.opt | 6 + > gcc/config/msp430/predicates.md | 13 +- > gcc/doc/invoke.texi | 15 +- > .../gcc.target/msp430/emulate-srli.c | 2 +- > .../msp430/max-inline-shift-430-no-opt.c | 52 +++ > .../gcc.target/msp430/max-inline-shift-430.c | 50 +++ > .../gcc.target/msp430/max-inline-shift-430x.c | 48 +++ > libgcc/config/msp430/slli.S | 15 + > libgcc/config/msp430/srai.S | 15 + > libgcc/config/msp430/srli.S | 16 + > 14 files changed, 527 insertions(+), 374 deletions(-) > create mode 100644 gcc/testsuite/gcc.target/msp430/max-inline-shift-430-no-opt.c > create mode 100644 gcc/testsuite/gcc.target/msp430/max-inline-shift-430.c > create mode 100644 gcc/testsuite/gcc.target/msp430/max-inline-shift-430x.c > > diff --git a/gcc/config/msp430/constraints.md b/gcc/config/msp430/constraints.md > index 14368f7be6d..b8f9674b2fe 100644 > --- a/gcc/config/msp430/constraints.md > +++ b/gcc/config/msp430/constraints.md > @@ -25,15 +25,16 @@ (define_register_constraint "R13" "R13_REGS" > "Register R13.") > > (define_constraint "K" > - "Integer constant 1." > + "Integer constant 1-19." > (and (match_code "const_int") > - (match_test "IN_RANGE (ival, 1, 1)"))) > + (match_test "IN_RANGE (ival, 1, 19)"))) > > (define_constraint "L" > "Integer constant -1^20..1^19." > (and (match_code "const_int") > (match_test "IN_RANGE (ival, HOST_WIDE_INT_M1U << 20, 1 << 19)"))) > > +;; Valid shift amount for RRUM, RRAM, RLAM, RRCM. > (define_constraint "M" > "Integer constant 1-4." > (and (match_code "const_int") > @@ -49,6 +50,11 @@ (define_constraint "O" > (and (match_code "const_int") > (match_test "IN_RANGE (ival, 256, 65535)"))) > > +(define_constraint "P" > + "Integer constant 1-16." > + (and (match_code "const_int") > + (match_test "IN_RANGE (ival, 1, 16)"))) > + > ;; 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. > diff --git a/gcc/config/msp430/msp430-protos.h b/gcc/config/msp430/msp430-protos.h > index a13a94cb92c..0b4d9a42b41 100644 > --- a/gcc/config/msp430/msp430-protos.h > +++ b/gcc/config/msp430/msp430-protos.h > @@ -35,7 +35,6 @@ 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); > void msp430_output_aligned_decl_common (FILE *, const tree, const char *, > unsigned HOST_WIDE_INT, unsigned, > @@ -51,4 +50,9 @@ bool msp430_use_f5_series_hwmult (void); > bool msp430_has_hwmult (void); > bool msp430_op_not_in_high_mem (rtx op); > > +#ifdef RTX_CODE > +int msp430_expand_shift (enum rtx_code code, machine_mode mode, rtx *operands); > +const char * msp430_output_asm_shift_insns (enum rtx_code code, machine_mode mode, rtx *operands); > +#endif > + > #endif /* GCC_MSP430_PROTOS_H */ > diff --git a/gcc/config/msp430/msp430.c b/gcc/config/msp430/msp430.c > index 455b4af3dad..c2b24974364 100644 > --- a/gcc/config/msp430/msp430.c > +++ b/gcc/config/msp430/msp430.c > @@ -1064,15 +1064,6 @@ static bool msp430_rtx_costs (rtx x ATTRIBUTE_UNUSED, > return true; > } > break; > - case ASHIFT: > - case ASHIFTRT: > - case LSHIFTRT: > - if (!msp430x) > - { > - *total = COSTS_N_INSNS (100); > - return true; > - } > - break; > } > return false; > } > @@ -2674,32 +2665,6 @@ msp430_init_dwarf_reg_sizes_extra (tree address) > } > } > > -/* 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 > @@ -2716,31 +2681,12 @@ msp430_expand_helper (rtx *operands, const char *helper_name, > machine_mode arg0mode = GET_MODE (operands[0]); > machine_mode arg1mode = GET_MODE (operands[1]); > machine_mode arg2mode = GET_MODE (operands[2]); > - int have_430x = msp430x ? 1 : 0; > int expand_mpy = strncmp (helper_name, "__mspabi_mpy", > sizeof ("__mspabi_mpy") - 1) == 0; > /* This function has been used incorrectly if CONST_VARIANTS is TRUE for a > hwmpy function. */ > gcc_assert (!(expand_mpy && const_variants)); > > - /* Emit size-optimal insns for small shifts we can easily do inline. */ > - if (CONST_INT_P (operands[2]) && !expand_mpy) > - { > - 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 && arg2mode != VOIDmode) > /* Modes of arguments must be equal if not constants. */ > gcc_assert (arg1mode == arg2mode); > @@ -2835,6 +2781,190 @@ msp430_expand_helper (rtx *operands, const char *helper_name, > gen_rtx_REG (arg0mode, 12)); > } > > +/* Return TRUE if the helper function should be used and FALSE if the shifts > + insns should be emitted inline. */ > +static bool > +use_helper_for_const_shift (enum rtx_code code, machine_mode mode, > + HOST_WIDE_INT amt) > +{ > + const int default_inline_shift = 4; > + /* We initialize the option to 65 so we know if the user set it or not. */ > + int user_set_max_inline = (msp430_max_inline_shift == 65 ? 0 : 1); > + int max_inline = (user_set_max_inline ? msp430_max_inline_shift > + : default_inline_shift); > + /* 32-bit shifts are roughly twice as costly as 16-bit shifts so we adjust > + the heuristic accordingly. */ > + int max_inline_32 = max_inline / 2; > + > + /* Don't use helpers for these modes on 430X, when optimizing for speed, or > + when emitting a small number of insns. */ > + if ((mode == E_QImode || mode == E_HImode || mode == E_PSImode) > + && (msp430x > + /* If the user set max_inline then we always obey that number. > + Otherwise we always emit the shifts inline at -O2 and above. */ > + || amt <= max_inline > + || (!user_set_max_inline > + && (optimize >= 2 && !optimize_size)))) > + return false; > + > + /* 430 and 430X codegen for SImode shifts is the same. > + Set a hard limit of 15 for the number of shifts that will be emitted > + inline by default, even at -O2 and above, to prevent code size > + explosion. */ > + if (mode == E_SImode > + && (amt <= max_inline_32 > + || (!user_set_max_inline > + && (optimize >= 2 && !optimize_size) > + && amt <= 15))) > + return false; > + > + return true; > +} > + > +/* For shift operations which will use an mspabi helper function, setup the > + call to msp430_expand helper. Return 1 to indicate we have finished with > + this insn and invoke "DONE". > + Otherwise return 0 to indicate the insn should fallthrough. > + Never FAIL. */ > +int > +msp430_expand_shift (enum rtx_code code, machine_mode mode, rtx *operands) > +{ > + /* Always use the helper function when the shift amount is not a > + constant. */ > + if (!CONST_INT_P (operands[2]) > + || mode == E_DImode > + || use_helper_for_const_shift (code, mode, INTVAL (operands[2]))) > + { > + const char *helper_name = NULL; > + /* The const variants of mspabi shifts have significantly larger code > + size than the generic version, so use the generic version if > + optimizing for size. */ > + bool const_variant = !optimize_size; > + switch (mode) > + { > + case E_HImode: > + helper_name = (code == ASHIFT ? "__mspabi_slli" : > + (code == ASHIFTRT ? "__mspabi_srai" : > + (code == LSHIFTRT ? "__mspabi_srli" : > + NULL))); > + break; > + case E_PSImode: > + helper_name = (code == ASHIFT ? "__gnu_mspabi_sllp" : > + (code == ASHIFTRT ? "__gnu_mspabi_srap" : > + (code == LSHIFTRT ? "__gnu_mspabi_srlp" : > + NULL))); > + /* No const variant for PSImode shifts FIXME. */ > + const_variant = false; > + break; > + case E_SImode: > + helper_name = (code == ASHIFT ? "__mspabi_slll" : > + (code == ASHIFTRT ? "__mspabi_sral" : > + (code == LSHIFTRT ? "__mspabi_srll" : > + NULL))); > + break; > + case E_DImode: > + helper_name = (code == ASHIFT ? "__mspabi_sllll" : > + (code == ASHIFTRT ? "__mspabi_srall" : > + (code == LSHIFTRT ? "__mspabi_srlll" : > + NULL))); > + /* No const variant for DImode shifts. */ > + const_variant = false; > + break; > + default: > + gcc_unreachable (); > + break; > + } > + gcc_assert (helper_name); > + msp430_expand_helper (operands, helper_name, const_variant); > + return 1; > + } > + /* When returning 0, there must be an insn to match the RTL pattern > + otherwise there will be an unrecognizeable insn. */ > + return 0; > +} > + > +/* Helper function to emit a sequence of shift instructions. The amount of > + shift instructions to emit is in OPERANDS[2]. > + For 430 we output copies of identical inline shifts for all modes. > + For 430X it is inneficient to do so for any modes except SI and DI, since we > + can make use of R*M insns or RPT with 430X insns, so this function is only > + used for SImode in that case. */ > +const char * > +msp430_output_asm_shift_insns (enum rtx_code code, machine_mode mode, > + rtx *operands) > +{ > + int i; > + int amt; > + int max_shift = GET_MODE_BITSIZE (mode) - 1; > + gcc_assert (CONST_INT_P (operands[2])); > + amt = INTVAL (operands[2]); > + > + if (amt == 0 || amt > max_shift) > + { > + switch (code) > + { > + case ASHIFT: > + output_asm_insn ("# ignored undefined behaviour left shift " > + "of %1 by %2", operands); > + break; > + case ASHIFTRT: > + output_asm_insn ("# ignored undefined behaviour arithmetic right " > + "shift of %1 by %2", operands); > + break; > + case LSHIFTRT: > + output_asm_insn ("# ignored undefined behaviour logical right shift " > + "of %1 by %2", operands); > + break; > + default: > + gcc_unreachable (); > + } > + return ""; > + } > + > + if (code == ASHIFT) > + { > + if (!msp430x && mode == HImode) > + for (i = 0; i < amt; i++) > + output_asm_insn ("RLA.W\t%0", operands); > + else if (mode == SImode) > + for (i = 0; i < amt; i++) > + output_asm_insn ("RLA%X0.W\t%L0 { RLC%X0.W\t%H0", operands); > + else > + /* Catch unhandled cases. */ > + gcc_unreachable (); > + } > + else if (code == ASHIFTRT) > + { > + if (!msp430x && mode == HImode) > + for (i = 0; i < amt; i++) > + output_asm_insn ("RRA.W\t%0", operands); > + else if (mode == SImode) > + for (i = 0; i < amt; i++) > + output_asm_insn ("RRA%X0.W\t%H0 { RRC%X0.W\t%L0", operands); > + else > + gcc_unreachable (); > + } > + else if (code == LSHIFTRT) > + { > + if (!msp430x && mode == HImode) > + for (i = 0; i < amt; i++) > + output_asm_insn ("CLRC { RRC.W\t%0", operands); > + else if (mode == SImode) > + for (i = 0; i < amt; i++) > + output_asm_insn ("CLRC { RRC%X0.W\t%H0 { RRC%X0.W\t%L0", operands); > + /* FIXME: Why doesn't "RRUX.W\t%H0 { RRC%X0.W\t%L0" work for msp430x? > + It causes execution timeouts e.g. pr41963.c. */ > +#if 0 > + else if (msp430x && mode == SImode) > + for (i = 0; i < amt; i++) > + output_asm_insn ("RRUX.W\t%H0 { RRC%X0.W\t%L0", operands); > +#endif > + else > + gcc_unreachable (); > + } > + return ""; > +} > + > /* Called by cbranch<mode>4 to coerce operands into usable forms. */ > void > msp430_fixup_compare_operands (machine_mode my_mode, rtx * operands) > @@ -3368,6 +3498,7 @@ msp430_op_not_in_high_mem (rtx op) > O offset of the top of the stack > Q like X but generates an A postfix > R inverse of condition code, unsigned. > + W value - 16 > X X instruction postfix in large mode > Y value - 4 > Z value - 1 > @@ -3394,6 +3525,11 @@ msp430_print_operand (FILE * file, rtx op, int letter) > /* Print the constant value, less four. */ > fprintf (file, "#%ld", INTVAL (op) - 4); > return; > + case 'W': > + gcc_assert (CONST_INT_P (op)); > + /* Print the constant value, less 16. */ > + fprintf (file, "#%ld", INTVAL (op) - 16); > + return; > case 'I': > if (GET_CODE (op) == CONST_INT) > { > @@ -3711,34 +3847,6 @@ msp430x_extendhisi (rtx * operands) > return "MOV.W\t%1, %L0 { MOV.W\t%1, %H0 { RPT\t#15 { RRAX.W\t%H0"; > } > > -/* 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. */ > -} > - > /* Stop GCC from thinking that it can eliminate (SUBREG:PSI (SI)). */ > > #undef TARGET_CAN_CHANGE_MODE_CLASS > diff --git a/gcc/config/msp430/msp430.md b/gcc/config/msp430/msp430.md > index ed21eb02868..f70e61b97dd 100644 > --- a/gcc/config/msp430/msp430.md > +++ b/gcc/config/msp430/msp430.md > @@ -65,6 +65,15 @@ (define_attr "length" "" (const_int 4)) > (include "constraints.md") > > (define_mode_iterator QHI [QI HI PSI]) > +(define_mode_iterator HPSI [HI PSI]) > +(define_mode_iterator HDI [HI PSI SI DI]) > + > +;; Mapping of all shift operators > +(define_code_iterator any_shift [ashift ashiftrt lshiftrt]) > + > +;; Base name for define_insn > +(define_code_attr shift_insn > + [(ashift "ashl") (lshiftrt "lshr") (ashiftrt "ashr")]) > > ;; There are two basic "family" tests we do here: > ;; > @@ -689,31 +698,42 @@ (define_insn "" > MOV%X1.B\t%1, %0" > ) > > +;; The next three insns emit identical assembly code. > +;; They take a QImode and shift it in SImode. Only shift counts <= 8 > +;; are handled since that is the simple case where the high 16-bits (i.e. the > +;; high register) are always 0. > (define_insn "" > - [(set (match_operand:SI 0 "register_operand" "=r") > - (ashift:SI (zero_extend:SI (match_operand:QI 1 "general_operand" "rm")) > - (match_operand:HI 2 "immediate_operand" "M")))] > + [(set (match_operand:SI 0 "register_operand" "=r,r,r") > + (ashift:SI (zero_extend:SI (match_operand:QI 1 "general_operand" "0,rm,rm")) > + (match_operand:HI 2 "const_1_to_8_operand" "M,M,i")))] > "msp430x" > - "MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0" > + "@ > + RLAM.W %2, %L0 { CLR %H0 > + MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0 > + MOV%X1.B %1, %L0 { RPT %2 { RLAX.W %L0 { CLR %H0" > ) > > -;; We are taking a char and shifting it and putting the result in 2 registers. > -;; the high register will always be for 0 shift counts < 8. > (define_insn "" > - [(set (match_operand:SI 0 "register_operand" "=r") > - (ashift:SI (zero_extend:SI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0)) > - (match_operand:HI 2 "immediate_operand" "M")))] > + [(set (match_operand:SI 0 "register_operand" "=r,r,r") > + (ashift:SI (zero_extend:SI (subreg:HI (match_operand:QI 1 "general_operand" "0,rm,rm") 0)) > + (match_operand:HI 2 "const_1_to_8_operand" "M,M,i")))] > "msp430x" > - "MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0" > + "@ > + RLAM.W %2, %L0 { CLR %H0 > + MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0 > + MOV%X1.B %1, %L0 { RPT %2 { RLAX.W %L0 { CLR %H0" > ) > > ;; Same as above but with a NOP sign_extend round the subreg > (define_insn "" > - [(set (match_operand:SI 0 "register_operand" "=r") > - (ashift:SI (zero_extend:SI (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0))) > - (match_operand:HI 2 "immediate_operand" "M")))] > + [(set (match_operand:SI 0 "register_operand" "=r,r,r") > + (ashift:SI (zero_extend:SI (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "0,rm,rm") 0))) > + (match_operand:HI 2 "const_1_to_8_operand" "M,M,i")))] > "msp430x" > - "MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0" > + "@ > + RLAM.W %2, %L0 { CLR %H0 > + MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0 > + MOV%X1.B %1, %L0 { RPT %2 { RLAX.W %L0 { CLR %H0" > ) > > (define_insn "" > @@ -724,11 +744,14 @@ (define_insn "" > ) > > (define_insn "" > - [(set (match_operand:PSI 0 "register_operand" "=r") > - (ashift:PSI (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0)) > - (match_operand:HI 2 "immediate_operand" "M")))] > + [(set (match_operand:PSI 0 "register_operand" "=r,r,r") > + (ashift:PSI (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "0,rm,rm") 0)) > + (match_operand:HI 2 "const_1_to_19_operand" "M,M,i")))] > "msp430x" > - "MOV%X1.B %1, %0 { RLAM.W %2, %0" > + "@ > + RLAM.W %2, %0 > + MOV%X1.B %1, %0 { RLAM.W %2, %0 > + MOV%X1.B %1, %0 { RPT %2 { RLAX.A %0" > ) > ;; END msp430 pointer manipulation combine insn patterns > > @@ -840,287 +863,75 @@ (define_insn "truncsipsi2" > ;; 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" behavior. [6.5.7 (3)] > +;; > +;; We avoid emitting insns in msp430_expand_shift, since we would have to handle > +;; many extra cases such as op0 != op1, or, op0 or op1 in memory. Instead we > +;; let reload coerce op0 and op1 into the same register. > > -;; signed A << C > - > -(define_expand "ashlhi3" > - [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand") > - (ashift:HI (match_operand:HI 1 "general_operand") > - (match_operand:HI 2 "general_operand")))] > +(define_expand "<shift_insn><mode>3" > + [(set (match_operand:HDI 0 "msp430_general_dst_nonv_operand") > + (any_shift:HDI (match_operand:HDI 1 "general_operand") > + (match_operand:HDI 2 "general_operand")))] > "" > { > - if ((GET_CODE (operands[1]) == SUBREG > - && REG_P (XEXP (operands[1], 0))) > - || MEM_P (operands[1])) > - operands[1] = force_reg (HImode, operands[1]); > - 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 if (CONST_INT_P (operands[2]) > - && INTVAL (operands[2]) == 1) > - emit_insn (gen_slli_1 (operands[0], operands[1])); > - else > - /* The const variants of mspabi shifts have larger code size than the > - generic version, so use the generic version if optimizing for > - size. */ > - msp430_expand_helper (operands, \"__mspabi_slli\", !optimize_size); > - DONE; > + if (msp430_expand_shift (<CODE>, <MODE>mode, operands)) > + DONE; > + /* Otherwise, fallthrough. */ > } > ) > > -(define_insn "slli_1" > - [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand" "=rm") > - (ashift:HI (match_operand:HI 1 "general_operand" "0") > - (const_int 1)))] > - "" > - "RLA%X0.W\t%0" ;; Note - this is a macro for ADD > -) > - > -(define_insn "430x_shift_left" > - [(set (match_operand:HI 0 "register_operand" "=r") > - (ashift:HI (match_operand:HI 1 "register_operand" "0") > - (match_operand 2 "immediate_operand" "n")))] > - "msp430x" > - "* > - if (INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 5) > - return \"RLAM.W\t%2, %0\"; > - else if (INTVAL (operands[2]) >= 5 && INTVAL (operands[2]) < 16) > - return \"RPT\t%2 { RLAX.W\t%0\"; > - return \"# nop left shift\"; > - " > +;; All 430 HImode constant shifts > +(define_insn "<shift_insn>hi3_430" > + [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand" "=rm") > + (any_shift:HI (match_operand:HI 1 "general_operand" "0") > + (match_operand:HI 2 "const_int_operand" "n")))] > + "!msp430x" > + "* return msp430_output_asm_shift_insns (<CODE>, HImode, operands);" > ) > > -(define_insn "slll_1" > - [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") > - (ashift:SI (match_operand:SI 1 "general_operand" "0") > - (const_int 1)))] > +;; All 430 and 430X SImode constant shifts > +(define_insn "<shift_insn>si3_const" > + [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") > + (any_shift:SI (match_operand:SI 1 "general_operand" "0") > + (match_operand:SI 2 "const_int_operand" "n")))] > "" > - "RLA%X0.W\t%L0 { RLC%X0.W\t%H0" > -) > - > -(define_insn "slll_2" > - [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") > - (ashift:SI (match_operand:SI 1 "general_operand" "0") > - (const_int 2)))] > - "" > - "RLA%X0.W\t%L0 { RLC%X0.W\t%H0 { RLA%X0.W\t%L0 { RLC%X0.W\t%H0" > -) > - > -(define_expand "ashlsi3" > - [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand") > - (ashift:SI (match_operand:SI 1 "general_operand") > - (match_operand:SI 2 "general_operand")))] > - "" > - "msp430_expand_helper (operands, \"__mspabi_slll\", !optimize_size); > - DONE;" > -) > - > -(define_expand "ashldi3" > - [(set (match_operand:DI 0 "msp430_general_dst_nonv_operand") > - (ashift:DI (match_operand:DI 1 "general_operand") > - (match_operand:DI 2 "general_operand")))] > - "" > - { > - /* No const_variant for 64-bit shifts. */ > - msp430_expand_helper (operands, \"__mspabi_sllll\", false); > - DONE; > - } > -) > - > -;;---------- > - > -;; signed A >> C > - > -(define_expand "ashrhi3" > - [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand") > - (ashiftrt:HI (match_operand:HI 1 "general_operand") > - (match_operand:HI 2 "general_operand")))] > - "" > - { > - if ((GET_CODE (operands[1]) == SUBREG > - && REG_P (XEXP (operands[1], 0))) > - || MEM_P (operands[1])) > - operands[1] = force_reg (HImode, operands[1]); > - 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 if (CONST_INT_P (operands[2]) > - && INTVAL (operands[2]) == 1) > - emit_insn (gen_srai_1 (operands[0], operands[1])); > - else > - msp430_expand_helper (operands, \"__mspabi_srai\", !optimize_size); > - DONE; > - } > -) > - > -(define_insn "srai_1" > - [(set (match_operand:HI 0 "msp430_general_dst_operand" "=rm") > - (ashiftrt:HI (match_operand:HI 1 "msp430_general_operand" "0") > - (const_int 1)))] > - "" > - "RRA%X0.W\t%0" > -) > - > -(define_insn "430x_arithmetic_shift_right" > - [(set (match_operand:HI 0 "register_operand" "=r") > - (ashiftrt:HI (match_operand:HI 1 "register_operand" "0") > - (match_operand 2 "immediate_operand" "n")))] > - "msp430x" > - "* > - if (INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 5) > - return \"RRAM.W\t%2, %0\"; > - else if (INTVAL (operands[2]) >= 5 && INTVAL (operands[2]) < 16) > - return \"RPT\t%2 { RRAX.W\t%0\"; > - return \"# nop arith right shift\"; > - " > -) > - > -(define_insn "srap_1" > - [(set (match_operand:PSI 0 "register_operand" "=r") > - (ashiftrt:PSI (match_operand:PSI 1 "general_operand" "0") > - (const_int 1)))] > - "msp430x" > - "RRAM.A #1,%0" > + "* return msp430_output_asm_shift_insns (<CODE>, SImode, operands);" > ) > > -(define_insn "srap_2" > - [(set (match_operand:PSI 0 "register_operand" "=r") > - (ashiftrt:PSI (match_operand:PSI 1 "general_operand" "0") > - (const_int 2)))] > +(define_insn "ashl<mode>3_430x" > + [(set (match_operand:HPSI 0 "msp430_general_dst_nonv_operand" "=r,r,r,r") > + (ashift:HPSI (match_operand:HPSI 1 "general_operand" "0 ,0,0,0") > + (match_operand:HPSI 2 "const_int_operand" "M ,P,K,i")))] > "msp430x" > - "RRAM.A #2,%0" > -) > - > -(define_insn "sral_1" > - [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") > - (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") > - (const_int 1)))] > - "" > - "RRA%X0.W\t%H0 { RRC%X0.W\t%L0" > -) > - > -(define_insn "sral_2" > - [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") > - (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") > - (const_int 2)))] > - "" > - "RRA%X0.W\t%H0 { RRC%X0.W\t%L0 { RRA%X0.W\t%H0 { RRC%X0.W\t%L0" > -) > - > -(define_expand "ashrsi3" > - [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand") > - (ashiftrt:SI (match_operand:SI 1 "general_operand") > - (match_operand:SI 2 "general_operand")))] > - "" > - "msp430_expand_helper (operands, \"__mspabi_sral\", !optimize_size); > - DONE;" > -) > - > -(define_expand "ashrdi3" > - [(set (match_operand:DI 0 "msp430_general_dst_nonv_operand") > - (ashift:DI (match_operand:DI 1 "general_operand") > - (match_operand:DI 2 "general_operand")))] > - "" > - { > - /* No const_variant for 64-bit shifts. */ > - msp430_expand_helper (operands, \"__mspabi_srall\", false); > - DONE; > - } > -) > - > -;;---------- > - > -;; unsigned A >> C > - > -(define_expand "lshrhi3" > - [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand") > - (lshiftrt:HI (match_operand:HI 1 "general_operand") > - (match_operand:HI 2 "general_operand")))] > - "" > - { > - if ((GET_CODE (operands[1]) == SUBREG > - && REG_P (XEXP (operands[1], 0))) > - || MEM_P (operands[1])) > - operands[1] = force_reg (HImode, operands[1]); > - 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 if (CONST_INT_P (operands[2]) > - && INTVAL (operands[2]) == 1) > - emit_insn (gen_srli_1 (operands[0], operands[1])); > - else > - msp430_expand_helper (operands, \"__mspabi_srli\", !optimize_size); > - DONE; > - } > -) > - > -(define_insn "srli_1" > - [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand" "=rm") > - (lshiftrt:HI (match_operand:HI 1 "general_operand" "0") > - (const_int 1)))] > - "" > - "CLRC { RRC%X0.W\t%0" > + "@ > + RLAM%b0\t%2, %0 > + RPT\t%2 { RLAX%b0\t%0 > + RPT\t#16 { RLAX%b0\t%0 { RPT\t%W2 { RLAX%b0\t%0 > + # undefined behavior left shift of %1 by %2" > ) > > -(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")))] > +(define_insn "ashr<mode>3_430x" > + [(set (match_operand:HPSI 0 "msp430_general_dst_nonv_operand" "=r,r,r,r") > + (ashiftrt:HPSI (match_operand:HPSI 1 "general_operand" "0,0,0,0") > + (match_operand:HPSI 2 "const_int_operand" "M,P,K,i")))] > "msp430x" > - { > - return msp430x_logical_shift_right (operands[2]); > - } > -) > - > -(define_insn "srlp_1" > - [(set (match_operand:PSI 0 "register_operand" "=r") > - (lshiftrt:PSI (match_operand:PSI 1 "general_operand" "0") > - (const_int 1)))] > - "" > - "RRUM.A #1,%0" > -) > - > -(define_insn "srll_1" > - [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") > - (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") > - (const_int 1)))] > - "" > - "CLRC { RRC%X0.W\t%H0 { RRC%X0.W\t%L0" > + "@ > + RRAM%b0\t%2, %0 > + RPT\t%2 { RRAX%b0\t%0 > + RPT\t#16 { RRAX%b0\t%0 { RPT\t%W2 { RRAX%b0\t%0 > + # undefined behavior arithmetic right shift of %1 by %2" > ) > > -(define_insn "srll_2x" > - [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=r") > - (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") > - (const_int 2)))] > +(define_insn "lshr<mode>3_430x" > + [(set (match_operand:HPSI 0 "msp430_general_dst_nonv_operand" "=r,r,r,r") > + (lshiftrt:HPSI (match_operand:HPSI 1 "general_operand" "0,0,0,0") > + (match_operand:HPSI 2 "const_int_operand" "M,P,K,i")))] > "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 "msp430_general_dst_nonv_operand") > - (lshiftrt:SI (match_operand:SI 1 "general_operand") > - (match_operand:SI 2 "general_operand")))] > - "" > - "msp430_expand_helper (operands, \"__mspabi_srll\", !optimize_size); > - DONE;" > -) > - > -(define_expand "lshrdi3" > - [(set (match_operand:DI 0 "msp430_general_dst_nonv_operand") > - (ashift:DI (match_operand:DI 1 "general_operand") > - (match_operand:DI 2 "general_operand")))] > - "" > - { > - /* No const_variant for 64-bit shifts. */ > - msp430_expand_helper (operands, \"__mspabi_srlll\", false); > - DONE; > - } > + "@ > + RRUM%b0\t%2, %0 > + RPT\t%2 { RRUX%b0\t%0 > + RPT\t#16 { RRUX%b0\t%0 { RPT\t%W2 { RRUX%b0\t%0 > + # undefined behavior logical right shift of %1 by %2" > ) > > ;;------------------------------------------------------------ > @@ -1427,7 +1238,7 @@ (define_insn "*bitbranch<mode>4_z" > [(set (pc) (if_then_else > (ne (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rYs,rm") > (const_int 1) > - (match_operand 1 "msp430_bitpos" "i,i")) > + (match_operand 1 "const_0_to_15_operand" "i,i")) > (const_int 0)) > (label_ref (match_operand 2 "" "")) > (pc))) > @@ -1443,7 +1254,7 @@ (define_insn "*bitbranch<mode>4_z" > [(set (pc) (if_then_else > (eq (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rm") > (const_int 1) > - (match_operand 1 "msp430_bitpos" "i")) > + (match_operand 1 "const_0_to_15_operand" "i")) > (const_int 0)) > (label_ref (match_operand 2 "" "")) > (pc))) > @@ -1457,7 +1268,7 @@ (define_insn "*bitbranch<mode>4_z" > [(set (pc) (if_then_else > (eq (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rm") > (const_int 1) > - (match_operand 1 "msp430_bitpos" "i")) > + (match_operand 1 "const_0_to_15_operand" "i")) > (const_int 0)) > (pc) > (label_ref (match_operand 2 "" "")))) > @@ -1471,7 +1282,7 @@ (define_insn "*bitbranch<mode>4_z" > [(set (pc) (if_then_else > (ne (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rm") > (const_int 1) > - (match_operand 1 "msp430_bitpos" "i")) > + (match_operand 1 "const_0_to_15_operand" "i")) > (const_int 0)) > (pc) > (label_ref (match_operand 2 "" "")))) > diff --git a/gcc/config/msp430/msp430.opt b/gcc/config/msp430/msp430.opt > index b451174c3d1..8134ca7ac95 100644 > --- a/gcc/config/msp430/msp430.opt > +++ b/gcc/config/msp430/msp430.opt > @@ -109,3 +109,9 @@ mdevices-csv-loc= > Target Joined Var(msp430_devices_csv_loc) RejectNegative Report > The path to devices.csv. The GCC driver can normally locate devices.csv itself > and pass this option to the compiler, so the user shouldn't need to pass this. > + > +mmax-inline-shift= > +Target RejectNegative Joined UInteger IntegerRange(0,65) Var(msp430_max_inline_shift) Init(65) Report > +For shift operations by a constant amount, which require an individual instruction to shift by one > +position, set the maximum number of inline shift instructions (maximum value 64) to emit instead of using the corresponding __mspabi helper function. > +The default value is 4. > diff --git a/gcc/config/msp430/predicates.md b/gcc/config/msp430/predicates.md > index 408d56f610a..4bfa0c0f2d5 100644 > --- a/gcc/config/msp430/predicates.md > +++ b/gcc/config/msp430/predicates.md > @@ -113,12 +113,21 @@ (define_predicate "msp430_nonsubregnonpostinc_or_imm_operand" > (ior (match_code "reg,mem") > (match_operand 0 "immediate_operand")))) > > -; TRUE for constants which are bit positions for zero_extract > -(define_predicate "msp430_bitpos" > +(define_predicate "const_1_to_8_operand" > + (and (match_code "const_int") > + (match_test (" INTVAL (op) >= 1 > + && INTVAL (op) <= 8 ")))) > + > +(define_predicate "const_0_to_15_operand" > (and (match_code "const_int") > (match_test (" INTVAL (op) >= 0 > && INTVAL (op) <= 15 ")))) > > +(define_predicate "const_1_to_19_operand" > + (and (match_code "const_int") > + (match_test (" INTVAL (op) >= 1 > + && INTVAL (op) <= 19 ")))) > + > (define_predicate "msp430_symbol_operand" > (match_code "symbol_ref") > ) > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > index 09bcc5b0f78..885c7aae3a5 100644 > --- a/gcc/doc/invoke.texi > +++ b/gcc/doc/invoke.texi > @@ -1066,7 +1066,7 @@ Objective-C and Objective-C++ Dialects}. > -mwarn-mcu @gol > -mcode-region= -mdata-region= @gol > -msilicon-errata= -msilicon-errata-warn= @gol > --mhwmult= -minrt -mtiny-printf} > +-mhwmult= -minrt -mtiny-printf -mmax-inline-shift=} > > @emph{NDS32 Options} > @gccoptlist{-mbig-endian -mlittle-endian @gol > @@ -24728,6 +24728,19 @@ buffered before it is sent to write. > This option requires Newlib Nano IO, so GCC must be configured with > @samp{--enable-newlib-nano-formatted-io}. > > +@item -mmax-inline-shift= > +@opindex mmax-inline-shift= > +This option takes an integer between 0 and 64 inclusive, and sets > +the maximum number of inline shift instructions which should be emitted to > +perform a shift operation by a constant amount. When this value needs to be > +exceeded, an mspabi helper function is used instead. The default value is 4. > + > +This only affects cases where a shift by multiple positions cannot be > +completed with a single instruction (e.g. all shifts >1 on the 430 ISA). > + > +Shifts of a 32-bit value are at least twice as costly, so the value passed for > +this option is divided by 2 and the resulting value used instead. > + > @item -mcode-region= > @itemx -mdata-region= > @opindex mcode-region > diff --git a/gcc/testsuite/gcc.target/msp430/emulate-srli.c b/gcc/testsuite/gcc.target/msp430/emulate-srli.c > index f870d13f86b..35207b7c458 100644 > --- a/gcc/testsuite/gcc.target/msp430/emulate-srli.c > +++ b/gcc/testsuite/gcc.target/msp430/emulate-srli.c > @@ -2,7 +2,7 @@ > /* { dg-skip-if "" { *-*-* } { "-mcpu=msp430" } { "" } } */ > /* { dg-options "-Os" } */ > /* { dg-final { scan-assembler-not "mspabi_srli" } } */ > -/* { dg-final { scan-assembler "rrum" } } */ > +/* { dg-final { scan-assembler "RRUM" } } */ > > /* Ensure that HImode shifts with source operand in memory are emulated with a > rotate instructions. */ > diff --git a/gcc/testsuite/gcc.target/msp430/max-inline-shift-430-no-opt.c b/gcc/testsuite/gcc.target/msp430/max-inline-shift-430-no-opt.c > new file mode 100644 > index 00000000000..c795f7570d7 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/msp430/max-inline-shift-430-no-opt.c > @@ -0,0 +1,52 @@ > +/* { dg-do compile } */ > +/* { dg-skip-if "" { *-*-* } { "-mcpu=msp430x" "-mlarge" } { "" } } */ > +/* { dg-options "-mcpu=msp430" } */ > +/* { dg-final { scan-assembler-not "__mspabi_slli_4" } } */ > +/* { dg-final { scan-assembler-not "__mspabi_sral_2" } } */ > +/* { dg-final { scan-assembler "__mspabi_slli_5" } } */ > +/* { dg-final { scan-assembler "__mspabi_sral_3" } } */ > + > +/* Test the default value of 4 for -mmax-inline-shift has been observed. */ > + > +volatile int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15; > +volatile long l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15; > + > +void > +ashift (void) > +{ > + a1 <<= 1; > + a2 <<= 2; > + a3 <<= 3; > + a4 <<= 4; > + a5 <<= 5; > + a6 <<= 6; > + a7 <<= 7; > + a8 <<= 8; > + a9 <<= 9; > + a10 <<= 10; > + a11 <<= 11; > + a12 <<= 12; > + a13 <<= 13; > + a14 <<= 14; > + a15 <<= 15; > +} > + > +void > +ashiftrt (void) > +{ > + l1 >>= 1; > + l2 >>= 2; > + l3 >>= 3; > + l4 >>= 4; > + l5 >>= 5; > + l6 >>= 6; > + l7 >>= 7; > + l8 >>= 8; > + l9 >>= 9; > + l10 >>= 10; > + l11 >>= 11; > + l12 >>= 12; > + l13 >>= 13; > + l14 >>= 14; > + l15 >>= 15; > +} > diff --git a/gcc/testsuite/gcc.target/msp430/max-inline-shift-430.c b/gcc/testsuite/gcc.target/msp430/max-inline-shift-430.c > new file mode 100644 > index 00000000000..7a519eec663 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/msp430/max-inline-shift-430.c > @@ -0,0 +1,50 @@ > +/* { dg-do compile } */ > +/* { dg-skip-if "" { *-*-* } { "-mcpu=msp430x" "-mlarge" } { "" } } */ > +/* { dg-options "-mcpu=msp430 -mmax-inline-shift=10" } */ > +/* { dg-final { scan-assembler-not "__mspabi_slli_10" } } */ > +/* { dg-final { scan-assembler-not "__mspabi_sral_5" } } */ > +/* { dg-final { scan-assembler "__mspabi_slli_11" } } */ > +/* { dg-final { scan-assembler "__mspabi_sral_6" } } */ > + > +volatile int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15; > +volatile long l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15; > + > +void > +ashift (void) > +{ > + a1 <<= 1; > + a2 <<= 2; > + a3 <<= 3; > + a4 <<= 4; > + a5 <<= 5; > + a6 <<= 6; > + a7 <<= 7; > + a8 <<= 8; > + a9 <<= 9; > + a10 <<= 10; > + a11 <<= 11; > + a12 <<= 12; > + a13 <<= 13; > + a14 <<= 14; > + a15 <<= 15; > +} > + > +void > +ashiftrt (void) > +{ > + l1 >>= 1; > + l2 >>= 2; > + l3 >>= 3; > + l4 >>= 4; > + l5 >>= 5; > + l6 >>= 6; > + l7 >>= 7; > + l8 >>= 8; > + l9 >>= 9; > + l10 >>= 10; > + l11 >>= 11; > + l12 >>= 12; > + l13 >>= 13; > + l14 >>= 14; > + l15 >>= 15; > +} > diff --git a/gcc/testsuite/gcc.target/msp430/max-inline-shift-430x.c b/gcc/testsuite/gcc.target/msp430/max-inline-shift-430x.c > new file mode 100644 > index 00000000000..074b3af5539 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/msp430/max-inline-shift-430x.c > @@ -0,0 +1,48 @@ > +/* { dg-do compile } */ > +/* { dg-skip-if "" { *-*-* } { "-mcpu=msp430" } { "" } } */ > +/* { dg-options "-mcpu=msp430x -mmax-inline-shift=10" } */ > +/* { dg-final { scan-assembler-not "__mspabi_slli" } } */ > +/* { dg-final { scan-assembler "__mspabi_sral_6" } } */ > + > +volatile int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15; > +volatile long l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15; > + > +void > +ashift (void) > +{ > + a1 <<= 1; > + a2 <<= 2; > + a3 <<= 3; > + a4 <<= 4; > + a5 <<= 5; > + a6 <<= 6; > + a7 <<= 7; > + a8 <<= 8; > + a9 <<= 9; > + a10 <<= 10; > + a11 <<= 11; > + a12 <<= 12; > + a13 <<= 13; > + a14 <<= 14; > + a15 <<= 15; > +} > + > +void > +ashiftrt (void) > +{ > + l1 >>= 1; > + l2 >>= 2; > + l3 >>= 3; > + l4 >>= 4; > + l5 >>= 5; > + l6 >>= 6; > + l7 >>= 7; > + l8 >>= 8; > + l9 >>= 9; > + l10 >>= 10; > + l11 >>= 11; > + l12 >>= 12; > + l13 >>= 13; > + l14 >>= 14; > + l15 >>= 15; > +} > diff --git a/libgcc/config/msp430/slli.S b/libgcc/config/msp430/slli.S > index c31e2d5db9b..b22622e0bf5 100644 > --- a/libgcc/config/msp430/slli.S > +++ b/libgcc/config/msp430/slli.S > @@ -65,6 +65,21 @@ __mspabi_slli: > RET > #endif > > +#ifdef __MSP430X__ > + .section .text.__gnu_mspabi_sllp > +1: ADDA #-1,R13 > + ADDA R12,R12 > + .global __gnu_mspabi_sllp > +__gnu_mspabi_sllp: > + CMP #0,R13 > + JNZ 1b > +#ifdef __MSP430X_LARGE__ > + RETA > +#else > + RET > +#endif /* __MSP430X_LARGE__ */ > +#endif /* __MSP430X__ */ > + > /* Logical Left Shift - R12:R13 -> R12:R13. */ > > .section .text.__mspabi_slll_n > diff --git a/libgcc/config/msp430/srai.S b/libgcc/config/msp430/srai.S > index d4a47fa985a..0100a368365 100644 > --- a/libgcc/config/msp430/srai.S > +++ b/libgcc/config/msp430/srai.S > @@ -64,6 +64,21 @@ __mspabi_srai: > RET > #endif > > +#ifdef __MSP430X__ > + .section .text.__gnu_mspabi_srap > +1: ADDA #-1,R13 > + RRAX.A R12,R12 > + .global __gnu_mspabi_srap > +__gnu_mspabi_srap: > + CMP #0,R13 > + JNZ 1b > +#ifdef __MSP430X_LARGE__ > + RETA > +#else > + RET > +#endif /* __MSP430X_LARGE__ */ > +#endif /* __MSP430X__ */ > + > /* Arithmetic Right Shift - R12:R13 -> R12:R13. */ > > .section .text.__mspabi_sral_n > diff --git a/libgcc/config/msp430/srli.S b/libgcc/config/msp430/srli.S > index 838c4bc0617..50db47c9938 100644 > --- a/libgcc/config/msp430/srli.S > +++ b/libgcc/config/msp430/srli.S > @@ -66,6 +66,22 @@ __mspabi_srli: > RET > #endif > > +#ifdef __MSP430X__ > + .section .text.__gnu_mspabi_srlp > +1: ADDA #-1,R13 > + CLRC > + RRCX.A R12,R12 > + .global __gnu_mspabi_srlp > +__gnu_mspabi_srlp: > + CMP #0,R13 > + JNZ 1b > +#ifdef __MSP430X_LARGE__ > + RETA > +#else > + RET > +#endif /* __MSP430X_LARGE__ */ > +#endif /* __MSP430X__ */ > + > /* Logical Right Shift - R12:R13 -> R12:R13. */ > > .section .text.__mspabi_srll_n > -- > 2.27.0
On Tue, 2020-07-21 at 19:29 +0100, Jozef Lawrynowicz wrote: > The implementation of define_expand and define_insn patterns to handle > shifts in the MSP430 backend is inconsistent, resulting in missed > opportunities to make best use of the architecture's features. > > There's now a single define_expand used as the entry point for all valid > shifts, and the decision to either use a helper function to perform the > shift (often required for the 430 ISA), or fall through to the > define_insn patterns can be made from that expander function. > > Shifts by a constant amount have been grouped into one define_insn for > each type of shift, instead of having different define_insn patterns for > shifts by different amounts. > > A new target option "-mmax-inline-shift=" has been added to allow tuning > of the number of shift instructions to emit inline, instead of using > a library helper function. > > Successfully regtested on trunk for msp430-elf, ok to apply? OK jeff
diff --git a/gcc/config/msp430/constraints.md b/gcc/config/msp430/constraints.md index 14368f7be6d..b8f9674b2fe 100644 --- a/gcc/config/msp430/constraints.md +++ b/gcc/config/msp430/constraints.md @@ -25,15 +25,16 @@ (define_register_constraint "R13" "R13_REGS" "Register R13.") (define_constraint "K" - "Integer constant 1." + "Integer constant 1-19." (and (match_code "const_int") - (match_test "IN_RANGE (ival, 1, 1)"))) + (match_test "IN_RANGE (ival, 1, 19)"))) (define_constraint "L" "Integer constant -1^20..1^19." (and (match_code "const_int") (match_test "IN_RANGE (ival, HOST_WIDE_INT_M1U << 20, 1 << 19)"))) +;; Valid shift amount for RRUM, RRAM, RLAM, RRCM. (define_constraint "M" "Integer constant 1-4." (and (match_code "const_int") @@ -49,6 +50,11 @@ (define_constraint "O" (and (match_code "const_int") (match_test "IN_RANGE (ival, 256, 65535)"))) +(define_constraint "P" + "Integer constant 1-16." + (and (match_code "const_int") + (match_test "IN_RANGE (ival, 1, 16)"))) + ;; 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. diff --git a/gcc/config/msp430/msp430-protos.h b/gcc/config/msp430/msp430-protos.h index a13a94cb92c..0b4d9a42b41 100644 --- a/gcc/config/msp430/msp430-protos.h +++ b/gcc/config/msp430/msp430-protos.h @@ -35,7 +35,6 @@ 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); void msp430_output_aligned_decl_common (FILE *, const tree, const char *, unsigned HOST_WIDE_INT, unsigned, @@ -51,4 +50,9 @@ bool msp430_use_f5_series_hwmult (void); bool msp430_has_hwmult (void); bool msp430_op_not_in_high_mem (rtx op); +#ifdef RTX_CODE +int msp430_expand_shift (enum rtx_code code, machine_mode mode, rtx *operands); +const char * msp430_output_asm_shift_insns (enum rtx_code code, machine_mode mode, rtx *operands); +#endif + #endif /* GCC_MSP430_PROTOS_H */ diff --git a/gcc/config/msp430/msp430.c b/gcc/config/msp430/msp430.c index 455b4af3dad..c2b24974364 100644 --- a/gcc/config/msp430/msp430.c +++ b/gcc/config/msp430/msp430.c @@ -1064,15 +1064,6 @@ static bool msp430_rtx_costs (rtx x ATTRIBUTE_UNUSED, return true; } break; - case ASHIFT: - case ASHIFTRT: - case LSHIFTRT: - if (!msp430x) - { - *total = COSTS_N_INSNS (100); - return true; - } - break; } return false; } @@ -2674,32 +2665,6 @@ msp430_init_dwarf_reg_sizes_extra (tree address) } } -/* 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 @@ -2716,31 +2681,12 @@ msp430_expand_helper (rtx *operands, const char *helper_name, machine_mode arg0mode = GET_MODE (operands[0]); machine_mode arg1mode = GET_MODE (operands[1]); machine_mode arg2mode = GET_MODE (operands[2]); - int have_430x = msp430x ? 1 : 0; int expand_mpy = strncmp (helper_name, "__mspabi_mpy", sizeof ("__mspabi_mpy") - 1) == 0; /* This function has been used incorrectly if CONST_VARIANTS is TRUE for a hwmpy function. */ gcc_assert (!(expand_mpy && const_variants)); - /* Emit size-optimal insns for small shifts we can easily do inline. */ - if (CONST_INT_P (operands[2]) && !expand_mpy) - { - 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 && arg2mode != VOIDmode) /* Modes of arguments must be equal if not constants. */ gcc_assert (arg1mode == arg2mode); @@ -2835,6 +2781,190 @@ msp430_expand_helper (rtx *operands, const char *helper_name, gen_rtx_REG (arg0mode, 12)); } +/* Return TRUE if the helper function should be used and FALSE if the shifts + insns should be emitted inline. */ +static bool +use_helper_for_const_shift (enum rtx_code code, machine_mode mode, + HOST_WIDE_INT amt) +{ + const int default_inline_shift = 4; + /* We initialize the option to 65 so we know if the user set it or not. */ + int user_set_max_inline = (msp430_max_inline_shift == 65 ? 0 : 1); + int max_inline = (user_set_max_inline ? msp430_max_inline_shift + : default_inline_shift); + /* 32-bit shifts are roughly twice as costly as 16-bit shifts so we adjust + the heuristic accordingly. */ + int max_inline_32 = max_inline / 2; + + /* Don't use helpers for these modes on 430X, when optimizing for speed, or + when emitting a small number of insns. */ + if ((mode == E_QImode || mode == E_HImode || mode == E_PSImode) + && (msp430x + /* If the user set max_inline then we always obey that number. + Otherwise we always emit the shifts inline at -O2 and above. */ + || amt <= max_inline + || (!user_set_max_inline + && (optimize >= 2 && !optimize_size)))) + return false; + + /* 430 and 430X codegen for SImode shifts is the same. + Set a hard limit of 15 for the number of shifts that will be emitted + inline by default, even at -O2 and above, to prevent code size + explosion. */ + if (mode == E_SImode + && (amt <= max_inline_32 + || (!user_set_max_inline + && (optimize >= 2 && !optimize_size) + && amt <= 15))) + return false; + + return true; +} + +/* For shift operations which will use an mspabi helper function, setup the + call to msp430_expand helper. Return 1 to indicate we have finished with + this insn and invoke "DONE". + Otherwise return 0 to indicate the insn should fallthrough. + Never FAIL. */ +int +msp430_expand_shift (enum rtx_code code, machine_mode mode, rtx *operands) +{ + /* Always use the helper function when the shift amount is not a + constant. */ + if (!CONST_INT_P (operands[2]) + || mode == E_DImode + || use_helper_for_const_shift (code, mode, INTVAL (operands[2]))) + { + const char *helper_name = NULL; + /* The const variants of mspabi shifts have significantly larger code + size than the generic version, so use the generic version if + optimizing for size. */ + bool const_variant = !optimize_size; + switch (mode) + { + case E_HImode: + helper_name = (code == ASHIFT ? "__mspabi_slli" : + (code == ASHIFTRT ? "__mspabi_srai" : + (code == LSHIFTRT ? "__mspabi_srli" : + NULL))); + break; + case E_PSImode: + helper_name = (code == ASHIFT ? "__gnu_mspabi_sllp" : + (code == ASHIFTRT ? "__gnu_mspabi_srap" : + (code == LSHIFTRT ? "__gnu_mspabi_srlp" : + NULL))); + /* No const variant for PSImode shifts FIXME. */ + const_variant = false; + break; + case E_SImode: + helper_name = (code == ASHIFT ? "__mspabi_slll" : + (code == ASHIFTRT ? "__mspabi_sral" : + (code == LSHIFTRT ? "__mspabi_srll" : + NULL))); + break; + case E_DImode: + helper_name = (code == ASHIFT ? "__mspabi_sllll" : + (code == ASHIFTRT ? "__mspabi_srall" : + (code == LSHIFTRT ? "__mspabi_srlll" : + NULL))); + /* No const variant for DImode shifts. */ + const_variant = false; + break; + default: + gcc_unreachable (); + break; + } + gcc_assert (helper_name); + msp430_expand_helper (operands, helper_name, const_variant); + return 1; + } + /* When returning 0, there must be an insn to match the RTL pattern + otherwise there will be an unrecognizeable insn. */ + return 0; +} + +/* Helper function to emit a sequence of shift instructions. The amount of + shift instructions to emit is in OPERANDS[2]. + For 430 we output copies of identical inline shifts for all modes. + For 430X it is inneficient to do so for any modes except SI and DI, since we + can make use of R*M insns or RPT with 430X insns, so this function is only + used for SImode in that case. */ +const char * +msp430_output_asm_shift_insns (enum rtx_code code, machine_mode mode, + rtx *operands) +{ + int i; + int amt; + int max_shift = GET_MODE_BITSIZE (mode) - 1; + gcc_assert (CONST_INT_P (operands[2])); + amt = INTVAL (operands[2]); + + if (amt == 0 || amt > max_shift) + { + switch (code) + { + case ASHIFT: + output_asm_insn ("# ignored undefined behaviour left shift " + "of %1 by %2", operands); + break; + case ASHIFTRT: + output_asm_insn ("# ignored undefined behaviour arithmetic right " + "shift of %1 by %2", operands); + break; + case LSHIFTRT: + output_asm_insn ("# ignored undefined behaviour logical right shift " + "of %1 by %2", operands); + break; + default: + gcc_unreachable (); + } + return ""; + } + + if (code == ASHIFT) + { + if (!msp430x && mode == HImode) + for (i = 0; i < amt; i++) + output_asm_insn ("RLA.W\t%0", operands); + else if (mode == SImode) + for (i = 0; i < amt; i++) + output_asm_insn ("RLA%X0.W\t%L0 { RLC%X0.W\t%H0", operands); + else + /* Catch unhandled cases. */ + gcc_unreachable (); + } + else if (code == ASHIFTRT) + { + if (!msp430x && mode == HImode) + for (i = 0; i < amt; i++) + output_asm_insn ("RRA.W\t%0", operands); + else if (mode == SImode) + for (i = 0; i < amt; i++) + output_asm_insn ("RRA%X0.W\t%H0 { RRC%X0.W\t%L0", operands); + else + gcc_unreachable (); + } + else if (code == LSHIFTRT) + { + if (!msp430x && mode == HImode) + for (i = 0; i < amt; i++) + output_asm_insn ("CLRC { RRC.W\t%0", operands); + else if (mode == SImode) + for (i = 0; i < amt; i++) + output_asm_insn ("CLRC { RRC%X0.W\t%H0 { RRC%X0.W\t%L0", operands); + /* FIXME: Why doesn't "RRUX.W\t%H0 { RRC%X0.W\t%L0" work for msp430x? + It causes execution timeouts e.g. pr41963.c. */ +#if 0 + else if (msp430x && mode == SImode) + for (i = 0; i < amt; i++) + output_asm_insn ("RRUX.W\t%H0 { RRC%X0.W\t%L0", operands); +#endif + else + gcc_unreachable (); + } + return ""; +} + /* Called by cbranch<mode>4 to coerce operands into usable forms. */ void msp430_fixup_compare_operands (machine_mode my_mode, rtx * operands) @@ -3368,6 +3498,7 @@ msp430_op_not_in_high_mem (rtx op) O offset of the top of the stack Q like X but generates an A postfix R inverse of condition code, unsigned. + W value - 16 X X instruction postfix in large mode Y value - 4 Z value - 1 @@ -3394,6 +3525,11 @@ msp430_print_operand (FILE * file, rtx op, int letter) /* Print the constant value, less four. */ fprintf (file, "#%ld", INTVAL (op) - 4); return; + case 'W': + gcc_assert (CONST_INT_P (op)); + /* Print the constant value, less 16. */ + fprintf (file, "#%ld", INTVAL (op) - 16); + return; case 'I': if (GET_CODE (op) == CONST_INT) { @@ -3711,34 +3847,6 @@ msp430x_extendhisi (rtx * operands) return "MOV.W\t%1, %L0 { MOV.W\t%1, %H0 { RPT\t#15 { RRAX.W\t%H0"; } -/* 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. */ -} - /* Stop GCC from thinking that it can eliminate (SUBREG:PSI (SI)). */ #undef TARGET_CAN_CHANGE_MODE_CLASS diff --git a/gcc/config/msp430/msp430.md b/gcc/config/msp430/msp430.md index ed21eb02868..f70e61b97dd 100644 --- a/gcc/config/msp430/msp430.md +++ b/gcc/config/msp430/msp430.md @@ -65,6 +65,15 @@ (define_attr "length" "" (const_int 4)) (include "constraints.md") (define_mode_iterator QHI [QI HI PSI]) +(define_mode_iterator HPSI [HI PSI]) +(define_mode_iterator HDI [HI PSI SI DI]) + +;; Mapping of all shift operators +(define_code_iterator any_shift [ashift ashiftrt lshiftrt]) + +;; Base name for define_insn +(define_code_attr shift_insn + [(ashift "ashl") (lshiftrt "lshr") (ashiftrt "ashr")]) ;; There are two basic "family" tests we do here: ;; @@ -689,31 +698,42 @@ (define_insn "" MOV%X1.B\t%1, %0" ) +;; The next three insns emit identical assembly code. +;; They take a QImode and shift it in SImode. Only shift counts <= 8 +;; are handled since that is the simple case where the high 16-bits (i.e. the +;; high register) are always 0. (define_insn "" - [(set (match_operand:SI 0 "register_operand" "=r") - (ashift:SI (zero_extend:SI (match_operand:QI 1 "general_operand" "rm")) - (match_operand:HI 2 "immediate_operand" "M")))] + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (ashift:SI (zero_extend:SI (match_operand:QI 1 "general_operand" "0,rm,rm")) + (match_operand:HI 2 "const_1_to_8_operand" "M,M,i")))] "msp430x" - "MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0" + "@ + RLAM.W %2, %L0 { CLR %H0 + MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0 + MOV%X1.B %1, %L0 { RPT %2 { RLAX.W %L0 { CLR %H0" ) -;; We are taking a char and shifting it and putting the result in 2 registers. -;; the high register will always be for 0 shift counts < 8. (define_insn "" - [(set (match_operand:SI 0 "register_operand" "=r") - (ashift:SI (zero_extend:SI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0)) - (match_operand:HI 2 "immediate_operand" "M")))] + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (ashift:SI (zero_extend:SI (subreg:HI (match_operand:QI 1 "general_operand" "0,rm,rm") 0)) + (match_operand:HI 2 "const_1_to_8_operand" "M,M,i")))] "msp430x" - "MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0" + "@ + RLAM.W %2, %L0 { CLR %H0 + MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0 + MOV%X1.B %1, %L0 { RPT %2 { RLAX.W %L0 { CLR %H0" ) ;; Same as above but with a NOP sign_extend round the subreg (define_insn "" - [(set (match_operand:SI 0 "register_operand" "=r") - (ashift:SI (zero_extend:SI (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0))) - (match_operand:HI 2 "immediate_operand" "M")))] + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (ashift:SI (zero_extend:SI (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "0,rm,rm") 0))) + (match_operand:HI 2 "const_1_to_8_operand" "M,M,i")))] "msp430x" - "MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0" + "@ + RLAM.W %2, %L0 { CLR %H0 + MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0 + MOV%X1.B %1, %L0 { RPT %2 { RLAX.W %L0 { CLR %H0" ) (define_insn "" @@ -724,11 +744,14 @@ (define_insn "" ) (define_insn "" - [(set (match_operand:PSI 0 "register_operand" "=r") - (ashift:PSI (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0)) - (match_operand:HI 2 "immediate_operand" "M")))] + [(set (match_operand:PSI 0 "register_operand" "=r,r,r") + (ashift:PSI (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "0,rm,rm") 0)) + (match_operand:HI 2 "const_1_to_19_operand" "M,M,i")))] "msp430x" - "MOV%X1.B %1, %0 { RLAM.W %2, %0" + "@ + RLAM.W %2, %0 + MOV%X1.B %1, %0 { RLAM.W %2, %0 + MOV%X1.B %1, %0 { RPT %2 { RLAX.A %0" ) ;; END msp430 pointer manipulation combine insn patterns @@ -840,287 +863,75 @@ (define_insn "truncsipsi2" ;; 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" behavior. [6.5.7 (3)] +;; +;; We avoid emitting insns in msp430_expand_shift, since we would have to handle +;; many extra cases such as op0 != op1, or, op0 or op1 in memory. Instead we +;; let reload coerce op0 and op1 into the same register. -;; signed A << C - -(define_expand "ashlhi3" - [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand") - (ashift:HI (match_operand:HI 1 "general_operand") - (match_operand:HI 2 "general_operand")))] +(define_expand "<shift_insn><mode>3" + [(set (match_operand:HDI 0 "msp430_general_dst_nonv_operand") + (any_shift:HDI (match_operand:HDI 1 "general_operand") + (match_operand:HDI 2 "general_operand")))] "" { - if ((GET_CODE (operands[1]) == SUBREG - && REG_P (XEXP (operands[1], 0))) - || MEM_P (operands[1])) - operands[1] = force_reg (HImode, operands[1]); - 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 if (CONST_INT_P (operands[2]) - && INTVAL (operands[2]) == 1) - emit_insn (gen_slli_1 (operands[0], operands[1])); - else - /* The const variants of mspabi shifts have larger code size than the - generic version, so use the generic version if optimizing for - size. */ - msp430_expand_helper (operands, \"__mspabi_slli\", !optimize_size); - DONE; + if (msp430_expand_shift (<CODE>, <MODE>mode, operands)) + DONE; + /* Otherwise, fallthrough. */ } ) -(define_insn "slli_1" - [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand" "=rm") - (ashift:HI (match_operand:HI 1 "general_operand" "0") - (const_int 1)))] - "" - "RLA%X0.W\t%0" ;; Note - this is a macro for ADD -) - -(define_insn "430x_shift_left" - [(set (match_operand:HI 0 "register_operand" "=r") - (ashift:HI (match_operand:HI 1 "register_operand" "0") - (match_operand 2 "immediate_operand" "n")))] - "msp430x" - "* - if (INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 5) - return \"RLAM.W\t%2, %0\"; - else if (INTVAL (operands[2]) >= 5 && INTVAL (operands[2]) < 16) - return \"RPT\t%2 { RLAX.W\t%0\"; - return \"# nop left shift\"; - " +;; All 430 HImode constant shifts +(define_insn "<shift_insn>hi3_430" + [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand" "=rm") + (any_shift:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "const_int_operand" "n")))] + "!msp430x" + "* return msp430_output_asm_shift_insns (<CODE>, HImode, operands);" ) -(define_insn "slll_1" - [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") - (ashift:SI (match_operand:SI 1 "general_operand" "0") - (const_int 1)))] +;; All 430 and 430X SImode constant shifts +(define_insn "<shift_insn>si3_const" + [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") + (any_shift:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "const_int_operand" "n")))] "" - "RLA%X0.W\t%L0 { RLC%X0.W\t%H0" -) - -(define_insn "slll_2" - [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") - (ashift:SI (match_operand:SI 1 "general_operand" "0") - (const_int 2)))] - "" - "RLA%X0.W\t%L0 { RLC%X0.W\t%H0 { RLA%X0.W\t%L0 { RLC%X0.W\t%H0" -) - -(define_expand "ashlsi3" - [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand") - (ashift:SI (match_operand:SI 1 "general_operand") - (match_operand:SI 2 "general_operand")))] - "" - "msp430_expand_helper (operands, \"__mspabi_slll\", !optimize_size); - DONE;" -) - -(define_expand "ashldi3" - [(set (match_operand:DI 0 "msp430_general_dst_nonv_operand") - (ashift:DI (match_operand:DI 1 "general_operand") - (match_operand:DI 2 "general_operand")))] - "" - { - /* No const_variant for 64-bit shifts. */ - msp430_expand_helper (operands, \"__mspabi_sllll\", false); - DONE; - } -) - -;;---------- - -;; signed A >> C - -(define_expand "ashrhi3" - [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand") - (ashiftrt:HI (match_operand:HI 1 "general_operand") - (match_operand:HI 2 "general_operand")))] - "" - { - if ((GET_CODE (operands[1]) == SUBREG - && REG_P (XEXP (operands[1], 0))) - || MEM_P (operands[1])) - operands[1] = force_reg (HImode, operands[1]); - 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 if (CONST_INT_P (operands[2]) - && INTVAL (operands[2]) == 1) - emit_insn (gen_srai_1 (operands[0], operands[1])); - else - msp430_expand_helper (operands, \"__mspabi_srai\", !optimize_size); - DONE; - } -) - -(define_insn "srai_1" - [(set (match_operand:HI 0 "msp430_general_dst_operand" "=rm") - (ashiftrt:HI (match_operand:HI 1 "msp430_general_operand" "0") - (const_int 1)))] - "" - "RRA%X0.W\t%0" -) - -(define_insn "430x_arithmetic_shift_right" - [(set (match_operand:HI 0 "register_operand" "=r") - (ashiftrt:HI (match_operand:HI 1 "register_operand" "0") - (match_operand 2 "immediate_operand" "n")))] - "msp430x" - "* - if (INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 5) - return \"RRAM.W\t%2, %0\"; - else if (INTVAL (operands[2]) >= 5 && INTVAL (operands[2]) < 16) - return \"RPT\t%2 { RRAX.W\t%0\"; - return \"# nop arith right shift\"; - " -) - -(define_insn "srap_1" - [(set (match_operand:PSI 0 "register_operand" "=r") - (ashiftrt:PSI (match_operand:PSI 1 "general_operand" "0") - (const_int 1)))] - "msp430x" - "RRAM.A #1,%0" + "* return msp430_output_asm_shift_insns (<CODE>, SImode, operands);" ) -(define_insn "srap_2" - [(set (match_operand:PSI 0 "register_operand" "=r") - (ashiftrt:PSI (match_operand:PSI 1 "general_operand" "0") - (const_int 2)))] +(define_insn "ashl<mode>3_430x" + [(set (match_operand:HPSI 0 "msp430_general_dst_nonv_operand" "=r,r,r,r") + (ashift:HPSI (match_operand:HPSI 1 "general_operand" "0 ,0,0,0") + (match_operand:HPSI 2 "const_int_operand" "M ,P,K,i")))] "msp430x" - "RRAM.A #2,%0" -) - -(define_insn "sral_1" - [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") - (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") - (const_int 1)))] - "" - "RRA%X0.W\t%H0 { RRC%X0.W\t%L0" -) - -(define_insn "sral_2" - [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") - (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") - (const_int 2)))] - "" - "RRA%X0.W\t%H0 { RRC%X0.W\t%L0 { RRA%X0.W\t%H0 { RRC%X0.W\t%L0" -) - -(define_expand "ashrsi3" - [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand") - (ashiftrt:SI (match_operand:SI 1 "general_operand") - (match_operand:SI 2 "general_operand")))] - "" - "msp430_expand_helper (operands, \"__mspabi_sral\", !optimize_size); - DONE;" -) - -(define_expand "ashrdi3" - [(set (match_operand:DI 0 "msp430_general_dst_nonv_operand") - (ashift:DI (match_operand:DI 1 "general_operand") - (match_operand:DI 2 "general_operand")))] - "" - { - /* No const_variant for 64-bit shifts. */ - msp430_expand_helper (operands, \"__mspabi_srall\", false); - DONE; - } -) - -;;---------- - -;; unsigned A >> C - -(define_expand "lshrhi3" - [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand") - (lshiftrt:HI (match_operand:HI 1 "general_operand") - (match_operand:HI 2 "general_operand")))] - "" - { - if ((GET_CODE (operands[1]) == SUBREG - && REG_P (XEXP (operands[1], 0))) - || MEM_P (operands[1])) - operands[1] = force_reg (HImode, operands[1]); - 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 if (CONST_INT_P (operands[2]) - && INTVAL (operands[2]) == 1) - emit_insn (gen_srli_1 (operands[0], operands[1])); - else - msp430_expand_helper (operands, \"__mspabi_srli\", !optimize_size); - DONE; - } -) - -(define_insn "srli_1" - [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand" "=rm") - (lshiftrt:HI (match_operand:HI 1 "general_operand" "0") - (const_int 1)))] - "" - "CLRC { RRC%X0.W\t%0" + "@ + RLAM%b0\t%2, %0 + RPT\t%2 { RLAX%b0\t%0 + RPT\t#16 { RLAX%b0\t%0 { RPT\t%W2 { RLAX%b0\t%0 + # undefined behavior left shift of %1 by %2" ) -(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")))] +(define_insn "ashr<mode>3_430x" + [(set (match_operand:HPSI 0 "msp430_general_dst_nonv_operand" "=r,r,r,r") + (ashiftrt:HPSI (match_operand:HPSI 1 "general_operand" "0,0,0,0") + (match_operand:HPSI 2 "const_int_operand" "M,P,K,i")))] "msp430x" - { - return msp430x_logical_shift_right (operands[2]); - } -) - -(define_insn "srlp_1" - [(set (match_operand:PSI 0 "register_operand" "=r") - (lshiftrt:PSI (match_operand:PSI 1 "general_operand" "0") - (const_int 1)))] - "" - "RRUM.A #1,%0" -) - -(define_insn "srll_1" - [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") - (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") - (const_int 1)))] - "" - "CLRC { RRC%X0.W\t%H0 { RRC%X0.W\t%L0" + "@ + RRAM%b0\t%2, %0 + RPT\t%2 { RRAX%b0\t%0 + RPT\t#16 { RRAX%b0\t%0 { RPT\t%W2 { RRAX%b0\t%0 + # undefined behavior arithmetic right shift of %1 by %2" ) -(define_insn "srll_2x" - [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=r") - (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") - (const_int 2)))] +(define_insn "lshr<mode>3_430x" + [(set (match_operand:HPSI 0 "msp430_general_dst_nonv_operand" "=r,r,r,r") + (lshiftrt:HPSI (match_operand:HPSI 1 "general_operand" "0,0,0,0") + (match_operand:HPSI 2 "const_int_operand" "M,P,K,i")))] "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 "msp430_general_dst_nonv_operand") - (lshiftrt:SI (match_operand:SI 1 "general_operand") - (match_operand:SI 2 "general_operand")))] - "" - "msp430_expand_helper (operands, \"__mspabi_srll\", !optimize_size); - DONE;" -) - -(define_expand "lshrdi3" - [(set (match_operand:DI 0 "msp430_general_dst_nonv_operand") - (ashift:DI (match_operand:DI 1 "general_operand") - (match_operand:DI 2 "general_operand")))] - "" - { - /* No const_variant for 64-bit shifts. */ - msp430_expand_helper (operands, \"__mspabi_srlll\", false); - DONE; - } + "@ + RRUM%b0\t%2, %0 + RPT\t%2 { RRUX%b0\t%0 + RPT\t#16 { RRUX%b0\t%0 { RPT\t%W2 { RRUX%b0\t%0 + # undefined behavior logical right shift of %1 by %2" ) ;;------------------------------------------------------------ @@ -1427,7 +1238,7 @@ (define_insn "*bitbranch<mode>4_z" [(set (pc) (if_then_else (ne (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rYs,rm") (const_int 1) - (match_operand 1 "msp430_bitpos" "i,i")) + (match_operand 1 "const_0_to_15_operand" "i,i")) (const_int 0)) (label_ref (match_operand 2 "" "")) (pc))) @@ -1443,7 +1254,7 @@ (define_insn "*bitbranch<mode>4_z" [(set (pc) (if_then_else (eq (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rm") (const_int 1) - (match_operand 1 "msp430_bitpos" "i")) + (match_operand 1 "const_0_to_15_operand" "i")) (const_int 0)) (label_ref (match_operand 2 "" "")) (pc))) @@ -1457,7 +1268,7 @@ (define_insn "*bitbranch<mode>4_z" [(set (pc) (if_then_else (eq (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rm") (const_int 1) - (match_operand 1 "msp430_bitpos" "i")) + (match_operand 1 "const_0_to_15_operand" "i")) (const_int 0)) (pc) (label_ref (match_operand 2 "" "")))) @@ -1471,7 +1282,7 @@ (define_insn "*bitbranch<mode>4_z" [(set (pc) (if_then_else (ne (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rm") (const_int 1) - (match_operand 1 "msp430_bitpos" "i")) + (match_operand 1 "const_0_to_15_operand" "i")) (const_int 0)) (pc) (label_ref (match_operand 2 "" "")))) diff --git a/gcc/config/msp430/msp430.opt b/gcc/config/msp430/msp430.opt index b451174c3d1..8134ca7ac95 100644 --- a/gcc/config/msp430/msp430.opt +++ b/gcc/config/msp430/msp430.opt @@ -109,3 +109,9 @@ mdevices-csv-loc= Target Joined Var(msp430_devices_csv_loc) RejectNegative Report The path to devices.csv. The GCC driver can normally locate devices.csv itself and pass this option to the compiler, so the user shouldn't need to pass this. + +mmax-inline-shift= +Target RejectNegative Joined UInteger IntegerRange(0,65) Var(msp430_max_inline_shift) Init(65) Report +For shift operations by a constant amount, which require an individual instruction to shift by one +position, set the maximum number of inline shift instructions (maximum value 64) to emit instead of using the corresponding __mspabi helper function. +The default value is 4. diff --git a/gcc/config/msp430/predicates.md b/gcc/config/msp430/predicates.md index 408d56f610a..4bfa0c0f2d5 100644 --- a/gcc/config/msp430/predicates.md +++ b/gcc/config/msp430/predicates.md @@ -113,12 +113,21 @@ (define_predicate "msp430_nonsubregnonpostinc_or_imm_operand" (ior (match_code "reg,mem") (match_operand 0 "immediate_operand")))) -; TRUE for constants which are bit positions for zero_extract -(define_predicate "msp430_bitpos" +(define_predicate "const_1_to_8_operand" + (and (match_code "const_int") + (match_test (" INTVAL (op) >= 1 + && INTVAL (op) <= 8 ")))) + +(define_predicate "const_0_to_15_operand" (and (match_code "const_int") (match_test (" INTVAL (op) >= 0 && INTVAL (op) <= 15 ")))) +(define_predicate "const_1_to_19_operand" + (and (match_code "const_int") + (match_test (" INTVAL (op) >= 1 + && INTVAL (op) <= 19 ")))) + (define_predicate "msp430_symbol_operand" (match_code "symbol_ref") ) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 09bcc5b0f78..885c7aae3a5 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -1066,7 +1066,7 @@ Objective-C and Objective-C++ Dialects}. -mwarn-mcu @gol -mcode-region= -mdata-region= @gol -msilicon-errata= -msilicon-errata-warn= @gol --mhwmult= -minrt -mtiny-printf} +-mhwmult= -minrt -mtiny-printf -mmax-inline-shift=} @emph{NDS32 Options} @gccoptlist{-mbig-endian -mlittle-endian @gol @@ -24728,6 +24728,19 @@ buffered before it is sent to write. This option requires Newlib Nano IO, so GCC must be configured with @samp{--enable-newlib-nano-formatted-io}. +@item -mmax-inline-shift= +@opindex mmax-inline-shift= +This option takes an integer between 0 and 64 inclusive, and sets +the maximum number of inline shift instructions which should be emitted to +perform a shift operation by a constant amount. When this value needs to be +exceeded, an mspabi helper function is used instead. The default value is 4. + +This only affects cases where a shift by multiple positions cannot be +completed with a single instruction (e.g. all shifts >1 on the 430 ISA). + +Shifts of a 32-bit value are at least twice as costly, so the value passed for +this option is divided by 2 and the resulting value used instead. + @item -mcode-region= @itemx -mdata-region= @opindex mcode-region diff --git a/gcc/testsuite/gcc.target/msp430/emulate-srli.c b/gcc/testsuite/gcc.target/msp430/emulate-srli.c index f870d13f86b..35207b7c458 100644 --- a/gcc/testsuite/gcc.target/msp430/emulate-srli.c +++ b/gcc/testsuite/gcc.target/msp430/emulate-srli.c @@ -2,7 +2,7 @@ /* { dg-skip-if "" { *-*-* } { "-mcpu=msp430" } { "" } } */ /* { dg-options "-Os" } */ /* { dg-final { scan-assembler-not "mspabi_srli" } } */ -/* { dg-final { scan-assembler "rrum" } } */ +/* { dg-final { scan-assembler "RRUM" } } */ /* Ensure that HImode shifts with source operand in memory are emulated with a rotate instructions. */ diff --git a/gcc/testsuite/gcc.target/msp430/max-inline-shift-430-no-opt.c b/gcc/testsuite/gcc.target/msp430/max-inline-shift-430-no-opt.c new file mode 100644 index 00000000000..c795f7570d7 --- /dev/null +++ b/gcc/testsuite/gcc.target/msp430/max-inline-shift-430-no-opt.c @@ -0,0 +1,52 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-mcpu=msp430x" "-mlarge" } { "" } } */ +/* { dg-options "-mcpu=msp430" } */ +/* { dg-final { scan-assembler-not "__mspabi_slli_4" } } */ +/* { dg-final { scan-assembler-not "__mspabi_sral_2" } } */ +/* { dg-final { scan-assembler "__mspabi_slli_5" } } */ +/* { dg-final { scan-assembler "__mspabi_sral_3" } } */ + +/* Test the default value of 4 for -mmax-inline-shift has been observed. */ + +volatile int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15; +volatile long l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15; + +void +ashift (void) +{ + a1 <<= 1; + a2 <<= 2; + a3 <<= 3; + a4 <<= 4; + a5 <<= 5; + a6 <<= 6; + a7 <<= 7; + a8 <<= 8; + a9 <<= 9; + a10 <<= 10; + a11 <<= 11; + a12 <<= 12; + a13 <<= 13; + a14 <<= 14; + a15 <<= 15; +} + +void +ashiftrt (void) +{ + l1 >>= 1; + l2 >>= 2; + l3 >>= 3; + l4 >>= 4; + l5 >>= 5; + l6 >>= 6; + l7 >>= 7; + l8 >>= 8; + l9 >>= 9; + l10 >>= 10; + l11 >>= 11; + l12 >>= 12; + l13 >>= 13; + l14 >>= 14; + l15 >>= 15; +} diff --git a/gcc/testsuite/gcc.target/msp430/max-inline-shift-430.c b/gcc/testsuite/gcc.target/msp430/max-inline-shift-430.c new file mode 100644 index 00000000000..7a519eec663 --- /dev/null +++ b/gcc/testsuite/gcc.target/msp430/max-inline-shift-430.c @@ -0,0 +1,50 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-mcpu=msp430x" "-mlarge" } { "" } } */ +/* { dg-options "-mcpu=msp430 -mmax-inline-shift=10" } */ +/* { dg-final { scan-assembler-not "__mspabi_slli_10" } } */ +/* { dg-final { scan-assembler-not "__mspabi_sral_5" } } */ +/* { dg-final { scan-assembler "__mspabi_slli_11" } } */ +/* { dg-final { scan-assembler "__mspabi_sral_6" } } */ + +volatile int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15; +volatile long l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15; + +void +ashift (void) +{ + a1 <<= 1; + a2 <<= 2; + a3 <<= 3; + a4 <<= 4; + a5 <<= 5; + a6 <<= 6; + a7 <<= 7; + a8 <<= 8; + a9 <<= 9; + a10 <<= 10; + a11 <<= 11; + a12 <<= 12; + a13 <<= 13; + a14 <<= 14; + a15 <<= 15; +} + +void +ashiftrt (void) +{ + l1 >>= 1; + l2 >>= 2; + l3 >>= 3; + l4 >>= 4; + l5 >>= 5; + l6 >>= 6; + l7 >>= 7; + l8 >>= 8; + l9 >>= 9; + l10 >>= 10; + l11 >>= 11; + l12 >>= 12; + l13 >>= 13; + l14 >>= 14; + l15 >>= 15; +} diff --git a/gcc/testsuite/gcc.target/msp430/max-inline-shift-430x.c b/gcc/testsuite/gcc.target/msp430/max-inline-shift-430x.c new file mode 100644 index 00000000000..074b3af5539 --- /dev/null +++ b/gcc/testsuite/gcc.target/msp430/max-inline-shift-430x.c @@ -0,0 +1,48 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-mcpu=msp430" } { "" } } */ +/* { dg-options "-mcpu=msp430x -mmax-inline-shift=10" } */ +/* { dg-final { scan-assembler-not "__mspabi_slli" } } */ +/* { dg-final { scan-assembler "__mspabi_sral_6" } } */ + +volatile int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15; +volatile long l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15; + +void +ashift (void) +{ + a1 <<= 1; + a2 <<= 2; + a3 <<= 3; + a4 <<= 4; + a5 <<= 5; + a6 <<= 6; + a7 <<= 7; + a8 <<= 8; + a9 <<= 9; + a10 <<= 10; + a11 <<= 11; + a12 <<= 12; + a13 <<= 13; + a14 <<= 14; + a15 <<= 15; +} + +void +ashiftrt (void) +{ + l1 >>= 1; + l2 >>= 2; + l3 >>= 3; + l4 >>= 4; + l5 >>= 5; + l6 >>= 6; + l7 >>= 7; + l8 >>= 8; + l9 >>= 9; + l10 >>= 10; + l11 >>= 11; + l12 >>= 12; + l13 >>= 13; + l14 >>= 14; + l15 >>= 15; +} diff --git a/libgcc/config/msp430/slli.S b/libgcc/config/msp430/slli.S index c31e2d5db9b..b22622e0bf5 100644 --- a/libgcc/config/msp430/slli.S +++ b/libgcc/config/msp430/slli.S @@ -65,6 +65,21 @@ __mspabi_slli: RET #endif +#ifdef __MSP430X__ + .section .text.__gnu_mspabi_sllp +1: ADDA #-1,R13 + ADDA R12,R12 + .global __gnu_mspabi_sllp +__gnu_mspabi_sllp: + CMP #0,R13 + JNZ 1b +#ifdef __MSP430X_LARGE__ + RETA +#else + RET +#endif /* __MSP430X_LARGE__ */ +#endif /* __MSP430X__ */ + /* Logical Left Shift - R12:R13 -> R12:R13. */ .section .text.__mspabi_slll_n diff --git a/libgcc/config/msp430/srai.S b/libgcc/config/msp430/srai.S index d4a47fa985a..0100a368365 100644 --- a/libgcc/config/msp430/srai.S +++ b/libgcc/config/msp430/srai.S @@ -64,6 +64,21 @@ __mspabi_srai: RET #endif +#ifdef __MSP430X__ + .section .text.__gnu_mspabi_srap +1: ADDA #-1,R13 + RRAX.A R12,R12 + .global __gnu_mspabi_srap +__gnu_mspabi_srap: + CMP #0,R13 + JNZ 1b +#ifdef __MSP430X_LARGE__ + RETA +#else + RET +#endif /* __MSP430X_LARGE__ */ +#endif /* __MSP430X__ */ + /* Arithmetic Right Shift - R12:R13 -> R12:R13. */ .section .text.__mspabi_sral_n diff --git a/libgcc/config/msp430/srli.S b/libgcc/config/msp430/srli.S index 838c4bc0617..50db47c9938 100644 --- a/libgcc/config/msp430/srli.S +++ b/libgcc/config/msp430/srli.S @@ -66,6 +66,22 @@ __mspabi_srli: RET #endif +#ifdef __MSP430X__ + .section .text.__gnu_mspabi_srlp +1: ADDA #-1,R13 + CLRC + RRCX.A R12,R12 + .global __gnu_mspabi_srlp +__gnu_mspabi_srlp: + CMP #0,R13 + JNZ 1b +#ifdef __MSP430X_LARGE__ + RETA +#else + RET +#endif /* __MSP430X_LARGE__ */ +#endif /* __MSP430X__ */ + /* Logical Right Shift - R12:R13 -> R12:R13. */ .section .text.__mspabi_srll_n
The implementation of define_expand and define_insn patterns to handle shifts in the MSP430 backend is inconsistent, resulting in missed opportunities to make best use of the architecture's features. There's now a single define_expand used as the entry point for all valid shifts, and the decision to either use a helper function to perform the shift (often required for the 430 ISA), or fall through to the define_insn patterns can be made from that expander function. Shifts by a constant amount have been grouped into one define_insn for each type of shift, instead of having different define_insn patterns for shifts by different amounts. A new target option "-mmax-inline-shift=" has been added to allow tuning of the number of shift instructions to emit inline, instead of using a library helper function. Successfully regtested on trunk for msp430-elf, ok to apply? From a3c62c448c7f359bad85c86c35f712ca1fccf219 Mon Sep 17 00:00:00 2001 From: Jozef Lawrynowicz <jozef.l@mittosystems.com> Date: Wed, 15 Jul 2020 11:43:36 +0100 Subject: [PATCH 3/3] MSP430: Simplify and extend shift instruction patterns The implementation of define_expand and define_insn patterns to handle shifts in the MSP430 backend is inconsistent, resulting in missed opportunities to make best use of the architecture's features. There's now a single define_expand used as the entry point for all valid shifts, and the decision to either use a helper function to perform the shift (often required for the 430 ISA), or fall through to the define_insn patterns can be made from that expander function. Shifts by a constant amount have been grouped into one define_insn for each type of shift, instead of having different define_insn patterns for shifts by different amounts. A new target option "-mmax-inline-shift=" has been added to allow tuning of the number of shift instructions to emit inline, instead of using a library helper function. gcc/ChangeLog: * config/msp430/constraints.md (K): Change unused constraint to constraint to a const_int between 1 and 19. (P): New constraint. * config/msp430/msp430-protos.h (msp430x_logical_shift_right): Remove. (msp430_expand_shift): New. (msp430_output_asm_shift_insns): New. * config/msp430/msp430.c (msp430_rtx_costs): Remove shift costs. (CSH): Remove. (msp430_expand_helper): Remove hard-coded generation of some inline shift insns. (use_helper_for_const_shift): New. (msp430_expand_shift): New. (msp430_output_asm_shift_insns): New. (msp430_print_operand): Add new 'W' operand selector. (msp430x_logical_shift_right): Remove. * config/msp430/msp430.md (HPSI): New define_mode_iterator. (HDI): Likewise. (any_shift): New define_code_iterator. (shift_insn): New define_code_attr. Adjust unnamed insn patterns searched for by combine. (ashlhi3): Remove. (slli_1): Remove. (430x_shift_left): Remove. (slll_1): Remove. (slll_2): Remove. (ashlsi3): Remove. (ashldi3): Remove. (ashrhi3): Remove. (srai_1): Remove. (430x_arithmetic_shift_right): Remove. (srap_1): Remove. (srap_2): Remove. (sral_1): Remove. (sral_2): Remove. (ashrsi3): Remove. (ashrdi3): Remove. (lshrhi3): Remove. (srli_1): Remove. (430x_logical_shift_right): Remove. (srlp_1): Remove. (srll_1): Remove. (srll_2x): Remove. (lshrsi3): Remove. (lshrdi3): Remove. (<shift_insn><mode>3): New define_expand. (<shift_insn>hi3_430): New define_insn. (<shift_insn>si3_const): Likewise. (ashl<mode>3_430x): Likewise. (ashr<mode>3_430x): Likewise. (lshr<mode>3_430x): Likewise. (*bitbranch<mode>4_z): Replace renamed predicate msp430_bitpos with const_0_to_15_operand. * config/msp430/msp430.opt: New option -mmax-inline-shift=. * config/msp430/predicates.md (const_1_to_8_operand): New predicate. (const_0_to_15_operand): Rename msp430_bitpos predicate. (const_1_to_19_operand): New predicate. * doc/invoke.texi: Document -mmax-inline-shift=. libgcc/ChangeLog: * config/msp430/slli.S (__gnu_mspabi_sllp): New. * config/msp430/srai.S (__gnu_mspabi_srap): New. * config/msp430/srli.S (__gnu_mspabi_srlp): New. gcc/testsuite/ChangeLog: * gcc.target/msp430/emulate-srli.c: Fix expected assembler text. * gcc.target/msp430/max-inline-shift-430-no-opt.c: New test. * gcc.target/msp430/max-inline-shift-430.c: New test. * gcc.target/msp430/max-inline-shift-430x.c: New test. --- gcc/config/msp430/constraints.md | 10 +- gcc/config/msp430/msp430-protos.h | 6 +- gcc/config/msp430/msp430.c | 272 +++++++++---- gcc/config/msp430/msp430.md | 381 +++++------------- gcc/config/msp430/msp430.opt | 6 + gcc/config/msp430/predicates.md | 13 +- gcc/doc/invoke.texi | 15 +- .../gcc.target/msp430/emulate-srli.c | 2 +- .../msp430/max-inline-shift-430-no-opt.c | 52 +++ .../gcc.target/msp430/max-inline-shift-430.c | 50 +++ .../gcc.target/msp430/max-inline-shift-430x.c | 48 +++ libgcc/config/msp430/slli.S | 15 + libgcc/config/msp430/srai.S | 15 + libgcc/config/msp430/srli.S | 16 + 14 files changed, 527 insertions(+), 374 deletions(-) create mode 100644 gcc/testsuite/gcc.target/msp430/max-inline-shift-430-no-opt.c create mode 100644 gcc/testsuite/gcc.target/msp430/max-inline-shift-430.c create mode 100644 gcc/testsuite/gcc.target/msp430/max-inline-shift-430x.c