diff mbox

[RFC] Do refactoring of attribute functions and move them to attribs.[hc].

Message ID 7e541554-10a6-9cae-fca0-042900271768@suse.cz
State New
Headers show

Commit Message

Martin Liška July 13, 2017, 1:51 p.m. UTC
Hi.

It's request for comment where I mechanically moved attribute-related function to attribs.[hc].

Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.

Thoughts?
Martin

Comments

Jeff Law July 14, 2017, 7:23 a.m. UTC | #1
On 07/13/2017 07:51 AM, Martin Liška wrote:
> Hi.
> 
> It's request for comment where I mechanically moved attribute-related function to attribs.[hc].
> 
> Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.
> 
> Thoughts?
Seems reasonable.  We don't like to move things around without a good
reason and I assume you've got something in mind?

jeff
Martin Liška July 14, 2017, 7:39 a.m. UTC | #2
On 07/14/2017 09:23 AM, Jeff Law wrote:
> On 07/13/2017 07:51 AM, Martin Liška wrote:
>> Hi.
>>
>> It's request for comment where I mechanically moved attribute-related function to attribs.[hc].
>>
>> Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.
>>
>> Thoughts?
> Seems reasonable.  We don't like to move things around without a good
> reason and I assume you've got something in mind?

Well, I basically identified that attribute-related functions are spread in between
attribs.[ch] and tree.c[ch]. And as the later ones are quite big, the code movement
logical to me.

I'm going to prepare changelog entry for that.

Martin

> 
> jeff
>
Jakub Jelinek Sept. 12, 2017, 7:54 a.m. UTC | #3
On Thu, Jul 13, 2017 at 03:51:31PM +0200, Martin Liška wrote:
> It's request for comment where I mechanically moved attribute-related function to attribs.[hc].
> 
> Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.
> 
> Thoughts?

I've only noticed this now, what is the reason for undoing the size
optimization we had, i.e. inline lookup_attribute that handles the most
common case inline only and inline computes the strlen (an important
optimization, because we almost always call it with a string literal
and strlen of that is a constant) and doing the rest out of line?

> -/* 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);
> -}

The current code instead inlines the whole lookup_attribute which is larger.
Have you looked at the code size effects of that change?

	Jakub
Martin Liška Sept. 12, 2017, 11:31 a.m. UTC | #4
On 09/12/2017 09:54 AM, Jakub Jelinek wrote:
> On Thu, Jul 13, 2017 at 03:51:31PM +0200, Martin Liška wrote:
>> It's request for comment where I mechanically moved attribute-related function to attribs.[hc].
>>
>> Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.
>>
>> Thoughts?
> 
> I've only noticed this now, what is the reason for undoing the size
> optimization we had, i.e. inline lookup_attribute that handles the most
> common case inline only and inline computes the strlen (an important
> optimization, because we almost always call it with a string literal
> and strlen of that is a constant) and doing the rest out of line?
> 
>> -/* 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);
>> -}
> 
> The current code instead inlines the whole lookup_attribute which is larger.
> Have you looked at the code size effects of that change?
> 
> 	Jakub
> 

Hi.

Sorry for removal of the optimization. You're right it really adds some size (~30K of .text):

$ bloaty gcc/cc1plus -- /tmp/cc1plus 
     VM SIZE                      FILE SIZE
 ++++++++++++++ GROWING        ++++++++++++++
  [ = ]       0 .debug_loc      +277Ki  +0.4%
  [ = ]       0 .debug_info    +86.9Ki  +0.1%
  [ = ]       0 .debug_ranges  +59.9Ki  +0.5%
  +0.2% +32.1Ki .text          +32.1Ki  +0.2%
  [ = ]       0 .debug_line    +9.36Ki  +0.1%
  +0.0% +2.06Ki .rodata        +2.06Ki  +0.0%
  [ = ]       0 .symtab        +1.73Ki  +0.1%
  +0.1% +1.72Ki .eh_frame      +1.72Ki  +0.1%
  +0.0%    +272 .dynstr           +272  +0.0%
  [ = ]       0 .debug_abbrev     +140  +0.0%
  +0.0%     +72 .dynsym            +72  +0.0%
  +0.0%     +64 .eh_frame_hdr      +64  +0.0%
  [ = ]       0 .debug_aranges     +48  +0.0%
  +0.0%     +12 .gnu.hash          +12  +0.0%
  +0.0%     +12 .hash              +12  +0.0%
  +0.0%      +6 .gnu.version        +6  +0.0%

 -------------- SHRINKING      --------------
 -10.2%      -6 [Unmapped]        -317 -20.8%
  [ = ]       0 .strtab            -66  -0.0%
  [ = ]       0 .debug_str         -52  -0.0%

  +0.1% +36.3Ki TOTAL           +471Ki  +0.2%

$ bloaty gcc/cc1 -- /tmp/cc1
     VM SIZE                      FILE SIZE
 ++++++++++++++ GROWING        ++++++++++++++
  [ = ]       0 .debug_loc      +232Ki  +0.4%
  [ = ]       0 .debug_info    +74.1Ki  +0.1%
  [ = ]       0 .debug_ranges  +48.9Ki  +0.4%
  +0.2% +26.9Ki .text          +26.9Ki  +0.2%
  [ = ]       0 .debug_line    +8.22Ki  +0.1%
  +0.1% +1.79Ki .eh_frame      +1.79Ki  +0.1%
  +0.0% +1.75Ki .rodata        +1.75Ki  +0.0%
  [ = ]       0 .symtab        +1.50Ki  +0.1%
  +0.0%    +272 .dynstr           +272  +0.0%
  [ = ]       0 .debug_abbrev      +72  +0.0%
  +0.0%     +72 .dynsym            +72  +0.0%
  +0.0%     +64 .eh_frame_hdr      +64  +0.0%
  [ = ]       0 .debug_aranges     +48  +0.0%
  +0.0%     +12 .gnu.hash          +12  +0.0%
  +0.0%     +12 .hash              +12  +0.0%
  +0.0%      +6 .gnu.version        +6  +0.0%

 -------------- SHRINKING      --------------
  [ = ]       0 .debug_str         -52  -0.0%
  [ = ]       0 .strtab            -26  -0.0%

 -+-+-+-+-+-+-+ MIXED          +-+-+-+-+-+-+-
   +19%     +10 [Unmapped]     -2.87Ki -75.1%

  +0.1% +30.9Ki TOTAL           +392Ki  +0.2%

Thus I'm suggesting to the how it was. Is the patch OK after testing?

Martin
From a40c06fc06afcb7bb886d7a3106e6da631a48430 Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Tue, 12 Sep 2017 13:30:39 +0200
Subject: [PATCH] Reduce lookup_attribute memory footprint.

gcc/ChangeLog:

2017-09-12  Martin Liska  <mliska@suse.cz>

	* attribs.c (private_lookup_attribute): New function.
	* attribs.h (private_lookup_attribute): Declared here.
	(lookup_attribute): Called from this place.
---
 gcc/attribs.c | 17 +++++++++++++++++
 gcc/attribs.h | 17 ++++++-----------
 2 files changed, 23 insertions(+), 11 deletions(-)

diff --git a/gcc/attribs.c b/gcc/attribs.c
index b8f58a74596..9064434e5f2 100644
--- a/gcc/attribs.c
+++ b/gcc/attribs.c
@@ -1584,3 +1584,20 @@ attribute_list_contained (const_tree l1, const_tree l2)
 
   return 1;
 }
+
+
+tree
+private_lookup_attribute (const char *attr_name, size_t attr_len, tree list)
+{
+  while (list)
+    {
+      tree attr = get_attribute_name (list);
+      size_t ident_len = IDENTIFIER_LENGTH (attr);
+      if (cmp_attribs (attr_name, attr_len, IDENTIFIER_POINTER (attr),
+		       ident_len))
+	break;
+      list = TREE_CHAIN (list);
+    }
+
+  return list;
+}
diff --git a/gcc/attribs.h b/gcc/attribs.h
index 06e6993e958..0285b93cbc3 100644
--- a/gcc/attribs.h
+++ b/gcc/attribs.h
@@ -87,6 +87,11 @@ extern tree handle_dll_attribute (tree *, tree, tree, int, bool *);
 extern int attribute_list_equal (const_tree, const_tree);
 extern int attribute_list_contained (const_tree, const_tree);
 
+/* The backbone of lookup_attribute().  ATTR_LEN is the string length
+   of ATTR_NAME, and LIST is not NULL_TREE.  */
+extern tree private_lookup_attribute (const char *attr_name, size_t attr_len,
+				      tree list);
+
 /* For a given IDENTIFIER_NODE, strip leading and trailing '_' characters
    so that we have a canonical form of attribute names.  */
 
@@ -151,17 +156,7 @@ lookup_attribute (const char *attr_name, tree list)
       /* 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.  */
-      while (list)
-	{
-	  tree attr = get_attribute_name (list);
-	  size_t ident_len = IDENTIFIER_LENGTH (attr);
-	  if (cmp_attribs (attr_name, attr_len, IDENTIFIER_POINTER (attr),
-			   ident_len))
-	    break;
-	  list = TREE_CHAIN (list);
-	}
-
-      return list;
+      return private_lookup_attribute (attr_name, attr_len, list);
     }
 }
Jakub Jelinek Sept. 12, 2017, 11:39 a.m. UTC | #5
On Tue, Sep 12, 2017 at 01:31:47PM +0200, Martin Liška wrote:
> >From a40c06fc06afcb7bb886d7a3106e6da631a48430 Mon Sep 17 00:00:00 2001
> From: marxin <mliska@suse.cz>
> Date: Tue, 12 Sep 2017 13:30:39 +0200
> Subject: [PATCH] Reduce lookup_attribute memory footprint.
> 
> gcc/ChangeLog:
> 
> 2017-09-12  Martin Liska  <mliska@suse.cz>
> 
> 	* attribs.c (private_lookup_attribute): New function.
> 	* attribs.h (private_lookup_attribute): Declared here.
> 	(lookup_attribute): Called from this place.
> ---
>  gcc/attribs.c | 17 +++++++++++++++++
>  gcc/attribs.h | 17 ++++++-----------
>  2 files changed, 23 insertions(+), 11 deletions(-)
> 
> diff --git a/gcc/attribs.c b/gcc/attribs.c
> index b8f58a74596..9064434e5f2 100644
> --- a/gcc/attribs.c
> +++ b/gcc/attribs.c
> @@ -1584,3 +1584,20 @@ attribute_list_contained (const_tree l1, const_tree l2)
>  
>    return 1;
>  }
> +
> +

Can you please add a function comment (and in addition to arguments explain
there why lookup_attribute is split into the two parts)?

> +tree
> +private_lookup_attribute (const char *attr_name, size_t attr_len, tree list)
> +{
> +  while (list)
> +    {

> @@ -151,17 +156,7 @@ lookup_attribute (const char *attr_name, tree list)
>        /* 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.  */

Part of the comment is of course here and that comment didn't make any sense
when everything was inlined.

> -      while (list)
> -	{
> -	  tree attr = get_attribute_name (list);
> -	  size_t ident_len = IDENTIFIER_LENGTH (attr);
> -	  if (cmp_attribs (attr_name, attr_len, IDENTIFIER_POINTER (attr),
> -			   ident_len))
> -	    break;
> -	  list = TREE_CHAIN (list);
> -	}
> -
> -      return list;
> +      return private_lookup_attribute (attr_name, attr_len, list);
>      }
>  }

LGTM with the comment added.  In theory fnsplit could handle that too,
but 1) it would emit out of line stuff in every TU separately 2) the
compiler doesn't know that NULL DECL_ATTRIBUTES is so common (it could
with profiledbootstrap).  And of course LTO can decide to inline it
from attribs.c back anyway if there are reasons why it would be beneficial
somewhere (but I doubt it is beneficial at least in most spots).

	Jakub
Martin Liška Sept. 12, 2017, 2:25 p.m. UTC | #6
On 09/12/2017 01:39 PM, Jakub Jelinek wrote:
> On Tue, Sep 12, 2017 at 01:31:47PM +0200, Martin Liška wrote:
>> >From a40c06fc06afcb7bb886d7a3106e6da631a48430 Mon Sep 17 00:00:00 2001
>> From: marxin <mliska@suse.cz>
>> Date: Tue, 12 Sep 2017 13:30:39 +0200
>> Subject: [PATCH] Reduce lookup_attribute memory footprint.
>>
>> gcc/ChangeLog:
>>
>> 2017-09-12  Martin Liska  <mliska@suse.cz>
>>
>> 	* attribs.c (private_lookup_attribute): New function.
>> 	* attribs.h (private_lookup_attribute): Declared here.
>> 	(lookup_attribute): Called from this place.
>> ---
>>  gcc/attribs.c | 17 +++++++++++++++++
>>  gcc/attribs.h | 17 ++++++-----------
>>  2 files changed, 23 insertions(+), 11 deletions(-)
>>
>> diff --git a/gcc/attribs.c b/gcc/attribs.c
>> index b8f58a74596..9064434e5f2 100644
>> --- a/gcc/attribs.c
>> +++ b/gcc/attribs.c
>> @@ -1584,3 +1584,20 @@ attribute_list_contained (const_tree l1, const_tree l2)
>>  
>>    return 1;
>>  }
>> +
>> +
> 
> Can you please add a function comment (and in addition to arguments explain
> there why lookup_attribute is split into the two parts)?

Yes.

> 
>> +tree
>> +private_lookup_attribute (const char *attr_name, size_t attr_len, tree list)
>> +{
>> +  while (list)
>> +    {
> 
>> @@ -151,17 +156,7 @@ lookup_attribute (const char *attr_name, tree list)
>>        /* 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.  */
> 
> Part of the comment is of course here and that comment didn't make any sense
> when everything was inlined.

You're completely right.

> 
>> -      while (list)
>> -	{
>> -	  tree attr = get_attribute_name (list);
>> -	  size_t ident_len = IDENTIFIER_LENGTH (attr);
>> -	  if (cmp_attribs (attr_name, attr_len, IDENTIFIER_POINTER (attr),
>> -			   ident_len))
>> -	    break;
>> -	  list = TREE_CHAIN (list);
>> -	}
>> -
>> -      return list;
>> +      return private_lookup_attribute (attr_name, attr_len, list);
>>      }
>>  }
> 
> LGTM with the comment added.  In theory fnsplit could handle that too,
> but 1) it would emit out of line stuff in every TU separately 2) the
> compiler doesn't know that NULL DECL_ATTRIBUTES is so common (it could
> with profiledbootstrap).  And of course LTO can decide to inline it
> from attribs.c back anyway if there are reasons why it would be beneficial
> somewhere (but I doubt it is beneficial at least in most spots).

Doing it as it was is the right way ;)
Installed as r252022.

Martin

> 
> 	Jakub
>
diff mbox

Patch

From f4322151ebcd8cf71fd677317ef0a74374b0db5e Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Wed, 12 Jul 2017 13:39:54 +0200
Subject: [PATCH] Do refactoring of attribute functions and move them to
 attribs.[hc].

---
 gcc/asan.c                |   2 +
 gcc/attribs.c             | 633 ++++++++++++++++++++++++++++++++++++++++++
 gcc/attribs.h             | 113 ++++++++
 gcc/bb-reorder.c          |   2 +
 gcc/builtins.c            |   2 +
 gcc/c-family/c-ada-spec.c |   2 +
 gcc/c-family/c-ubsan.c    |   4 +-
 gcc/c-family/c-warn.c     |   2 +
 gcc/c/c-convert.c         |   2 +
 gcc/c/c-typeck.c          |   2 +
 gcc/calls.c               |   2 +
 gcc/cfgexpand.c           |   2 +
 gcc/cgraph.c              |   2 +
 gcc/cgraphunit.c          |   2 +
 gcc/convert.c             |   2 +
 gcc/cp/call.c             |   2 +
 gcc/cp/cp-gimplify.c      |   2 +
 gcc/cp/cp-ubsan.c         |   2 +
 gcc/cp/cvt.c              |   2 +
 gcc/cp/init.c             |   2 +
 gcc/cp/search.c           |   2 +
 gcc/cp/semantics.c        |   2 +
 gcc/cp/typeck.c           |   2 +
 gcc/dwarf2out.c           |   2 +
 gcc/final.c               |   2 +
 gcc/fold-const.c          |   2 +
 gcc/fortran/trans-types.c |   1 +
 gcc/function.c            |   2 +
 gcc/gimple-expr.c         |   2 +
 gcc/gimple-fold.c         |   2 +
 gcc/gimple-pretty-print.c |   2 +
 gcc/gimple.c              |   2 +
 gcc/gimplify.c            |   2 +
 gcc/hsa-common.c          |   2 +
 gcc/hsa-gen.c             |   2 +
 gcc/internal-fn.c         |   2 +
 gcc/ipa-chkp.c            |   2 +
 gcc/ipa-cp.c              |   2 +
 gcc/ipa-devirt.c          |   2 +
 gcc/ipa-fnsummary.c       |   2 +
 gcc/ipa-inline.c          |   2 +
 gcc/ipa-visibility.c      |   2 +
 gcc/ipa.c                 |   3 +-
 gcc/lto-cgraph.c          |   2 +
 gcc/lto/lto-lang.c        |   2 +
 gcc/lto/lto-symtab.c      |   2 +
 gcc/omp-expand.c          |   3 +-
 gcc/omp-general.c         |   3 +-
 gcc/omp-low.c             |   2 +
 gcc/omp-offload.c         |   2 +
 gcc/omp-simd-clone.c      |   3 +-
 gcc/opts-global.c         |   2 +
 gcc/passes.c              |   2 +
 gcc/predict.c             |   2 +
 gcc/sancov.c              |   2 +
 gcc/sanopt.c              |   2 +
 gcc/symtab.c              |   2 +
 gcc/toplev.c              |   2 +
 gcc/trans-mem.c           |   3 +-
 gcc/tree-chkp.c           |   2 +
 gcc/tree-eh.c             |   2 +
 gcc/tree-into-ssa.c       |   2 +
 gcc/tree-object-size.c    |   2 +
 gcc/tree-parloops.c       |   2 +
 gcc/tree-profile.c        |   2 +
 gcc/tree-ssa-ccp.c        |   2 +
 gcc/tree-ssa-live.c       |   2 +
 gcc/tree-ssa-loop.c       |   2 +
 gcc/tree-ssa-sccvn.c      |   2 +
 gcc/tree-ssa.c            |   2 +
 gcc/tree-streamer-in.c    |   2 +
 gcc/tree-vectorizer.c     |   2 +
 gcc/tree-vrp.c            |   2 +
 gcc/tree.c                | 685 +---------------------------------------------
 gcc/tree.h                |  86 ------
 gcc/tsan.c                |   2 +
 gcc/ubsan.c               |   2 +
 gcc/varasm.c              |   2 +
 gcc/varpool.c             |   2 +
 79 files changed, 898 insertions(+), 775 deletions(-)

diff --git a/gcc/asan.c b/gcc/asan.c
index 89c2731e8cd..23686358a08 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -47,6 +47,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "varasm.h"
 #include "stor-layout.h"
 #include "tree-iterator.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "dojump.h"
 #include "explow.h"
diff --git a/gcc/attribs.c b/gcc/attribs.c
index 5eb19e82795..a1e52653edd 100644
--- a/gcc/attribs.c
+++ b/gcc/attribs.c
@@ -925,3 +925,636 @@  is_function_default_version (const tree decl)
   return (TREE_CODE (attr) == STRING_CST
 	  && strcmp (TREE_STRING_POINTER (attr), "default") == 0);
 }
+
+/* Return a declaration like DDECL except that its DECL_ATTRIBUTES
+   is ATTRIBUTE.  */
+
+tree
+build_decl_attribute_variant (tree ddecl, tree attribute)
+{
+  DECL_ATTRIBUTES (ddecl) = attribute;
+  return ddecl;
+}
+
+/* Return a type like TTYPE except that its TYPE_ATTRIBUTE
+   is ATTRIBUTE and its qualifiers are QUALS.
+
+   Record such modified types already made so we don't make duplicates.  */
+
+tree
+build_type_attribute_qual_variant (tree ttype, tree attribute, int quals)
+{
+  if (! attribute_list_equal (TYPE_ATTRIBUTES (ttype), attribute))
+    {
+      tree ntype;
+
+      /* Building a distinct copy of a tagged type is inappropriate; it
+	 causes breakage in code that expects there to be a one-to-one
+	 relationship between a struct and its fields.
+	 build_duplicate_type is another solution (as used in
+	 handle_transparent_union_attribute), but that doesn't play well
+	 with the stronger C++ type identity model.  */
+      if (TREE_CODE (ttype) == RECORD_TYPE
+	  || TREE_CODE (ttype) == UNION_TYPE
+	  || TREE_CODE (ttype) == QUAL_UNION_TYPE
+	  || TREE_CODE (ttype) == ENUMERAL_TYPE)
+	{
+	  warning (OPT_Wattributes,
+		   "ignoring attributes applied to %qT after definition",
+		   TYPE_MAIN_VARIANT (ttype));
+	  return build_qualified_type (ttype, quals);
+	}
+
+      ttype = build_qualified_type (ttype, TYPE_UNQUALIFIED);
+      ntype = build_distinct_type_copy (ttype);
+
+      TYPE_ATTRIBUTES (ntype) = attribute;
+
+      hashval_t hash = type_hash_canon_hash (ntype);
+      ntype = type_hash_canon (hash, ntype);
+
+      /* If the target-dependent attributes make NTYPE different from
+	 its canonical type, we will need to use structural equality
+	 checks for this type. */
+      if (TYPE_STRUCTURAL_EQUALITY_P (ttype)
+          || !comp_type_attributes (ntype, ttype))
+	SET_TYPE_STRUCTURAL_EQUALITY (ntype);
+      else if (TYPE_CANONICAL (ntype) == ntype)
+	TYPE_CANONICAL (ntype) = TYPE_CANONICAL (ttype);
+
+      ttype = build_qualified_type (ntype, quals);
+    }
+  else if (TYPE_QUALS (ttype) != quals)
+    ttype = build_qualified_type (ttype, quals);
+
+  return ttype;
+}
+
+/* Compare two identifier nodes representing attributes.
+   Return true if they are the same, false otherwise.  */
+
+static bool
+cmp_attrib_identifiers (const_tree attr1, const_tree attr2)
+{
+  /* Make sure we're dealing with IDENTIFIER_NODEs.  */
+  gcc_checking_assert (TREE_CODE (attr1) == IDENTIFIER_NODE
+		       && TREE_CODE (attr2) == IDENTIFIER_NODE);
+
+  /* Identifiers can be compared directly for equality.  */
+  if (attr1 == attr2)
+    return true;
+
+  return cmp_attribs (IDENTIFIER_POINTER (attr1), IDENTIFIER_LENGTH (attr1),
+		      IDENTIFIER_POINTER (attr2), IDENTIFIER_LENGTH (attr2));
+}
+
+/* Compare two constructor-element-type constants.  Return 1 if the lists
+   are known to be equal; otherwise return 0.  */
+
+static bool
+simple_cst_list_equal (const_tree l1, const_tree l2)
+{
+  while (l1 != NULL_TREE && l2 != NULL_TREE)
+    {
+      if (simple_cst_equal (TREE_VALUE (l1), TREE_VALUE (l2)) != 1)
+	return false;
+
+      l1 = TREE_CHAIN (l1);
+      l2 = TREE_CHAIN (l2);
+    }
+
+  return l1 == l2;
+}
+
+/* Check if "omp declare simd" attribute arguments, CLAUSES1 and CLAUSES2, are
+   the same.  */
+
+static bool
+omp_declare_simd_clauses_equal (tree clauses1, tree clauses2)
+{
+  tree cl1, cl2;
+  for (cl1 = clauses1, cl2 = clauses2;
+       cl1 && cl2;
+       cl1 = OMP_CLAUSE_CHAIN (cl1), cl2 = OMP_CLAUSE_CHAIN (cl2))
+    {
+      if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_CODE (cl2))
+	return false;
+      if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_SIMDLEN)
+	{
+	  if (simple_cst_equal (OMP_CLAUSE_DECL (cl1),
+				OMP_CLAUSE_DECL (cl2)) != 1)
+	    return false;
+	}
+      switch (OMP_CLAUSE_CODE (cl1))
+	{
+	case OMP_CLAUSE_ALIGNED:
+	  if (simple_cst_equal (OMP_CLAUSE_ALIGNED_ALIGNMENT (cl1),
+				OMP_CLAUSE_ALIGNED_ALIGNMENT (cl2)) != 1)
+	    return false;
+	  break;
+	case OMP_CLAUSE_LINEAR:
+	  if (simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (cl1),
+				OMP_CLAUSE_LINEAR_STEP (cl2)) != 1)
+	    return false;
+	  break;
+	case OMP_CLAUSE_SIMDLEN:
+	  if (simple_cst_equal (OMP_CLAUSE_SIMDLEN_EXPR (cl1),
+				OMP_CLAUSE_SIMDLEN_EXPR (cl2)) != 1)
+	    return false;
+	default:
+	  break;
+	}
+    }
+  return true;
+}
+
+
+/* Compare two attributes for their value identity.  Return true if the
+   attribute values are known to be equal; otherwise return false.  */
+
+bool
+attribute_value_equal (const_tree attr1, const_tree attr2)
+{
+  if (TREE_VALUE (attr1) == TREE_VALUE (attr2))
+    return true;
+
+  if (TREE_VALUE (attr1) != NULL_TREE
+      && TREE_CODE (TREE_VALUE (attr1)) == TREE_LIST
+      && TREE_VALUE (attr2) != NULL_TREE
+      && TREE_CODE (TREE_VALUE (attr2)) == TREE_LIST)
+    {
+      /* Handle attribute format.  */
+      if (is_attribute_p ("format", get_attribute_name (attr1)))
+	{
+	  attr1 = TREE_VALUE (attr1);
+	  attr2 = TREE_VALUE (attr2);
+	  /* Compare the archetypes (printf/scanf/strftime/...).  */
+	  if (!cmp_attrib_identifiers (TREE_VALUE (attr1), TREE_VALUE (attr2)))
+	    return false;
+	  /* Archetypes are the same.  Compare the rest.  */
+	  return (simple_cst_list_equal (TREE_CHAIN (attr1),
+					 TREE_CHAIN (attr2)) == 1);
+	}
+      return (simple_cst_list_equal (TREE_VALUE (attr1),
+				     TREE_VALUE (attr2)) == 1);
+    }
+
+  if ((flag_openmp || flag_openmp_simd)
+      && TREE_VALUE (attr1) && TREE_VALUE (attr2)
+      && TREE_CODE (TREE_VALUE (attr1)) == OMP_CLAUSE
+      && TREE_CODE (TREE_VALUE (attr2)) == OMP_CLAUSE)
+    return omp_declare_simd_clauses_equal (TREE_VALUE (attr1),
+					   TREE_VALUE (attr2));
+
+  return (simple_cst_equal (TREE_VALUE (attr1), TREE_VALUE (attr2)) == 1);
+}
+
+/* Return 0 if the attributes for two types are incompatible, 1 if they
+   are compatible, and 2 if they are nearly compatible (which causes a
+   warning to be generated).  */
+int
+comp_type_attributes (const_tree type1, const_tree type2)
+{
+  const_tree a1 = TYPE_ATTRIBUTES (type1);
+  const_tree a2 = TYPE_ATTRIBUTES (type2);
+  const_tree a;
+
+  if (a1 == a2)
+    return 1;
+  for (a = a1; a != NULL_TREE; a = TREE_CHAIN (a))
+    {
+      const struct attribute_spec *as;
+      const_tree attr;
+
+      as = lookup_attribute_spec (get_attribute_name (a));
+      if (!as || as->affects_type_identity == false)
+        continue;
+
+      attr = lookup_attribute (as->name, CONST_CAST_TREE (a2));
+      if (!attr || !attribute_value_equal (a, attr))
+        break;
+    }
+  if (!a)
+    {
+      for (a = a2; a != NULL_TREE; a = TREE_CHAIN (a))
+	{
+	  const struct attribute_spec *as;
+
+	  as = lookup_attribute_spec (get_attribute_name (a));
+	  if (!as || as->affects_type_identity == false)
+	    continue;
+
+	  if (!lookup_attribute (as->name, CONST_CAST_TREE (a1)))
+	    break;
+	  /* We don't need to compare trees again, as we did this
+	     already in first loop.  */
+	}
+      /* All types - affecting identity - are equal, so
+         there is no need to call target hook for comparison.  */
+      if (!a)
+        return 1;
+    }
+  if (lookup_attribute ("transaction_safe", CONST_CAST_TREE (a)))
+    return 0;
+  /* As some type combinations - like default calling-convention - might
+     be compatible, we have to call the target hook to get the final result.  */
+  return targetm.comp_type_attributes (type1, type2);
+}
+
+/* Return a type like TTYPE except that its TYPE_ATTRIBUTE
+   is ATTRIBUTE.
+
+   Record such modified types already made so we don't make duplicates.  */
+
+tree
+build_type_attribute_variant (tree ttype, tree attribute)
+{
+  return build_type_attribute_qual_variant (ttype, attribute,
+					    TYPE_QUALS (ttype));
+}
+
+/* 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 (get_attribute_name (list))
+			   == IDENTIFIER_NODE);
+
+      if (cmp_attrib_identifiers (attr_identifier,
+				  get_attribute_name (list)))
+	/* Found it.  */
+	break;
+      list = TREE_CHAIN (list);
+    }
+
+  return list;
+}
+
+/* Remove any instances of attribute ATTR_NAME in LIST and return the
+   modified list.  */
+
+tree
+remove_attribute (const char *attr_name, tree list)
+{
+  tree *p;
+  gcc_checking_assert (attr_name[0] != '_');
+
+  for (p = &list; *p; )
+    {
+      tree l = *p;
+
+      tree attr = get_attribute_name (l);
+      if (is_attribute_p (attr_name, attr))
+	*p = TREE_CHAIN (l);
+      else
+	p = &TREE_CHAIN (l);
+    }
+
+  return list;
+}
+
+/* Return an attribute list that is the union of a1 and a2.  */
+
+tree
+merge_attributes (tree a1, tree a2)
+{
+  tree attributes;
+
+  /* Either one unset?  Take the set one.  */
+
+  if ((attributes = a1) == 0)
+    attributes = a2;
+
+  /* One that completely contains the other?  Take it.  */
+
+  else if (a2 != 0 && ! attribute_list_contained (a1, a2))
+    {
+      if (attribute_list_contained (a2, a1))
+	attributes = a2;
+      else
+	{
+	  /* Pick the longest list, and hang on the other list.  */
+
+	  if (list_length (a1) < list_length (a2))
+	    attributes = a2, a2 = a1;
+
+	  for (; a2 != 0; a2 = TREE_CHAIN (a2))
+	    {
+	      tree a;
+	      for (a = lookup_ident_attribute (get_attribute_name (a2),
+					       attributes);
+		   a != NULL_TREE && !attribute_value_equal (a, a2);
+		   a = lookup_ident_attribute (get_attribute_name (a2),
+					       TREE_CHAIN (a)))
+		;
+	      if (a == NULL_TREE)
+		{
+		  a1 = copy_node (a2);
+		  TREE_CHAIN (a1) = attributes;
+		  attributes = a1;
+		}
+	    }
+	}
+    }
+  return attributes;
+}
+
+/* Given types T1 and T2, merge their attributes and return
+  the result.  */
+
+tree
+merge_type_attributes (tree t1, tree t2)
+{
+  return merge_attributes (TYPE_ATTRIBUTES (t1),
+			   TYPE_ATTRIBUTES (t2));
+}
+
+/* Given decls OLDDECL and NEWDECL, merge their attributes and return
+   the result.  */
+
+tree
+merge_decl_attributes (tree olddecl, tree newdecl)
+{
+  return merge_attributes (DECL_ATTRIBUTES (olddecl),
+			   DECL_ATTRIBUTES (newdecl));
+}
+
+#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
+
+/* Specialization of merge_decl_attributes for various Windows targets.
+
+   This handles the following situation:
+
+     __declspec (dllimport) int foo;
+     int foo;
+
+   The second instance of `foo' nullifies the dllimport.  */
+
+tree
+merge_dllimport_decl_attributes (tree old, tree new_tree)
+{
+  tree a;
+  int delete_dllimport_p = 1;
+
+  /* What we need to do here is remove from `old' dllimport if it doesn't
+     appear in `new'.  dllimport behaves like extern: if a declaration is
+     marked dllimport and a definition appears later, then the object
+     is not dllimport'd.  We also remove a `new' dllimport if the old list
+     contains dllexport:  dllexport always overrides dllimport, regardless
+     of the order of declaration.  */
+  if (!VAR_OR_FUNCTION_DECL_P (new_tree))
+    delete_dllimport_p = 0;
+  else if (DECL_DLLIMPORT_P (new_tree)
+     	   && lookup_attribute ("dllexport", DECL_ATTRIBUTES (old)))
+    {
+      DECL_DLLIMPORT_P (new_tree) = 0;
+      warning (OPT_Wattributes, "%q+D already declared with dllexport attribute: "
+	      "dllimport ignored", new_tree);
+    }
+  else if (DECL_DLLIMPORT_P (old) && !DECL_DLLIMPORT_P (new_tree))
+    {
+      /* Warn about overriding a symbol that has already been used, e.g.:
+           extern int __attribute__ ((dllimport)) foo;
+	   int* bar () {return &foo;}
+	   int foo;
+      */
+      if (TREE_USED (old))
+	{
+	  warning (0, "%q+D redeclared without dllimport attribute "
+		   "after being referenced with dll linkage", new_tree);
+	  /* If we have used a variable's address with dllimport linkage,
+	      keep the old DECL_DLLIMPORT_P flag: the ADDR_EXPR using the
+	      decl may already have had TREE_CONSTANT computed.
+	      We still remove the attribute so that assembler code refers
+	      to '&foo rather than '_imp__foo'.  */
+	  if (VAR_P (old) && TREE_ADDRESSABLE (old))
+	    DECL_DLLIMPORT_P (new_tree) = 1;
+	}
+
+      /* Let an inline definition silently override the external reference,
+	 but otherwise warn about attribute inconsistency.  */
+      else if (VAR_P (new_tree) || !DECL_DECLARED_INLINE_P (new_tree))
+	warning (OPT_Wattributes, "%q+D redeclared without dllimport attribute: "
+		  "previous dllimport ignored", new_tree);
+    }
+  else
+    delete_dllimport_p = 0;
+
+  a = merge_attributes (DECL_ATTRIBUTES (old), DECL_ATTRIBUTES (new_tree));
+
+  if (delete_dllimport_p)
+    a = remove_attribute ("dllimport", a);
+
+  return a;
+}
+
+/* Handle a "dllimport" or "dllexport" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+tree
+handle_dll_attribute (tree * pnode, tree name, tree args, int flags,
+		      bool *no_add_attrs)
+{
+  tree node = *pnode;
+  bool is_dllimport;
+
+  /* These attributes may apply to structure and union types being created,
+     but otherwise should pass to the declaration involved.  */
+  if (!DECL_P (node))
+    {
+      if (flags & ((int) ATTR_FLAG_DECL_NEXT | (int) ATTR_FLAG_FUNCTION_NEXT
+		   | (int) ATTR_FLAG_ARRAY_NEXT))
+	{
+	  *no_add_attrs = true;
+	  return tree_cons (name, args, NULL_TREE);
+	}
+      if (TREE_CODE (node) == RECORD_TYPE
+	  || TREE_CODE (node) == UNION_TYPE)
+	{
+	  node = TYPE_NAME (node);
+	  if (!node)
+	    return NULL_TREE;
+	}
+      else
+	{
+	  warning (OPT_Wattributes, "%qE attribute ignored",
+		   name);
+	  *no_add_attrs = true;
+	  return NULL_TREE;
+	}
+    }
+
+  if (!VAR_OR_FUNCTION_DECL_P (node) && TREE_CODE (node) != TYPE_DECL)
+    {
+      *no_add_attrs = true;
+      warning (OPT_Wattributes, "%qE attribute ignored",
+	       name);
+      return NULL_TREE;
+    }
+
+  if (TREE_CODE (node) == TYPE_DECL
+      && TREE_CODE (TREE_TYPE (node)) != RECORD_TYPE
+      && TREE_CODE (TREE_TYPE (node)) != UNION_TYPE)
+    {
+      *no_add_attrs = true;
+      warning (OPT_Wattributes, "%qE attribute ignored",
+	       name);
+      return NULL_TREE;
+    }
+
+  is_dllimport = is_attribute_p ("dllimport", name);
+
+  /* Report error on dllimport ambiguities seen now before they cause
+     any damage.  */
+  if (is_dllimport)
+    {
+      /* Honor any target-specific overrides. */
+      if (!targetm.valid_dllimport_attribute_p (node))
+	*no_add_attrs = true;
+
+     else if (TREE_CODE (node) == FUNCTION_DECL
+	        && DECL_DECLARED_INLINE_P (node))
+	{
+	  warning (OPT_Wattributes, "inline function %q+D declared as "
+		  " dllimport: attribute ignored", node);
+	  *no_add_attrs = true;
+	}
+      /* Like MS, treat definition of dllimported variables and
+	 non-inlined functions on declaration as syntax errors. */
+     else if (TREE_CODE (node) == FUNCTION_DECL && DECL_INITIAL (node))
+	{
+	  error ("function %q+D definition is marked dllimport", node);
+	  *no_add_attrs = true;
+	}
+
+     else if (VAR_P (node))
+	{
+	  if (DECL_INITIAL (node))
+	    {
+	      error ("variable %q+D definition is marked dllimport",
+		     node);
+	      *no_add_attrs = true;
+	    }
+
+	  /* `extern' needn't be specified with dllimport.
+	     Specify `extern' now and hope for the best.  Sigh.  */
+	  DECL_EXTERNAL (node) = 1;
+	  /* Also, implicitly give dllimport'd variables declared within
+	     a function global scope, unless declared static.  */
+	  if (current_function_decl != NULL_TREE && !TREE_STATIC (node))
+	    TREE_PUBLIC (node) = 1;
+	}
+
+      if (*no_add_attrs == false)
+        DECL_DLLIMPORT_P (node) = 1;
+    }
+  else if (TREE_CODE (node) == FUNCTION_DECL
+	   && DECL_DECLARED_INLINE_P (node)
+	   && flag_keep_inline_dllexport)
+    /* An exported function, even if inline, must be emitted.  */
+    DECL_EXTERNAL (node) = 0;
+
+  /*  Report error if symbol is not accessible at global scope.  */
+  if (!TREE_PUBLIC (node) && VAR_OR_FUNCTION_DECL_P (node))
+    {
+      error ("external linkage required for symbol %q+D because of "
+	     "%qE attribute", node, name);
+      *no_add_attrs = true;
+    }
+
+  /* A dllexport'd entity must have default visibility so that other
+     program units (shared libraries or the main executable) can see
+     it.  A dllimport'd entity must have default visibility so that
+     the linker knows that undefined references within this program
+     unit can be resolved by the dynamic linker.  */
+  if (!*no_add_attrs)
+    {
+      if (DECL_VISIBILITY_SPECIFIED (node)
+	  && DECL_VISIBILITY (node) != VISIBILITY_DEFAULT)
+	error ("%qE implies default visibility, but %qD has already "
+	       "been declared with a different visibility",
+	       name, node);
+      DECL_VISIBILITY (node) = VISIBILITY_DEFAULT;
+      DECL_VISIBILITY_SPECIFIED (node) = 1;
+    }
+
+  return NULL_TREE;
+}
+
+#endif /* TARGET_DLLIMPORT_DECL_ATTRIBUTES  */
+
+/* Given two lists of attributes, return true if list l2 is
+   equivalent to l1.  */
+
+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);
+}
+
+/* Given two lists of attributes, return true if list L2 is
+   completely contained within L1.  */
+/* ??? This would be faster if attribute names were stored in a canonicalized
+   form.  Otherwise, if L1 uses `foo' and L2 uses `__foo__', the long method
+   must be used to show these elements are equivalent (which they are).  */
+/* ??? It's not clear that attributes with arguments will always be handled
+   correctly.  */
+
+int
+attribute_list_contained (const_tree l1, const_tree l2)
+{
+  const_tree t1, t2;
+
+  /* First check the obvious, maybe the lists are identical.  */
+  if (l1 == l2)
+    return 1;
+
+  /* Maybe the lists are similar.  */
+  for (t1 = l1, t2 = l2;
+       t1 != 0 && t2 != 0
+        && get_attribute_name (t1) == get_attribute_name (t2)
+        && TREE_VALUE (t1) == TREE_VALUE (t2);
+       t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
+    ;
+
+  /* Maybe the lists are equal.  */
+  if (t1 == 0 && t2 == 0)
+    return 1;
+
+  for (; t2 != 0; t2 = TREE_CHAIN (t2))
+    {
+      const_tree attr;
+      /* 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 (get_attribute_name (t2),
+					  CONST_CAST_TREE (l1));
+	   attr != NULL_TREE && !attribute_value_equal (t2, attr);
+	   attr = lookup_ident_attribute (get_attribute_name (t2),
+					  TREE_CHAIN (attr)))
+	;
+
+      if (attr == NULL_TREE)
+	return 0;
+    }
+
+  return 1;
+}
diff --git a/gcc/attribs.h b/gcc/attribs.h
index a6b1ac1ff35..4cb9beaa483 100644
--- a/gcc/attribs.h
+++ b/gcc/attribs.h
@@ -47,6 +47,46 @@  extern char *make_unique_name (tree, const char *, bool);
 extern tree make_dispatcher_decl (const tree);
 extern bool is_function_default_version (const tree);
 
+/* Return a type like TTYPE except that its TYPE_ATTRIBUTES
+   is ATTRIBUTE.
+
+   Such modified types already made are recorded so that duplicates
+   are not made.  */
+
+extern tree build_type_attribute_variant (tree, tree);
+extern tree build_decl_attribute_variant (tree, tree);
+extern tree build_type_attribute_qual_variant (tree, tree, int);
+
+extern bool attribute_value_equal (const_tree, const_tree);
+
+/* Return 0 if the attributes for two types are incompatible, 1 if they
+   are compatible, and 2 if they are nearly compatible (which causes a
+   warning to be generated).  */
+extern int comp_type_attributes (const_tree, const_tree);
+
+/* Default versions of target-overridable functions.  */
+extern tree merge_decl_attributes (tree, tree);
+extern tree merge_type_attributes (tree, tree);
+
+/* Remove any instances of attribute ATTR_NAME in LIST and return the
+   modified list.  */
+
+extern tree remove_attribute (const char *, tree);
+
+/* Given two attributes lists, return a list of their union.  */
+
+extern tree merge_attributes (tree, tree);
+
+/* Given two Windows decl attributes lists, possibly including
+   dllimport, return a list of their union .  */
+extern tree merge_dllimport_decl_attributes (tree, tree);
+
+/* Handle a "dllimport" or "dllexport" attribute.  */
+extern tree handle_dll_attribute (tree *, tree, tree, int, bool *);
+
+extern int attribute_list_equal (const_tree, const_tree);
+extern int attribute_list_contained (const_tree, const_tree);
+
 /* For a given IDENTIFIER_NODE, strip leading and trailing '_' characters
    so that we have a canonical form of attribute names.  */
 
@@ -96,4 +136,77 @@  is_attribute_p (const char *attr_name, const_tree ident)
 		      IDENTIFIER_POINTER (ident), IDENTIFIER_LENGTH (ident));
 }
 
+/* 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
+    {
+      size_t attr_len = strlen (attr_name);
+      /* 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.  */
+      while (list)
+	{
+	  tree attr = get_attribute_name (list);
+	  size_t ident_len = IDENTIFIER_LENGTH (attr);
+	  if (cmp_attribs (attr_name, attr_len, IDENTIFIER_POINTER (attr),
+			   ident_len))
+	    break;
+	  list = TREE_CHAIN (list);
+	}
+
+      return list;
+    }
+}
+
+/* Given an attribute name ATTR_NAME and a list of attributes LIST,
+   return a pointer to the attribute's list first element if the attribute
+   starts with ATTR_NAME. ATTR_NAME must be in the form 'text' (not
+   '__text__').  */
+
+static inline tree
+lookup_attribute_by_prefix (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
+    {
+      size_t attr_len = strlen (attr_name);
+      while (list)
+	{
+	  size_t ident_len = IDENTIFIER_LENGTH (get_attribute_name (list));
+
+	  if (attr_len > ident_len)
+	    {
+	      list = TREE_CHAIN (list);
+	      continue;
+	    }
+
+	  const char *p = IDENTIFIER_POINTER (get_attribute_name (list));
+	  gcc_checking_assert (attr_len == 0 || p[0] != '_');
+
+	  if (strncmp (attr_name, p, attr_len) == 0)
+	    break;
+
+	  list = TREE_CHAIN (list);
+	}
+
+      return list;
+    }
+}
+
 #endif // GCC_ATTRIBS_H
diff --git a/gcc/bb-reorder.c b/gcc/bb-reorder.c
index a421f6b3c71..ff67d8d846d 100644
--- a/gcc/bb-reorder.c
+++ b/gcc/bb-reorder.c
@@ -115,6 +115,8 @@ 
 #include "bb-reorder.h"
 #include "except.h"
 #include "fibonacci_heap.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* The number of rounds.  In most cases there will only be 4 rounds, but
    when partitioning hot and cold basic blocks into separate sections of
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 2deef725620..3ef10cf8a1e 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -60,6 +60,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "value-prof.h"
 #include "builtins.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "cilk.h"
 #include "tree-chkp.h"
diff --git a/gcc/c-family/c-ada-spec.c b/gcc/c-family/c-ada-spec.c
index 6cf298a126a..8ee0c9a088c 100644
--- a/gcc/c-family/c-ada-spec.c
+++ b/gcc/c-family/c-ada-spec.c
@@ -28,6 +28,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "fold-const.h"
 #include "c-pragma.h"
 #include "cpp-id-data.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Local functions, macros and variables.  */
 static int dump_generic_ada_node (pretty_printer *, tree, tree, int, int,
diff --git a/gcc/c-family/c-ubsan.c b/gcc/c-family/c-ubsan.c
index a072d19eda6..1295cfadcd0 100644
--- a/gcc/c-family/c-ubsan.c
+++ b/gcc/c-family/c-ubsan.c
@@ -25,10 +25,12 @@  along with GCC; see the file COPYING3.  If not see
 #include "c-family/c-common.h"
 #include "ubsan.h"
 #include "c-family/c-ubsan.h"
-#include "asan.h"
 #include "stor-layout.h"
 #include "builtins.h"
 #include "gimplify.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "asan.h"
 
 /* Instrument division by zero and INT_MIN / -1.  If not instrumenting,
    return NULL_TREE.  */
diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
index b9378c2dbe2..21e64811630 100644
--- a/gcc/c-family/c-warn.c
+++ b/gcc/c-family/c-warn.c
@@ -28,6 +28,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "tm_p.h"
 #include "diagnostic.h"
 #include "intl.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "gcc-rich-location.h"
 #include "gimplify.h"
diff --git a/gcc/c/c-convert.c b/gcc/c/c-convert.c
index 33c9143e354..d6aeb9f3634 100644
--- a/gcc/c/c-convert.c
+++ b/gcc/c/c-convert.c
@@ -31,6 +31,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "convert.h"
 #include "langhooks.h"
 #include "ubsan.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* Change of width--truncation and extension of integers or reals--
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 4d067e96dd3..ba542d0cceb 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -50,6 +50,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "gomp-constants.h"
 #include "spellcheck-tree.h"
 #include "gcc-rich-location.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* Possible cases of implicit bad conversions.  Used to select
diff --git a/gcc/calls.c b/gcc/calls.c
index 8a23b50fc66..83a1274a4f5 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -52,6 +52,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "tree-ssanames.h"
 #include "rtl-chkp.h"
 #include "intl.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Like PREFERRED_STACK_BOUNDARY but in units of bytes, not bits.  */
 #define STACK_BYTES (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT)
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index c427a89bab0..49ab3537ba7 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -68,6 +68,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "tree-outof-ssa.h"
 #include "cfgloop.h"
 #include "insn-attr.h" /* For INSN_SCHEDULING.  */
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "tree-ssa-address.h"
 #include "output.h"
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 6711aeb828e..23f040a9433 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -61,6 +61,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "tree-chkp.h"
 #include "context.h"
 #include "gimplify.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* FIXME: Only for PROP_loops, but cgraph shouldn't have to know about this.  */
 #include "tree-pass.h"
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 6072c567bc3..e8cc765095d 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -204,6 +204,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "dbgcnt.h"
 #include "tree-chkp.h"
 #include "lto-section-names.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Queue of cgraph nodes scheduled to be added into cgraph.  This is a
    secondary queue used during optimization to accommodate passes that
diff --git a/gcc/convert.c b/gcc/convert.c
index 429f988cbde..110995fdfbe 100644
--- a/gcc/convert.c
+++ b/gcc/convert.c
@@ -33,6 +33,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "builtins.h"
 #include "ubsan.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 #define maybe_fold_build1_loc(FOLD_P, LOC, CODE, TYPE, EXPR) \
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index fac6b6c16ac..48d00afe175 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -39,6 +39,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "c-family/c-objc.h"
 #include "internal-fn.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* The various kinds of conversion.  */
 
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index f010f6c63be..786894ec231 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -33,6 +33,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "c-family/c-ubsan.h"
 #include "cilk.h"
 #include "cp-cilkplus.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* Forward declarations.  */
diff --git a/gcc/cp/cp-ubsan.c b/gcc/cp/cp-ubsan.c
index f00f870bd3e..a1ee62618a2 100644
--- a/gcc/cp/cp-ubsan.c
+++ b/gcc/cp/cp-ubsan.c
@@ -23,6 +23,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "cp-tree.h"
 #include "ubsan.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* Test if we should instrument vptr access.  */
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index 631ff49673f..fd758d3c2dc 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -33,6 +33,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "flags.h"
 #include "intl.h"
 #include "convert.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static tree convert_to_pointer_force (tree, tree, tsubst_flags_t);
 static tree build_type_conversion (tree, tree);
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 14335388a50..0b73fae4146 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -30,6 +30,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "gimplify.h"
 #include "c-family/c-ubsan.h"
 #include "intl.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 static bool begin_init_stmts (tree *, tree *);
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index cd06e529fb9..5c8aeba0d99 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -28,6 +28,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "intl.h"
 #include "toplev.h"
 #include "spellcheck-tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static int is_subobject_of_p (tree, tree);
 static tree dfs_lookup_base (tree, void *);
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index f6177b32a32..3018f1b1c1e 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -40,6 +40,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "tree-iterator.h"
 #include "omp-general.h"
 #include "convert.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "gomp-constants.h"
 
 /* There routines provide a modular interface to perform many parsing
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 1c15f29eb3d..4aad31b283a 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -37,6 +37,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "c-family/c-ubsan.h"
 #include "params.h"
 #include "gcc-rich-location.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 static tree cp_build_addr_expr_strict (tree, tsubst_flags_t);
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 5a57b93a73a..dce2ca67666 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -92,6 +92,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "tree-dfa.h"
 #include "gdb/gdb-index.h"
 #include "rtl-iter.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static void dwarf2out_source_line (unsigned int, unsigned int, const char *,
 				   int, bool);
diff --git a/gcc/final.c b/gcc/final.c
index 356c923c4cd..b4c84a3b327 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -76,6 +76,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa.h"
 #include "cfgloop.h"
 #include "params.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "rtl-iter.h"
 #include "print-rtl.h"
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 1bcbbb58154..1ccab70e31a 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -79,6 +79,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "selftest.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Nonzero if we are folding constants inside an initializer; zero
    otherwise.  */
diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c
index 8617cd51a7c..76ee97b81c0 100644
--- a/gcc/fortran/trans-types.c
+++ b/gcc/fortran/trans-types.c
@@ -36,6 +36,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "trans-types.h"
 #include "trans-const.h"
 #include "dwarf2out.h"	/* For struct array_descr_info.  */
+#include "attribs.h"
 
 
 #if (GFC_MAX_DIMENSIONS < 10)
diff --git a/gcc/function.c b/gcc/function.c
index f625489205b..bd2cf882982 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -77,6 +77,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "rtl-chkp.h"
 #include "tree-dfa.h"
 #include "tree-ssa.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* So we can assign to cfun in this file.  */
 #undef cfun
diff --git a/gcc/gimple-expr.c b/gcc/gimple-expr.c
index 9d8034c3192..001b4bafb0e 100644
--- a/gcc/gimple-expr.c
+++ b/gcc/gimple-expr.c
@@ -35,6 +35,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "hash-set.h"
 #include "rtl.h"
 #include "tree-pass.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* ----- Type related -----  */
 
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index d94dc9cd563..7b2052ef39e 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -56,6 +56,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "ipa-chkp.h"
 #include "tree-cfg.h"
 #include "fold-const-call.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* Return true when DECL can be referenced from current unit.
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 4012b3b9e2d..da7666d8284 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -38,6 +38,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "value-prof.h"
 #include "trans-mem.h"
 #include "cfganal.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 #define INDENT(SPACE)							\
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 488f8c82b82..3ab21848dca 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -41,6 +41,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "selftest.h"
 #include "gimple-pretty-print.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 641a8210dad..3562bea4a8b 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -60,6 +60,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "gimple-walk.h"
 #include "langhooks-def.h"	/* FIXME: for lhd_set_decl_assembler_name */
 #include "builtins.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "dbgcnt.h"
 
diff --git a/gcc/hsa-common.c b/gcc/hsa-common.c
index 95636ebc9a8..c8c12afb04c 100644
--- a/gcc/hsa-common.c
+++ b/gcc/hsa-common.c
@@ -40,6 +40,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "internal-fn.h"
 #include "ctype.h"
 #include "builtins.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Structure containing intermediate HSA representation of the generated
    function.  */
diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c
index 6ec8c348eb4..bd227626e83 100644
--- a/gcc/hsa-gen.c
+++ b/gcc/hsa-gen.c
@@ -60,6 +60,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "internal-fn.h"
 #include "builtins.h"
 #include "stor-layout.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Print a warning message and set that we have seen an error.  */
 
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index 1dc75412484..59ee053115a 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -39,6 +39,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "stor-layout.h"
 #include "dojump.h"
 #include "expr.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "ubsan.h"
 #include "recog.h"
diff --git a/gcc/ipa-chkp.c b/gcc/ipa-chkp.c
index 753673c8f66..704ef6e4550 100644
--- a/gcc/ipa-chkp.c
+++ b/gcc/ipa-chkp.c
@@ -34,6 +34,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "tree-chkp.h"
 #include "tree-inline.h"
 #include "ipa-chkp.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /*  Pointer Bounds Checker has two IPA passes to support code instrumentation.
 
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 3b9eab41672..6b3d8d7364c 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -122,6 +122,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "ipa-fnsummary.h"
 #include "ipa-utils.h"
 #include "tree-ssa-ccp.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 template <typename valtype> class ipcp_value;
 
diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c
index f0bc2501c27..7f46c5dc698 100644
--- a/gcc/ipa-devirt.c
+++ b/gcc/ipa-devirt.c
@@ -129,6 +129,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "dbgcnt.h"
 #include "gimple-pretty-print.h"
 #include "intl.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Hash based set of pairs of types.  */
 struct type_pair
diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
index 52a8c9b0e81..ff485210762 100644
--- a/gcc/ipa-fnsummary.c
+++ b/gcc/ipa-fnsummary.c
@@ -82,6 +82,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "cilk.h"
 #include "cfgexpand.h"
 #include "gimplify.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Summaries.  */
 function_summary <ipa_fn_summary *> *ipa_fn_summaries;
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 608db8f8857..dd46cb61362 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -117,6 +117,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "auto-profile.h"
 #include "builtins.h"
 #include "fibonacci_heap.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 typedef fibonacci_heap <sreal, cgraph_edge> edge_heap_t;
diff --git a/gcc/ipa-visibility.c b/gcc/ipa-visibility.c
index cfd90c62211..fadff7ad15e 100644
--- a/gcc/ipa-visibility.c
+++ b/gcc/ipa-visibility.c
@@ -83,6 +83,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "cgraph.h"
 #include "calls.h"
 #include "varasm.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Return true when NODE can not be local. Worker for cgraph_local_node_p.  */
 
diff --git a/gcc/ipa.c b/gcc/ipa.c
index 00cd3084f66..16df4cacedd 100644
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -37,7 +37,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "ipa-fnsummary.h"
 #include "dbgcnt.h"
 #include "debug.h"
-
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Return true when NODE has ADDR reference.  */
 
diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c
index e2680277bb5..15f0eaadf20 100644
--- a/gcc/lto-cgraph.c
+++ b/gcc/lto-cgraph.c
@@ -38,6 +38,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "ipa-utils.h"
 #include "omp-offload.h"
 #include "ipa-chkp.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* True when asm nodes has been output.  */
 bool asm_nodes_output = false;
diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c
index 58935172b2c..ae670142cc5 100644
--- a/gcc/lto/lto-lang.c
+++ b/gcc/lto/lto-lang.c
@@ -35,6 +35,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "lto-tree.h"
 #include "lto.h"
 #include "cilk.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *);
 static tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
diff --git a/gcc/lto/lto-symtab.c b/gcc/lto/lto-symtab.c
index 019677eaf95..70190d0fda2 100644
--- a/gcc/lto/lto-symtab.c
+++ b/gcc/lto/lto-symtab.c
@@ -32,6 +32,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "alias.h"
 #include "lto-symtab.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging
    all edges and removing the old node.  */
diff --git a/gcc/omp-expand.c b/gcc/omp-expand.c
index 929c53078d5..c0caed6011f 100644
--- a/gcc/omp-expand.c
+++ b/gcc/omp-expand.c
@@ -58,7 +58,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "gimple-pretty-print.h"
 #include "hsa-common.h"
 #include "debug.h"
-
+#include "stringpool.h"
+#include "attribs.h"
 
 /* OMP region information.  Every parallel and workshare
    directive is enclosed between two markers, the OMP_* directive
diff --git a/gcc/omp-general.c b/gcc/omp-general.c
index 9a5ed88e2d6..237f20608ff 100644
--- a/gcc/omp-general.c
+++ b/gcc/omp-general.c
@@ -33,7 +33,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "fold-const.h"
 #include "langhooks.h"
 #include "omp-general.h"
-
+#include "stringpool.h"
+#include "attribs.h"
 
 tree
 omp_find_clause (tree clauses, enum omp_clause_code kind)
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index bf3fc53b07a..38f2ebe523a 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -58,6 +58,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "gomp-constants.h"
 #include "gimple-pretty-print.h"
 #include "hsa-common.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Lowering of OMP parallel and workshare constructs proceeds in two
    phases.  The first phase scans the function looking for OMP statements
diff --git a/gcc/omp-offload.c b/gcc/omp-offload.c
index 54a4e90f70c..2d4fd411680 100644
--- a/gcc/omp-offload.c
+++ b/gcc/omp-offload.c
@@ -49,6 +49,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "gomp-constants.h"
 #include "gimple-pretty-print.h"
 #include "intl.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Describe the OpenACC looping structure of a function.  The entire
    function is held in a 'NULL' loop.  */
diff --git a/gcc/omp-simd-clone.c b/gcc/omp-simd-clone.c
index a1a563e8094..ad56a61b9da 100644
--- a/gcc/omp-simd-clone.c
+++ b/gcc/omp-simd-clone.c
@@ -48,7 +48,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "ipa-prop.h"
 #include "tree-eh.h"
 #include "varasm.h"
-
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Allocate a fresh `simd_clone' and return it.  NARGS is the number
    of arguments to reserve space for.  */
diff --git a/gcc/opts-global.c b/gcc/opts-global.c
index 50bad77c347..fc55512e554 100644
--- a/gcc/opts-global.c
+++ b/gcc/opts-global.c
@@ -35,6 +35,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "plugin.h"
 #include "toplev.h"
 #include "context.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 typedef const char *const_char_p; /* For DEF_VEC_P.  */
diff --git a/gcc/passes.c b/gcc/passes.c
index 374f6f77897..56d8fd3268b 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -61,6 +61,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "tree-cfgcleanup.h"
 #include "insn-addr.h" /* for INSN_ADDRESSES_ALLOC.  */
 #include "diagnostic-core.h" /* for fnotice */
+#include "stringpool.h"
+#include "attribs.h"
 
 using namespace gcc;
 
diff --git a/gcc/predict.c b/gcc/predict.c
index 2a7dbfa4d9b..d1eaf4ca265 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -59,6 +59,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "gimple-pretty-print.h"
 #include "selftest.h"
 #include "cfgrtl.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Enum with reasons why a predictor is ignored.  */
 
diff --git a/gcc/sancov.c b/gcc/sancov.c
index 1651989ea24..b19de8bbbc5 100644
--- a/gcc/sancov.c
+++ b/gcc/sancov.c
@@ -32,6 +32,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "tree-cfg.h"
 #include "tree-pass.h"
 #include "tree-iterator.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 namespace {
diff --git a/gcc/sanopt.c b/gcc/sanopt.c
index b7740741d43..1f9c82feaa9 100644
--- a/gcc/sanopt.c
+++ b/gcc/sanopt.c
@@ -30,6 +30,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "gimple-pretty-print.h"
 #include "fold-const.h"
 #include "gimple-iterator.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "ubsan.h"
 #include "params.h"
diff --git a/gcc/symtab.c b/gcc/symtab.c
index 0145910023f..7e5eb7d6416 100644
--- a/gcc/symtab.c
+++ b/gcc/symtab.c
@@ -35,6 +35,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "output.h"
 #include "ipa-utils.h"
 #include "calls.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static const char *ipa_ref_use_name[] = {"read","write","addr","alias","chkp"};
 
diff --git a/gcc/toplev.c b/gcc/toplev.c
index e6c69a4ba93..1ff7fd9b6fa 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -63,6 +63,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "hosthooks.h"
 #include "opts.h"
 #include "opts-diagnostic.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "tsan.h"
 #include "plugin.h"
diff --git a/gcc/trans-mem.c b/gcc/trans-mem.c
index eb03560be26..40b53681186 100644
--- a/gcc/trans-mem.c
+++ b/gcc/trans-mem.c
@@ -50,7 +50,8 @@ 
 #include "langhooks.h"
 #include "cfgloop.h"
 #include "tree-ssa-address.h"
-
+#include "stringpool.h"
+#include "attribs.h"
 
 #define A_RUNINSTRUMENTEDCODE	0x0001
 #define A_RUNUNINSTRUMENTEDCODE	0x0002
diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c
index e241f50f308..12af458fb90 100644
--- a/gcc/tree-chkp.c
+++ b/gcc/tree-chkp.c
@@ -52,6 +52,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "tree-dfa.h"
 #include "ipa-chkp.h"
 #include "params.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /*  Pointer Bounds Checker instruments code with memory checks to find
     out-of-bounds memory accesses.  Checks are performed by computing
diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c
index 79d02adbade..ba05dba6ae4 100644
--- a/gcc/tree-eh.c
+++ b/gcc/tree-eh.c
@@ -43,6 +43,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "cfgloop.h"
 #include "gimple-low.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* In some instances a tree and a gimple need to be stored in a same table,
diff --git a/gcc/tree-into-ssa.c b/gcc/tree-into-ssa.c
index d4056373f31..28f72e4ce32 100644
--- a/gcc/tree-into-ssa.c
+++ b/gcc/tree-into-ssa.c
@@ -38,6 +38,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa.h"
 #include "domwalk.h"
 #include "statistics.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 #define PERCENT(x,y) ((float)(x) * 100.0 / (float)(y))
diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c
index 723a5283da6..a56b78a4510 100644
--- a/gcc/tree-object-size.c
+++ b/gcc/tree-object-size.c
@@ -32,6 +32,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "gimple-fold.h"
 #include "gimple-iterator.h"
 #include "tree-cfg.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 struct object_size_info
 {
diff --git a/gcc/tree-parloops.c b/gcc/tree-parloops.c
index cf9bc36936c..e8f8ae07992 100644
--- a/gcc/tree-parloops.c
+++ b/gcc/tree-parloops.c
@@ -58,6 +58,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "tree-eh.h"
 #include "gomp-constants.h"
 #include "tree-dfa.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* This pass tries to distribute iterations of loops into several threads.
    The implementation is straightforward -- for each loop we test whether its
diff --git a/gcc/tree-profile.c b/gcc/tree-profile.c
index b1ee7f2b3f5..4b73255018c 100644
--- a/gcc/tree-profile.c
+++ b/gcc/tree-profile.c
@@ -50,6 +50,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "profile.h"
 #include "tree-cfgcleanup.h"
 #include "params.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static GTY(()) tree gcov_type_node;
 static GTY(()) tree tree_interval_profiler_fn;
diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c
index f18f2e0c2a4..3940d538ca7 100644
--- a/gcc/tree-ssa-ccp.c
+++ b/gcc/tree-ssa-ccp.c
@@ -145,6 +145,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-ccp.h"
 #include "tree-dfa.h"
 #include "diagnostic-core.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Possible lattice values.  */
 typedef enum
diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c
index c77075e4ac6..8738fe21a6e 100644
--- a/gcc/tree-ssa-live.c
+++ b/gcc/tree-ssa-live.c
@@ -38,6 +38,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa.h"
 #include "ipa-utils.h"
 #include "cfgloop.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static void verify_live_on_entry (tree_live_info_p);
 
diff --git a/gcc/tree-ssa-loop.c b/gcc/tree-ssa-loop.c
index 19a0f30c525..1e8491757a6 100644
--- a/gcc/tree-ssa-loop.c
+++ b/gcc/tree-ssa-loop.c
@@ -38,6 +38,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "tree-vectorizer.h"
 #include "omp-general.h"
 #include "diagnostic-core.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 
 /* A pass making sure loops are fixed up.  */
diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c
index 324cd73f513..e4786fb9aaa 100644
--- a/gcc/tree-ssa-sccvn.c
+++ b/gcc/tree-ssa-sccvn.c
@@ -60,6 +60,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "domwalk.h"
 #include "gimple-iterator.h"
 #include "gimple-match.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* This algorithm is based on the SCC algorithm presented by Keith
    Cooper and L. Taylor Simpson in "SCC-Based Value numbering"
diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c
index fa8f81e9a1a..fc6022eb47a 100644
--- a/gcc/tree-ssa.c
+++ b/gcc/tree-ssa.c
@@ -41,6 +41,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "cfgexpand.h"
 #include "tree-cfg.h"
 #include "tree-dfa.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* Pointer map of variable mappings, keyed by edge.  */
diff --git a/gcc/tree-streamer-in.c b/gcc/tree-streamer-in.c
index 7f7ea7f90ab..cabdb71fd12 100644
--- a/gcc/tree-streamer-in.c
+++ b/gcc/tree-streamer-in.c
@@ -32,6 +32,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "ipa-chkp.h"
 #include "gomp-constants.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 
diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c
index 33a1f580474..9fe40b928d4 100644
--- a/gcc/tree-vectorizer.c
+++ b/gcc/tree-vectorizer.c
@@ -76,6 +76,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-propagate.h"
 #include "dbgcnt.h"
 #include "tree-scalar-evolution.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 
 /* Loop or bb location.  */
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 28205f19751..ebc4701d377 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -62,6 +62,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "alloc-pool.h"
 #include "domwalk.h"
 #include "tree-cfgcleanup.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 #define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
 
diff --git a/gcc/tree.c b/gcc/tree.c
index 13335a007b7..de902f77319 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -62,6 +62,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "print-tree.h"
 #include "ipa-utils.h"
 #include "selftest.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Tree code classes.  */
 
@@ -4804,254 +4806,6 @@  protected_set_expr_location (tree t, location_t loc)
     SET_EXPR_LOCATION (t, loc);
 }
 
-/* Return a declaration like DDECL except that its DECL_ATTRIBUTES
-   is ATTRIBUTE.  */
-
-tree
-build_decl_attribute_variant (tree ddecl, tree attribute)
-{
-  DECL_ATTRIBUTES (ddecl) = attribute;
-  return ddecl;
-}
-
-/* Return a type like TTYPE except that its TYPE_ATTRIBUTE
-   is ATTRIBUTE and its qualifiers are QUALS.
-
-   Record such modified types already made so we don't make duplicates.  */
-
-tree
-build_type_attribute_qual_variant (tree ttype, tree attribute, int quals)
-{
-  if (! attribute_list_equal (TYPE_ATTRIBUTES (ttype), attribute))
-    {
-      tree ntype;
-
-      /* Building a distinct copy of a tagged type is inappropriate; it
-	 causes breakage in code that expects there to be a one-to-one
-	 relationship between a struct and its fields.
-	 build_duplicate_type is another solution (as used in
-	 handle_transparent_union_attribute), but that doesn't play well
-	 with the stronger C++ type identity model.  */
-      if (TREE_CODE (ttype) == RECORD_TYPE
-	  || TREE_CODE (ttype) == UNION_TYPE
-	  || TREE_CODE (ttype) == QUAL_UNION_TYPE
-	  || TREE_CODE (ttype) == ENUMERAL_TYPE)
-	{
-	  warning (OPT_Wattributes,
-		   "ignoring attributes applied to %qT after definition",
-		   TYPE_MAIN_VARIANT (ttype));
-	  return build_qualified_type (ttype, quals);
-	}
-
-      ttype = build_qualified_type (ttype, TYPE_UNQUALIFIED);
-      ntype = build_distinct_type_copy (ttype);
-
-      TYPE_ATTRIBUTES (ntype) = attribute;
-
-      hashval_t hash = type_hash_canon_hash (ntype);
-      ntype = type_hash_canon (hash, ntype);
-
-      /* If the target-dependent attributes make NTYPE different from
-	 its canonical type, we will need to use structural equality
-	 checks for this type. */
-      if (TYPE_STRUCTURAL_EQUALITY_P (ttype)
-          || !comp_type_attributes (ntype, ttype))
-	SET_TYPE_STRUCTURAL_EQUALITY (ntype);
-      else if (TYPE_CANONICAL (ntype) == ntype)
-	TYPE_CANONICAL (ntype) = TYPE_CANONICAL (ttype);
-
-      ttype = build_qualified_type (ntype, quals);
-    }
-  else if (TYPE_QUALS (ttype) != quals)
-    ttype = build_qualified_type (ttype, quals);
-
-  return ttype;
-}
-
-/* Check if "omp declare simd" attribute arguments, CLAUSES1 and CLAUSES2, are
-   the same.  */
-
-static bool
-omp_declare_simd_clauses_equal (tree clauses1, tree clauses2)
-{
-  tree cl1, cl2;
-  for (cl1 = clauses1, cl2 = clauses2;
-       cl1 && cl2;
-       cl1 = OMP_CLAUSE_CHAIN (cl1), cl2 = OMP_CLAUSE_CHAIN (cl2))
-    {
-      if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_CODE (cl2))
-	return false;
-      if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_SIMDLEN)
-	{
-	  if (simple_cst_equal (OMP_CLAUSE_DECL (cl1),
-				OMP_CLAUSE_DECL (cl2)) != 1)
-	    return false;
-	}
-      switch (OMP_CLAUSE_CODE (cl1))
-	{
-	case OMP_CLAUSE_ALIGNED:
-	  if (simple_cst_equal (OMP_CLAUSE_ALIGNED_ALIGNMENT (cl1),
-				OMP_CLAUSE_ALIGNED_ALIGNMENT (cl2)) != 1)
-	    return false;
-	  break;
-	case OMP_CLAUSE_LINEAR:
-	  if (simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (cl1),
-				OMP_CLAUSE_LINEAR_STEP (cl2)) != 1)
-	    return false;
-	  break;
-	case OMP_CLAUSE_SIMDLEN:
-	  if (simple_cst_equal (OMP_CLAUSE_SIMDLEN_EXPR (cl1),
-				OMP_CLAUSE_SIMDLEN_EXPR (cl2)) != 1)
-	    return false;
-	default:
-	  break;
-	}
-    }
-  return true;
-}
-
-/* Compare two constructor-element-type constants.  Return 1 if the lists
-   are known to be equal; otherwise return 0.  */
-
-static bool
-simple_cst_list_equal (const_tree l1, const_tree l2)
-{
-  while (l1 != NULL_TREE && l2 != NULL_TREE)
-    {
-      if (simple_cst_equal (TREE_VALUE (l1), TREE_VALUE (l2)) != 1)
-	return false;
-
-      l1 = TREE_CHAIN (l1);
-      l2 = TREE_CHAIN (l2);
-    }
-
-  return l1 == l2;
-}
-
-/* Compare two identifier nodes representing attributes.
-   Return true if they are the same, false otherwise.  */
-
-static bool
-cmp_attrib_identifiers (const_tree attr1, const_tree attr2)
-{
-  /* Make sure we're dealing with IDENTIFIER_NODEs.  */
-  gcc_checking_assert (TREE_CODE (attr1) == IDENTIFIER_NODE
-		       && TREE_CODE (attr2) == IDENTIFIER_NODE);
-
-  /* Identifiers can be compared directly for equality.  */
-  if (attr1 == attr2)
-    return true;
-
-  return cmp_attribs (IDENTIFIER_POINTER (attr1), IDENTIFIER_LENGTH (attr1),
-		      IDENTIFIER_POINTER (attr2), IDENTIFIER_LENGTH (attr2));
-}
-
-/* Compare two attributes for their value identity.  Return true if the
-   attribute values are known to be equal; otherwise return false.  */
-
-bool
-attribute_value_equal (const_tree attr1, const_tree attr2)
-{
-  if (TREE_VALUE (attr1) == TREE_VALUE (attr2))
-    return true;
-
-  if (TREE_VALUE (attr1) != NULL_TREE
-      && TREE_CODE (TREE_VALUE (attr1)) == TREE_LIST
-      && TREE_VALUE (attr2) != NULL_TREE
-      && TREE_CODE (TREE_VALUE (attr2)) == TREE_LIST)
-    {
-      /* Handle attribute format.  */
-      if (is_attribute_p ("format", get_attribute_name (attr1)))
-	{
-	  attr1 = TREE_VALUE (attr1);
-	  attr2 = TREE_VALUE (attr2);
-	  /* Compare the archetypes (printf/scanf/strftime/...).  */
-	  if (!cmp_attrib_identifiers (TREE_VALUE (attr1),
-				       TREE_VALUE (attr2)))
-	    return false;
-	  /* Archetypes are the same.  Compare the rest.  */
-	  return (simple_cst_list_equal (TREE_CHAIN (attr1),
-					 TREE_CHAIN (attr2)) == 1);
-	}
-      return (simple_cst_list_equal (TREE_VALUE (attr1),
-				     TREE_VALUE (attr2)) == 1);
-    }
-
-  if ((flag_openmp || flag_openmp_simd)
-      && TREE_VALUE (attr1) && TREE_VALUE (attr2)
-      && TREE_CODE (TREE_VALUE (attr1)) == OMP_CLAUSE
-      && TREE_CODE (TREE_VALUE (attr2)) == OMP_CLAUSE)
-    return omp_declare_simd_clauses_equal (TREE_VALUE (attr1),
-					   TREE_VALUE (attr2));
-
-  return (simple_cst_equal (TREE_VALUE (attr1), TREE_VALUE (attr2)) == 1);
-}
-
-/* Return 0 if the attributes for two types are incompatible, 1 if they
-   are compatible, and 2 if they are nearly compatible (which causes a
-   warning to be generated).  */
-int
-comp_type_attributes (const_tree type1, const_tree type2)
-{
-  const_tree a1 = TYPE_ATTRIBUTES (type1);
-  const_tree a2 = TYPE_ATTRIBUTES (type2);
-  const_tree a;
-
-  if (a1 == a2)
-    return 1;
-  for (a = a1; a != NULL_TREE; a = TREE_CHAIN (a))
-    {
-      const struct attribute_spec *as;
-      const_tree attr;
-
-      as = lookup_attribute_spec (get_attribute_name (a));
-      if (!as || as->affects_type_identity == false)
-        continue;
-
-      attr = lookup_attribute (as->name, CONST_CAST_TREE (a2));
-      if (!attr || !attribute_value_equal (a, attr))
-        break;
-    }
-  if (!a)
-    {
-      for (a = a2; a != NULL_TREE; a = TREE_CHAIN (a))
-	{
-	  const struct attribute_spec *as;
-
-	  as = lookup_attribute_spec (get_attribute_name (a));
-	  if (!as || as->affects_type_identity == false)
-	    continue;
-
-	  if (!lookup_attribute (as->name, CONST_CAST_TREE (a1)))
-	    break;
-	  /* We don't need to compare trees again, as we did this
-	     already in first loop.  */
-	}
-      /* All types - affecting identity - are equal, so
-         there is no need to call target hook for comparison.  */
-      if (!a)
-        return 1;
-    }
-  if (lookup_attribute ("transaction_safe", CONST_CAST_TREE (a)))
-    return 0;
-  /* As some type combinations - like default calling-convention - might
-     be compatible, we have to call the target hook to get the final result.  */
-  return targetm.comp_type_attributes (type1, type2);
-}
-
-/* Return a type like TTYPE except that its TYPE_ATTRIBUTE
-   is ATTRIBUTE.
-
-   Record such modified types already made so we don't make duplicates.  */
-
-tree
-build_type_attribute_variant (tree ttype, tree attribute)
-{
-  return build_type_attribute_qual_variant (ttype, attribute,
-					    TYPE_QUALS (ttype));
-}
-
-
 /* Reset the expression *EXPR_P, a size or position.
 
    ??? We could reset all non-constant sizes or positions.  But it's cheap
@@ -6015,379 +5769,6 @@  make_pass_ipa_free_lang_data (gcc::context *ctxt)
 {
   return new pass_ipa_free_lang_data (ctxt);
 }
-
-/* 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)
-    {
-      tree attr = get_attribute_name (list);
-      size_t ident_len = IDENTIFIER_LENGTH (attr);
-      if (cmp_attribs (attr_name, attr_len, IDENTIFIER_POINTER (attr),
-		       ident_len))
-	break;
-      list = TREE_CHAIN (list);
-    }
-
-  return list;
-}
-
-/* Given an attribute name ATTR_NAME and a list of attributes LIST,
-   return a pointer to the attribute's list first element if the attribute
-   starts with ATTR_NAME.  */
-
-tree
-private_lookup_attribute_by_prefix (const char *attr_name, size_t attr_len,
-				    tree list)
-{
-  while (list)
-    {
-      size_t ident_len = IDENTIFIER_LENGTH (get_attribute_name (list));
-
-      if (attr_len > ident_len)
-	{
-	  list = TREE_CHAIN (list);
-	  continue;
-	}
-
-      const char *p = IDENTIFIER_POINTER (get_attribute_name (list));
-      gcc_checking_assert (attr_len == 0 || p[0] != '_');
-
-      if (strncmp (attr_name, p, 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 (get_attribute_name (list))
-			   == IDENTIFIER_NODE);
-
-      if (cmp_attrib_identifiers (attr_identifier,
-				  get_attribute_name (list)))
-	/* Found it.  */
-	break;
-      list = TREE_CHAIN (list);
-    }
-
-  return list;
-}
-
-/* Remove any instances of attribute ATTR_NAME in LIST and return the
-   modified list.  */
-
-tree
-remove_attribute (const char *attr_name, tree list)
-{
-  tree *p;
-  gcc_checking_assert (attr_name[0] != '_');
-
-  for (p = &list; *p; )
-    {
-      tree l = *p;
-
-      tree attr = get_attribute_name (l);
-      if (is_attribute_p (attr_name, attr))
-	*p = TREE_CHAIN (l);
-      else
-	p = &TREE_CHAIN (l);
-    }
-
-  return list;
-}
-
-/* Return an attribute list that is the union of a1 and a2.  */
-
-tree
-merge_attributes (tree a1, tree a2)
-{
-  tree attributes;
-
-  /* Either one unset?  Take the set one.  */
-
-  if ((attributes = a1) == 0)
-    attributes = a2;
-
-  /* One that completely contains the other?  Take it.  */
-
-  else if (a2 != 0 && ! attribute_list_contained (a1, a2))
-    {
-      if (attribute_list_contained (a2, a1))
-	attributes = a2;
-      else
-	{
-	  /* Pick the longest list, and hang on the other list.  */
-
-	  if (list_length (a1) < list_length (a2))
-	    attributes = a2, a2 = a1;
-
-	  for (; a2 != 0; a2 = TREE_CHAIN (a2))
-	    {
-	      tree a;
-	      for (a = lookup_ident_attribute (get_attribute_name (a2),
-					       attributes);
-		   a != NULL_TREE && !attribute_value_equal (a, a2);
-		   a = lookup_ident_attribute (get_attribute_name (a2),
-					       TREE_CHAIN (a)))
-		;
-	      if (a == NULL_TREE)
-		{
-		  a1 = copy_node (a2);
-		  TREE_CHAIN (a1) = attributes;
-		  attributes = a1;
-		}
-	    }
-	}
-    }
-  return attributes;
-}
-
-/* Given types T1 and T2, merge their attributes and return
-  the result.  */
-
-tree
-merge_type_attributes (tree t1, tree t2)
-{
-  return merge_attributes (TYPE_ATTRIBUTES (t1),
-			   TYPE_ATTRIBUTES (t2));
-}
-
-/* Given decls OLDDECL and NEWDECL, merge their attributes and return
-   the result.  */
-
-tree
-merge_decl_attributes (tree olddecl, tree newdecl)
-{
-  return merge_attributes (DECL_ATTRIBUTES (olddecl),
-			   DECL_ATTRIBUTES (newdecl));
-}
-
-#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
-
-/* Specialization of merge_decl_attributes for various Windows targets.
-
-   This handles the following situation:
-
-     __declspec (dllimport) int foo;
-     int foo;
-
-   The second instance of `foo' nullifies the dllimport.  */
-
-tree
-merge_dllimport_decl_attributes (tree old, tree new_tree)
-{
-  tree a;
-  int delete_dllimport_p = 1;
-
-  /* What we need to do here is remove from `old' dllimport if it doesn't
-     appear in `new'.  dllimport behaves like extern: if a declaration is
-     marked dllimport and a definition appears later, then the object
-     is not dllimport'd.  We also remove a `new' dllimport if the old list
-     contains dllexport:  dllexport always overrides dllimport, regardless
-     of the order of declaration.  */
-  if (!VAR_OR_FUNCTION_DECL_P (new_tree))
-    delete_dllimport_p = 0;
-  else if (DECL_DLLIMPORT_P (new_tree)
-     	   && lookup_attribute ("dllexport", DECL_ATTRIBUTES (old)))
-    {
-      DECL_DLLIMPORT_P (new_tree) = 0;
-      warning (OPT_Wattributes, "%q+D already declared with dllexport attribute: "
-	      "dllimport ignored", new_tree);
-    }
-  else if (DECL_DLLIMPORT_P (old) && !DECL_DLLIMPORT_P (new_tree))
-    {
-      /* Warn about overriding a symbol that has already been used, e.g.:
-           extern int __attribute__ ((dllimport)) foo;
-	   int* bar () {return &foo;}
-	   int foo;
-      */
-      if (TREE_USED (old))
-	{
-	  warning (0, "%q+D redeclared without dllimport attribute "
-		   "after being referenced with dll linkage", new_tree);
-	  /* If we have used a variable's address with dllimport linkage,
-	      keep the old DECL_DLLIMPORT_P flag: the ADDR_EXPR using the
-	      decl may already have had TREE_CONSTANT computed.
-	      We still remove the attribute so that assembler code refers
-	      to '&foo rather than '_imp__foo'.  */
-	  if (VAR_P (old) && TREE_ADDRESSABLE (old))
-	    DECL_DLLIMPORT_P (new_tree) = 1;
-	}
-
-      /* Let an inline definition silently override the external reference,
-	 but otherwise warn about attribute inconsistency.  */
-      else if (VAR_P (new_tree) || !DECL_DECLARED_INLINE_P (new_tree))
-	warning (OPT_Wattributes, "%q+D redeclared without dllimport attribute: "
-		  "previous dllimport ignored", new_tree);
-    }
-  else
-    delete_dllimport_p = 0;
-
-  a = merge_attributes (DECL_ATTRIBUTES (old), DECL_ATTRIBUTES (new_tree));
-
-  if (delete_dllimport_p)
-    a = remove_attribute ("dllimport", a);
-
-  return a;
-}
-
-/* Handle a "dllimport" or "dllexport" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-tree
-handle_dll_attribute (tree * pnode, tree name, tree args, int flags,
-		      bool *no_add_attrs)
-{
-  tree node = *pnode;
-  bool is_dllimport;
-
-  /* These attributes may apply to structure and union types being created,
-     but otherwise should pass to the declaration involved.  */
-  if (!DECL_P (node))
-    {
-      if (flags & ((int) ATTR_FLAG_DECL_NEXT | (int) ATTR_FLAG_FUNCTION_NEXT
-		   | (int) ATTR_FLAG_ARRAY_NEXT))
-	{
-	  *no_add_attrs = true;
-	  return tree_cons (name, args, NULL_TREE);
-	}
-      if (TREE_CODE (node) == RECORD_TYPE
-	  || TREE_CODE (node) == UNION_TYPE)
-	{
-	  node = TYPE_NAME (node);
-	  if (!node)
-	    return NULL_TREE;
-	}
-      else
-	{
-	  warning (OPT_Wattributes, "%qE attribute ignored",
-		   name);
-	  *no_add_attrs = true;
-	  return NULL_TREE;
-	}
-    }
-
-  if (!VAR_OR_FUNCTION_DECL_P (node) && TREE_CODE (node) != TYPE_DECL)
-    {
-      *no_add_attrs = true;
-      warning (OPT_Wattributes, "%qE attribute ignored",
-	       name);
-      return NULL_TREE;
-    }
-
-  if (TREE_CODE (node) == TYPE_DECL
-      && TREE_CODE (TREE_TYPE (node)) != RECORD_TYPE
-      && TREE_CODE (TREE_TYPE (node)) != UNION_TYPE)
-    {
-      *no_add_attrs = true;
-      warning (OPT_Wattributes, "%qE attribute ignored",
-	       name);
-      return NULL_TREE;
-    }
-
-  is_dllimport = is_attribute_p ("dllimport", name);
-
-  /* Report error on dllimport ambiguities seen now before they cause
-     any damage.  */
-  if (is_dllimport)
-    {
-      /* Honor any target-specific overrides. */
-      if (!targetm.valid_dllimport_attribute_p (node))
-	*no_add_attrs = true;
-
-     else if (TREE_CODE (node) == FUNCTION_DECL
-	        && DECL_DECLARED_INLINE_P (node))
-	{
-	  warning (OPT_Wattributes, "inline function %q+D declared as "
-		  " dllimport: attribute ignored", node);
-	  *no_add_attrs = true;
-	}
-      /* Like MS, treat definition of dllimported variables and
-	 non-inlined functions on declaration as syntax errors. */
-     else if (TREE_CODE (node) == FUNCTION_DECL && DECL_INITIAL (node))
-	{
-	  error ("function %q+D definition is marked dllimport", node);
-	  *no_add_attrs = true;
-	}
-
-     else if (VAR_P (node))
-	{
-	  if (DECL_INITIAL (node))
-	    {
-	      error ("variable %q+D definition is marked dllimport",
-		     node);
-	      *no_add_attrs = true;
-	    }
-
-	  /* `extern' needn't be specified with dllimport.
-	     Specify `extern' now and hope for the best.  Sigh.  */
-	  DECL_EXTERNAL (node) = 1;
-	  /* Also, implicitly give dllimport'd variables declared within
-	     a function global scope, unless declared static.  */
-	  if (current_function_decl != NULL_TREE && !TREE_STATIC (node))
-	    TREE_PUBLIC (node) = 1;
-	}
-
-      if (*no_add_attrs == false)
-        DECL_DLLIMPORT_P (node) = 1;
-    }
-  else if (TREE_CODE (node) == FUNCTION_DECL
-	   && DECL_DECLARED_INLINE_P (node)
-	   && flag_keep_inline_dllexport)
-    /* An exported function, even if inline, must be emitted.  */
-    DECL_EXTERNAL (node) = 0;
-
-  /*  Report error if symbol is not accessible at global scope.  */
-  if (!TREE_PUBLIC (node) && VAR_OR_FUNCTION_DECL_P (node))
-    {
-      error ("external linkage required for symbol %q+D because of "
-	     "%qE attribute", node, name);
-      *no_add_attrs = true;
-    }
-
-  /* A dllexport'd entity must have default visibility so that other
-     program units (shared libraries or the main executable) can see
-     it.  A dllimport'd entity must have default visibility so that
-     the linker knows that undefined references within this program
-     unit can be resolved by the dynamic linker.  */
-  if (!*no_add_attrs)
-    {
-      if (DECL_VISIBILITY_SPECIFIED (node)
-	  && DECL_VISIBILITY (node) != VISIBILITY_DEFAULT)
-	error ("%qE implies default visibility, but %qD has already "
-	       "been declared with a different visibility",
-	       name, node);
-      DECL_VISIBILITY (node) = VISIBILITY_DEFAULT;
-      DECL_VISIBILITY_SPECIFIED (node) = 1;
-    }
-
-  return NULL_TREE;
-}
-
-#endif /* TARGET_DLLIMPORT_DECL_ATTRIBUTES  */
 
 /* Set the type qualifiers for TYPE to TYPE_QUALS, which is a bitmask
    of the various TYPE_QUAL values.  */
@@ -7153,68 +6534,6 @@  print_type_hash_statistics (void)
 	   type_hash_table->collisions ());
 }
 
-/* Given two lists of attributes, return true if list l2 is
-   equivalent to l1.  */
-
-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);
-}
-
-/* Given two lists of attributes, return true if list L2 is
-   completely contained within L1.  */
-/* ??? This would be faster if attribute names were stored in a canonicalized
-   form.  Otherwise, if L1 uses `foo' and L2 uses `__foo__', the long method
-   must be used to show these elements are equivalent (which they are).  */
-/* ??? It's not clear that attributes with arguments will always be handled
-   correctly.  */
-
-int
-attribute_list_contained (const_tree l1, const_tree l2)
-{
-  const_tree t1, t2;
-
-  /* First check the obvious, maybe the lists are identical.  */
-  if (l1 == l2)
-    return 1;
-
-  /* Maybe the lists are similar.  */
-  for (t1 = l1, t2 = l2;
-       t1 != 0 && t2 != 0
-        && get_attribute_name (t1) == get_attribute_name (t2)
-        && TREE_VALUE (t1) == TREE_VALUE (t2);
-       t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
-    ;
-
-  /* Maybe the lists are equal.  */
-  if (t1 == 0 && t2 == 0)
-    return 1;
-
-  for (; t2 != 0; t2 = TREE_CHAIN (t2))
-    {
-      const_tree attr;
-      /* 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 (get_attribute_name (t2),
-					  CONST_CAST_TREE (l1));
-	   attr != NULL_TREE && !attribute_value_equal (t2, attr);
-	   attr = lookup_ident_attribute (get_attribute_name (t2),
-					  TREE_CHAIN (attr)))
-	;
-
-      if (attr == NULL_TREE)
-	return 0;
-    }
-
-  return 1;
-}
-
 /* Given two lists of types
    (chains of TREE_LIST nodes with types in the TREE_VALUE slots)
    return 1 if the lists contain the same types in the same order.
diff --git a/gcc/tree.h b/gcc/tree.h
index fab566b6684..17b11a1f707 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4124,8 +4124,6 @@  extern tree purpose_member (const_tree, tree);
 extern bool vec_member (const_tree, vec<tree, va_gc> *);
 extern tree chain_index (int, tree);
 
-extern int attribute_list_equal (const_tree, const_tree);
-extern int attribute_list_contained (const_tree, const_tree);
 extern int tree_int_cst_equal (const_tree, const_tree);
 
 extern bool tree_fits_shwi_p (const_tree)
@@ -4163,90 +4161,6 @@  extern bool valid_constant_size_p (const_tree);
 
 extern tree make_tree (tree, rtx);
 
-/* Return a type like TTYPE except that its TYPE_ATTRIBUTES
-   is ATTRIBUTE.
-
-   Such modified types already made are recorded so that duplicates
-   are not made.  */
-
-extern tree build_type_attribute_variant (tree, tree);
-extern tree build_decl_attribute_variant (tree, tree);
-extern tree build_type_attribute_qual_variant (tree, tree, int);
-
-extern bool attribute_value_equal (const_tree, const_tree);
-
-/* Return 0 if the attributes for two types are incompatible, 1 if they
-   are compatible, and 2 if they are nearly compatible (which causes a
-   warning to be generated).  */
-extern int comp_type_attributes (const_tree, const_tree);
-
-/* Default versions of target-overridable functions.  */
-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);
-
-/* This function is a private implementation detail
-   of lookup_attribute_by_prefix() and you should never call it directly.  */
-extern tree private_lookup_attribute_by_prefix (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);
-}
-
-/* Given an attribute name ATTR_NAME and a list of attributes LIST,
-   return a pointer to the attribute's list first element if the attribute
-   starts with ATTR_NAME. ATTR_NAME must be in the form 'text' (not
-   '__text__').  */
-
-static inline tree
-lookup_attribute_by_prefix (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
-    return private_lookup_attribute_by_prefix (attr_name, strlen (attr_name),
-					       list);
-}
-
-/* Remove any instances of attribute ATTR_NAME in LIST and return the
-   modified list.  */
-
-extern tree remove_attribute (const char *, tree);
-
-/* Given two attributes lists, return a list of their union.  */
-
-extern tree merge_attributes (tree, tree);
-
-/* Given two Windows decl attributes lists, possibly including
-   dllimport, return a list of their union .  */
-extern tree merge_dllimport_decl_attributes (tree, tree);
-
-/* Handle a "dllimport" or "dllexport" attribute.  */
-extern tree handle_dll_attribute (tree *, tree, tree, int, bool *);
-
 /* Returns true iff CAND and BASE have equivalent language-specific
    qualifiers.  */
 
diff --git a/gcc/tsan.c b/gcc/tsan.c
index 2f98b936c03..51b5821deb3 100644
--- a/gcc/tsan.c
+++ b/gcc/tsan.c
@@ -40,6 +40,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-loop-ivopts.h"
 #include "tree-eh.h"
 #include "tsan.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "builtins.h"
 #include "target.h"
diff --git a/gcc/ubsan.c b/gcc/ubsan.c
index 8ea352a69d4..b66e84c6edf 100644
--- a/gcc/ubsan.c
+++ b/gcc/ubsan.c
@@ -39,6 +39,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "cfgloop.h"
 #include "ubsan.h"
 #include "expr.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "gimplify-me.h"
 #include "dfp.h"
diff --git a/gcc/varasm.c b/gcc/varasm.c
index fbaebc1b5c0..a6cffb4fa66 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -51,6 +51,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "debug.h"
 #include "common/common-target.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "rtl-iter.h"
 
diff --git a/gcc/varpool.c b/gcc/varpool.c
index ab59c80406b..b005f529cc0 100644
--- a/gcc/varpool.c
+++ b/gcc/varpool.c
@@ -33,6 +33,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "output.h"
 #include "omp-offload.h"
 #include "context.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 const char * const tls_model_names[]={"none", "emulated",
 				      "global-dynamic", "local-dynamic",
-- 
2.13.2