[codeview] Begin to add support for inlined call sites

Summary:
There are three parts to inlined call frames:
1. The inlinee line subsection
2. The inline site symbol record
3. The function ids referenced by both

This change starts by emitting function ids (3) for all subprograms and
emitting the base inline site symbol record (2). The actual line numbers
in (2) use an encoded format that will come next, along with the inlinee
line subsection.

Reviewers: majnemer

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D16333

llvm-svn: 259217
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index b503f1d..e3c4829 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -15,6 +15,8 @@
 #include "llvm/DebugInfo/CodeView/CodeView.h"
 #include "llvm/DebugInfo/CodeView/Line.h"
 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
 #include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCSymbol.h"
 #include "llvm/Support/COFF.h"
@@ -87,6 +89,17 @@
   return Insertion.first->second;
 }
 
+CodeViewDebug::InlineSite &CodeViewDebug::getInlineSite(const DILocation *Loc) {
+  const DILocation *InlinedAt = Loc->getInlinedAt();
+  auto Insertion = CurFn->InlineSites.insert({InlinedAt, InlineSite()});
+  if (Insertion.second) {
+    InlineSite &Site = Insertion.first->second;
+    Site.SiteFuncId = NextFuncId++;
+    Site.Inlinee = Loc->getScope()->getSubprogram();
+  }
+  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.
@@ -115,7 +128,28 @@
   else
     FileId = CurFn->LastFileId = maybeRecordFile(DL->getFile());
   CurFn->LastLoc = DL;
-  Asm->OutStreamer->EmitCVLocDirective(CurFn->FuncId, FileId, DL.getLine(),
+
+  unsigned FuncId = CurFn->FuncId;
+  if (const DILocation *Loc = DL->getInlinedAt()) {
+    // If this location was actually inlined from somewhere else, give it the ID
+    // of the inline call site.
+    FuncId = getInlineSite(DL.get()).SiteFuncId;
+    // Ensure we have links in the tree of inline call sites.
+    const DILocation *ChildLoc = nullptr;
+    while (Loc->getInlinedAt()) {
+      InlineSite &Site = getInlineSite(Loc);
+      if (ChildLoc) {
+        // Record the child inline site if not already present.
+        auto B = Site.ChildSites.begin(), E = Site.ChildSites.end();
+        if (std::find(B, E, Loc) != E)
+          break;
+        Site.ChildSites.push_back(Loc);
+      }
+      ChildLoc = Loc;
+    }
+  }
+
+  Asm->OutStreamer->EmitCVLocDirective(FuncId, FileId, DL.getLine(),
                                        DL.getCol(), /*PrologueEnd=*/false,
                                        /*IsStmt=*/false, DL->getFilename());
 }
@@ -139,6 +173,8 @@
   if (FnDebugInfo.empty())
     return;
 
+  emitTypeInformation();
+
   // FIXME: For functions that are comdat, we should emit separate .debug$S
   // sections that are comdat associative with the main function instead of
   // having one big .debug$S section.
@@ -167,6 +203,60 @@
   clear();
 }
 
+template <typename T> static void emitRecord(MCStreamer &OS, const T &Rec) {
+  OS.EmitBytes(StringRef(reinterpret_cast<const char *>(&Rec), sizeof(Rec)));
+}
+
+void CodeViewDebug::emitTypeInformation() {
+  // Start the .debug$T section with 0x4.
+  Asm->OutStreamer->SwitchSection(
+      Asm->getObjFileLowering().getCOFFDebugTypesSection());
+  Asm->EmitInt32(COFF::DEBUG_SECTION_MAGIC);
+
+  NamedMDNode *CU_Nodes =
+      Asm->MMI->getModule()->getNamedMetadata("llvm.dbg.cu");
+  if (!CU_Nodes)
+    return;
+
+  // 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.
+  TypeIndex ArgListIdx = getNextTypeIndex();
+  Asm->EmitInt16(2 + sizeof(ArgList));
+  Asm->EmitInt16(LF_ARGLIST);
+  Asm->EmitInt32(0);
+
+  TypeIndex VoidProcIdx = getNextTypeIndex();
+  Asm->EmitInt16(2 + sizeof(ProcedureType));
+  Asm->EmitInt16(LF_PROCEDURE);
+  ProcedureType Proc{}; // Zero initialize.
+  Proc.ReturnType = TypeIndex::Void();
+  Proc.CallConv = CallingConvention::NearC;
+  Proc.Options = FunctionOptions::None;
+  Proc.NumParameters = 0;
+  Proc.ArgListType = ArgListIdx;
+  emitRecord(*Asm->OutStreamer, Proc);
+
+  for (MDNode *N : CU_Nodes->operands()) {
+    auto *CUNode = cast<DICompileUnit>(N);
+    for (auto *SP : CUNode->getSubprograms()) {
+      StringRef DisplayName = SP->getDisplayName();
+      Asm->EmitInt16(2 + sizeof(FuncId) + DisplayName.size() + 1);
+      Asm->EmitInt16(LF_FUNC_ID);
+
+      FuncId Func{}; // Zero initialize.
+      Func.ParentScope = TypeIndex();
+      Func.FunctionType = VoidProcIdx;
+      emitRecord(*Asm->OutStreamer, Func);
+      Asm->OutStreamer->EmitBytes(DisplayName);
+      Asm->EmitInt8(0);
+
+      TypeIndex FuncIdIdx = getNextTypeIndex();
+      SubprogramToFuncId.insert(std::make_pair(SP, FuncIdIdx));
+    }
+  }
+}
+
 static void EmitLabelDiff(MCStreamer &Streamer,
                           const MCSymbol *From, const MCSymbol *To,
                           unsigned int Size = 4) {
@@ -179,6 +269,44 @@
   Streamer.EmitValue(AddrDelta, Size);
 }
 
+void CodeViewDebug::emitInlinedCallSite(const FunctionInfo &FI,
+                                        const DILocation *InlinedAt,
+                                        const InlineSite &Site) {
+  MCStreamer &OS = *Asm->OutStreamer;
+
+  MCSymbol *InlineBegin = Asm->MMI->getContext().createTempSymbol(),
+           *InlineEnd = Asm->MMI->getContext().createTempSymbol();
+
+  assert(SubprogramToFuncId.count(Site.Inlinee));
+  TypeIndex InlineeIdx = SubprogramToFuncId[Site.Inlinee];
+
+  // SymbolRecord
+  EmitLabelDiff(OS, InlineBegin, InlineEnd, 2);   // RecordLength
+  OS.EmitLabel(InlineBegin);
+  Asm->EmitInt16(SymbolRecordKind::S_INLINESITE); // RecordKind
+
+  InlineSiteSym SiteBytes{};
+  SiteBytes.Inlinee = InlineeIdx;
+  Asm->OutStreamer->EmitBytes(
+      StringRef(reinterpret_cast<const char *>(&SiteBytes), sizeof(SiteBytes)));
+
+  // FIXME: annotations
+
+  OS.EmitLabel(InlineEnd);
+
+  // Recurse on child inlined call sites before closing the scope.
+  for (const DILocation *ChildSite : Site.ChildSites) {
+    auto I = FI.InlineSites.find(ChildSite);
+    assert(I != FI.InlineSites.end() &&
+           "child site not in function inline site map");
+    emitInlinedCallSite(FI, ChildSite, I->second);
+  }
+
+  // Close the scope.
+  Asm->EmitInt16(2);                                  // RecordLength
+  Asm->EmitInt16(SymbolRecordKind::S_INLINESITE_END); // RecordKind
+}
+
 void CodeViewDebug::emitDebugInfoForFunction(const Function *GV,
                                              FunctionInfo &FI) {
   // For each function there is a separate subsection
@@ -224,6 +352,15 @@
     Asm->EmitInt8(0);
     Asm->OutStreamer->EmitLabel(ProcSegmentEnd);
 
+    // Emit inlined call site information. Only emit functions inlined directly
+    // into the parent function. We'll emit the other sites recursively as part
+    // of their parent inline site.
+    for (auto &KV : FI.InlineSites) {
+      const DILocation *InlinedAt = KV.first;
+      if (!InlinedAt->getInlinedAt())
+        emitInlinedCallSite(FI, InlinedAt, KV.second);
+    }
+
     // We're done with this function.
     Asm->EmitInt16(0x0002);
     Asm->EmitInt16(unsigned(SymbolRecordKind::S_PROC_ID_END));
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h
index 77b5ed3..4883905 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h
@@ -22,6 +22,7 @@
 #include "llvm/CodeGen/LexicalScopes.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
 #include "llvm/IR/DebugInfo.h"
 #include "llvm/IR/DebugLoc.h"
 #include "llvm/MC/MCStreamer.h"
@@ -33,19 +34,31 @@
   AsmPrinter *Asm;
   DebugLoc PrevInstLoc;
 
+  struct InlineSite {
+    TinyPtrVector<const DILocation *> ChildSites;
+    const DISubprogram *Inlinee = nullptr;
+    unsigned SiteFuncId = 0;
+  };
+
   // For each function, store a vector of labels to its instructions, as well as
   // to the end of the function.
   struct FunctionInfo {
+    /// Map from inlined call site to inlined instructions and child inlined
+    /// call sites. Listed in program order.
+    MapVector<const DILocation *, InlineSite> InlineSites;
+
     DebugLoc LastLoc;
     MCSymbol *End = nullptr;
     unsigned FuncId = 0;
-    unsigned LastFileId;
+    unsigned LastFileId = 0;
     bool HaveLineInfo = false;
   };
   FunctionInfo *CurFn;
 
   unsigned NextFuncId = 0;
 
+  InlineSite &getInlineSite(const DILocation *Loc);
+
   /// Remember some debug info about each function. Keep it in a stable order to
   /// emit at the end of the TU.
   MapVector<const Function *, FunctionInfo> FnDebugInfo;
@@ -53,6 +66,16 @@
   /// Map from DIFile to .cv_file id.
   DenseMap<const DIFile *, unsigned> FileIdMap;
 
+  DenseMap<const DISubprogram *, codeview::TypeIndex> SubprogramToFuncId;
+
+  unsigned TypeCount = 0;
+
+  /// Gets the next type index and increments the count of types streamed so
+  /// far.
+  codeview::TypeIndex getNextTypeIndex() {
+    return codeview::TypeIndex(codeview::TypeIndex::FirstNonSimpleIndex + TypeCount++);
+  }
+
   typedef std::map<const DIFile *, std::string> FileToFilepathMapTy;
   FileToFilepathMapTy FileToFilepathMap;
   StringRef getFullFilepath(const DIFile *S);
@@ -68,8 +91,13 @@
     FileToFilepathMap.clear();
   }
 
+  void emitTypeInformation();
+
   void emitDebugInfoForFunction(const Function *GV, FunctionInfo &FI);
 
+  void emitInlinedCallSite(const FunctionInfo &FI, const DILocation *InlinedAt,
+                           const InlineSite &Site);
+
 public:
   CodeViewDebug(AsmPrinter *Asm);