RISC-V: Scale RVV integer vector body costs by unit ratio
Checks
| Context |
Check |
Description |
| linaro-tcwg-bot/tcwg_simplebootstrap_build--master-aarch64-bootstrap |
success
|
Build passed
|
| linaro-tcwg-bot/tcwg_simplebootstrap_build--master-arm-bootstrap |
success
|
Build passed
|
Commit Message
This applies a scalar/vector unit ratio to integer vector body costs,
which helps the cost model better match the actual hardware throughput.
Take an int64 vadd at VLEN=128 for example: 4 scalar units and 2 vector
units can both process 4 elements per cycle. Without this ratio, both
vector and scalar stmts just get a cost of 1, which ends up making
vectorization look too cheap.
Skip applying this ratio for:
- reduction stmts
- gather/scatter stmts
Add scalar_units and vector_units fields to riscv_tune_param. A zero
value for either field disables the scaling.
For generic-ooo, use a 4:2 scalar/vector unit ratio.
Other uarch are left unconfig since I dont know their unit number.
They can be tuned individually later.
BTW, this is still a rough cost model adjustment,
we’re trying to make progress one small piece at a time.
gcc/ChangeLog:
* config/riscv/riscv-protos.h (get_vector_units): New.
(get_scalar_units): New.
* config/riscv/riscv-vector-costs.cc (costs::add_stmt_cost):
Scale ordinary integer vector body costs using the current tune's
scalar/vector unit ratio.
* config/riscv/riscv.cc (riscv_tune_param): Add scalar_units and
vector_units.
(generic_ooo_tune_info): Set scalar_units to 4 and vector_units to 2.
(get_vector_units): New.
(get_scalar_units): New.
Signed-off-by: Zhongyao Chen <chen.zhongyao@zte.com.cn>
---
gcc/config/riscv/riscv-protos.h | 2 ++
gcc/config/riscv/riscv-vector-costs.cc | 16 ++++++++++++++++
gcc/config/riscv/riscv.cc | 25 +++++++++++++++++++++++++
3 files changed, 43 insertions(+)
Comments
Hi Zhongyao,
I am not sure about the downstream implementation of other vendors, but
currently in the tune parameters of our design, we are modeling that with our
`common_vector_cost` instance with int_stmt_cost and fp_stmt_cost
greater than 1. I guess that can already suffice for many cases? Also, we
can have designs whose FP vector unit number is different than the integer
vector unit number, and we may still need to bother with the
`common_vector_cost` struct.
Regards,
Bohan
Hi Bohan,
Yeah, common_vector_cost is another way to model this.
I’m just trying to make the cost-model rules clearer instead of hiding
them in magic numbers.
Otherwise, it may be hard to tell later whether a vector cost for a
given uarch already includes the unit-ratio scaling.
--
Regards,
Zhongyao
On Wed, Sep 2, 2026 at 5:01 PM Bohan Lei <garthlei@linux.alibaba.com> wrote:
>
> Hi Zhongyao,
>
> I am not sure about the downstream implementation of other vendors, but
> currently in the tune parameters of our design, we are modeling that with our
> `common_vector_cost` instance with int_stmt_cost and fp_stmt_cost
> greater than 1. I guess that can already suffice for many cases? Also, we
> can have designs whose FP vector unit number is different than the integer
> vector unit number, and we may still need to bother with the
> `common_vector_cost` struct.
>
> Regards,
> Bohan
> Yeah, common_vector_cost is another way to model this.
>
> I’m just trying to make the cost-model rules clearer instead of hiding
> them in magic numbers.
> Otherwise, it may be hard to tell later whether a vector cost for a
> given uarch already includes the unit-ratio scaling.
Originally, my idea was to have a target knob to enable this kind of
costing but that might further complicate things, rather than
simplify... Bohan's approach is the basic one that we also used for a
while but we want to do better than that in the future.
Therefore, I would suggest something similar to what I proposed in the
original thread about this: Let's introduce a function that (for now,
crudely) estimates things. If a uarch doesn't want or need the new
scaling, it can still opt out by disabling the scaling (which already is
the default).
I'll note that the insn scheduler for generic-ooo assumes one vector
unit. We might want to extend this.
I'd say this is good to go but for documentation purposes, let's
introduce a function scale_vector_costs or something right away and
add a comment/TODO that we should try to estimate throughput as well
as the critical path.
@@ -940,6 +940,8 @@ struct riscv_tune_info {
const struct riscv_tune_info *
riscv_parse_tune (const char *, bool);
const cpu_vector_cost *get_vector_costs ();
+unsigned int get_vector_units ();
+unsigned int get_scalar_units ();
int get_gr2vr_cost ();
int get_vr2gr_cost ();
int get_fr2vr_cost ();
@@ -1617,6 +1617,22 @@ costs::add_stmt_cost (int count, vect_cost_for_stmt kind,
stmt_cost = adjust_stmt_cost (kind, loop_vinfo, stmt_info, node, vectype,
stmt_cost);
+ unsigned int scalar_units = get_scalar_units ();
+ unsigned int vector_units = get_vector_units ();
+
+ /* Scale integer vector body costs by the scalar/vector unit ratio. */
+ if (!costing_for_scalar ()
+ && loop_vinfo
+ && where == vect_body
+ && kind == vector_stmt
+ && !is_reduction (stmt_info, node)
+ && !(stmt_info && STMT_VINFO_GATHER_SCATTER_P (stmt_info))
+ && !(node && mat_gather_scatter_p (SLP_TREE_MEMORY_ACCESS_TYPE (node)))
+ && vectype
+ && VECTOR_INTEGER_TYPE_P (vectype)
+ && scalar_units != 0 && vector_units != 0)
+ stmt_cost = CEIL (stmt_cost * scalar_units, vector_units);
+
return record_stmt_cost (stmt_info, where, count * stmt_cost);
}
@@ -310,6 +310,10 @@ struct riscv_tune_param
AUTOPREFETCHER_OFF,
AUTOPREFETCHER_WEAK
} autoprefetcher_model = AUTOPREFETCHER_OFF;
+ /* scalar and vector units used for vector costing.
+ A zero value disables the scaling. */
+ unsigned short scalar_units;
+ unsigned short vector_units;
};
@@ -726,6 +730,11 @@ static const struct riscv_tune_param generic_ooo_tune_info = {
2, /* int_reassoc_width. */
2, /* fp_reassoc_width. */
1, /* vec_reassoc_width. */
+ 4, /* small_loop_unroll_ninsns. */
+ 2, /* small_loop_unroll_factor. */
+ riscv_tune_param::AUTOPREFETCHER_OFF, /* autoprefetcher_model. */
+ 4, /* scalar_units. */
+ 2, /* vector_units. */
};
static const common_vector_cost xt_c9501_vls_vector_cost = {
@@ -14165,6 +14174,22 @@ get_vector_costs ()
return costs;
}
+/* Return the number of vector units. */
+
+unsigned int
+get_vector_units ()
+{
+ return tune_param->vector_units;
+}
+
+/* Return the number of scalar units. */
+
+unsigned int
+get_scalar_units ()
+{
+ return tune_param->scalar_units;
+}
+
/* Return the cost of operation that move from gpr to vr.
It will take the value of --param=gpr2vr_cost if it is provided.
Or the default regmove->GR2VR will be returned. */