At 2026/6/16 3:06, Robin Dapp wrote:
Hi Jiawei,

+;; Source modes for Zvzip instructions whose destination/source operand has
+;; 2x LMUL, without exposing forms that would require LMUL > 8.
+(define_mode_iterator VLMULX2 [
+  (RVVMF8QI "TARGET_VECTOR_ELEN_64")
+  RVVMF4QI RVVMF2QI RVVM1QI RVVM2QI RVVM4QI
+
+  (RVVMF4HI "TARGET_VECTOR_ELEN_64")
+  RVVMF2HI RVVM1HI RVVM2HI RVVM4HI
+
+  (RVVMF4BF "TARGET_VECTOR_ELEN_BF_16 && TARGET_VECTOR_ELEN_64")
+  (RVVMF2BF "TARGET_VECTOR_ELEN_BF_16")
+  (RVVM1BF "TARGET_VECTOR_ELEN_BF_16")
+  (RVVM2BF "TARGET_VECTOR_ELEN_BF_16")
+  (RVVM4BF "TARGET_VECTOR_ELEN_BF_16")
+
+  (RVVMF4HF "TARGET_VECTOR_ELEN_FP_16 && TARGET_VECTOR_ELEN_64")
+  (RVVMF2HF "TARGET_VECTOR_ELEN_FP_16")
+  (RVVM1HF "TARGET_VECTOR_ELEN_FP_16")
+  (RVVM2HF "TARGET_VECTOR_ELEN_FP_16")
+  (RVVM4HF "TARGET_VECTOR_ELEN_FP_16")
+
+  (RVVMF2SI "TARGET_VECTOR_ELEN_64")
+  RVVM1SI RVVM2SI RVVM4SI
+
+  (RVVMF2SF "TARGET_VECTOR_ELEN_FP_32 && TARGET_VECTOR_ELEN_64")
+  (RVVM1SF "TARGET_VECTOR_ELEN_FP_32")
+  (RVVM2SF "TARGET_VECTOR_ELEN_FP_32")
+  (RVVM4SF "TARGET_VECTOR_ELEN_FP_32")
+
+  (RVVM1DI "TARGET_VECTOR_ELEN_64")
+  (RVVM2DI "TARGET_VECTOR_ELEN_64")
+  (RVVM4DI "TARGET_VECTOR_ELEN_64")
+
+  (RVVM1DF "TARGET_VECTOR_ELEN_FP_64")
+  (RVVM2DF "TARGET_VECTOR_ELEN_FP_64")
+  (RVVM4DF "TARGET_VECTOR_ELEN_FP_64")
+])
I'm afraid we need VLS modes as well here :)  And once we have those, we might
need to think about the naming, as LMUL might not make a lot of sense for e.g.
V4QI -> V8QI.  Maybe just V_DOUBLE?

Also, we already have VI_QHS_NO_M8.  You could re-use that and just add the
missing modes in a new combined iterator.

Then, HF modes, are these in scope?

+;; Zvzip v0.1 draft.
+(define_insn "@pred_vzip<mode>"
+  [(set (match_operand:<VLMUL_EXT2> 0 "register_operand"        "=&vr,  &vr")
+       (if_then_else:<VLMUL_EXT2>
+         (unspec:<VM>
+           [(match_operand:<VM> 1 "vector_mask_operand"       "vmWc1,vmWc1")
+            (match_operand 5 "vector_length_operand"          "  rvl,  rvl")
+            (match_operand 6 "const_int_operand"              "    i,    i")
+            (match_operand 7 "const_int_operand"              "    i,    i")
+            (match_operand 8 "const_int_operand"              "    i,    i")
+            (reg:SI VL_REGNUM)
+            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
+         (unspec:<VLMUL_EXT2>
+           [(match_operand:VLMULX2 3 "register_operand"       "   vr,   vr")
+            (match_operand:VLMULX2 4 "register_operand"       "   vr,   vr")] 
UNSPEC_VZIP)
+         (match_operand:<VLMUL_EXT2> 2 "vector_merge_operand" "   vu,    0")))]
+  "TARGET_ZVZIP"
+  "vzip.vv\t%0,%3,%4%p1"
+  [(set_attr "type" "vgather")
+   (set_attr "mode" "<MODE>")])
Does the vgather type work with a "widening" instruction type?  Like mode_idx
for example would come from operand[0] but operand[3] and operand[4] have
a smaller mode.  Such kinds of issues will likely only occur in more
complicated scenarios and might not be caught in simpler tests.

I guess the earlyclobber is alright for now, until we have more fine-grained
options.

+(define_insn "@pred_vunzipe<mode>"
+  [(set (match_operand:VLMULX2 0 "register_operand"             "=&vr,  &vr")
+       (if_then_else:VLMULX2
+         (unspec:<VM>
+           [(match_operand:<VM> 1 "vector_mask_operand"       "vmWc1,vmWc1")
+            (match_operand 4 "vector_length_operand"          "  rvl,  rvl")
+            (match_operand 5 "const_int_operand"              "    i,    i")
+            (match_operand 6 "const_int_operand"              "    i,    i")
+            (match_operand 7 "const_int_operand"              "    i,    i")
+            (reg:SI VL_REGNUM)
+            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
+         (unspec:VLMULX2
+           [(match_operand:<VLMUL_EXT2> 3 "register_operand"  "   vr,   vr")] 
UNSPEC_VUNZIPE)
+         (match_operand:VLMULX2 2 "vector_merge_operand"      "   vu,    0")))]
+  "TARGET_ZVZIP"
+  "vunzipe.v\t%0,%3%p1"
+  [(set_attr "type" "vgather")
+   (set_attr "mode" "<MODE>")
+   (set_attr "vl_op_idx" "4")
+   (set (attr "ta") (symbol_ref "riscv_vector::get_ta(operands[5])"))
+   (set (attr "ma") (symbol_ref "riscv_vector::get_ma(operands[6])"))
+   (set_attr "avl_type_idx" "7")])
Same question here about the attributes.  I haven't checked in detail, just
wanted to make sure.

Hi Robin,

Thanks for the suggestions, that makes sense.

I will rename the iterator/attribute so that the name no longer refers to
LMUL.  Something like V_DOUBLE_EXTENDABLE / V_DOUBLE_EXT should be clearer for
both scalable RVV modes and fixed-length VLS modes.

I will also add the VLS modes.  For the integer Q/H/S modes I will reuse the
existing VI_QHS_NO_M8 iterator and build a combined iterator for the remaining
modes that have a valid double-sized mode.

For the HF modes: I included them because Zvzip is a data movement/reordering
extension rather than an FP arithmetic extension, and the current intrinsic
document / LLVM draft API exposes f16 forms.  The modes will still be gated by the existing FP16 vector type availability.  If you prefer, I can add a comment
or split that out for easier review.

Regarding the attributes: yes, vzip is the special case.  The vtype/VL should be based on the source mode, not the 2xLMUL destination mode.  I will make this explicit instead of relying on the vgather defaults, e.g. by setting mode_idx to the source operand for vzip.  For vunzipe/vunzipo the destination mode is the mode used for vsetvl, so operand 0 is still the right mode, but I can set the
mode_idx explicitly there too for clarity.

I will also add tests that check the emitted vsetvli mode, for example making
sure vzip_i8m2 uses e8,m1 rather than e8,m2.

Best regards,
Jiawei


Reply via email to