Optimize serialized representation of redeclarable declarations for
which there are no redeclarations. This reduced by size of the PCH
file for Cocoa.h by ~650k: ~536k of that was in the new
LOCAL_REDECLARATIONS table, which went from a ridiculous 540k down to
an acceptable 3.5k, while the rest was due to the more compact
abbreviated representation of redeclarable declaration kinds (which no
longer need to store the 'first' declaration ID).


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@146869 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index d538d6e..3e08d99 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -1410,9 +1410,18 @@
 
 template <typename T>
 void ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
-  enum RedeclKind { FirstInFile, PointsToPrevious };
+  enum RedeclKind { OnlyDeclaration = 0, FirstInFile, PointsToPrevious };
   RedeclKind Kind = (RedeclKind)Record[Idx++];
   
+  // If this is the only known declaration of this entity, this module file
+  // has no additional redeclaration information. However, other module
+  // files might have redeclarations.
+  if (Kind == OnlyDeclaration) {
+    if (Reader.PendingDeclChainsKnown.insert(ThisDeclID))
+      Reader.PendingDeclChains.push_back(ThisDeclID);
+    return;
+  }
+  
   // Read the first declaration ID, and note that we need to reconstruct
   // the redeclaration chain once we hit the top level.
   DeclID FirstDeclID = ReadDeclID(Record, Idx);
@@ -1422,6 +1431,9 @@
   T *FirstDecl = cast_or_null<T>(Reader.GetDecl(FirstDeclID));
 
   switch (Kind) {
+  case OnlyDeclaration:
+    llvm_unreachable("only declaration handled above");
+      
   case FirstInFile:
     if (FirstDecl != D)
       D->RedeclLink = typename Redeclarable<T>::PreviousDeclLink(FirstDecl);
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 4e9a315..bb4359a 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -126,30 +126,6 @@
   };
 }
 
-static bool isFirstDeclInFile(Decl *D) {
-  // FIXME: There must be a better way to abstract Redeclarable<T> into a 
-  // more-general "redeclarable type".
-  if (TagDecl *Tag = dyn_cast<TagDecl>(D))
-    return !Tag->getPreviousDeclaration() ||
-           Tag->getPreviousDeclaration()->isFromASTFile();
-  if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
-    return !FD->getPreviousDeclaration() ||
-           FD->getPreviousDeclaration()->isFromASTFile();
-  if (VarDecl *VD = dyn_cast<VarDecl>(D))
-    return !VD->getPreviousDeclaration() ||
-           VD->getPreviousDeclaration()->isFromASTFile();
-  if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D))
-    return !TD->getPreviousDeclaration() ||
-           TD->getPreviousDeclaration()->isFromASTFile();
-  if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D))
-    return !ID->getPreviousDeclaration() ||
-            ID->getPreviousDeclaration()->isFromASTFile();
-  
-  RedeclarableTemplateDecl *RTD = cast<RedeclarableTemplateDecl>(D);
-  return !RTD->getPreviousDeclaration() ||
-          RTD->getPreviousDeclaration()->isFromASTFile();  
-}
-
 void ASTDeclWriter::Visit(Decl *D) {
   DeclVisitor<ASTDeclWriter>::Visit(D);
 
@@ -212,7 +188,7 @@
   if (!D->hasAttrs() &&
       !D->isImplicit() &&
       !D->isUsed(false) &&
-      isFirstDeclInFile(D) &&
+      D->RedeclLink.getPointer() == D &&
       !D->isInvalidDecl() &&
       !D->isReferenced() &&
       !D->isTopLevelDeclInObjCContainer() &&
@@ -262,7 +238,7 @@
       !D->isImplicit() &&
       !D->isUsed(false) &&
       !D->hasExtInfo() &&
-      isFirstDeclInFile(D) &&
+      D->RedeclLink.getPointer() == D &&
       !D->isInvalidDecl() &&
       !D->isReferenced() &&
       !D->isTopLevelDeclInObjCContainer() &&
@@ -286,7 +262,7 @@
       !D->isImplicit() &&
       !D->isUsed(false) &&
       !D->hasExtInfo() &&
-      isFirstDeclInFile(D) &&
+      D->RedeclLink.getPointer() == D &&
       !D->isInvalidDecl() &&
       !D->isReferenced() &&
       !D->isTopLevelDeclInObjCContainer() &&
@@ -732,7 +708,7 @@
       !D->isModulePrivate() &&
       D->getDeclName().getNameKind() == DeclarationName::Identifier &&
       !D->hasExtInfo() &&
-      isFirstDeclInFile(D) &&
+      D->RedeclLink.getPointer() == D &&
       !D->hasCXXDirectInitializer() &&
       D->getInit() == 0 &&
       !isa<ParmVarDecl>(D) &&
@@ -1298,7 +1274,13 @@
 
 template <typename T>
 void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) {
-  enum { FirstInFile, PointsToPrevious };
+  enum { OnlyDeclaration = 0, FirstInFile, PointsToPrevious };
+  if (D->RedeclLink.getPointer() == D) {
+    // This is the only declaration.
+    Record.push_back(OnlyDeclaration);
+    return;
+  }
+  
   T *First = D->getFirstDeclaration();
   if (!D->getPreviousDeclaration() ||
       D->getPreviousDeclaration()->isFromASTFile()) {
@@ -1399,8 +1381,7 @@
   Abv = new BitCodeAbbrev();
   Abv->Add(BitCodeAbbrevOp(serialization::DECL_ENUM));
   // Redeclarable
-  Abv->Add(BitCodeAbbrevOp(0));                       // First in file
-  Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // First ID
+  Abv->Add(BitCodeAbbrevOp(0));                       // No redeclaration
   // Decl
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
@@ -1447,8 +1428,7 @@
   Abv = new BitCodeAbbrev();
   Abv->Add(BitCodeAbbrevOp(serialization::DECL_RECORD));
   // Redeclarable
-  Abv->Add(BitCodeAbbrevOp(0));                       // First in file
-  Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // First ID
+  Abv->Add(BitCodeAbbrevOp(0));                       // No redeclaration
   // Decl
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
@@ -1489,8 +1469,7 @@
   Abv = new BitCodeAbbrev();
   Abv->Add(BitCodeAbbrevOp(serialization::DECL_PARM_VAR));
   // Redeclarable
-  Abv->Add(BitCodeAbbrevOp(0));                       // First in file
-  Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // First ID
+  Abv->Add(BitCodeAbbrevOp(0));                       // No redeclaration
   // Decl
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
@@ -1540,8 +1519,7 @@
   Abv = new BitCodeAbbrev();
   Abv->Add(BitCodeAbbrevOp(serialization::DECL_TYPEDEF));
   // Redeclarable
-  Abv->Add(BitCodeAbbrevOp(0));                       // First in file
-  Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // First ID
+  Abv->Add(BitCodeAbbrevOp(0));                       // No redeclaration
   // Decl
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
@@ -1569,8 +1547,7 @@
   Abv = new BitCodeAbbrev();
   Abv->Add(BitCodeAbbrevOp(serialization::DECL_VAR));
   // Redeclarable
-  Abv->Add(BitCodeAbbrevOp(0));                       // First in file
-  Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // First ID
+  Abv->Add(BitCodeAbbrevOp(0));                       // No redeclaration
   // Decl
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
diff --git a/test/Modules/Inputs/redecl-merge-bottom.h b/test/Modules/Inputs/redecl-merge-bottom.h
index e45e0de..198bde3 100644
--- a/test/Modules/Inputs/redecl-merge-bottom.h
+++ b/test/Modules/Inputs/redecl-merge-bottom.h
@@ -1,4 +1,7 @@
 __import_module__ redecl_merge_left;
 __import_module__ redecl_merge_right;
 
+@class B;
+
 @class A;
+
diff --git a/test/Modules/Inputs/redecl-merge-left.h b/test/Modules/Inputs/redecl-merge-left.h
index 0858922..048b3e6 100644
--- a/test/Modules/Inputs/redecl-merge-left.h
+++ b/test/Modules/Inputs/redecl-merge-left.h
@@ -4,4 +4,8 @@
 
 @class A;
 
+@interface B
+@end
+
 @class A;
+
diff --git a/test/Modules/Inputs/redecl-merge-right.h b/test/Modules/Inputs/redecl-merge-right.h
index 266146c..d8fd45f 100644
--- a/test/Modules/Inputs/redecl-merge-right.h
+++ b/test/Modules/Inputs/redecl-merge-right.h
@@ -7,3 +7,5 @@
 - (Super*)init;
 @end
 
+@class B;
+
diff --git a/test/Modules/Inputs/redecl-merge-top.h b/test/Modules/Inputs/redecl-merge-top.h
index 886436c..68dae50 100644
--- a/test/Modules/Inputs/redecl-merge-top.h
+++ b/test/Modules/Inputs/redecl-merge-top.h
@@ -3,3 +3,5 @@
 @class A;
 
 @class A;
+
+@class B;
diff --git a/test/Modules/redecl-merge.m b/test/Modules/redecl-merge.m
index d62d504..fe25044 100644
--- a/test/Modules/redecl-merge.m
+++ b/test/Modules/redecl-merge.m
@@ -14,8 +14,13 @@
 
 @class A;
 
+@class B;
+
 __import_module__ redecl_merge_bottom;
 
+@implementation B
+@end
+
 void g(A *a) {
   [a init];
 }