diff options
-rw-r--r-- | gcc/ada/gcc-interface/utils.cc | 6 | ||||
-rw-r--r-- | gcc/attribs.cc | 8 | ||||
-rw-r--r-- | gcc/c-family/c-attribs.cc | 40 | ||||
-rw-r--r-- | gcc/cgraphclones.cc | 13 | ||||
-rw-r--r-- | gcc/cp/decl2.cc | 4 | ||||
-rw-r--r-- | gcc/d/d-attribs.cc | 6 | ||||
-rw-r--r-- | gcc/defaults.h | 10 | ||||
-rw-r--r-- | gcc/doc/tm.texi | 12 | ||||
-rw-r--r-- | gcc/doc/tm.texi.in | 2 | ||||
-rw-r--r-- | gcc/multiple_target.cc | 10 | ||||
-rw-r--r-- | gcc/target.def | 17 | ||||
-rw-r--r-- | gcc/targhooks.cc | 14 | ||||
-rw-r--r-- | gcc/targhooks.h | 1 | ||||
-rw-r--r-- | gcc/tree.h | 4 |
14 files changed, 124 insertions, 23 deletions
diff --git a/gcc/ada/gcc-interface/utils.cc b/gcc/ada/gcc-interface/utils.cc index 3eabbec..17f6afd 100644 --- a/gcc/ada/gcc-interface/utils.cc +++ b/gcc/ada/gcc-interface/utils.cc @@ -146,14 +146,16 @@ static const struct attribute_spec::exclusions attr_noinline_exclusions[] = static const struct attribute_spec::exclusions attr_target_exclusions[] = { - { "target_clones", true, true, true }, + { "target_clones", TARGET_HAS_FMV_TARGET_ATTRIBUTE, + TARGET_HAS_FMV_TARGET_ATTRIBUTE, TARGET_HAS_FMV_TARGET_ATTRIBUTE }, { NULL, false, false, false }, }; static const struct attribute_spec::exclusions attr_target_clones_exclusions[] = { { "always_inline", true, true, true }, - { "target", true, true, true }, + { "target", TARGET_HAS_FMV_TARGET_ATTRIBUTE, TARGET_HAS_FMV_TARGET_ATTRIBUTE, + TARGET_HAS_FMV_TARGET_ATTRIBUTE }, { NULL, false, false, false }, }; diff --git a/gcc/attribs.cc b/gcc/attribs.cc index 4e313d3..0ca2779 100644 --- a/gcc/attribs.cc +++ b/gcc/attribs.cc @@ -675,7 +675,8 @@ decl_attributes (tree *node, tree attributes, int flags, options to the attribute((target(...))) list. */ if (TREE_CODE (*node) == FUNCTION_DECL && current_target_pragma - && targetm.target_option.valid_attribute_p (*node, NULL_TREE, + && targetm.target_option.valid_attribute_p (*node, + get_identifier ("target"), current_target_pragma, 0)) { tree cur_attr = lookup_attribute ("target", attributes); @@ -1276,8 +1277,9 @@ make_dispatcher_decl (const tree decl) return func_decl; } -/* Returns true if decl is multi-versioned and DECL is the default function, - that is it is not tagged with target specific optimization. */ +/* Returns true if DECL is multi-versioned using the target attribute, and this + is the default version. This function can only be used for targets that do + not support the "target_version" attribute. */ bool is_function_default_version (const tree decl) diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc index 9638848..169c96a 100644 --- a/gcc/c-family/c-attribs.cc +++ b/gcc/c-family/c-attribs.cc @@ -151,6 +151,7 @@ static tree handle_alloc_align_attribute (tree *, tree, tree, int, bool *); static tree handle_assume_aligned_attribute (tree *, tree, tree, int, bool *); static tree handle_assume_attribute (tree *, tree, tree, int, bool *); static tree handle_target_attribute (tree *, tree, tree, int, bool *); +static tree handle_target_version_attribute (tree *, tree, tree, int, bool *); static tree handle_target_clones_attribute (tree *, tree, tree, int, bool *); static tree handle_optimize_attribute (tree *, tree, tree, int, bool *); static tree ignore_attribute (tree *, tree, tree, int, bool *); @@ -233,14 +234,23 @@ static const struct attribute_spec::exclusions attr_noinline_exclusions[] = static const struct attribute_spec::exclusions attr_target_exclusions[] = { - ATTR_EXCL ("target_clones", true, true, true), + ATTR_EXCL ("target_clones", TARGET_HAS_FMV_TARGET_ATTRIBUTE, + TARGET_HAS_FMV_TARGET_ATTRIBUTE, TARGET_HAS_FMV_TARGET_ATTRIBUTE), ATTR_EXCL (NULL, false, false, false), }; static const struct attribute_spec::exclusions attr_target_clones_exclusions[] = { ATTR_EXCL ("always_inline", true, true, true), - ATTR_EXCL ("target", true, true, true), + ATTR_EXCL ("target", TARGET_HAS_FMV_TARGET_ATTRIBUTE, + TARGET_HAS_FMV_TARGET_ATTRIBUTE, TARGET_HAS_FMV_TARGET_ATTRIBUTE), + ATTR_EXCL ("target_version", true, true, true), + ATTR_EXCL (NULL, false, false, false), +}; + +static const struct attribute_spec::exclusions attr_target_version_exclusions[] = +{ + ATTR_EXCL ("target_clones", true, true, true), ATTR_EXCL (NULL, false, false, false), }; @@ -512,6 +522,9 @@ const struct attribute_spec c_common_gnu_attributes[] = { "target", 1, -1, true, false, false, false, handle_target_attribute, attr_target_exclusions }, + { "target_version", 1, 1, true, false, false, false, + handle_target_version_attribute, + attr_target_version_exclusions }, { "target_clones", 1, -1, true, false, false, false, handle_target_clones_attribute, attr_target_clones_exclusions }, @@ -5830,7 +5843,7 @@ static tree handle_target_attribute (tree *node, tree name, tree args, int flags, bool *no_add_attrs) { - /* Ensure we have a function type. */ + /* Ensure we have a function declaration. */ if (TREE_CODE (*node) != FUNCTION_DECL) { warning (OPT_Wattributes, "%qE attribute ignored", name); @@ -5856,13 +5869,32 @@ handle_target_attribute (tree *node, tree name, tree args, int flags, return NULL_TREE; } +/* Handle a "target_version" attribute. */ + +static tree +handle_target_version_attribute (tree *node, tree name, tree args, int flags, + bool *no_add_attrs) +{ + /* Ensure we have a function declaration. */ + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + else if (!targetm.target_option.valid_version_attribute_p (*node, name, args, + flags)) + *no_add_attrs = true; + + return NULL_TREE; +} + /* Handle a "target_clones" attribute. */ static tree handle_target_clones_attribute (tree *node, tree name, tree ARG_UNUSED (args), int ARG_UNUSED (flags), bool *no_add_attrs) { - /* Ensure we have a function type. */ + /* Ensure we have a function declaration. */ if (TREE_CODE (*node) == FUNCTION_DECL) { for (tree t = args; t != NULL_TREE; t = TREE_CHAIN (t)) diff --git a/gcc/cgraphclones.cc b/gcc/cgraphclones.cc index 29d28ef..3ba5a4a 100644 --- a/gcc/cgraphclones.cc +++ b/gcc/cgraphclones.cc @@ -78,6 +78,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-eh.h" #include "tree-cfg.h" #include "tree-inline.h" +#include "attribs.h" #include "dumpfile.h" #include "gimple-pretty-print.h" #include "alloc-pool.h" @@ -1048,7 +1049,17 @@ cgraph_node::create_version_clone_with_body location_t saved_loc = input_location; tree v = TREE_VALUE (target_attributes); input_location = DECL_SOURCE_LOCATION (new_decl); - bool r = targetm.target_option.valid_attribute_p (new_decl, NULL, v, 1); + bool r; + tree name_id = get_attribute_name (target_attributes); + const char *name_str = IDENTIFIER_POINTER (name_id); + if (strcmp (name_str, "target") == 0) + r = targetm.target_option.valid_attribute_p (new_decl, name_id, v, 1); + else if (strcmp (name_str, "target_version") == 0) + r = targetm.target_option.valid_version_attribute_p (new_decl, name_id, + v, 1); + else + gcc_unreachable(); + input_location = saved_loc; if (!r) return NULL; diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index bee8487..0850d3f 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -834,8 +834,8 @@ check_classfn (tree ctype, tree function, tree template_parms) tree c2 = get_constraints (fndecl); /* While finding a match, same types and params are not enough - if the function is versioned. Also check version ("target") - attributes. */ + if the function is versioned. Also check for different target + specific attributes. */ if (same_type_p (TREE_TYPE (TREE_TYPE (function)), TREE_TYPE (TREE_TYPE (fndecl))) && compparms (p1, p2) diff --git a/gcc/d/d-attribs.cc b/gcc/d/d-attribs.cc index 3b69c53..52f3b27 100644 --- a/gcc/d/d-attribs.cc +++ b/gcc/d/d-attribs.cc @@ -128,14 +128,16 @@ static const struct attribute_spec::exclusions attr_noinline_exclusions[] = static const struct attribute_spec::exclusions attr_target_exclusions[] = { - ATTR_EXCL ("target_clones", true, true, true), + ATTR_EXCL ("target_clones", TARGET_HAS_FMV_TARGET_ATTRIBUTE, + TARGET_HAS_FMV_TARGET_ATTRIBUTE, TARGET_HAS_FMV_TARGET_ATTRIBUTE), ATTR_EXCL (NULL, false, false, false), }; static const struct attribute_spec::exclusions attr_target_clones_exclusions[] = { ATTR_EXCL ("always_inline", true, true, true), - ATTR_EXCL ("target", true, true, true), + ATTR_EXCL ("target", TARGET_HAS_FMV_TARGET_ATTRIBUTE, + TARGET_HAS_FMV_TARGET_ATTRIBUTE, TARGET_HAS_FMV_TARGET_ATTRIBUTE), ATTR_EXCL (NULL, false, false, false), }; diff --git a/gcc/defaults.h b/gcc/defaults.h index dc6f09c..6f09596 100644 --- a/gcc/defaults.h +++ b/gcc/defaults.h @@ -877,6 +877,16 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #endif #endif +/* Indicate whether the target uses "target" attributes for function + multiversioning. This is used to choose between the "target" and + "target_version" attributes when expanding a "target_clones" attribute, and + determine whether the "target" and "target_clones" attributes are mutually + exclusive. */ +#ifndef TARGET_HAS_FMV_TARGET_ATTRIBUTE +#define TARGET_HAS_FMV_TARGET_ATTRIBUTE 1 +#endif + + /* Select a format to encode pointers in exception handling data. We prefer those that result in fewer dynamic relocations. Assume no special support here and encode direct references. */ diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 0bb6da0..22a1beb 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -10741,6 +10741,18 @@ the function declaration to hold a pointer to a target-specific @code{struct cl_target_option} structure. @end deftypefn +@deftypefn {Target Hook} bool TARGET_OPTION_VALID_VERSION_ATTRIBUTE_P (tree @var{fndecl}, tree @var{name}, tree @var{args}, int @var{flags}) +This hook is called to parse @code{attribute(target_version("..."))}, +which allows setting target-specific options on individual function versions. +These function-specific options may differ +from the options specified on the command line. The hook should return +@code{true} if the options are valid. + +The hook should set the @code{DECL_FUNCTION_SPECIFIC_TARGET} field in +the function declaration to hold a pointer to a target-specific +@code{struct cl_target_option} structure. +@end deftypefn + @deftypefn {Target Hook} void TARGET_OPTION_SAVE (struct cl_target_option *@var{ptr}, struct gcc_options *@var{opts}, struct gcc_options *@var{opts_set}) This hook is called to save any additional target-specific information in the @code{struct cl_target_option} structure for function-specific diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 4fe0805..f92cb76 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -7066,6 +7066,8 @@ on this implementation detail. @hook TARGET_OPTION_VALID_ATTRIBUTE_P +@hook TARGET_OPTION_VALID_VERSION_ATTRIBUTE_P + @hook TARGET_OPTION_SAVE @hook TARGET_OPTION_RESTORE diff --git a/gcc/multiple_target.cc b/gcc/multiple_target.cc index a2ed048..a832d1e 100644 --- a/gcc/multiple_target.cc +++ b/gcc/multiple_target.cc @@ -66,10 +66,6 @@ create_dispatcher_calls (struct cgraph_node *node) { ipa_ref *ref; - if (!DECL_FUNCTION_VERSIONED (node->decl) - || !is_function_default_version (node->decl)) - return; - if (!targetm.has_ifunc_p ()) { error_at (DECL_SOURCE_LOCATION (node->decl), @@ -377,6 +373,8 @@ expand_target_clones (struct cgraph_node *node, bool definition) return false; } + const char *new_attr_name = (TARGET_HAS_FMV_TARGET_ATTRIBUTE + ? "target" : "target_version"); cgraph_function_version_info *decl1_v = NULL; cgraph_function_version_info *decl2_v = NULL; cgraph_function_version_info *before = NULL; @@ -392,7 +390,7 @@ expand_target_clones (struct cgraph_node *node, bool definition) char *attr = attrs[i]; /* Create new target clone. */ - tree attributes = make_attribute ("target", attr, + tree attributes = make_attribute (new_attr_name, attr, DECL_ATTRIBUTES (node->decl)); char *suffix = XNEWVEC (char, strlen (attr) + 1); @@ -430,7 +428,7 @@ expand_target_clones (struct cgraph_node *node, bool definition) XDELETEVEC (attr_str); /* Setting new attribute to initial function. */ - tree attributes = make_attribute ("target", "default", + tree attributes = make_attribute (new_attr_name, "default", DECL_ATTRIBUTES (node->decl)); DECL_ATTRIBUTES (node->decl) = attributes; node->local = false; diff --git a/gcc/target.def b/gcc/target.def index ca030ab..0509e07 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -6635,6 +6635,23 @@ the function declaration to hold a pointer to a target-specific\n\ bool, (tree fndecl, tree name, tree args, int flags), default_target_option_valid_attribute_p) +/* Function to validate the attribute((target_version(...))) strings. If + the option is validated, the hook should also fill in + DECL_FUNCTION_SPECIFIC_TARGET in the function decl node. */ +DEFHOOK +(valid_version_attribute_p, + "This hook is called to parse @code{attribute(target_version(\"...\"))},\n\ +which allows setting target-specific options on individual function versions.\n\ +These function-specific options may differ\n\ +from the options specified on the command line. The hook should return\n\ +@code{true} if the options are valid.\n\ +\n\ +The hook should set the @code{DECL_FUNCTION_SPECIFIC_TARGET} field in\n\ +the function declaration to hold a pointer to a target-specific\n\ +@code{struct cl_target_option} structure.", + bool, (tree fndecl, tree name, tree args, int flags), + default_target_option_valid_version_attribute_p) + /* Function to save any extra target state in the target options structure. */ DEFHOOK (save, diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc index afe91fe1..1cc0895 100644 --- a/gcc/targhooks.cc +++ b/gcc/targhooks.cc @@ -1799,7 +1799,19 @@ default_target_option_valid_attribute_p (tree ARG_UNUSED (fndecl), int ARG_UNUSED (flags)) { warning (OPT_Wattributes, - "target attribute is not supported on this machine"); + "%<target%> attribute is not supported on this machine"); + + return false; +} + +bool +default_target_option_valid_version_attribute_p (tree ARG_UNUSED (fndecl), + tree ARG_UNUSED (name), + tree ARG_UNUSED (args), + int ARG_UNUSED (flags)) +{ + warning (OPT_Wattributes, + "%<target_version%> attribute is not supported on this machine"); return false; } diff --git a/gcc/targhooks.h b/gcc/targhooks.h index 5a39e8e..7996cb4 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -193,6 +193,7 @@ extern bool default_hard_regno_scratch_ok (unsigned int); extern bool default_mode_dependent_address_p (const_rtx, addr_space_t); extern bool default_new_address_profitable_p (rtx, rtx_insn *, rtx); extern bool default_target_option_valid_attribute_p (tree, tree, tree, int); +extern bool default_target_option_valid_version_attribute_p (tree, tree, tree, int); extern bool default_target_option_pragma_parse (tree, tree); extern bool default_target_can_inline_p (tree, tree); extern bool default_update_ipa_fn_target_info (unsigned int &, const gimple *); @@ -3510,8 +3510,8 @@ extern vec<tree, va_gc> **decl_debug_args_insert (tree); (FUNCTION_DECL_CHECK (NODE)->function_decl.function_specific_optimization) /* In FUNCTION_DECL, this is set if this function has other versions generated - using "target" attributes. The default version is the one which does not - have any "target" attribute set. */ + to support different architecture feature sets, e.g. using "target" or + "target_version" attributes. */ #define DECL_FUNCTION_VERSIONED(NODE)\ (FUNCTION_DECL_CHECK (NODE)->function_decl.versioned_function) |