Skip to content

Commit 8de8713

Browse files
committed
[dwarf] make dwarf fission compatible with RISCV relaxations 1/2
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 f60e693 commit 8de8713

File tree

4 files changed

+240
-28
lines changed

4 files changed

+240
-28
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/DwarfDebug.cpp

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3291,14 +3291,12 @@ static MCSymbol *emitLoclistsTableHeader(AsmPrinter *Asm,
32913291
}
32923292

32933293
template <typename Ranges, typename PayloadEmitter>
3294-
static void emitRangeList(
3295-
DwarfDebug &DD, AsmPrinter *Asm, MCSymbol *Sym, const Ranges &R,
3296-
const DwarfCompileUnit &CU, unsigned BaseAddressx, unsigned OffsetPair,
3297-
unsigned StartxLength, unsigned EndOfList,
3298-
StringRef (*StringifyEnum)(unsigned),
3299-
bool ShouldUseBaseAddress,
3300-
PayloadEmitter EmitPayload) {
3301-
3294+
static void
3295+
emitRangeList(DwarfDebug &DD, AsmPrinter *Asm, MCSymbol *Sym, const Ranges &R,
3296+
const DwarfCompileUnit &CU, unsigned BaseAddressx,
3297+
unsigned OffsetPair, unsigned StartxLength, unsigned StartxEndx,
3298+
unsigned EndOfList, StringRef (*StringifyEnum)(unsigned),
3299+
bool ShouldUseBaseAddress, PayloadEmitter EmitPayload) {
33023300
auto Size = Asm->MAI->getCodePointerSize();
33033301
bool UseDwarf5 = DD.getDwarfVersion() >= 5;
33043302

@@ -3317,7 +3315,8 @@ static void emitRangeList(
33173315
bool BaseIsSet = false;
33183316
for (const auto &P : SectionRanges) {
33193317
auto *Base = CUBase;
3320-
if ((Asm->TM.getTargetTriple().isNVPTX() && DD.tuneForGDB())) {
3318+
if ((Asm->TM.getTargetTriple().isNVPTX() && DD.tuneForGDB()) ||
3319+
(DD.useSplitDwarf() && UseDwarf5 && P.first->isLinkerRelaxable())) {
33213320
// PTX does not support subtracting labels from the code section in the
33223321
// debug_loc section. To work around this, the NVPTX backend needs the
33233322
// compile unit to have no low_pc in order to have a zero base_address
@@ -3373,12 +3372,21 @@ static void emitRangeList(
33733372
Asm->emitLabelDifference(End, Base, Size);
33743373
}
33753374
} else if (UseDwarf5) {
3376-
Asm->OutStreamer->AddComment(StringifyEnum(StartxLength));
3377-
Asm->emitInt8(StartxLength);
3378-
Asm->OutStreamer->AddComment(" start index");
3379-
Asm->emitULEB128(DD.getAddressPool().getIndex(Begin));
3380-
Asm->OutStreamer->AddComment(" length");
3381-
Asm->emitLabelDifferenceAsULEB128(End, Begin);
3375+
if (DD.useSplitDwarf() && llvm::isRangeRelaxable(Begin, End)) {
3376+
Asm->OutStreamer->AddComment(StringifyEnum(StartxEndx));
3377+
Asm->emitInt8(StartxEndx);
3378+
Asm->OutStreamer->AddComment(" start index");
3379+
Asm->emitULEB128(DD.getAddressPool().getIndex(Begin));
3380+
Asm->OutStreamer->AddComment(" end index");
3381+
Asm->emitULEB128(DD.getAddressPool().getIndex(End));
3382+
} else {
3383+
Asm->OutStreamer->AddComment(StringifyEnum(StartxLength));
3384+
Asm->emitInt8(StartxLength);
3385+
Asm->OutStreamer->AddComment(" start index");
3386+
Asm->emitULEB128(DD.getAddressPool().getIndex(Begin));
3387+
Asm->OutStreamer->AddComment(" length");
3388+
Asm->emitLabelDifferenceAsULEB128(End, Begin);
3389+
}
33823390
} else {
33833391
Asm->OutStreamer->emitSymbolValue(Begin, Size);
33843392
Asm->OutStreamer->emitSymbolValue(End, Size);
@@ -3399,14 +3407,14 @@ static void emitRangeList(
33993407

34003408
// Handles emission of both debug_loclist / debug_loclist.dwo
34013409
static void emitLocList(DwarfDebug &DD, AsmPrinter *Asm, const DebugLocStream::List &List) {
3402-
emitRangeList(DD, Asm, List.Label, DD.getDebugLocs().getEntries(List),
3403-
*List.CU, dwarf::DW_LLE_base_addressx,
3404-
dwarf::DW_LLE_offset_pair, dwarf::DW_LLE_startx_length,
3405-
dwarf::DW_LLE_end_of_list, llvm::dwarf::LocListEncodingString,
3406-
/* ShouldUseBaseAddress */ true,
3407-
[&](const DebugLocStream::Entry &E) {
3408-
DD.emitDebugLocEntryLocation(E, List.CU);
3409-
});
3410+
emitRangeList(
3411+
DD, Asm, List.Label, DD.getDebugLocs().getEntries(List), *List.CU,
3412+
dwarf::DW_LLE_base_addressx, dwarf::DW_LLE_offset_pair,
3413+
dwarf::DW_LLE_startx_length, dwarf::DW_LLE_startx_endx,
3414+
dwarf::DW_LLE_end_of_list, llvm::dwarf::LocListEncodingString,
3415+
/* ShouldUseBaseAddress */ true, [&](const DebugLocStream::Entry &E) {
3416+
DD.emitDebugLocEntryLocation(E, List.CU);
3417+
});
34103418
}
34113419

34123420
void DwarfDebug::emitDebugLocImpl(MCSection *Sec) {
@@ -3628,8 +3636,8 @@ static void emitRangeList(DwarfDebug &DD, AsmPrinter *Asm,
36283636
const RangeSpanList &List) {
36293637
emitRangeList(DD, Asm, List.Label, List.Ranges, *List.CU,
36303638
dwarf::DW_RLE_base_addressx, dwarf::DW_RLE_offset_pair,
3631-
dwarf::DW_RLE_startx_length, dwarf::DW_RLE_end_of_list,
3632-
llvm::dwarf::RangeListEncodingString,
3639+
dwarf::DW_RLE_startx_length, dwarf::DW_RLE_startx_endx,
3640+
dwarf::DW_RLE_end_of_list, llvm::dwarf::RangeListEncodingString,
36333641
List.CU->getCUNode()->getRangesBaseAddress() ||
36343642
DD.getDwarfVersion() >= 5,
36353643
[](auto) {});

llvm/lib/MC/MCSymbol.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,22 @@ void MCSymbol::print(raw_ostream &OS, const MCAsmInfo *MAI) const {
8484
}
8585

8686
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
87-
LLVM_DUMP_METHOD void MCSymbol::dump() const {
88-
dbgs() << *this;
89-
}
87+
LLVM_DUMP_METHOD void MCSymbol::dump() const { dbgs() << *this; }
9088
#endif
89+
90+
bool llvm::isRangeRelaxable(const MCSymbol *Begin, const MCSymbol *End) {
91+
assert(Begin && "Range without a begin symbol?");
92+
assert(End && "Range without an end symbol?");
93+
llvm::SmallVector<const MCFragment *> RangeFragments{};
94+
for (const auto *Fragment = Begin->getFragment();
95+
Fragment != End->getFragment(); Fragment = Fragment->getNext()) {
96+
RangeFragments.push_back(Fragment);
97+
}
98+
RangeFragments.push_back(End->getFragment());
99+
100+
bool IsRelaxableRange = llvm::any_of(RangeFragments, [](auto &&Fragment) {
101+
assert(Fragment);
102+
return Fragment->isLinkerRelaxable();
103+
});
104+
return IsRelaxableRange;
105+
}
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
; RUN: llc -dwarf-version=5 -split-dwarf-file=foo.dwo -O0 %s -mtriple=riscv64-unknown-linux-gnu -filetype=obj -o %t
2+
; RUN: llvm-dwarfdump -v %t | FileCheck --check-prefix=DWARF5 %s
3+
; RUN: llvm-dwarfdump --debug-info %t 2> %t.txt
4+
; RUN: FileCheck --input-file=%t.txt %s --check-prefix=RELOCS --implicit-check-not=warning:
5+
6+
; RUN: llc -dwarf-version=4 -split-dwarf-file=foo.dwo -O0 %s -mtriple=riscv64-unknown-linux-gnu -filetype=obj -o %t
7+
; RUN: llvm-dwarfdump -v %t | FileCheck --check-prefix=DWARF4 %s
8+
; RUN: llvm-dwarfdump --debug-info %t 2> %t.txt
9+
; RUN: FileCheck --input-file=%t.txt %s --check-prefix=RELOCS --implicit-check-not=warning:
10+
11+
; In the RISC-V architecture, the .text section is subject to
12+
; relaxation, meaning the start address of each function can change
13+
; during the linking process. Therefore, the .debug_rnglists.dwo
14+
; section must obtain function's start addresses from the .debug_addr
15+
; section.
16+
17+
; Generally, a function's body can be relaxed (for example, the
18+
; square() and main() functions in this test, which contain call
19+
; instructions). For such code ranges, the linker must place the
20+
; start and end addresses into the .debug_addr section and use
21+
; the DW_RLE_startx_endx entry form in the .debug_rnglists.dwo
22+
; section within the .dwo file.
23+
24+
; However, some functions may not contain any relaxable instructions
25+
; (for example, the boo() function in this test). In these cases,
26+
; it is possible to use the more space-efficient DW_RLE_startx_length
27+
; range entry form.
28+
29+
; From the code:
30+
31+
; __attribute__((noinline)) int boo();
32+
33+
; int square(int num) {
34+
; int num1 = boo();
35+
; return num1 * num;
36+
; }
37+
38+
; __attribute__((noinline)) int boo() {
39+
; return 8;
40+
; }
41+
42+
; int main() {
43+
; int a = 10;
44+
; int squared = square(a);
45+
; return squared;
46+
; }
47+
48+
; compiled with
49+
50+
; clang -g -S -gsplit-dwarf --target=riscv64 -march=rv64gc -O0 relax_dwo_ranges.cpp
51+
52+
; Currently, square() still uses an offset to represent the function's end address,
53+
; which requires a relocation here.
54+
; RELOCS: warning: unexpected relocations for dwo section '.debug_info.dwo'
55+
56+
; DWARF5: .debug_info.dwo contents:
57+
; DWARF5: DW_TAG_subprogram
58+
; DWARF5-NEXT: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x0000000000000000 ".text")
59+
; DWARF5-NEXT: DW_AT_high_pc [DW_FORM_data4] (0x00000000)
60+
; DWARF5: DW_AT_name {{.*}} "square")
61+
; DWARF5: DW_TAG_formal_parameter
62+
63+
; Ensure there is no unnecessary addresses in .o file
64+
; DWARF5: .debug_addr contents:
65+
; DWARF5: Addrs: [
66+
; DWARF5-NEXT: 0x0000000000000000
67+
; DWARF5-NEXT: 0x0000000000000046
68+
; DWARF5-NEXT: 0x000000000000006c
69+
; DWARF5-NEXT: 0x00000000000000b0
70+
; DWARF5-NEXT: ]
71+
72+
; Ensure that 'boo()' and 'main()' use DW_RLE_startx_length and DW_RLE_startx_endx
73+
; entries respectively
74+
; DWARF5: .debug_rnglists.dwo contents:
75+
; DWARF5: ranges:
76+
; DWARF5-NEXT: 0x00000014: [DW_RLE_startx_length]: 0x0000000000000001, 0x0000000000000024 => [0x0000000000000046, 0x000000000000006a)
77+
; DWARF5-NEXT: 0x00000017: [DW_RLE_end_of_list ]
78+
; DWARF5-NEXT: 0x00000018: [DW_RLE_startx_endx ]: 0x0000000000000002, 0x0000000000000003 => [0x000000000000006c, 0x00000000000000b0)
79+
; DWARF5-NEXT: 0x0000001b: [DW_RLE_end_of_list ]
80+
; DWARF5-EMPTY:
81+
82+
; DWARF4: .debug_info.dwo contents:
83+
; DWARF4: DW_TAG_subprogram
84+
; DWARF4-NEXT: DW_AT_low_pc [DW_FORM_GNU_addr_index] (indexed (00000000) address = 0x0000000000000000 ".text")
85+
; DWARF4-NEXT: DW_AT_high_pc [DW_FORM_data4] (0x00000000)
86+
; DWARF4: DW_AT_name {{.*}} "square")
87+
88+
; DWARF4: DW_TAG_subprogram
89+
; DWARF4-NEXT: DW_AT_low_pc [DW_FORM_GNU_addr_index] (indexed (00000001) address = 0x0000000000000046 ".text")
90+
; DWARF4-NEXT: DW_AT_high_pc [DW_FORM_data4] (0x00000024)
91+
; DWARF4: DW_AT_name {{.*}} "boo")
92+
93+
; DWARF4: DW_TAG_subprogram
94+
; DWARF4-NEXT: DW_AT_low_pc [DW_FORM_GNU_addr_index] (indexed (00000002) address = 0x000000000000006c ".text")
95+
; DWARF4-NEXT: DW_AT_high_pc [DW_FORM_data4] (0x00000000)
96+
; DWARF4: DW_AT_name {{.*}} "main")
97+
98+
; Ensure there is no unnecessary addresses in .o file
99+
; DWARF4: .debug_addr contents:
100+
; DWARF4: Addrs: [
101+
; DWARF4-NEXT: 0x0000000000000000
102+
; DWARF4-NEXT: 0x0000000000000046
103+
; DWARF4-NEXT: 0x000000000000006c
104+
; DWARF4-NEXT: ]
105+
106+
; Function Attrs: mustprogress noinline optnone
107+
define dso_local noundef signext i32 @_Z6squarei(i32 noundef signext %0) #0 !dbg !11 {
108+
%2 = alloca i32, align 4
109+
%3 = alloca i32, align 4
110+
store i32 %0, ptr %2, align 4
111+
#dbg_declare(ptr %2, !16, !DIExpression(), !17)
112+
#dbg_declare(ptr %3, !18, !DIExpression(), !19)
113+
%4 = call noundef signext i32 @_Z3boov(), !dbg !20
114+
store i32 %4, ptr %3, align 4, !dbg !19
115+
%5 = load i32, ptr %3, align 4, !dbg !21
116+
%6 = load i32, ptr %2, align 4, !dbg !22
117+
%7 = mul nsw i32 %5, %6, !dbg !23
118+
ret i32 %7, !dbg !24
119+
}
120+
121+
; Function Attrs: mustprogress noinline nounwind optnone
122+
define dso_local noundef signext i32 @_Z3boov() #1 !dbg !25 {
123+
ret i32 8, !dbg !28
124+
}
125+
126+
; Function Attrs: mustprogress noinline norecurse optnone
127+
define dso_local noundef signext i32 @main() #2 !dbg !29 {
128+
%1 = alloca i32, align 4
129+
%2 = alloca i32, align 4
130+
%3 = alloca i32, align 4
131+
store i32 0, ptr %1, align 4
132+
#dbg_declare(ptr %2, !30, !DIExpression(), !31)
133+
store i32 10, ptr %2, align 4, !dbg !31
134+
#dbg_declare(ptr %3, !32, !DIExpression(), !33)
135+
%4 = load i32, ptr %2, align 4, !dbg !34
136+
%5 = call noundef signext i32 @_Z6squarei(i32 noundef signext %4), !dbg !35
137+
store i32 %5, ptr %3, align 4, !dbg !33
138+
%6 = load i32, ptr %3, align 4, !dbg !36
139+
ret i32 %6, !dbg !37
140+
}
141+
142+
attributes #0 = { mustprogress noinline optnone "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic-rv64" "target-features"="+64bit,+relax,+f,+d" }
143+
attributes #1 = { mustprogress noinline nounwind optnone "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic-rv64" "target-features"="+64bit,+relax,+f,+d" }
144+
attributes #2 = { mustprogress noinline norecurse optnone "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic-rv64" "target-features"="+64bit,+relax,+f,+d" }
145+
146+
!llvm.dbg.cu = !{!0}
147+
!llvm.module.flags = !{!2, !3, !4, !5, !6, !8, !9}
148+
!llvm.ident = !{!10}
149+
150+
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 22.0.0git ([email protected]:dlav-sc/llvm-project.git 972928c7a5fecec79f36c6899f1df779d0a17202)", isOptimized: false, runtimeVersion: 0, splitDebugFilename: "riscv_relax_dwo_ranges.dwo", emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: GNU)
151+
!1 = !DIFile(filename: "riscv_relax_dwo_ranges.cpp", directory: "/root/test/dwarf/generate", checksumkind: CSK_MD5, checksum: "ea48d4b4acc770ff327714eaf1348b92")
152+
!2 = !{i32 7, !"Dwarf Version", i32 5}
153+
!3 = !{i32 2, !"Debug Info Version", i32 3}
154+
!4 = !{i32 1, !"wchar_size", i32 4}
155+
!5 = !{i32 1, !"target-abi", !"lp64d"}
156+
!6 = !{i32 6, !"riscv-isa", !7}
157+
!7 = !{!"rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zmmul1p0_zaamo1p0_zalrsc1p0_zca1p0_zcd1p0"}
158+
!8 = !{i32 7, !"frame-pointer", i32 2}
159+
!9 = !{i32 8, !"SmallDataLimit", i32 0}
160+
!10 = !{!"clang version 22.0.0git ([email protected]:dlav-sc/llvm-project.git 972928c7a5fecec79f36c6899f1df779d0a17202)"}
161+
!11 = distinct !DISubprogram(name: "square", linkageName: "_Z6squarei", scope: !1, file: !1, line: 3, type: !12, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !15)
162+
!12 = !DISubroutineType(types: !13)
163+
!13 = !{!14, !14}
164+
!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
165+
!15 = !{}
166+
!16 = !DILocalVariable(name: "num", arg: 1, scope: !11, file: !1, line: 3, type: !14)
167+
!17 = !DILocation(line: 3, column: 16, scope: !11)
168+
!18 = !DILocalVariable(name: "num1", scope: !11, file: !1, line: 4, type: !14)
169+
!19 = !DILocation(line: 4, column: 7, scope: !11)
170+
!20 = !DILocation(line: 4, column: 14, scope: !11)
171+
!21 = !DILocation(line: 5, column: 10, scope: !11)
172+
!22 = !DILocation(line: 5, column: 17, scope: !11)
173+
!23 = !DILocation(line: 5, column: 15, scope: !11)
174+
!24 = !DILocation(line: 5, column: 3, scope: !11)
175+
!25 = distinct !DISubprogram(name: "boo", linkageName: "_Z3boov", scope: !1, file: !1, line: 8, type: !26, scopeLine: 8, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
176+
!26 = !DISubroutineType(types: !27)
177+
!27 = !{!14}
178+
!28 = !DILocation(line: 9, column: 3, scope: !25)
179+
!29 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 12, type: !26, scopeLine: 12, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !15)
180+
!30 = !DILocalVariable(name: "a", scope: !29, file: !1, line: 13, type: !14)
181+
!31 = !DILocation(line: 13, column: 7, scope: !29)
182+
!32 = !DILocalVariable(name: "squared", scope: !29, file: !1, line: 14, type: !14)
183+
!33 = !DILocation(line: 14, column: 7, scope: !29)
184+
!34 = !DILocation(line: 14, column: 24, scope: !29)
185+
!35 = !DILocation(line: 14, column: 17, scope: !29)
186+
!36 = !DILocation(line: 15, column: 10, scope: !29)
187+
!37 = !DILocation(line: 15, column: 3, scope: !29)

0 commit comments

Comments
 (0)