[codeview] Describe local variables in registers

llvm-svn: 260746
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index 4817729..9218579 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -105,18 +105,32 @@
   return Insertion.first->second;
 }
 
-CodeViewDebug::InlineSite &CodeViewDebug::getInlineSite(const DILocation *Loc) {
-  const DILocation *InlinedAt = Loc->getInlinedAt();
+CodeViewDebug::InlineSite &
+CodeViewDebug::getInlineSite(const DILocation *InlinedAt,
+                             const DISubprogram *Inlinee) {
   auto Insertion = CurFn->InlineSites.insert({InlinedAt, InlineSite()});
   InlineSite *Site = &Insertion.first->second;
   if (Insertion.second) {
     Site->SiteFuncId = NextFuncId++;
-    Site->Inlinee = Loc->getScope()->getSubprogram();
-    InlinedSubprograms.insert(Loc->getScope()->getSubprogram());
+    Site->Inlinee = Inlinee;
+    InlinedSubprograms.insert(Inlinee);
   }
   return *Site;
 }
 
+void CodeViewDebug::recordLocalVariable(LocalVariable &&Var,
+                                        const DILocation *InlinedAt) {
+  if (InlinedAt) {
+    // This variable was inlined. Associate it with the InlineSite.
+    const DISubprogram *Inlinee = Var.DIVar->getScope()->getSubprogram();
+    InlineSite &Site = getInlineSite(InlinedAt, Inlinee);
+    Site.InlinedLocals.emplace_back(Var);
+  } else {
+    // This variable goes in the main ProcSym.
+    CurFn->Locals.emplace_back(Var);
+  }
+}
+
 static void addLocIfNotPresent(SmallVectorImpl<const DILocation *> &Locs,
                                const DILocation *Loc) {
   auto B = Locs.begin(), E = Locs.end();
@@ -154,18 +168,19 @@
   CurFn->LastLoc = DL;
 
   unsigned FuncId = CurFn->FuncId;
-  if (DL->getInlinedAt()) {
+  if (const DILocation *SiteLoc = DL->getInlinedAt()) {
     const DILocation *Loc = DL.get();
 
     // If this location was actually inlined from somewhere else, give it the ID
     // of the inline call site.
-    FuncId = getInlineSite(Loc).SiteFuncId;
+    FuncId =
+        getInlineSite(SiteLoc, Loc->getScope()->getSubprogram()).SiteFuncId;
 
     // Ensure we have links in the tree of inline call sites.
-    const DILocation *SiteLoc;
     bool FirstLoc = true;
     while ((SiteLoc = Loc->getInlinedAt())) {
-      InlineSite &Site = getInlineSite(Loc);
+      InlineSite &Site =
+          getInlineSite(SiteLoc, Loc->getScope()->getSubprogram());
       if (!FirstLoc)
         addLocIfNotPresent(Site.ChildSites, Loc);
       FirstLoc = false;
@@ -477,45 +492,148 @@
   OS.EmitCVLinetableDirective(FI.FuncId, Fn, FI.End);
 }
 
-void CodeViewDebug::collectVariableInfoFromMMITable() {
-  for (const auto &VI : MMI->getVariableDbgInfo()) {
+CodeViewDebug::LocalVarDefRange
+CodeViewDebug::createDefRangeMem(uint16_t CVRegister, int Offset) {
+  LocalVarDefRange DR;
+  DR.InMemory = 1;
+  DR.DataOffset = Offset;
+  assert(DR.DataOffset == Offset && "truncation");
+  DR.StructOffset = 0;
+  DR.CVRegister = CVRegister;
+  return DR;
+}
+
+CodeViewDebug::LocalVarDefRange
+CodeViewDebug::createDefRangeReg(uint16_t CVRegister) {
+  LocalVarDefRange DR;
+  DR.InMemory = 0;
+  DR.DataOffset = 0;
+  DR.StructOffset = 0;
+  DR.CVRegister = CVRegister;
+  return DR;
+}
+
+void CodeViewDebug::collectVariableInfoFromMMITable(
+    DenseSet<InlinedVariable> &Processed) {
+  const TargetSubtargetInfo &TSI = Asm->MF->getSubtarget();
+  const TargetFrameLowering *TFI = TSI.getFrameLowering();
+  const TargetRegisterInfo *TRI = TSI.getRegisterInfo();
+
+  for (const MachineModuleInfo::VariableDbgInfo &VI :
+       MMI->getVariableDbgInfo()) {
     if (!VI.Var)
       continue;
     assert(VI.Var->isValidLocationForIntrinsic(VI.Loc) &&
            "Expected inlined-at fields to agree");
 
+    Processed.insert(InlinedVariable(VI.Var, VI.Loc->getInlinedAt()));
     LexicalScope *Scope = LScopes.findLexicalScope(VI.Loc);
 
     // If variable scope is not found then skip this variable.
     if (!Scope)
       continue;
 
-    LocalVariable Var;
-    Var.DIVar = VI.Var;
-
     // Get the frame register used and the offset.
     unsigned FrameReg = 0;
-    const TargetSubtargetInfo &TSI = Asm->MF->getSubtarget();
-    const TargetFrameLowering *TFI = TSI.getFrameLowering();
-    const TargetRegisterInfo *TRI = TSI.getRegisterInfo();
-    Var.RegisterOffset = TFI->getFrameIndexReference(*Asm->MF, VI.Slot, FrameReg);
-    Var.CVRegister = TRI->getCodeViewRegNum(FrameReg);
+    int FrameOffset = TFI->getFrameIndexReference(*Asm->MF, VI.Slot, FrameReg);
+    uint16_t CVReg = TRI->getCodeViewRegNum(FrameReg);
 
     // Calculate the label ranges.
+    LocalVarDefRange DefRange = createDefRangeMem(CVReg, FrameOffset);
     for (const InsnRange &Range : Scope->getRanges()) {
       const MCSymbol *Begin = getLabelBeforeInsn(Range.first);
       const MCSymbol *End = getLabelAfterInsn(Range.second);
-      Var.Ranges.push_back({Begin, End});
+      End = End ? End : Asm->getFunctionEnd();
+      DefRange.Ranges.emplace_back(Begin, End);
     }
 
-    if (VI.Loc->getInlinedAt()) {
-      // This variable was inlined. Associate it with the InlineSite.
-      InlineSite &Site = getInlineSite(VI.Loc);
-      Site.InlinedLocals.emplace_back(std::move(Var));
-    } else {
-      // This variable goes in the main ProcSym.
-      CurFn->Locals.emplace_back(std::move(Var));
+    LocalVariable Var;
+    Var.DIVar = VI.Var;
+    Var.DefRanges.emplace_back(std::move(DefRange));
+    recordLocalVariable(std::move(Var), VI.Loc->getInlinedAt());
+  }
+}
+
+void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) {
+  DenseSet<InlinedVariable> Processed;
+  // Grab the variable info that was squirreled away in the MMI side-table.
+  collectVariableInfoFromMMITable(Processed);
+
+  const TargetRegisterInfo *TRI = Asm->MF->getSubtarget().getRegisterInfo();
+
+  for (const auto &I : DbgValues) {
+    InlinedVariable IV = I.first;
+    if (Processed.count(IV))
+      continue;
+    const DILocalVariable *DIVar = IV.first;
+    const DILocation *InlinedAt = IV.second;
+
+    // Instruction ranges, specifying where IV is accessible.
+    const auto &Ranges = I.second;
+
+    LexicalScope *Scope = nullptr;
+    if (InlinedAt)
+      Scope = LScopes.findInlinedScope(DIVar->getScope(), InlinedAt);
+    else
+      Scope = LScopes.findLexicalScope(DIVar->getScope());
+    // If variable scope is not found then skip this variable.
+    if (!Scope)
+      continue;
+
+    LocalVariable Var;
+    Var.DIVar = DIVar;
+
+    // Calculate the definition ranges.
+    for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) {
+      const InsnRange &Range = *I;
+      const MachineInstr *DVInst = Range.first;
+      assert(DVInst->isDebugValue() && "Invalid History entry");
+      const DIExpression *DIExpr = DVInst->getDebugExpression();
+
+      // Bail if there is a complex DWARF expression for now.
+      if (DIExpr && DIExpr->getNumElements() > 0)
+        continue;
+
+      // Handle the two cases we can handle: indirect in memory and in register.
+      bool IsIndirect = DVInst->getOperand(1).isImm();
+      unsigned CVReg = TRI->getCodeViewRegNum(DVInst->getOperand(0).getReg());
+      {
+        LocalVarDefRange DefRange;
+        if (IsIndirect) {
+          int64_t Offset = DVInst->getOperand(1).getImm();
+          DefRange = createDefRangeMem(CVReg, Offset);
+        } else {
+          DefRange = createDefRangeReg(CVReg);
+        }
+        if (Var.DefRanges.empty() ||
+            Var.DefRanges.back().isDifferentLocation(DefRange)) {
+          Var.DefRanges.emplace_back(std::move(DefRange));
+        }
+      }
+
+      // Compute the label range.
+      const MCSymbol *Begin = getLabelBeforeInsn(Range.first);
+      const MCSymbol *End = getLabelAfterInsn(Range.second);
+      if (!End) {
+        if (std::next(I) != E)
+          End = getLabelBeforeInsn(std::next(I)->first);
+        else
+          End = Asm->getFunctionEnd();
+      }
+
+      // If the last range end is our begin, just extend the last range.
+      // Otherwise make a new range.
+      SmallVectorImpl<std::pair<const MCSymbol *, const MCSymbol *>> &Ranges =
+          Var.DefRanges.back().Ranges;
+      if (!Ranges.empty() && Ranges.back().second == Begin)
+        Ranges.back().second = End;
+      else
+        Ranges.emplace_back(Begin, End);
+
+      // FIXME: Do more range combining.
     }
+
+    recordLocalVariable(std::move(Var), InlinedAt);
   }
 }
 
@@ -572,6 +690,8 @@
   uint16_t Flags = 0;
   if (Var.DIVar->isParameter())
     Flags |= LocalSym::IsParameter;
+  if (Var.DefRanges.empty())
+    Flags |= LocalSym::IsOptimizedOut;
 
   OS.AddComment("TypeIndex");
   OS.EmitIntValue(TypeIndex::Int32().getIndex(), 4);
@@ -580,28 +700,42 @@
   emitNullTerminatedString(OS, Var.DIVar->getName());
   OS.EmitLabel(LocalEnd);
 
-  // DefRangeRegisterRelSym record, see SymbolRecord.h for more info.  Omit the
-  // LocalVariableAddrRange field from the record. The directive will emit that.
-  DefRangeRegisterRelSym Sym{};
-  ulittle16_t SymKind = ulittle16_t(S_DEFRANGE_REGISTER_REL);
-  Sym.BaseRegister = Var.CVRegister;
-  Sym.Flags = 0; // Unclear what matters here.
-  Sym.BasePointerOffset = Var.RegisterOffset;
-  SmallString<sizeof(Sym) + sizeof(SymKind) - sizeof(LocalVariableAddrRange)>
-      BytePrefix;
-  BytePrefix += StringRef(reinterpret_cast<const char *>(&SymKind),
-                          sizeof(SymKind));
-  BytePrefix += StringRef(reinterpret_cast<const char *>(&Sym),
-                          sizeof(Sym) - sizeof(LocalVariableAddrRange));
+  // Calculate the on disk prefix of the appropriate def range record. The
+  // records and on disk formats are described in SymbolRecords.h. BytePrefix
+  // should be big enough to hold all forms without memory allocation.
+  SmallString<20> BytePrefix;
+  for (const LocalVarDefRange &DefRange : Var.DefRanges) {
+    BytePrefix.clear();
+    // FIXME: Handle bitpieces.
+    if (DefRange.StructOffset != 0)
+      continue;
 
-  OS.EmitCVDefRangeDirective(Var.Ranges, BytePrefix);
+    if (DefRange.InMemory) {
+      DefRangeRegisterRelSym Sym{};
+      ulittle16_t SymKind = ulittle16_t(S_DEFRANGE_REGISTER_REL);
+      Sym.BaseRegister = DefRange.CVRegister;
+      Sym.Flags = 0; // Unclear what matters here.
+      Sym.BasePointerOffset = DefRange.DataOffset;
+      BytePrefix +=
+          StringRef(reinterpret_cast<const char *>(&SymKind), sizeof(SymKind));
+      BytePrefix += StringRef(reinterpret_cast<const char *>(&Sym),
+                              sizeof(Sym) - sizeof(LocalVariableAddrRange));
+    } else {
+      assert(DefRange.DataOffset == 0 && "unexpected offset into register");
+      DefRangeRegisterSym Sym{};
+      ulittle16_t SymKind = ulittle16_t(S_DEFRANGE_REGISTER);
+      Sym.Register = DefRange.CVRegister;
+      Sym.MayHaveNoName = 0; // Unclear what matters here.
+      BytePrefix +=
+          StringRef(reinterpret_cast<const char *>(&SymKind), sizeof(SymKind));
+      BytePrefix += StringRef(reinterpret_cast<const char *>(&Sym),
+                              sizeof(Sym) - sizeof(LocalVariableAddrRange));
+    }
+    OS.EmitCVDefRangeDirective(DefRange.Ranges, BytePrefix);
+  }
 }
 
 void CodeViewDebug::endFunction(const MachineFunction *MF) {
-  collectVariableInfoFromMMITable();
-
-  DebugHandlerBase::endFunction(MF);
-
   if (!Asm || !CurFn)  // We haven't created any debug info for this function.
     return;
 
@@ -609,6 +743,10 @@
   assert(FnDebugInfo.count(GV));
   assert(CurFn == &FnDebugInfo[GV]);
 
+  collectVariableInfo(getDISubprogram(GV));
+
+  DebugHandlerBase::endFunction(MF);
+
   // Don't emit anything if we don't have any line tables.
   if (!CurFn->HaveLineInfo) {
     FnDebugInfo.erase(GV);