On Wed, Feb 11, 2026 at 08:53:08PM +0100, Robin Dapp wrote:
> Hi,
> 
> In the PR code we have the somewhat rare case that we need to reload
> a vector subreg of a scalar register, (subreg:V2HI (reg:DI)).
> What complicates things is that the test is compiled with
> -mrvv-vector-bits=zvl, so VLS-only mode.
> Unfortunately, we can still get VLA-named modes that are actually VLS
> modes (i.e. a constant number of units).
> 
> For moving real VLS modes we simply use
> 
>  (define_insn_and_split "*mov<mode>"
>    [(set (match_operand:VLS_AVL_IMM 0 "reg_or_mem_operand" "=vr, m, vr")
>       (match_operand:VLS_AVL_IMM 1 "reg_or_mem_operand" "  m,vr, vr"))]
> 
> Here, lra recognizes cycle danger, quickly switches to the memory
> alternative and the resulting code is as expected - we perform a vector
> load from that memory the DImode reg was spilled to.
> 
> For VLA (named) modes the mov insn is
> 
> (define_insn_and_split "*mov<V_FRACT:mode><P:mode>_lra"
>   [(set (match_operand:V_FRACT 0 "reg_or_mem_operand" "=vr, m,vr")
>       (match_operand:V_FRACT 1 "reg_or_mem_operand" "  m,vr,vr"))
>    (clobber (match_scratch:P 2 "=&r,&r,X"))]
> 
> The extra clobber here is an optimization:  For modes smaller than a full 
> register we want to store the actual size, rather than always the full
> vector size.  If that mode size happens to exceed 32, instead of using an 
> immediate we need to move it to a register so vsetvl can consume it.
> 
> As the second mov insn above has three operands lra never checks for cycle 
> danger and promptly creates a cycle :)  This patch loosens the conditions on
> the cycle check by allowing a third operand that is a clobber.  As a 
> consequence, we also need to prevent scratch regs to be "written back".

So this is just a different form of a mov and therefore it is not
completely unrelated to cycle danger.  At a first glance it sounds
reasonable.

I might be completely off here, but a quick idea which came up is
whether a secondary reload could be utilized in order to get a scratch
register, rendering the initial mov into an ordinary mov with two
operands so that LRA would again detect a cycle.

Cheers,
Stefan

> 
> I'm not 100% on this but figured I'll just send the patch out for further 
> comments.
> 
> Regtested and bootstrapped on x86 and aarch64.  The power10 cfarm machine that
> I normally use is currently unreachable.  Regtested on rv64gcv_zvl512b.
> 
> Regards
>  Robin
> 
>       PR rtl-optimization/123381
> 
> gcc/ChangeLog:
> 
>       * lra-constraints.cc (process_alt_operands): Detect cycles in
>       three-operand moves with clobber.
>       (curr_insn_transform): Don't write back a scratch operand.
> 
> gcc/testsuite/ChangeLog:
> 
>       * gcc.target/riscv/rvv/autovec/pr123381.c: New test.
> ---
>  gcc/lra-constraints.cc                               | 12 +++++++++++-
>  .../gcc.target/riscv/rvv/autovec/pr123381.c          | 11 +++++++++++
>  2 files changed, 22 insertions(+), 1 deletion(-)
>  create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123381.c
> 
> diff --git a/gcc/lra-constraints.cc b/gcc/lra-constraints.cc
> index 87b18f30c98..0d073724043 100644
> --- a/gcc/lra-constraints.cc
> +++ b/gcc/lra-constraints.cc
> @@ -3315,7 +3315,15 @@ process_alt_operands (int only_alternative)
>           early_clobbered_nops[early_clobbered_regs_num++] = nop;
>       }
>  
> -      if (curr_insn_set != NULL_RTX && n_operands == 2
> +      if (curr_insn_set != NULL_RTX
> +       /* Allow just two operands or three operands where the third
> +          is a clobber.  */
> +       && (n_operands == 2
> +           || (n_operands == 3
> +               && GET_CODE (PATTERN (curr_insn)) == PARALLEL
> +               && XVECLEN (PATTERN (curr_insn), 0) == 2
> +               && GET_CODE (XVECEXP (PATTERN (curr_insn), 0, 1))
> +                  == CLOBBER))
>         /* Prevent processing non-move insns.  */
>         && (GET_CODE (SET_SRC (curr_insn_set)) == SUBREG
>             || SET_SRC (curr_insn_set) == no_subreg_reg_operand[1])
> @@ -4919,6 +4927,8 @@ curr_insn_transform (bool check_only_p)
>             && find_reg_note (curr_insn, REG_UNUSED, old) == NULL_RTX
>             /* OLD can be an equivalent constant here.  */
>             && !CONSTANT_P (old)
> +           /* No need to write back anything for a scratch.  */
> +           && GET_CODE (old) != SCRATCH
>             && (!REG_P(old) || !ira_former_scratch_p (REGNO (old))))
>           {
>             start_sequence ();
> diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123381.c 
> b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123381.c
> new file mode 100644
> index 00000000000..cc21b0feca4
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123381.c
> @@ -0,0 +1,11 @@
> +/* { dg-do compile } */
> +/* { dg-options "-Ofast -mcpu=xiangshan-kunminghu -mrvv-vector-bits=zvl 
> -fno-tree-ccp -fno-vect-cost-model" } */
> +
> +char c;
> +
> +void
> +foo(short, short, short, short, int, int, int, int, long x)
> +{
> +  x /= *(_Complex short *)&x;
> +  c = x;
> +}
> -- 
> 2.52.0
> 

Reply via email to