From: Pan Li <[email protected]>

According to the RVV 1.0 spec, the widening ops like vzext.vf2
could have the source registers overlap on constraint, aka:

`
The destination EEW is greater than the source EEW, the source
EMUL is at least 1, and the overlap is in the highest-
numbered part of the destination register group.
`

However, the lra for now doesn't try to overlap as much as
possible.  The overlap rvv register pair(s) in the constraint
is avaiable but the lra is the final decicsion maker to pick
the avaiable register pairs.

Therefore, from the test cases we can see, not all registers
in rvv will overlap for insn vsext.vf, even if it could
overlap up to a point.

gcc/ChangeLog:

        * config/riscv/constraints.md (Wtt): Rename to Wvr to
        indicate widen vector register constraint.
        * config/riscv/riscv-protos.h (riscv_widen_overlap_ok): Rename
        from...
        (riscv_vector_mode_p): Add new decl for riscv-v.cc visibile.
        (riscv_hard_regno_nregs): Ditto.
        (riscv_v_widen_constraint_ok): Rename to...
        * config/riscv/riscv-v.cc (riscv_v_widen_constraint_ok): Rename
        to... and take care of Wvr constraint.
        * config/riscv/riscv.cc (riscv_vector_mode_p): Remove static.
        (riscv_hard_regno_nregs): Ditto.
        (riscv_widen_overlap_ok): Remove.
        * config/riscv/vector.md: Rename to Wvr.

Signed-off-by: Pan Li <[email protected]>
---
 gcc/config/riscv/constraints.md | 37 ++++++++++++++++++++----
 gcc/config/riscv/riscv-protos.h |  6 ++--
 gcc/config/riscv/riscv-v.cc     | 51 +++++++++++++++++++++++++++++++++
 gcc/config/riscv/riscv.cc       | 44 ++--------------------------
 gcc/config/riscv/vector.md      |  2 +-
 5 files changed, 89 insertions(+), 51 deletions(-)

diff --git a/gcc/config/riscv/constraints.md b/gcc/config/riscv/constraints.md
index 81d14df17ab..8051c1e330b 100644
--- a/gcc/config/riscv/constraints.md
+++ b/gcc/config/riscv/constraints.md
@@ -184,12 +184,37 @@ (define_register_constraint "vd" "TARGET_VECTOR ? VD_REGS 
: NO_REGS"
 (define_register_constraint "vm" "TARGET_VECTOR ? VM_REGS : NO_REGS"
   "A vector mask register (if available).")
 
-;; Dependent (dynamic) constraint:
-;; "The source group must overlap the highest-numbered part of the
-;; "destination group", i.e. this operand depends on operand 0.
-(define_register_constraint "Wtt" "TARGET_VECTOR ? V_REGS : NO_REGS"
-  "Vector widening overlap"
-  "riscv_widen_overlap_ok (regno, mode, ref_regno, ref_mode)"
+;; Dependent (dynamic) constraint for widening overlap:
+;; The RVV widening constraints for register overlap, aka dest EEW > src EEW.
+;; Quote from RVV spec 1.0:
+;;
+;; The destination EEW is greater than the source EEW, the source EMUL is at
+;; least 1, and the overlap is in the highest-numbered part of the destination
+;; register group (e.g., when LMUL=8, vzext.vf4 v0, v6 is legal, but a source
+;; of v0, v2, or v4 is not).
+;;
+;; Take vzext.vfN for example, only below cases are valid.
+;; Source EMUL = LMUL * (Source EEW / SEW) = LMUL * SEW / (N * SEW) = LMUL / N
+;;
+;; +-----------+------------+------------+----------+
+;; |           | LMUL = 8   | LMUL = 4   | LMUL = 2 |
+;; +-----------+------------+------------+----------+
+;; | vzext.vf2 | EMUL = 4   | EMUL = 2   | EMUL = 1 |
+;; +-----------+------------+------------+----------+
+;; |           | v0-7, v4-7 | v0-3, v2-3 | v0-1, v1 |
+;; +-----------+------------+------------+----------+
+;; | vzext.vf4 | EMUL = 2   | EMUL = 1   |          |
+;; +-----------+------------+------------+----------+
+;; |           | v0-7, v6-7 | v0-3, v3   |          |
+;; +-----------+------------+------------+----------+
+;; | vzext.vf8 | EMUL = 1   |            |          |
+;; +-----------+------------+------------+----------+
+;; |           | v0-7, v7   |            |          |
+;; +-----------+------------+------------+----------+
+;;
+(define_register_constraint "Wvr" "TARGET_VECTOR ? V_REGS : NO_REGS"
+  "Widening vector reg constraint"
+  "riscv_vector::riscv_v_widen_constraint_ok (regno, mode, ref_regno, 
ref_mode)"
   "0")
 
 ;; This constraint is used to match instruction "csrr %0, vlenb" which is 
generated in "mov<mode>".
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 5fd2328062d..e7bce0db7a3 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -175,8 +175,6 @@ extern poly_uint64 riscv_regmode_natural_size 
(machine_mode);
 extern bool riscv_vla_mode_p (machine_mode);
 extern bool riscv_tuple_mode_p (machine_mode);
 extern bool riscv_vls_mode_p (machine_mode);
-extern bool riscv_widen_overlap_ok (unsigned int, machine_mode,
-                                   unsigned int, machine_mode);
 extern int riscv_get_v_regno_alignment (machine_mode);
 extern bool riscv_shamt_matches_mask_p (int, HOST_WIDE_INT);
 extern void riscv_subword_address (rtx, rtx *, rtx *, rtx *, rtx *);
@@ -206,6 +204,8 @@ extern std::string riscv_arch_str (bool version_p = true);
 extern void riscv_parse_arch_string (const char *, struct gcc_options *, 
location_t);
 
 extern bool riscv_hard_regno_rename_ok (unsigned, unsigned);
+extern bool riscv_vector_mode_p (machine_mode);
+extern unsigned int riscv_hard_regno_nregs (unsigned int, machine_mode);
 
 rtl_opt_pass * make_pass_shorten_memrefs (gcc::context *ctxt);
 rtl_opt_pass * make_pass_avlprop (gcc::context *ctxt);
@@ -825,6 +825,8 @@ bool whole_reg_loadstore_p (rtx dest, rtx src, rtx mask, 
rtx avl, rtx
                            avl_type);
 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);
 }
 
 /* We classify builtin types into two classes:
diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc
index 431aaa1e761..48cc56ea3d9 100644
--- a/gcc/config/riscv/riscv-v.cc
+++ b/gcc/config/riscv/riscv-v.cc
@@ -6473,4 +6473,55 @@ splat_to_scalar_move_p (rtx *ops)
         && known_ge (GET_MODE_SIZE (Pmode), GET_MODE_SIZE (GET_MODE (ops[3])));
 }
 
+/* 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
+   is in the highest-numbered part of the destination group.  */
+
+bool
+riscv_v_widen_constraint_ok (unsigned int regno, machine_mode mode,
+                            unsigned int wide_regno, machine_mode wide_mode)
+{
+  /* If the referenced regno is no hard reg, allow everything.
+     Note: Even if we don't have a wide_regno yet, here we could also decline
+          operands based on just regno alone.  If we decided to accept only
+          overlapping registers in this constraint, we'd might need to e.g.
+          decline a regno = v0 right away, even if we don't know wide_regno
+          yet.  Otherwise, the return true here could get us into unsatisfiable
+          situations in LRA later, as no wide reg can overlap v0 in the high
+          part.  */
+  if (wide_regno == INVALID_REGNUM)
+    return true;
+
+  if (!V_REG_P (regno) || !V_REG_P (wide_regno) || regno == wide_regno)
+    return false;
+
+  gcc_checking_assert (riscv_vector_mode_p (mode)
+                      && riscv_vector_mode_p (wide_mode));
+
+  if (riscv_tuple_mode_p (mode))
+     return false;
+
+  unsigned int wide_nregs = riscv_hard_regno_nregs (wide_regno, wide_mode);
+  unsigned int nregs = riscv_hard_regno_nregs (regno, mode);
+
+  if (wide_nregs == nregs) /* Source LMUL < 1.  */
+    {
+      gcc_checking_assert (nregs == 1);
+
+      return true;
+    }
+
+  gcc_checking_assert (wide_nregs > nregs);
+  gcc_checking_assert ((wide_nregs % nregs) == 0);
+
+  /* No overlap.  */
+  if (regno + nregs <= wide_regno || wide_regno + wide_nregs <= regno)
+    return true;
+
+  unsigned int highest_num = wide_nregs - nregs;
+
+  return (regno % wide_nregs) == highest_num;
+}
+
 } // namespace riscv_vector
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 251da7c0999..45367bc3069 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -2531,7 +2531,7 @@ riscv_vls_mode_p (machine_mode mode)
    2. RVV tuple mode.
    3. RVV vls mode.  */
 
-static bool
+bool
 riscv_vector_mode_p (machine_mode mode)
 {
   return riscv_vla_mode_p (mode) || riscv_tuple_mode_p (mode)
@@ -6922,9 +6922,6 @@ riscv_vector_type_p (const_tree type)
   return riscv_vector::builtin_type_p (type);
 }
 
-static unsigned int
-riscv_hard_regno_nregs (unsigned int regno, machine_mode mode);
-
 /* Subroutine of riscv_get_arg_info.  */
 
 static rtx
@@ -11186,7 +11183,7 @@ riscv_register_move_cost (machine_mode mode,
 
 /* Implement TARGET_HARD_REGNO_NREGS.  */
 
-static unsigned int
+unsigned int
 riscv_hard_regno_nregs (unsigned int regno, machine_mode mode)
 {
   if (riscv_vla_mode_p (mode))
@@ -11242,43 +11239,6 @@ riscv_hard_regno_nregs (unsigned int regno, 
machine_mode mode)
   return (GET_MODE_SIZE (mode).to_constant () + UNITS_PER_WORD - 1) / 
UNITS_PER_WORD;
 }
 
-/* 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
-   is in the highest-numbered part of the destination group.  */
-
-bool
-riscv_widen_overlap_ok (unsigned int regno, machine_mode mode,
-                       unsigned int wide_regno, machine_mode wide_mode)
-{
-  /* If the referenced regno is no hard reg, allow everything.  */
-  if (wide_regno == INVALID_REGNUM)
-    return true;
-
-  if (!V_REG_P (regno) || !V_REG_P (wide_regno))
-    return false;
-
-  gcc_checking_assert (riscv_vector_mode_p (mode)
-                      && riscv_vector_mode_p (wide_mode));
-
-  unsigned int wide_nregs = riscv_hard_regno_nregs (wide_regno, wide_mode);
-  unsigned int nregs = riscv_hard_regno_nregs (regno, mode);
-
-  /* Overlap is only allowed in the highest-numbered part of the wider
-     destination.  */
-  if (regno == wide_regno)
-    return false;
-
-  if (regno >= wide_regno + (wide_nregs - nregs))
-    return true;
-
-  /* No overlap is OK.  */
-  if (regno < wide_regno)
-    return true;
-
-  return false;
-}
-
 /* Implement TARGET_HARD_REGNO_MODE_OK.  */
 
 static bool
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index 2b6888fc679..5d22edb0f3f 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -4101,7 +4101,7 @@ (define_insn "@pred_<optab><mode>_vf2"
             (reg:SI VL_REGNUM)
             (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
          (any_extend:VWEXTI
-           (match_operand:<V_DOUBLE_TRUNC> 3 "register_operand" 
"Wtt,Wtt,Wtt,Wtt"))
+           (match_operand:<V_DOUBLE_TRUNC> 3 "register_operand" 
"Wvr,Wvr,Wvr,Wvr"))
          (match_operand:VWEXTI 2 "vector_merge_operand"         " vu,  0, vu,  
0")))]
   "TARGET_VECTOR && !TARGET_XTHEADVECTOR"
   "v<sz>ext.vf2\t%0,%3%p1"
-- 
2.43.0

Reply via email to