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
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)
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
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
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
{
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)
{}
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; }
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; }
{
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)
{
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)
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)
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 ());
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. */
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
&& 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
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 ());
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 ());
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)
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)
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 ();
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;
}
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));
}
(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 ""