Skip to content

[NFC][MC][Dwarf] Add Range/Location List Entry fragment to reduce memory usage #146098

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions llvm/include/llvm/CodeGen/AsmPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,11 @@ class LLVM_ABI AsmPrinter : public MachineFunctionPass {
// Dwarf Emission Helper Routines
//===------------------------------------------------------------------===//

MCDwarfLocListOffsetPairFragment *
emitDwarfLocListOffsetPairEntry(int8_t OffsetPair, const MCSymbol *Base,
const MCSymbol *Begin, const MCSymbol *End,
StringRef EnumEle);

/// Emit a .byte 42 directive that corresponds to an encoding. If verbose
/// assembly output is enabled, we output comments describing the encoding.
/// Desc is a string saying what the encoding is specifying (e.g. "LSDA").
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/MC/MCAssembler.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ class MCAssembler {
bool relaxBoundaryAlign(MCBoundaryAlignFragment &BF);
bool relaxDwarfLineAddr(MCDwarfLineAddrFragment &DF);
bool relaxDwarfCallFrameFragment(MCDwarfCallFrameFragment &DF);
bool relaxDwarfLoclistEntry(MCDwarfLocListOffsetPairFragment &DF);
bool relaxCVInlineLineTable(MCCVInlineLineTableFragment &DF);
bool relaxCVDefRange(MCCVDefRangeFragment &DF);
bool relaxFill(MCFillFragment &F);
Expand Down
28 changes: 27 additions & 1 deletion llvm/include/llvm/MC/MCFragment.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class MCFragment {
FT_Org,
FT_Dwarf,
FT_DwarfFrame,
FT_DwarfLoclistEntry,
FT_LEB,
FT_BoundaryAlign,
FT_SymbolId,
Expand Down Expand Up @@ -135,6 +136,7 @@ class MCEncodedFragment : public MCFragment {
case MCFragment::FT_Data:
case MCFragment::FT_Dwarf:
case MCFragment::FT_DwarfFrame:
case MCFragment::FT_DwarfLoclistEntry:
case MCFragment::FT_PseudoProbe:
return true;
}
Expand Down Expand Up @@ -197,7 +199,8 @@ class MCEncodedFragmentWithFixups : public MCEncodedFragment {
MCFragment::FragmentType Kind = F->getKind();
return Kind == MCFragment::FT_Relaxable || Kind == MCFragment::FT_Data ||
Kind == MCFragment::FT_CVDefRange || Kind == MCFragment::FT_Dwarf ||
Kind == MCFragment::FT_DwarfFrame;
Kind == MCFragment::FT_DwarfFrame ||
Kind == MCFragment::FT_DwarfLoclistEntry;
}
};

Expand Down Expand Up @@ -440,6 +443,29 @@ class MCDwarfCallFrameFragment : public MCEncodedFragmentWithFixups<8, 1> {
}
};

class MCContext;

/// Represents a DWARF offset-pair kind location list or range list entry.
/// Currently not suitable to use if either of the offsets require
/// linker-relaxable relocations, which should be emitted as uleb fragments
/// instead.
/// LocationDescriptionExpr, which represents a DWARF location description,
/// is only used for location list entries.
class MCDwarfLocListOffsetPairFragment
: public MCEncodedFragmentWithFixups<16, 0> {
public:
SmallVector<char, 8> LocationDescriptionExpr;
const MCExpr *StartOffset;
const MCExpr *EndOffset;

MCDwarfLocListOffsetPairFragment(MCContext &Context, const MCSymbol *Base,
const MCSymbol *Begin, const MCSymbol *End);

static bool classof(const MCFragment *F) {
return F->getKind() == MCFragment::FT_DwarfLoclistEntry;
}
};

/// Represents a symbol table index fragment.
class MCSymbolIdFragment : public MCFragment {
const MCSymbol *Sym;
Expand Down
5 changes: 5 additions & 0 deletions llvm/include/llvm/MC/MCObjectStreamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,11 @@ class MCObjectStreamer : public MCStreamer {
void emitAbsoluteSymbolDiffAsULEB128(const MCSymbol *Hi,
const MCSymbol *Lo) override;

MCDwarfLocListOffsetPairFragment *
emitDwarfLocListOffsetPairEntry(int8_t OffsetPair, const MCSymbol *Base,
const MCSymbol *Begin, const MCSymbol *End,
StringRef EnumEle) override;

bool mayHaveInstructions(MCSection &Sec) const override;

/// Emits pending conditional assignments that depend on \p Symbol
Expand Down
5 changes: 5 additions & 0 deletions llvm/include/llvm/MC/MCStreamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,11 @@ class LLVM_ABI MCStreamer {
virtual void emitAbsoluteSymbolDiffAsULEB128(const MCSymbol *Hi,
const MCSymbol *Lo);

virtual MCDwarfLocListOffsetPairFragment *
emitDwarfLocListOffsetPairEntry(int8_t OffsetPair, const MCSymbol *Base,
const MCSymbol *Begin, const MCSymbol *End,
StringRef EnumEle);

virtual MCSymbol *getDwarfLineTableSymbol(unsigned CUID);
virtual void emitCFISections(bool EH, bool Debug);
void emitCFIStartProc(bool IsSimple, SMLoc Loc = SMLoc());
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3383,6 +3383,13 @@ void AsmPrinter::emitLabelDifferenceAsULEB128(const MCSymbol *Hi,
OutStreamer->emitAbsoluteSymbolDiffAsULEB128(Hi, Lo);
}

MCDwarfLocListOffsetPairFragment *AsmPrinter::emitDwarfLocListOffsetPairEntry(
int8_t OffsetPair, const MCSymbol *Base, const MCSymbol *Begin,
const MCSymbol *End, StringRef EnumEle) {
return OutStreamer->emitDwarfLocListOffsetPairEntry(OffsetPair, Base, Begin,
End, EnumEle);
}

/// EmitLabelPlusOffset - Emit something like ".long Label+Offset"
/// where the size in bytes of the directive is specified by Size and Label
/// specifies the label. This implicitly uses .set if it is available.
Expand Down
38 changes: 22 additions & 16 deletions llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3308,19 +3308,16 @@ static void emitRangeList(
}

for (const auto *RS : P.second) {
MCDwarfLocListOffsetPairFragment *LE = nullptr;
const MCSymbol *Begin = RS->Begin;
const MCSymbol *End = RS->End;
assert(Begin && "Range without a begin symbol?");
assert(End && "Range without an end symbol?");
if (Base) {
if (UseDwarf5) {
// Emit offset_pair when we have a base.
Asm->OutStreamer->AddComment(StringifyEnum(OffsetPair));
Asm->emitInt8(OffsetPair);
Asm->OutStreamer->AddComment(" starting offset");
Asm->emitLabelDifferenceAsULEB128(Begin, Base);
Asm->OutStreamer->AddComment(" ending offset");
Asm->emitLabelDifferenceAsULEB128(End, Base);
LE = Asm->emitDwarfLocListOffsetPairEntry(
OffsetPair, Base, Begin, End, StringifyEnum(OffsetPair));
} else {
Asm->emitLabelDifference(Begin, Base, Size);
Asm->emitLabelDifference(End, Base, Size);
Expand All @@ -3336,7 +3333,7 @@ static void emitRangeList(
Asm->OutStreamer->emitSymbolValue(Begin, Size);
Asm->OutStreamer->emitSymbolValue(End, Size);
}
EmitPayload(*RS);
EmitPayload(*RS, LE);
}
}

Expand All @@ -3357,8 +3354,18 @@ static void emitLocList(DwarfDebug &DD, AsmPrinter *Asm, const DebugLocStream::L
dwarf::DW_LLE_offset_pair, dwarf::DW_LLE_startx_length,
dwarf::DW_LLE_end_of_list, llvm::dwarf::LocListEncodingString,
/* ShouldUseBaseAddress */ true,
[&](const DebugLocStream::Entry &E) {
DD.emitDebugLocEntryLocation(E, List.CU);
[&](const DebugLocStream::Entry &E,
MCDwarfLocListOffsetPairFragment *LLE) {
if (LLE) {
// We don't need to emit the length header if we're writing
// to an entry fragment directly.
std::vector<std::string> Comments;
BufferByteStreamer S(LLE->LocationDescriptionExpr, Comments,
/*GenerateComments*/ false);
DD.emitDebugLocEntry(S, E, List.CU);
} else {
DD.emitDebugLocEntryLocation(E, List.CU);
}
});
}

Expand Down Expand Up @@ -3579,13 +3586,12 @@ void DwarfDebug::emitDebugARanges() {
/// Emit a single range list. We handle both DWARF v5 and earlier.
static void emitRangeList(DwarfDebug &DD, AsmPrinter *Asm,
const RangeSpanList &List) {
emitRangeList(DD, Asm, List.Label, List.Ranges, *List.CU,
dwarf::DW_RLE_base_addressx, dwarf::DW_RLE_offset_pair,
dwarf::DW_RLE_startx_length, dwarf::DW_RLE_end_of_list,
llvm::dwarf::RangeListEncodingString,
List.CU->getCUNode()->getRangesBaseAddress() ||
DD.getDwarfVersion() >= 5,
[](auto) {});
emitRangeList(
DD, Asm, List.Label, List.Ranges, *List.CU, dwarf::DW_RLE_base_addressx,
dwarf::DW_RLE_offset_pair, dwarf::DW_RLE_startx_length,
dwarf::DW_RLE_end_of_list, llvm::dwarf::RangeListEncodingString,
List.CU->getCUNode()->getRangesBaseAddress() || DD.getDwarfVersion() >= 5,
[](auto, auto) {});
}

void DwarfDebug::emitDebugRangesImpl(const DwarfFile &Holder, MCSection *Section) {
Expand Down
53 changes: 53 additions & 0 deletions llvm/lib/MC/MCAssembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,8 @@ uint64_t MCAssembler::computeFragmentSize(const MCFragment &F) const {
return cast<MCDwarfLineAddrFragment>(F).getContents().size();
case MCFragment::FT_DwarfFrame:
return cast<MCDwarfCallFrameFragment>(F).getContents().size();
case MCFragment::FT_DwarfLoclistEntry:
return cast<MCDwarfLocListOffsetPairFragment>(F).getContents().size();
case MCFragment::FT_CVInlineLines:
return cast<MCCVInlineLineTableFragment>(F).getContents().size();
case MCFragment::FT_CVDefRange:
Expand Down Expand Up @@ -730,6 +732,12 @@ static void writeFragment(raw_ostream &OS, const MCAssembler &Asm,
OS << CF.getContents();
break;
}
case MCFragment::FT_DwarfLoclistEntry: {
const MCDwarfLocListOffsetPairFragment &OF =
cast<MCDwarfLocListOffsetPairFragment>(F);
OS << OF.getContents();
break;
}
case MCFragment::FT_CVInlineLines: {
const auto &OF = cast<MCCVInlineLineTableFragment>(F);
OS << OF.getContents();
Expand Down Expand Up @@ -1150,6 +1158,49 @@ bool MCAssembler::relaxDwarfCallFrameFragment(MCDwarfCallFrameFragment &DF) {
return OldSize != Data.size();
}

bool MCAssembler::relaxDwarfLoclistEntry(MCDwarfLocListOffsetPairFragment &DF) {
SmallVectorImpl<char> &Data = DF.getContents();
raw_svector_ostream OSE(Data);

int64_t DiffAInt, DiffBInt;
bool Abs = DF.StartOffset->evaluateKnownAbsolute(DiffAInt, *this);
assert(Abs && "We created a loc/range list entry with an invalid expression");

Abs = DF.EndOffset->evaluateKnownAbsolute(DiffBInt, *this);
assert(Abs && "We created a loc/range list entry with an invalid expression");
(void)Abs;

unsigned OldSize = Data.size();
Data.clear();

// We could track the list entry kind encoding in a field, but it so happens
// that LLE and RLE offset_pair encodings are both 0x4.
static_assert((unsigned)dwarf::DW_LLE_offset_pair ==
(unsigned)dwarf::DW_RLE_offset_pair);
// DWARVv5 p44.
// Each location list entry begins with a single byte identifying the kind of
// that entry, followed by zero or more operands depending on the kind.
OSE << static_cast<uint8_t>(dwarf::DW_LLE_offset_pair);
// DWARFv5 p45, 54.
// [DW_LLE_offset_pair and DW_RLE_offset_pair have] two unsigned LEB128
// operands. The values of these operands are the starting and ending
// offsets, respectively, relative to the applicable base address, that
// define the address range.
encodeULEB128(DiffAInt, OSE);
encodeULEB128(DiffBInt, OSE);

// DWARFv5 p45.
// [DW_LLE_offset_pair] operands are followed by a counted location
// description.
if (unsigned Sz = DF.LocationDescriptionExpr.size()) {
encodeULEB128(Sz, OSE);
Data.append(DF.LocationDescriptionExpr.begin(),
DF.LocationDescriptionExpr.begin() + Sz);
}

return OldSize != Data.size();
}

bool MCAssembler::relaxCVInlineLineTable(MCCVInlineLineTableFragment &F) {
unsigned OldSize = F.getContents().size();
getContext().getCVContext().encodeInlineLineTable(*this, F);
Expand Down Expand Up @@ -1198,6 +1249,8 @@ bool MCAssembler::relaxFragment(MCFragment &F) {
return relaxDwarfLineAddr(cast<MCDwarfLineAddrFragment>(F));
case MCFragment::FT_DwarfFrame:
return relaxDwarfCallFrameFragment(cast<MCDwarfCallFrameFragment>(F));
case MCFragment::FT_DwarfLoclistEntry:
return relaxDwarfLoclistEntry(cast<MCDwarfLocListOffsetPairFragment>(F));
case MCFragment::FT_LEB:
return relaxLEB(cast<MCLEBFragment>(F));
case MCFragment::FT_BoundaryAlign:
Expand Down
35 changes: 35 additions & 0 deletions llvm/lib/MC/MCFragment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <utility>
Expand Down Expand Up @@ -72,6 +74,10 @@ void MCFragment::destroy() {
case FT_PseudoProbe:
cast<MCPseudoProbeAddrFragment>(this)->~MCPseudoProbeAddrFragment();
return;
case FT_DwarfLoclistEntry:
cast<MCDwarfLocListOffsetPairFragment>(this)
->~MCDwarfLocListOffsetPairFragment();
return;
}
}

Expand Down Expand Up @@ -108,6 +114,9 @@ LLVM_DUMP_METHOD void MCFragment::dump() const {
case MCFragment::FT_Org: OS << "MCOrgFragment"; break;
case MCFragment::FT_Dwarf: OS << "MCDwarfFragment"; break;
case MCFragment::FT_DwarfFrame: OS << "MCDwarfCallFrameFragment"; break;
case MCFragment::FT_DwarfLoclistEntry:
OS << "MCDwarfLocListOffsetPairFragment";
break;
case MCFragment::FT_LEB: OS << "MCLEBFragment"; break;
case MCFragment::FT_BoundaryAlign: OS<<"MCBoundaryAlignFragment"; break;
case MCFragment::FT_SymbolId: OS << "MCSymbolIdFragment"; break;
Expand Down Expand Up @@ -195,6 +204,21 @@ LLVM_DUMP_METHOD void MCFragment::dump() const {
OS << " AddrDelta:" << CF->getAddrDelta();
break;
}
case MCFragment::FT_DwarfLoclistEntry: {
const auto *LF = cast<MCDwarfLocListOffsetPairFragment>(this);
OS << "\n "
<< " StartOffset: " << LF->StartOffset
<< " EndOffset: " << LF->EndOffset;
if (!LF->LocationDescriptionExpr.empty()) {
OS << " Expr: [";
llvm::interleave(
LF->LocationDescriptionExpr,
[&](uint8_t C) { OS << format_hex_no_prefix(C, 2); },
[&]() { OS << " "; });
OS << "]";
}
break;
}
case MCFragment::FT_LEB: {
const auto *LF = cast<MCLEBFragment>(this);
OS << "\n ";
Expand Down Expand Up @@ -241,3 +265,14 @@ LLVM_DUMP_METHOD void MCFragment::dump() const {
OS << ">";
}
#endif

MCDwarfLocListOffsetPairFragment::MCDwarfLocListOffsetPairFragment(
MCContext &Context, const MCSymbol *Base, const MCSymbol *Begin,
const MCSymbol *End)
: MCEncodedFragmentWithFixups<16, 0>(FT_DwarfLoclistEntry, false) {
const MCExpr *BaseSym = MCSymbolRefExpr::create(Base, Context);
StartOffset = MCBinaryExpr::createSub(MCSymbolRefExpr::create(Begin, Context),
BaseSym, Context);
EndOffset = MCBinaryExpr::createSub(MCSymbolRefExpr::create(End, Context),
BaseSym, Context);
}
28 changes: 28 additions & 0 deletions llvm/lib/MC/MCObjectStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,34 @@ void MCObjectStreamer::emitAbsoluteSymbolDiffAsULEB128(const MCSymbol *Hi,
MCStreamer::emitAbsoluteSymbolDiffAsULEB128(Hi, Lo);
}

MCDwarfLocListOffsetPairFragment *
MCObjectStreamer::emitDwarfLocListOffsetPairEntry(int8_t OffsetPair,
const MCSymbol *Base,
const MCSymbol *Begin,
const MCSymbol *End,
StringRef EnumEle) {
// Heuristic: if we can emit one of the offsets as a constant now, that
// consumes less memory than creating a MCDwarfLocListOffsetPairFragment.
bool BeginOrEndInBaseFragment = Base->getFragment() == Begin->getFragment() ||
Base->getFragment() == End->getFragment();
// If the offset ulebs require linker-relaxable relocations then fall back to
// default uleb emission, rather than using MCDwarfLocListOffsetPairFragment.
// FIXME: Is there a better way to check this?
bool SameSection = &Base->getSection() == &End->getSection() &&
&End->getSection() == &Begin->getSection();
bool MayBeLinkerRelaxable =
Base->getSection().isLinkerRelaxable() || !SameSection;
if (BeginOrEndInBaseFragment || MayBeLinkerRelaxable)
return MCStreamer::emitDwarfLocListOffsetPairEntry(OffsetPair, Base, Begin,
End, EnumEle);

MCDwarfLocListOffsetPairFragment *Frag =
getContext().allocFragment<MCDwarfLocListOffsetPairFragment>(
getContext(), Base, Begin, End);
insert(Frag);
return Frag;
}

void MCObjectStreamer::reset() {
if (Assembler) {
Assembler->reset();
Expand Down
14 changes: 14 additions & 0 deletions llvm/lib/MC/MCStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1249,6 +1249,20 @@ void MCStreamer::emitAbsoluteSymbolDiffAsULEB128(const MCSymbol *Hi,
emitULEB128Value(Diff);
}

MCDwarfLocListOffsetPairFragment *MCStreamer::emitDwarfLocListOffsetPairEntry(
int8_t OffsetPair, const MCSymbol *Base, const MCSymbol *Begin,
const MCSymbol *End, StringRef EnumEle) {
// Base impl: emit offsets independently, possibly resulting in multiple
// fragments.
AddComment(EnumEle);
emitInt8(OffsetPair);
AddComment(" starting offset");
emitAbsoluteSymbolDiffAsULEB128(Begin, Base);
AddComment(" ending offset");
emitAbsoluteSymbolDiffAsULEB128(End, Base);
return nullptr;
}

void MCStreamer::emitSubsectionsViaSymbols() {
llvm_unreachable(
"emitSubsectionsViaSymbols only supported on Mach-O targets");
Expand Down
Loading