return vlmax_avl_type_p (rinsn) && tail_agnostic_p (rinsn);
}
+static machine_mode
+get_insn_vtype_mode (rtx_insn *rinsn)
+{
+ extract_insn_cached (rinsn);
+ int mode_idx = get_attr_mode_idx (rinsn);
+ gcc_assert (mode_idx != INVALID_ATTRIBUTE);
+ return GET_MODE (recog_data.operand[mode_idx]);
+}
+
+static void
+simplify_replace_vlmax_avl (rtx_insn *rinsn, rtx new_avl)
+{
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nPropagating AVL: ");
+ print_rtl_single (dump_file, new_avl);
+ fprintf (dump_file, "into: ");
+ print_rtl_single (dump_file, rinsn);
+ }
+ /* Replace AVL operand. */
+ extract_insn_cached (rinsn);
+ rtx avl = recog_data.operand[get_attr_vl_op_idx (rinsn)];
+ int count = count_regno_occurrences (rinsn, REGNO (avl));
+ gcc_assert (count == 1);
+ rtx new_pat = simplify_replace_rtx (PATTERN (rinsn), avl, new_avl);
+ validate_change_or_fail (rinsn, &PATTERN (rinsn), new_pat, false);
+
+ /* Change AVL TYPE into NONVLMAX if it is VLMAX. */
+ if (vlmax_avl_type_p (rinsn))
+ {
+ int index = get_attr_avl_type_idx (rinsn);
+ gcc_assert (index != INVALID_ATTRIBUTE);
+ validate_change_or_fail (rinsn, recog_data.operand_loc[index],
+ get_avl_type_rtx (avl_type::NONVLMAX), false);
+ }
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Successfully to match this instruction: ");
+ print_rtl_single (dump_file, rinsn);
+ }
+}
+
const pass_data pass_data_avlprop = {
RTL_PASS, /* type */
"avlprop", /* name */
for (const auto prop : *m_avl_propagations)
{
rtx_insn *rinsn = prop.first->rtl ();
+ simplify_replace_vlmax_avl (rinsn, prop.second);
+ }
+
+ if (riscv_autovec_preference == RVV_FIXED_VLMAX)
+ {
+ /* Simplify VLMAX AVL into immediate AVL.
+ E.g. Simplify this following case:
+
+ vsetvl a5, zero, e32, m1
+ vadd.vv
+
+ into:
+
+ vsetvl zero, 4, e32, m1
+ vadd.vv
+ if GET_MODE_NUNITS (RVVM1SImode) == 4. */
if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "\nSimplifying VLMAX AVL into IMM AVL\n\n");
+ for (auto &candidate : m_candidates)
{
- fprintf (dump_file, "\nPropagating AVL: ");
- print_rtl_single (dump_file, prop.second);
- fprintf (dump_file, "into: ");
- print_rtl_single (dump_file, rinsn);
- }
- /* Replace AVL operand. */
- extract_insn_cached (rinsn);
- rtx avl = recog_data.operand[get_attr_vl_op_idx (rinsn)];
- int count = count_regno_occurrences (rinsn, REGNO (avl));
- gcc_assert (count == 1);
- rtx new_pat = simplify_replace_rtx (PATTERN (rinsn), avl, prop.second);
- validate_change_or_fail (rinsn, &PATTERN (rinsn), new_pat, false);
-
- /* Change AVL TYPE into NONVLMAX if it is VLMAX. */
- if (vlmax_avl_type_p (rinsn))
- {
- int index = get_attr_avl_type_idx (rinsn);
- gcc_assert (index != INVALID_ATTRIBUTE);
- validate_change_or_fail (rinsn, recog_data.operand_loc[index],
- get_avl_type_rtx (avl_type::NONVLMAX),
- false);
- }
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "Successfully to match this instruction: ");
- print_rtl_single (dump_file, rinsn);
+ rtx_insn *rinsn = candidate.second->rtl ();
+ machine_mode vtype_mode = get_insn_vtype_mode (rinsn);
+ if (candidate.first == AVLPROP_VLMAX_TA
+ && !m_avl_propagations->get (candidate.second)
+ && imm_avl_p (vtype_mode))
+ {
+ rtx new_avl = gen_int_mode (GET_MODE_NUNITS (vtype_mode), Pmode);
+ simplify_replace_vlmax_avl (rinsn, new_avl);
+ }
}
}
uint8_t get_sew (rtx_insn *);
enum vlmul_type get_vlmul (rtx_insn *);
int count_regno_occurrences (rtx_insn *, unsigned int);
+bool imm_avl_p (machine_mode);
}
/* We classify builtin types into two classes:
namespace riscv_vector {
-/* Return true if vlmax is constant value and can be used in vsetivl. */
-static bool
-const_vlmax_p (machine_mode mode)
+/* Return true if NUNTIS <=31 so that we can use immediate AVL in vsetivli. */
+bool
+imm_avl_p (machine_mode mode)
{
- poly_uint64 nuints = GET_MODE_NUNITS (mode);
+ poly_uint64 nunits = GET_MODE_NUNITS (mode);
- return nuints.is_constant ()
- /* The vsetivli can only hold register 0~31. */
- ? (IN_RANGE (nuints.to_constant (), 0, 31))
- /* Only allowed in VLS-VLMAX mode. */
- : false;
+ return nunits.is_constant ()
+ /* The vsetivli can only hold register 0~31. */
+ ? (IN_RANGE (nunits.to_constant (), 0, 31))
+ /* Only allowed in VLS-VLMAX mode. */
+ : false;
}
/* Helper functions for insn_flags && insn_types */
len = force_reg (Pmode, len);
vls_p = true;
}
- else if (const_vlmax_p (vtype_mode))
- {
- /* Optimize VLS-VLMAX code gen, we can use vsetivli instead of
- the vsetvli to obtain the value of vlmax. */
- poly_uint64 nunits = GET_MODE_NUNITS (vtype_mode);
- len = gen_int_mode (nunits, Pmode);
- vls_p = true;
- }
else if (can_create_pseudo_p ())
{
len = gen_reg_rtx (Pmode);
emit_vlmax_insn (unsigned icode, unsigned insn_flags, rtx *ops)
{
insn_expander<RVV_INSN_OPERANDS_MAX> e (insn_flags, true);
- gcc_assert (can_create_pseudo_p () || const_vlmax_p (e.get_vtype_mode (ops)));
+ gcc_assert (can_create_pseudo_p () || imm_avl_p (e.get_vtype_mode (ops)));
e.emit_insn ((enum insn_code) icode, ops);
}
(const_int 5)]
(const_int INVALID_ATTRIBUTE)))
+;; The index of operand[] represents the machine mode of the instruction.
+(define_attr "mode_idx" ""
+ (cond [(eq_attr "type" "vlde,vste,vldm,vstm,vlds,vsts,vldux,vldox,vldff,vldr,vstr,\
+ vlsegde,vlsegds,vlsegdux,vlsegdox,vlsegdff,vialu,vext,vicalu,\
+ vshift,vicmp,viminmax,vimul,vidiv,vimuladd,vimerge,vimov,\
+ vsalu,vaalu,vsmul,vsshift,vfalu,vfmul,vfdiv,vfmuladd,vfsqrt,vfrecp,\
+ vfcmp,vfminmax,vfsgnj,vfclass,vfmerge,vfmov,\
+ vfcvtitof,vfncvtitof,vfncvtftoi,vfncvtftof,vmalu,vmiota,vmidx,\
+ vimovxv,vfmovfv,vslideup,vslidedown,vislide1up,vislide1down,vfslide1up,vfslide1down,\
+ vgather,vcompress,vmov,vnclip,vnshift")
+ (const_int 0)
+
+ (eq_attr "type" "vimovvx,vfmovvf")
+ (const_int 1)
+
+ (eq_attr "type" "vssegte,vmpop,vmffs")
+ (const_int 2)
+
+ (eq_attr "type" "vstux,vstox,vssegts,vssegtux,vssegtox,vfcvtftoi,vfwcvtitof,vfwcvtftoi,
+ vfwcvtftof,vmsfs,vired,viwred,vfredu,vfredo,vfwredu,vfwredo")
+ (const_int 3)
+
+ (eq_attr "type" "viwalu,viwmul,viwmuladd,vfwalu,vfwmul,vfwmuladd")
+ (const_int 4)]
+ (const_int INVALID_ATTRIBUTE)))
+
;; The index of operand[] to get the avl op.
(define_attr "vl_op_idx" ""
(cond [(eq_attr "type" "vlde,vste,vimov,vfmov,vldm,vstm,vmalu,vsts,vstux,\
}
[(set_attr "type" "vmov,vlde,vste")
(set_attr "mode" "<VT:MODE>")
- (set (attr "avl_type_idx") (const_int INVALID_ATTRIBUTE))])
+ (set (attr "avl_type_idx") (const_int INVALID_ATTRIBUTE))
+ (set (attr "mode_idx") (const_int INVALID_ATTRIBUTE))])
;; -----------------------------------------------------------------
;; ---- VLS Moves Operations
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -O3 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+void
+f (int *__restrict y, int *__restrict x, int *__restrict z, int n)
+{
+ for (int i = 0; i < n; ++i)
+ x[i] = y[i] + x[i];
+}
+
+/* { dg-final { scan-assembler-times {vsetvli} 1 } } */
+/* { dg-final { scan-assembler-not {vsetivli} } } */
+/* { dg-final { scan-assembler-times {vsetvli\s*[a-x0-9]+,\s*[a-x0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {vsetvli\s*[a-x0-9]+,\s*zero} } } */
+/* { dg-final { scan-assembler-not {vsetvli\s*zero} } } */
+/* { dg-final { scan-assembler-not {vsetivli\s*zero} } } */