From: Jozef Lawrynowicz <jozef.l@mittosystems.com>
To: gcc-patches@gcc.gnu.org
Subject: ping [PATCH 3/3] MSP430: Simplify and extend shift instruction patterns
Date: Fri, 7 Aug 2020 11:55:43 +0100 [thread overview]
Message-ID: <20200807105543.s7clmrfnpvjg2zbz@jozef-acer-manjaro> (raw)
In-Reply-To: <20200721182953.wh2sprenianogipq@jozef-acer-manjaro>
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
next prev parent reply other threads:[~2020-08-07 10:55 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-07-21 18:17 [PATCH 0/3] MSP430: Improve code-generation for shift instructions Jozef Lawrynowicz
2020-07-21 18:24 ` [PATCH 1/3] expr: Allow scalar_int_mode target mode when converting a constant Jozef Lawrynowicz
2020-07-22 8:33 ` Richard Sandiford
2020-07-22 9:48 ` Jozef Lawrynowicz
2020-07-24 14:14 ` Richard Sandiford
2020-07-21 18:26 ` [PATCH 2/3] expmed: Fix possible use of NULL_RTX return value from emit_store_flag Jozef Lawrynowicz
2020-07-22 8:38 ` Richard Sandiford
2020-07-21 18:29 ` [PATCH 3/3] MSP430: Simplify and extend shift instruction patterns Jozef Lawrynowicz
2020-08-07 10:55 ` Jozef Lawrynowicz [this message]
2020-08-25 19:16 ` Jeff Law
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200807105543.s7clmrfnpvjg2zbz@jozef-acer-manjaro \
--to=jozef.l@mittosystems.com \
--cc=gcc-patches@gcc.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).