On Mon, Dec 15, 2025 at 11:28 PM Andrew Pinski
<[email protected]> wrote:
>
> On Fri, Nov 7, 2025 at 8:08 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.
> >
> > 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 argument.
> > * config/riscv/riscv.cc (riscv_same_function_versions): Update hook
> > impl
> > for new argument.
> > * hooks.cc (hook_stringslice_stringslice_unreachable): Changed to...
> > (hook_stringslice_stringslice_locationtptr_unreachable ): ...this
> > and
> > add extra argument.
> > ---
> > gcc/config/aarch64/aarch64.cc | 19 +++++++++++--------
> > gcc/config/riscv/riscv.cc | 2 +-
> > gcc/doc/tm.texi | 8 +++++++-
> > gcc/hooks.cc | 2 +-
> > gcc/target.def | 18 +++++++++++++-----
> > gcc/tree.cc | 34 +++++++++++++++++++---------------
> > 6 files changed, 52 insertions(+), 31 deletions(-)
> >
> > diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> > index b3e752bbd8c..abc5bafb50d 100644
> > --- a/gcc/config/aarch64/aarch64.cc
> > +++ b/gcc/config/aarch64/aarch64.cc
> > @@ -21278,19 +21278,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, string_slice new_str,
> > + location_t *)
> > {
> > 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/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
> > index 7d723fc4d69..a8962860a6b 100644
> > --- a/gcc/config/riscv/riscv.cc
> > +++ b/gcc/config/riscv/riscv.cc
> > @@ -14744,7 +14744,7 @@ 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, string_slice v2, location_t
> > *)
> > {
> > struct riscv_feature_bits mask1, mask2;
> > int prio1, prio2;
> > diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
> > index fd208f53844..17d8c3ac40e 100644
> > --- a/gcc/doc/tm.texi
> > +++ b/gcc/doc/tm.texi
> > @@ -10997,9 +10997,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}, string_slice @var{fn2}, location_t *@var{loc})
> > This target hook returns @code{true} if the target/target-version strings
> > @var{fn1} and @var{fn2} imply the same function version.
> > +
> > +If @var{loc} is 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 at @var{loc}.
>
> Constantify loc since this target hook should NOT be changing what loc
> points to.
> I am not sure I like the idea of passing a pointer here for making
> this specify if we are merging from the same decl or from different
> declarations.
> Also it would be useful to print out where the old declaration was.
> So I think the interface should be:
> (string_slice fn1, location_t loc1, string_slice fn2, location_t loc2)
>
> And then have UNKNOWN_LOC for both locations for the case of not from
> an earlier/later declaration.
> And then in aarch64, do an error for the new decl (loc2) and a note
> where the old one was.
The other option is to pass both decls. That actually might be the
better option here.
That is:
(string_slice fn1, tree old_decl, string_slice fn2, tree new_decl)
And then the error message in aarch64 would be something like:
error ("%q+D has an inconsistent function multi-version priority
value", new_decl);
note("%q+D was previously declared here with priority value of %d",
old_decl, old_priority);
Thanks,
Andrew Pinski
>
> Thanks,
> Andrew
>
> > @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..ff2bd80ae77 100644
> > --- a/gcc/hooks.cc
> > +++ b/gcc/hooks.cc
> > @@ -595,7 +595,7 @@ hook_stringslice_locationtptr_true (string_slice,
> > location_t *)
> > }
> >
> > bool
> > -hook_stringslice_stringslice_unreachable (string_slice, string_slice)
> > +hook_stringslice_stringslice_locationtptr_unreachable (string_slice,
> > string_slice, location_t *)
> > {
> > gcc_unreachable ();
> > }
> > diff --git a/gcc/target.def b/gcc/target.def
> > index f288329ffca..dae7da331c2 100644
> > --- a/gcc/target.def
> > +++ b/gcc/target.def
> > @@ -6954,14 +6954,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 LOC 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{loc} is non @code{NULL} then @var{fn1} and @var{fn2} are from an\n\
> > +earlier and a later declaration respectively, and the hook diagnoses any\n\
> > +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 at @var{loc}.",
> > + bool, (string_slice fn1, string_slice fn2, location_t *loc),
> > + hook_stringslice_stringslice_locationtptr_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 298784e6960..c4cb65e3220 100644
> > --- a/gcc/tree.cc
> > +++ b/gcc/tree.cc
> > @@ -15605,7 +15605,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,
> > v2,
> > + NULL))
> > return false;
> > }
> > return true;
> > @@ -15623,7 +15624,7 @@ 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, v2,
> > NULL))
> > return false;
> > return true;
> > }
> > @@ -15642,7 +15643,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, v2, NULL))
> > return false;
> >
> > return true;
> > @@ -15690,30 +15691,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, newv, &DECL_SOURCE_LOCATION (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, newv, &DECL_SOURCE_LOCATION (new_decl)))
> > matched = true;
> > if (!matched)
> > mergeable = false;
> > @@ -15762,9 +15765,10 @@ 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, new_target_attr,
> > + &DECL_SOURCE_LOCATION (new_decl)));
> > }
> >
> > void
> > --
> > 2.34.1
> >