]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[PATCH v3 2/9] RISC-V: Track altfmt in RVV vtype state
authorLino Hsing-Yu Peng <linopeng@andestech.com>
Tue, 9 Jun 2026 15:35:46 +0000 (09:35 -0600)
committerJeff Law <jeffrey.law@oss.qualcomm.com>
Tue, 9 Jun 2026 15:36:17 +0000 (09:36 -0600)
Zvfofp8min instructions use the VTYPE altfmt field to select the
alternate FP8 format.  Track altfmt in vsetvl_info so the vsetvl pass
does not merge or remove configurations that require different altfmt
values.

gcc/ChangeLog:

* config/riscv/riscv-protos.h (enum altfmt_type): New.
* config/riscv/riscv-v.cc (emit_hard_vlmax_vsetvl): Pass
ALTFMT_NONE to gen_vsetvl.
(gen_no_side_effects_vsetvl_rtx): Pass ALTFMT_NONE to
gen_vsetvl_no_side_effects.
* config/riscv/riscv-vector-builtins-bases.cc: Include insn-attr.h.
(vsetvl::expand): Pass ALTFMT_NONE to gen_vsetvl_no_side_effects.
* config/riscv/riscv-vsetvl.cc (altfmt_to_str): New function.
(get_altfmt): New function.
(demand_flags): Add DEMAND_ALTFMT_P.
(altfmt_demand_type): New enum.
(vsetvl_info): Track altfmt.
(demand_system): Add altfmt compatibility, availability, and merge handling.
* config/riscv/riscv-vsetvl.def: Add altfmt rules.
* config/riscv/vector.md (altfmt): New attribute, numeric with
INVALID_ATTRIBUTE default.
(@vsetvl<mode>, vsetvl_vtype_change_only,
@vsetvl_discard_result<mode>, @vsetvl<mode>_no_side_effects,
*vsetvldi_no_side_effects_si_extend): Add altfmt operand.

gcc/config/riscv/riscv-protos.h
gcc/config/riscv/riscv-v.cc
gcc/config/riscv/riscv-vector-builtins-bases.cc
gcc/config/riscv/riscv-vsetvl.cc
gcc/config/riscv/riscv-vsetvl.def
gcc/config/riscv/vector.md

index 39cef86174877f80fd8326e6ee8d26b973703c19..fa360157570aed8d2f6b4a8e8c638deab486b292 100644 (file)
@@ -661,6 +661,17 @@ enum mask_policy
   MASK_ANY = 2,
 };
 
+/* Values for the VTYPE altfmt field.  Instructions that do not care about
+   altfmt leave the "altfmt" insn attribute at its default (INVALID_ATTRIBUTE);
+   FP8 instructions select between standard (ALTFMT_NONE, E4M3) and the
+   alternate format (ALTFMT_ALT, E5M2) by setting the attribute via an
+   operand.  */
+enum altfmt_type
+{
+  ALTFMT_NONE = 0,
+  ALTFMT_ALT = 1,
+};
+
 /* Return true if VALUE is agnostic or any policy.  */
 #define IS_AGNOSTIC(VALUE) (bool) (VALUE & 0x1 || (VALUE >> 1 & 0x1))
 
index 2f1d1be50d69daf3f09b404f8384b9773e35574c..431aaa1e76165fd034cc410c075ca7148af2b150 100644 (file)
@@ -865,9 +865,10 @@ void
 emit_hard_vlmax_vsetvl (machine_mode vmode, rtx vl)
 {
   unsigned int sew = get_sew (vmode);
+  rtx altfmt = gen_int_mode (ALTFMT_NONE, Pmode);
   emit_insn (gen_vsetvl (Pmode, vl, RVV_VLMAX, gen_int_mode (sew, Pmode),
                         gen_int_mode (get_vlmul (vmode), Pmode), const0_rtx,
-                        const0_rtx));
+                        const0_rtx, altfmt));
 }
 
 void
@@ -2413,11 +2414,12 @@ rtx
 gen_no_side_effects_vsetvl_rtx (machine_mode vmode, rtx vl, rtx avl)
 {
   unsigned int sew = get_sew (vmode);
+  rtx altfmt = gen_int_mode (ALTFMT_NONE, Pmode);
   rtx tail_policy = gen_int_mode (get_prefer_tail_policy (), Pmode);
   rtx mask_policy = gen_int_mode (get_prefer_mask_policy (), Pmode);
   return gen_vsetvl_no_side_effects (Pmode, vl, avl, gen_int_mode (sew, Pmode),
                                     gen_int_mode (get_vlmul (vmode), Pmode),
-                                    tail_policy, mask_policy);
+                                    tail_policy, mask_policy, altfmt);
 }
 
 /* GET VL * 2 rtx.  */
index 8f39a28856c2f0c793953d9be151e70b22a541e2..0ae9b34fa2b678567168a01dd2058ae76f030bb7 100644 (file)
@@ -27,6 +27,7 @@
 #include "tm_p.h"
 #include "memmodel.h"
 #include "insn-codes.h"
+#include "riscv-protos.h"
 #include "optabs.h"
 #include "recog.h"
 #include "expr.h"
@@ -116,6 +117,10 @@ public:
     /* MASK_ANY.  */
     e.add_input_operand (Pmode,
                         gen_int_mode (get_prefer_mask_policy (), Pmode));
+
+    /* ALTFMT_NONE.  */
+    e.add_input_operand (Pmode, gen_int_mode (ALTFMT_NONE, Pmode));
+
     return e.generate_insn (code_for_vsetvl_no_side_effects (Pmode));
   }
 };
index e10b5bc0413388d6d964723b47c50e809dc10e47..4db4349a6e1d0dfd73d8ddafe8f0e46b5cf66fde 100644 (file)
@@ -257,6 +257,21 @@ policy_to_str (bool agnostic_p)
   return agnostic_p ? "agnostic" : "undisturbed";
 }
 
+/* Return a printable name for the VTYPE altfmt value ALTFMT.  */
+static const char *
+altfmt_to_str (uint8_t altfmt)
+{
+  switch (altfmt)
+    {
+    case ALTFMT_NONE:
+      return "none";
+    case ALTFMT_ALT:
+      return "alt";
+    default:
+      return "any";
+    }
+}
+
 /* Return true if it is an RVV instruction that depends on VTYPE global
    status register.  */
 bool
@@ -503,6 +518,15 @@ mask_agnostic_p (rtx_insn *rinsn)
   return ma == INVALID_ATTRIBUTE ? get_default_ma () : IS_AGNOSTIC (ma);
 }
 
+/* Return the alternate FP8 format requirement of RINSN.  INVALID_ATTRIBUTE
+   means that RINSN does not require a specific VTYPE altfmt value.  */
+static uint8_t
+get_altfmt (rtx_insn *rinsn)
+{
+  extract_insn_cached (rinsn);
+  return get_attr_altfmt (rinsn);
+}
+
 /* Return true if FN has a vector instruction that use VL/VTYPE.  */
 static bool
 has_vector_insn (function *fn)
@@ -819,19 +843,21 @@ enum demand_flags : unsigned
   DEMAND_MASK_POLICY_P = 1 << 5,
   DEMAND_AVL_P = 1 << 6,
   DEMAND_NON_ZERO_AVL_P = 1 << 7,
+  DEMAND_ALTFMT_P = 1 << 8,
 };
 
-/* We split the demand information into three parts.  They are sew and lmul
+/* We split the demand information into four parts.  They are sew and lmul
    related (sew_lmul_demand_type), tail and mask policy related
-   (policy_demand_type) and avl related (avl_demand_type). Then we define three
-   interfaces available_p, compatible_p and merge. available_p is
-   used to determine whether the two vsetvl infos prev_info and next_info are
-   available or not.  If prev_info is available for next_info, it means that the
-   RVV insn corresponding to next_info on the path from prev_info to next_info
-   can be used without inserting a separate vsetvl instruction. compatible_p
-   is used to determine whether prev_info is compatible with next_info, and if
-   so, merge can be used to merge the stricter demand information from
-   next_info into prev_info so that prev_info becomes available to next_info.
+   (policy_demand_type), avl related (avl_demand_type) and alternate FP8 format
+   related (altfmt_demand_type).  Then we define three interfaces available_p,
+   compatible_p and merge.  available_p is used to determine whether the two
+   vsetvl infos prev_info and next_info are available or not.  If prev_info is
+   available for next_info, it means that the RVV insn corresponding to
+   next_info on the path from prev_info to next_info can be used without
+   inserting a separate vsetvl instruction.  compatible_p is used to determine
+   whether prev_info is compatible with next_info, and if so, merge can be used
+   to merge the stricter demand information from next_info into prev_info so
+   that prev_info becomes available to next_info.
  */
 
 enum class sew_lmul_demand_type : unsigned
@@ -860,6 +886,12 @@ enum class avl_demand_type : unsigned
   ignore_avl = demand_flags::DEMAND_EMPTY_P,
 };
 
+enum class altfmt_demand_type : unsigned
+{
+  altfmt = demand_flags::DEMAND_ALTFMT_P,
+  ignore_altfmt = demand_flags::DEMAND_EMPTY_P,
+};
+
 /* Go through all uses of INSN looking for a single use of register REG.
    Return true if we find
     - Uses in a non-RVV insn
@@ -904,10 +936,12 @@ private:
   uint8_t m_ratio;
   bool m_ta;
   bool m_ma;
+  uint8_t m_altfmt;
 
   sew_lmul_demand_type m_sew_lmul_demand;
   policy_demand_type m_policy_demand;
   avl_demand_type m_avl_demand;
+  altfmt_demand_type m_altfmt_demand;
 
   enum class state_type
   {
@@ -927,11 +961,13 @@ public:
   vsetvl_info ()
     : m_insn (nullptr), m_bb (nullptr), m_avl (NULL_RTX), m_vl (NULL_RTX),
       m_avl_def (nullptr), m_sew (0), m_max_sew (0), m_vlmul (LMUL_RESERVED),
-      m_ratio (0), m_ta (false), m_ma (false),
+      m_ratio (0), m_ta (false), m_ma (false), m_altfmt (ALTFMT_NONE),
       m_sew_lmul_demand (sew_lmul_demand_type::sew_lmul),
       m_policy_demand (policy_demand_type::tail_mask_policy),
-      m_avl_demand (avl_demand_type::avl), m_state (state_type::UNINITIALIZED),
-      m_delete (false), m_change_vtype_only (false), m_read_vl_insn (nullptr),
+      m_avl_demand (avl_demand_type::avl),
+      m_altfmt_demand (altfmt_demand_type::altfmt),
+      m_state (state_type::UNINITIALIZED), m_delete (false),
+      m_change_vtype_only (false), m_read_vl_insn (nullptr),
       m_vl_used_by_non_rvv_insn (false)
   {}
 
@@ -952,6 +988,7 @@ public:
   void set_max_sew (uint8_t max_sew) { m_max_sew = max_sew; }
   void set_change_vtype_only () { m_change_vtype_only = true; }
   void set_read_vl_insn (insn_info *insn) { m_read_vl_insn = insn; }
+  void set_altfmt (uint8_t altfmt) { m_altfmt = altfmt; }
 
   rtx get_avl () const { return m_avl; }
   rtx get_vl () const { return m_vl; }
@@ -959,6 +996,7 @@ public:
   uint8_t get_sew () const { return m_sew; }
   vlmul_type get_vlmul () const { return m_vlmul; }
   uint8_t get_ratio () const { return m_ratio; }
+  uint8_t get_altfmt () const { return m_altfmt; }
   bool get_ta () const { return m_ta; }
   bool get_ma () const { return m_ma; }
   insn_info *get_insn () const { return m_insn; }
@@ -1034,8 +1072,13 @@ public:
   {
     return m_sew_lmul_demand;
   }
+  void set_altfmt_demand (altfmt_demand_type demand)
+  {
+    m_altfmt_demand = demand;
+  }
   policy_demand_type get_policy_demand () const { return m_policy_demand; }
   avl_demand_type get_avl_demand () const { return m_avl_demand; }
+  altfmt_demand_type get_altfmt_demand () const { return m_altfmt_demand; }
 
   void normalize_demand (unsigned demand_flags)
   {
@@ -1093,6 +1136,18 @@ public:
       default:
        gcc_unreachable ();
       }
+
+    switch (demand_flags & DEMAND_ALTFMT_P)
+      {
+      case (unsigned) altfmt_demand_type::altfmt:
+       m_altfmt_demand = altfmt_demand_type::altfmt;
+       break;
+      case (unsigned) altfmt_demand_type::ignore_altfmt:
+       m_altfmt_demand = altfmt_demand_type::ignore_altfmt;
+       break;
+      default:
+       gcc_unreachable ();
+      }
   }
 
   void parse_insn (rtx_insn *rinsn)
@@ -1111,6 +1166,10 @@ public:
     m_vlmul = ::get_vlmul (rinsn);
     m_ta = tail_agnostic_p (rinsn);
     m_ma = mask_agnostic_p (rinsn);
+    m_altfmt = ::get_altfmt (rinsn);
+    m_altfmt_demand = m_altfmt == INVALID_ATTRIBUTE
+                       ? altfmt_demand_type::ignore_altfmt
+                       : altfmt_demand_type::altfmt;
   }
 
   void parse_insn (insn_info *insn)
@@ -1171,6 +1230,7 @@ public:
       m_ratio = calculate_ratio (m_sew, m_vlmul);
     m_ta = tail_agnostic_p (insn->rtl ());
     m_ma = mask_agnostic_p (insn->rtl ());
+    m_altfmt = ::get_altfmt (insn->rtl ());
 
     /* If merge operand is undef value, we prefer agnostic.  */
     int merge_op_idx = get_attr_merge_op_idx (insn->rtl ());
@@ -1235,6 +1295,9 @@ public:
          dflags |= demand_flags::DEMAND_MASK_POLICY_P;
       }
 
+    if (m_altfmt != INVALID_ATTRIBUTE)
+      dflags |= demand_flags::DEMAND_ALTFMT_P;
+
     normalize_demand (dflags);
 
     /* Optimize AVL from the vsetvl instruction.  */
@@ -1293,13 +1356,17 @@ public:
     rtx vlmul = gen_int_mode (get_vlmul (), Pmode);
     rtx ta = gen_int_mode (get_ta (), Pmode);
     rtx ma = gen_int_mode (get_ma (), Pmode);
+    /* If this vsetvl_info has no specific altfmt demand, default to
+       ALTFMT_NONE.  */
+    rtx altfmt = gen_int_mode (
+      get_altfmt () == ALTFMT_ALT ? ALTFMT_ALT : ALTFMT_NONE, Pmode);
 
     if (change_vtype_only_p ())
-      return gen_vsetvl_vtype_change_only (sew, vlmul, ta, ma);
+      return gen_vsetvl_vtype_change_only (sew, vlmul, ta, ma, altfmt);
     else if (has_vl () && !ignore_vl)
-      return gen_vsetvl (Pmode, get_vl (), avl, sew, vlmul, ta, ma);
+      return gen_vsetvl (Pmode, get_vl (), avl, sew, vlmul, ta, ma, altfmt);
     else
-      return gen_vsetvl_discard_result (Pmode, avl, sew, vlmul, ta, ma);
+      return gen_vsetvl_discard_result (Pmode, avl, sew, vlmul, ta, ma, altfmt);
   }
 
   /* Return true that the non-AVL operands of THIS will be modified
@@ -1339,9 +1406,11 @@ public:
           && get_sew () == other.get_sew ()
           && get_vlmul () == other.get_vlmul () && get_ta () == other.get_ta ()
           && get_ma () == other.get_ma ()
+          && get_altfmt () == other.get_altfmt ()
           && get_avl_demand () == other.get_avl_demand ()
           && get_sew_lmul_demand () == other.get_sew_lmul_demand ()
-          && get_policy_demand () == other.get_policy_demand ();
+          && get_policy_demand () == other.get_policy_demand ()
+          && get_altfmt_demand () == other.get_altfmt_demand ();
   }
 
   void dump (FILE *file, const char *indent = "") const
@@ -1390,6 +1459,9 @@ public:
       fprintf (file, " demand_avl");
     else if (m_avl_demand == avl_demand_type::non_zero_avl)
       fprintf (file, " demand_non_zero_avl");
+
+    if (m_altfmt_demand == altfmt_demand_type::altfmt)
+      fprintf (file, " demand_altfmt");
     fprintf (file, "\n");
 
     fprintf (file, "%sSEW=%d, ", indent, get_sew ());
@@ -1398,7 +1470,8 @@ public:
     fprintf (file, "MAX_SEW=%d\n", get_max_sew ());
 
     fprintf (file, "%sTAIL_POLICY=%s, ", indent, policy_to_str (get_ta ()));
-    fprintf (file, "MASK_POLICY=%s\n", policy_to_str (get_ma ()));
+    fprintf (file, "MASK_POLICY=%s, ", policy_to_str (get_ma ()));
+    fprintf (file, "ALTFMT=%s\n", altfmt_to_str (get_altfmt ()));
 
     fprintf (file, "%sAVL=", indent);
     print_rtl_single (file, get_avl ());
@@ -1671,6 +1744,13 @@ private:
     return tail_policy_eq_p (prev, next) && mask_policy_eq_p (prev, next);
   }
 
+  /* Predictors for altfmt.  */
+
+  inline bool altfmt_eq_p (const vsetvl_info &prev, const vsetvl_info &next)
+  {
+    return prev.get_altfmt () == next.get_altfmt ();
+  }
+
   /* predictors for avl */
 
   inline bool modify_or_use_vl_p (insn_info *i, const vsetvl_info &info)
@@ -1918,6 +1998,13 @@ private:
     use_mask_policy (prev, next);
   }
 
+  /* Modifiers for altfmt.  */
+
+  inline void use_next_altfmt (vsetvl_info &prev, const vsetvl_info &next)
+  {
+    prev.set_altfmt (next.get_altfmt ());
+  }
+
   /* modifiers for avl */
 
   inline void use_next_avl (vsetvl_info &prev, const vsetvl_info &next)
@@ -2153,6 +2240,59 @@ public:
       return;                                                                  \
     }
 
+#include "riscv-vsetvl.def"
+
+    gcc_unreachable ();
+  }
+
+  bool altfmt_compatible_p (const vsetvl_info &prev, const vsetvl_info &next)
+  {
+    gcc_assert (prev.valid_p () && next.valid_p ());
+    altfmt_demand_type prev_flags = prev.get_altfmt_demand ();
+    altfmt_demand_type next_flags = next.get_altfmt_demand ();
+#define DEF_ALTFMT_RULE(PREV_FLAGS, NEXT_FLAGS, NEW_FLAGS, COMPATIBLE_P,       \
+                       AVAILABLE_P, FUSE)                                     \
+  if (prev_flags == altfmt_demand_type::PREV_FLAGS                             \
+      && next_flags == altfmt_demand_type::NEXT_FLAGS)                         \
+    return COMPATIBLE_P (prev, next);
+
+#include "riscv-vsetvl.def"
+
+    gcc_unreachable ();
+  }
+
+  bool altfmt_available_p (const vsetvl_info &prev, const vsetvl_info &next)
+  {
+    gcc_assert (prev.valid_p () && next.valid_p ());
+    altfmt_demand_type prev_flags = prev.get_altfmt_demand ();
+    altfmt_demand_type next_flags = next.get_altfmt_demand ();
+#define DEF_ALTFMT_RULE(PREV_FLAGS, NEXT_FLAGS, NEW_FLAGS, COMPATIBLE_P,       \
+                       AVAILABLE_P, FUSE)                                     \
+  if (prev_flags == altfmt_demand_type::PREV_FLAGS                             \
+      && next_flags == altfmt_demand_type::NEXT_FLAGS)                         \
+    return AVAILABLE_P (prev, next);
+
+#include "riscv-vsetvl.def"
+
+    gcc_unreachable ();
+  }
+
+  void merge_altfmt (vsetvl_info &prev, const vsetvl_info &next)
+  {
+    gcc_assert (prev.valid_p () && next.valid_p ());
+    altfmt_demand_type prev_flags = prev.get_altfmt_demand ();
+    altfmt_demand_type next_flags = next.get_altfmt_demand ();
+#define DEF_ALTFMT_RULE(PREV_FLAGS, NEXT_FLAGS, NEW_FLAGS, COMPATIBLE_P,       \
+                       AVAILABLE_P, FUSE)                                     \
+  if (prev_flags == altfmt_demand_type::PREV_FLAGS                             \
+      && next_flags == altfmt_demand_type::NEXT_FLAGS)                         \
+    {                                                                          \
+      gcc_assert (COMPATIBLE_P (prev, next));                                  \
+      FUSE (prev, next);                                                       \
+      prev.set_altfmt_demand (altfmt_demand_type::NEW_FLAGS);                  \
+      return;                                                                  \
+    }
+
 #include "riscv-vsetvl.def"
 
     gcc_unreachable ();
@@ -2227,19 +2367,19 @@ public:
 
   bool compatible_p (const vsetvl_info &prev, const vsetvl_info &next)
   {
-    bool compatible_p = sew_lmul_compatible_p (prev, next)
-                       && policy_compatible_p (prev, next)
-                       && avl_compatible_p (prev, next)
-                       && vl_not_in_conflict_p (prev, next);
+    bool compatible_p
+      = sew_lmul_compatible_p (prev, next) && policy_compatible_p (prev, next)
+       && altfmt_compatible_p (prev, next) && avl_compatible_p (prev, next)
+       && vl_not_in_conflict_p (prev, next);
     return compatible_p;
   }
 
   bool available_p (const vsetvl_info &prev, const vsetvl_info &next)
   {
-    bool available_p = sew_lmul_available_p (prev, next)
-                      && policy_available_p (prev, next)
-                      && avl_available_p (prev, next)
-                      && vl_not_in_conflict_p (prev, next);
+    bool available_p
+      = sew_lmul_available_p (prev, next) && policy_available_p (prev, next)
+       && altfmt_available_p (prev, next) && avl_available_p (prev, next)
+       && vl_not_in_conflict_p (prev, next);
     gcc_assert (!available_p || compatible_p (prev, next));
     return available_p;
   }
@@ -2249,6 +2389,7 @@ public:
     gcc_assert (compatible_p (prev, next));
     merge_sew_lmul (prev, next);
     merge_policy (prev, next);
+    merge_altfmt (prev, next);
     merge_avl (prev, next);
     gcc_assert (available_p (prev, next));
   }
index c057ebd20a8c243ea6a96148bccf3b63f36fccbd..4b8b556ffac49ca21f53f5f83719529f5b8ec711 100644 (file)
@@ -43,6 +43,11 @@ along with GCC; see the file COPYING3.  If not see
                     available_p, fuse)
 #endif
 
+#ifndef DEF_ALTFMT_RULE
+#define DEF_ALTFMT_RULE(prev_demand, next_demand, fused_demand, compatible_p,  \
+                       available_p, fuse)
+#endif
+
 /* Define SEW and LMUL rules.  */
 DEF_SEW_LMUL_RULE (sew_lmul, sew_lmul, sew_lmul, sew_lmul_eq_p, sew_lmul_eq_p,
                   nop)
@@ -175,6 +180,16 @@ DEF_AVL_RULE (ignore_avl, non_zero_avl, non_zero_avl, can_use_next_avl_p,
              always_false, use_next_avl)
 DEF_AVL_RULE (ignore_avl, ignore_avl, ignore_avl, always_true, always_true, nop)
 
+/* Define ALTFMT compatible and merge rules.  */
+
+DEF_ALTFMT_RULE (altfmt, altfmt, altfmt, altfmt_eq_p, altfmt_eq_p, nop)
+DEF_ALTFMT_RULE (altfmt, ignore_altfmt, altfmt, always_true, always_true, nop)
+DEF_ALTFMT_RULE (ignore_altfmt, altfmt, altfmt, always_true, always_false,
+                use_next_altfmt)
+DEF_ALTFMT_RULE (ignore_altfmt, ignore_altfmt, ignore_altfmt, always_true,
+                always_true, nop)
+
 #undef DEF_SEW_LMUL_RULE
 #undef DEF_POLICY_RULE
 #undef DEF_AVL_RULE
+#undef DEF_ALTFMT_RULE
index dfd333f525e85b1c4685c79f4b67f5ba0cc9ed18..fba631d670f61d88d56403a2291b6bfb63143991 100644 (file)
         (const_string "true")]
        (const_string "false")))
 
+;; Alternate FP8 format requirement.  Most instructions do not care, so
+;; the attribute defaults to INVALID_ATTRIBUTE; FP8 instructions set it to
+;; ALTFMT_NONE (E4M3) or ALTFMT_ALT (E5M2) via an operand.
+(define_attr "altfmt" ""
+  (const_int INVALID_ATTRIBUTE))
+
 ;; True if the type is RVV instructions that include VL
 ;; global status register in the use op list.
 ;; The instruction need vector length to be specified is set
 ;; operands[3]: LMUL
 ;; operands[4]: Tail policy 0 or 1 (undisturbed/agnostic)
 ;; operands[5]: Mask policy 0 or 1 (undisturbed/agnostic)
+;; operands[6]: ALTFMT 0 or 1 (none/alt)
 
 ;; We define 2 types of "vsetvl*" instruction patterns:
 
                   (match_operand 2 "const_int_operand" "i")
                   (match_operand 3 "const_int_operand" "i")
                   (match_operand 4 "const_int_operand" "i")
-                  (match_operand 5 "const_int_operand" "i")] UNSPEC_VSETVL))
+                  (match_operand 5 "const_int_operand" "i")
+                  (match_operand 6 "const_int_operand" "i")] UNSPEC_VSETVL))
    (set (reg:SI VL_REGNUM)
        (unspec:SI [(match_dup 1)
                    (match_dup 2)
        (unspec:SI [(match_dup 2)
                    (match_dup 3)
                    (match_dup 4)
-                   (match_dup 5)] UNSPEC_VSETVL))]
+                   (match_dup 5)
+                   (match_dup 6)] UNSPEC_VSETVL))]
   "TARGET_VECTOR"
-  "vset%i1vli\t%0,%1,e%2,%m3,t%p4,m%p5"
+  {
+    if (INTVAL (operands[6]) == riscv_vector::ALTFMT_ALT)
+      return "vset%i1vli\t%0,%1,e%2alt,%m3,t%p4,m%p5";
+    return "vset%i1vli\t%0,%1,e%2,%m3,t%p4,m%p5";
+  }
   [(set_attr "type" "vsetvl")
    (set_attr "mode" "<MODE>")
    (set (attr "sew") (symbol_ref "INTVAL (operands[2])"))
    (set (attr "vlmul") (symbol_ref "INTVAL (operands[3])"))
    (set (attr "ta") (symbol_ref "INTVAL (operands[4])"))
-   (set (attr "ma") (symbol_ref "INTVAL (operands[5])"))])
+   (set (attr "ma") (symbol_ref "INTVAL (operands[5])"))
+   (set (attr "altfmt")
+       (symbol_ref "INTVAL (operands[6])"))])
 
 ;; vsetvl zero,zero,vtype instruction.
 ;; This pattern has no side effects and does not set X0 register.
          [(match_operand 0 "const_int_operand" "i")
           (match_operand 1 "const_int_operand" "i")
           (match_operand 2 "const_int_operand" "i")
-          (match_operand 3 "const_int_operand" "i")] UNSPEC_VSETVL))]
+          (match_operand 3 "const_int_operand" "i")
+          (match_operand 4 "const_int_operand" "i")] UNSPEC_VSETVL))]
   "TARGET_VECTOR"
-  "vsetvli\tzero,zero,e%0,%m1,t%p2,m%p3"
+  {
+    if (INTVAL (operands[4]) == riscv_vector::ALTFMT_ALT)
+      return "vsetvli\tzero,zero,e%0alt,%m1,t%p2,m%p3";
+    return "vsetvli\tzero,zero,e%0,%m1,t%p2,m%p3";
+  }
   [(set_attr "type" "vsetvl")
    (set_attr "mode" "SI")
    (set (attr "sew") (symbol_ref "INTVAL (operands[0])"))
    (set (attr "vlmul") (symbol_ref "INTVAL (operands[1])"))
    (set (attr "ta") (symbol_ref "INTVAL (operands[2])"))
-   (set (attr "ma") (symbol_ref "INTVAL (operands[3])"))])
+   (set (attr "ma") (symbol_ref "INTVAL (operands[3])"))
+   (set (attr "altfmt")
+       (symbol_ref "INTVAL (operands[4])"))])
 
 ;; vsetvl zero,rs1,vtype instruction.
 ;; The reason we need this pattern since we should avoid setting X0 register
        (unspec:SI [(match_dup 1)
                    (match_dup 2)
                    (match_operand 3 "const_int_operand" "i")
-                   (match_operand 4 "const_int_operand" "i")] UNSPEC_VSETVL))]
+                   (match_operand 4 "const_int_operand" "i")
+                   (match_operand 5 "const_int_operand" "i")] UNSPEC_VSETVL))]
   "TARGET_VECTOR"
-  "vset%i0vli\tzero,%0,e%1,%m2,t%p3,m%p4"
+  {
+    if (INTVAL (operands[5]) == riscv_vector::ALTFMT_ALT)
+      return "vset%i0vli\tzero,%0,e%1alt,%m2,t%p3,m%p4";
+    return "vset%i0vli\tzero,%0,e%1,%m2,t%p3,m%p4";
+  }
   [(set_attr "type" "vsetvl")
    (set_attr "mode" "<MODE>")
    (set (attr "sew") (symbol_ref "INTVAL (operands[1])"))
    (set (attr "vlmul") (symbol_ref "INTVAL (operands[2])"))
    (set (attr "ta") (symbol_ref "INTVAL (operands[3])"))
-   (set (attr "ma") (symbol_ref "INTVAL (operands[4])"))])
+   (set (attr "ma") (symbol_ref "INTVAL (operands[4])"))
+   (set (attr "altfmt")
+       (symbol_ref "INTVAL (operands[5])"))])
 
 ;; It's emit by vsetvl/vsetvlmax intrinsics with no side effects.
 ;; Since we have many optimization passes from "expand" to "reload_completed",
                   (match_operand 2 "const_int_operand" "i")
                   (match_operand 3 "const_int_operand" "i")
                   (match_operand 4 "const_int_operand" "i")
-                  (match_operand 5 "const_int_operand" "i")] UNSPEC_VSETVL))]
+                  (match_operand 5 "const_int_operand" "i")
+                  (match_operand 6 "const_int_operand" "i")] UNSPEC_VSETVL))]
   "TARGET_VECTOR"
   "#"
   "&& epilogue_completed"
   [(parallel
     [(set (match_dup 0)
          (unspec:P [(match_dup 1) (match_dup 2) (match_dup 3)
-                    (match_dup 4) (match_dup 5)] UNSPEC_VSETVL))
+                    (match_dup 4) (match_dup 5) (match_dup 6)] UNSPEC_VSETVL))
      (set (reg:SI VL_REGNUM)
          (unspec:SI [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPEC_VSETVL))
      (set (reg:SI VTYPE_REGNUM)
          (unspec:SI [(match_dup 2) (match_dup 3) (match_dup 4)
-                     (match_dup 5)] UNSPEC_VSETVL))])]
+                     (match_dup 5) (match_dup 6)] UNSPEC_VSETVL))])]
   ""
   [(set_attr "type" "vsetvl")
-   (set_attr "mode" "SI")])
+   (set_attr "mode" "SI")
+   (set (attr "altfmt")
+       (symbol_ref "INTVAL (operands[6])"))])
 
 ;; This pattern use to combine below two insns and then further remove
 ;; unnecessary sign_extend operations:
   [(set (match_operand:DI 0 "register_operand")
         (sign_extend:DI
           (subreg:SI
-           (unspec:DI [(match_operand:P 1 "vector_length_operand")
-                       (match_operand 2 "const_int_operand")
-                       (match_operand 3 "const_int_operand")
-                       (match_operand 4 "const_int_operand")
-                       (match_operand 5 "const_int_operand")] UNSPEC_VSETVL) 0)))]
+                   (unspec:DI
+                     [(match_operand:P 1 "vector_length_operand")
+                      (match_operand 2 "const_int_operand")
+                      (match_operand 3 "const_int_operand")
+                      (match_operand 4 "const_int_operand")
+                      (match_operand 5 "const_int_operand")
+                      (match_operand 6 "const_int_operand")]
+                     UNSPEC_VSETVL) 0)))]
   "TARGET_VECTOR && TARGET_64BIT"
   "#"
   "&& 1"
         (unspec:DI [(match_dup 1)
                     (match_dup 2)
                     (match_dup 3)
-                    (match_dup 4)
-                    (match_dup 5)] UNSPEC_VSETVL))]
+                   (match_dup 4)
+                   (match_dup 5)
+                   (match_dup 6)] UNSPEC_VSETVL))]
   ""
   [(set_attr "type" "vsetvl")
-   (set_attr "mode" "SI")])
+   (set_attr "mode" "SI")
+   (set (attr "altfmt")
+       (symbol_ref "INTVAL (operands[6])"))])
 
 ;; RVV machine description matching format
 ;; (define_insn ""