Revert "[CodeView] Use assembler directives for line tables"

This reverts commit r259117.

The LineInfo constructor is defined in the codeview library and we have
to link against it now. Doing that isn't trivial, so reverting for now.

llvm-svn: 259126
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index b503f1d..f171636 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -13,7 +13,6 @@
 
 #include "CodeViewDebug.h"
 #include "llvm/DebugInfo/CodeView/CodeView.h"
-#include "llvm/DebugInfo/CodeView/Line.h"
 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
 #include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCSymbol.h"
@@ -75,18 +74,6 @@
   return Filepath;
 }
 
-unsigned CodeViewDebug::maybeRecordFile(const DIFile *F) {
-  unsigned NextId = FileIdMap.size() + 1;
-  auto Insertion = FileIdMap.insert(std::make_pair(F, NextId));
-  if (Insertion.second) {
-    // We have to compute the full filepath and emit a .cv_file directive.
-    StringRef FullPath = getFullFilepath(F);
-    NextId = Asm->OutStreamer->EmitCVFileDirective(NextId, FullPath);
-    assert(NextId == FileIdMap.size() && ".cv_file directive failed");
-  }
-  return Insertion.first->second;
-}
-
 void CodeViewDebug::maybeRecordLocation(DebugLoc DL,
                                         const MachineFunction *MF) {
   // Skip this instruction if it has the same location as the previous one.
@@ -98,26 +85,15 @@
     return;
 
   // Skip this line if it is longer than the maximum we can record.
-  LineInfo LI(DL.getLine(), DL.getLine(), /*IsStatement=*/true);
-  if (LI.getStartLine() != DL.getLine() || LI.isAlwaysStepInto() ||
-      LI.isNeverStepInto())
+  if (DL.getLine() > COFF::CVL_MaxLineNumber)
     return;
 
-  ColumnInfo CI(DL.getCol(), /*EndColumn=*/0);
-  if (CI.getStartColumn() != DL.getCol())
-    return;
-
-  if (!CurFn->HaveLineInfo)
-    CurFn->HaveLineInfo = true;
-  unsigned FileId = 0;
-  if (CurFn->LastLoc.get() && CurFn->LastLoc->getFile() == DL->getFile())
-    FileId = CurFn->LastFileId;
-  else
-    FileId = CurFn->LastFileId = maybeRecordFile(DL->getFile());
   CurFn->LastLoc = DL;
-  Asm->OutStreamer->EmitCVLocDirective(CurFn->FuncId, FileId, DL.getLine(),
-                                       DL.getCol(), /*PrologueEnd=*/false,
-                                       /*IsStmt=*/false, DL->getFilename());
+
+  MCSymbol *MCL = Asm->MMI->getContext().createTempSymbol();
+  Asm->OutStreamer->EmitLabel(MCL);
+  CurFn->Instrs.push_back(MCL);
+  LabelsAndLocs[MCL] = DL;
 }
 
 CodeViewDebug::CodeViewDebug(AsmPrinter *AP)
@@ -152,17 +128,39 @@
   // of the payload followed by the payload itself.  The subsections are 4-byte
   // aligned.
 
-  // Emit per-function debug information.
-  for (auto &P : FnDebugInfo)
-    emitDebugInfoForFunction(P.first, P.second);
+  // Emit per-function debug information.  This code is extracted into a
+  // separate function for readability.
+  for (size_t I = 0, E = VisitedFunctions.size(); I != E; ++I)
+    emitDebugInfoForFunction(VisitedFunctions[I]);
 
   // This subsection holds a file index to offset in string table table.
   Asm->OutStreamer->AddComment("File index to string table offset subsection");
-  Asm->OutStreamer->EmitCVFileChecksumsDirective();
+  Asm->EmitInt32(unsigned(ModuleSubstreamKind::FileChecksums));
+  size_t NumFilenames = FileNameRegistry.Infos.size();
+  Asm->EmitInt32(8 * NumFilenames);
+  for (size_t I = 0, E = FileNameRegistry.Filenames.size(); I != E; ++I) {
+    StringRef Filename = FileNameRegistry.Filenames[I];
+    // For each unique filename, just write its offset in the string table.
+    Asm->EmitInt32(FileNameRegistry.Infos[Filename].StartOffset);
+    // The function name offset is not followed by any additional data.
+    Asm->EmitInt32(0);
+  }
 
   // This subsection holds the string table.
   Asm->OutStreamer->AddComment("String table");
-  Asm->OutStreamer->EmitCVStringTableDirective();
+  Asm->EmitInt32(unsigned(ModuleSubstreamKind::StringTable));
+  Asm->EmitInt32(FileNameRegistry.LastOffset);
+  // The payload starts with a null character.
+  Asm->EmitInt8(0);
+
+  for (size_t I = 0, E = FileNameRegistry.Filenames.size(); I != E; ++I) {
+    // Just emit unique filenames one by one, separated by a null character.
+    Asm->OutStreamer->EmitBytes(FileNameRegistry.Filenames[I]);
+    Asm->EmitInt8(0);
+  }
+
+  // No more subsections. Fill with zeros to align the end of the section by 4.
+  Asm->OutStreamer->EmitFill((-FileNameRegistry.LastOffset) % 4, 0);
 
   clear();
 }
@@ -179,13 +177,21 @@
   Streamer.EmitValue(AddrDelta, Size);
 }
 
-void CodeViewDebug::emitDebugInfoForFunction(const Function *GV,
-                                             FunctionInfo &FI) {
+static const DIFile *getFileFromLoc(DebugLoc DL) {
+  return DL.get()->getScope()->getFile();
+}
+
+void CodeViewDebug::emitDebugInfoForFunction(const Function *GV) {
   // For each function there is a separate subsection
   // which holds the PC to file:line table.
   const MCSymbol *Fn = Asm->getSymbol(GV);
   assert(Fn);
 
+  const FunctionInfo &FI = FnDebugInfo[GV];
+  if (FI.Instrs.empty())
+    return;
+  assert(FI.End && "Don't know where the function ends?");
+
   StringRef FuncName;
   if (auto *SP = getDISubprogram(GV))
     FuncName = SP->getDisplayName();
@@ -232,8 +238,102 @@
   // Every subsection must be aligned to a 4-byte boundary.
   Asm->OutStreamer->EmitFill((-FuncName.size()) % 4, 0);
 
-  // We have an assembler directive that takes care of the whole line table.
-  Asm->OutStreamer->EmitCVLinetableDirective(FI.FuncId, Fn, FI.End);
+  // PCs/Instructions are grouped into segments sharing the same filename.
+  // Pre-calculate the lengths (in instructions) of these segments and store
+  // them in a map for convenience.  Each index in the map is the sequential
+  // number of the respective instruction that starts a new segment.
+  DenseMap<size_t, size_t> FilenameSegmentLengths;
+  size_t LastSegmentEnd = 0;
+  const DIFile *PrevFile = getFileFromLoc(LabelsAndLocs[FI.Instrs[0]]);
+  for (size_t J = 1, F = FI.Instrs.size(); J != F; ++J) {
+    const DIFile *CurFile = getFileFromLoc(LabelsAndLocs[FI.Instrs[J]]);
+    if (PrevFile == CurFile)
+      continue;
+    FilenameSegmentLengths[LastSegmentEnd] = J - LastSegmentEnd;
+    LastSegmentEnd = J;
+    PrevFile = CurFile;
+  }
+  FilenameSegmentLengths[LastSegmentEnd] = FI.Instrs.size() - LastSegmentEnd;
+
+  // Emit a line table subsection, required to do PC-to-file:line lookup.
+  Asm->OutStreamer->AddComment("Line table subsection for " + Twine(FuncName));
+  Asm->EmitInt32(unsigned(ModuleSubstreamKind::Lines));
+  MCSymbol *LineTableBegin = Asm->MMI->getContext().createTempSymbol(),
+           *LineTableEnd = Asm->MMI->getContext().createTempSymbol();
+  EmitLabelDiff(*Asm->OutStreamer, LineTableBegin, LineTableEnd);
+  Asm->OutStreamer->EmitLabel(LineTableBegin);
+
+  // Identify the function this subsection is for.
+  Asm->OutStreamer->EmitCOFFSecRel32(Fn);
+  Asm->OutStreamer->EmitCOFFSectionIndex(Fn);
+  // Insert flags after a 16-bit section index.
+  Asm->EmitInt16(COFF::DEBUG_LINE_TABLES_HAVE_COLUMN_RECORDS);
+
+  // Length of the function's code, in bytes.
+  EmitLabelDiff(*Asm->OutStreamer, Fn, FI.End);
+
+  // PC-to-linenumber lookup table:
+  MCSymbol *FileSegmentEnd = nullptr;
+
+  // The start of the last segment:
+  size_t LastSegmentStart = 0;
+
+  auto FinishPreviousChunk = [&] {
+    if (!FileSegmentEnd)
+      return;
+    for (size_t ColSegI = LastSegmentStart,
+                ColSegEnd = ColSegI + FilenameSegmentLengths[LastSegmentStart];
+         ColSegI != ColSegEnd; ++ColSegI) {
+      unsigned ColumnNumber = LabelsAndLocs[FI.Instrs[ColSegI]].getCol();
+      // Truncate the column number if it is longer than the maximum we can
+      // record.
+      if (ColumnNumber > COFF::CVL_MaxColumnNumber)
+        ColumnNumber = 0;
+      Asm->EmitInt16(ColumnNumber); // Start column
+      Asm->EmitInt16(0);            // End column
+    }
+    Asm->OutStreamer->EmitLabel(FileSegmentEnd);
+  };
+
+  for (size_t J = 0, F = FI.Instrs.size(); J != F; ++J) {
+    MCSymbol *Instr = FI.Instrs[J];
+    assert(LabelsAndLocs.count(Instr));
+
+    if (FilenameSegmentLengths.count(J)) {
+      // We came to a beginning of a new filename segment.
+      FinishPreviousChunk();
+      const DIFile *File = getFileFromLoc(LabelsAndLocs[FI.Instrs[J]]);
+      StringRef CurFilename = getFullFilepath(File);
+      size_t IndexInFileTable = FileNameRegistry.add(CurFilename);
+      // Each segment starts with the offset of the filename
+      // in the string table.
+      Asm->OutStreamer->AddComment(
+          "Segment for file '" + Twine(CurFilename) + "' begins");
+      MCSymbol *FileSegmentBegin = Asm->MMI->getContext().createTempSymbol();
+      Asm->OutStreamer->EmitLabel(FileSegmentBegin);
+      Asm->EmitInt32(8 * IndexInFileTable);
+
+      // Number of PC records in the lookup table.
+      size_t SegmentLength = FilenameSegmentLengths[J];
+      Asm->EmitInt32(SegmentLength);
+
+      // Full size of the segment for this filename, including the prev two
+      // records.
+      FileSegmentEnd = Asm->MMI->getContext().createTempSymbol();
+      EmitLabelDiff(*Asm->OutStreamer, FileSegmentBegin, FileSegmentEnd);
+      LastSegmentStart = J;
+    }
+
+    // The first PC with the given linenumber and the linenumber itself.
+    EmitLabelDiff(*Asm->OutStreamer, Fn, Instr);
+    uint32_t LineNumber = LabelsAndLocs[Instr].getLine();
+    assert(LineNumber <= COFF::CVL_MaxLineNumber);
+    uint32_t LineData = LineNumber | COFF::CVL_IsStatement;
+    Asm->EmitInt32(LineData);
+  }
+
+  FinishPreviousChunk();
+  Asm->OutStreamer->EmitLabel(LineTableEnd);
 }
 
 void CodeViewDebug::beginFunction(const MachineFunction *MF) {
@@ -244,8 +344,8 @@
 
   const Function *GV = MF->getFunction();
   assert(FnDebugInfo.count(GV) == false);
+  VisitedFunctions.push_back(GV);
   CurFn = &FnDebugInfo[GV];
-  CurFn->FuncId = NextFuncId++;
 
   // Find the end of the function prolog.
   // FIXME: is there a simpler a way to do this? Can we just search
@@ -284,9 +384,9 @@
   assert(FnDebugInfo.count(GV));
   assert(CurFn == &FnDebugInfo[GV]);
 
-  // Don't emit anything if we don't have any line tables.
-  if (!CurFn->HaveLineInfo) {
+  if (CurFn->Instrs.empty()) {
     FnDebugInfo.erase(GV);
+    VisitedFunctions.pop_back();
   } else {
     CurFn->End = Asm->getFunctionEnd();
   }