Skip to content

[debuginfo][coro] Emit debug info labels for coroutine resume points #141937

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
24 changes: 16 additions & 8 deletions clang/docs/DebuggingCoroutines.rst
Original file line number Diff line number Diff line change
Expand Up @@ -311,17 +311,25 @@ variables in the C++ source.
Get the suspended points
========================

An important requirement for debugging coroutines is to understand suspended
points, which are where the coroutine is currently suspended and awaiting.
An important requirement for debugging coroutines is to understand at which
point a coroutine is currently suspended and awaiting.

For simple cases like the above, inspecting the value of the `__coro_index`
variable in the coroutine frame works well.
The value of the `__coro_index` inside a couroutine frame indicates the current
suspension point. To map this id back to a source code location, you can lookup
the source location of a special, compiler-generated label `__coro_suspend_<N>`.

However, it is not quite so simple in really complex situations. In these
cases, it is necessary to use the coroutine libraries to insert the
line-number.
::

For example:
(gdb) info line -function coro_task -label __coro_resume_2
Line 45 of "llvm-example.cpp" starts at address 0x1b1b <_ZL9coro_taski.resume+555> and ends at 0x1b46 <_ZL9coro_taski.resume+598>.
Line 45 of "llvm-example.cpp" starts at address 0x201b <_ZL9coro_taski.destroy+555> and ends at 0x2046 <_ZL9coro_taski.destroy+598>.
Line 45 of "llvm-example.cpp" starts at address 0x253b <_ZL9coro_taski.cleanup+555> and ends at 0x2566 <_ZL9coro_taski.cleanup+598>.

Older versions of LLVM/clang might not yet emit those labels, though. For
simple cases, you might still be able to guess the suspension point correctly.

Alternatively, you might also want to modify your coroutine library to store
the line number of the current suspension point in the promise:

.. code-block:: c++

Expand Down
5 changes: 3 additions & 2 deletions clang/lib/CodeGen/CGDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5292,8 +5292,9 @@ void CGDebugInfo::EmitLabel(const LabelDecl *D, CGBuilderTy &Builder) {
StringRef Name = D->getName();

// Create the descriptor for the label.
auto *L =
DBuilder.createLabel(Scope, Name, Unit, Line, CGM.getLangOpts().Optimize);
auto *L = DBuilder.createLabel(
Scope, Name, Unit, Line, Column, /*IsArtificial=*/false,
/*CoroSuspendIdx=*/std::nullopt, CGM.getLangOpts().Optimize);

// Insert an llvm.dbg.label into the current block.
DBuilder.insertLabel(L,
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CodeGen/debug-label-inline.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ int f2(void) {

// CHECK: distinct !DISubprogram(name: "f1", {{.*}}, retainedNodes: [[ELEMENTS:!.*]])
// CHECK: [[ELEMENTS]] = !{{{.*}}, [[LABEL_METADATA]]}
// CHECK: [[LABEL_METADATA]] = !DILabel({{.*}}, name: "top", {{.*}}, line: 8)
// CHECK: [[LABEL_METADATA]] = !DILabel({{.*}}, name: "top", {{.*}}, line: 8, column: 1)
// CHECK: [[INLINEDAT:!.*]] = distinct !DILocation(line: 18,
// CHECK: [[LABEL_LOCATION]] = !DILocation(line: 8, {{.*}}, inlinedAt: [[INLINEDAT]])
2 changes: 1 addition & 1 deletion clang/test/CodeGen/debug-label.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ int f1(int a, int b) {
return sum;
}

// CHECK: [[LABEL_METADATA]] = !DILabel({{.*}}, name: "top", {{.*}}, line: 9)
// CHECK: [[LABEL_METADATA]] = !DILabel({{.*}}, name: "top", {{.*}}, line: 9, column: 1)
// CHECK: [[LABEL_LOCATION]] = !DILocation(line: 9,
18 changes: 12 additions & 6 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6975,16 +6975,22 @@ appear in the included source file.
DILabel
"""""""

``DILabel`` nodes represent labels within a :ref:`DISubprogram`. All fields of
a ``DILabel`` are mandatory. The ``scope:`` field must be one of either a
:ref:`DILexicalBlockFile`, a :ref:`DILexicalBlock`, or a :ref:`DISubprogram`.
The ``name:`` field is the label identifier. The ``file:`` field is the
:ref:`DIFile` the label is present in. The ``line:`` field is the source line
``DILabel`` nodes represent labels within a :ref:`DISubprogram`. The ``scope:``
field must be one of either a :ref:`DILexicalBlockFile`, a
:ref:`DILexicalBlock`, or a :ref:`DISubprogram`. The ``name:`` field is the
label identifier. The ``file:`` field is the :ref:`DIFile` the label is
present in. The ``line:`` and ``column:`` field are the source line and column
within the file where the label is declared.

Furthermore, a label can be marked as artificial, i.e. compiler-generated,
using ``isArtificial:``. Such artitificial labels are generated, e.g., by
the ``CoroSplit`` pass. In addition, the ``CoroSplit`` pass also uses the
``coroSuspendIdx:`` field to identify the coroutine suspend points.

.. code-block:: text

!2 = !DILabel(scope: !0, name: "foo", file: !1, line: 7)
!2 = !DILabel(scope: !0, name: "foo", file: !1, line: 7, column: 4)
!3 = !DILabel(scope: !0, name: "__coro_resume_3", file: !1, line: 9, column: 3, isArtificial: true, coroSuspendIdx: 3)

DICommonBlock
"""""""""""""
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/BinaryFormat/Dwarf.def
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,7 @@ HANDLE_DW_AT(0x3e09, LLVM_ptrauth_authenticates_null_values, 0, LLVM)
HANDLE_DW_AT(0x3e0a, LLVM_ptrauth_authentication_mode, 0, LLVM)
HANDLE_DW_AT(0x3e0b, LLVM_num_extra_inhabitants, 0, LLVM)
HANDLE_DW_AT(0x3e0c, LLVM_stmt_sequence, 0, LLVM)
HANDLE_DW_AT(0x3e0d, LLVM_coro_suspend_idx, 0, LLVM)

// Apple extensions.

Expand Down
5 changes: 4 additions & 1 deletion llvm/include/llvm/IR/DIBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -901,7 +901,10 @@ namespace llvm {
/// \c Scope must be a \a DILocalScope, and thus its scope chain eventually
/// leads to a \a DISubprogram.
LLVM_ABI DILabel *createLabel(DIScope *Scope, StringRef Name, DIFile *File,
unsigned LineNo, bool AlwaysPreserve = false);
unsigned LineNo, unsigned Column,
bool IsArtificial,
std::optional<unsigned> CoroSuspendIdx,
bool AlwaysPreserve = false);

/// Create a new descriptor for a parameter variable.
///
Expand Down
43 changes: 30 additions & 13 deletions llvm/include/llvm/IR/DebugInfoMetadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -4104,35 +4104,49 @@ class DILabel : public DINode {
friend class LLVMContextImpl;
friend class MDNode;

DILabel(LLVMContext &C, StorageType Storage, unsigned Line,
unsigned Column;
std::optional<unsigned> CoroSuspendIdx;
bool IsArtificial;

DILabel(LLVMContext &C, StorageType Storage, unsigned Line, unsigned Column,
bool IsArtificial, std::optional<unsigned> CoroSuspendIdx,
ArrayRef<Metadata *> Ops);
~DILabel() = default;

static DILabel *getImpl(LLVMContext &Context, DIScope *Scope, StringRef Name,
DIFile *File, unsigned Line, StorageType Storage,
bool ShouldCreate = true) {
DIFile *File, unsigned Line, unsigned Column,
bool IsArtificial,
std::optional<unsigned> CoroSuspendIdx,
StorageType Storage, bool ShouldCreate = true) {
return getImpl(Context, Scope, getCanonicalMDString(Context, Name), File,
Line, Storage, ShouldCreate);
Line, Column, IsArtificial, CoroSuspendIdx, Storage,
ShouldCreate);
}
LLVM_ABI static DILabel *getImpl(LLVMContext &Context, Metadata *Scope,
MDString *Name, Metadata *File,
unsigned Line, StorageType Storage,
bool ShouldCreate = true);
LLVM_ABI static DILabel *
getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, Metadata *File,
unsigned Line, unsigned Column, bool IsArtificial,
std::optional<unsigned> CoroSuspendIdx, StorageType Storage,
bool ShouldCreate = true);

TempDILabel cloneImpl() const {
return getTemporary(getContext(), getScope(), getName(), getFile(),
getLine());
getLine(), getColumn(), isArtificial(),
getCoroSuspendIdx());
}

public:
DEFINE_MDNODE_GET(DILabel,
(DILocalScope * Scope, StringRef Name, DIFile *File,
unsigned Line),
(Scope, Name, File, Line))
unsigned Line, unsigned Column, bool IsArtificial,
std::optional<unsigned> CoroSuspendIdx),
(Scope, Name, File, Line, Column, IsArtificial,
CoroSuspendIdx))
DEFINE_MDNODE_GET(DILabel,
(Metadata * Scope, MDString *Name, Metadata *File,
unsigned Line),
(Scope, Name, File, Line))
unsigned Line, unsigned Column, bool IsArtificial,
std::optional<unsigned> CoroSuspendIdx),
(Scope, Name, File, Line, Column, IsArtificial,
CoroSuspendIdx))

TempDILabel clone() const { return cloneImpl(); }

Expand All @@ -4143,8 +4157,11 @@ class DILabel : public DINode {
return cast_or_null<DILocalScope>(getRawScope());
}
unsigned getLine() const { return SubclassData32; }
unsigned getColumn() const { return Column; }
StringRef getName() const { return getStringOperand(1); }
DIFile *getFile() const { return cast_or_null<DIFile>(getRawFile()); }
bool isArtificial() const { return IsArtificial; }
std::optional<unsigned> getCoroSuspendIdx() const { return CoroSuspendIdx; }

Metadata *getRawScope() const { return getOperand(0); }
MDString *getRawName() const { return getOperandAs<MDString>(1); }
Expand Down
14 changes: 11 additions & 3 deletions llvm/lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6116,18 +6116,26 @@ bool LLParser::parseDILocalVariable(MDNode *&Result, bool IsDistinct) {
}

/// parseDILabel:
/// ::= !DILabel(scope: !0, name: "foo", file: !1, line: 7)
/// ::= !DILabel(scope: !0, name: "foo", file: !1, line: 7, column: 4)
bool LLParser::parseDILabel(MDNode *&Result, bool IsDistinct) {
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
REQUIRED(scope, MDField, (/* AllowNull */ false)); \
REQUIRED(name, MDStringField, ); \
REQUIRED(file, MDField, ); \
REQUIRED(line, LineField, );
REQUIRED(line, LineField, ); \
OPTIONAL(column, ColumnField, ); \
OPTIONAL(isArtificial, MDBoolField, ); \
OPTIONAL(coroSuspendIdx, MDUnsignedField, );
PARSE_MD_FIELDS();
#undef VISIT_MD_FIELDS

std::optional<unsigned> CoroSuspendIdx =
coroSuspendIdx.Seen ? std::optional<unsigned>(coroSuspendIdx.Val)
: std::nullopt;

Result = GET_OR_DISTINCT(DILabel,
(Context, scope.Val, name.Val, file.Val, line.Val));
(Context, scope.Val, name.Val, file.Val, line.Val,
column.Val, isArtificial.Val, CoroSuspendIdx));
return false;
}

Expand Down
24 changes: 20 additions & 4 deletions llvm/lib/Bitcode/Reader/MetadataLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1133,6 +1133,7 @@ Error MetadataLoader::MetadataLoaderImpl::parseMetadata(bool ModuleLevel) {
++NumMDRecordLoaded;
if (Expected<unsigned> MaybeCode =
Stream.readRecord(Entry.ID, Record, &Blob)) {
// Crashes called from here!
if (Error Err = parseOneMetadata(Record, MaybeCode.get(), Placeholders,
Blob, NextMetadataNo))
return Err;
Expand Down Expand Up @@ -1319,6 +1320,7 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
unsigned Size = Record.size();
NamedMDNode *NMD = TheModule.getOrInsertNamedMetadata(Name);
for (unsigned i = 0; i != Size; ++i) {
// Crashes here!
MDNode *MD = MetadataList.getMDNodeFwdRefOrNull(Record[i]);
if (!MD)
return error("Invalid named metadata: expect fwd ref to MDNode");
Expand Down Expand Up @@ -2240,14 +2242,28 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
break;
}
case bitc::METADATA_LABEL: {
if (Record.size() != 5)
if (Record.size() < 5 || Record.size() > 7)
return error("Invalid record");

IsDistinct = Record[0] & 1;
uint64_t Line = Record[4];
uint64_t Column = Record.size() > 5 ? Record[5] : 0;
bool IsArtificial = Record[0] & 2;
std::optional<unsigned> CoroSuspendIdx;
if (Record.size() > 6) {
unsigned RawSuspendIdx = Record[6];
if (RawSuspendIdx != std::numeric_limits<unsigned>::max()) {
if (RawSuspendIdx > (uint64_t)std::numeric_limits<unsigned>::max())
return error("CoroSuspendIdx value is too large");
CoroSuspendIdx = RawSuspendIdx;
}
}

MetadataList.assignValue(
GET_OR_DISTINCT(DILabel, (Context, getMDOrNull(Record[1]),
getMDString(Record[2]),
getMDOrNull(Record[3]), Record[4])),
GET_OR_DISTINCT(DILabel,
(Context, getMDOrNull(Record[1]),
getMDString(Record[2]), getMDOrNull(Record[3]), Line,
Column, IsArtificial, CoroSuspendIdx)),
NextMetadataNo);
NextMetadataNo++;
break;
Expand Down
6 changes: 5 additions & 1 deletion llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2344,11 +2344,15 @@ void ModuleBitcodeWriter::writeDILocalVariable(
void ModuleBitcodeWriter::writeDILabel(
const DILabel *N, SmallVectorImpl<uint64_t> &Record,
unsigned Abbrev) {
Record.push_back((uint64_t)N->isDistinct());
uint64_t IsArtificialFlag = uint64_t(N->isArtificial()) << 1;
Record.push_back((uint64_t)N->isDistinct() | IsArtificialFlag);
Record.push_back(VE.getMetadataOrNullID(N->getScope()));
Record.push_back(VE.getMetadataOrNullID(N->getRawName()));
Record.push_back(VE.getMetadataOrNullID(N->getFile()));
Record.push_back(N->getLine());
Record.push_back(N->getColumn());
Record.push_back(
N->getCoroSuspendIdx().value_or(std::numeric_limits<uint64_t>::max()));

Stream.EmitRecord(bitc::METADATA_LABEL, Record, Abbrev);
Record.clear();
Expand Down
9 changes: 7 additions & 2 deletions llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ DIE *DwarfCompileUnit::getOrCreateCommonBlock(
addString(NDie, dwarf::DW_AT_name, Name);
addGlobalName(Name, NDie, CB->getScope());
if (CB->getFile())
addSourceLine(NDie, CB->getLineNo(), CB->getFile());
addSourceLine(NDie, CB->getLineNo(), /*Column*/ 0, CB->getFile());
if (DIGlobalVariable *V = CB->getDecl())
getCU().addLocationAttribute(&NDie, V, GlobalExprs);
return &NDie;
Expand Down Expand Up @@ -1404,7 +1404,7 @@ DIE *DwarfCompileUnit::constructImportedEntityDIE(
else
EntityDie = getDIE(Entity);
assert(EntityDie);
addSourceLine(*IMDie, Module->getLine(), Module->getFile());
addSourceLine(*IMDie, Module->getLine(), /*Column*/ 0, Module->getFile());
addDIEEntry(*IMDie, dwarf::DW_AT_import, *EntityDie);
StringRef Name = Module->getName();
if (!Name.empty()) {
Expand Down Expand Up @@ -1701,6 +1701,11 @@ void DwarfCompileUnit::applyLabelAttributes(const DbgLabel &Label,
addString(LabelDie, dwarf::DW_AT_name, Name);
const auto *DILabel = Label.getLabel();
addSourceLine(LabelDie, DILabel);
if (DILabel->isArtificial())
addFlag(LabelDie, dwarf::DW_AT_artificial);
if (DILabel->getCoroSuspendIdx())
addUInt(LabelDie, dwarf::DW_AT_LLVM_coro_suspend_idx, std::nullopt,
*DILabel->getCoroSuspendIdx());
}

/// Add a Dwarf expression attribute data and value.
Expand Down
18 changes: 11 additions & 7 deletions llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -442,49 +442,53 @@ void DwarfUnit::addBlock(DIE &Die, dwarf::Attribute Attribute,
addBlock(Die, Attribute, Block->BestForm(), Block);
}

void DwarfUnit::addSourceLine(DIE &Die, unsigned Line, const DIFile *File) {
void DwarfUnit::addSourceLine(DIE &Die, unsigned Line, unsigned Column,
const DIFile *File) {
if (Line == 0)
return;

unsigned FileID = getOrCreateSourceID(File);
addUInt(Die, dwarf::DW_AT_decl_file, std::nullopt, FileID);
addUInt(Die, dwarf::DW_AT_decl_line, std::nullopt, Line);

if (Column != 0)
addUInt(Die, dwarf::DW_AT_decl_column, std::nullopt, Column);
}

void DwarfUnit::addSourceLine(DIE &Die, const DILocalVariable *V) {
assert(V);

addSourceLine(Die, V->getLine(), V->getFile());
addSourceLine(Die, V->getLine(), /*Column*/ 0, V->getFile());
}

void DwarfUnit::addSourceLine(DIE &Die, const DIGlobalVariable *G) {
assert(G);

addSourceLine(Die, G->getLine(), G->getFile());
addSourceLine(Die, G->getLine(), /*Column*/ 0, G->getFile());
}

void DwarfUnit::addSourceLine(DIE &Die, const DISubprogram *SP) {
assert(SP);

addSourceLine(Die, SP->getLine(), SP->getFile());
addSourceLine(Die, SP->getLine(), /*Column*/ 0, SP->getFile());
}

void DwarfUnit::addSourceLine(DIE &Die, const DILabel *L) {
assert(L);

addSourceLine(Die, L->getLine(), L->getFile());
addSourceLine(Die, L->getLine(), L->getColumn(), L->getFile());
}

void DwarfUnit::addSourceLine(DIE &Die, const DIType *Ty) {
assert(Ty);

addSourceLine(Die, Ty->getLine(), Ty->getFile());
addSourceLine(Die, Ty->getLine(), /*Column*/ 0, Ty->getFile());
}

void DwarfUnit::addSourceLine(DIE &Die, const DIObjCProperty *Ty) {
assert(Ty);

addSourceLine(Die, Ty->getLine(), Ty->getFile());
addSourceLine(Die, Ty->getLine(), /*Column*/ 0, Ty->getFile());
}

void DwarfUnit::addConstantFPValue(DIE &Die, const ConstantFP *CFP) {
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,8 @@ class DwarfUnit : public DIEUnit {
DIEBlock *Block);

/// Add location information to specified debug information entry.
void addSourceLine(DIE &Die, unsigned Line, const DIFile *File);
void addSourceLine(DIE &Die, unsigned Line, unsigned Column,
const DIFile *File);
void addSourceLine(DIE &Die, const DILocalVariable *V);
void addSourceLine(DIE &Die, const DIGlobalVariable *G);
void addSourceLine(DIE &Die, const DISubprogram *SP);
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/CodeGen/LiveDebugVariables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,7 @@ static void printExtendedName(raw_ostream &OS, const DINode *Node,
Res = V->getName();
Line = V->getLine();
} else if (const auto *L = dyn_cast<const DILabel>(Node)) {
// XXX what are we doing here? Adjust it?
Res = L->getName();
Line = L->getLine();
}
Expand Down
Loading
Loading