static void
prepend_one_attribute_pragma (struct attrib **attr_list, Node_Id gnat_pragma)
{
- const Node_Id gnat_arg = Pragma_Argument_Associations (gnat_pragma);
- tree gnu_arg0 = NULL_TREE, gnu_arg1 = NULL_TREE;
+ const Node_Id gnat_arg = First (Pragma_Argument_Associations (gnat_pragma));
+ Node_Id gnat_next_arg = Next (gnat_arg);
+ tree gnu_arg1 = NULL_TREE, gnu_arg_list = NULL_TREE;
enum attrib_type etype;
/* Map the pragma at hand. Skip if this isn't one we know how to handle. */
switch (Get_Pragma_Id (Chars (Pragma_Identifier (gnat_pragma))))
{
- case Pragma_Machine_Attribute:
- etype = ATTR_MACHINE_ATTRIBUTE;
- break;
-
case Pragma_Linker_Alias:
etype = ATTR_LINK_ALIAS;
break;
- case Pragma_Linker_Section:
- etype = ATTR_LINK_SECTION;
- break;
-
case Pragma_Linker_Constructor:
etype = ATTR_LINK_CONSTRUCTOR;
break;
etype = ATTR_LINK_DESTRUCTOR;
break;
- case Pragma_Weak_External:
- etype = ATTR_WEAK_EXTERNAL;
+ case Pragma_Linker_Section:
+ etype = ATTR_LINK_SECTION;
+ break;
+
+ case Pragma_Machine_Attribute:
+ etype = ATTR_MACHINE_ATTRIBUTE;
break;
case Pragma_Thread_Local_Storage:
etype = ATTR_THREAD_LOCAL_STORAGE;
break;
+ case Pragma_Weak_External:
+ etype = ATTR_WEAK_EXTERNAL;
+ break;
+
default:
return;
}
/* See what arguments we have and turn them into GCC trees for attribute
- handlers. These expect identifier for strings. We handle at most two
- arguments and static expressions only. */
- if (Present (gnat_arg) && Present (First (gnat_arg)))
+ handlers. The first one is always expected to be a string meant to be
+ turned into an identifier. The next ones are all static expressions,
+ among which strings meant to be turned into an identifier, except for
+ a couple of specific attributes that require raw strings. */
+ if (Present (gnat_next_arg))
{
- Node_Id gnat_arg0 = Next (First (gnat_arg));
- Node_Id gnat_arg1 = Empty;
-
- if (Present (gnat_arg0)
- && Is_OK_Static_Expression (Expression (gnat_arg0)))
- {
- gnu_arg0 = gnat_to_gnu (Expression (gnat_arg0));
-
- if (TREE_CODE (gnu_arg0) == STRING_CST)
- {
- gnu_arg0 = get_identifier (TREE_STRING_POINTER (gnu_arg0));
- if (IDENTIFIER_LENGTH (gnu_arg0) == 0)
- return;
- }
-
- gnat_arg1 = Next (gnat_arg0);
- }
-
- if (Present (gnat_arg1)
- && Is_OK_Static_Expression (Expression (gnat_arg1)))
+ gnu_arg1 = gnat_to_gnu (Expression (gnat_next_arg));
+ gcc_assert (TREE_CODE (gnu_arg1) == STRING_CST);
+
+ const char *const p = TREE_STRING_POINTER (gnu_arg1);
+ const bool string_args
+ = strcmp (p, "target") == 0 || strcmp (p, "target_clones") == 0;
+ gnu_arg1 = get_identifier (p);
+ if (IDENTIFIER_LENGTH (gnu_arg1) == 0)
+ return;
+ gnat_next_arg = Next (gnat_next_arg);
+
+ while (Present (gnat_next_arg))
{
- gnu_arg1 = gnat_to_gnu (Expression (gnat_arg1));
-
- if (TREE_CODE (gnu_arg1) == STRING_CST)
- gnu_arg1 = get_identifier (TREE_STRING_POINTER (gnu_arg1));
+ tree gnu_arg = gnat_to_gnu (Expression (gnat_next_arg));
+ if (TREE_CODE (gnu_arg) == STRING_CST && !string_args)
+ gnu_arg = get_identifier (TREE_STRING_POINTER (gnu_arg));
+ gnu_arg_list
+ = chainon (gnu_arg_list, build_tree_list (NULL_TREE, gnu_arg));
+ gnat_next_arg = Next (gnat_next_arg);
}
}
- /* Prepend to the list. Make a list of the argument we might have, as GCC
- expects it. */
- prepend_one_attribute (attr_list, etype, gnu_arg0,
- gnu_arg1
- ? build_tree_list (NULL_TREE, gnu_arg1) : NULL_TREE,
- Present (Next (First (gnat_arg)))
- ? Expression (Next (First (gnat_arg))) : gnat_pragma);
+ prepend_one_attribute (attr_list, etype, gnu_arg1, gnu_arg_list,
+ Present (Next (gnat_arg))
+ ? Expression (Next (gnat_arg)) : gnat_pragma);
}
/* Prepend to ATTR_LIST the list of attributes for GNAT_ENTITY, if any. */
static tree handle_stack_protect_attribute (tree *, tree, tree, int, bool *);
static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
static tree handle_noclone_attribute (tree *, tree, tree, int, bool *);
+static tree handle_noicf_attribute (tree *, tree, tree, int, bool *);
+static tree handle_noipa_attribute (tree *, tree, tree, int, bool *);
static tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
static tree handle_always_inline_attribute (tree *, tree, tree, int, bool *);
static tree handle_malloc_attribute (tree *, tree, tree, int, bool *);
static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *);
+static tree handle_flatten_attribute (tree *, tree, tree, int, bool *);
+static tree handle_used_attribute (tree *, tree, tree, int, bool *);
+static tree handle_cold_attribute (tree *, tree, tree, int, bool *);
+static tree handle_hot_attribute (tree *, tree, tree, int, bool *);
+static tree handle_target_attribute (tree *, tree, tree, int, bool *);
+static tree handle_target_clones_attribute (tree *, tree, tree, int, bool *);
static tree handle_vector_size_attribute (tree *, tree, tree, int, bool *);
static tree handle_vector_type_attribute (tree *, tree, tree, int, bool *);
+static const struct attribute_spec::exclusions attr_cold_hot_exclusions[] =
+{
+ { "cold", true, true, true },
+ { "hot" , true, true, true },
+ { NULL , false, false, false }
+};
+
/* Fake handler for attributes we don't properly support, typically because
they'd require dragging a lot of the common-c front-end circuitry. */
static tree fake_attribute_handler (tree *, tree, tree, int, bool *);
handle_noinline_attribute, NULL },
{ "noclone", 0, 0, true, false, false, false,
handle_noclone_attribute, NULL },
+ { "no_icf", 0, 0, true, false, false, false,
+ handle_noicf_attribute, NULL },
+ { "noipa", 0, 0, true, false, false, false,
+ handle_noipa_attribute, NULL },
{ "leaf", 0, 0, true, false, false, false,
handle_leaf_attribute, NULL },
{ "always_inline",0, 0, true, false, false, false,
handle_always_inline_attribute, NULL },
{ "malloc", 0, 0, true, false, false, false,
handle_malloc_attribute, NULL },
- { "type generic", 0, 0, false, true, true, false,
+ { "type generic", 0, 0, false, true, true, false,
handle_type_generic_attribute, NULL },
- { "vector_size", 1, 1, false, true, false, false,
+ { "flatten", 0, 0, true, false, false, false,
+ handle_flatten_attribute, NULL },
+ { "used", 0, 0, true, false, false, false,
+ handle_used_attribute, NULL },
+ { "cold", 0, 0, true, false, false, false,
+ handle_cold_attribute, attr_cold_hot_exclusions },
+ { "hot", 0, 0, true, false, false, false,
+ handle_hot_attribute, attr_cold_hot_exclusions },
+ { "target", 1, -1, true, false, false, false,
+ handle_target_attribute, NULL },
+ { "target_clones",1, -1, true, false, false, false,
+ handle_target_clones_attribute, NULL },
+
+ { "vector_size", 1, 1, false, true, false, false,
handle_vector_size_attribute, NULL },
- { "vector_type", 0, 0, false, true, false, false,
+ { "vector_type", 0, 0, false, true, false, false,
handle_vector_type_attribute, NULL },
- { "may_alias", 0, 0, false, true, false, false, NULL, NULL },
+ { "may_alias", 0, 0, false, true, false, false,
+ NULL, NULL },
/* ??? format and format_arg are heavy and not supported, which actually
prevents support for stdio builtins, which we however declare as part
of the common builtins.def contents. */
- { "format", 3, 3, false, true, true, false, fake_attribute_handler,
- NULL },
- { "format_arg", 1, 1, false, true, true, false, fake_attribute_handler,
- NULL },
+ { "format", 3, 3, false, true, true, false,
+ fake_attribute_handler, NULL },
+ { "format_arg", 1, 1, false, true, true, false,
+ fake_attribute_handler, NULL },
- { NULL, 0, 0, false, false, false, false, NULL, NULL }
+ { NULL, 0, 0, false, false, false, false,
+ NULL, NULL }
};
/* Associates a GNAT tree node to a GCC tree node. It is used in
for (param_decl = DECL_ARGUMENTS (subprog_decl); param_decl;
param_decl = DECL_CHAIN (param_decl))
DECL_CONTEXT (param_decl) = subprog_decl;
-
- make_decl_rtl (subprog_decl);
}
/* Finish translating the current subprogram and set its BODY. */
return NULL_TREE;
}
+/* Handle a "no_icf" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_noicf_attribute (tree *node, tree name,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "noipa" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_noipa_attribute (tree *node, tree name, tree, int, bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
/* Handle a "leaf" attribute; arguments as in
struct attribute_spec.handler. */
return NULL_TREE;
}
+/* Handle a "flatten" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_flatten_attribute (tree *node, tree name,
+ tree args ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ /* Do nothing else, just set the attribute. We'll get at
+ it later with lookup_attribute. */
+ ;
+ else
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "used" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_used_attribute (tree *pnode, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ tree node = *pnode;
+
+ if (TREE_CODE (node) == FUNCTION_DECL
+ || (VAR_P (node) && TREE_STATIC (node))
+ || (TREE_CODE (node) == TYPE_DECL))
+ {
+ TREE_USED (node) = 1;
+ DECL_PRESERVE_P (node) = 1;
+ if (VAR_P (node))
+ DECL_READ_P (node) = 1;
+ }
+ else
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "cold" and attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_cold_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) == FUNCTION_DECL
+ || TREE_CODE (*node) == LABEL_DECL)
+ {
+ /* Attribute cold processing is done later with lookup_attribute. */
+ }
+ else
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "hot" and attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_hot_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) == FUNCTION_DECL
+ || TREE_CODE (*node) == LABEL_DECL)
+ {
+ /* Attribute hot processing is done later with lookup_attribute. */
+ }
+ else
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "target" attribute. */
+
+static tree
+handle_target_attribute (tree *node, tree name, tree args, int flags,
+ bool *no_add_attrs)
+{
+ /* Ensure we have a function type. */
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+ else if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (*node)))
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
+ "with %qs attribute", name, "target_clones");
+ *no_add_attrs = true;
+ }
+ else if (!targetm.target_option.valid_attribute_p (*node, name, args, flags))
+ *no_add_attrs = true;
+
+ /* Check that there's no empty string in values of the attribute. */
+ for (tree t = args; t != NULL_TREE; t = TREE_CHAIN (t))
+ {
+ tree value = TREE_VALUE (t);
+ if (TREE_CODE (value) == STRING_CST
+ && TREE_STRING_LENGTH (value) == 1
+ && TREE_STRING_POINTER (value)[0] == '\0')
+ {
+ warning (OPT_Wattributes, "empty string in attribute %<target%>");
+ *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. */
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ {
+ if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (*node)))
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
+ "with %qs attribute", name, "always_inline");
+ *no_add_attrs = true;
+ }
+ else if (lookup_attribute ("target", DECL_ATTRIBUTES (*node)))
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
+ "with %qs attribute", name, "target");
+ *no_add_attrs = true;
+ }
+ else
+ /* Do not inline functions with multiple clone targets. */
+ DECL_UNINLINABLE (*node) = 1;
+ }
+ else
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+ return NULL_TREE;
+}
+
/* Handle a "vector_size" attribute; arguments as in
struct attribute_spec.handler. */