Add an RVV-specific loop-overhead comparison in the RISC-V cost model and
use it after inside-loop cost comparison.
The RISC-V implementation prefers RVV mode that eliminate the main
loop, and otherwise compares their main-loop head overhead.
Local testing shows no regressions. This is likely because few testcases
have equal inside-loop cost, especially before VLS lmul cost scaling support.
I also ran regression tests with temporary VLS lmul cost scaling support.
Only 3 regressions found:
- dyn-lmul-conv-1.c & dyn-lmul-conv-2.c: Cost model now prefers smaller LMULs
due to VLS lmul scaling, so this is reasonable, just need to update
expectations.
- pr123414.c: This test relies on large LMULs to trigger a specific bug,
so reasonable too, can be fixed by adding -fno-vect-cost-model.
The VLS LMUL cost scaling patch will be updated after this is pushed.
Changes from v1:
- Add some comments.
- Keep the comparison local instead of adding a generic hook.
- Return HOST_WIDE_INT_M1U for estimated_loop_iters.
- Rename the loop iteration helper.
- Fold the loop-overhead estimate into compare_loop_overhead.
gcc/ChangeLog:
* config/riscv/riscv-vector-costs.cc
(estimated_loop_iters): New function.
(compare_loop_overhead): New function.
(costs::better_main_loop_than_p): Compare RVV loop overhead after
inside-loop cost.
Signed-off-by: Zhongyao Chen <[email protected]>
---
gcc/config/riscv/riscv-vector-costs.cc | 86 +++++++++++++++++++++++++-
1 file changed, 85 insertions(+), 1 deletion(-)
diff --git a/gcc/config/riscv/riscv-vector-costs.cc
b/gcc/config/riscv/riscv-vector-costs.cc
index e678e0de766..79b22251f25 100644
--- a/gcc/config/riscv/riscv-vector-costs.cc
+++ b/gcc/config/riscv/riscv-vector-costs.cc
@@ -1095,6 +1095,74 @@ costs::prefer_unrolled_loop () const
<= (unsigned int) param_max_completely_peeled_insns));
}
+/* Return the estimated number of vector iterations for LOOP_VINFO, or
+ HOST_WIDE_INT_M1U if the scalar iteration count is not known. */
+static unsigned HOST_WIDE_INT
+estimated_loop_iters (loop_vec_info loop_vinfo)
+{
+ if (!LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo))
+ return HOST_WIDE_INT_M1U;
+
+ unsigned HOST_WIDE_INT scalar_niters = LOOP_VINFO_INT_NITERS (loop_vinfo);
+ unsigned int vf = vect_vf_for_cost (loop_vinfo);
+ return (LOOP_VINFO_USING_PARTIAL_VECTORS_P (loop_vinfo)
+ ? CEIL (scalar_niters, vf)
+ : scalar_niters / vf);
+}
+
+/* Compare the estimated loop overheads of two loops. With LMUL cost scaling,
+ simple loop bodies can have equal inside-loop costs for different LMULs.
+ Include loop-back branch costs so that larger RVV modes are preferred when
+ they reduce or eliminate vector loop iterations. */
+static int
+compare_loop_overhead (loop_vec_info this_loop_vinfo,
+ loop_vec_info other_loop_vinfo)
+{
+ gcc_assert (LOOP_VINFO_NITERS_KNOWN_P (this_loop_vinfo));
+ gcc_assert (LOOP_VINFO_NITERS_KNOWN_P (other_loop_vinfo));
+
+ unsigned HOST_WIDE_INT this_niters = estimated_loop_iters (this_loop_vinfo);
+ unsigned HOST_WIDE_INT other_niters = estimated_loop_iters
(other_loop_vinfo);
+ bool this_eliminate_loop_p = this_niters == 1;
+ bool other_eliminate_loop_p = other_niters == 1;
+
+ if (this_eliminate_loop_p != other_eliminate_loop_p)
+ {
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_NOTE, vect_location,
+ "Preferring %s loop because it is estimated to"
+ " eliminate the main loop entirely\n",
+ GET_MODE_NAME ((this_eliminate_loop_p
+ ? this_loop_vinfo
+ : other_loop_vinfo)->vector_mode));
+ return this_eliminate_loop_p ? -1 : 1;
+ }
+
+ unsigned int branch_cost
+ = builtin_vectorization_cost (cond_branch_taken, NULL_TREE, 0);
+ unsigned HOST_WIDE_INT this_overhead
+ = this_niters > 1 ? (this_niters - 1) * branch_cost : 0;
+ unsigned HOST_WIDE_INT other_overhead
+ = other_niters > 1 ? (other_niters - 1) * branch_cost : 0;
+
+ if (this_overhead != other_overhead)
+ {
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_NOTE, vect_location,
+ "Preferring %s loop because it has lower"
+ " main-loop overhead ("
+ HOST_WIDE_INT_PRINT_UNSIGNED " vs. "
+ HOST_WIDE_INT_PRINT_UNSIGNED ")\n",
+ GET_MODE_NAME ((this_overhead < other_overhead
+ ? this_loop_vinfo
+ : other_loop_vinfo)->vector_mode),
+ this_overhead, other_overhead);
+ return this_overhead < other_overhead ? -1 : 1;
+ }
+
+ return 0;
+}
+
bool
costs::better_main_loop_than_p (const vector_costs *uncast_other) const
{
@@ -1213,7 +1281,23 @@ costs::better_main_loop_than_p (const vector_costs
*uncast_other) const
&& m_cost_type == VLS_VECTOR_COST)
return false;
- return vector_costs::better_main_loop_than_p (other);
+ if (!LOOP_VINFO_NITERS_KNOWN_P (this_loop_vinfo)
+ || !LOOP_VINFO_NITERS_KNOWN_P (other_loop_vinfo))
+ return vector_costs::better_main_loop_than_p (other);
+
+ int diff = compare_inside_loop_cost (other);
+ if (diff != 0)
+ return diff < 0;
+
+ diff = compare_loop_overhead (this_loop_vinfo, other_loop_vinfo);
+ if (diff != 0)
+ return diff < 0;
+
+ diff = compare_outside_loop_cost (other);
+ if (diff != 0)
+ return diff < 0;
+
+ return false;
}
/* Returns the group size i.e. the number of vectors to be loaded by a
--
2.43.0