From: Pan Li <[email protected]> According to the different-source-EEW rule, aka: A vector register cannot be used to provide source operands with more than one EEW for a single instruction.
And further confirmation from the issue as below: https://github.com/riscv/riscv-isa-manual/issues/2350 For widening reductions, if vs2 overlaps vs1, then the instruction is reserved, because the same vector register supplies operands with different EEWs. Therefore, add a new explicit constraint Wvs to restrict that the vs1 and vs2 cannot overlap. gcc/ChangeLog: * config/riscv/constraints.md (Wvs): New constraint for the vector register which doesn't overlap the operand 3 register group. * config/riscv/riscv-protos.h (riscv_v_widen_reduce_constraint_ok): New function decl. * config/riscv/riscv-v.cc (riscv_v_widen_reduce_constraint_ok): New function impl to tell if the register group is overlapped. * config/riscv/vector.md: Leverage Wvs constraint. Signed-off-by: Pan Li <[email protected]> --- gcc/config/riscv/constraints.md | 10 ++++++++++ gcc/config/riscv/riscv-protos.h | 2 ++ gcc/config/riscv/riscv-v.cc | 26 ++++++++++++++++++++++++++ gcc/config/riscv/vector.md | 2 +- 4 files changed, 39 insertions(+), 1 deletion(-) 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") + ;; This constraint is used to match instruction "csrr %0, vlenb" which is generated in "mov<mode>". ;; VLENB is a run-time constant which represent the vector register length in bytes. ;; BYTES_PER_RISCV_VECTOR represent runtime invariant of vector register length in bytes. diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index b0c1d8d4d05..087ee56f3a7 100644 --- 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); } /* We classify builtin types into two classes: diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc index d98f0a94023..46288aa7d7a 100644 --- a/gcc/config/riscv/riscv-v.cc +++ b/gcc/config/riscv/riscv-v.cc @@ -6575,4 +6575,30 @@ riscv_v_widen_constraint_ok (unsigned int regno, machine_mode mode, return (regno % wide_nregs) == highest_num; } +/* Return true if REGNO in MODE does not overlap the vector register group + starting at REF_REGNO in REF_MODE. + + The widening reductions vwredsum[u].vs / vfwred[o|u]sum.vs read vs1 with + EEW = 2 * SEW (EMUL = 1) and vs2 with EEW = SEW (EMUL = LMUL). Section 5.2 + of the vector spec reserves any encoding in which one vector register + supplies source operands with two or more different EEWs, so vs1 must not + fall inside the vs2 group. See + https://github.com/riscv/riscv-isa-manual/issues/2350. */ + +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; +} + } // namespace riscv_vector diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md index e760f708faf..96c9b2bb80e 100644 --- a/gcc/config/riscv/vector.md +++ b/gcc/config/riscv/vector.md @@ -8093,7 +8093,7 @@ (define_insn "@pred_<reduc_op_pat_name><mode>" (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) (unspec:<V_EXT_LMUL1> [ (match_operand:VI_QHS 3 "register_operand" " vr, vr") - (match_operand:<V_EXT_LMUL1> 4 "register_operand" " vr, vr") + (match_operand:<V_EXT_LMUL1> 4 "register_operand" " Wvs, Wvs") ] ANY_WREDUC) (match_operand:<V_EXT_LMUL1> 2 "vector_merge_operand" " vu, 0")] UNSPEC_REDUC))] "TARGET_VECTOR" -- 2.43.0
