"Robin Dapp" <[email protected]> writes:
>> Oops, I meant target-dependent of course.
>
> Grml, now I know why the issues disappeared... I accidentally
> re-introduced an older oversight in riscv's regmode_natural_size where I
> divided by 64 instead of by 8, leading to very limited coverage.
> I'll need at least two more hunks in expmed.cc and expr.cc both of which
> would be better off checking for a mov optab as well. Also, there is an
> ICE in simplify_subreg_concatn.
Could you give an example of something that needs the new changes?
Richard
> Rather than changing all callers of operand_subword_force, can we fix it
> in there directly? Even though they are mostly clustered, all of them
> would need to do the same thing anyway?
> I think by now (with the approved changes) extract_bit_field and
> store_bit_field can handle "word-unsplittable" vector modes already,
> either by extract/set or by spilling, so we could use those?
>
> With the changes below
>
> - aarch64/riscv hooks
> - accepted extract_bit_field/store_bit_field
> - accepted read_complex_part
> - your lower-subreg hunk
> - operand_subword_force using extract_bit_field
> - emit_move_multi_word using store_bit_field
>
> on riscv I only have one lower-subreg ICE left:
>
> FAIL: gcc.dg/pr44136.c (internal compiler error: in
> simplify_subreg_concatn, at lower-subreg.cc:678)
>
> Is that acceptable in order to avoid further whack-a-mole?
>
> ---
> gcc/config/aarch64/aarch64.cc | 16 ++++++++--------
> gcc/config/riscv/riscv-v.cc | 12 ++++--------
> gcc/config/riscv/riscv.cc | 5 ++---
> gcc/emit-rtl.cc | 9 +++++++++
> gcc/expmed.cc | 10 ++++++++--
> gcc/expr.cc | 19 +++++++++++++------
> gcc/lower-subreg.cc | 19 ++++++++++++++++++-
> 7 files changed, 62 insertions(+), 28 deletions(-)
>
> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> index 93c00c23a50..a2d67ea3d39 100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -2995,20 +2995,20 @@ aarch64_regmode_natural_size (machine_mode mode)
> /* The natural size for SVE data modes is one SVE data vector,
> and similarly for predicates. We can't independently modify
> anything smaller than that. */
> - /* ??? For now, only do this for variable-width SVE registers.
> - Doing it for constant-sized registers breaks lower-subreg.cc. */
> - /* ??? And once that's fixed, we should probably have similar
> - code for Advanced SIMD. */
> - if (!aarch64_sve_vg.is_constant ())
> - {
> - /* REGMODE_NATURAL_SIZE influences general subreg validity rules,
> - so we need to handle memory-only modes as well. */
> + if (VECTOR_MODE_P (mode))
> + {
> unsigned int vec_flags = aarch64_classify_vector_memory_mode (mode);
> if (vec_flags & VEC_SVE_PRED)
> return BYTES_PER_SVE_PRED;
> if (vec_flags & VEC_SVE_DATA)
> return BYTES_PER_SVE_VECTOR;
> + if (vec_flags & VEC_ADVSIMD)
> + return MAX
> + (exact_div (GET_MODE_SIZE (mode),
> + aarch64_ldn_stn_vectors (mode)).to_constant (),
> + UNITS_PER_WORD);
> }
> +
> return UNITS_PER_WORD;
> }
>
> diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc
> index 01960ff96e5..fd4fd89d05d 100644
> --- a/gcc/config/riscv/riscv-v.cc
> +++ b/gcc/config/riscv/riscv-v.cc
> @@ -4032,14 +4032,10 @@ shuffle_even_odd_patterns (struct expand_vec_perm_d
> *d)
>
> /* When the element width is smaller than the greatest ELEN, we can use two
> vnsrl instructions, each extracting the even/odd elements of one source,
> - and a vslideup instruction to merge them into one vector.
> -
> - PR target/124996: VLS mode subregs larger than what
> - riscv_regmode_natural_size allows cause a memory roundtrip. Therefore,
> for
> - now, we only do this when the mode size is no greater than the natural
> size
> - of the register. Once this is fixed, the condition should be replaced
> by
> - the ELEN condition. */
> - if (known_le (GET_MODE_SIZE (vmode), riscv_regmode_natural_size (vmode)))
> + and a vslideup instruction to merge them into one vector. */
> + unsigned int max_elen = TARGET_VECTOR_ELEN_64 ? 64 : 32;
> + if (known_le (GET_MODE_SIZE (vmode), riscv_regmode_natural_size (vmode))
> + && GET_MODE_BITSIZE (GET_MODE_INNER (vmode)) * 2 <= max_elen)
> {
> unsigned int elen = GET_MODE_BITSIZE (GET_MODE_INNER (vmode));
> unsigned int elen2x = elen * 2;
> diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
> index a401c0c7c93..a42fdc56e0e 100644
> --- a/gcc/config/riscv/riscv.cc
> +++ b/gcc/config/riscv/riscv.cc
> @@ -13311,9 +13311,6 @@ riscv_regmode_natural_size (machine_mode mode)
> /* The natural size for RVV data modes is one RVV data vector,
> and similarly for predicates. We can't independently modify
> anything smaller than that. */
> - /* ??? For now, only do this for variable-width RVV registers.
> - Doing it for constant-sized registers breaks lower-subreg.c. */
> -
> if (riscv_vector_mode_p (mode))
> {
> poly_uint64 size = GET_MODE_SIZE (mode);
> @@ -13337,6 +13334,8 @@ riscv_regmode_natural_size (machine_mode mode)
> return minimum size between vector register size and scalar
> register size. */
> return MIN (size.to_constant (), UNITS_PER_WORD);
> + else
> + return TARGET_MIN_VLEN / UNITS_PER_WORD;
> }
> return UNITS_PER_WORD;
> }
> diff --git a/gcc/emit-rtl.cc b/gcc/emit-rtl.cc
> index 4a23eaefe02..42d1b10090c 100644
> --- a/gcc/emit-rtl.cc
> +++ b/gcc/emit-rtl.cc
> @@ -53,6 +53,7 @@ along with GCC; see the file COPYING3. If not see
> #include "cfgrtl.h"
> #include "tree-eh.h"
> #include "explow.h"
> +#include "expmed.h"
> #include "expr.h"
> #include "builtins.h"
> #include "rtl-iter.h"
> @@ -1827,6 +1828,14 @@ operand_subword_force (rtx op, poly_uint64 offset,
> machine_mode mode)
>
> if (mode != BLKmode && mode != VOIDmode)
> {
> + /* If the register cannot easily be split into words, let
> + extract_bit_field handle it. */
> + rtx tmp = SUBREG_P (op) ? SUBREG_REG (op) : op;
> + if (maybe_lt ((unsigned) UNITS_PER_WORD,
> + (poly_uint64) REGMODE_NATURAL_SIZE (GET_MODE (tmp))))
> + return extract_bit_field (tmp, BITS_PER_WORD,
> + offset * BITS_PER_WORD, 1, NULL_RTX,
> + word_mode, word_mode, false, NULL);
> /* If this is a register which cannot be accessed by words, copy it
> to a pseudo register. */
> if (REG_P (op))
> diff --git a/gcc/expmed.cc b/gcc/expmed.cc
> index b87d06bc9a4..9c719d8614a 100644
> --- a/gcc/expmed.cc
> +++ b/gcc/expmed.cc
> @@ -863,7 +863,10 @@ store_bit_field_1 (rtx str_rtx, poly_uint64 bitsize,
> poly_uint64 bitnum,
> if (MEM_P (op0))
> op0 = adjust_bitfield_address_size (op0, op0_mode.else_blk (),
> 0, MEM_SIZE (op0));
> - else if (!op0_mode.exists ())
> + else if (!op0_mode.exists ()
> + || maybe_lt
> + ((unsigned) UNITS_PER_WORD,
> + (poly_uint64) REGMODE_NATURAL_SIZE (GET_MODE (op0))))
> {
> if (ibitnum == 0
> && known_eq (ibitsize, GET_MODE_BITSIZE (GET_MODE (op0)))
> @@ -1839,7 +1842,10 @@ extract_bit_field_1 (rtx str_rtx, poly_uint64 bitsize,
> poly_uint64 bitnum,
> if (MEM_P (op0))
> op0 = adjust_bitfield_address_size (op0, op0_mode.else_blk (),
> 0, MEM_SIZE (op0));
> - else if (op0_mode.exists (&imode))
> + else if (op0_mode.exists (&imode)
> + && known_ge
> + ((unsigned) UNITS_PER_WORD,
> + (poly_uint64) REGMODE_NATURAL_SIZE (GET_MODE (op0))))
> {
> op0 = gen_lowpart (imode, op0);
>
> diff --git a/gcc/expr.cc b/gcc/expr.cc
> index 210a7bc0888..7de94807550 100644
> --- a/gcc/expr.cc
> +++ b/gcc/expr.cc
> @@ -4198,9 +4198,6 @@ read_complex_part (rtx cplx, bool imag_p)
> imag_p ? GET_MODE_SIZE (imode) : 0);
> if (ret)
> return ret;
> - else
> - /* simplify_gen_subreg may fail for sub-word MEMs. */
> - gcc_assert (MEM_P (cplx) && ibitsize < BITS_PER_WORD);
> }
>
> return extract_bit_field (cplx, ibitsize, imag_p ? ibitsize : 0,
> @@ -4567,11 +4564,21 @@ emit_move_multi_word (machine_mode mode, rtx x, rtx y)
> else if (ypart == 0)
> ypart = operand_subword_force (y, i, mode);
>
> - gcc_assert (xpart && ypart);
> + if (xpart == 0)
> + {
> + need_clobber = true;
> + store_bit_field (x, BITS_PER_WORD, i * BITS_PER_WORD, 0, 0,
> + word_mode, ypart, false, false);
> + last_insn = get_last_insn ();
> + }
> + else
> + {
> + gcc_assert (xpart && ypart);
>
> - need_clobber |= (GET_CODE (xpart) == SUBREG);
> + need_clobber |= (GET_CODE (xpart) == SUBREG);
>
> - last_insn = emit_move_insn (xpart, ypart);
> + last_insn = emit_move_insn (xpart, ypart);
> + }
> }
>
> seq = end_sequence ();
> diff --git a/gcc/lower-subreg.cc b/gcc/lower-subreg.cc
> index 5dee6a0b646..5033c6886c5 100644
> --- a/gcc/lower-subreg.cc
> +++ b/gcc/lower-subreg.cc
> @@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see
> #include "memmodel.h"
> #include "tm_p.h"
> #include "expmed.h"
> +#include "regs.h"
> #include "insn-config.h"
> #include "emit-rtl.h"
> #include "recog.h"
> @@ -113,6 +114,9 @@ interesting_mode_p (machine_mode mode, unsigned int
> *bytes,
> {
> if (!GET_MODE_SIZE (mode).is_constant (bytes))
> return false;
> + if (maybe_lt ((unsigned) UNITS_PER_WORD,
> + (poly_uint64) REGMODE_NATURAL_SIZE (mode)))
> + return false;
> *words = CEIL (*bytes, UNITS_PER_WORD);
> return true;
> }
> @@ -302,7 +306,20 @@ static bool
> simple_move_operand (rtx x)
> {
> if (GET_CODE (x) == SUBREG)
> - x = SUBREG_REG (x);
> + {
> + /* Exclude subregs whose outer mode can be split into multiple words
> + but whose inner mode cannot. Attempting to split such a subreg
> + would mean trying to split the unsplittable inner register.
> +
> + If instead the subreg occupies a single word, we can keep it as-is,
> + regardless of what the SUBREG_REG is. If the outer mode cannot be
> + split then the subreg makes things no worse than they already are. */
> + unsigned int factor, size;
> + if (interesting_mode_p (GET_MODE (x), &size, &factor) && factor > 1
> + && !interesting_mode_p (GET_MODE (SUBREG_REG (x)), &size, &factor))
> + return false;
> + x = SUBREG_REG (x);
> + }
>
> if (!OBJECT_P (x))
> return false;