On Wed, Jun 22, 2011 at 2:17 AM, Nicola Pero
<nicola.p...@meta-innovation.com> wrote:
> Ok, here's a revised patch (contextual diff, as requested).
>
> The inline code is now minimized to the "hot" stuff, as discussed.  In 
> benchmarks
> this arrangement performs a tiny bit slightly better than the previous patch, 
> so
> that's great news. :-)
>
> Bootstrapped on GNU/Linux i686, regression tested.  Benchmarked.
>
> OK to commit ?

Ok.

Thanks,
Richard.

> Thanks
>
> Index: attribs.c
> ===================================================================
> *** attribs.c   (revision 175269)
> --- attribs.c   (working copy)
> ***************
> *** 198,203 ****
> --- 198,208 ----
>
>    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,284 ****
> --- 284,290 ----
>    /* 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)
>      {
> Index: tree.c
> ===================================================================
> *** tree.c      (revision 175269)
> --- tree.c      (working copy)
> ***************
> *** 5218,5299 ****
>   }
>  };
>
> ! /* 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)
>  {
> !   int ident_len;
> !   const char *p;
> !
> !   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] == '_')
>      {
> !       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;
>      }
> !   else
>      {
> !       if (ident_len == attr_len + 4
> !         && p[0] == '_' && p[1] == '_'
>          && p[ident_len - 2] == '_' && p[ident_len - 1] == '_'
> !         && strncmp (attr, p + 2, attr_len) == 0)
> !       return 1;
>      }
>
> !   return 0;
>  }
>
> ! /* 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.  */
>
> ! int
> ! is_attribute_p (const char *attr, const_tree ident)
> ! {
> !   return is_attribute_with_length_p (attr, strlen (attr), ident);
>  }
>
> ! /* 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.  */
> !
> ! tree
> ! lookup_attribute (const char *attr_name, tree list)
>  {
> !   tree l;
> !   size_t attr_len = strlen (attr_name);
>
> !   for (l = list; l; l = TREE_CHAIN (l))
>      {
> !       gcc_assert (TREE_CODE (TREE_PURPOSE (l)) == IDENTIFIER_NODE);
> !       if (is_attribute_with_length_p (attr_name, attr_len, TREE_PURPOSE 
> (l)))
> !       return l;
>      }
> !   return NULL_TREE;
>  }
>
>  /* Remove any instances of attribute ATTR_NAME in LIST and return the
> --- 5218,5336 ----
>   }
>  };
>
> ! /* 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)
>  {
> !   size_t ident_len = IDENTIFIER_LENGTH (ident);
>
> !   if (ident_len == attr_len)
>      {
> !       if (strcmp (attr_name, IDENTIFIER_POINTER (ident)) == 0)
> !       return true;
>      }
> !   else if (ident_len == attr_len + 4)
>      {
> !       /* 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_name, p + 2, attr_len) == 0)
> !       return true;
>      }
>
> !   return false;
>  }
>
> ! /* 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));
>
> !       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);
> !     }
>
> !   return list;
>  }
>
> ! /* 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__'.
> !
> !    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)
>  {
> !   gcc_checking_assert (TREE_CODE (attr_identifier) == IDENTIFIER_NODE);
>
> !   while (list)
>      {
> !       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 list;
>  }
>
>  /* Remove any instances of attribute ATTR_NAME in LIST and return the
> ***************
> *** 5305,5315 ****
>    tree *p;
>    size_t attr_len = strlen (attr_name);
>
>    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)))
>        *p = TREE_CHAIN (l);
>        else
>        p = &TREE_CHAIN (l);
> --- 5342,5355 ----
>    tree *p;
>    size_t attr_len = strlen (attr_name);
>
> +   gcc_checking_assert (attr_name[0] != '_');
> +
>    for (p = &list; *p; )
>      {
>        tree l = *p;
> !       /* 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,5356 ****
>          for (; a2 != 0; a2 = TREE_CHAIN (a2))
>            {
>              tree a;
> !             for (a = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE 
> (a2)),
> !                                        attributes);
>                   a != NULL_TREE && !attribute_value_equal (a, a2);
> !                  a = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE 
> (a2)),
> !                                        TREE_CHAIN (a)))
>                ;
>              if (a == NULL_TREE)
>                {
> --- 5386,5394 ----
>          for (; a2 != 0; a2 = TREE_CHAIN (a2))
>            {
>              tree a;
> !             for (a = lookup_ident_attribute (TREE_PURPOSE (a2), attributes);
>                   a != NULL_TREE && !attribute_value_equal (a, a2);
> !                  a = lookup_ident_attribute (TREE_PURPOSE (a2), TREE_CHAIN 
> (a)))
>                ;
>              if (a == NULL_TREE)
>                {
> ***************
> *** 5449,5472 ****
>    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;
> !           }
> !       }
> !     }
>
>    return a;
>  }
> --- 5487,5493 ----
>    a = merge_attributes (DECL_ATTRIBUTES (old), DECL_ATTRIBUTES (new_tree));
>
>    if (delete_dllimport_p)
> !     a = remove_attribute ("dllimport", a);
>
>    return a;
>  }
> ***************
> *** 6254,6259 ****
> --- 6275,6283 ----
>  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,6302 ****
>        /* 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));
>           attr != NULL_TREE && !attribute_value_equal (t2, attr);
> !          attr = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (t2)),
> !                                   TREE_CHAIN (attr)))
>        ;
>
>        if (attr == NULL_TREE)
> --- 6316,6324 ----
>        /* 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_ident_attribute (TREE_PURPOSE (t2), 
> CONST_CAST_TREE(l1));
>           attr != NULL_TREE && !attribute_value_equal (t2, attr);
> !          attr = lookup_ident_attribute (TREE_PURPOSE (t2), TREE_CHAIN 
> (attr)))
>        ;
>
>        if (attr == NULL_TREE)
> Index: tree.h
> ===================================================================
> *** tree.h      (revision 175269)
> --- tree.h      (working copy)
> ***************
> *** 4498,4515 ****
>  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.  */
>
> ! extern int is_attribute_p (const char *, const_tree);
> !
> ! /* Given an attribute name and a list of attributes, return the list element
> !    of the attribute or NULL_TREE if not found.  */
>
> ! extern tree lookup_attribute (const char *, tree);
>
>  /* Remove any instances of attribute ATTR_NAME in LIST and return the
> !    modified list.  */
>
>  extern tree remove_attribute (const char *, tree);
>
> --- 4498,4550 ----
>  extern tree merge_decl_attributes (tree, tree);
>  extern tree merge_type_attributes (tree, tree);
>
> ! /* 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__').  */
>
> ! 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);
> ! }
>
> ! /* 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);
> !
> ! /* 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.  ATTR_NAME must be in the form 'text' (not
> !    '__text__').  */
>
>  extern tree remove_attribute (const char *, tree);
>
> Index: ChangeLog
> ===================================================================
> *** ChangeLog   (revision 175269)
> --- ChangeLog   (working copy)
> ***************
> *** 1,3 ****
> --- 1,32 ----
> + 2011-06-21  Nicola Pero  <nicola.p...@meta-innovation.com>
> +
> +       * 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  Georg-Johann Lay  <a...@gjlay.de>
>
>        PR target/33049
>
>
>
>
>
>

Reply via email to