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

Reply via email to