Skip to content

Commit bb526f6

Browse files
committed
[dwarf] make dwarf fission compatible with RISCV relaxations
Currently, `-gsplit-dwarf` and `-mrelax` are incompatible options in Clang. The issue is that `.dwo` files should not contain any relocations, as they are not processed by the linker. However, relaxable code emits relocations in DWARF for debug ranges that reside in the `.dwo` file when DWARF fission is enabled. This patch makes DWARF fission compatible with RISC-V relaxations. It uses the `StartxEndx` DWARF forms in `.debug_rnglists.dwo`, which allow referencing addresses from `.debug_addr` instead of using absolute addresses. This approach eliminates relocations from `.dwo` files.
1 parent 8400679 commit bb526f6

File tree

5 files changed

+293
-41
lines changed

5 files changed

+293
-41
lines changed

llvm/include/llvm/MC/MCSymbol.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,8 @@ inline raw_ostream &operator<<(raw_ostream &OS, const MCSymbol &Sym) {
383383
return OS;
384384
}
385385

386+
bool isRangeRelaxable(const MCSymbol *Begin, const MCSymbol *End);
387+
386388
} // end namespace llvm
387389

388390
#endif // LLVM_MC_MCSYMBOL_H

llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -493,10 +493,12 @@ void DwarfCompileUnit::attachLowHighPC(DIE &D, const MCSymbol *Begin,
493493
assert(End->isDefined() && "Invalid end label");
494494

495495
addLabelAddress(D, dwarf::DW_AT_low_pc, Begin);
496-
if (DD->getDwarfVersion() < 4)
497-
addLabelAddress(D, dwarf::DW_AT_high_pc, End);
498-
else
496+
if (DD->getDwarfVersion() >= 4 &&
497+
(!isDwoUnit() || !llvm::isRangeRelaxable(Begin, End))) {
499498
addLabelDelta(D, dwarf::DW_AT_high_pc, End, Begin);
499+
return;
500+
}
501+
addLabelAddress(D, dwarf::DW_AT_high_pc, End);
500502
}
501503

502504
// Add info for Wasm-global-based relocation.

llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp

Lines changed: 112 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3275,34 +3275,70 @@ static MCSymbol *emitLoclistsTableHeader(AsmPrinter *Asm,
32753275
return TableEnd;
32763276
}
32773277

3278-
template <typename Ranges, typename PayloadEmitter>
3279-
static void emitRangeList(
3280-
DwarfDebug &DD, AsmPrinter *Asm, MCSymbol *Sym, const Ranges &R,
3281-
const DwarfCompileUnit &CU, unsigned BaseAddressx, unsigned OffsetPair,
3282-
unsigned StartxLength, unsigned EndOfList,
3283-
StringRef (*StringifyEnum)(unsigned),
3284-
bool ShouldUseBaseAddress,
3285-
PayloadEmitter EmitPayload) {
3278+
namespace {
3279+
3280+
struct DebugLocSpanList {
3281+
MCSymbol *Label;
3282+
const DwarfCompileUnit *CU;
3283+
llvm::ArrayRef<llvm::DebugLocStream::Entry> Ranges;
3284+
};
3285+
3286+
template <typename DWARFSpanList> struct DwarfRangeListTraits {};
3287+
3288+
template <> struct DwarfRangeListTraits<DebugLocSpanList> {
3289+
static constexpr unsigned BaseAddressx = dwarf::DW_LLE_base_addressx;
3290+
static constexpr unsigned OffsetPair = dwarf::DW_LLE_offset_pair;
3291+
static constexpr unsigned StartxLength = dwarf::DW_LLE_startx_length;
3292+
static constexpr unsigned StartxEndx = dwarf::DW_LLE_startx_endx;
3293+
static constexpr unsigned EndOfList = dwarf::DW_LLE_end_of_list;
3294+
3295+
static StringRef StringifyRangeKind(unsigned Encoding) {
3296+
return llvm::dwarf::LocListEncodingString(Encoding);
3297+
}
3298+
};
3299+
3300+
template <> struct DwarfRangeListTraits<RangeSpanList> {
3301+
static constexpr unsigned BaseAddressx = dwarf::DW_RLE_base_addressx;
3302+
static constexpr unsigned OffsetPair = dwarf::DW_RLE_offset_pair;
3303+
static constexpr unsigned StartxLength = dwarf::DW_RLE_startx_length;
3304+
static constexpr unsigned StartxEndx = dwarf::DW_RLE_startx_endx;
3305+
static constexpr unsigned EndOfList = dwarf::DW_RLE_end_of_list;
3306+
3307+
static StringRef StringifyRangeKind(unsigned Encoding) {
3308+
return llvm::dwarf::RangeListEncodingString(Encoding);
3309+
}
3310+
};
3311+
3312+
} // namespace
3313+
3314+
template <
3315+
typename Ranges, typename PayloadEmitter,
3316+
std::enable_if_t<DwarfRangeListTraits<Ranges>::BaseAddressx, bool> = true>
3317+
static void emitRangeList(DwarfDebug &DD, AsmPrinter *Asm, const Ranges &R,
3318+
bool ShouldUseBaseAddress,
3319+
PayloadEmitter EmitPayload) {
32863320

32873321
auto Size = Asm->MAI->getCodePointerSize();
32883322
bool UseDwarf5 = DD.getDwarfVersion() >= 5;
32893323

32903324
// Emit our symbol so we can find the beginning of the range.
3291-
Asm->OutStreamer->emitLabel(Sym);
3325+
Asm->OutStreamer->emitLabel(R.Label);
32923326

32933327
// Gather all the ranges that apply to the same section so they can share
32943328
// a base address entry.
3295-
SmallMapVector<const MCSection *, std::vector<decltype(&*R.begin())>, 16>
3329+
SmallMapVector<const MCSection *, std::vector<decltype(&*R.Ranges.begin())>,
3330+
16>
32963331
SectionRanges;
32973332

3298-
for (const auto &Range : R)
3333+
for (const auto &Range : R.Ranges)
32993334
SectionRanges[&Range.Begin->getSection()].push_back(&Range);
33003335

3301-
const MCSymbol *CUBase = CU.getBaseAddress();
3336+
const MCSymbol *CUBase = R.CU->getBaseAddress();
33023337
bool BaseIsSet = false;
33033338
for (const auto &P : SectionRanges) {
33043339
auto *Base = CUBase;
3305-
if ((Asm->TM.getTargetTriple().isNVPTX() && DD.tuneForGDB())) {
3340+
if ((Asm->TM.getTargetTriple().isNVPTX() && DD.tuneForGDB()) ||
3341+
(DD.useSplitDwarf() && P.first->isLinkerRelaxable())) {
33063342
// PTX does not support subtracting labels from the code section in the
33073343
// debug_loc section. To work around this, the NVPTX backend needs the
33083344
// compile unit to have no low_pc in order to have a zero base_address
@@ -3327,8 +3363,10 @@ static void emitRangeList(
33273363
// * or, there's more than one entry to share the base address
33283364
Base = NewBase;
33293365
BaseIsSet = true;
3330-
Asm->OutStreamer->AddComment(StringifyEnum(BaseAddressx));
3331-
Asm->emitInt8(BaseAddressx);
3366+
Asm->OutStreamer->AddComment(
3367+
DwarfRangeListTraits<Ranges>::StringifyRangeKind(
3368+
DwarfRangeListTraits<Ranges>::BaseAddressx));
3369+
Asm->emitInt8(DwarfRangeListTraits<Ranges>::BaseAddressx);
33323370
Asm->OutStreamer->AddComment(" base address index");
33333371
Asm->emitULEB128(DD.getAddressPool().getIndex(Base));
33343372
}
@@ -3339,16 +3377,57 @@ static void emitRangeList(
33393377
Asm->OutStreamer->emitIntValue(0, Size);
33403378
}
33413379

3342-
for (const auto *RS : P.second) {
3380+
if (DD.useSplitDwarf() && UseDwarf5) {
3381+
// In .dwo files, we must ensure no relocations are present. For
3382+
// .debug_ranges.dwo. this means that if there is at least one
3383+
// relocation between the start and end of a range, we must
3384+
// represent the range boundaries using indirect addresses from
3385+
// the .debug_addr section.
3386+
//
3387+
// The DWARFv5 specification (section 2.17.3) does not require
3388+
// range entries to be ordered. Therefore, we emit such range
3389+
// entries here to allow using more optimal formats (e.g.
3390+
// StartxLength) for other ranges.
3391+
3392+
auto RelaxableRanges = llvm::make_filter_range(P.second, [](auto &&RS) {
3393+
return llvm::isRangeRelaxable(RS->Begin, RS->End);
3394+
});
3395+
3396+
for (auto &&RS : RelaxableRanges) {
3397+
const auto *Begin = RS->Begin;
3398+
const auto *End = RS->End;
3399+
Asm->OutStreamer->AddComment(
3400+
DwarfRangeListTraits<Ranges>::StringifyRangeKind(
3401+
DwarfRangeListTraits<Ranges>::StartxEndx));
3402+
Asm->emitInt8(DwarfRangeListTraits<Ranges>::StartxEndx);
3403+
Asm->OutStreamer->AddComment(" start index");
3404+
Asm->emitULEB128(DD.getAddressPool().getIndex(Begin));
3405+
Asm->OutStreamer->AddComment(" end index");
3406+
Asm->emitULEB128(DD.getAddressPool().getIndex(End));
3407+
EmitPayload(*RS);
3408+
}
3409+
}
3410+
3411+
auto NonRelaxableRanges = llvm::make_filter_range(
3412+
P.second,
3413+
[HasRelaxableRanges = DD.useSplitDwarf() && UseDwarf5](auto &&RS) {
3414+
if (!HasRelaxableRanges)
3415+
return true;
3416+
return !llvm::isRangeRelaxable(RS->Begin, RS->End);
3417+
});
3418+
3419+
for (const auto *RS : NonRelaxableRanges) {
33433420
const MCSymbol *Begin = RS->Begin;
33443421
const MCSymbol *End = RS->End;
33453422
assert(Begin && "Range without a begin symbol?");
33463423
assert(End && "Range without an end symbol?");
33473424
if (Base) {
33483425
if (UseDwarf5) {
33493426
// Emit offset_pair when we have a base.
3350-
Asm->OutStreamer->AddComment(StringifyEnum(OffsetPair));
3351-
Asm->emitInt8(OffsetPair);
3427+
Asm->OutStreamer->AddComment(
3428+
DwarfRangeListTraits<Ranges>::StringifyRangeKind(
3429+
DwarfRangeListTraits<Ranges>::OffsetPair));
3430+
Asm->emitInt8(DwarfRangeListTraits<Ranges>::OffsetPair);
33523431
Asm->OutStreamer->AddComment(" starting offset");
33533432
Asm->emitLabelDifferenceAsULEB128(Begin, Base);
33543433
Asm->OutStreamer->AddComment(" ending offset");
@@ -3358,8 +3437,10 @@ static void emitRangeList(
33583437
Asm->emitLabelDifference(End, Base, Size);
33593438
}
33603439
} else if (UseDwarf5) {
3361-
Asm->OutStreamer->AddComment(StringifyEnum(StartxLength));
3362-
Asm->emitInt8(StartxLength);
3440+
Asm->OutStreamer->AddComment(
3441+
DwarfRangeListTraits<Ranges>::StringifyRangeKind(
3442+
DwarfRangeListTraits<Ranges>::StartxLength));
3443+
Asm->emitInt8(DwarfRangeListTraits<Ranges>::StartxLength);
33633444
Asm->OutStreamer->AddComment(" start index");
33643445
Asm->emitULEB128(DD.getAddressPool().getIndex(Begin));
33653446
Asm->OutStreamer->AddComment(" length");
@@ -3373,8 +3454,10 @@ static void emitRangeList(
33733454
}
33743455

33753456
if (UseDwarf5) {
3376-
Asm->OutStreamer->AddComment(StringifyEnum(EndOfList));
3377-
Asm->emitInt8(EndOfList);
3457+
Asm->OutStreamer->AddComment(
3458+
DwarfRangeListTraits<Ranges>::StringifyRangeKind(
3459+
DwarfRangeListTraits<Ranges>::EndOfList));
3460+
Asm->emitInt8(DwarfRangeListTraits<Ranges>::EndOfList);
33783461
} else {
33793462
// Terminate the list with two 0 values.
33803463
Asm->OutStreamer->emitIntValue(0, Size);
@@ -3384,11 +3467,9 @@ static void emitRangeList(
33843467

33853468
// Handles emission of both debug_loclist / debug_loclist.dwo
33863469
static void emitLocList(DwarfDebug &DD, AsmPrinter *Asm, const DebugLocStream::List &List) {
3387-
emitRangeList(DD, Asm, List.Label, DD.getDebugLocs().getEntries(List),
3388-
*List.CU, dwarf::DW_LLE_base_addressx,
3389-
dwarf::DW_LLE_offset_pair, dwarf::DW_LLE_startx_length,
3390-
dwarf::DW_LLE_end_of_list, llvm::dwarf::LocListEncodingString,
3391-
/* ShouldUseBaseAddress */ true,
3470+
DebugLocSpanList Ranges = {List.Label, List.CU,
3471+
DD.getDebugLocs().getEntries(List)};
3472+
emitRangeList(DD, Asm, Ranges, /* ShouldUseBaseAddress */ true,
33923473
[&](const DebugLocStream::Entry &E) {
33933474
DD.emitDebugLocEntryLocation(E, List.CU);
33943475
});
@@ -3413,10 +3494,9 @@ void DwarfDebug::emitDebugLocImpl(MCSection *Sec) {
34133494

34143495
// Emit locations into the .debug_loc/.debug_loclists section.
34153496
void DwarfDebug::emitDebugLoc() {
3416-
emitDebugLocImpl(
3417-
getDwarfVersion() >= 5
3418-
? Asm->getObjFileLowering().getDwarfLoclistsSection()
3419-
: Asm->getObjFileLowering().getDwarfLocSection());
3497+
emitDebugLocImpl(getDwarfVersion() >= 5
3498+
? Asm->getObjFileLowering().getDwarfLoclistsSection()
3499+
: Asm->getObjFileLowering().getDwarfLocSection());
34203500
}
34213501

34223502
// Emit locations into the .debug_loc.dwo/.debug_loclists.dwo section.
@@ -3611,10 +3691,7 @@ void DwarfDebug::emitDebugARanges() {
36113691
/// Emit a single range list. We handle both DWARF v5 and earlier.
36123692
static void emitRangeList(DwarfDebug &DD, AsmPrinter *Asm,
36133693
const RangeSpanList &List) {
3614-
emitRangeList(DD, Asm, List.Label, List.Ranges, *List.CU,
3615-
dwarf::DW_RLE_base_addressx, dwarf::DW_RLE_offset_pair,
3616-
dwarf::DW_RLE_startx_length, dwarf::DW_RLE_end_of_list,
3617-
llvm::dwarf::RangeListEncodingString,
3694+
emitRangeList(DD, Asm, List,
36183695
List.CU->getCUNode()->getRangesBaseAddress() ||
36193696
DD.getDwarfVersion() >= 5,
36203697
[](auto) {});

llvm/lib/MC/MCSymbol.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,24 @@ void MCSymbol::print(raw_ostream &OS, const MCAsmInfo *MAI) const {
8383
OS << '"';
8484
}
8585

86-
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
87-
LLVM_DUMP_METHOD void MCSymbol::dump() const {
88-
dbgs() << *this;
86+
bool llvm::isRangeRelaxable(const MCSymbol *Begin, const MCSymbol *End) {
87+
assert(Begin && "Range without a begin symbol?");
88+
assert(End && "Range without an end symbol?");
89+
llvm::SmallVector<const MCFragment *> RangeFragments{};
90+
for (const auto *Fragment = Begin->getFragment();
91+
Fragment != End->getFragment(); Fragment = Fragment->getNext()) {
92+
assert(Fragment);
93+
RangeFragments.push_back(Fragment);
94+
}
95+
assert(End->getFragment());
96+
RangeFragments.push_back(End->getFragment());
97+
98+
bool IsRelaxableRange = llvm::any_of(RangeFragments, [](auto &&Fragment) {
99+
return Fragment->isLinkerRelaxable();
100+
});
101+
return IsRelaxableRange;
89102
}
103+
104+
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
105+
LLVM_DUMP_METHOD void MCSymbol::dump() const { dbgs() << *this; }
90106
#endif

0 commit comments

Comments
 (0)