[DWARF v5] Generate range list tables into the .debug_rnglists section. No support for split DWARF 
and no use of DW_FORM_rnglistx with the DW_AT_ranges attribute.

Reviewer: aprantl

Differential Revision: https://reviews.llvm.org/D49214

llvm-svn: 336927
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index c9e7a91..e12c866 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -645,6 +645,12 @@
     (useSplitDwarf() ? SkeletonHolder : InfoHolder)
         .setStringOffsetsStartSym(Asm->createTempSymbol("str_offsets_base"));
 
+  // Create the symbol that designates the start of the DWARF v5 range list
+  // table. It is located past the header and before the offsets table.
+  if (getDwarfVersion() >= 5)
+    (useSplitDwarf() ? SkeletonHolder : InfoHolder)
+        .setRnglistsTableBaseSym(Asm->createTempSymbol("rnglists_table_base"));
+
   for (DICompileUnit *CUNode : M->debug_compile_units()) {
     // FIXME: Move local imported entities into a list attached to the
     // subprogram, then this search won't be needed and a
@@ -765,7 +771,7 @@
         SkCU->addSectionLabel(SkCU->getUnitDie(), dwarf::DW_AT_GNU_addr_base,
                               Sym, Sym);
       }
-      if (!SkCU->getRangeLists().empty()) {
+      if (getDwarfVersion() < 5 && !SkCU->getRangeLists().empty()) {
         const MCSymbol *Sym = TLOF.getDwarfRangesSection()->getBeginSymbol();
         SkCU->addSectionLabel(SkCU->getUnitDie(), dwarf::DW_AT_GNU_ranges_base,
                               Sym, Sym);
@@ -1970,9 +1976,11 @@
   }
 }
 
-/// Emit a single range list.
+/// Emit a single range list. We handle both DWARF v5 and earlier.
 static void emitRangeList(AsmPrinter *Asm, DwarfCompileUnit *CU,
                           const RangeSpanList &List) {
+
+  auto DwarfVersion = CU->getDwarfVersion();
   // Emit our symbol so we can find the beginning of the range.
   Asm->OutStreamer->EmitLabel(List.getSym());
   // Gather all the ranges that apply to the same section so they can share
@@ -1992,18 +2000,24 @@
     // usually consist of single regions from each of many sections
     // (-ffunction-sections, or just C++ inline functions) except under LTO
     // or optnone where there may be holes in a single CU's section
-    // contrubutions.
+    // contributions.
     auto *Base = CUBase;
     if (!Base && P.second.size() > 1 && UseDwarfRangesBaseAddressSpecifier) {
       BaseIsSet = true;
       // FIXME/use care: This may not be a useful base address if it's not
       // the lowest address/range in this object.
       Base = P.second.front()->getStart();
-      Asm->OutStreamer->EmitIntValue(-1, Size);
+      if (DwarfVersion >= 5)
+        Asm->OutStreamer->EmitIntValue(dwarf::DW_RLE_base_address, 1);
+      else
+        Asm->OutStreamer->EmitIntValue(-1, Size);
       Asm->OutStreamer->EmitSymbolValue(Base, Size);
     } else if (BaseIsSet) {
       BaseIsSet = false;
-      Asm->OutStreamer->EmitIntValue(-1, Size);
+      if (DwarfVersion >= 5)
+        Asm->OutStreamer->EmitIntValue(dwarf::DW_RLE_base_address, 1);
+      else
+        Asm->OutStreamer->EmitIntValue(-1, Size);
       Asm->OutStreamer->EmitIntValue(0, Size);
     }
 
@@ -2013,21 +2027,87 @@
       assert(Begin && "Range without a begin symbol?");
       assert(End && "Range without an end symbol?");
       if (Base) {
-        Asm->EmitLabelDifference(Begin, Base, Size);
-        Asm->EmitLabelDifference(End, Base, Size);
+        if (DwarfVersion >= 5) {
+          // Emit DW_RLE_offset_pair when we have a base.
+          Asm->OutStreamer->EmitIntValue(dwarf::DW_RLE_offset_pair, 1);
+          Asm->EmitLabelDifferenceAsULEB128(Begin, Base);
+          Asm->EmitLabelDifferenceAsULEB128(End, Base);
+        } else {
+          Asm->EmitLabelDifference(Begin, Base, Size);
+          Asm->EmitLabelDifference(End, Base, Size);
+        }
+      } else if (DwarfVersion >= 5) {
+        Asm->OutStreamer->EmitIntValue(dwarf::DW_RLE_start_length, 1);
+        Asm->OutStreamer->EmitSymbolValue(Begin, Size);
+        Asm->EmitLabelDifferenceAsULEB128(End, Begin);
       } else {
         Asm->OutStreamer->EmitSymbolValue(Begin, Size);
         Asm->OutStreamer->EmitSymbolValue(End, Size);
       }
     }
   }
-
-  // And terminate the list with two 0 values.
-  Asm->OutStreamer->EmitIntValue(0, Size);
-  Asm->OutStreamer->EmitIntValue(0, Size);
+  if (DwarfVersion >= 5)
+    Asm->OutStreamer->EmitIntValue(dwarf::DW_RLE_end_of_list, 1);
+  else {
+    // Terminate the list with two 0 values.
+    Asm->OutStreamer->EmitIntValue(0, Size);
+    Asm->OutStreamer->EmitIntValue(0, Size);
+  }
 }
 
-/// Emit address ranges into a debug ranges section.
+void DwarfDebug::emitDebugRnglists() {
+
+  // Don't emit a rangelist table if there are no ranges.
+  if (llvm::all_of(CUMap,
+                   [](const decltype(CUMap)::const_iterator::value_type &Pair) {
+                     DwarfCompileUnit *TheCU = Pair.second;
+                     if (auto *Skel = TheCU->getSkeleton())
+                       TheCU = Skel;
+                     return TheCU->getRangeLists().empty();
+                   }))
+    return;
+
+  assert(getDwarfVersion() >= 5 && "Dwarf version must be 5 or greater");
+  // FIXME: As long as we don't support DW_RLE_base_addrx, we cannot generate
+  // any tables in the .debug_rnglists.dwo section.
+  Asm->OutStreamer->SwitchSection(
+      Asm->getObjFileLowering().getDwarfRnglistsSection());
+  // The length is described by a starting label right after the length field
+  // and an end label.
+  MCSymbol *TableStart = Asm->createTempSymbol("debug_rnglist_table_start");
+  MCSymbol *TableEnd = Asm->createTempSymbol("debug_rnglist_table_end");
+  // Build the range table header, which starts with the length field.
+  Asm->EmitLabelDifference(TableEnd, TableStart, 4);
+  Asm->OutStreamer->EmitLabel(TableStart);
+  // Version number (DWARF v5 and later).
+  Asm->emitInt16(getDwarfVersion());
+  // Address size.
+  Asm->emitInt8(Asm->MAI->getCodePointerSize());
+  // Segment selector size.
+  Asm->emitInt8(0);
+
+  MCSymbol *RnglistTableBaseSym =
+      (useSplitDwarf() ? SkeletonHolder : InfoHolder).getRnglistsTableBaseSym();
+
+  // FIXME: Generate the offsets table and use DW_FORM_rnglistx with the
+  // DW_AT_ranges attribute. Until then set the number of offsets to 0.
+  Asm->emitInt32(0);
+  Asm->OutStreamer->EmitLabel(RnglistTableBaseSym);
+
+  // Emit the individual range lists.
+  for (const auto &I : CUMap) {
+    DwarfCompileUnit *TheCU = I.second;
+    if (auto *Skel = TheCU->getSkeleton())
+      TheCU = Skel;
+    for (const RangeSpanList &List : TheCU->getRangeLists())
+      emitRangeList(Asm, TheCU, List);
+  }
+
+  Asm->OutStreamer->EmitLabel(TableEnd);
+}
+
+/// Emit address ranges into the .debug_ranges section or DWARF v5 rangelists
+/// into the .debug_rnglists section.
 void DwarfDebug::emitDebugRanges() {
   if (CUMap.empty())
     return;
@@ -2042,6 +2122,11 @@
     return;
   }
 
+  if (getDwarfVersion() >= 5) {
+    emitDebugRnglists();
+    return;
+  }
+
   // Start the dwarf ranges section.
   Asm->OutStreamer->SwitchSection(
       Asm->getObjFileLowering().getDwarfRangesSection());
@@ -2134,7 +2219,7 @@
 
 // This DIE has the following attributes: DW_AT_comp_dir, DW_AT_stmt_list,
 // DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_dwo_name, DW_AT_dwo_id,
-// DW_AT_addr_base, DW_AT_ranges_base.
+// DW_AT_addr_base, DW_AT_ranges_base or DW_AT_rnglists_base.
 DwarfCompileUnit &DwarfDebug::constructSkeletonCU(const DwarfCompileUnit &CU) {
 
   auto OwnedUnit = llvm::make_unique<DwarfCompileUnit>(