Hi Pan,
> diff --git a/gcc/config/riscv/constraints.md b/gcc/config/riscv/constraints.md
> index d9fc9704ef5..b297d205782 100644
> --- a/gcc/config/riscv/constraints.md
> +++ b/gcc/config/riscv/constraints.md
> @@ -243,6 +243,16 @@ (define_register_constraint "Wvr" "TARGET_VECTOR ?
> V_REGS : NO_REGS"
> "riscv_vector::riscv_v_widen_constraint_ok (regno, mode, ref_regno,
> ref_mode)"
> "0")
>
> +;; The scalar operand vs1 of a widening reduction (vwredsum[u].vs,
> +;; vfwred[o|u]sum.vs) is read with EEW = 2 * SEW while the vector operand vs2
> +;; (operand 3) is read with EEW = SEW. A vector register may not supply
> +;; source operands with two different EEWs, so vs1 must not fall inside the
> +;; vs2 register group.
> +(define_register_constraint "Wvs" "TARGET_VECTOR ? V_REGS : NO_REGS"
> + "Vector reg not overlapping the operand 3 register group"
> + "riscv_vector::riscv_v_widen_reduce_constraint_ok (regno, mode, ref_regno,
> ref_mode)"
> + "3")
The only concern I have here is that we might need several of these
because the "sibling" operands might always have different operand
numbers (like 2 and 3 here, but could be 3 and 4, 4 and 5). That's
nothing your patch can improve of course, just wondering if we should
have allowed a relative operand number (like +1). Certainly wouldn't
help complexity :)
> --- a/gcc/config/riscv/riscv-protos.h
> +++ b/gcc/config/riscv/riscv-protos.h
> @@ -829,6 +829,8 @@ bool splat_to_scalar_move_p (rtx *);
> rtx get_fp_rounding_coefficient (machine_mode);
> bool riscv_v_widen_constraint_ok (unsigned int, machine_mode, unsigned int,
> machine_mode);
> +bool riscv_v_widen_reduce_constraint_ok (unsigned int, machine_mode,
> + unsigned int, machine_mode);
> }
As the constraint itself is fairly generic, I wouldn't call it widen
reduce. Note we have a similar issue in PR113695 where the instruction
is an indexed store and this constraint would apply as well.
> +bool
> +riscv_v_widen_reduce_constraint_ok (unsigned int regno, machine_mode mode,
> + unsigned int ref_regno, machine_mode
> ref_mode)
> +{
> + if (ref_regno == INVALID_REGNUM)
> + return true;
> +
> + if (!V_REG_P (regno) || !V_REG_P (ref_regno))
> + return false;
> +
> + unsigned int nregs = riscv_hard_regno_nregs (regno, mode);
> + unsigned int ref_nregs = riscv_hard_regno_nregs (ref_regno, ref_mode);
> +
> + return regno + nregs <= ref_regno || ref_regno + ref_nregs <= regno;
> +}
This non-overlap condition might be useful in other such constraints as
well. I think we even use it in riscv_v_widen_constraint_ok. Could we
move it into a separate function for clarity?
--
Regards
Robin