re PR c++/55742 (__attribute__ in class function declaration cause "prototype does...
authorJakub Jelinek <jakub@redhat.com>
Wed, 30 Jan 2013 18:04:34 +0000 (19:04 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 30 Jan 2013 18:04:34 +0000 (19:04 +0100)
PR c++/55742
* config/i386/i386.c (ix86_valid_target_attribute_inner_p): Diagnose
invalid args instead of ICEing on it.
(ix86_valid_target_attribute_tree): Return error_mark_node if
ix86_valid_target_attribute_inner_p failed.
(ix86_valid_target_attribute_p): Return false only if
ix86_valid_target_attribute_tree returned error_mark_node.  Allow
target("default") attribute.
(sorted_attr_string): Change argument from const char * to tree,
merge in all target attribute arguments rather than just one.
Formatting fix.  Use XNEWVEC instead of xmalloc and XDELETEVEC
instead of free.  Avoid using strcat.
(ix86_mangle_function_version_assembler_name): Mangle
target("default") as if no target attribute is present.  Adjust
sorted_attr_string caller.  Avoid leaking memory.  Use XNEWVEC
instead of xmalloc and XDELETEVEC instead of free.
(ix86_function_versions): Don't return true if one of the decls
doesn't have target attribute.  If they don't and one of the decls
is DECL_FUNCTION_VERSIONED, report an error.  Adjust
sorted_attr_string caller.  Use XDELETEVEC instead of free.
(ix86_supports_function_versions): Remove.
(make_name): Fix up formatting.
(make_dispatcher_decl): Remove resolver_name and its initialization.
Avoid leaking memory.
(is_function_default_version): Return true if there is
target("default") attribute rather than no target attribute at all.
(make_resolver_func): Avoid leaking memory.
(ix86_generate_version_dispatcher_body): Likewise.
(TARGET_OPTION_SUPPORTS_FUNCTION_VERSIONS): Remove.
* target.def (supports_function_versions): Remove.
* doc/tm.texi.in (SUPPORTS_FUNCTION_VERSIONS): Remove.
* doc/tm.texi: Regenerated.

* c-common.c (handle_target_attribute): Revert 2012-12-26 change.

* g++.dg/mv1.C: Moved to...
* g++.dg/ext/mv1.C: ... here.  Adjust test.
* g++.dg/mv2.C: Moved to...
* g++.dg/ext/mv2.C: ... here.  Adjust test.
* g++.dg/mv3.C: Moved to...
* g++.dg/ext/mv3.C: ... here.
* g++.dg/mv4.C: Moved to...
* g++.dg/ext/mv4.C: ... here.
* g++.dg/mv5.C: Moved to...
* g++.dg/ext/mv5.C: ... here.  Adjust test.
* g++.dg/mv6.C: Moved to...
* g++.dg/ext/mv6.C: ... here.  Adjust test.
* g++.dg/ext/mv7.C: New test.
* g++.dg/ext/mv8.C: New test.
* g++.dg/ext/mv9.C: New test.
* g++.dg/ext/mv10.C: New test.
* g++.dg/ext/mv11.C: New test.

From-SVN: r195584

25 files changed:
gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/config/i386/i386.c
gcc/doc/tm.texi
gcc/doc/tm.texi.in
gcc/target.def
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ext/mv1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/mv10.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/mv11.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/mv2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/mv3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/mv4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/mv5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/mv6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/mv7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/mv8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/mv9.C [new file with mode: 0644]
gcc/testsuite/g++.dg/mv1.C [deleted file]
gcc/testsuite/g++.dg/mv2.C [deleted file]
gcc/testsuite/g++.dg/mv3.C [deleted file]
gcc/testsuite/g++.dg/mv4.C [deleted file]
gcc/testsuite/g++.dg/mv5.C [deleted file]
gcc/testsuite/g++.dg/mv6.C [deleted file]

index 0eb5f7c3e3b7725cb9cddd871a0cb2ef743565a9..dd0b294a469a617e0e2180d075e48b90b35e967d 100644 (file)
@@ -1,3 +1,38 @@
+2013-01-30  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/55742
+       * config/i386/i386.c (ix86_valid_target_attribute_inner_p): Diagnose
+       invalid args instead of ICEing on it.
+       (ix86_valid_target_attribute_tree): Return error_mark_node if
+       ix86_valid_target_attribute_inner_p failed.
+       (ix86_valid_target_attribute_p): Return false only if
+       ix86_valid_target_attribute_tree returned error_mark_node.  Allow
+       target("default") attribute.
+       (sorted_attr_string): Change argument from const char * to tree,
+       merge in all target attribute arguments rather than just one.
+       Formatting fix.  Use XNEWVEC instead of xmalloc and XDELETEVEC
+       instead of free.  Avoid using strcat.
+       (ix86_mangle_function_version_assembler_name): Mangle
+       target("default") as if no target attribute is present.  Adjust
+       sorted_attr_string caller.  Avoid leaking memory.  Use XNEWVEC
+       instead of xmalloc and XDELETEVEC instead of free.
+       (ix86_function_versions): Don't return true if one of the decls
+       doesn't have target attribute.  If they don't and one of the decls
+       is DECL_FUNCTION_VERSIONED, report an error.  Adjust
+       sorted_attr_string caller.  Use XDELETEVEC instead of free.
+       (ix86_supports_function_versions): Remove.
+       (make_name): Fix up formatting.
+       (make_dispatcher_decl): Remove resolver_name and its initialization.
+       Avoid leaking memory.
+       (is_function_default_version): Return true if there is
+       target("default") attribute rather than no target attribute at all.
+       (make_resolver_func): Avoid leaking memory.
+       (ix86_generate_version_dispatcher_body): Likewise.
+       (TARGET_OPTION_SUPPORTS_FUNCTION_VERSIONS): Remove.
+       * target.def (supports_function_versions): Remove.
+       * doc/tm.texi.in (SUPPORTS_FUNCTION_VERSIONS): Remove.
+       * doc/tm.texi: Regenerated.
+
 2013-01-30  Vladimir Makarov  <vmakarov@redhat.com>
 
        PR rtl-optimization/56144
index d4f989be630f4bf1e3e2a9089f89d495aef8549d..2fbc8f49b70bf45b10ac4d820b0daa001bb6fc19 100644 (file)
@@ -1,3 +1,8 @@
+2013-01-30  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/55742
+       * c-common.c (handle_target_attribute): Revert 2012-12-26 change.
+
 2013-01-18  Jason Merrill  <jason@redhat.com>
 
        PR target/54908
index a50aae1e57ab1379ac24aa898738275a44ef6b98..b3699dc086b40b447b9a35cbbd53215bad5cdde4 100644 (file)
@@ -8759,12 +8759,8 @@ handle_target_attribute (tree *node, tree name, tree args, int flags,
       warning (OPT_Wattributes, "%qE attribute ignored", name);
       *no_add_attrs = true;
     }
-  /* Do not strip invalid target attributes for targets which support function
-     multiversioning as the target string is used to determine versioned
-     functions.  */
   else if (! targetm.target_option.valid_attribute_p (*node, name, args,
-                                                     flags)
-          && ! targetm.target_option.supports_function_versions ())
+                                                     flags))
     *no_add_attrs = true;
 
   return NULL_TREE;
index 19a495d15da860e1d33c27fd50fec132c7ac9f56..acdfa6c7b8832202b22bb1c1510190c9aba20029 100644 (file)
@@ -4225,7 +4225,10 @@ ix86_valid_target_attribute_inner_p (tree args, char *p_strings[],
     }
 
   else if (TREE_CODE (args) != STRING_CST)
-    gcc_unreachable ();
+    {
+      error ("attribute %<target%> argument not a string");
+      return false;
+    }
 
   /* Handle multiple arguments separated by commas.  */
   next_optstr = ASTRDUP (TREE_STRING_POINTER (args));
@@ -4370,7 +4373,7 @@ ix86_valid_target_attribute_tree (tree args)
   /* Process each of the options on the chain.  */
   if (! ix86_valid_target_attribute_inner_p (args, option_strings,
                                             &enum_opts_set))
-    return NULL_TREE;
+    return error_mark_node;
 
   /* If the changed options are different from the default, rerun
      ix86_option_override_internal, and then save the options away.
@@ -4435,6 +4438,15 @@ ix86_valid_target_attribute_p (tree fndecl,
 {
   struct cl_target_option cur_target;
   bool ret = true;
+
+  /* attribute((target("default"))) does nothing, beyond
+     affecting multi-versioning.  */
+  if (TREE_VALUE (args)
+      && TREE_CODE (TREE_VALUE (args)) == STRING_CST
+      && TREE_CHAIN (args) == NULL_TREE
+      && strcmp (TREE_STRING_POINTER (TREE_VALUE (args)), "default") == 0)
+    return true;
+
   tree old_optimize = build_optimization_node ();
   tree new_target, new_optimize;
   tree func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl);
@@ -4451,10 +4463,10 @@ ix86_valid_target_attribute_p (tree fndecl,
   new_target = ix86_valid_target_attribute_tree (args);
   new_optimize = build_optimization_node ();
 
-  if (!new_target)
+  if (new_target == error_mark_node)
     ret = false;
 
-  else if (fndecl)
+  else if (fndecl && new_target)
     {
       DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = new_target;
 
@@ -28948,26 +28960,44 @@ attr_strcmp (const void *v1, const void *v2)
   return strcmp (c1, c2);
 }
 
-/* STR is the argument to target attribute.  This function tokenizes
+/* ARGLIST is the argument to target attribute.  This function tokenizes
    the comma separated arguments, sorts them and returns a string which
    is a unique identifier for the comma separated arguments.   It also
    replaces non-identifier characters "=,-" with "_".  */
 
 static char *
-sorted_attr_string (const char *str)
+sorted_attr_string (tree arglist)
 {
+  tree arg;
+  size_t str_len_sum = 0;
   char **args = NULL;
   char *attr_str, *ret_str;
   char *attr = NULL;
   unsigned int argnum = 1;
   unsigned int i;
 
-  for (i = 0; i < strlen (str); i++)
-    if (str[i] == ',')
-      argnum++;
+  for (arg = arglist; arg; arg = TREE_CHAIN (arg))
+    {
+      const char *str = TREE_STRING_POINTER (TREE_VALUE (arg));
+      size_t len = strlen (str);
+      str_len_sum += len + 1;
+      if (arg != arglist)
+       argnum++;
+      for (i = 0; i < strlen (str); i++)
+       if (str[i] == ',')
+         argnum++;
+    }
 
-  attr_str = (char *)xmalloc (strlen (str) + 1);
-  strcpy (attr_str, str);
+  attr_str = XNEWVEC (char, str_len_sum);
+  str_len_sum = 0;
+  for (arg = arglist; arg; arg = TREE_CHAIN (arg))
+    {
+      const char *str = TREE_STRING_POINTER (TREE_VALUE (arg));
+      size_t len = strlen (str);
+      memcpy (attr_str + str_len_sum, str, len);
+      attr_str[str_len_sum + len] = TREE_CHAIN (arg) ? ',' : '\0';
+      str_len_sum += len + 1;
+    }
 
   /* Replace "=,-" with "_".  */
   for (i = 0; i < strlen (attr_str); i++)
@@ -28988,18 +29018,20 @@ sorted_attr_string (const char *str)
       attr = strtok (NULL, ",");
     }
 
-  qsort (args, argnum, sizeof (char*), attr_strcmp);
+  qsort (args, argnum, sizeof (char *), attr_strcmp);
 
-  ret_str = (char *)xmalloc (strlen (str) + 1);
-  strcpy (ret_str, args[0]);
-  for (i = 1; i < argnum; i++)
+  ret_str = XNEWVEC (char, str_len_sum);
+  str_len_sum = 0;
+  for (i = 0; i < argnum; i++)
     {
-      strcat (ret_str, "_");
-      strcat (ret_str, args[i]);
+      size_t len = strlen (args[i]);
+      memcpy (ret_str + str_len_sum, args[i], len);
+      ret_str[str_len_sum + len] = i < argnum - 1 ? '_' : '\0';
+      str_len_sum += len + 1;
     }
 
-  free (args);
-  free (attr_str);
+  XDELETEVEC (args);
+  XDELETEVEC (attr_str);
   return ret_str;
 }
 
@@ -29011,8 +29043,8 @@ static tree
 ix86_mangle_function_version_assembler_name (tree decl, tree id)
 {
   tree version_attr;
-  const char *orig_name, *version_string, *attr_str;
-  char *assembler_name;
+  const char *orig_name, *version_string;
+  char *attr_str, *assembler_name;
 
   if (DECL_DECLARED_INLINE_P (decl)
       && lookup_attribute ("gnu_inline",
@@ -29036,9 +29068,11 @@ ix86_mangle_function_version_assembler_name (tree decl, tree id)
   version_string
     = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (version_attr)));
 
-  attr_str = sorted_attr_string (version_string);
-  assembler_name = (char *) xmalloc (strlen (orig_name)
-                                    + strlen (attr_str) + 2);
+  if (strcmp (version_string, "default") == 0)
+    return id;
+
+  attr_str = sorted_attr_string (TREE_VALUE (version_attr));
+  assembler_name = XNEWVEC (char, strlen (orig_name) + strlen (attr_str) + 2);
 
   sprintf (assembler_name, "%s.%s", orig_name, attr_str);
 
@@ -29046,7 +29080,10 @@ ix86_mangle_function_version_assembler_name (tree decl, tree id)
   if (DECL_ASSEMBLER_NAME_SET_P (decl))
     SET_DECL_RTL (decl, NULL);
 
-  return get_identifier (assembler_name);
+  tree ret = get_identifier (assembler_name);
+  XDELETEVEC (attr_str);
+  XDELETEVEC (assembler_name);
+  return ret;
 }
 
 /* This function returns true if FN1 and FN2 are versions of the same function,
@@ -29057,10 +29094,9 @@ static bool
 ix86_function_versions (tree fn1, tree fn2)
 {
   tree attr1, attr2;
-  const char *attr_str1, *attr_str2;
   char *target1, *target2;
   bool result;
-  
+
   if (TREE_CODE (fn1) != FUNCTION_DECL
       || TREE_CODE (fn2) != FUNCTION_DECL)
     return false;
@@ -29072,15 +29108,35 @@ ix86_function_versions (tree fn1, tree fn2)
   if (attr1 == NULL_TREE && attr2 == NULL_TREE)
     return false;
 
-  /* If one function does not have a target attribute, these are versions.  */
+  /* Diagnose missing target attribute if one of the decls is already
+     multi-versioned.  */
   if (attr1 == NULL_TREE || attr2 == NULL_TREE)
-    return true;
-
-  attr_str1 =  TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr1)));
-  attr_str2 =  TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr2)));
+    {
+      if (DECL_FUNCTION_VERSIONED (fn1) || DECL_FUNCTION_VERSIONED (fn2))
+       {
+         if (attr2 != NULL_TREE)
+           {
+             tree tem = fn1;
+             fn1 = fn2;
+             fn2 = tem;
+             attr1 = attr2;
+           }
+         error_at (DECL_SOURCE_LOCATION (fn2),
+                   "missing %<target%> attribute for multi-versioned %D",
+                   fn2);
+         error_at (DECL_SOURCE_LOCATION (fn1),
+                   "previous declaration of %D", fn1);
+         /* Prevent diagnosing of the same error multiple times.  */
+         DECL_ATTRIBUTES (fn2)
+           = tree_cons (get_identifier ("target"),
+                        copy_node (TREE_VALUE (attr1)),
+                        DECL_ATTRIBUTES (fn2));
+       }
+      return false;
+    }
 
-  target1 = sorted_attr_string (attr_str1);
-  target2 = sorted_attr_string (attr_str2);
+  target1 = sorted_attr_string (TREE_VALUE (attr1));
+  target2 = sorted_attr_string (TREE_VALUE (attr2));
 
   /* The sorted target strings must be different for fn1 and fn2
      to be versions.  */
@@ -29089,20 +29145,12 @@ ix86_function_versions (tree fn1, tree fn2)
   else
     result = true;
 
-  free (target1);
-  free (target2); 
+  XDELETEVEC (target1);
+  XDELETEVEC (target2); 
   
   return result;
 }
 
-/* This target supports function multiversioning.  */
-
-static bool
-ix86_supports_function_versions (void)
-{
-  return true;
-}
-
 static tree 
 ix86_mangle_decl_assembler_name (tree decl, tree id)
 {
@@ -29143,10 +29191,10 @@ make_name (tree decl, const char *suffix, bool make_unique)
 
   /* Use '.' to concatenate names as it is demangler friendly.  */
   if (make_unique)
-      snprintf (global_var_name, name_len, "%s.%s.%s", name,
-               unique_name, suffix);
+    snprintf (global_var_name, name_len, "%s.%s.%s", name, unique_name,
+             suffix);
   else
-      snprintf (global_var_name, name_len, "%s.%s", name, suffix);
+    snprintf (global_var_name, name_len, "%s.%s", name, suffix);
 
   return global_var_name;
 }
@@ -29161,7 +29209,7 @@ static tree
 make_dispatcher_decl (const tree decl)
 {
   tree func_decl;
-  char *func_name, *resolver_name;
+  char *func_name;
   tree fn_type, func_type;
   bool is_uniq = false;
 
@@ -29169,14 +29217,13 @@ make_dispatcher_decl (const tree decl)
     is_uniq = true;
 
   func_name = make_name (decl, "ifunc", is_uniq);
-  resolver_name = make_name (decl, "resolver", is_uniq);
-  gcc_assert (resolver_name);
 
   fn_type = TREE_TYPE (decl);
   func_type = build_function_type (TREE_TYPE (fn_type),
                                   TYPE_ARG_TYPES (fn_type));
   
   func_decl = build_fn_decl (func_name, func_type);
+  XDELETEVEC (func_name);
   TREE_USED (func_decl) = 1;
   DECL_CONTEXT (func_decl) = NULL_TREE;
   DECL_INITIAL (func_decl) = error_mark_node;
@@ -29198,9 +29245,14 @@ make_dispatcher_decl (const tree decl)
 static bool
 is_function_default_version (const tree decl)
 {
-  return (TREE_CODE (decl) == FUNCTION_DECL
-         && DECL_FUNCTION_VERSIONED (decl)
-         && lookup_attribute ("target", DECL_ATTRIBUTES (decl)) == NULL_TREE);
+  if (TREE_CODE (decl) != FUNCTION_DECL
+      || !DECL_FUNCTION_VERSIONED (decl))
+    return false;
+  tree attr = lookup_attribute ("target", DECL_ATTRIBUTES (decl));
+  gcc_assert (attr);
+  attr = TREE_VALUE (TREE_VALUE (attr));
+  return (TREE_CODE (attr) == STRING_CST
+         && strcmp (TREE_STRING_POINTER (attr), "default") == 0);
 }
 
 /* Make a dispatcher declaration for the multi-versioned function DECL.
@@ -29394,6 +29446,7 @@ make_resolver_func (const tree default_decl,
   /* Create the alias for dispatch to resolver here.  */
   /*cgraph_create_function_alias (dispatch_decl, decl);*/
   cgraph_same_body_alias (NULL, dispatch_decl, decl);
+  XDELETEVEC (resolver_name);
   return decl;
 }
 
@@ -29455,7 +29508,7 @@ ix86_generate_version_dispatcher_body (void *node_p)
     }
 
   dispatch_function_versions (resolver_decl, &fn_ver_vec, &empty_bb);
-
+  fn_ver_vec.release ();
   rebuild_cgraph_edges (); 
   pop_cfun ();
   return resolver_decl;
@@ -42443,10 +42496,6 @@ ix86_memmodel_check (unsigned HOST_WIDE_INT val)
 #undef TARGET_OPTION_FUNCTION_VERSIONS
 #define TARGET_OPTION_FUNCTION_VERSIONS ix86_function_versions
 
-#undef TARGET_OPTION_SUPPORTS_FUNCTION_VERSIONS
-#define TARGET_OPTION_SUPPORTS_FUNCTION_VERSIONS \
-  ix86_supports_function_versions
-
 #undef TARGET_CAN_INLINE_P
 #define TARGET_CAN_INLINE_P ix86_can_inline_p
 
index 9d6f6bc91827eec154f7198ad96df0c79dbdc9da..ce2b44d854520f5b8af6d989139767c7a7a245f6 100644 (file)
@@ -9907,11 +9907,6 @@ different target specific attributes, that is, they are compiled for
 different target machines.
 @end deftypefn
 
-@deftypefn {Target Hook} bool TARGET_OPTION_SUPPORTS_FUNCTION_VERSIONS (void)
-This target hook returns @code{true} if the target supports function
-multiversioning.
-@end deftypefn
-
 @deftypefn {Target Hook} bool TARGET_CAN_INLINE_P (tree @var{caller}, tree @var{callee})
 This target hook returns @code{false} if the @var{caller} function
 cannot inline @var{callee}, based on target specific information.  By
index 36688820bb8cb1b137910efea6888704171532cd..d6e7ce79f9dc3ee9325d00c656c1e1214265a7a8 100644 (file)
@@ -9768,11 +9768,6 @@ different target specific attributes, that is, they are compiled for
 different target machines.
 @end deftypefn
 
-@hook TARGET_OPTION_SUPPORTS_FUNCTION_VERSIONS
-This target hook returns @code{true} if the target supports function
-multiversioning.
-@end deftypefn
-
 @hook TARGET_CAN_INLINE_P
 This target hook returns @code{false} if the @var{caller} function
 cannot inline @var{callee}, based on target specific information.  By
index 86279231bbe26cb5b9e875e7ea5178974fc2db4f..63ba55e98d0857be3f17fade7e49974ef9a01470 100644 (file)
@@ -2831,14 +2831,6 @@ DEFHOOK
  bool, (tree decl1, tree decl2),
  hook_bool_tree_tree_false)
 
-/* This function returns true if the target supports function
-   multiversioning.  */
-DEFHOOK
-(supports_function_versions,
- "",
- bool, (void),
- hook_bool_void_false)
-
 /* Function to determine if one function can inline another function.  */
 #undef HOOK_PREFIX
 #define HOOK_PREFIX "TARGET_"
index 17c91ee86283c3b5c7b76594ba091df3feec9f1e..215ab43d2526a49afa07560857358276138747ba 100644 (file)
@@ -1,3 +1,24 @@
+2013-01-30  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/55742
+       * g++.dg/mv1.C: Moved to...
+       * g++.dg/ext/mv1.C: ... here.  Adjust test.
+       * g++.dg/mv2.C: Moved to...
+       * g++.dg/ext/mv2.C: ... here.  Adjust test.
+       * g++.dg/mv3.C: Moved to...
+       * g++.dg/ext/mv3.C: ... here.
+       * g++.dg/mv4.C: Moved to...
+       * g++.dg/ext/mv4.C: ... here.
+       * g++.dg/mv5.C: Moved to...
+       * g++.dg/ext/mv5.C: ... here.  Adjust test.
+       * g++.dg/mv6.C: Moved to...
+       * g++.dg/ext/mv6.C: ... here.  Adjust test.
+       * g++.dg/ext/mv7.C: New test.
+       * g++.dg/ext/mv8.C: New test.
+       * g++.dg/ext/mv9.C: New test.
+       * g++.dg/ext/mv10.C: New test.
+       * g++.dg/ext/mv11.C: New test.
+
 2013-01-30  Vladimir Makarov  <vmakarov@redhat.com>
 
        PR rtl-optimization/56144
diff --git a/gcc/testsuite/g++.dg/ext/mv1.C b/gcc/testsuite/g++.dg/ext/mv1.C
new file mode 100644 (file)
index 0000000..4eedbff
--- /dev/null
@@ -0,0 +1,132 @@
+/* Test case to check if Multiversioning works.  */
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-require-ifunc "" }  */
+/* { dg-options "-O2 -fPIC" } */
+
+#include <assert.h>
+
+/* Default version.  */
+int foo (); // Extra declaration that is merged with the second one.
+int foo () __attribute__ ((target("default")));
+/* The other versions of foo.  Mix up the ordering and 
+   check if the dispatching does it in the order of priority. */
+/* Check combination of target attributes.  */
+int foo () __attribute__ ((target("arch=corei7,popcnt")));
+/* The target operands in this declaration and the definition are re-ordered.
+   This should still work.  */
+int foo () __attribute__ ((target("ssse3,avx2")));
+
+/* Check for all target attributes for which dispatchers are available.  */
+/* Check arch= */
+int foo () __attribute__((target("arch=core2")));
+int foo () __attribute__((target("arch=corei7")));
+int foo () __attribute__((target("arch=atom")));
+/* Check ISAs  */
+int foo () __attribute__((target("avx")));
+int foo () __attribute__ ((target("arch=core2,sse4.2")));
+/* Check more arch=.  */
+int foo () __attribute__((target("arch=amdfam10")));
+int foo () __attribute__((target("arch=bdver1")));
+int foo () __attribute__((target("arch=bdver2")));
+
+int (*p)() = &foo;
+int main ()
+{
+  int val = foo ();
+  assert (val ==  (*p)());
+
+  /* Check in the exact same order in which the dispatching
+     is expected to happen.  */
+  if (__builtin_cpu_is ("bdver1"))
+    assert (val == 1);
+  else if (__builtin_cpu_is ("bdver2"))
+    assert (val == 2);
+  else if (__builtin_cpu_supports ("avx2")
+          && __builtin_cpu_supports ("ssse3"))
+    assert (val == 3);
+  else if (__builtin_cpu_supports ("avx"))
+    assert (val == 4);
+  else if (__builtin_cpu_is ("corei7")
+          && __builtin_cpu_supports ("popcnt"))
+    assert (val == 5);
+  else if (__builtin_cpu_is ("corei7"))
+    assert (val == 6);
+  else if (__builtin_cpu_is ("amdfam10h"))
+    assert (val == 7);
+  else if (__builtin_cpu_is ("core2")
+          && __builtin_cpu_supports ("sse4.2"))
+    assert (val == 8);
+  else if (__builtin_cpu_is ("core2"))
+    assert (val == 9);
+  else if (__builtin_cpu_is ("atom"))
+    assert (val == 10);
+  else
+    assert (val == 0);
+  
+  return 0;
+}
+
+int __attribute__ ((target("default")))
+foo ()
+{
+  return 0;
+}
+
+int __attribute__ ((target("arch=corei7,popcnt")))
+foo ()
+{
+  return 5;
+}
+int __attribute__ ((target("avx2,ssse3")))
+foo ()
+{
+  return 3;
+}
+
+int __attribute__ ((target("arch=core2")))
+foo ()
+{
+  return 9;
+}
+
+int __attribute__ ((target("arch=corei7")))
+foo ()
+{
+  return 6;
+}
+
+int __attribute__ ((target("arch=atom")))
+foo ()
+{
+  return 10;
+}
+
+int __attribute__ ((target("avx")))
+foo ()
+{
+  return 4;
+}
+
+int __attribute__ ((target("arch=core2,sse4.2")))
+foo ()
+{
+  return 8;
+}
+
+int __attribute__ ((target("arch=amdfam10")))
+foo ()
+{
+  return 7;
+}
+
+int __attribute__ ((target("arch=bdver1")))
+foo ()
+{
+  return 1;
+}
+
+int __attribute__ ((target("arch=bdver2")))
+foo ()
+{
+  return 2;
+}
diff --git a/gcc/testsuite/g++.dg/ext/mv10.C b/gcc/testsuite/g++.dg/ext/mv10.C
new file mode 100644 (file)
index 0000000..5dfe363
--- /dev/null
@@ -0,0 +1,12 @@
+// { dg-do assemble { target i?86-*-* x86_64-*-* } }
+// { dg-options "" }
+
+__attribute__((target ("popcnt"), used))
+void foo (void)
+{
+}
+
+__attribute__((target ("popcnt","avx"), used))
+void foo (void)
+{
+}
diff --git a/gcc/testsuite/g++.dg/ext/mv11.C b/gcc/testsuite/g++.dg/ext/mv11.C
new file mode 100644 (file)
index 0000000..1f5c576
--- /dev/null
@@ -0,0 +1,23 @@
+// { dg-do compile { target i?86-*-* x86_64-*-* } }
+// { dg-options "-msse2" }
+
+int foo () __attribute__ ((target("default")));
+int foo () __attribute__ ((target("sse2")));
+
+int
+main ()
+{
+  return foo ();
+}
+
+int  __attribute__ ((target("default")))
+foo ()
+{
+  return 0;
+}
+
+int __attribute__ ((target("sse2")))
+foo ()
+{
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/ext/mv2.C b/gcc/testsuite/g++.dg/ext/mv2.C
new file mode 100644 (file)
index 0000000..869e99b
--- /dev/null
@@ -0,0 +1,118 @@
+/* Test case to check if Multiversioning chooses the correct
+   dispatching order when versions are for various ISAs.  */
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-require-ifunc "" }  */
+/* { dg-options "-O2" } */
+
+#include <assert.h>
+
+/* Default version.  */
+int foo () __attribute__ ((target ("default")));
+/* The dispatch checks should be in the exact reverse order of the
+   declarations below.  */
+int foo () __attribute__ ((target ("mmx")));
+int foo () __attribute__ ((target ("sse")));
+int foo () __attribute__ ((target ("sse2")));
+int foo () __attribute__ ((target ("sse3")));
+int foo () __attribute__ ((target ("ssse3")));
+int foo () __attribute__ ((target ("sse4.1")));
+int foo () __attribute__ ((target ("sse4.2")));
+int foo () __attribute__ ((target ("popcnt")));
+int foo () __attribute__ ((target ("avx")));
+int foo () __attribute__ ((target ("avx2")));
+
+int main ()
+{
+  int val = foo ();
+
+  if (__builtin_cpu_supports ("avx2"))
+    assert (val == 1);
+  else if (__builtin_cpu_supports ("avx"))
+    assert (val == 2);
+  else if (__builtin_cpu_supports ("popcnt"))
+    assert (val == 3);
+  else if (__builtin_cpu_supports ("sse4.2"))
+    assert (val == 4);
+  else if (__builtin_cpu_supports ("sse4.1"))
+    assert (val == 5);
+  else if (__builtin_cpu_supports ("ssse3"))
+    assert (val == 6);
+  else if (__builtin_cpu_supports ("sse3"))
+    assert (val == 7);
+  else if (__builtin_cpu_supports ("sse2"))
+    assert (val == 8);
+  else if (__builtin_cpu_supports ("sse"))
+    assert (val == 9);
+  else if (__builtin_cpu_supports ("mmx"))
+    assert (val == 10);
+  else
+    assert (val == 0);
+
+  return 0;
+}
+
+int __attribute__ ((target("default")))
+foo ()
+{
+  return 0;
+}
+
+int __attribute__ ((target("mmx")))
+foo ()
+{
+  return 10;
+}
+
+int __attribute__ ((target("sse")))
+foo ()
+{
+  return 9;
+}
+
+int __attribute__ ((target("sse2")))
+foo ()
+{
+  return 8;
+}
+
+int __attribute__ ((target("sse3")))
+foo ()
+{
+  return 7;
+}
+
+int __attribute__ ((target("ssse3")))
+foo ()
+{
+  return 6;
+}
+
+int __attribute__ ((target("sse4.1")))
+foo ()
+{
+  return 5;
+}
+
+int __attribute__ ((target("sse4.2")))
+foo ()
+{
+  return 4;
+}
+
+int __attribute__ ((target("popcnt")))
+foo ()
+{
+  return 3;
+}
+
+int __attribute__ ((target("avx")))
+foo ()
+{
+  return 2;
+}
+
+int __attribute__ ((target("avx2")))
+foo ()
+{
+  return 1;
+}
diff --git a/gcc/testsuite/g++.dg/ext/mv3.C b/gcc/testsuite/g++.dg/ext/mv3.C
new file mode 100644 (file)
index 0000000..ec2aa1f
--- /dev/null
@@ -0,0 +1,36 @@
+/* Test case to check if a call to a multiversioned function
+   is replaced with a direct call to the particular version when
+   the most specialized version's target attributes match the
+   caller.  
+  
+   In this program, foo is multiversioned but there is no default
+   function.  This is an error if the call has to go through a
+   dispatcher.  However, the call to foo in bar can be replaced
+   with a direct call to the popcnt version of foo.  Hence, this
+   test should pass.  */
+
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-O2" } */
+
+
+int __attribute__ ((target ("sse")))
+foo ()
+{
+  return 1;
+}
+int __attribute__ ((target ("popcnt")))
+foo ()
+{
+  return 0;
+}
+
+int __attribute__ ((target ("popcnt")))
+bar ()
+{
+  return foo ();
+}
+
+int main ()
+{
+  return bar ();
+}
diff --git a/gcc/testsuite/g++.dg/ext/mv4.C b/gcc/testsuite/g++.dg/ext/mv4.C
new file mode 100644 (file)
index 0000000..ff1cc2f
--- /dev/null
@@ -0,0 +1,24 @@
+/* Test case to check if the compiler generates an error message
+   when the default version of a multiversioned function is absent
+   and its pointer is taken.  */
+
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-require-ifunc "" }  */
+/* { dg-options "-O2" } */
+
+int __attribute__ ((target ("sse")))
+foo ()
+{
+  return 1;
+}
+int __attribute__ ((target ("popcnt")))
+foo ()
+{
+  return 0;
+}
+
+int main ()
+{
+  int (*p)() = &foo; /* { dg-error "use of multiversioned function without a default" {} } */
+  return (*p)();
+}
diff --git a/gcc/testsuite/g++.dg/ext/mv5.C b/gcc/testsuite/g++.dg/ext/mv5.C
new file mode 100644 (file)
index 0000000..fd62eee
--- /dev/null
@@ -0,0 +1,25 @@
+/* Test case to check if multiversioned functions are still generated if they are
+   marked comdat with inline keyword.  */
+
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-require-ifunc "" }  */
+/* { dg-options "-O2" } */
+
+
+/* Default version.  */
+inline int __attribute__ ((target ("default")))
+foo ()
+{
+  return 0;
+}
+
+inline int __attribute__ ((target ("popcnt")))
+foo ()
+{
+  return 0;
+}
+
+int main ()
+{
+  return foo ();
+}
diff --git a/gcc/testsuite/g++.dg/ext/mv6.C b/gcc/testsuite/g++.dg/ext/mv6.C
new file mode 100644 (file)
index 0000000..2273065
--- /dev/null
@@ -0,0 +1,28 @@
+/* Test to check if member version multiversioning works correctly.  */
+
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-require-ifunc "" }  */
+/* { dg-options "-march=x86-64" } */
+
+class Foo
+{
+ public:
+  /* Default version of foo.  */
+  __attribute__ ((target("default")))
+  int foo ()
+  {
+    return 0;
+  }
+  /* corei7 version of foo.  */
+  __attribute__ ((target("arch=corei7")))
+  int foo ()
+  {
+    return 0;
+  }
+};
+
+int main ()
+{
+  Foo f;
+  return f.foo ();
+}
diff --git a/gcc/testsuite/g++.dg/ext/mv7.C b/gcc/testsuite/g++.dg/ext/mv7.C
new file mode 100644 (file)
index 0000000..d378402
--- /dev/null
@@ -0,0 +1,12 @@
+// { dg-do compile { target i?86-*-* x86_64-*-* } }
+// { dg-options "" }
+
+__attribute__((target ("default")))
+void foo (void)        // { dg-error "previously defined here" }
+{
+}
+
+__attribute__((target (128)))
+void foo (void) // { dg-error "(not a string|redefinition)" }
+{
+}
diff --git a/gcc/testsuite/g++.dg/ext/mv8.C b/gcc/testsuite/g++.dg/ext/mv8.C
new file mode 100644 (file)
index 0000000..2e98dd7
--- /dev/null
@@ -0,0 +1,7 @@
+// { dg-do compile { target i?86-*-* x86_64-*-* } }
+// { dg-options "" }
+
+__attribute__((target (11,12)))
+void foo (void) // { dg-error "not a string" }
+{
+}
diff --git a/gcc/testsuite/g++.dg/ext/mv9.C b/gcc/testsuite/g++.dg/ext/mv9.C
new file mode 100644 (file)
index 0000000..53ee995
--- /dev/null
@@ -0,0 +1,9 @@
+// { dg-do compile { target i?86-*-* x86_64-*-* } }    
+// { dg-options "" }   
+
+void foo ();
+void foo () __attribute__((target ("sse4")));
+void foo () __attribute__((target ("default"))); // { dg-error "previous declaration" }
+void foo ()    // { dg-error "attribute for multi-versioned" }
+{
+}
diff --git a/gcc/testsuite/g++.dg/mv1.C b/gcc/testsuite/g++.dg/mv1.C
deleted file mode 100644 (file)
index bad0c44..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-/* Test case to check if Multiversioning works.  */
-/* { dg-do run { target i?86-*-* x86_64-*-* } } */
-/* { dg-require-ifunc "" }  */
-/* { dg-options "-O2 -fPIC" } */
-
-#include <assert.h>
-
-/* Default version.  */
-int foo ();
-/* The other versions of foo.  Mix up the ordering and 
-   check if the dispatching does it in the order of priority. */
-/* Check combination of target attributes.  */
-int foo () __attribute__ ((target("arch=corei7,popcnt")));
-/* The target operands in this declaration and the definition are re-ordered.
-   This should still work.  */
-int foo () __attribute__ ((target("ssse3,avx2")));
-
-/* Check for all target attributes for which dispatchers are available.  */
-/* Check arch= */
-int foo () __attribute__((target("arch=core2")));
-int foo () __attribute__((target("arch=corei7")));
-int foo () __attribute__((target("arch=atom")));
-/* Check ISAs  */
-int foo () __attribute__((target("avx")));
-int foo () __attribute__ ((target("arch=core2,sse4.2")));
-/* Check more arch=.  */
-int foo () __attribute__((target("arch=amdfam10")));
-int foo () __attribute__((target("arch=bdver1")));
-int foo () __attribute__((target("arch=bdver2")));
-
-int (*p)() = &foo;
-int main ()
-{
-  int val = foo ();
-  assert (val ==  (*p)());
-
-  /* Check in the exact same order in which the dispatching
-     is expected to happen.  */
-  if (__builtin_cpu_is ("bdver1"))
-    assert (val == 1);
-  else if (__builtin_cpu_is ("bdver2"))
-    assert (val == 2);
-  else if (__builtin_cpu_supports ("avx2")
-          && __builtin_cpu_supports ("ssse3"))
-    assert (val == 3);
-  else if (__builtin_cpu_supports ("avx"))
-    assert (val == 4);
-  else if (__builtin_cpu_is ("corei7")
-          && __builtin_cpu_supports ("popcnt"))
-    assert (val == 5);
-  else if (__builtin_cpu_is ("corei7"))
-    assert (val == 6);
-  else if (__builtin_cpu_is ("amdfam10h"))
-    assert (val == 7);
-  else if (__builtin_cpu_is ("core2")
-          && __builtin_cpu_supports ("sse4.2"))
-    assert (val == 8);
-  else if (__builtin_cpu_is ("core2"))
-    assert (val == 9);
-  else if (__builtin_cpu_is ("atom"))
-    assert (val == 10);
-  else
-    assert (val == 0);
-  
-  return 0;
-}
-
-int foo ()
-{
-  return 0;
-}
-
-int __attribute__ ((target("arch=corei7,popcnt")))
-foo ()
-{
-  return 5;
-}
-int __attribute__ ((target("avx2,ssse3")))
-foo ()
-{
-  return 3;
-}
-
-int __attribute__ ((target("arch=core2")))
-foo ()
-{
-  return 9;
-}
-
-int __attribute__ ((target("arch=corei7")))
-foo ()
-{
-  return 6;
-}
-
-int __attribute__ ((target("arch=atom")))
-foo ()
-{
-  return 10;
-}
-
-int __attribute__ ((target("avx")))
-foo ()
-{
-  return 4;
-}
-
-int __attribute__ ((target("arch=core2,sse4.2")))
-foo ()
-{
-  return 8;
-}
-
-int __attribute__ ((target("arch=amdfam10")))
-foo ()
-{
-  return 7;
-}
-
-int __attribute__ ((target("arch=bdver1")))
-foo ()
-{
-  return 1;
-}
-
-int __attribute__ ((target("arch=bdver2")))
-foo ()
-{
-  return 2;
-}
diff --git a/gcc/testsuite/g++.dg/mv2.C b/gcc/testsuite/g++.dg/mv2.C
deleted file mode 100644 (file)
index baaa5da..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/* Test case to check if Multiversioning chooses the correct
-   dispatching order when versions are for various ISAs.  */
-/* { dg-do run { target i?86-*-* x86_64-*-* } } */
-/* { dg-require-ifunc "" }  */
-/* { dg-options "-O2" } */
-
-#include <assert.h>
-
-/* Default version.  */
-int foo ();
-/* The dispatch checks should be in the exact reverse order of the
-   declarations below.  */
-int foo () __attribute__ ((target ("mmx")));
-int foo () __attribute__ ((target ("sse")));
-int foo () __attribute__ ((target ("sse2")));
-int foo () __attribute__ ((target ("sse3")));
-int foo () __attribute__ ((target ("ssse3")));
-int foo () __attribute__ ((target ("sse4.1")));
-int foo () __attribute__ ((target ("sse4.2")));
-int foo () __attribute__ ((target ("popcnt")));
-int foo () __attribute__ ((target ("avx")));
-int foo () __attribute__ ((target ("avx2")));
-
-int main ()
-{
-  int val = foo ();
-
-  if (__builtin_cpu_supports ("avx2"))
-    assert (val == 1);
-  else if (__builtin_cpu_supports ("avx"))
-    assert (val == 2);
-  else if (__builtin_cpu_supports ("popcnt"))
-    assert (val == 3);
-  else if (__builtin_cpu_supports ("sse4.2"))
-    assert (val == 4);
-  else if (__builtin_cpu_supports ("sse4.1"))
-    assert (val == 5);
-  else if (__builtin_cpu_supports ("ssse3"))
-    assert (val == 6);
-  else if (__builtin_cpu_supports ("sse3"))
-    assert (val == 7);
-  else if (__builtin_cpu_supports ("sse2"))
-    assert (val == 8);
-  else if (__builtin_cpu_supports ("sse"))
-    assert (val == 9);
-  else if (__builtin_cpu_supports ("mmx"))
-    assert (val == 10);
-  else
-    assert (val == 0);
-
-  return 0;
-}
-
-int
-foo ()
-{
-  return 0;
-}
-
-int __attribute__ ((target("mmx")))
-foo ()
-{
-  return 10;
-}
-
-int __attribute__ ((target("sse")))
-foo ()
-{
-  return 9;
-}
-
-int __attribute__ ((target("sse2")))
-foo ()
-{
-  return 8;
-}
-
-int __attribute__ ((target("sse3")))
-foo ()
-{
-  return 7;
-}
-
-int __attribute__ ((target("ssse3")))
-foo ()
-{
-  return 6;
-}
-
-int __attribute__ ((target("sse4.1")))
-foo ()
-{
-  return 5;
-}
-
-int __attribute__ ((target("sse4.2")))
-foo ()
-{
-  return 4;
-}
-
-int __attribute__ ((target("popcnt")))
-foo ()
-{
-  return 3;
-}
-
-int __attribute__ ((target("avx")))
-foo ()
-{
-  return 2;
-}
-
-int __attribute__ ((target("avx2")))
-foo ()
-{
-  return 1;
-}
diff --git a/gcc/testsuite/g++.dg/mv3.C b/gcc/testsuite/g++.dg/mv3.C
deleted file mode 100644 (file)
index ec2aa1f..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/* Test case to check if a call to a multiversioned function
-   is replaced with a direct call to the particular version when
-   the most specialized version's target attributes match the
-   caller.  
-  
-   In this program, foo is multiversioned but there is no default
-   function.  This is an error if the call has to go through a
-   dispatcher.  However, the call to foo in bar can be replaced
-   with a direct call to the popcnt version of foo.  Hence, this
-   test should pass.  */
-
-/* { dg-do run { target i?86-*-* x86_64-*-* } } */
-/* { dg-options "-O2" } */
-
-
-int __attribute__ ((target ("sse")))
-foo ()
-{
-  return 1;
-}
-int __attribute__ ((target ("popcnt")))
-foo ()
-{
-  return 0;
-}
-
-int __attribute__ ((target ("popcnt")))
-bar ()
-{
-  return foo ();
-}
-
-int main ()
-{
-  return bar ();
-}
diff --git a/gcc/testsuite/g++.dg/mv4.C b/gcc/testsuite/g++.dg/mv4.C
deleted file mode 100644 (file)
index ff1cc2f..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/* Test case to check if the compiler generates an error message
-   when the default version of a multiversioned function is absent
-   and its pointer is taken.  */
-
-/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
-/* { dg-require-ifunc "" }  */
-/* { dg-options "-O2" } */
-
-int __attribute__ ((target ("sse")))
-foo ()
-{
-  return 1;
-}
-int __attribute__ ((target ("popcnt")))
-foo ()
-{
-  return 0;
-}
-
-int main ()
-{
-  int (*p)() = &foo; /* { dg-error "use of multiversioned function without a default" {} } */
-  return (*p)();
-}
diff --git a/gcc/testsuite/g++.dg/mv5.C b/gcc/testsuite/g++.dg/mv5.C
deleted file mode 100644 (file)
index 93daab6..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/* Test case to check if multiversioned functions are still generated if they are
-   marked comdat with inline keyword.  */
-
-/* { dg-do run { target i?86-*-* x86_64-*-* } } */
-/* { dg-require-ifunc "" }  */
-/* { dg-options "-O2" } */
-
-
-/* Default version.  */
-inline int
-foo ()
-{
-  return 0;
-}
-
-inline int __attribute__ ((target ("popcnt")))
-foo ()
-{
-  return 0;
-}
-
-int main ()
-{
-  return foo ();
-}
diff --git a/gcc/testsuite/g++.dg/mv6.C b/gcc/testsuite/g++.dg/mv6.C
deleted file mode 100644 (file)
index c0323f6..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/* Test to check if member version multiversioning works correctly.  */
-
-/* { dg-do run { target i?86-*-* x86_64-*-* } } */
-/* { dg-require-ifunc "" }  */
-/* { dg-options "-march=x86-64" } */
-
-class Foo
-{
- public:
-  /* Default version of foo.  */
-  int foo ()
-  {
-    return 0;
-  }
-  /* corei7 version of foo.  */
-  __attribute__ ((target("arch=corei7")))
-  int foo ()
-  {
-    return 0;
-  }
-};
-
-int main ()
-{
-  Foo f;
-  return f.foo ();
-}