From: Lino Hsing-Yu Peng Date: Tue, 9 Jun 2026 15:35:46 +0000 (-0600) Subject: [PATCH v3 2/9] RISC-V: Track altfmt in RVV vtype state X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=613a3462bb231131ece33dca5849749498dc019b;p=thirdparty%2Fgcc.git [PATCH v3 2/9] RISC-V: Track altfmt in RVV vtype state 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, vsetvl_vtype_change_only, @vsetvl_discard_result, @vsetvl_no_side_effects, *vsetvldi_no_side_effects_si_extend): Add altfmt operand. --- diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index 39cef861748..fa360157570 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -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)) diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc index 2f1d1be50d6..431aaa1e761 100644 --- a/gcc/config/riscv/riscv-v.cc +++ b/gcc/config/riscv/riscv-v.cc @@ -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. */ diff --git a/gcc/config/riscv/riscv-vector-builtins-bases.cc b/gcc/config/riscv/riscv-vector-builtins-bases.cc index 8f39a28856c..0ae9b34fa2b 100644 --- a/gcc/config/riscv/riscv-vector-builtins-bases.cc +++ b/gcc/config/riscv/riscv-vector-builtins-bases.cc @@ -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)); } }; diff --git a/gcc/config/riscv/riscv-vsetvl.cc b/gcc/config/riscv/riscv-vsetvl.cc index e10b5bc0413..4db4349a6e1 100644 --- a/gcc/config/riscv/riscv-vsetvl.cc +++ b/gcc/config/riscv/riscv-vsetvl.cc @@ -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)); } diff --git a/gcc/config/riscv/riscv-vsetvl.def b/gcc/config/riscv/riscv-vsetvl.def index c057ebd20a8..4b8b556ffac 100644 --- a/gcc/config/riscv/riscv-vsetvl.def +++ b/gcc/config/riscv/riscv-vsetvl.def @@ -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 diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md index dfd333f525e..fba631d670f 100644 --- a/gcc/config/riscv/vector.md +++ b/gcc/config/riscv/vector.md @@ -60,6 +60,12 @@ (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 @@ -1671,6 +1677,7 @@ ;; 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: @@ -1762,7 +1769,8 @@ (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) @@ -1771,15 +1779,22 @@ (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" "") (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. @@ -1789,15 +1804,22 @@ [(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 @@ -1811,15 +1833,22 @@ (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" "") (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", @@ -1830,22 +1859,25 @@ (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: @@ -1870,11 +1902,14 @@ [(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" @@ -1882,11 +1917,14 @@ (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 ""