LLVM 23.0.0git
NVPTXDwarfDebug.cpp
Go to the documentation of this file.
1//===-- NVPTXDwarfDebug.cpp - NVPTX DwarfDebug Implementation ------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements helper functions for NVPTX-specific debug information
10// processing.
11//
12//===----------------------------------------------------------------------===//
13
14#include "NVPTXDwarfDebug.h"
15#include "NVPTXSubtarget.h"
19#include "llvm/IR/Function.h"
20#include "llvm/MC/MCAsmInfo.h"
21#include "llvm/MC/MCContext.h"
22#include "llvm/MC/MCStreamer.h"
25
26using namespace llvm;
27
28// Command line option to control inlined_at enhancement to lineinfo support.
29// Valid only when debuginfo emissionkind is DebugDirectivesOnly or
30// LineTablesOnly.
32 "line-info-inlined-at",
33 cl::desc("Emit line with inlined_at enhancement for NVPTX"), cl::init(true),
35
37
38/// NVPTX-specific source line recording with inlined_at support.
39///
40/// Why this exists:
41/// NVPTX supports an "enhanced lineinfo" mode where inlining context is carried
42/// via line-table directives, rather than full DWARF DIEs. This is conceptually
43/// similar to proposals[1] for richer DWARF line tables that carry inline call
44/// context and callee identity in the line table. NVPTX implements this via
45/// target-specific `.loc` extensions in the PTX ISA[3].
46///
47/// How it impacts PTX assembly generation:
48/// - When enabled (PTX ISA >= 7.2 + line-tables-only / debug-directives-only),
49/// we emit multiple consecutive `.loc` directives for a single inlined
50/// instruction: the instruction's own location and its `inlined_at` parent
51/// chain.
52/// - During emission we use `MCStreamer::emitDwarfLocDirectiveWithInlinedAt` to
53/// emit an enhanced `.loc` directive[3] that carries the extra
54/// `function_name` and `inlined_at` operands in the PTX assembly stream.
55///
56/// Example (conceptual PTX `.loc` sequence for an inlined callsite):
57/// .loc 1 16 3 // caller location
58/// .loc 1 5 3, function_name $L__info_stringN, inlined_at 1 16 3
59/// // inlined callee location
60/// Here, $L__info_stringN is a label (or label+immediate) referring into
61/// `.debug_str`.
62///
63/// How this impacts DWARF :
64/// DWARF generation tools that consume this PTX(e.g. ptxas assembler) can use
65/// the `inlined_at` and `function_name` operands to extend the DWARF v2
66/// line table information.
67/// This adds:
68/// - a `context` column[2]: the `inlined_at <file> <line> <col>` information
69/// populates an inlining "context" (a reference to the parent/callsite row)
70/// enabling reconstruction of inline call chains from the line table.
71/// - a `function_name` column[2]: the `.loc ... function_name <sym>` identifies
72/// the inlined callee associated with a non-zero context.
73///
74/// References:
75/// - [1] DWARF line tables / Two-Level Line Tables:
76/// https://wiki.dwarfstd.org/TwoLevelLineTables.md
77/// - [2] DWARF issue tracking for Two-Level Line Tables:
78/// https://dwarfstd.org/issues/140906.1.html
79/// - [3] NVIDIA PTX ISA `.loc` (debugging directives; PTX ISA 7.2+):
80/// https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#debugging-directives-loc
82 unsigned Flags) {
83 // Maintain a work list of .loc to be emitted. If we are emitting the
84 // inlined_at directive, we might need to emit additional .loc prior
85 // to it for the location contained in the inlined_at.
88 const DILocation *EmitLoc = DL.get();
89
90 if (!EmitLoc)
91 return;
92
93 const MachineFunction *MF = Asm->MF;
94 if (!MF)
95 return;
96
97 const DISubprogram *SP = MF->getFunction().getSubprogram();
98 const NVPTXSubtarget &STI = MF->getSubtarget<NVPTXSubtarget>();
99 const bool EnhancedLineinfo =
100 LineInfoWithInlinedAt && (STI.getPTXVersion() >= 72) && SP &&
101 (SP->getUnit()->isDebugDirectivesOnly() ||
102 SP->getUnit()->getEmissionKind() == DICompileUnit::LineTablesOnly);
103
104 while (EmitLoc) {
105 // Get the scope for the current location.
106 const DIScope *Scope = EmitLoc->getScope();
107 if (!Scope)
108 break; // scope is null, we are done.
109
110 // Check if this loc is already in work list, if so, we are done.
111 if (WorkListSet.contains(EmitLoc))
112 break;
113
114 // Add this location to the work list.
115 WorkList.push_back(EmitLoc);
116 WorkListSet.insert(EmitLoc);
117
118 if (!EnhancedLineinfo) // No enhanced lineinfo, we are done.
119 break;
120
121 const DILocation *IA = EmitLoc->getInlinedAt();
122 // Check if this has inlined_at information, and if the parent location
123 // has not yet been emitted. If already emitted, we don't need to
124 // re-emit the parent chain.
125 if (IA && !EmittedInlinedAtLocs.contains(IA))
126 EmitLoc = IA;
127 else // We are done.
128 break;
129 }
130
131 const unsigned CUID = Asm->OutStreamer->getContext().getDwarfCompileUnitID();
132 // Traverse the work list, and emit .loc.
133 while (!WorkList.empty()) {
134 const DILocation *Current = WorkList.pop_back_val();
135 const DIScope *Scope = Current->getScope();
136
137 if (!Scope)
138 llvm_unreachable("we shouldn't be here for null scope");
139
140 const DILocation *InlinedAt = Current->getInlinedAt();
141 StringRef Fn = Scope->getFilename();
142 const unsigned Line = Current->getLine();
143 const unsigned Col = Current->getColumn();
144 unsigned Discriminator = 0;
145 if (Line != 0 && getDwarfVersion() >= 4)
146 if (const DILexicalBlockFile *LBF = dyn_cast<DILexicalBlockFile>(Scope))
147 Discriminator = LBF->getDiscriminator();
148
149 const unsigned FileNo = static_cast<DwarfCompileUnit &>(*getUnits()[CUID])
150 .getOrCreateSourceID(Scope->getFile());
151
152 if (EnhancedLineinfo && InlinedAt) {
153 const unsigned FileIA = static_cast<DwarfCompileUnit &>(*getUnits()[CUID])
154 .getOrCreateSourceID(InlinedAt->getFile());
155 const DISubprogram *SubProgram = getDISubprogram(Current->getScope());
156 DwarfStringPoolEntryRef Entry = InfoHolder.getStringPool().getEntry(
157 *Asm, SubProgram->getLinkageName());
158 Asm->OutStreamer->emitDwarfLocDirectiveWithInlinedAt(
159 FileNo, Line, Col, FileIA, InlinedAt->getLine(),
160 InlinedAt->getColumn(), Entry.getSymbol(), Flags, 0, Discriminator,
161 Fn);
162 } else {
163 Asm->OutStreamer->emitDwarfLocDirective(FileNo, Line, Col, Flags, 0,
164 Discriminator, Fn);
165 }
166 // Mark this location as emitted so we don't re-emit the parent chain
167 // for subsequent instructions that share the same inlined_at parent.
168 if (EnhancedLineinfo)
169 EmittedInlinedAtLocs.insert(Current);
170 }
171}
172
173/// NVPTX-specific debug info initialization.
175 // Clear the set of emitted inlined_at locations for each new function.
176 EmittedInlinedAtLocs.clear();
177}
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static cl::opt< bool > LineInfoWithInlinedAt("line-info-inlined-at", cl::desc("Emit line with inlined_at enhancement for NVPTX"), cl::init(true), cl::Hidden)
This class is intended to be used as a driving class for all asm writers.
Definition AsmPrinter.h:91
Base class for scope-like contexts.
Subprogram description. Uses SubclassData1.
AsmPrinter * Asm
Target of debug info emission.
A debug info location.
Definition DebugLoc.h:123
uint16_t getDwarfVersion() const
Returns the Dwarf Version.
const SmallVectorImpl< std::unique_ptr< DwarfCompileUnit > > & getUnits()
Definition DwarfDebug.h:727
DwarfFile InfoHolder
Holder for the file specific debug information.
Definition DwarfDebug.h:708
DwarfDebug(AsmPrinter *A)
DwarfStringPoolEntryRef: Dwarf string pool entry reference.
DISubprogram * getSubprogram() const
Get the attached subprogram.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Function & getFunction()
Return the LLVM function that this machine code represents.
void recordTargetSourceLine(const DebugLoc &DL, unsigned Flags) override
Override to record source line information with inlined_at support.
NVPTXDwarfDebug(AsmPrinter *A)
Constructor - Pass through to DwarfDebug constructor.
void initializeTargetDebugInfo(const MachineFunction &MF) override
Override to collect inlined_at locations.
unsigned getPTXVersion() const
Implements a dense probed hash-table based set with some number of buckets stored inline.
Definition DenseSet.h:291
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
std::pair< iterator, bool > insert(const ValueT &V)
Definition DenseSet.h:202
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
Definition DenseSet.h:175
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
LLVM_ABI DISubprogram * getDISubprogram(const MDNode *Scope)
Find subprogram that is enclosing this scope.