Modify emitTypeInformation to use MemoryTypeTableBuilder, take 2

This effectively revers commit r270389 and re-lands r270106, but it's
almost a rewrite.

The behavior change in r270106 was that we could no longer assume that
each LF_FUNC_ID record got its own type index. This patch adds a map
from DINode* to TypeIndex, so we can stop making that assumption.

This change also emits padding bytes between type records similar to the
way MSVC does. The size of the type record includes the padding bytes.

llvm-svn: 270485
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index 06ac583..0eb3e44 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -113,14 +113,34 @@
   if (SiteInsertion.second) {
     Site->SiteFuncId = NextFuncId++;
     Site->Inlinee = Inlinee;
-    auto InlineeInsertion =
-        SubprogramIndices.insert({Inlinee, InlinedSubprograms.size()});
-    if (InlineeInsertion.second)
-      InlinedSubprograms.push_back(Inlinee);
+    InlinedSubprograms.insert(Inlinee);
+    recordFuncIdForSubprogram(Inlinee);
   }
   return *Site;
 }
 
+TypeIndex CodeViewDebug::getGenericFunctionTypeIndex() {
+  if (VoidFnTyIdx.getIndex() != 0)
+    return VoidFnTyIdx;
+
+  ArrayRef<TypeIndex> NoArgs;
+  ArgListRecord ArgListRec(TypeRecordKind::ArgList, NoArgs);
+  TypeIndex ArgListIndex = TypeTable.writeArgList(ArgListRec);
+
+  ProcedureRecord Procedure(TypeIndex::Void(), CallingConvention::NearC,
+                            FunctionOptions::None, 0, ArgListIndex);
+  VoidFnTyIdx = TypeTable.writeProcedure(Procedure);
+  return VoidFnTyIdx;
+}
+
+void CodeViewDebug::recordFuncIdForSubprogram(const DISubprogram *SP) {
+  TypeIndex ParentScope = TypeIndex(0);
+  StringRef DisplayName = SP->getDisplayName();
+  FuncIdRecord FuncId(ParentScope, getGenericFunctionTypeIndex(), DisplayName);
+  TypeIndex TI = TypeTable.writeFuncId(FuncId);
+  TypeIndices[SP] = TI;
+}
+
 void CodeViewDebug::recordLocalVariable(LocalVariable &&Var,
                                         const DILocation *InlinedAt) {
   if (InlinedAt) {
@@ -244,72 +264,38 @@
 }
 
 void CodeViewDebug::emitTypeInformation() {
-  // Do nothing if we have no debug info or no inlined subprograms.  The types
-  // we currently emit exist only to support inlined call site info.
+  // Do nothing if we have no debug info or if no non-trivial types were emitted
+  // to TypeTable during codegen.
   NamedMDNode *CU_Nodes =
       MMI->getModule()->getNamedMetadata("llvm.dbg.cu");
   if (!CU_Nodes)
     return;
-  if (InlinedSubprograms.empty())
+  if (TypeTable.empty())
     return;
 
   // Start the .debug$T section with 0x4.
   OS.SwitchSection(Asm->getObjFileLowering().getCOFFDebugTypesSection());
   OS.AddComment("Debug section magic");
+  OS.EmitValueToAlignment(4);
   OS.EmitIntValue(COFF::DEBUG_SECTION_MAGIC, 4);
 
-  // This type info currently only holds function ids for use with inline call
-  // frame info. All functions are assigned a simple 'void ()' type. Emit that
-  // type here.
-  unsigned ArgListIndex = getNextTypeIndex();
-  OS.AddComment("Type record length");
-  OS.EmitIntValue(ArgListRecord::getLayoutSize(), 2);
-  OS.AddComment("Leaf type: LF_ARGLIST");
-  OS.EmitIntValue(LF_ARGLIST, 2);
-  OS.AddComment("Number of arguments");
-  OS.EmitIntValue(0, 4);
-
-  unsigned VoidFnTyIdx = getNextTypeIndex();
-  OS.AddComment("Type record length");
-  OS.EmitIntValue(ProcedureRecord::getLayoutSize(), 2);
-  OS.AddComment("Leaf type: LF_PROCEDURE");
-  OS.EmitIntValue(LF_PROCEDURE, 2);
-  OS.AddComment("Return type index");
-  OS.EmitIntValue(TypeIndex::Void().getIndex(), 4);
-  OS.AddComment("Calling convention");
-  OS.EmitIntValue(char(CallingConvention::NearC), 1);
-  OS.AddComment("Function options");
-  OS.EmitIntValue(char(FunctionOptions::None), 1);
-  OS.AddComment("# of parameters");
-  OS.EmitIntValue(0, 2);
-  OS.AddComment("Argument list type index");
-  OS.EmitIntValue(ArgListIndex, 4);
-
-  // Emit LF_FUNC_ID records for all inlined subprograms to the type stream.
-  // Allocate one type index for each func id.
-  unsigned NextIdx = getNextTypeIndex(InlinedSubprograms.size());
-  (void)NextIdx;
-  assert(NextIdx == FuncIdTypeIndexStart && "func id type indices broken");
-  for (auto *SP : InlinedSubprograms) {
-    StringRef DisplayName = SP->getDisplayName();
-    OS.AddComment("Type record length");
-    MCSymbol *FuncBegin = MMI->getContext().createTempSymbol(),
-             *FuncEnd = MMI->getContext().createTempSymbol();
-    OS.emitAbsoluteSymbolDiff(FuncEnd, FuncBegin, 2);
-    OS.EmitLabel(FuncBegin);
-    OS.AddComment("Leaf type: LF_FUNC_ID");
-    OS.EmitIntValue(LF_FUNC_ID, 2);
-
-    OS.AddComment("Scope type index");
-    OS.EmitIntValue(0, 4);
-    OS.AddComment("Function type");
-    OS.EmitIntValue(VoidFnTyIdx, 4);
-    {
-      OS.AddComment("Function name");
-      emitNullTerminatedSymbolName(OS, DisplayName);
-    }
-    OS.EmitLabel(FuncEnd);
-  }
+  TypeTable.ForEachRecord(
+      [&](TypeIndex Index, const MemoryTypeTableBuilder::Record *R) {
+        // Each record should be 4 byte aligned. We achieve that by emitting
+        // LF_PAD padding bytes. The on-disk record size includes the padding
+        // bytes so that consumers don't have to skip past them.
+        uint64_t RecordSize = R->size() + 2;
+        uint64_t AlignedSize = alignTo(RecordSize, 4);
+        uint64_t AlignedRecordSize = AlignedSize - 2;
+        assert(AlignedRecordSize < (1 << 16) && "type record size overflow");
+        OS.AddComment("Type record length");
+        OS.EmitIntValue(AlignedRecordSize, 2);
+        OS.AddComment("Type record data");
+        OS.EmitBytes(StringRef(R->data(), R->size()));
+        // Pad the record with LF_PAD bytes.
+        for (unsigned I = AlignedSize - RecordSize; I > 0; --I)
+          OS.EmitIntValue(LF_PAD0 + I, 1);
+      });
 }
 
 void CodeViewDebug::emitInlineeFuncIdsAndLines() {
@@ -330,8 +316,10 @@
   OS.AddComment("Inlinee lines signature");
   OS.EmitIntValue(unsigned(InlineeLinesSignature::Normal), 4);
 
-  unsigned InlineeIndex = FuncIdTypeIndexStart;
   for (const DISubprogram *SP : InlinedSubprograms) {
+    assert(TypeIndices.count(SP));
+    TypeIndex InlineeIdx = TypeIndices[SP];
+
     OS.AddBlankLine();
     unsigned FileId = maybeRecordFile(SP->getFile());
     OS.AddComment("Inlined function " + SP->getDisplayName() + " starts at " +
@@ -341,14 +329,11 @@
     // 1.
     unsigned FileOffset = (FileId - 1) * 8;
     OS.AddComment("Type index of inlined function");
-    OS.EmitIntValue(InlineeIndex, 4);
+    OS.EmitIntValue(InlineeIdx.getIndex(), 4);
     OS.AddComment("Offset into filechecksum table");
     OS.EmitIntValue(FileOffset, 4);
     OS.AddComment("Starting line number");
     OS.EmitIntValue(SP->getLine(), 4);
-
-    // The next inlined subprogram has the next function id.
-    InlineeIndex++;
   }
 
   OS.EmitLabel(InlineEnd);
@@ -371,8 +356,8 @@
   MCSymbol *InlineBegin = MMI->getContext().createTempSymbol(),
            *InlineEnd = MMI->getContext().createTempSymbol();
 
-  assert(SubprogramIndices.count(Site.Inlinee));
-  unsigned InlineeIdx = FuncIdTypeIndexStart + SubprogramIndices[Site.Inlinee];
+  assert(TypeIndices.count(Site.Inlinee));
+  TypeIndex InlineeIdx = TypeIndices[Site.Inlinee];
 
   // SymbolRecord
   OS.AddComment("Record length");
@@ -386,7 +371,7 @@
   OS.AddComment("PtrEnd");
   OS.EmitIntValue(0, 4);
   OS.AddComment("Inlinee type index");
-  OS.EmitIntValue(InlineeIdx, 4);
+  OS.EmitIntValue(InlineeIdx.getIndex(), 4);
 
   unsigned FileId = maybeRecordFile(Site.Inlinee->getFile());
   unsigned StartLineNum = Site.Inlinee->getLine();
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h
index 3cc1172..53e1aa0 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h
@@ -20,6 +20,7 @@
 #include "llvm/CodeGen/AsmPrinter.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
 #include "llvm/IR/DebugInfo.h"
 #include "llvm/IR/DebugLoc.h"
@@ -34,6 +35,7 @@
 /// \brief Collects and handles line tables information in a CodeView format.
 class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
   MCStreamer &OS;
+  codeview::MemoryTypeTableBuilder TypeTable;
 
   /// Represents the most general definition range.
   struct LocalVarDefRange {
@@ -103,20 +105,16 @@
   /// to be confused with type indices for LF_FUNC_ID records.
   unsigned NextFuncId = 0;
 
-  /// The next available type index.
-  unsigned NextTypeIndex = llvm::codeview::TypeIndex::FirstNonSimpleIndex;
+  codeview::TypeIndex VoidFnTyIdx;
 
-  /// Get the next type index and reserve it. Can be used to reserve more than
-  /// one type index.
-  unsigned getNextTypeIndex(unsigned NumRecords = 1) {
-    unsigned Result = NextTypeIndex;
-    NextTypeIndex += NumRecords;
-    return Result;
-  }
+  /// Get a type index for a generic void function type.
+  codeview::TypeIndex getGenericFunctionTypeIndex();
 
   InlineSite &getInlineSite(const DILocation *InlinedAt,
                             const DISubprogram *Inlinee);
 
+  void recordFuncIdForSubprogram(const DISubprogram *SP);
+
   static void collectInlineSiteChildren(SmallVectorImpl<unsigned> &Children,
                                         const FunctionInfo &FI,
                                         const InlineSite &Site);
@@ -128,18 +126,12 @@
   /// Map from DIFile to .cv_file id.
   DenseMap<const DIFile *, unsigned> FileIdMap;
 
-  /// Map from subprogram to index in InlinedSubprograms.
-  DenseMap<const DISubprogram *, size_t> SubprogramIndices;
-
   /// All inlined subprograms in the order they should be emitted.
-  SmallVector<const DISubprogram *, 4> InlinedSubprograms;
+  SmallSetVector<const DISubprogram *, 4> InlinedSubprograms;
 
-  /// The first type index that refers to an LF_FUNC_ID record. We have one
-  /// record per inlined subprogram.
-  /// FIXME: Keep in sync with emitTypeInformation until we buffer type records
-  /// on the side as we go. Once we buffer type records, we can allocate type
-  /// indices on demand without interleaving our assembly output.
-  unsigned FuncIdTypeIndexStart = NextTypeIndex + 2;
+  /// Map from DI metadata nodes to CodeView type indices. Primarily indexed by
+  /// DIType* and DISubprogram*.
+  DenseMap<const DINode *, codeview::TypeIndex> TypeIndices;
 
   typedef std::map<const DIFile *, std::string> FileToFilepathMapTy;
   FileToFilepathMapTy FileToFilepathMap;