[gcc(refs/vendors/riscv/heads/gcc-15-with-riscv-opts)] RISC-V: -mmax-vectorization.
Jeff Law
law@gcc.gnu.org
Sat Jan 17 07:25:48 GMT 2026
https://gcc.gnu.org/g:7fceee3db9a1239ebceb740da7bdf94a9179f0d5
commit 7fceee3db9a1239ebceb740da7bdf94a9179f0d5
Author: Robin Dapp <rdapp@ventanamicro.com>
Date: Fri Nov 14 15:50:05 2025 +0100
RISC-V: -mmax-vectorization.
This adds an -mmax-vectorization option to riscv, a verbatim copy from
aarch64. It is an option for vector code analysis. Internally it increases
scalar costs by a large factor so every vector approach will be
profitable. As opposed to -fno-vect-cost-model, we will still compare
the vector approaches amongst each other, though.
In order to handle this argument without an '=' I needed to change the
parsing flow slightly.
gcc/ChangeLog:
* config/riscv/riscv-target-attr.cc (riscv_target_attr_parser::handle_max_vect):
New parser entry.
(riscv_target_attr_parser::update_settings): Set max-vect
option.
(riscv_process_one_target_attr): Change null-arg handling.
* config/riscv/riscv.cc (riscv_override_options_internal): Set
max-vect option.
* config/riscv/riscv.opt: Add -mmax-vectorization option.
* doc/extend.texi: Document new option.
* doc/invoke.texi: Ditto.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/rvv/autovec/max-vect-1.c: New test.
* gcc.target/riscv/rvv/autovec/max-vect-2.c: New test.
(cherry picked from commit 7068b2e190053341498f200b720908be45134c24)
Diff:
---
gcc/config/riscv/riscv-target-attr.cc | 85 ++++++++++++++++------
gcc/config/riscv/riscv.cc | 6 ++
gcc/config/riscv/riscv.opt | 4 +
gcc/doc/extend.texi | 10 +++
gcc/doc/invoke.texi | 6 ++
.../gcc.target/riscv/rvv/autovec/max-vect-1.c | 21 ++++++
.../gcc.target/riscv/rvv/autovec/max-vect-2.c | 21 ++++++
7 files changed, 129 insertions(+), 24 deletions(-)
diff --git a/gcc/config/riscv/riscv-target-attr.cc b/gcc/config/riscv/riscv-target-attr.cc
index 323dce1d92dd..99b0fa5285bd 100644
--- a/gcc/config/riscv/riscv-target-attr.cc
+++ b/gcc/config/riscv/riscv-target-attr.cc
@@ -44,6 +44,7 @@ public:
, m_cpu_info (nullptr)
, m_tune (nullptr)
, m_priority (0)
+ , m_max_vect (false)
{
}
@@ -51,6 +52,7 @@ public:
bool handle_cpu (const char *);
bool handle_tune (const char *);
bool handle_priority (const char *);
+ bool handle_max_vect (const char *);
void update_settings (struct gcc_options *opts) const;
private:
@@ -66,31 +68,35 @@ private:
const riscv_cpu_info *m_cpu_info;
const char *m_tune;
int m_priority;
+ bool m_max_vect;
};
}
/* All the information needed to handle a target attribute.
NAME is the name of the attribute.
- HANDLER is the function that takes the attribute string as an argument. */
+ HANDLER is the function that takes the attribute string as an argument.
+ REQUIRES_ARG indicates whether this attribute requires an argument value. */
struct riscv_attribute_info
{
const char *name;
bool (riscv_target_attr_parser::*handler) (const char *);
+ bool requires_arg;
};
/* The target attributes that we support. */
static const struct riscv_attribute_info riscv_target_attrs[]
- = {{"arch", &riscv_target_attr_parser::handle_arch},
- {"cpu", &riscv_target_attr_parser::handle_cpu},
- {"tune", &riscv_target_attr_parser::handle_tune},
- {NULL, NULL}};
+ = {{"arch", &riscv_target_attr_parser::handle_arch, true},
+ {"cpu", &riscv_target_attr_parser::handle_cpu, true},
+ {"tune", &riscv_target_attr_parser::handle_tune, true},
+ {"max-vectorization", &riscv_target_attr_parser::handle_max_vect, false},
+ {NULL, NULL, false}};
static const struct riscv_attribute_info riscv_target_version_attrs[]
- = {{"arch", &riscv_target_attr_parser::handle_arch},
- {"priority", &riscv_target_attr_parser::handle_priority},
- {NULL, NULL}};
+ = {{"arch", &riscv_target_attr_parser::handle_arch, true},
+ {"priority", &riscv_target_attr_parser::handle_priority, true},
+ {NULL, NULL, false}};
bool
riscv_target_attr_parser::parse_arch (const char *str)
@@ -254,6 +260,17 @@ riscv_target_attr_parser::handle_priority (const char *str)
return true;
}
+/* Handle max-vectorization. There are no further options, just
+ enable it. */
+
+bool
+riscv_target_attr_parser::handle_max_vect (const char *str ATTRIBUTE_UNUSED)
+{
+ m_max_vect = true;
+
+ return true;
+}
+
void
riscv_target_attr_parser::update_settings (struct gcc_options *opts) const
{
@@ -279,6 +296,9 @@ riscv_target_attr_parser::update_settings (struct gcc_options *opts) const
if (m_priority)
opts->x_riscv_fmv_priority = m_priority;
+
+ if (m_max_vect)
+ opts->x_riscv_max_vectorization = true;
}
/* Parse ARG_STR which contains the definition of one target attribute.
@@ -303,33 +323,50 @@ riscv_process_one_target_attr (char *arg_str,
char *str_to_check = buf.get();
strcpy (str_to_check, arg_str);
+ /* Split attribute name from argument (if present). */
char *arg = strchr (str_to_check, '=');
-
- if (!arg)
+ if (arg)
{
- if (loc)
- error_at (*loc, "attribute %<target(\"%s\")%> does not "
- "accept an argument", str_to_check);
- return false;
+ *arg = '\0';
+ ++arg;
+ /* Check for empty argument after '='. */
+ if (*arg == '\0')
+ {
+ if (loc)
+ error_at (*loc, "attribute %<target(\"%s\")%> has empty argument",
+ str_to_check);
+ return false;
+ }
}
- arg[0] = '\0';
- ++arg;
- for (const auto *attr = attrs;
- attr->name;
- ++attr)
+ /* Find matching attribute. */
+ for (const auto *attr = attrs; attr->name; ++attr)
{
- /* If the names don't match up, or the user has given an argument
- to an attribute that doesn't accept one, or didn't give an argument
- to an attribute that expects one, fail to match. */
- if (strncmp (str_to_check, attr->name, strlen (attr->name)) != 0)
+ if (strcmp (str_to_check, attr->name) != 0)
continue;
+ /* Validate argument presence matches expectations. */
+ if (attr->requires_arg && !arg)
+ {
+ if (loc)
+ error_at (*loc, "attribute %<target(\"%s\")%> expects "
+ "an argument", str_to_check);
+ return false;
+ }
+
+ if (!attr->requires_arg && arg)
+ {
+ if (loc)
+ error_at (*loc, "attribute %<target(\"%s\")%> does not "
+ "accept an argument", str_to_check);
+ return false;
+ }
+
return (&attr_parser->*attr->handler) (arg);
}
if (loc)
- error_at (*loc, "Got unknown attribute %<target(\"%s\")%>", str_to_check);
+ error_at (*loc, "unknown attribute %<target(\"%s\")%>", str_to_check);
return false;
}
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index a16206f454e9..bb1aac39b2ee 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -12225,6 +12225,12 @@ riscv_override_options_internal (struct gcc_options *opts)
/* Convert -march and -mrvv-vector-bits to a chunks count. */
riscv_vector_chunks = riscv_convert_vector_chunks (opts);
+ /* Set scalar costing to a high value such that we always pick
+ vectorization. Increase scalar costing by 100x. */
+ if (opts->x_riscv_max_vectorization)
+ SET_OPTION_IF_UNSET (&global_options, &global_options_set,
+ param_vect_scalar_cost_multiplier, 10000);
+
if (opts->x_flag_cf_protection != CF_NONE)
{
if ((opts->x_flag_cf_protection & CF_RETURN) == CF_RETURN
diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
index b334e6c10c8f..452062c65008 100644
--- a/gcc/config/riscv/riscv.opt
+++ b/gcc/config/riscv/riscv.opt
@@ -341,6 +341,10 @@ Target Undocumented RejectNegative Joined Enum(vsetvl_strategy) Var(vsetvl_strat
Target Undocumented Uinteger Var(riscv_two_source_permutes) Init(0)
-param=riscv-two-source-permutes Enable permutes with two source vectors.
+mmax-vectorization
+Target Var(riscv_max_vectorization) Save
+Override the scalar cost model such that vectorization is always profitable.
+
Enum
Name(stringop_strategy) Type(enum stringop_strategy_enum)
Valid arguments to -mstringop-strategy=:
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index f7121dbe9085..f28a452080c2 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -5675,6 +5675,16 @@ Specifies the core for which to tune the performance of this function and also
whose architectural features to use. The behavior and valid arguments are the
same as for the @option{-mcpu=} command-line option.
+@cindex @code{max-vectorization} function attribute, RISC-V
+@item max-vectorization
+@itemx no-max-vectorization
+@code{max-vectorization} tells GCC's vectorizer to treat all vector
+loops as being more profitable than the original scalar loops when
+optimizing the current function. @code{no-max-vectorization} disables
+this behavior.
+This corresponds to the behavior of the command-line options
+@option{-mmax-vectorization} and @option{-mno-max-vectorization}.
+
@end table
The above target attributes can be specified as follows:
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 3a54aecc093a..a75d8d8639b4 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -31262,6 +31262,12 @@ Do not or do generate unaligned vector memory accesses. The default is set
to off unless the processor we are optimizing for explicitly supports
element-misaligned vector memory access.
+@item -mmax-vectorization
+@itemx -mno-max-vectorization
+Enable or disable an override to vectorizer cost model making vectorization
+always appear profitable. Unlike @option{-fno-vect-cost-model} or
+@option{-fvect-cost-model=unlimited} this option does not turn off cost
+comparison between different vector modes.
@opindex mcmodel=
@opindex mcmodel=medlow
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/max-vect-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/max-vect-1.c
new file mode 100644
index 000000000000..923c1f8fb9ce
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/max-vect-1.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d -fdump-tree-vect-details" } */
+
+void __attribute__ (( target ("max-vectorization")))
+foo (char *restrict a, int *restrict b, short *restrict c,
+ int *restrict d, int stride)
+{
+ if (stride <= 1)
+ return;
+
+ for (int i = 0; i < 3; i++)
+ {
+ int res = c[i];
+ int t = b[d[i]];
+ if (a[c[i]] != 0)
+ res = t * b[d[i]];
+ c[i] = res;
+ }
+}
+
+/* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/max-vect-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/max-vect-2.c
new file mode 100644
index 000000000000..fc5c2ada2246
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/max-vect-2.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d -mmax-vectorization -fdump-tree-vect-details" } */
+
+void
+foo (char *restrict a, int *restrict b, short *restrict c,
+ int *restrict d, int stride)
+{
+ if (stride <= 1)
+ return;
+
+ for (int i = 0; i < 3; i++)
+ {
+ int res = c[i];
+ int t = b[d[i]];
+ if (a[c[i]] != 0)
+ res = t * b[d[i]];
+ c[i] = res;
+ }
+}
+
+/* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */
More information about the Gcc-cvs
mailing list