]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
RISC-V: theadvector specifics for vec_init and vec_extract. [PR124147]
authorRobin Dapp <rdapp@oss.qualcomm.com>
Wed, 18 Feb 2026 11:10:13 +0000 (12:10 +0100)
committerRobin Dapp <rdapp@oss.qualcomm.com>
Tue, 24 Feb 2026 20:48:48 +0000 (21:48 +0100)
The mask-mode vec_init and vec_extract expanders assume that we can
create QImode vectors with the same number of units as the mask mode
has.  XTheadVector does not have fractional-LMUL modes and we ICE when
trying to expand the actual insns.

An obvioius solution would be to simply disable the autovec expanders for
TARGET_XTHEADVECTOR but exactly these optab/mode combination has no fallback
in the common expansion code.  That's a known problem and should be fixed
separately in extract_bit_field_1.

For now, though, we do not need to use small modes and can go with full
vectors instead.  The excess elements don't matter.
To that end, this patch uses paradoxical subregs on the source (for
vec_extract) and on the destination (for vec_init), leaving the
remaining elements undefined.

In order to obtain the right "full vector" I needed to adjust
get_m1_mode slightly.  By default it returns a VLA mode so when
introducing a subreg like above we can have
  (subreg:full_vector_mode (reg:small_vls_vector_mode) 0)
where full_vector_mode is a VLA mode and small_vls_vector_mode is a VLS
mode.  This won't be a valid subreg so the patch adds a VLS_P
argument to get_m1_mode that returns a full VLS vector mode.

Regtested on rv64gcv_zvl512b.  As I didn't have theadvector hardware
available I made the new code paths unconditional (so they are active
for regular RVV) and re-tested.

PR target/124147

gcc/ChangeLog:

* config/riscv/autovec.md: Work around fractional-LMUL modes for
TARGET_XTHEADVECTOR.
* config/riscv/riscv-protos.h (get_m1_mode): Export.
* config/riscv/riscv-v.cc (get_m1_mode): Allow to get a VLS m1
vector.

gcc/testsuite/ChangeLog:

* gcc.target/riscv/rvv/xtheadvector/pr124147.c: New test.

gcc/config/riscv/autovec.md
gcc/config/riscv/riscv-protos.h
gcc/config/riscv/riscv-v.cc
gcc/testsuite/gcc.target/riscv/rvv/xtheadvector/pr124147.c [new file with mode: 0644]

index cc27a76c44f35effa7c111829a3d036f28362c9c..fc5a31c93968ecb6695244c9610fa249441575d5 100644 (file)
    (match_operand 1 "")]
   "TARGET_VECTOR"
   {
-    /* Expand into a QImode vector.  */
-    machine_mode qimode = riscv_vector::get_vector_mode
+    /* Expand into a QImode vector.
+       For XTheadVector which does not have fractional-LMUL modes, we use
+       a full-size vector instead.  */
+    bool fractional_p = known_lt (GET_MODE_NUNITS (<MODE>mode),
+                                 BYTES_PER_RISCV_VECTOR);
+    machine_mode qimode;
+    if (!TARGET_XTHEADVECTOR || !fractional_p)
+      qimode = riscv_vector::get_vector_mode
        (QImode, GET_MODE_NUNITS (<MODE>mode)).require ();
+    else
+      qimode = riscv_vector::get_m1_mode
+       (QImode, GET_MODE_NUNITS (<MODE>mode).is_constant ()).require ();
     rtx tmp = gen_reg_rtx (qimode);
     riscv_vector::expand_vec_init (tmp, operands[1]);
 
     riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, ops);
 
     /* Compare against zero.  */
-    riscv_vector::expand_vec_cmp (operands[0], NE, tmp2, CONST0_RTX (qimode));
+    rtx op0;
+    if (!TARGET_XTHEADVECTOR || !fractional_p)
+      op0 = operands[0];
+    else
+      op0 = gen_lowpart (riscv_vector::get_mask_mode (qimode), operands[0]);
+    riscv_vector::expand_vec_cmp (op0, NE, tmp2, CONST0_RTX (qimode));
     DONE;
   }
 )
         [(match_operand          2 "nonmemory_operand")])))]
   "TARGET_VECTOR"
 {
-  /* Create an empty byte vector and set it to one under mask.  */
-  machine_mode qimode = riscv_vector::get_vector_mode
-      (QImode, GET_MODE_NUNITS (<MODE>mode)).require ();
+  /* Create an empty byte vector and set it to one under mask.
+     For XTheadVector which does not have fractional-LMUL modes, we use
+     a full-size vector instead.  */
+  bool fractional_p = known_lt (GET_MODE_NUNITS (<MODE>mode),
+                               BYTES_PER_RISCV_VECTOR);
+  machine_mode qimode;
+  if (!TARGET_XTHEADVECTOR || !fractional_p)
+    qimode = riscv_vector::get_vector_mode
+       (QImode, GET_MODE_NUNITS (<MODE>mode)).require ();
+  else
+    qimode = riscv_vector::get_m1_mode
+       (QImode, GET_MODE_NUNITS (<MODE>mode).is_constant ()).require ();
 
   rtx tmp1 = gen_reg_rtx (qimode);
   emit_move_insn (tmp1, gen_const_vec_duplicate (qimode, GEN_INT (0)));
   rtx ones = gen_const_vec_duplicate (qimode, GEN_INT (1));
 
-  rtx ops1[] = {tmp1, tmp1, ones, operands[1]};
+  rtx op1;
+  if (!TARGET_XTHEADVECTOR || !fractional_p)
+    op1 = operands[1];
+  else
+    op1 = gen_lowpart (riscv_vector::get_mask_mode (qimode), operands[1]);
+
+  rtx ops1[] = {tmp1, tmp1, ones, op1};
   riscv_vector::emit_vlmax_insn (code_for_pred_merge (qimode),
                                 riscv_vector::MERGE_OP, ops1);
 
index 0734c31ec5628ae12a0f0e44b7074e86a86fbf8f..dd029c704133704b10a829c24d62fbd530713e68 100644 (file)
@@ -653,6 +653,7 @@ enum tail_policy get_prefer_tail_policy ();
 enum mask_policy get_prefer_mask_policy ();
 rtx get_avl_type_rtx (enum avl_type);
 opt_machine_mode get_lmul_mode (scalar_mode, int);
+opt_machine_mode get_m1_mode (machine_mode, bool = false);
 opt_machine_mode get_vector_mode (scalar_mode, poly_uint64);
 opt_machine_mode get_tuple_mode (machine_mode, unsigned int);
 bool simm5_p (rtx);
index 29dc3ebccd60ed2985fdb10a67421ba34ef0d2cd..82313356a800628c51f87f219d8bf60abe6671c5 100644 (file)
@@ -2281,14 +2281,19 @@ get_lmul_mode (scalar_mode mode, int lmul)
   return E_VOIDmode;
 }
 
-/* Return the appropriate M1 mode for MODE.  */
+/* Return the appropriate LMUL1 mode for MODE.
+   If VLS_P is specified, get a VLS mode that represents a full
+   vector.  */
 
-static opt_machine_mode
-get_m1_mode (machine_mode mode)
+opt_machine_mode
+get_m1_mode (machine_mode mode, bool vls_p)
 {
   scalar_mode smode = GET_MODE_INNER (mode);
   unsigned int bytes = GET_MODE_SIZE (smode);
-  poly_uint64 m1_nunits = exact_div (BYTES_PER_RISCV_VECTOR, bytes);
+  poly_uint64 bytes_vector = BYTES_PER_RISCV_VECTOR;
+  if (vls_p)
+    bytes_vector = constant_lower_bound (bytes_vector);
+  poly_uint64 m1_nunits = exact_div (bytes_vector, bytes);
   return get_vector_mode (smode, m1_nunits);
 }
 
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/xtheadvector/pr124147.c b/gcc/testsuite/gcc.target/riscv/rvv/xtheadvector/pr124147.c
new file mode 100644 (file)
index 0000000..2233a18
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -mcpu=xt-c920 -mrvv-vector-bits=zvl" } */
+
+typedef __attribute__((__vector_size__(2 * sizeof(int)))) int V;
+
+V
+foo(V v)
+{
+  return v > 0;
+}
+