From: Pan Li <[email protected]>

The vs1 of the widening reduction (aka vwredsum[u].vs) is read with
EEW = 2 * SEW while the vs2 is read with EEW = SEW.  The section 5.2
of the vector spec reserves any encoding in which one vector register
supplies source operands with two or more different EEWs.  Thus, the
vs1 must not fall inside the vs2 register group, but we may have below
asm dump when the vs1 comes from the vs2 register group.

  vwredsum.vs v2,v2,v3

Add one new constraint Wn3 which indicates the register of the operand
doesn't overlap the register group of the operand 3 (aka vs2), and then
take it for the operand 4 (aka vs1) of the widening integer reduction.
See below issue of the riscv-isa-manual for more details.

  https://github.com/riscv/riscv-isa-manual/issues/2350

gcc/ChangeLog:

        * config/riscv/constraints.md (Wn3): New constraint for the
        vector register which doesn't overlap the register group of
        the operand 3.
        * config/riscv/riscv-protos.h (riscv_v_widen_non_overlap_constraint_ok):
        New function declaration.
        * config/riscv/riscv-v.cc (riscv_v_reg_group_overlap_p): New
        function to tell if two vector register groups overlap.
        (riscv_v_widen_constraint_ok): Leverage the above function for
        the register group overlap check.
        (riscv_v_widen_non_overlap_constraint_ok): New function to tell
        if the register doesn't overlap the reference register group.
        * config/riscv/vector.md: Take the Wn3 constraint for the
        operand 4 of the widening integer reduction.

Signed-off-by: Pan Li <[email protected]>
---
 gcc/config/riscv/constraints.md | 11 ++++++++
 gcc/config/riscv/riscv-protos.h |  2 ++
 gcc/config/riscv/riscv-v.cc     | 45 ++++++++++++++++++++++++++++++++-
 gcc/config/riscv/vector.md      |  2 +-
 4 files changed, 58 insertions(+), 2 deletions(-)

diff --git a/gcc/config/riscv/constraints.md b/gcc/config/riscv/constraints.md
index d9fc9704ef5..38f46d8fec5 100644
--- a/gcc/config/riscv/constraints.md
+++ b/gcc/config/riscv/constraints.md
@@ -243,6 +243,17 @@ (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.
+;; Therefore, we take Wn3 indicates widen non-overlap to operand 3.
+(define_register_constraint "Wn3" "TARGET_VECTOR ? V_REGS : NO_REGS"
+  "Vector reg not overlapping the operand 3 register group"
+  "riscv_vector::riscv_v_widen_non_overlap_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 72b7b482339..c0fb2839780 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -828,6 +828,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_non_overlap_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 e50ebdee163..398a1003a1d 100644
--- a/gcc/config/riscv/riscv-v.cc
+++ b/gcc/config/riscv/riscv-v.cc
@@ -6521,6 +6521,22 @@ splat_to_scalar_move_p (rtx *ops)
         && known_ge (GET_MODE_SIZE (Pmode), GET_MODE_SIZE (GET_MODE (ops[3])));
 }
 
+static inline bool
+riscv_v_reg_group_overlap_p (unsigned int regno, machine_mode mode,
+                            unsigned int ref_regno, machine_mode ref_mode)
+{
+  gcc_checking_assert (V_REG_P (regno));
+  gcc_checking_assert (V_REG_P (ref_regno));
+
+  gcc_checking_assert (riscv_vector_mode_p (mode));
+  gcc_checking_assert (riscv_vector_mode_p (ref_mode));
+
+  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);
+}
+
 /* Return true if REGNO in MODE can be used as source in a widening
    instruction with destination WIDE_REGNO in WIDE_MODE.
    This is true if either there is no overlap at all, or the overlap
@@ -6560,7 +6576,7 @@ riscv_v_widen_constraint_ok (unsigned int regno, 
machine_mode mode,
   gcc_checking_assert ((wide_nregs % nregs) == 0);
 
   /* No overlap.  */
-  if (regno + nregs <= wide_regno || wide_regno + wide_nregs <= regno)
+  if (!riscv_v_reg_group_overlap_p (regno, mode, wide_regno, wide_mode))
     return true;
 
   if (is_frac_vlmul_p (mode)) /* Source LMUL < 1.  */
@@ -6571,4 +6587,31 @@ 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_non_overlap_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;
+
+  if (riscv_tuple_mode_p (mode) || ref_mode == mode)
+    return false;
+
+  return !riscv_v_reg_group_overlap_p (regno, mode, ref_regno, ref_mode);
+}
+
 } // namespace riscv_vector
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index e760f708faf..83a2c8f346d 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"      "  Wn3,  
Wn3")
            ] ANY_WREDUC)
           (match_operand:<V_EXT_LMUL1>    2 "vector_merge_operand"  "   vu,    
0")] UNSPEC_REDUC))]
   "TARGET_VECTOR"
-- 
2.43.0

Reply via email to