https://github.com/qiongsiwu updated 
https://github.com/llvm/llvm-project/pull/200961

>From b2ffa916c4b4f43183fb90a47548f08e2986882b Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <[email protected]>
Date: Mon, 1 Jun 2026 14:54:21 -0700
Subject: [PATCH 1/3] Fixing attributed type deduplication.

---
 clang/include/clang/AST/Attr.h                 | 12 ++++++++++++
 clang/include/clang/AST/TypeBase.h             |  8 +-------
 clang/include/clang/Basic/Attr.td              |  5 +++++
 clang/lib/AST/Type.cpp                         | 11 +++++++++++
 .../AST/attributed-type-dedup-nullability.m    | 18 ++++++++++++++++++
 .../AST/attributed-type-dedup-swift-attr.m     | 15 +++++++++++++++
 6 files changed, 62 insertions(+), 7 deletions(-)
 create mode 100644 clang/test/AST/attributed-type-dedup-nullability.m
 create mode 100644 clang/test/AST/attributed-type-dedup-swift-attr.m

diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h
index 0f9fc01391c30..df2da85cf6402 100644
--- a/clang/include/clang/AST/Attr.h
+++ b/clang/include/clang/AST/Attr.h
@@ -81,6 +81,8 @@ class Attr : public AttributeCommonInfo {
     return ::operator delete(Ptr, C, Alignment);
   }
 
+  virtual ~Attr() = default;
+
 protected:
   Attr(ASTContext &Context, const AttributeCommonInfo &CommonInfo,
        attr::Kind AK, bool IsLateParsed)
@@ -120,6 +122,16 @@ class Attr : public AttributeCommonInfo {
   void printPretty(raw_ostream &OS, const PrintingPolicy &Policy) const;
 
   static StringRef getDocumentation(attr::Kind);
+
+  // Contribute Attr-specific content to a FoldingSetNodeID for callers like
+  // AttributedType::Profile that dedupe nodes by Attr identity. The default
+  // is empty: AttributedType::Profile already hashes attrKind (and
+  // asserts attr->getKind() == attrKind), so a no-op default makes stateless
+  // Attrs (nullability, ARC ownership, calling conventions, ...) dedupe by
+  // (kind, modified, equivalent) — pointer identity of the Attr is ignored.
+  // Override this in subclasses whose arguments meaningfully distinguish
+  // the wrapped type (e.g. SwiftAttrAttr hashes its string payload).
+  virtual void Profile(llvm::FoldingSetNodeID &ID) const {}
 };
 
 class TypeAttr : public Attr {
diff --git a/clang/include/clang/AST/TypeBase.h 
b/clang/include/clang/AST/TypeBase.h
index c64eee11fd91e..cce7af88181cd 100644
--- a/clang/include/clang/AST/TypeBase.h
+++ b/clang/include/clang/AST/TypeBase.h
@@ -6746,13 +6746,7 @@ class AttributedType : public Type, public 
llvm::FoldingSetNode {
   }
 
   static void Profile(llvm::FoldingSetNodeID &ID, Kind attrKind,
-                      QualType modified, QualType equivalent,
-                      const Attr *attr) {
-    ID.AddInteger(attrKind);
-    ID.AddPointer(modified.getAsOpaquePtr());
-    ID.AddPointer(equivalent.getAsOpaquePtr());
-    ID.AddPointer(attr);
-  }
+                      QualType modified, QualType equivalent, const Attr 
*attr);
 
   static bool classof(const Type *T) {
     return T->getTypeClass() == Attributed;
diff --git a/clang/include/clang/Basic/Attr.td 
b/clang/include/clang/Basic/Attr.td
index 32f72e8da960e..533f13d2ca879 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -3196,6 +3196,11 @@ def SwiftAttr : DeclOrTypeAttr {
   let Args = [StringArgument<"Attribute">];
   let Documentation = [SwiftAttrDocs];
   let PragmaAttributeSupport = 1;
+  let AdditionalMembers = [{
+    void Profile(llvm::FoldingSetNodeID &ID) const override {
+      ID.AddString(getAttribute());
+    }
+  }];
 }
 
 def SwiftBridge : InheritableAttr {
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 96a398aa21dad..711b216d81de7 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -5338,6 +5338,17 @@ NullabilityKindOrNone 
AttributedType::stripOuterNullability(QualType &T) {
   return std::nullopt;
 }
 
+void AttributedType::Profile(llvm::FoldingSetNodeID &ID, Kind attrKind,
+                             QualType modified, QualType equivalent,
+                             const Attr *attr) {
+
+  ID.AddInteger(attrKind);
+  ID.AddPointer(modified.getAsOpaquePtr());
+  ID.AddPointer(equivalent.getAsOpaquePtr());
+  if (attr)
+    attr->Profile(ID);
+}
+
 bool Type::isSignableIntegerType(const ASTContext &Ctx) const {
   if (!isIntegralType(Ctx) || isEnumeralType())
     return false;
diff --git a/clang/test/AST/attributed-type-dedup-nullability.m 
b/clang/test/AST/attributed-type-dedup-nullability.m
new file mode 100644
index 0000000000000..9904ec00913d0
--- /dev/null
+++ b/clang/test/AST/attributed-type-dedup-nullability.m
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fobjc-arc -emit-pch -o %t.pch %s
+// RUN: llvm-bcanalyzer --dump --disable-histogram %t.pch | FileCheck %s
+
+// All three non-null types below should share a single AttributedType node and
+// serialize as exactly one TYPE_ATTRIBUTED record.
+
+@class NSString;
+
+#pragma clang assume_nonnull begin
+@interface T
+- (NSString *)a;
+- (NSString *)b;
+- (NSString *)c;
+@end
+#pragma clang assume_nonnull end
+
+// CHECK-COUNT-1: <TYPE_ATTRIBUTED
+// CHECK-NOT:     <TYPE_ATTRIBUTED
diff --git a/clang/test/AST/attributed-type-dedup-swift-attr.m 
b/clang/test/AST/attributed-type-dedup-swift-attr.m
new file mode 100644
index 0000000000000..d39778572eda5
--- /dev/null
+++ b/clang/test/AST/attributed-type-dedup-swift-attr.m
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fobjc-arc -emit-pch -o %t.pch %s
+// RUN: llvm-bcanalyzer --dump --disable-histogram %t.pch | FileCheck %s
+
+// Checks that swift_attr deduplication works correctly.
+// The following test should generate two attributed types, not three.
+
+#define ATTR_A __attribute__((swift_attr("@A")))
+#define ATTR_B __attribute__((swift_attr("@B")))
+
+void f1(int * ATTR_A p);
+void f2(int * ATTR_A p);
+void f3(int * ATTR_B p);
+
+// CHECK-COUNT-2: <TYPE_ATTRIBUTED
+// CHECK-NOT:     <TYPE_ATTRIBUTED

>From 90f72abfe49e55b1c93eaa93640e9ba05ebd00f6 Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <[email protected]>
Date: Tue, 2 Jun 2026 10:52:23 -0700
Subject: [PATCH 2/3] Revise to make the fix more focused. Removed the virtual
 method Profile from the base Attr class.

---
 clang/include/clang/AST/Attr.h    | 12 ------------
 clang/include/clang/Basic/Attr.td |  2 +-
 clang/lib/AST/Type.cpp            |  6 +++---
 3 files changed, 4 insertions(+), 16 deletions(-)

diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h
index df2da85cf6402..0f9fc01391c30 100644
--- a/clang/include/clang/AST/Attr.h
+++ b/clang/include/clang/AST/Attr.h
@@ -81,8 +81,6 @@ class Attr : public AttributeCommonInfo {
     return ::operator delete(Ptr, C, Alignment);
   }
 
-  virtual ~Attr() = default;
-
 protected:
   Attr(ASTContext &Context, const AttributeCommonInfo &CommonInfo,
        attr::Kind AK, bool IsLateParsed)
@@ -122,16 +120,6 @@ class Attr : public AttributeCommonInfo {
   void printPretty(raw_ostream &OS, const PrintingPolicy &Policy) const;
 
   static StringRef getDocumentation(attr::Kind);
-
-  // Contribute Attr-specific content to a FoldingSetNodeID for callers like
-  // AttributedType::Profile that dedupe nodes by Attr identity. The default
-  // is empty: AttributedType::Profile already hashes attrKind (and
-  // asserts attr->getKind() == attrKind), so a no-op default makes stateless
-  // Attrs (nullability, ARC ownership, calling conventions, ...) dedupe by
-  // (kind, modified, equivalent) — pointer identity of the Attr is ignored.
-  // Override this in subclasses whose arguments meaningfully distinguish
-  // the wrapped type (e.g. SwiftAttrAttr hashes its string payload).
-  virtual void Profile(llvm::FoldingSetNodeID &ID) const {}
 };
 
 class TypeAttr : public Attr {
diff --git a/clang/include/clang/Basic/Attr.td 
b/clang/include/clang/Basic/Attr.td
index 533f13d2ca879..44f8ea6d16532 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -3197,7 +3197,7 @@ def SwiftAttr : DeclOrTypeAttr {
   let Documentation = [SwiftAttrDocs];
   let PragmaAttributeSupport = 1;
   let AdditionalMembers = [{
-    void Profile(llvm::FoldingSetNodeID &ID) const override {
+    void Profile(llvm::FoldingSetNodeID &ID) const {
       ID.AddString(getAttribute());
     }
   }];
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 711b216d81de7..c9d038ec308ef 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -14,6 +14,7 @@
 #include "Linkage.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Attr.h"
+#include "clang/AST/Attrs.inc"
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclBase.h"
@@ -5341,12 +5342,11 @@ NullabilityKindOrNone 
AttributedType::stripOuterNullability(QualType &T) {
 void AttributedType::Profile(llvm::FoldingSetNodeID &ID, Kind attrKind,
                              QualType modified, QualType equivalent,
                              const Attr *attr) {
-
   ID.AddInteger(attrKind);
   ID.AddPointer(modified.getAsOpaquePtr());
   ID.AddPointer(equivalent.getAsOpaquePtr());
-  if (attr)
-    attr->Profile(ID);
+  if (const auto *A = dyn_cast_or_null<SwiftAttrAttr>(attr))
+    A->Profile(ID);
 }
 
 bool Type::isSignableIntegerType(const ASTContext &Ctx) const {

>From f7da8103e353f2bbcb3c2fab6c374b514b5d6c1d Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <[email protected]>
Date: Wed, 3 Jun 2026 14:23:57 -0700
Subject: [PATCH 3/3] More general fix - an attribute's argument is taken into
 account automatically when computing the profile.

---
 clang/include/clang/AST/ASTContext.h          |  3 +-
 clang/include/clang/AST/Attr.h                |  2 +
 clang/include/clang/AST/TypeBase.h            |  9 +-
 clang/include/clang/Basic/Attr.td             |  6 +-
 clang/lib/AST/ASTContext.cpp                  | 10 ++-
 clang/lib/AST/AttrImpl.cpp                    | 85 +++++++++++++++++++
 clang/lib/AST/Type.cpp                        | 10 +--
 .../AST/attributed-type-dedup-address-space.c |  9 ++
 ...attributed-type-dedup-annotate-type-args.c | 14 +++
 .../AST/attributed-type-dedup-annotate-type.m | 12 +++
 .../attributed-type-dedup-objc-ownership.m    | 11 +++
 clang/test/AST/attributed-type-dedup-pcs.c    | 15 ++++
 clang/utils/TableGen/ClangAttrEmitter.cpp     | 43 ++++++++++
 13 files changed, 214 insertions(+), 15 deletions(-)
 create mode 100644 clang/test/AST/attributed-type-dedup-address-space.c
 create mode 100644 clang/test/AST/attributed-type-dedup-annotate-type-args.c
 create mode 100644 clang/test/AST/attributed-type-dedup-annotate-type.m
 create mode 100644 clang/test/AST/attributed-type-dedup-objc-ownership.m
 create mode 100644 clang/test/AST/attributed-type-dedup-pcs.c

diff --git a/clang/include/clang/AST/ASTContext.h 
b/clang/include/clang/AST/ASTContext.h
index c952b8d46974c..e58e123cf95af 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -294,7 +294,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
   mutable llvm::FoldingSet<DeducedTemplateSpecializationType>
     DeducedTemplateSpecializationTypes;
   mutable llvm::FoldingSet<AtomicType> AtomicTypes;
-  mutable llvm::FoldingSet<AttributedType> AttributedTypes;
+  mutable llvm::ContextualFoldingSet<AttributedType, ASTContext &>
+      AttributedTypes;
   mutable llvm::FoldingSet<PipeType> PipeTypes;
   mutable llvm::FoldingSet<BitIntType> BitIntTypes;
   mutable llvm::ContextualFoldingSet<DependentBitIntType, ASTContext &>
diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h
index 0f9fc01391c30..f204bb4faa9b7 100644
--- a/clang/include/clang/AST/Attr.h
+++ b/clang/include/clang/AST/Attr.h
@@ -116,6 +116,8 @@ class Attr : public AttributeCommonInfo {
   bool isEquivalent(const Attr &Other,
                     StructuralEquivalenceContext &Context) const;
 
+  void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) const;
+
   // Pretty print this attribute.
   void printPretty(raw_ostream &OS, const PrintingPolicy &Policy) const;
 
diff --git a/clang/include/clang/AST/TypeBase.h 
b/clang/include/clang/AST/TypeBase.h
index cce7af88181cd..e3141a82b54d2 100644
--- a/clang/include/clang/AST/TypeBase.h
+++ b/clang/include/clang/AST/TypeBase.h
@@ -6741,12 +6741,13 @@ class AttributedType : public Type, public 
llvm::FoldingSetNode {
   /// \returns the top-level nullability, if present.
   static NullabilityKindOrNone stripOuterNullability(QualType &T);
 
-  void Profile(llvm::FoldingSetNodeID &ID) {
-    Profile(ID, getAttrKind(), ModifiedType, EquivalentType, Attribute);
+  void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) {
+    Profile(ID, Ctx, getAttrKind(), ModifiedType, EquivalentType, Attribute);
   }
 
-  static void Profile(llvm::FoldingSetNodeID &ID, Kind attrKind,
-                      QualType modified, QualType equivalent, const Attr 
*attr);
+  static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx,
+                      Kind attrKind, QualType modified, QualType equivalent,
+                      const Attr *attr);
 
   static bool classof(const Type *T) {
     return T->getTypeClass() == Attributed;
diff --git a/clang/include/clang/Basic/Attr.td 
b/clang/include/clang/Basic/Attr.td
index 44f8ea6d16532..6ef9786ce5717 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -768,10 +768,13 @@ class Attr {
   // Note: Any additional data members will leak and should be constructed
   // externally on the ASTContext.
   code AdditionalMembers = [{}];
+
+  string comparisonFn = "";
+  string profileFn = "";
+
   // Any documentation that should be associated with the attribute. Since an
   // attribute may be documented under multiple categories, more than one
   // Documentation entry may be listed.
-  string comparisonFn = "";
   list<Documentation> Documentation;
 }
 
@@ -897,6 +900,7 @@ def Aligned : InheritableAttr {
                                           CustomKeyword<"_Alignas">]>,
                    Accessor<"isDeclspec",[Declspec<"align">]>];
   let comparisonFn = "areAlignedAttrsEqual";
+  let profileFn = "profileAlignedAttr";
   let Documentation = [Undocumented];
 }
 
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index a401a7471e6fc..f46672b086c12 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -937,9 +937,10 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager 
&SM,
       FunctionProtoTypes(this_(), FunctionProtoTypesLog2InitSize),
       DependentTypeOfExprTypes(this_()), DependentDecltypeTypes(this_()),
       DependentPackIndexingTypes(this_()), 
TemplateSpecializationTypes(this_()),
-      DependentBitIntTypes(this_()), SubstTemplateTemplateParmPacks(this_()),
-      DeducedTemplates(this_()), ArrayParameterTypes(this_()),
-      CanonTemplateTemplateParms(this_()), SourceMgr(SM), LangOpts(LOpts),
+      AttributedTypes(this_()), DependentBitIntTypes(this_()),
+      SubstTemplateTemplateParmPacks(this_()), DeducedTemplates(this_()),
+      ArrayParameterTypes(this_()), CanonTemplateTemplateParms(this_()),
+      SourceMgr(SM), LangOpts(LOpts),
       NoSanitizeL(new NoSanitizeList(LangOpts.NoSanitizeFiles, SM)),
       XRayFilter(new XRayFunctionFilter(LangOpts.XRayAlwaysInstrumentFiles,
                                         LangOpts.XRayNeverInstrumentFiles,
@@ -5741,7 +5742,8 @@ QualType ASTContext::getAttributedType(attr::Kind 
attrKind,
                                        QualType equivalentType,
                                        const Attr *attr) const {
   llvm::FoldingSetNodeID id;
-  AttributedType::Profile(id, attrKind, modifiedType, equivalentType, attr);
+  AttributedType::Profile(id, *this, attrKind, modifiedType, equivalentType,
+                          attr);
 
   void *insertPos = nullptr;
   AttributedType *type = AttributedTypes.FindNodeOrInsertPos(id, insertPos);
diff --git a/clang/lib/AST/AttrImpl.cpp b/clang/lib/AST/AttrImpl.cpp
index 3a379891016f8..c613f5a6690f8 100644
--- a/clang/lib/AST/AttrImpl.cpp
+++ b/clang/lib/AST/AttrImpl.cpp
@@ -376,4 +376,89 @@ bool areAlignedAttrsEqual(const AlignedAttr &A1, const 
AlignedAttr &A2,
 }
 } // namespace
 
+namespace {
+// Machinery to unique attributes based on the arguments.
+// The construction mirrors the equivalent testing code above.
+// The content of the arguments are added to the FoldingSetNodeID instance,
+// which allows the AttributedTypes to unique the attributes based on
+// the value of the arguments.
+
+#define USE_DEFAULT_PROFILE                                                    
\
+  (std::is_same_v<T, StringRef> || std::is_same_v<T, VersionTuple> ||          
\
+   std::is_same_v<T, IdentifierInfo *> ||                                      
\
+   std::is_same_v<T, const IdentifierInfo *> || std::is_enum_v<T> ||           
\
+   std::is_integral_v<T>)
+
+template <class T>
+typename std::enable_if_t<!USE_DEFAULT_PROFILE>
+profileAttrArg(llvm::FoldingSetNodeID &, const ASTContext &, T) {}
+
+template <class T>
+typename std::enable_if_t<USE_DEFAULT_PROFILE>
+profileAttrArg(llvm::FoldingSetNodeID &ID, const ASTContext &, T V) {
+  if constexpr (std::is_same_v<T, StringRef>)
+    ID.AddString(V);
+  else if constexpr (std::is_same_v<T, VersionTuple>) {
+    ID.AddInteger(V.getMajor());
+    ID.AddInteger(V.getMinor().value_or(0));
+    ID.AddInteger(V.getSubminor().value_or(0));
+    ID.AddInteger(V.getBuild().value_or(0));
+  } else if constexpr (std::is_same_v<T, IdentifierInfo *> ||
+                       std::is_same_v<T, const IdentifierInfo *>)
+    ID.AddPointer(V);
+  else
+    ID.AddInteger(static_cast<long long>(V));
+}
+
+template <>
+inline void profileAttrArg<ParamIdx>(llvm::FoldingSetNodeID &ID,
+                                     const ASTContext &, ParamIdx P) {
+  // Mirror equalAttrArgs<ParamIdx>: invalid ParamIdx must agree.
+  ID.AddBoolean(P.isValid());
+  if (P.isValid())
+    ID.AddInteger(P.getASTIndex());
+}
+
+template <class T>
+inline void profileAttrArg(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx,
+                           T *Begin, T *End) {
+  ID.AddInteger(End - Begin);
+  for (; Begin != End; ++Begin)
+    profileAttrArg(ID, Ctx, *Begin);
+}
+
+template <>
+inline void profileAttrArg<Attr *>(llvm::FoldingSetNodeID &ID,
+                                   const ASTContext &Ctx, Attr *A) {
+  if (!A) {
+    ID.AddPointer(nullptr);
+    return;
+  }
+  ID.AddInteger(A->getKind());
+  A->Profile(ID, Ctx);
+}
+
+template <>
+inline void profileAttrArg<Expr *>(llvm::FoldingSetNodeID &ID,
+                                   const ASTContext &Ctx, Expr *E) {
+  E->Profile(ID, Ctx, /*Canonical=*/true);
+}
+
+template <>
+inline void profileAttrArg<QualType>(llvm::FoldingSetNodeID &ID,
+                                     const ASTContext &, QualType T) {
+  ID.AddPointer(T.getCanonicalType().getAsOpaquePtr());
+}
+
+void profileAlignedAttr(const AlignedAttr &A, llvm::FoldingSetNodeID &ID,
+                        const ASTContext &Ctx) {
+  ID.AddInteger(A.getSpellingListIndex());
+  ID.AddBoolean(A.isAlignmentExpr());
+  if (A.isAlignmentExpr())
+    profileAttrArg(ID, Ctx, A.getAlignmentExpr());
+  else
+    profileAttrArg(ID, Ctx, A.getAlignmentType()->getType());
+}
+} // namespace
+
 #include "clang/AST/AttrImpl.inc"
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index c9d038ec308ef..55c3e5c3ead17 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -5339,14 +5339,14 @@ NullabilityKindOrNone 
AttributedType::stripOuterNullability(QualType &T) {
   return std::nullopt;
 }
 
-void AttributedType::Profile(llvm::FoldingSetNodeID &ID, Kind attrKind,
-                             QualType modified, QualType equivalent,
-                             const Attr *attr) {
+void AttributedType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx,
+                             Kind attrKind, QualType modified,
+                             QualType equivalent, const Attr *attr) {
   ID.AddInteger(attrKind);
   ID.AddPointer(modified.getAsOpaquePtr());
   ID.AddPointer(equivalent.getAsOpaquePtr());
-  if (const auto *A = dyn_cast_or_null<SwiftAttrAttr>(attr))
-    A->Profile(ID);
+  if (attr)
+    attr->Profile(ID, Ctx);
 }
 
 bool Type::isSignableIntegerType(const ASTContext &Ctx) const {
diff --git a/clang/test/AST/attributed-type-dedup-address-space.c 
b/clang/test/AST/attributed-type-dedup-address-space.c
new file mode 100644
index 0000000000000..8372a21c4eb5a
--- /dev/null
+++ b/clang/test/AST/attributed-type-dedup-address-space.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -emit-pch -o %t.pch %s
+// RUN: llvm-bcanalyzer --dump --disable-histogram %t.pch | FileCheck %s
+
+__attribute__((address_space(1))) int *a;
+__attribute__((address_space(1))) int *b;
+__attribute__((address_space(2))) int *c;
+
+// CHECK-COUNT-2: <TYPE_ATTRIBUTED
+// CHECK-NOT:     <TYPE_ATTRIBUTED
diff --git a/clang/test/AST/attributed-type-dedup-annotate-type-args.c 
b/clang/test/AST/attributed-type-dedup-annotate-type-args.c
new file mode 100644
index 0000000000000..060dbfc9bf37e
--- /dev/null
+++ b/clang/test/AST/attributed-type-dedup-annotate-type-args.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -emit-pch -o %t.pch %s
+// RUN: llvm-bcanalyzer --dump --disable-histogram %t.pch | FileCheck %s
+
+// annotate_type with VariadicExprArgument. The attribued types should
+// dedupe not only based on the string argument, but all of the variadic
+// arguments.
+
+int *[[clang::annotate_type("foo", 1)]] a;
+int *[[clang::annotate_type("foo", 1)]] b;
+int *[[clang::annotate_type("foo", 2)]] c;
+int *[[clang::annotate_type("foo")]] d;
+
+// CHECK-COUNT-3: <TYPE_ATTRIBUTED
+// CHECK-NOT:     <TYPE_ATTRIBUTED
diff --git a/clang/test/AST/attributed-type-dedup-annotate-type.m 
b/clang/test/AST/attributed-type-dedup-annotate-type.m
new file mode 100644
index 0000000000000..2c4bfff0aefbe
--- /dev/null
+++ b/clang/test/AST/attributed-type-dedup-annotate-type.m
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-pch -o %t.pch %s
+// RUN: llvm-bcanalyzer --dump --disable-histogram %t.pch | FileCheck %s
+
+// Only two unique string arguments are present. Correspondingly,
+// we should have two TYPE_ATTRIBUTED records.
+
+int *[[clang::annotate_type("foo")]] a;
+int *[[clang::annotate_type("foo")]] b;
+int *[[clang::annotate_type("bar")]] c;
+
+// CHECK-COUNT-2: <TYPE_ATTRIBUTED
+// CHECK-NOT:     <TYPE_ATTRIBUTED
diff --git a/clang/test/AST/attributed-type-dedup-objc-ownership.m 
b/clang/test/AST/attributed-type-dedup-objc-ownership.m
new file mode 100644
index 0000000000000..4d3d69373a1d5
--- /dev/null
+++ b/clang/test/AST/attributed-type-dedup-objc-ownership.m
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fobjc-arc -emit-pch -o %t.pch %s
+// RUN: llvm-bcanalyzer --dump --disable-histogram %t.pch | FileCheck %s
+
+@class NSString;
+
+__attribute__((objc_ownership(strong))) NSString *a;
+__attribute__((objc_ownership(strong))) NSString *b;
+__attribute__((objc_ownership(none)))   NSString *c;
+
+// CHECK-COUNT-2: <TYPE_ATTRIBUTED
+// CHECK-NOT:     <TYPE_ATTRIBUTED
diff --git a/clang/test/AST/attributed-type-dedup-pcs.c 
b/clang/test/AST/attributed-type-dedup-pcs.c
new file mode 100644
index 0000000000000..cfd7b7d9f4658
--- /dev/null
+++ b/clang/test/AST/attributed-type-dedup-pcs.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -triple arm-none-eabi -emit-pch -o %t.pch %s
+// RUN: llvm-bcanalyzer --dump --disable-histogram %t.pch | FileCheck %s
+
+// Pcs uses an EnumArgument and is encoded in the FunctionProtoType's
+// calling convention bits on ARM targets, so the equivalent type
+// discriminates aapcs vs aapcs-vfp. Two same-PCS uses must dedup; a
+// different-PCS use must be distinct. Requires an ARM triple — on x86 /
+// arm64-apple-darwin, pcs is silently ignored and no records are emitted.
+
+void __attribute__((pcs("aapcs")))     f1(void);
+void __attribute__((pcs("aapcs")))     f2(void);
+void __attribute__((pcs("aapcs-vfp"))) f3(void);
+
+// CHECK-COUNT-2: <TYPE_ATTRIBUTED
+// CHECK-NOT:     <TYPE_ATTRIBUTED
diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp 
b/clang/utils/TableGen/ClangAttrEmitter.cpp
index 7df99d3beb11a..1eaec5f07c75e 100644
--- a/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -287,6 +287,10 @@ namespace {
       std::string S = std::string("get") + std::string(getUpperName()) + "()";
       return getArgEqualityFn().str() + "(" + S + ", Other." + S + ", 
Context)";
     }
+
+    virtual std::string emitAttrArgProfileCall() const {
+      return "profileAttrArg(ID, Ctx, get" + getUpperName().str() + "())";
+    }
   };
 
   class SimpleArgument : public Argument {
@@ -867,6 +871,11 @@ namespace {
              GenIter(false, "end") + ", " + GenIter(true, "begin") + ", " +
              GenIter(true, "end") + ", Context)";
     }
+
+    std::string emitAttrArgProfileCall() const override {
+      std::string LN = getLowerName().str();
+      return "profileAttrArg(ID, Ctx, " + LN + "_begin(), " + LN + "_end())";
+    }
   };
 
   class VariadicOMPInteropInfoArgument : public VariadicArgument {
@@ -3266,6 +3275,22 @@ static void emitAttributes(const RecordKeeper &Records, 
raw_ostream &OS,
       OS << "}\n\n";
     }
 
+    std::string ProfileSig = "Profile(llvm::FoldingSetNodeID &ID, "
+                             "const ASTContext &Ctx) const";
+    if (Header) {
+      OS << "  void " << ProfileSig << ";\n";
+    } else {
+      OS << "void " << R.getName() << "Attr::" << ProfileSig << " {\n";
+      std::string CustomFn = R.getValueAsString("profileFn").str();
+      if (CustomFn.empty()) {
+        for (const auto &ai : Args)
+          OS << "  " << ai->emitAttrArgProfileCall() << ";\n";
+      } else {
+        OS << "  " << CustomFn << "(*this, ID, Ctx);\n";
+      }
+      OS << "}\n\n";
+    }
+
     if (Header) {
       if (DelayedArgs) {
         DelayedArgs->writeAccessors(OS);
@@ -3338,6 +3363,23 @@ static void emitEquivalenceFunction(const RecordKeeper 
&Records,
   OS << "}\n\n";
 }
 
+static void emitProfileFunction(const RecordKeeper &Records, raw_ostream &OS) {
+  OS << "void Attr::Profile(llvm::FoldingSetNodeID &ID, "
+        "const ASTContext &Ctx) const {\n";
+  OS << "  switch (getKind()) {\n";
+  for (const auto *Attr : Records.getAllDerivedDefinitions("Attr")) {
+    const Record &R = *Attr;
+    if (!R.getValueAsBit("ASTNode"))
+      continue;
+    OS << "  case attr::" << R.getName() << ":\n";
+    OS << "    return cast<" << R.getName()
+       << "Attr>(this)->Profile(ID, Ctx);\n";
+  }
+  OS << "  }\n";
+  OS << "  llvm_unreachable(\"Unexpected attribute kind!\");\n";
+  OS << "}\n\n";
+}
+
 // Emits the class method definitions for attributes.
 void clang::EmitClangAttrImpl(const RecordKeeper &Records, raw_ostream &OS) {
   emitSourceFileHeader("Attribute classes' member function definitions", OS,
@@ -3374,6 +3416,7 @@ void clang::EmitClangAttrImpl(const RecordKeeper 
&Records, raw_ostream &OS) {
   EmitFunc("printPretty(OS, Policy)");
 
   emitEquivalenceFunction(Records, OS);
+  emitProfileFunction(Records, OS);
 }
 
 static void emitAttrList(raw_ostream &OS, StringRef Class,

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to