From 70e41a6a27a6aad0abbe5598497b4b17ef3feb48 Mon Sep 17 00:00:00 2001 From: Nicola Pero Date: Wed, 22 Jun 2011 09:52:55 +0000 Subject: [PATCH] In gcc/: 2011-06-21 Nicola Pero In gcc/: 2011-06-21 Nicola Pero * attribs.c (register_attribute): Added assert to check that all attribute specs are registered with a name that is not empty and does not start with '_'. (decl_attributes): Avoid the lookup of the "naked" attribute spec if the function has no attributes. * tree.c (is_attribute_with_length_p): Removed. (is_attribute_p): Removed. (private_is_attribute_p): New. (private_lookup_attribute): New. (lookup_attribute): Removed. (lookup_ident_attribute): New. (remove_attribute): Require the first argument to be in the form 'text', not '__text__'. Updated asserts. (merge_attributes): Use lookup_ident_attributes instead of lookup_attribute. (merge_dllimport_decl_attributes): Use remove_attribute. (attribute_list_contained): Likewise. (attribute_list_equal): Immediately return 1 if the arguments are identical pointers. * tree.h (is_attribute_p): Made inline. Return a 'bool', not an 'int'. Require the first argument to be in the form 'text', not '__text__'. Require the second argument to be an identifier. (lookup_attribute): Made inline. Require the first argument to be in the form 'text', not '__text__'. (private_is_attribute_p, private_lookup_attribute): New. Updated comments. From-SVN: r175286 --- gcc/ChangeLog | 29 ++++++++ gcc/attribs.c | 6 ++ gcc/tree.c | 192 ++++++++++++++++++++++++++++---------------------- gcc/tree.h | 50 +++++++++++-- 4 files changed, 185 insertions(+), 92 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1dff45a1437..aa89cdda46e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,32 @@ +2011-06-21 Nicola Pero + + * attribs.c (register_attribute): Added assert to check that all + attribute specs are registered with a name that is not empty and + does not start with '_'. + (decl_attributes): Avoid the lookup of the "naked" attribute spec + if the function has no attributes. + * tree.c (is_attribute_with_length_p): Removed. + (is_attribute_p): Removed. + (private_is_attribute_p): New. + (private_lookup_attribute): New. + (lookup_attribute): Removed. + (lookup_ident_attribute): New. + (remove_attribute): Require the first argument to be in the form + 'text', not '__text__'. Updated asserts. + (merge_attributes): Use lookup_ident_attributes instead of + lookup_attribute. + (merge_dllimport_decl_attributes): Use remove_attribute. + (attribute_list_contained): Likewise. + (attribute_list_equal): Immediately return 1 if the arguments are + identical pointers. + * tree.h (is_attribute_p): Made inline. Return a 'bool', not an + 'int'. Require the first argument to be in the form 'text', not + '__text__'. Require the second argument to be an identifier. + (lookup_attribute): Made inline. Require the first argument to be + in the form 'text', not '__text__'. + (private_is_attribute_p, private_lookup_attribute): New. + Updated comments. + 2011-06-21 Andrew MacLeod * builtins.c: Add sync_ or SYNC__ to builtin names. diff --git a/gcc/attribs.c b/gcc/attribs.c index ce977d4a337..98a6310294b 100644 --- a/gcc/attribs.c +++ b/gcc/attribs.c @@ -198,6 +198,11 @@ register_attribute (const struct attribute_spec *attr) str.str = attr->name; str.length = strlen (str.str); + + /* Attribute names in the table must be in the form 'text' and not + in the form '__text__'. */ + gcc_assert (str.length > 0 && str.str[0] != '_'); + slot = htab_find_slot_with_hash (attribute_hash, &str, substring_hash (str.str, str.length), INSERT); @@ -279,6 +284,7 @@ decl_attributes (tree *node, tree attributes, int flags) /* A "naked" function attribute implies "noinline" and "noclone" for those targets that support it. */ if (TREE_CODE (*node) == FUNCTION_DECL + && attributes && lookup_attribute_spec (get_identifier ("naked")) && lookup_attribute ("naked", attributes) != NULL) { diff --git a/gcc/tree.c b/gcc/tree.c index 73126cf30d6..d984ecef331 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -5218,82 +5218,119 @@ struct simple_ipa_opt_pass pass_ipa_free_lang_data = } }; -/* Return nonzero if IDENT is a valid name for attribute ATTR, - or zero if not. - - We try both `text' and `__text__', ATTR may be either one. */ -/* ??? It might be a reasonable simplification to require ATTR to be only - `text'. One might then also require attribute lists to be stored in - their canonicalized form. */ - -static int -is_attribute_with_length_p (const char *attr, int attr_len, const_tree ident) +/* The backbone of is_attribute_p(). ATTR_LEN is the string length of + ATTR_NAME. Also used internally by remove_attribute(). */ +bool +private_is_attribute_p (const char *attr_name, size_t attr_len, const_tree ident) { - int ident_len; - const char *p; + size_t ident_len = IDENTIFIER_LENGTH (ident); - if (TREE_CODE (ident) != IDENTIFIER_NODE) - return 0; - - p = IDENTIFIER_POINTER (ident); - ident_len = IDENTIFIER_LENGTH (ident); - - if (ident_len == attr_len - && strcmp (attr, p) == 0) - return 1; - - /* If ATTR is `__text__', IDENT must be `text'; and vice versa. */ - if (attr[0] == '_') + if (ident_len == attr_len) { - gcc_assert (attr[1] == '_'); - gcc_assert (attr[attr_len - 2] == '_'); - gcc_assert (attr[attr_len - 1] == '_'); - if (ident_len == attr_len - 4 - && strncmp (attr + 2, p, attr_len - 4) == 0) - return 1; + if (strcmp (attr_name, IDENTIFIER_POINTER (ident)) == 0) + return true; } - else + else if (ident_len == attr_len + 4) { - if (ident_len == attr_len + 4 - && p[0] == '_' && p[1] == '_' + /* There is the possibility that ATTR is 'text' and IDENT is + '__text__'. */ + const char *p = IDENTIFIER_POINTER (ident); + if (p[0] == '_' && p[1] == '_' && p[ident_len - 2] == '_' && p[ident_len - 1] == '_' - && strncmp (attr, p + 2, attr_len) == 0) - return 1; + && strncmp (attr_name, p + 2, attr_len) == 0) + return true; } - return 0; + return false; } -/* Return nonzero if IDENT is a valid name for attribute ATTR, - or zero if not. +/* The backbone of lookup_attribute(). ATTR_LEN is the string length + of ATTR_NAME, and LIST is not NULL_TREE. */ +tree +private_lookup_attribute (const char *attr_name, size_t attr_len, tree list) +{ + while (list) + { + size_t ident_len = IDENTIFIER_LENGTH (TREE_PURPOSE (list)); - We try both `text' and `__text__', ATTR may be either one. */ + if (ident_len == attr_len) + { + if (strcmp (attr_name, IDENTIFIER_POINTER (TREE_PURPOSE (list))) == 0) + break; + } + /* TODO: If we made sure that attributes were stored in the + canonical form without '__...__' (ie, as in 'text' as opposed + to '__text__') then we could avoid the following case. */ + else if (ident_len == attr_len + 4) + { + const char *p = IDENTIFIER_POINTER (TREE_PURPOSE (list)); + if (p[0] == '_' && p[1] == '_' + && p[ident_len - 2] == '_' && p[ident_len - 1] == '_' + && strncmp (attr_name, p + 2, attr_len) == 0) + break; + } + list = TREE_CHAIN (list); + } -int -is_attribute_p (const char *attr, const_tree ident) -{ - return is_attribute_with_length_p (attr, strlen (attr), ident); + return list; } -/* Given an attribute name and a list of attributes, return a pointer to the - attribute's list element if the attribute is part of the list, or NULL_TREE - if not found. If the attribute appears more than once, this only - returns the first occurrence; the TREE_CHAIN of the return value should - be passed back in if further occurrences are wanted. */ +/* A variant of lookup_attribute() that can be used with an identifier + as the first argument, and where the identifier can be either + 'text' or '__text__'. -tree -lookup_attribute (const char *attr_name, tree list) + Given an attribute ATTR_IDENTIFIER, and a list of attributes LIST, + return a pointer to the attribute's list element if the attribute + is part of the list, or NULL_TREE if not found. If the attribute + appears more than once, this only returns the first occurrence; the + TREE_CHAIN of the return value should be passed back in if further + occurrences are wanted. ATTR_IDENTIFIER must be an identifier but + can be in the form 'text' or '__text__'. */ +static tree +lookup_ident_attribute (tree attr_identifier, tree list) { - tree l; - size_t attr_len = strlen (attr_name); + gcc_checking_assert (TREE_CODE (attr_identifier) == IDENTIFIER_NODE); - for (l = list; l; l = TREE_CHAIN (l)) + while (list) { - gcc_assert (TREE_CODE (TREE_PURPOSE (l)) == IDENTIFIER_NODE); - if (is_attribute_with_length_p (attr_name, attr_len, TREE_PURPOSE (l))) - return l; + gcc_checking_assert (TREE_CODE (TREE_PURPOSE (list)) == IDENTIFIER_NODE); + + /* Identifiers can be compared directly for equality. */ + if (attr_identifier == TREE_PURPOSE (list)) + break; + + /* If they are not equal, they may still be one in the form + 'text' while the other one is in the form '__text__'. TODO: + If we were storing attributes in normalized 'text' form, then + this could all go away and we could take full advantage of + the fact that we're comparing identifiers. :-) */ + { + size_t attr_len = IDENTIFIER_LENGTH (attr_identifier); + size_t ident_len = IDENTIFIER_LENGTH (TREE_PURPOSE (list)); + + if (ident_len == attr_len + 4) + { + const char *p = IDENTIFIER_POINTER (TREE_PURPOSE (list)); + const char *q = IDENTIFIER_POINTER (attr_identifier); + if (p[0] == '_' && p[1] == '_' + && p[ident_len - 2] == '_' && p[ident_len - 1] == '_' + && strncmp (q, p + 2, attr_len) == 0) + break; + } + else if (ident_len + 4 == attr_len) + { + const char *p = IDENTIFIER_POINTER (TREE_PURPOSE (list)); + const char *q = IDENTIFIER_POINTER (attr_identifier); + if (q[0] == '_' && q[1] == '_' + && q[attr_len - 2] == '_' && q[attr_len - 1] == '_' + && strncmp (q + 2, p, ident_len) == 0) + break; + } + } + list = TREE_CHAIN (list); } - return NULL_TREE; + + return list; } /* Remove any instances of attribute ATTR_NAME in LIST and return the @@ -5305,11 +5342,14 @@ remove_attribute (const char *attr_name, tree list) tree *p; size_t attr_len = strlen (attr_name); + gcc_checking_assert (attr_name[0] != '_'); + for (p = &list; *p; ) { tree l = *p; - gcc_assert (TREE_CODE (TREE_PURPOSE (l)) == IDENTIFIER_NODE); - if (is_attribute_with_length_p (attr_name, attr_len, TREE_PURPOSE (l))) + /* TODO: If we were storing attributes in normalized form, here + we could use a simple strcmp(). */ + if (private_is_attribute_p (attr_name, attr_len, TREE_PURPOSE (l))) *p = TREE_CHAIN (l); else p = &TREE_CHAIN (l); @@ -5346,11 +5386,9 @@ merge_attributes (tree a1, tree a2) for (; a2 != 0; a2 = TREE_CHAIN (a2)) { tree a; - for (a = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)), - attributes); + for (a = lookup_ident_attribute (TREE_PURPOSE (a2), attributes); a != NULL_TREE && !attribute_value_equal (a, a2); - a = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)), - TREE_CHAIN (a))) + a = lookup_ident_attribute (TREE_PURPOSE (a2), TREE_CHAIN (a))) ; if (a == NULL_TREE) { @@ -5449,24 +5487,7 @@ merge_dllimport_decl_attributes (tree old, tree new_tree) a = merge_attributes (DECL_ATTRIBUTES (old), DECL_ATTRIBUTES (new_tree)); if (delete_dllimport_p) - { - tree prev, t; - const size_t attr_len = strlen ("dllimport"); - - /* Scan the list for dllimport and delete it. */ - for (prev = NULL_TREE, t = a; t; prev = t, t = TREE_CHAIN (t)) - { - if (is_attribute_with_length_p ("dllimport", attr_len, - TREE_PURPOSE (t))) - { - if (prev == NULL_TREE) - a = TREE_CHAIN (a); - else - TREE_CHAIN (prev) = TREE_CHAIN (t); - break; - } - } - } + a = remove_attribute ("dllimport", a); return a; } @@ -6254,6 +6275,9 @@ attribute_hash_list (const_tree list, hashval_t hashcode) int attribute_list_equal (const_tree l1, const_tree l2) { + if (l1 == l2) + return 1; + return attribute_list_contained (l1, l2) && attribute_list_contained (l2, l1); } @@ -6292,11 +6316,9 @@ attribute_list_contained (const_tree l1, const_tree l2) /* This CONST_CAST is okay because lookup_attribute does not modify its argument and the return value is assigned to a const_tree. */ - for (attr = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (t2)), - CONST_CAST_TREE(l1)); + for (attr = lookup_ident_attribute (TREE_PURPOSE (t2), CONST_CAST_TREE(l1)); attr != NULL_TREE && !attribute_value_equal (t2, attr); - attr = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (t2)), - TREE_CHAIN (attr))) + attr = lookup_ident_attribute (TREE_PURPOSE (t2), TREE_CHAIN (attr))) ; if (attr == NULL_TREE) diff --git a/gcc/tree.h b/gcc/tree.h index f55574dd5f1..3840fed8c04 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -4498,18 +4498,54 @@ enum attribute_flags extern tree merge_decl_attributes (tree, tree); extern tree merge_type_attributes (tree, tree); -/* Given a tree node and a string, return nonzero if the tree node is - a valid attribute name for the string. */ +/* This function is a private implementation detail of lookup_attribute() + and you should never call it directly. */ +extern tree private_lookup_attribute (const char *, size_t, tree); + +/* Given an attribute name ATTR_NAME and a list of attributes LIST, + return a pointer to the attribute's list element if the attribute + is part of the list, or NULL_TREE if not found. If the attribute + appears more than once, this only returns the first occurrence; the + TREE_CHAIN of the return value should be passed back in if further + occurrences are wanted. ATTR_NAME must be in the form 'text' (not + '__text__'). */ -extern int is_attribute_p (const char *, const_tree); +static inline tree +lookup_attribute (const char *attr_name, tree list) +{ + gcc_checking_assert (attr_name[0] != '_'); + /* In most cases, list is NULL_TREE. */ + if (list == NULL_TREE) + return NULL_TREE; + else + /* Do the strlen() before calling the out-of-line implementation. + In most cases attr_name is a string constant, and the compiler + will optimize the strlen() away. */ + return private_lookup_attribute (attr_name, strlen (attr_name), list); +} -/* Given an attribute name and a list of attributes, return the list element - of the attribute or NULL_TREE if not found. */ +/* This function is a private implementation detail of + is_attribute_p() and you should never call it directly. */ +extern bool private_is_attribute_p (const char *, size_t, const_tree); -extern tree lookup_attribute (const char *, tree); +/* Given an identifier node IDENT and a string ATTR_NAME, return true + if the identifier node is a valid attribute name for the string. + ATTR_NAME must be in the form 'text' (not '__text__'). IDENT could + be the identifier for 'text' or for '__text__'. */ + +static inline bool +is_attribute_p (const char *attr_name, const_tree ident) +{ + gcc_checking_assert (attr_name[0] != '_'); + /* Do the strlen() before calling the out-of-line implementation. + In most cases attr_name is a string constant, and the compiler + will optimize the strlen() away. */ + return private_is_attribute_p (attr_name, strlen (attr_name), ident); +} /* Remove any instances of attribute ATTR_NAME in LIST and return the - modified list. */ + modified list. ATTR_NAME must be in the form 'text' (not + '__text__'). */ extern tree remove_attribute (const char *, tree); -- 2.30.2