Skip to content

Commit 3402f2a

Browse files
author
Alex B
committed
[DebugInfo] Add subprogram attr pointing to its line entries
1 parent 3864bfd commit 3402f2a

File tree

8 files changed

+176
-9
lines changed

8 files changed

+176
-9
lines changed

llvm/include/llvm/BinaryFormat/Dwarf.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,8 @@ HANDLE_DW_AT(0x2904, GO_runtime_type, 0, GO)
578578

579579
HANDLE_DW_AT(0x3210, UPC_threads_scaled, 0, UPC)
580580

581+
HANDLE_DW_AT(0x3600, META_stmt_sequence, 0, META)
582+
581583
HANDLE_DW_AT(0x393e, IBM_wsa_addr, 0, IBM)
582584
HANDLE_DW_AT(0x393f, IBM_home_location, 0, IBM)
583585
HANDLE_DW_AT(0x3940, IBM_alt_srcview, 0, IBM)

llvm/include/llvm/BinaryFormat/Dwarf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ enum LLVMConstants : uint32_t {
8484
DWARF_VENDOR_PGI,
8585
DWARF_VENDOR_SUN,
8686
DWARF_VENDOR_UPC,
87+
DWARF_VENDOR_META,
8788
///\}
8889
};
8990

llvm/include/llvm/MC/MCDwarf.h

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ class MCDwarfLoc {
122122
private: // MCContext manages these
123123
friend class MCContext;
124124
friend class MCDwarfLineEntry;
125+
// DwarfDebug::endFunctionImpl needs to construct MCDwarfLoc(IsEndOfFunction)
126+
friend class DwarfDebug;
125127

126128
MCDwarfLoc(unsigned fileNum, unsigned line, unsigned column, unsigned flags,
127129
unsigned isa, unsigned discriminator)
@@ -194,14 +196,27 @@ class MCDwarfLineEntry : public MCDwarfLoc {
194196

195197
public:
196198
// Constructor to create an MCDwarfLineEntry given a symbol and the dwarf loc.
197-
MCDwarfLineEntry(MCSymbol *label, const MCDwarfLoc loc)
198-
: MCDwarfLoc(loc), Label(label) {}
199+
MCDwarfLineEntry(MCSymbol *label, const MCDwarfLoc loc,
200+
bool isEndOfFunction = false,
201+
MCSymbol *streamLabel = nullptr)
202+
: MCDwarfLoc(loc), Label(label), IsEndOfFunction(isEndOfFunction),
203+
StreamLabel(streamLabel) {}
199204

200205
MCSymbol *getLabel() const { return Label; }
201206

202207
// This indicates the line entry is synthesized for an end entry.
203208
bool IsEndEntry = false;
204209

210+
// This indicates that the current line entry denotes the end of a function,
211+
// it is used to emit a DW_LNE_end_sequnece to reset the state machine
212+
// registers.
213+
bool IsEndOfFunction;
214+
215+
// Optional symbol to be emitted just before the line is written into the
216+
// output stream. It can be used to reference the position of the start of
217+
// this line's data in the output stream.
218+
MCSymbol *StreamLabel;
219+
205220
// Override the label with the given EndLabel.
206221
void setEndLabel(MCSymbol *EndLabel) {
207222
Label = EndLabel;
@@ -227,7 +242,7 @@ class MCLineSection {
227242

228243
// Add an end entry by cloning the last entry, if exists, for the section
229244
// the given EndLabel belongs to. The label is replaced by the given EndLabel.
230-
void addEndEntry(MCSymbol *EndLabel);
245+
void addEndEntry(MCSymbol *EndLabel, bool generatingFuncLineTableOffsets);
231246

232247
using MCDwarfLineEntryCollection = std::vector<MCDwarfLineEntry>;
233248
using iterator = MCDwarfLineEntryCollection::iterator;

llvm/include/llvm/MC/MCStreamer.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,15 @@ class MCStreamer {
254254
/// discussion for future inclusion.
255255
bool AllowAutoPadding = false;
256256

257+
// Flag specyfing weather functions will have an offset into the line table
258+
// where the line data for that function starts
259+
bool GenerateFuncLineTableOffsets = false;
260+
261+
// Symbol that tracks the stream symbol for first line of the current function
262+
// being generated. This symbol can be used to reference where the line
263+
// entries for the function start in the generated line table.
264+
MCSymbol *CurrentFuncFirstLineStreamSym;
265+
257266
protected:
258267
MCStreamer(MCContext &Ctx);
259268

@@ -310,6 +319,24 @@ class MCStreamer {
310319
void setAllowAutoPadding(bool v) { AllowAutoPadding = v; }
311320
bool getAllowAutoPadding() const { return AllowAutoPadding; }
312321

322+
void setGenerateFuncLineTableOffsets(bool v) {
323+
GenerateFuncLineTableOffsets = v;
324+
}
325+
bool getGenerateFuncLineTableOffsets() const {
326+
return GenerateFuncLineTableOffsets;
327+
}
328+
329+
// Use the below functions to track the symbol that points to the current
330+
// function's line info in the output stream.
331+
void beginFunction() { CurrentFuncFirstLineStreamSym = nullptr; }
332+
void emittedLineStreamSym(MCSymbol *StreamSym) {
333+
if (!CurrentFuncFirstLineStreamSym)
334+
CurrentFuncFirstLineStreamSym = StreamSym;
335+
}
336+
MCSymbol *getCurrentFuncFirstLineStreamSym() {
337+
return CurrentFuncFirstLineStreamSym;
338+
}
339+
313340
/// When emitting an object file, create and emit a real label. When emitting
314341
/// textual assembly, this should do nothing to avoid polluting our output.
315342
virtual MCSymbol *emitCFILabel();

llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,14 @@ DIE &DwarfCompileUnit::updateSubprogramScopeDIE(const DISubprogram *SP) {
526526
*DD->getCurrentFunction()))
527527
addFlag(*SPDie, dwarf::DW_AT_APPLE_omit_frame_ptr);
528528

529+
if (Asm->OutStreamer->getGenerateFuncLineTableOffsets() &&
530+
Asm->OutStreamer->getCurrentFuncFirstLineStreamSym()) {
531+
addSectionLabel(
532+
*SPDie, dwarf::DW_AT_META_stmt_sequence,
533+
Asm->OutStreamer->getCurrentFuncFirstLineStreamSym(),
534+
Asm->getObjFileLowering().getDwarfLineSection()->getBeginSymbol());
535+
}
536+
529537
// Only include DW_AT_frame_base in full debug info
530538
if (!includeMinimalInlineScopes()) {
531539
const TargetFrameLowering *TFI = Asm->MF->getSubtarget().getFrameLowering();

llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,12 @@ static cl::opt<DwarfDebug::MinimizeAddrInV5> MinimizeAddrInV5Option(
170170
"Stuff")),
171171
cl::init(DwarfDebug::MinimizeAddrInV5::Default));
172172

173+
static cl::opt<bool> EmitFuncLineTableOffsetsOption(
174+
"emit-func-debug-line-table-offsets", cl::Hidden,
175+
cl::desc("Include line table offset in function's debug info and emit end "
176+
"sequence after each function's line data."),
177+
cl::init(false));
178+
173179
static constexpr unsigned ULEB128PadSize = 4;
174180

175181
void DebugLocDwarfExpression::emitOp(uint8_t Op, const char *Comment) {
@@ -440,6 +446,8 @@ DwarfDebug::DwarfDebug(AsmPrinter *A)
440446
Asm->OutStreamer->getContext().setDwarfVersion(DwarfVersion);
441447
Asm->OutStreamer->getContext().setDwarfFormat(Dwarf64 ? dwarf::DWARF64
442448
: dwarf::DWARF32);
449+
Asm->OutStreamer->setGenerateFuncLineTableOffsets(
450+
EmitFuncLineTableOffsetsOption);
443451
}
444452

445453
// Define out of line so we don't have to include DwarfUnit.h in DwarfDebug.h.
@@ -2222,6 +2230,10 @@ void DwarfDebug::beginFunctionImpl(const MachineFunction *MF) {
22222230
if (SP->getUnit()->getEmissionKind() == DICompileUnit::NoDebug)
22232231
return;
22242232

2233+
// Notify the streamer that we are beginning a function - this will reset the
2234+
// label pointing to the currently generated function's first line entry
2235+
Asm->OutStreamer->beginFunction();
2236+
22252237
DwarfCompileUnit &CU = getOrCreateDwarfCompileUnit(SP->getUnit());
22262238

22272239
Asm->OutStreamer->getContext().setDwarfCompileUnitID(
@@ -2250,7 +2262,8 @@ void DwarfDebug::terminateLineTable(const DwarfCompileUnit *CU) {
22502262
getDwarfCompileUnitIDForLineTable(*CU));
22512263
// Add the last range label for the given CU.
22522264
LineTable.getMCLineSections().addEndEntry(
2253-
const_cast<MCSymbol *>(CURanges.back().End));
2265+
const_cast<MCSymbol *>(CURanges.back().End),
2266+
EmitFuncLineTableOffsetsOption);
22542267
}
22552268

22562269
void DwarfDebug::skippedNonDebugFunction() {
@@ -2343,6 +2356,21 @@ void DwarfDebug::endFunctionImpl(const MachineFunction *MF) {
23432356
// Construct call site entries.
23442357
constructCallSiteEntryDIEs(*SP, TheCU, ScopeDIE, *MF);
23452358

2359+
// If we're emitting line table offsets, we also need to emit an end label
2360+
// after all function's line entries
2361+
if (EmitFuncLineTableOffsetsOption) {
2362+
MCSymbol *LineSym = Asm->OutStreamer->getContext().createTempSymbol();
2363+
Asm->OutStreamer->emitLabel(LineSym);
2364+
MCDwarfLoc DwarfLoc(
2365+
1, 1, 0, DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0, 0, 0);
2366+
MCDwarfLineEntry LineEntry(LineSym, DwarfLoc, /*IsEndOfFunction*/ true);
2367+
Asm->OutStreamer->getContext()
2368+
.getMCDwarfLineTable(
2369+
Asm->OutStreamer->getContext().getDwarfCompileUnitID())
2370+
.getMCLineSections()
2371+
.addLineEntry(LineEntry, Asm->OutStreamer->getCurrentSectionOnly());
2372+
}
2373+
23462374
// Clear debug info
23472375
// Ownership of DbgVariables is a bit subtle - ScopeVariables owns all the
23482376
// DbgVariables except those that are also in AbstractVariables (since they

llvm/lib/MC/MCDwarf.cpp

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,18 @@ void MCDwarfLineEntry::make(MCStreamer *MCOS, MCSection *Section) {
103103
// Get the current .loc info saved in the context.
104104
const MCDwarfLoc &DwarfLoc = MCOS->getContext().getCurrentDwarfLoc();
105105

106+
MCSymbol *StreamLabel = nullptr;
107+
// If functions need offsets into the generated line table, then we need to
108+
// create a label referencing where the line was generated in the output
109+
// stream
110+
if (MCOS->getGenerateFuncLineTableOffsets()) {
111+
StreamLabel = MCOS->getContext().createTempSymbol();
112+
MCOS->emittedLineStreamSym(StreamLabel);
113+
}
114+
106115
// Create a (local) line entry with the symbol and the current .loc info.
107-
MCDwarfLineEntry LineEntry(LineSym, DwarfLoc);
116+
MCDwarfLineEntry LineEntry(LineSym, DwarfLoc, /*isEndOfFunction=*/false,
117+
StreamLabel);
108118

109119
// clear DwarfLocSeen saying the current .loc info is now used.
110120
MCOS->getContext().clearDwarfLocSeen();
@@ -144,7 +154,8 @@ makeStartPlusIntExpr(MCContext &Ctx, const MCSymbol &Start, int IntVal) {
144154
return Res;
145155
}
146156

147-
void MCLineSection::addEndEntry(MCSymbol *EndLabel) {
157+
void MCLineSection::addEndEntry(MCSymbol *EndLabel,
158+
bool generatingFuncLineTableOffsets) {
148159
auto *Sec = &EndLabel->getSection();
149160
// The line table may be empty, which we should skip adding an end entry.
150161
// There are two cases:
@@ -157,8 +168,12 @@ void MCLineSection::addEndEntry(MCSymbol *EndLabel) {
157168
if (I != MCLineDivisions.end()) {
158169
auto &Entries = I->second;
159170
auto EndEntry = Entries.back();
160-
EndEntry.setEndLabel(EndLabel);
161-
Entries.push_back(EndEntry);
171+
// If generatingFuncLineTableOffsets is set, then we already generated an
172+
// end label at the end of the last function, so skip generating another one
173+
if (!generatingFuncLineTableOffsets) {
174+
EndEntry.setEndLabel(EndLabel);
175+
Entries.push_back(EndEntry);
176+
}
162177
}
163178
}
164179

@@ -187,8 +202,11 @@ void MCDwarfLineTable::emitOne(
187202
bool EndEntryEmitted = false;
188203
for (const MCDwarfLineEntry &LineEntry : LineEntries) {
189204
MCSymbol *Label = LineEntry.getLabel();
205+
if (LineEntry.StreamLabel && MCOS->getGenerateFuncLineTableOffsets()) {
206+
MCOS->emitLabel(LineEntry.StreamLabel);
207+
}
190208
const MCAsmInfo *asmInfo = MCOS->getContext().getAsmInfo();
191-
if (LineEntry.IsEndEntry) {
209+
if (LineEntry.IsEndEntry || LineEntry.IsEndOfFunction) {
192210
MCOS->emitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, Label,
193211
asmInfo->getCodePointerSize());
194212
init();
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
; RUN: llc -mtriple=i686-w64-mingw32 -o %t -filetype=obj %s
2+
; RUN: llvm-dwarfdump -v -all %t | FileCheck %s -check-prefix=NO_STMT_SEQ
3+
4+
; RUN: llc -mtriple=i686-w64-mingw32 -o %t -filetype=obj %s -emit-func-debug-line-table-offsets
5+
; RUN: llvm-dwarfdump -v -all %t | FileCheck %s -check-prefix=STMT_SEQ
6+
7+
; NO_STMT_SEQ-NOT: DW_AT_META_stmt_sequence
8+
9+
; STMT_SEQ: [2] DW_TAG_subprogram
10+
; STMT_SEQ: DW_AT_META_stmt_sequence DW_FORM_sec_offset
11+
; STMT_SEQ: DW_TAG_subprogram [2]
12+
; STMT_SEQ: DW_AT_META_stmt_sequence [DW_FORM_sec_offset] (0x00000028)
13+
; STMT_SEQ: DW_AT_name {{.*}}func01
14+
; STMT_SEQ: DW_TAG_subprogram [2]
15+
; STMT_SEQ: DW_AT_META_stmt_sequence [DW_FORM_sec_offset] (0x00000038)
16+
; STMT_SEQ: DW_AT_name {{.*}}main
17+
18+
; generated from:
19+
; clang -g -S -emit-llvm test.c -o test.ll
20+
; ======= test.c ======
21+
; int func01() {
22+
; return 1;
23+
; }
24+
; int main() {
25+
; return 0;
26+
; }
27+
; =====================
28+
29+
30+
; ModuleID = 'test.c'
31+
source_filename = "test.c"
32+
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
33+
target triple = "arm64-apple-macosx14.0.0"
34+
35+
; Function Attrs: noinline nounwind optnone ssp uwtable(sync)
36+
define i32 @func01() #0 !dbg !9 {
37+
ret i32 1, !dbg !13
38+
}
39+
40+
; Function Attrs: noinline nounwind optnone ssp uwtable(sync)
41+
define i32 @main() #0 !dbg !14 {
42+
%1 = alloca i32, align 4
43+
store i32 0, ptr %1, align 4
44+
ret i32 0, !dbg !15
45+
}
46+
47+
attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" }
48+
49+
!llvm.dbg.cu = !{!0}
50+
!llvm.module.flags = !{!2, !3, !4, !5, !6, !7}
51+
!llvm.ident = !{!8}
52+
53+
!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "Homebrew clang version 17.0.6", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk", sdk: "MacOSX14.sdk")
54+
!1 = !DIFile(filename: "test.c", directory: "/tmp/clang_test")
55+
!2 = !{i32 7, !"Dwarf Version", i32 4}
56+
!3 = !{i32 2, !"Debug Info Version", i32 3}
57+
!4 = !{i32 1, !"wchar_size", i32 4}
58+
!5 = !{i32 8, !"PIC Level", i32 2}
59+
!6 = !{i32 7, !"uwtable", i32 1}
60+
!7 = !{i32 7, !"frame-pointer", i32 1}
61+
!8 = !{!"Homebrew clang version 17.0.6"}
62+
!9 = distinct !DISubprogram(name: "func01", scope: !1, file: !1, line: 1, type: !10, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0)
63+
!10 = !DISubroutineType(types: !11)
64+
!11 = !{!12}
65+
!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
66+
!13 = !DILocation(line: 2, column: 3, scope: !9)
67+
!14 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 5, type: !10, scopeLine: 5, spFlags: DISPFlagDefinition, unit: !0)
68+
!15 = !DILocation(line: 6, column: 3, scope: !14)

0 commit comments

Comments
 (0)