https://gcc.gnu.org/g:7068b2e190053341498f200b720908be45134c24
commit r16-5982-g7068b2e190053341498f200b720908be45134c24 Author: Robin Dapp <[email protected]> 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. 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 e6ea073acc14..eb3e68880955 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 223344a2533a..96519c96a2b4 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 916452a932d7..5f36510135c9 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -6007,6 +6007,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 b89fbf8dbbc1..813403a97331 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -32163,6 +32163,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" } } */
