aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ada/gcc-interface/utils.cc6
-rw-r--r--gcc/attribs.cc8
-rw-r--r--gcc/c-family/c-attribs.cc40
-rw-r--r--gcc/cgraphclones.cc13
-rw-r--r--gcc/cp/decl2.cc4
-rw-r--r--gcc/d/d-attribs.cc6
-rw-r--r--gcc/defaults.h10
-rw-r--r--gcc/doc/tm.texi12
-rw-r--r--gcc/doc/tm.texi.in2
-rw-r--r--gcc/multiple_target.cc10
-rw-r--r--gcc/target.def17
-rw-r--r--gcc/targhooks.cc14
-rw-r--r--gcc/targhooks.h1
-rw-r--r--gcc/tree.h4
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 *);
diff --git a/gcc/tree.h b/gcc/tree.h
index cec9f6c..4829f84 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -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)