From: Alfie Richards <[email protected]>

This changes the hook from being symmetric, to explicitly taking a version
string from the old decl and one from the new decl.

Additionally, it documents that we support emitting a diagnostic if the strings
do imply the same version, but are incompatible.

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 to explicitly have old_decl
        and new_decl.
        * doc/tm.texi: Regenerate.

gcc/c/ChangeLog:
        * c-decl.cc (pushdecl): Change argument order in call to
        disjoint_version_decls.
---
 gcc/c/c-decl.cc |  2 +-
 gcc/doc/tm.texi |  6 ++-
 gcc/target.def  | 10 +++--
 gcc/tree.cc     | 97 +++++++++++++++++++++++++++++--------------------
 4 files changed, 68 insertions(+), 47 deletions(-)

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 4a940d5eec3..093f86c6285 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -3437,7 +3437,7 @@ pushdecl (tree x)
             in the set.  */
          cgraph_function_version_info *version = b_v;
          for (; version; version = version->next)
-           if (!disjoint_version_decls (version->this_node->decl, x))
+           if (!disjoint_version_decls (x, version->this_node->decl))
              {
                /* The decls define overlapping version, so attempt to merge
                   or diagnose the conflict.  */
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index fd208f53844..8847699ca9f 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -10997,9 +10997,11 @@ 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{old_str}, string_slice @var{new_str})
 This target hook returns @code{true} if the target/target-version strings
-@var{fn1} and @var{fn2} imply the same function version.
+@var{old_str} and @var{new_str} imply the same function version.
+Can also produce a diagnostic if the version strings do imply the same
+version, but are incompatible.
 @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/target.def b/gcc/target.def
index f288329ffca..35f55540326 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -6954,13 +6954,15 @@ 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 OLD_STR and NEW_STR define the same version
+   of a function.  */
 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),
+@var{old_str} and @var{new_str} imply the same function version.\n\
+Can also produce a diagnostic if the version strings do imply the same\n\
+version, but are incompatible.",
+ bool, (string_slice old_str, string_slice new_str),
  hook_stringslice_stringslice_unreachable)
 
 /* Checks if we can be certain that function DECL_A could resolve DECL_B.  */
diff --git a/gcc/tree.cc b/gcc/tree.cc
index 18abd1f3c4b..8a294a646cc 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -15499,25 +15499,26 @@ get_target_version (const tree decl)
           .strip ();
 }
 
-/* Returns true if FN1 and FN2 define disjoint function versions in an FMV
-   function set.  That is, the two declarations are completely non-overlapping.
+/* Returns true if NEW_DECL and OLD_DECL define disjoint function versions in
+   an FMV function set.  That is, the two declarations are completely
+   non-overlapping.
    For target_version semantics, that means if one is a target clone and one is
    a target version, the target_version must not be defined by the 
target_clone,
    and for two target_clones, they must not define any of the same version.
 
-   FN1 and FN2 should be function decls.  */
+   NEW_DECL and OLD_DECL should be function decls.  */
 
 bool
-disjoint_version_decls (tree fn1, tree fn2)
+disjoint_version_decls (tree new_decl, tree old_decl)
 {
-  if (TREE_CODE (fn1) != FUNCTION_DECL
-      || TREE_CODE (fn2) != FUNCTION_DECL)
+  if (TREE_CODE (new_decl) != FUNCTION_DECL
+      || TREE_CODE (old_decl) != FUNCTION_DECL)
     return false;
 
   if (TARGET_HAS_FMV_TARGET_ATTRIBUTE)
     {
-      tree attr1 = lookup_attribute ("target", DECL_ATTRIBUTES (fn1));
-      tree attr2 = lookup_attribute ("target", DECL_ATTRIBUTES (fn2));
+      tree attr1 = lookup_attribute ("target", DECL_ATTRIBUTES (new_decl));
+      tree attr2 = lookup_attribute ("target", DECL_ATTRIBUTES (old_decl));
 
       /* At least one function decl should have the target attribute
         specified.  */
@@ -15528,24 +15529,25 @@ disjoint_version_decls (tree fn1, tree fn2)
         multi-versioned.  */
       if (attr1 == NULL_TREE || attr2 == NULL_TREE)
        {
-         if (DECL_FUNCTION_VERSIONED (fn1) || DECL_FUNCTION_VERSIONED (fn2))
+         if (DECL_FUNCTION_VERSIONED (new_decl)
+             || DECL_FUNCTION_VERSIONED (old_decl))
            {
              if (attr2 != NULL_TREE)
                {
-                 std::swap (fn1, fn2);
+                 std::swap (new_decl, old_decl);
                  attr1 = attr2;
                }
              auto_diagnostic_group d;
-             error_at (DECL_SOURCE_LOCATION (fn2),
+             error_at (DECL_SOURCE_LOCATION (old_decl),
                        "missing %<target%> attribute for multi-versioned %qD",
-                       fn2);
-             inform (DECL_SOURCE_LOCATION (fn1),
-                     "previous declaration of %qD", fn1);
+                       old_decl);
+             inform (DECL_SOURCE_LOCATION (new_decl),
+                     "previous declaration of %qD", new_decl);
              /* Prevent diagnosing of the same error multiple times.  */
-             DECL_ATTRIBUTES (fn2)
+             DECL_ATTRIBUTES (old_decl)
                = tree_cons (get_identifier ("target"),
                             copy_node (TREE_VALUE (attr1)),
-                            DECL_ATTRIBUTES (fn2));
+                            DECL_ATTRIBUTES (old_decl));
            }
          return false;
        }
@@ -15566,28 +15568,38 @@ disjoint_version_decls (tree fn1, tree fn2)
     {
       /* As this is symmetric, can remove the case where fn2 is target clone
         and fn1 is target version by swapping here.  */
-      if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (fn2)))
-       std::swap (fn1, fn2);
+      bool swapped = false;
+      if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (old_decl)))
+       {
+         swapped = true;
+         std::swap (new_decl, old_decl);
+       }
 
-      if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (fn1)))
+      if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (new_decl)))
        {
-         auto_vec<string_slice> fn1_versions = get_clone_versions (fn1);
+         auto_vec<string_slice> new_versions = get_clone_versions (new_decl);
          /* fn1 is target_clone.  */
-         if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (fn2)))
+         if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (old_decl)))
            {
              /* Both are target_clone.  */
-             auto_vec<string_slice> fn2_versions = get_clone_versions (fn2);
-             for (string_slice v1 : fn1_versions)
+             auto_vec<string_slice> old_versions
+               = get_clone_versions (old_decl);
+             for (string_slice new_v : new_versions)
                {
-                 for (string_slice v2 : fn2_versions)
-                   if (targetm.target_option.same_function_versions (v1, v2))
-                     return false;
+                 for (string_slice old_v : old_versions)
+                   {
+                     if (swapped)
+                       std::swap (new_v, old_v);
+                     if (targetm.target_option.same_function_versions (old_v,
+                                                                       new_v))
+                       return false;
+                   }
                }
              return true;
            }
          else
            {
-             string_slice v2 = get_target_version (fn2);
+             string_slice old_v = get_target_version (old_decl);
 
              /* target and target_clones is always conflicting for target
                 semantics.  */
@@ -15595,29 +15607,34 @@ disjoint_version_decls (tree fn1, tree fn2)
                return false;
 
              /* Only fn1 is target clone.  */
-             if (!v2.is_valid ())
-               v2 = "default";
-             for (string_slice v1 : fn1_versions)
-               if (targetm.target_option.same_function_versions (v1, v2))
-                 return false;
+             if (!old_v.is_valid ())
+               old_v = "default";
+             for (string_slice new_v : new_versions)
+               {
+                 if (swapped)
+                   std::swap (new_v, old_v);
+                 if (targetm.target_option.same_function_versions (old_v,
+                                                                   new_v))
+                   return false;
+               }
              return true;
            }
        }
       else
        {
          /* Both are target_version.  */
-         string_slice v1 = get_target_version (fn1);
-         string_slice v2 = get_target_version (fn2);
+         string_slice new_v = get_target_version (new_decl);
+         string_slice old_v = get_target_version (old_decl);
 
-         if (!v1.is_valid () && !v2.is_valid ())
+         if (!new_v.is_valid () && !old_v.is_valid ())
            return false;
 
-         if (!v1.is_valid ())
-           v1 = "default";
-         if (!v2.is_valid ())
-           v2 = "default";
+         if (!new_v.is_valid ())
+           new_v = "default";
+         if (!old_v.is_valid ())
+           old_v = "default";
 
-         if (targetm.target_option.same_function_versions (v1, v2))
+         if (targetm.target_option.same_function_versions (old_v, new_v))
            return false;
 
          return true;
-- 
2.34.1

Reply via email to