On Thu, 10 Sep 2026, Robin Dapp wrote:

> Hi,
> 
> This is split off of r17-3907-gec58d736cd572b.  The patch mainly avoids
> splitting subregs whose outer mode can be split but the inner cannot
> like in
>   (subreg:TI (reg:VNx4SI 665) 0).
> Also, it filters out unsplittable modes and doesn't assert that an
> outermode in simplify_subreg_concatn is interesting.  It suffices that
> its size is constant so we can build subregs.
> 
> Bootstrapped and regtested on aarch64.
> 
> While testing I noticed one new fail in gcc.dg/pr78213.c.  Andrea 
> confirmed in the PR that this is not worrying and will be fixed 
> separately.
> 
> OK for GCC 16?

OK with me, please wait in case Richard S. has any comments.

Richard.

> Regards
>  Robin
> 
>       PR middle-end/127256
> 
> gcc/ChangeLog:
> 
>       * lower-subreg.cc (interesting_mode_p): Don't consider
>       unsplittable modes as interesting.
>       (simple_move_operand): Don't split subregs whose outer mode
>       can be split but the inner mode cannot.
>       (simplify_subreg_concatn): Don't insist the outer mode is
>       interesting but rather check that its size is constant.
> 
> gcc/testsuite/ChangeLog:
> 
>       * g++.target/aarch64/pr127256.C: New test.
> ---
>  gcc/lower-subreg.cc                         | 29 +++++++++++++++++----
>  gcc/testsuite/g++.target/aarch64/pr127256.C | 22 ++++++++++++++++
>  2 files changed, 46 insertions(+), 5 deletions(-)
>  create mode 100644 gcc/testsuite/g++.target/aarch64/pr127256.C
> 
> diff --git a/gcc/lower-subreg.cc b/gcc/lower-subreg.cc
> index 5dee6a0b646..5a74d842939 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;
> @@ -649,18 +666,20 @@ decompose_register (unsigned int regno)
>  static rtx
>  simplify_subreg_concatn (machine_mode outermode, rtx op, poly_uint64 
> orig_byte)
>  {
> -  unsigned int outer_size, outer_words, inner_size, inner_words;
> +  unsigned int outer_size, inner_size, inner_words;
>    machine_mode innermode, partmode;
>    rtx part;
>    unsigned int final_offset;
>    unsigned int byte;
>  
>    innermode = GET_MODE (op);
> -  if (!interesting_mode_p (outermode, &outer_size, &outer_words)
> -      || !interesting_mode_p (innermode, &inner_size, &inner_words))
> +  if (!interesting_mode_p (innermode, &inner_size, &inner_words))
>      gcc_unreachable ();
>  
> -  /* Must be constant if interesting_mode_p passes.  */
> +  if (!GET_MODE_SIZE (outermode).is_constant (&outer_size))
> +    return NULL_RTX;
> +
> +  /* Must be constant if outer_size is.  */
>    byte = orig_byte.to_constant ();
>    gcc_assert (GET_CODE (op) == CONCATN);
>    gcc_assert (byte % outer_size == 0);
> diff --git a/gcc/testsuite/g++.target/aarch64/pr127256.C 
> b/gcc/testsuite/g++.target/aarch64/pr127256.C
> new file mode 100644
> index 00000000000..2520af1e2f7
> --- /dev/null
> +++ b/gcc/testsuite/g++.target/aarch64/pr127256.C
> @@ -0,0 +1,22 @@
> +/* { dg-do compile } */
> +/* { dg-additional-options "-O2" } */
> +
> +#include <arm_sve.h>
> +#pragma GCC target "+sve"
> +
> +float tt[4];
> +float t2[4];
> +void ComputeCoefficients() {
> +    float block[4];
> +    {
> +        svbool_t t = svwhilelt_b32_u32({}, 4);
> +        svfloat32_t v = svld1_f32(t, tt);
> +        svst1_f32(t, block, v);
> +    }
> +    __builtin_memcpy(tt, block, sizeof(block));
> +    {
> +        svbool_t t = svwhilelt_b32_u32({}, 1);
> +        svfloat32_t v = svld1_f32(t, tt);
> +        svst1_f32(t, t2, v);
> +    }
> +}
> 

-- 
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Jochen Jaser, Andrew McDonald, Abhinav Puri; (HRB 36809, AG Nuernberg)

Reply via email to