[llvm-pdbdump] Re-write the record layout code to be more resilient.

This reworks the way virtual bases are handled, and also the way
padding is detected across multiple levels of aggregates, producing
a much more accurate result.

llvm-svn: 301203
diff --git a/llvm/tools/llvm-pdbdump/LinePrinter.cpp b/llvm/tools/llvm-pdbdump/LinePrinter.cpp
index d4a5a8d..7fa5244 100644
--- a/llvm/tools/llvm-pdbdump/LinePrinter.cpp
+++ b/llvm/tools/llvm-pdbdump/LinePrinter.cpp
@@ -72,7 +72,7 @@
 }
 
 bool LinePrinter::IsClassExcluded(const ClassLayout &Class) {
-  if (IsTypeExcluded(Class.getUDTName(), Class.getClassSize()))
+  if (IsTypeExcluded(Class.getName(), Class.getSize()))
     return true;
   if (Class.deepPaddingSize() < opts::pretty::PaddingThreshold)
     return true;
diff --git a/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp b/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp
index 9f213a4..81ef261 100644
--- a/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp
+++ b/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp
@@ -58,25 +58,11 @@
   prettyPrintClassOutro(Layout);
 }
 
-static void printBase(LinePrinter &Printer, const PDBSymbolTypeBaseClass &Base,
-                      uint32_t &CurIndex, uint32_t TotalBaseCount,
-                      bool IsVirtual) {
-  Printer << " ";
-  WithColor(Printer, PDB_ColorItem::Keyword).get() << Base.getAccess();
-  if (IsVirtual)
-    WithColor(Printer, PDB_ColorItem::Keyword).get() << " virtual";
-  WithColor(Printer, PDB_ColorItem::Type).get() << " " << Base.getName();
-  if (++CurIndex < TotalBaseCount) {
-    Printer.NewLine();
-    Printer << ",";
-  }
-}
-
 void ClassDefinitionDumper::prettyPrintClassIntro(const ClassLayout &Layout) {
   DumpedAnything = false;
   Printer.NewLine();
 
-  uint32_t Size = Layout.getClassSize();
+  uint32_t Size = Layout.getSize();
   const PDBSymbolTypeUDT &Class = Layout.getClass();
 
   WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " ";
@@ -84,19 +70,22 @@
   WithColor(Printer, PDB_ColorItem::Comment).get() << " [sizeof = " << Size
                                                    << "]";
   uint32_t BaseCount = Layout.bases().size();
-  uint32_t VBaseCount = Layout.vbases().size();
-  uint32_t TotalBaseCount = BaseCount + VBaseCount;
-  if (TotalBaseCount > 0) {
+  if (BaseCount > 0) {
     Printer.Indent();
-    Printer.NewLine();
-    Printer << ":";
-    uint32_t BaseIndex = 0;
+    char NextSeparator = ':';
     for (auto BC : Layout.bases()) {
       const auto &Base = BC->getBase();
-      printBase(Printer, Base, BaseIndex, TotalBaseCount, false);
-    }
-    for (auto &BC : Layout.vbases()) {
-      printBase(Printer, *BC, BaseIndex, TotalBaseCount, true);
+      if (Base.isIndirectVirtualBaseClass())
+        continue;
+
+      Printer.NewLine();
+      Printer << NextSeparator << " ";
+      WithColor(Printer, PDB_ColorItem::Keyword).get() << Base.getAccess();
+      if (BC->isVirtualBase())
+        WithColor(Printer, PDB_ColorItem::Keyword).get() << " virtual";
+
+      WithColor(Printer, PDB_ColorItem::Type).get() << " " << Base.getName();
+      NextSeparator = ',';
     }
 
     Printer.Unindent();
@@ -114,7 +103,7 @@
   Printer.NewLine();
   if (Layout.deepPaddingSize() > 0) {
     APFloat Pct(100.0 * (double)Layout.deepPaddingSize() /
-                (double)Layout.getClassSize());
+                (double)Layout.getSize());
     SmallString<8> PctStr;
     Pct.toString(PctStr, 4);
     WithColor(Printer, PDB_ColorItem::Padding).get()
diff --git a/llvm/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.cpp b/llvm/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.cpp
index d146ca9..f0385f1 100644
--- a/llvm/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.cpp
+++ b/llvm/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.cpp
@@ -53,15 +53,28 @@
       }
     }
 
-    CurrentItem = Item.get();
-    Item->getSymbol().dump(*this);
+    CurrentItem = Item;
+    if (Item->isVBPtr()) {
+      VTableLayoutItem &Layout = static_cast<VTableLayoutItem &>(*CurrentItem);
+
+      VariableDumper VarDumper(Printer);
+      VarDumper.startVbptr(CurrentAbsoluteOffset, Layout.getSize());
+    } else {
+      if (auto Sym = Item->getSymbol())
+        Sym->dump(*this);
+    }
+
+    if (Item->getLayoutSize() > 0) {
+      uint32_t Prev = RelativeOffset + Item->getLayoutSize() - 1;
+      NextPaddingByte = UseMap.find_next_unset(Prev);
+    }
   }
 
-  if (NextPaddingByte >= 0 && Layout.getClassSize() > 1) {
-    uint32_t Amount = Layout.getClassSize() - NextPaddingByte;
+  auto TailPadding = Layout.tailPadding();
+  if (TailPadding > 0) {
     Printer.NewLine();
-    WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> (" << Amount
-                                                     << " bytes)";
+    WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> ("
+      << TailPadding << " bytes)";
     DumpedAnything = true;
   }
 
@@ -85,12 +98,19 @@
   Printer.NewLine();
   BaseClassLayout &Layout = static_cast<BaseClassLayout &>(*CurrentItem);
 
-  std::string Label = Layout.isVirtualBase() ? "vbase" : "base";
+  std::string Label = "base";
+  if (Layout.isVirtualBase()) {
+    Label.insert(Label.begin(), 'v');
+    if (Layout.getBase().isIndirectVirtualBaseClass())
+      Label.insert(Label.begin(), 'i');
+  }
   Printer << Label << " ";
 
+  uint32_t Size = Layout.isEmptyBase() ? 1 : Layout.getLayoutSize();
+
   WithColor(Printer, PDB_ColorItem::Offset).get()
-      << "+" << format_hex(CurrentAbsoluteOffset, 4)
-      << " [sizeof=" << Layout.getSize() << "] ";
+      << "+" << format_hex(CurrentAbsoluteOffset, 4) << " [sizeof=" << Size
+      << "] ";
 
   WithColor(Printer, PDB_ColorItem::Identifier).get() << Layout.getName();
 
@@ -125,27 +145,8 @@
 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeVTable &Symbol) {
   assert(CurrentItem != nullptr);
 
-  VTableLayoutItem &Layout = static_cast<VTableLayoutItem &>(*CurrentItem);
-
   VariableDumper VarDumper(Printer);
   VarDumper.start(Symbol, ClassOffsetZero);
 
-  Printer.Indent();
-  uint32_t Index = 0;
-  for (auto &Func : Layout.funcs()) {
-    Printer.NewLine();
-    std::string Name = Func->getName();
-    auto ParentClass =
-        unique_dyn_cast<PDBSymbolTypeUDT>(Func->getClassParent());
-    assert(ParentClass);
-    WithColor(Printer, PDB_ColorItem::Address).get() << " [" << Index << "] ";
-    WithColor(Printer, PDB_ColorItem::Identifier).get()
-        << "&" << ParentClass->getName();
-    Printer << "::";
-    WithColor(Printer, PDB_ColorItem::Identifier).get() << Name;
-    ++Index;
-  }
-  Printer.Unindent();
-
   DumpedAnything = true;
 }
diff --git a/llvm/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.h b/llvm/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.h
index 7dfb74c..61b62b1 100644
--- a/llvm/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.h
+++ b/llvm/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.h
@@ -19,7 +19,7 @@
 namespace pdb {
 
 class UDTLayoutBase;
-class StorageItemBase;
+class LayoutItemBase;
 class LinePrinter;
 
 class PrettyClassLayoutGraphicalDumper : public PDBSymDumper {
@@ -37,7 +37,7 @@
 
   LinePrinter &Printer;
 
-  StorageItemBase *CurrentItem = nullptr;
+  LayoutItemBase *CurrentItem = nullptr;
   uint32_t ClassOffsetZero = 0;
   uint32_t CurrentAbsoluteOffset = 0;
   bool DumpedAnything = false;
diff --git a/llvm/tools/llvm-pdbdump/PrettyClassLayoutTextDumper.cpp b/llvm/tools/llvm-pdbdump/PrettyClassLayoutTextDumper.cpp
index 02f3110..ccfd38c 100644
--- a/llvm/tools/llvm-pdbdump/PrettyClassLayoutTextDumper.cpp
+++ b/llvm/tools/llvm-pdbdump/PrettyClassLayoutTextDumper.cpp
@@ -59,14 +59,17 @@
         NextUnusedByte = UseMap.find_next_unset(Off);
       }
     }
-    LayoutItem->getSymbol().dump(*this);
+    if (auto Sym = LayoutItem->getSymbol())
+      Sym->dump(*this);
   }
 
-  if (NextUnusedByte >= 0 && Layout.getClassSize() > 1) {
-    uint32_t Amount = Layout.getClassSize() - NextUnusedByte;
-    Printer.NewLine();
-    WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> (" << Amount
-                                                     << " bytes)";
+  if (NextUnusedByte >= 0 && Layout.getSize() > 1) {
+    uint32_t Amount = Layout.getSize() - NextUnusedByte;
+    if (Amount > 0) {
+      Printer.NewLine();
+      WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> ("
+                                                       << Amount << " bytes)";
+    }
     DumpedAnything = true;
   }
 
@@ -116,4 +119,6 @@
   Dumper.start(Symbol);
 }
 
+void PrettyClassLayoutTextDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {}
+
 void PrettyClassLayoutTextDumper::dump(const PDBSymbolTypeUDT &Symbol) {}
diff --git a/llvm/tools/llvm-pdbdump/PrettyClassLayoutTextDumper.h b/llvm/tools/llvm-pdbdump/PrettyClassLayoutTextDumper.h
index 56c20f0..1adbbff 100644
--- a/llvm/tools/llvm-pdbdump/PrettyClassLayoutTextDumper.h
+++ b/llvm/tools/llvm-pdbdump/PrettyClassLayoutTextDumper.h
@@ -34,6 +34,7 @@
   void dump(const PDBSymbolTypeTypedef &Symbol) override;
   void dump(const PDBSymbolTypeUDT &Symbol) override;
   void dump(const PDBSymbolTypeVTable &Symbol) override;
+  void dump(const PDBSymbolTypeBuiltin &Symbol) override;
 
 private:
   bool DumpedAnything = false;
diff --git a/llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp b/llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp
index ffeef72..324a26f 100644
--- a/llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp
+++ b/llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp
@@ -34,17 +34,23 @@
 typedef bool (*CompareFunc)(const LayoutPtr &S1, const LayoutPtr &S2);
 
 static bool CompareNames(const LayoutPtr &S1, const LayoutPtr &S2) {
-  return S1->getUDTName() < S2->getUDTName();
+  return S1->getName() < S2->getName();
 }
 
 static bool CompareSizes(const LayoutPtr &S1, const LayoutPtr &S2) {
-  return S1->getClassSize() < S2->getClassSize();
+  return S1->getSize() < S2->getSize();
 }
 
 static bool ComparePadding(const LayoutPtr &S1, const LayoutPtr &S2) {
   return S1->deepPaddingSize() < S2->deepPaddingSize();
 }
 
+static bool ComparePaddingPct(const LayoutPtr &S1, const LayoutPtr &S2) {
+  double Pct1 = (double)S1->deepPaddingSize() / (double)S1->getSize();
+  double Pct2 = (double)S2->deepPaddingSize() / (double)S2->getSize();
+  return Pct1 < Pct2;
+}
+
 static CompareFunc getComparisonFunc(opts::pretty::ClassSortMode Mode) {
   switch (Mode) {
   case opts::pretty::ClassSortMode::Name:
@@ -53,6 +59,8 @@
     return CompareSizes;
   case opts::pretty::ClassSortMode::Padding:
     return ComparePadding;
+  case opts::pretty::ClassSortMode::PaddingPct:
+    return ComparePaddingPct;
   default:
     return nullptr;
   }
@@ -67,14 +75,18 @@
   Filtered.reserve(UnfilteredCount);
   CompareFunc Comp = getComparisonFunc(opts::pretty::ClassOrder);
 
+  if (UnfilteredCount > 10000) {
+    errs() << formatv("Filtering and sorting {0} types", UnfilteredCount);
+    errs().flush();
+  }
   uint32_t Examined = 0;
   uint32_t Discarded = 0;
   while (auto Class = E.getNext()) {
     ++Examined;
     if (Examined % 10000 == 0) {
-      outs() << formatv("Examined {0}/{1} items.  {2} items discarded\n",
+      errs() << formatv("Examined {0}/{1} items.  {2} items discarded\n",
                         Examined, UnfilteredCount, Discarded);
-      outs().flush();
+      errs().flush();
     }
 
     if (Class->getUnmodifiedTypeId() != 0) {
@@ -163,6 +175,9 @@
         dumpClassLayout(*Class);
     } else {
       while (auto Class = Classes->getNext()) {
+        if (Class->getUnmodifiedTypeId() != 0)
+          continue;
+
         if (Printer.IsTypeExcluded(Class->getName(), Class->getLength()))
           continue;
 
@@ -209,7 +224,7 @@
   if (opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::None) {
     Printer.NewLine();
     WithColor(Printer, PDB_ColorItem::Keyword).get() << "class ";
-    WithColor(Printer, PDB_ColorItem::Identifier).get() << Class.getUDTName();
+    WithColor(Printer, PDB_ColorItem::Identifier).get() << Class.getName();
   } else {
     ClassDefinitionDumper Dumper(Printer);
     Dumper.start(Class);
diff --git a/llvm/tools/llvm-pdbdump/PrettyVariableDumper.cpp b/llvm/tools/llvm-pdbdump/PrettyVariableDumper.cpp
index 76a0d23..70925f4 100644
--- a/llvm/tools/llvm-pdbdump/PrettyVariableDumper.cpp
+++ b/llvm/tools/llvm-pdbdump/PrettyVariableDumper.cpp
@@ -91,6 +91,14 @@
   }
 }
 
+void VariableDumper::startVbptr(uint32_t Offset, uint32_t Size) {
+  Printer.NewLine();
+  Printer << "vbptr ";
+
+  WithColor(Printer, PDB_ColorItem::Offset).get()
+      << "+" << format_hex(Offset, 4) << " [sizeof=" << Size << "] ";
+}
+
 void VariableDumper::start(const PDBSymbolTypeVTable &Var, uint32_t Offset) {
   Printer.NewLine();
   Printer << "vfptr ";
diff --git a/llvm/tools/llvm-pdbdump/PrettyVariableDumper.h b/llvm/tools/llvm-pdbdump/PrettyVariableDumper.h
index 4ba3bc9..cacf1ce 100644
--- a/llvm/tools/llvm-pdbdump/PrettyVariableDumper.h
+++ b/llvm/tools/llvm-pdbdump/PrettyVariableDumper.h
@@ -26,6 +26,7 @@
 
   void start(const PDBSymbolData &Var, uint32_t Offset = 0);
   void start(const PDBSymbolTypeVTable &Var, uint32_t Offset = 0);
+  void startVbptr(uint32_t Offset, uint32_t Size);
 
   void dump(const PDBSymbolTypeArray &Symbol) override;
   void dump(const PDBSymbolTypeBuiltin &Symbol) override;
diff --git a/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp b/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp
index 06c2afc..d51f640 100644
--- a/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp
+++ b/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp
@@ -124,12 +124,15 @@
                        cl::cat(TypeCategory), cl::sub(PrettySubcommand));
 cl::opt<ClassSortMode> ClassOrder(
     "class-order", cl::desc("Class sort order"), cl::init(ClassSortMode::None),
-    cl::values(clEnumValN(ClassSortMode::None, "none",
-                          "Undefined / no particular sort order"),
-               clEnumValN(ClassSortMode::Name, "name", "Sort classes by name"),
-               clEnumValN(ClassSortMode::Size, "size", "Sort classes by size"),
-               clEnumValN(ClassSortMode::Padding, "padding",
-                          "Sort classes by amount of padding")),
+    cl::values(
+        clEnumValN(ClassSortMode::None, "none",
+                   "Undefined / no particular sort order"),
+        clEnumValN(ClassSortMode::Name, "name", "Sort classes by name"),
+        clEnumValN(ClassSortMode::Size, "size", "Sort classes by size"),
+        clEnumValN(ClassSortMode::Padding, "padding",
+                   "Sort classes by amount of padding"),
+        clEnumValN(ClassSortMode::PaddingPct, "padding-pct",
+                   "Sort classes by percentage of space consumed by padding")),
     cl::cat(TypeCategory), cl::sub(PrettySubcommand));
 
 cl::opt<ClassDefinitionFormat> ClassFormat(
diff --git a/llvm/tools/llvm-pdbdump/llvm-pdbdump.h b/llvm/tools/llvm-pdbdump/llvm-pdbdump.h
index a5429a2..f77124d 100644
--- a/llvm/tools/llvm-pdbdump/llvm-pdbdump.h
+++ b/llvm/tools/llvm-pdbdump/llvm-pdbdump.h
@@ -19,7 +19,7 @@
 namespace pretty {
 
 enum class ClassDefinitionFormat { None, Layout, Graphical, Standard };
-enum class ClassSortMode { None, Name, Size, Padding };
+enum class ClassSortMode { None, Name, Size, Padding, PaddingPct };
 
 extern llvm::cl::opt<bool> Compilands;
 extern llvm::cl::opt<bool> Symbols;