On Thu, Dec 18, 2025 at 11:41 AM Alfie Richards <[email protected]> wrote:
>
> This changes the hook to support checking version mergeability for cases
> where the version strings do imply the same version, but are conflicting
> in some other way so cannot be merged.
>
> This is a change required for adding priority version support in aarch64.
This is ok; a few minor change below, just using NULL_TREE instead of
NULL (that change be done afterwards).
>
> gcc/ChangeLog:
>
> * target.def (TARGET_OPTION_SAME_FUNCTION_VERSIONS): Update
> documentation.
> * tree.cc (disjoint_version_decls): Change for new NULL parameter
> to same_function_versions.
> (diagnose_versioned_decls): Update to pass diagnostic location to
> same_function_versions.
> * doc/tm.texi: Regenerate.
> * config/aarch64/aarch64.cc (aarch64_same_function_versions):
> Update hook impl for new arguments.
> * config/riscv/riscv.cc (riscv_same_function_versions): Update
> hook impl for new arguments.
> * config/loongarch/loongarch.cc
> (loongarch_same_function_versions): Likewise
> * hooks.cc (hook_stringslice_stringslice_unreachable): Changed
> to...
> (hook_stringslice_consttree_stringslice_consttree_unreachable):
> ...this and add extra arguments.
> * hooks.h (hook_stringslice_stringslice_unreachable): Changed
> to...
> (hook_stringslice_consttree_stringslice_consttree_unreachable):
> and add extra arguments.
> ---
> gcc/config/aarch64/aarch64.cc | 19 +++++++++--------
> gcc/config/loongarch/loongarch.cc | 3 ++-
> gcc/config/riscv/riscv.cc | 3 ++-
> gcc/doc/tm.texi | 8 +++++++-
> gcc/hooks.cc | 5 ++++-
> gcc/hooks.h | 2 +-
> gcc/target.def | 18 +++++++++++-----
> gcc/tree.cc | 34 +++++++++++++++++--------------
> 8 files changed, 59 insertions(+), 33 deletions(-)
>
> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> index 8b7253b11fe..7baf041ceb3 100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -21499,19 +21499,22 @@ aarch64_get_function_versions_dispatcher (void
> *decl)
> function. */
>
> bool
> -aarch64_same_function_versions (string_slice str1, string_slice str2)
> +aarch64_same_function_versions (string_slice old_str, const_tree,
> + string_slice new_str, const_tree)
> {
> enum aarch_parse_opt_result parse_res;
> - aarch64_fmv_feature_mask feature_mask1;
> - aarch64_fmv_feature_mask feature_mask2;
> - parse_res = aarch64_parse_fmv_features (str1, NULL,
> - &feature_mask1, NULL);
> + aarch64_fmv_feature_mask old_feature_mask;
> + aarch64_fmv_feature_mask new_feature_mask;
> +
> + parse_res = aarch64_parse_fmv_features (old_str, NULL, &old_feature_mask,
> + NULL);
> gcc_assert (parse_res == AARCH_PARSE_OK);
> - parse_res = aarch64_parse_fmv_features (str2, NULL,
> - &feature_mask2, NULL);
> +
> + parse_res = aarch64_parse_fmv_features (new_str, NULL, &new_feature_mask,
> + NULL);
> gcc_assert (parse_res == AARCH_PARSE_OK);
>
> - return feature_mask1 == feature_mask2;
> + return old_feature_mask == new_feature_mask;
> }
>
> /* Implement TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P. Use an opt-out
> diff --git a/gcc/config/loongarch/loongarch.cc
> b/gcc/config/loongarch/loongarch.cc
> index 0b50aa214fd..f5fa9ead2be 100644
> --- a/gcc/config/loongarch/loongarch.cc
> +++ b/gcc/config/loongarch/loongarch.cc
> @@ -12165,7 +12165,8 @@ loongarch_generate_version_dispatcher_body (void
> *node_p)
> This assumes that FN1 and FN2 have the same signature. */
>
> bool
> -loongarch_option_same_function_versions (string_slice str1, string_slice
> str2)
> +loongarch_option_same_function_versions (string_slice str1, const_tree,
> + string_slice str2, const_tree)
> {
> loongarch_fmv_feature_mask feature_mask1;
> loongarch_fmv_feature_mask feature_mask2;
> diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
> index 96519c96a2b..3a0449e2ca8 100644
> --- a/gcc/config/riscv/riscv.cc
> +++ b/gcc/config/riscv/riscv.cc
> @@ -14823,7 +14823,8 @@ compare_fmv_features (const struct riscv_feature_bits
> &mask1,
> version. */
>
> bool
> -riscv_same_function_versions (string_slice v1, string_slice v2)
> +riscv_same_function_versions (string_slice v1, const_tree, string_slice v2,
> + const_tree)
> {
> struct riscv_feature_bits mask1, mask2;
> int prio1, prio2;
> diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
> index 2ddb11846ee..ce7ad16100d 100644
> --- a/gcc/doc/tm.texi
> +++ b/gcc/doc/tm.texi
> @@ -11012,9 +11012,15 @@ changed via the optimize attribute or pragma, see
> @code{TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE}
> @end deftypefn
>
> -@deftypefn {Target Hook} bool TARGET_OPTION_SAME_FUNCTION_VERSIONS
> (string_slice @var{fn1}, string_slice @var{fn2})
> +@deftypefn {Target Hook} bool TARGET_OPTION_SAME_FUNCTION_VERSIONS
> (string_slice @var{fn1}, const_tree @var{decl1}, string_slice @var{fn2},
> const_tree @var{decl2})
> This target hook returns @code{true} if the target/target-version strings
> @var{fn1} and @var{fn2} imply the same function version.
> +
> +If @var{decl1} and @var{decl2} are non @code{NULL} then @var{fn1} and
> +@var{fn2} are from an earlier and a later declaration respectively, and the
> +hook diagnoses any version string incompatibility for these decls.
> +If the version strings are incompatible and the declarations can not be
> +merged, then hook emits an error.
> @end deftypefn
>
> @deftypefn {Target Hook} bool TARGET_OPTION_FUNCTIONS_B_RESOLVABLE_FROM_A
> (tree @var{decl_a}, tree @var{decl_v}, tree @var{base})
> diff --git a/gcc/hooks.cc b/gcc/hooks.cc
> index 5321142495b..06aebd3daaa 100644
> --- a/gcc/hooks.cc
> +++ b/gcc/hooks.cc
> @@ -595,7 +595,10 @@ hook_stringslice_locationtptr_true (string_slice,
> location_t *)
> }
>
> bool
> -hook_stringslice_stringslice_unreachable (string_slice, string_slice)
> +hook_stringslice_consttree_stringslice_consttree_unreachable (string_slice,
> + const_tree,
> + string_slice,
> + const_tree)
> {
> gcc_unreachable ();
> }
> diff --git a/gcc/hooks.h b/gcc/hooks.h
> index a7021f532a5..1d8630c8349 100644
> --- a/gcc/hooks.h
> +++ b/gcc/hooks.h
> @@ -139,6 +139,6 @@ extern opt_machine_mode hook_optmode_mode_uhwi_none
> (machine_mode,
> unsigned HOST_WIDE_INT);
>
> extern bool hook_stringslice_locationtptr_true (string_slice, location_t *);
> -extern bool hook_stringslice_stringslice_unreachable (string_slice,
> string_slice);
> +extern bool hook_stringslice_consttree_stringslice_consttree_unreachable
> (string_slice, const_tree, string_slice, const_tree);
>
> #endif
> diff --git a/gcc/target.def b/gcc/target.def
> index d695f38fbcc..b994ccef215 100644
> --- a/gcc/target.def
> +++ b/gcc/target.def
> @@ -6971,14 +6971,22 @@ changed via the optimize attribute or pragma, see\n\
> void, (void),
> hook_void_void)
>
> -/* This function returns true if FN1 and FN2 define the same version of a
> - function. */
> +/* This function returns true if FN1 and FN2 define the same version
> + of a function.
> + If DECL1 and DECL2 is not-null then emit a diagnostic if the versions do
> + imply the same version, but are not mergeable. */
> DEFHOOK
> (same_function_versions,
> "This target hook returns @code{true} if the target/target-version
> strings\n\
> -@var{fn1} and @var{fn2} imply the same function version.",
> - bool, (string_slice fn1, string_slice fn2),
> - hook_stringslice_stringslice_unreachable)
> +@var{fn1} and @var{fn2} imply the same function version.\n\
> +\n\
> +If @var{decl1} and @var{decl2} are non @code{NULL} then @var{fn1} and\n\
> +@var{fn2} are from an earlier and a later declaration respectively, and
> the\n\
> +hook diagnoses any version string incompatibility for these decls.\n\
> +If the version strings are incompatible and the declarations can not be\n\
> +merged, then hook emits an error.",
> + bool, (string_slice fn1, const_tree decl1, string_slice fn2, const_tree
> decl2),
> + hook_stringslice_consttree_stringslice_consttree_unreachable)
>
> /* Checks if we can be certain that function DECL_A could resolve DECL_B. */
> DEFHOOK
> diff --git a/gcc/tree.cc b/gcc/tree.cc
> index 8dcb59dc875..69f44846b7f 100644
> --- a/gcc/tree.cc
> +++ b/gcc/tree.cc
> @@ -15610,7 +15610,8 @@ disjoint_version_decls (tree fn1, tree fn2)
> for (string_slice v1 : fn1_versions)
> {
> for (string_slice v2 : fn2_versions)
> - if (targetm.target_option.same_function_versions (v1, v2))
> + if (targetm.target_option.same_function_versions (v1,
> NULL,
> + v2,
> NULL))
NULL_TREE instead of NULL since these are tree.
> return false;
> }
> return true;
> @@ -15628,7 +15629,8 @@ disjoint_version_decls (tree fn1, tree fn2)
> if (!v2.is_valid ())
> v2 = "default";
> for (string_slice v1 : fn1_versions)
> - if (targetm.target_option.same_function_versions (v1, v2))
> + if (targetm.target_option.same_function_versions (v1, NULL,
> v2,
> + NULL))
Likewise.
> return false;
> return true;
> }
> @@ -15647,7 +15649,7 @@ disjoint_version_decls (tree fn1, tree fn2)
> if (!v2.is_valid ())
> v2 = "default";
>
> - if (targetm.target_option.same_function_versions (v1, v2))
> + if (targetm.target_option.same_function_versions (v1, NULL, v2,
> NULL))
Likewise.
Thanks,
Andrew Pinski
> return false;
>
> return true;
> @@ -15695,30 +15697,32 @@ diagnose_versioned_decls (tree old_decl, tree
> new_decl)
> the two sets of target_clones imply the same set of versions. */
> if (old_target_clones_attr && new_target_clones_attr)
> {
> - auto_vec<string_slice> fn1_versions = get_clone_versions (old_decl);
> - auto_vec<string_slice> fn2_versions = get_clone_versions (new_decl);
> + auto_vec<string_slice> old_versions = get_clone_versions (old_decl);
> + auto_vec<string_slice> new_versions = get_clone_versions (new_decl);
>
> bool mergeable = true;
>
> - if (fn1_versions.length () != fn2_versions.length ())
> + if (old_versions.length () != new_versions.length ())
> mergeable = false;
>
> /* Check both inclusion directions. */
> - for (auto fn1v : fn1_versions)
> + for (auto oldv: old_versions)
> {
> bool matched = false;
> - for (auto fn2v : fn2_versions)
> - if (targetm.target_option.same_function_versions (fn1v, fn2v))
> + for (auto newv: new_versions)
> + if (targetm.target_option.same_function_versions (oldv, old_decl,
> + newv, new_decl))
> matched = true;
> if (!matched)
> mergeable = false;
> }
>
> - for (auto fn2v : fn2_versions)
> + for (auto newv: new_versions)
> {
> bool matched = false;
> - for (auto fn1v : fn1_versions)
> - if (targetm.target_option.same_function_versions (fn1v, fn2v))
> + for (auto oldv: old_versions)
> + if (targetm.target_option.same_function_versions (oldv, old_decl,
> + newv, new_decl))
> matched = true;
> if (!matched)
> mergeable = false;
> @@ -15767,9 +15771,9 @@ diagnose_versioned_decls (tree old_decl, tree
> new_decl)
> return true;
> }
>
> - /* The only remaining case is two target_version annotated decls. Must
> - be mergeable as otherwise are distinct. */
> - return false;
> + /* The only remaining case is two target_version annotated decls. */
> + return !targetm.target_option.same_function_versions
> + (old_target_attr, old_decl, new_target_attr, new_decl);
> }
>
> void
> --
> 2.34.1
>