diff --git a/clang/docs/DebuggingCoroutines.rst b/clang/docs/DebuggingCoroutines.rst index c47579bc62e51..c221b2ec9c19b 100644 --- a/clang/docs/DebuggingCoroutines.rst +++ b/clang/docs/DebuggingCoroutines.rst @@ -209,9 +209,24 @@ important. This member identifies the suspension point at which the coroutine is currently suspended. However, it is non-trivial to map this number back to a source code location. -In simple cases, one might correctly guess the source code location. In more -complex cases, we can modify the C++ code to store additional information in -the promise type: +The compiler emits debug info labels for the suspension points. This allows us +to map the suspension point index back to a source code location. In gdb, we +can use the ``info line`` command to get the source code location of the +suspension point. + +:: + + (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>. + +LLDB does not support looking up labels. Furthmore, those labels are only emitted +starting with clang 21.0. + +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++ @@ -221,8 +236,6 @@ the promise type: void* _coro_return_address = nullptr; }; - #include - // For all the awaiter types we need: class awaiter { ... diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 7ab0e2fdaa731..3ff189297c546 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -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, diff --git a/clang/test/CodeGen/debug-label-inline.c b/clang/test/CodeGen/debug-label-inline.c index 972a32b5af32d..9d92ffb5ef61f 100644 --- a/clang/test/CodeGen/debug-label-inline.c +++ b/clang/test/CodeGen/debug-label-inline.c @@ -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]]) diff --git a/clang/test/CodeGen/debug-label.c b/clang/test/CodeGen/debug-label.c index 662b1a7dd2062..308d664ab712b 100644 --- a/clang/test/CodeGen/debug-label.c +++ b/clang/test/CodeGen/debug-label.c @@ -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, diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index d77c659055236..5f95b30652b2d 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -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 """"""""""""" diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.def b/llvm/include/llvm/BinaryFormat/Dwarf.def index 9cccea4fcaa58..48b33478d5045 100644 --- a/llvm/include/llvm/BinaryFormat/Dwarf.def +++ b/llvm/include/llvm/BinaryFormat/Dwarf.def @@ -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. diff --git a/llvm/include/llvm/IR/DIBuilder.h b/llvm/include/llvm/IR/DIBuilder.h index 99f7491b1b9b5..17a4e237342e1 100644 --- a/llvm/include/llvm/IR/DIBuilder.h +++ b/llvm/include/llvm/IR/DIBuilder.h @@ -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 CoroSuspendIdx, + bool AlwaysPreserve = false); /// Create a new descriptor for a parameter variable. /// diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h index f80e44ce3abbc..559a18033ad81 100644 --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -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 CoroSuspendIdx; + bool IsArtificial; + + DILabel(LLVMContext &C, StorageType Storage, unsigned Line, unsigned Column, + bool IsArtificial, std::optional CoroSuspendIdx, ArrayRef 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 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 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 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 CoroSuspendIdx), + (Scope, Name, File, Line, Column, IsArtificial, + CoroSuspendIdx)) TempDILabel clone() const { return cloneImpl(); } @@ -4143,8 +4157,11 @@ class DILabel : public DINode { return cast_or_null(getRawScope()); } unsigned getLine() const { return SubclassData32; } + unsigned getColumn() const { return Column; } StringRef getName() const { return getStringOperand(1); } DIFile *getFile() const { return cast_or_null(getRawFile()); } + bool isArtificial() const { return IsArtificial; } + std::optional getCoroSuspendIdx() const { return CoroSuspendIdx; } Metadata *getRawScope() const { return getOperand(0); } MDString *getRawName() const { return getOperandAs(1); } diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index c5e166cef6da6..168ad5a575064 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -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 CoroSuspendIdx = + coroSuspendIdx.Seen ? std::optional(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; } diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp index a9467d16c9a14..eed35d8d38440 100644 --- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -1133,6 +1133,7 @@ Error MetadataLoader::MetadataLoaderImpl::parseMetadata(bool ModuleLevel) { ++NumMDRecordLoaded; if (Expected MaybeCode = Stream.readRecord(Entry.ID, Record, &Blob)) { + // Crashes called from here! if (Error Err = parseOneMetadata(Record, MaybeCode.get(), Placeholders, Blob, NextMetadataNo)) return Err; @@ -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"); @@ -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 CoroSuspendIdx; + if (Record.size() > 6) { + unsigned RawSuspendIdx = Record[6]; + if (RawSuspendIdx != std::numeric_limits::max()) { + if (RawSuspendIdx > (uint64_t)std::numeric_limits::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; diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index 2a2dd085a9461..0e962056b8dbd 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -2344,11 +2344,15 @@ void ModuleBitcodeWriter::writeDILocalVariable( void ModuleBitcodeWriter::writeDILabel( const DILabel *N, SmallVectorImpl &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::max())); Stream.EmitRecord(bitc::METADATA_LABEL, Record, Abbrev); Record.clear(); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index a20c374e08935..8e8cda4eef573 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -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; @@ -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()) { @@ -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. diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index 9bd337a962b86..b03fac2d22a52 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -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) { diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h index 43bf197563867..fe05766cf36e1 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -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); diff --git a/llvm/lib/CodeGen/LiveDebugVariables.cpp b/llvm/lib/CodeGen/LiveDebugVariables.cpp index f12f437c493e1..83b179499decb 100644 --- a/llvm/lib/CodeGen/LiveDebugVariables.cpp +++ b/llvm/lib/CodeGen/LiveDebugVariables.cpp @@ -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(Node)) { + // XXX what are we doing here? Adjust it? Res = L->getName(); Line = L->getLine(); } diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index 7828ba45ec27f..306c684431b5c 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -2611,6 +2611,11 @@ static void writeDILabel(raw_ostream &Out, const DILabel *N, Printer.printString("name", N->getName()); Printer.printMetadata("file", N->getRawFile()); Printer.printInt("line", N->getLine()); + Printer.printInt("column", N->getColumn()); + Printer.printBool("isArtificial", N->isArtificial(), false); + if (N->getCoroSuspendIdx()) + Printer.printInt("coroSuspendIdx", *N->getCoroSuspendIdx(), + /* ShouldSkipZero */ false); Out << ")"; } diff --git a/llvm/lib/IR/DIBuilder.cpp b/llvm/lib/IR/DIBuilder.cpp index 6001ed421183b..c871edaaec973 100644 --- a/llvm/lib/IR/DIBuilder.cpp +++ b/llvm/lib/IR/DIBuilder.cpp @@ -946,9 +946,13 @@ DILocalVariable *DIBuilder::createParameterVariable( } DILabel *DIBuilder::createLabel(DIScope *Context, StringRef Name, DIFile *File, - unsigned LineNo, bool AlwaysPreserve) { + unsigned LineNo, unsigned Column, + bool IsArtificial, + std::optional CoroSuspendIdx, + bool AlwaysPreserve) { auto *Scope = cast(Context); - auto *Node = DILabel::get(VMContext, Scope, Name, File, LineNo); + auto *Node = DILabel::get(VMContext, Scope, Name, File, LineNo, Column, + IsArtificial, CoroSuspendIdx); if (AlwaysPreserve) { /// The optimizer may remove labels. If there is an interest diff --git a/llvm/lib/IR/DebugInfo.cpp b/llvm/lib/IR/DebugInfo.cpp index ecb19fd3c82db..220a1e397ca7c 100644 --- a/llvm/lib/IR/DebugInfo.cpp +++ b/llvm/lib/IR/DebugInfo.cpp @@ -1837,7 +1837,8 @@ LLVMMetadataRef LLVMDIBuilderCreateLabel(LLVMDIBuilderRef Builder, LLVMBool AlwaysPreserve) { return wrap(unwrap(Builder)->createLabel( unwrapDI(Context), StringRef(Name, NameLen), - unwrapDI(File), LineNo, AlwaysPreserve)); + unwrapDI(File), LineNo, /*Column*/ 0, /*IsArtificial*/ false, + /*CoroSuspendIdx*/ std::nullopt, AlwaysPreserve)); } LLVMDbgRecordRef LLVMDIBuilderInsertLabelBefore(LLVMDIBuilderRef Builder, diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index 44b0f0d50067c..0c8f1d78e4933 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -1616,18 +1616,27 @@ std::optional DIVariable::getSizeInBits() const { } DILabel::DILabel(LLVMContext &C, StorageType Storage, unsigned Line, + unsigned Column, bool IsArtificial, + std::optional CoroSuspendIdx, ArrayRef Ops) : DINode(C, DILabelKind, Storage, dwarf::DW_TAG_label, Ops) { - SubclassData32 = Line; + this->SubclassData32 = Line; + this->Column = Column; + this->IsArtificial = IsArtificial; + this->CoroSuspendIdx = CoroSuspendIdx; } DILabel *DILabel::getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, - Metadata *File, unsigned Line, StorageType Storage, - bool ShouldCreate) { + Metadata *File, unsigned Line, unsigned Column, + bool IsArtificial, + std::optional CoroSuspendIdx, + StorageType Storage, bool ShouldCreate) { assert(Scope && "Expected scope"); assert(isCanonical(Name) && "Expected canonical MDString"); - DEFINE_GETIMPL_LOOKUP(DILabel, (Scope, Name, File, Line)); + DEFINE_GETIMPL_LOOKUP( + DILabel, (Scope, Name, File, Line, Column, IsArtificial, CoroSuspendIdx)); Metadata *Ops[] = {Scope, Name, File}; - DEFINE_GETIMPL_STORE(DILabel, (Line), Ops); + DEFINE_GETIMPL_STORE(DILabel, (Line, Column, IsArtificial, CoroSuspendIdx), + Ops); } DIExpression *DIExpression::getImpl(LLVMContext &Context, diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h index 4446f47d323d2..ae7c926502fe6 100644 --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -1329,20 +1329,33 @@ template <> struct MDNodeKeyImpl { MDString *Name; Metadata *File; unsigned Line; + unsigned Column; + bool IsArtificial; + std::optional CoroSuspendIdx; - MDNodeKeyImpl(Metadata *Scope, MDString *Name, Metadata *File, unsigned Line) - : Scope(Scope), Name(Name), File(File), Line(Line) {} + MDNodeKeyImpl(Metadata *Scope, MDString *Name, Metadata *File, unsigned Line, + unsigned Column, bool IsArtificial, + std::optional CoroSuspendIdx) + : Scope(Scope), Name(Name), File(File), Line(Line), Column(Column), + IsArtificial(IsArtificial), CoroSuspendIdx(CoroSuspendIdx) {} MDNodeKeyImpl(const DILabel *N) : Scope(N->getRawScope()), Name(N->getRawName()), File(N->getRawFile()), - Line(N->getLine()) {} + Line(N->getLine()), Column(N->getColumn()), + IsArtificial(N->isArtificial()), + CoroSuspendIdx(N->getCoroSuspendIdx()) {} bool isKeyOf(const DILabel *RHS) const { return Scope == RHS->getRawScope() && Name == RHS->getRawName() && - File == RHS->getRawFile() && Line == RHS->getLine(); + File == RHS->getRawFile() && Line == RHS->getLine() && + Column == RHS->getColumn() && IsArtificial == RHS->isArtificial() && + CoroSuspendIdx == RHS->getCoroSuspendIdx(); } /// Using name and line to get hash value. It should already be mostly unique. - unsigned getHashValue() const { return hash_combine(Scope, Name, Line); } + unsigned getHashValue() const { + return hash_combine(Scope, Name, Line, Column, IsArtificial, + CoroSuspendIdx); + } }; template <> struct MDNodeKeyImpl { diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp index 1acd9139fe26e..42f8bf91118ae 100644 --- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp @@ -688,9 +688,9 @@ static DIType *solveDIType(DIBuilder &Builder, Type *Ty, static void buildFrameDebugInfo(Function &F, coro::Shape &Shape, FrameDataInfo &FrameData) { DISubprogram *DIS = F.getSubprogram(); - // If there is no DISubprogram for F, it implies the Function are not compiled - // with debug info. So we also don't need to generate debug info for the frame - // neither. + // If there is no DISubprogram for F, it implies the function is compiled + // without debug info. So we also don't generate debug info for the frame, + // either. if (!DIS || !DIS->getUnit() || !dwarf::isCPlusPlus( (dwarf::SourceLanguage)DIS->getUnit()->getSourceLanguage()) || diff --git a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp index 8813f91e9060c..1f0aa106cec63 100644 --- a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp @@ -42,6 +42,7 @@ #include "llvm/IR/CFG.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DIBuilder.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DerivedTypes.h" @@ -302,7 +303,7 @@ static void replaceFallthroughCoroEnd(AnyCoroEndInst *End, } // Mark a coroutine as done, which implies that the coroutine is finished and -// never get resumed. +// never gets resumed. // // In resume-switched ABI, the done state is represented by storing zero in // ResumeFnAddr. @@ -1478,6 +1479,18 @@ struct SwitchCoroutineSplitter { static void createResumeEntryBlock(Function &F, coro::Shape &Shape) { LLVMContext &C = F.getContext(); + DIBuilder DBuilder(*F.getParent(), /*AllowUnresolved*/ false); + DISubprogram *DIS = F.getSubprogram(); + // If there is no DISubprogram for F, it implies the function is compiled + // without debug info. So we also don't generate debug info for the + // suspension points, either. + bool AddDebugLabels = + (DIS && DIS->getUnit() && + (DIS->getUnit()->getEmissionKind() == + DICompileUnit::DebugEmissionKind::FullDebug || + DIS->getUnit()->getEmissionKind() == + DICompileUnit::DebugEmissionKind::LineTablesOnly)); + // resume.entry: // %index.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 // 0, i32 2 % index = load i32, i32* %index.addr switch i32 %index, label @@ -1500,6 +1513,7 @@ struct SwitchCoroutineSplitter { Builder.CreateSwitch(Index, UnreachBB, Shape.CoroSuspends.size()); Shape.SwitchLowering.ResumeSwitch = Switch; + // Split all coro.suspend calls size_t SuspendIndex = 0; for (auto *AnyS : Shape.CoroSuspends) { auto *S = cast(AnyS); @@ -1538,6 +1552,7 @@ struct SwitchCoroutineSplitter { // br label %resume.0.landing // // resume.0: ; <--- jump from the switch in the resume.entry + // XXX: label // %0 = tail call i8 @llvm.coro.suspend(token none, i1 false) // br label %resume.0.landing // @@ -1560,11 +1575,27 @@ struct SwitchCoroutineSplitter { PN->addIncoming(Builder.getInt8(-1), SuspendBB); PN->addIncoming(S, ResumeBB); + if (AddDebugLabels) { + if (DebugLoc SuspendLoc = S->getDebugLoc()) { + std::string LabelName = + ("__coro_resume_" + Twine(SuspendIndex)).str(); + DILocation &DILoc = *SuspendLoc.get(); + DILabel *ResumeLabel = + DBuilder.createLabel(DIS, LabelName, DILoc.getFile(), + SuspendLoc.getLine(), SuspendLoc.getCol(), + /*IsArtificial=*/true, + /*CoroSuspendIdx=*/SuspendIndex, + /*AlwaysPreserve=*/false); + DBuilder.insertLabel(ResumeLabel, &DILoc, ResumeBB->begin()); + } + } + ++SuspendIndex; } Builder.SetInsertPoint(UnreachBB); Builder.CreateUnreachable(); + DBuilder.finalize(); Shape.SwitchLowering.ResumeEntryBlock = NewEntry; } diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp index 242cf6d811b66..25d3db9431bda 100644 --- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -1347,8 +1347,10 @@ static void fixupDebugInfoPostExtraction(Function &OldFunc, Function &NewFunc, if (!NewLabel) { DILocalScope *NewScope = DILocalScope::cloneScopeForSubprogram( *OldLabel->getScope(), *NewSP, Ctx, Cache); - NewLabel = DILabel::get(Ctx, NewScope, OldLabel->getName(), - OldLabel->getFile(), OldLabel->getLine()); + NewLabel = + DILabel::get(Ctx, NewScope, OldLabel->getName(), OldLabel->getFile(), + OldLabel->getLine(), OldLabel->getColumn(), + OldLabel->isArtificial(), OldLabel->getCoroSuspendIdx()); } LabelRecord->setLabel(cast(NewLabel)); }; diff --git a/llvm/test/DebugInfo/Generic/debug-label.ll b/llvm/test/DebugInfo/Generic/debug-label.ll index eff482a25ee0f..0adb0608fafb6 100644 --- a/llvm/test/DebugInfo/Generic/debug-label.ll +++ b/llvm/test/DebugInfo/Generic/debug-label.ll @@ -5,6 +5,7 @@ ; CHECK-NEXT: DW_AT_name {{.*}}"top" ; CHECK-NEXT: DW_AT_decl_file [DW_FORM_data1] {{.*}}debug-label.c ; CHECK-NEXT: DW_AT_decl_line [DW_FORM_data1] {{.*}}4 +; CHECK-NEXT: DW_AT_decl_column [DW_FORM_data1] {{.*}}9 ; CHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] {{.*}}{{0x[0-9a-f]+}} ; CHECK: DW_TAG_label ; CHECK-NEXT: DW_AT_name {{.*}}"done" @@ -22,6 +23,7 @@ ; ASM-NEXT: DW_AT_name ; ASM: 1 {{.*}} DW_AT_decl_file ; ASM-NEXT: 4 {{.*}} DW_AT_decl_line +; ASM-NEXT: 9 {{.*}} DW_AT_decl_column ; ASM-NEXT: [[TOP_LOW_PC]]{{.*}} DW_AT_low_pc ; ASM: DW_TAG_label ; ASM-NEXT: DW_AT_name @@ -68,7 +70,7 @@ declare void @llvm.dbg.label(metadata) !7 = !DISubroutineType(types: !8) !8 = !{!9, !9, !9} !9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) -!10 = !DILabel(scope: !6, name: "top", file: !1, line: 4) +!10 = !DILabel(scope: !6, name: "top", file: !1, line: 4, column: 9) !11 = !DILocation(line: 4, column: 1, scope: !6) !12 = !DILabel(scope: !15, name: "done", file: !1, line: 7) !13 = !DILocation(line: 7, column: 1, scope: !6) diff --git a/llvm/test/Transforms/Coroutines/coro-debug-dbg.values.ll b/llvm/test/Transforms/Coroutines/coro-debug-dbg.values.ll index 5f7701c357ec3..0934393a667ee 100644 --- a/llvm/test/Transforms/Coroutines/coro-debug-dbg.values.ll +++ b/llvm/test/Transforms/Coroutines/coro-debug-dbg.values.ll @@ -1,4 +1,4 @@ -; Tests whether resume function would remain dbg.value infomation. +; Tests whether resume function retains dbg.value information. ; RUN: opt < %s -passes='module(coro-early),cgscc(coro-split,coro-split)' -S | FileCheck %s ; ; This file is based on coro-debug-frame-variable.ll. diff --git a/llvm/test/Transforms/Coroutines/coro-debug.ll b/llvm/test/Transforms/Coroutines/coro-debug.ll index a220073248ba3..5f8e9c9c1d16d 100644 --- a/llvm/test/Transforms/Coroutines/coro-debug.ll +++ b/llvm/test/Transforms/Coroutines/coro-debug.ll @@ -19,7 +19,6 @@ entry: %3 = call i8 @llvm.coro.suspend(token none, i1 false), !dbg !17 %conv = sext i8 %3 to i32, !dbg !17 %late_local = alloca i32, align 4 - call void @coro.devirt.trigger(ptr null) switch i32 %conv, label %sw.default [ i32 0, label %sw.bb i32 1, label %sw.bb1 @@ -113,12 +112,6 @@ declare ptr @llvm.coro.free(token, ptr nocapture readonly) #2 ; Function Attrs: nounwind declare i1 @llvm.coro.end(ptr, i1, token) #5 -; Function Attrs: alwaysinline -define private void @coro.devirt.trigger(ptr) #6 { -entry: - ret void -} - ; Function Attrs: argmemonly nounwind readonly declare ptr @llvm.coro.subfn.addr(ptr nocapture readonly, i8) #2 @@ -170,15 +163,20 @@ attributes #7 = { noduplicate } !31 = !DILocalVariable(name: "allocated", scope: !6, file: !7, line: 55, type: !11) !32 = !DILocalVariable(name: "inline_asm", scope: !6, file: !7, line: 55, type: !11) +; Check that the original function is visible and capture its debug info id. ; CHECK: define ptr @flink(i32 %x) #0 personality i32 0 !dbg ![[ORIG:[0-9]+]] + +; Check that the resume function is present and capture its debug info id. +; Also check that it contains `#dbg_declare` and `#dbg_value` debug instructions +; making the debug variables available to the debugger. +; ; CHECK: define internal fastcc void @flink.resume(ptr noundef nonnull align 8 dereferenceable(40) %0) #0 personality i32 0 !dbg ![[RESUME:[0-9]+]] ; CHECK: entry.resume: ; CHECK: %[[DBG_PTR:.*]] = alloca ptr -; CHECK: #dbg_declare(ptr %[[DBG_PTR]], ![[RESUME_COROHDL:[0-9]+]], !DIExpression(DW_OP_deref, DW_OP_plus_uconst, -; CHECK: #dbg_declare(ptr %[[DBG_PTR]], ![[RESUME_X:[0-9]+]], !DIExpression(DW_OP_deref, DW_OP_plus_uconst, [[EXPR_TAIL:.*]]) -; CHECK: store ptr {{.*}}, ptr %[[DBG_PTR]] +; CHECK-NEXT: #dbg_declare(ptr %[[DBG_PTR]], ![[RESUME_COROHDL:[0-9]+]], !DIExpression(DW_OP_deref, DW_OP_plus_uconst, +; CHECK-NEXT: #dbg_declare(ptr %[[DBG_PTR]], ![[RESUME_X:[0-9]+]], !DIExpression(DW_OP_deref, DW_OP_plus_uconst, [[EXPR_TAIL:.*]]) +; CHECK-NEXT: store ptr {{.*}}, ptr %[[DBG_PTR]] ; CHECK-NOT: alloca ptr -; CHECK: call void @coro.devirt.trigger(ptr null) ; CHECK: #dbg_value(i8 0, ![[RESUME_CONST:[0-9]+]], !DIExpression(DW_OP_LLVM_convert, 8, DW_ATE_signed, DW_OP_LLVM_convert, 32, DW_ATE_signed), ; CHECK: #dbg_value(ptr %[[DBG_PTR]], ![[RESUME_DIRECT:[0-9]+]], !DIExpression(DW_OP_deref, DW_OP_plus_uconst, {{[0-9]+}}, DW_OP_deref), ; Note that keeping the undef value here could be acceptable, too. @@ -194,18 +192,26 @@ attributes #7 = { noduplicate } ; CHECK: [[DEFAULT_DEST]]: ; CHECK-NOT: {{.*}}: ; CHECK: #dbg_value(i32 %[[CALLBR_RES]] + +; Check that the destroy and cleanup functions are present and capture their debug info id. +; ; CHECK: define internal fastcc void @flink.destroy(ptr noundef nonnull align 8 dereferenceable(40) %0) #0 personality i32 0 !dbg ![[DESTROY:[0-9]+]] ; CHECK: define internal fastcc void @flink.cleanup(ptr noundef nonnull align 8 dereferenceable(40) %0) #0 personality i32 0 !dbg ![[CLEANUP:[0-9]+]] +; Check that the linkage name of the original function is set correctly. +; ; CHECK: ![[ORIG]] = distinct !DISubprogram(name: "f", linkageName: "flink" - ; CHECK: ![[RESUME]] = distinct !DISubprogram(name: "f", linkageName: "flink.resume" + +; Check that metadata for local variables in the resume function is set correctly. +; ; CHECK: ![[RESUME_COROHDL]] = !DILocalVariable(name: "coro_hdl", scope: ![[RESUME]] ; CHECK: ![[RESUME_X]] = !DILocalVariable(name: "x", arg: 1, scope: ![[RESUME]] ; CHECK: ![[RESUME_CONST]] = !DILocalVariable(name: "direct_const", scope: ![[RESUME]] ; CHECK: ![[RESUME_DIRECT]] = !DILocalVariable(name: "direct_mem", scope: ![[RESUME]] ; CHECK: ![[RESUME_DIRECT_VALUE]] = !DILocalVariable(name: "direct_value", scope: ![[RESUME]] +; Check that the linkage names are set correctly for the destroy and cleanup functions. +; ; CHECK: ![[DESTROY]] = distinct !DISubprogram(name: "f", linkageName: "flink.destroy" - ; CHECK: ![[CLEANUP]] = distinct !DISubprogram(name: "f", linkageName: "flink.cleanup" diff --git a/llvm/test/Transforms/Coroutines/coro-split-dbg-labels.ll b/llvm/test/Transforms/Coroutines/coro-split-dbg-labels.ll new file mode 100644 index 0000000000000..48642ffa97b4d --- /dev/null +++ b/llvm/test/Transforms/Coroutines/coro-split-dbg-labels.ll @@ -0,0 +1,148 @@ +; Tests that we add DILabels for the suspend points. +; +; We check both the generated LLVM: +; RUN: opt < %s -passes='cgscc(coro-split)' -S | FileCheck %s +; +; And the debug info: +; RUN: opt < %s -passes='cgscc(coro-split),coro-cleanup' \ +; RUN: | llc -O0 -filetype=obj -o - \ +; RUN: | llvm-dwarfdump - \ +; RUN: | FileCheck %s -check-prefix=DWARF + +source_filename = "coro.c" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @bar(...) local_unnamed_addr #2 +declare void @baz(...) local_unnamed_addr #2 + +; Roughly equivalent to: +; +; task f() { +; while (true) { +; bar(); +; co_await std::suspend_always{}; +; baz(); +; co_await std::suspend_always{}; +; } +; } + +; Function Attrs: nounwind uwtable +define ptr @f() #3 !dbg !16 { +entry: + %0 = tail call token @llvm.coro.id(i32 0, ptr null, ptr @f, ptr null), !dbg !26 + %1 = tail call i64 @llvm.coro.size.i64(), !dbg !26 + %frame = tail call ptr @malloc(i64 %1), !dbg !26 + %2 = tail call ptr @llvm.coro.begin(token %0, ptr %frame) #4, !dbg !26 + br label %loop1, !dbg !27 + +loop1: ; preds = %for.cond, %entry + tail call void (...) @bar() #7, !dbg !33 + %3 = tail call token @llvm.coro.save(ptr null), !dbg !34 + %4 = tail call i8 @llvm.coro.suspend(token %3, i1 false), !dbg !34 + switch i8 %4, label %coro_Suspend [ + i8 0, label %loop2 + i8 1, label %coro_Cleanup + ], !dbg !34 + +loop2: ; preds = %for.cond, %entry + tail call void (...) @baz() #7, !dbg !35 + %5 = tail call token @llvm.coro.save(ptr null), !dbg !36 + %6 = tail call i8 @llvm.coro.suspend(token %5, i1 false), !dbg !36 + switch i8 %6, label %coro_Suspend [ + i8 0, label %loop1 + i8 1, label %coro_Cleanup + ], !dbg !36 + +coro_Cleanup: ; preds = %for.cond + %7 = tail call ptr @llvm.coro.free(token %0, ptr %2), !dbg !37 + tail call void @free(ptr nonnull %7), !dbg !37 + br label %coro_Suspend, !dbg !37 + +coro_Suspend: ; preds = %for.cond, %if.then, %coro_Cleanup + tail call i1 @llvm.coro.end(ptr null, i1 false, token none) #4, !dbg !40 + ret ptr %2, !dbg !41 +} + +; Check that the resume function contains the `#dbg_label` instructions. +; CHECK-LABEL: define ptr @f() #1 !dbg !6 { +; CHECK: resume.0: ; preds = %resume.entry +; CHECK-NEXT: #dbg_label(![[RESUME_0:[0-9]+]], !{{[0-9]+}}) +; CHECK: resume.1: ; preds = %resume.entry +; CHECK-NEXT: #dbg_label(![[RESUME_1:[0-9]+]], !{{[0-9]+}}) + +; Check that the destroy function contains the `#dbg_label` instructions. +; CHECK-LABEL: define internal fastcc void @f.destroy({{.*}}) #1 !dbg !38 { +; CHECK: resume.0: ; preds = %resume.entry +; CHECK-NEXT: #dbg_label(![[DESTROY_0:[0-9]+]], !{{[0-9]+}}) +; CHECK: resume.1: ; preds = %resume.entry +; CHECK-NEXT: #dbg_label(![[DESTROY_1:[0-9]+]], !{{[0-9]+}}) + +; Check that the DILabels are correct. +; CHECK: ![[RESUME_0]] = !DILabel(scope: !{{[0-9]+}}, name: "__coro_resume_0", file: !{{[0-9]*}}, line: 12, column: 6, isArtificial: true, coroSuspendIdx: 0) +; CHECK: ![[RESUME_1]] = !DILabel(scope: !{{[0-9]+}}, name: "__coro_resume_1", file: !{{[0-9]*}}, line: 14, column: 6, isArtificial: true, coroSuspendIdx: 1) +; CHECK: ![[DESTROY_0]] = !DILabel(scope: !{{[0-9]+}}, name: "__coro_resume_0", file: !{{[0-9]*}}, line: 12, column: 6, isArtificial: true, coroSuspendIdx: 0) +; CHECK: ![[DESTROY_1]] = !DILabel(scope: !{{[0-9]+}}, name: "__coro_resume_1", file: !{{[0-9]*}}, line: 14, column: 6, isArtificial: true, coroSuspendIdx: 1) + +; DWARF: {{.*}}DW_TAG_label +; DWARF-LABEL: DW_AT_name ("__coro_resume_0") +; DWARF-NEXT: DW_AT_decl_file +; DWARF-NEXT: DW_AT_decl_line (12) +; DWARF-NEXT: DW_AT_decl_column (6) +; DWARF-NEXT: DW_AT_artificial (true) +; DWARF-NEXT: DW_AT_LLVM_coro_suspend_idx (0x00) +; DWARF-NEXT: DW_AT_low_pc + + +; Function Attrs: argmemonly nounwind readonly +declare token @llvm.coro.id(i32, ptr readnone, ptr nocapture readonly, ptr) #5 + +; Function Attrs: nounwind +declare noalias ptr @malloc(i64) local_unnamed_addr #6 +declare i64 @llvm.coro.size.i64() #1 +declare ptr @llvm.coro.begin(token, ptr writeonly) #7 +declare token @llvm.coro.save(ptr) #7 +declare i8 @llvm.coro.suspend(token, i1) #7 +declare ptr @llvm.coro.free(token, ptr nocapture readonly) #5 +declare void @free(ptr nocapture) local_unnamed_addr #6 +declare i1 @llvm.coro.end(ptr, i1, token) #7 + +attributes #0 = { nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="none" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="none" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #3 = { nounwind uwtable presplitcoroutine "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="none" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #4 = { noduplicate } +attributes #5 = { argmemonly nounwind readonly } +attributes #6 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="none" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #7 = { nounwind } +attributes #8 = { alwaysinline nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4} +!llvm.ident = !{!5} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0 - manually edited", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "coro.c", directory: "/home/gor/build/bin") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{!"clang version 4.0.0 - manually edited"} +!9 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!16 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 8, type: !17, isLocal: false, isDefinition: true, scopeLine: 8, isOptimized: true, unit: !0, retainedNodes: !20) +!17 = !DISubroutineType(types: !18) +!18 = !{!19} +!19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64, align: 64) +!20 = !{!21, !22, !24} +!21 = !DILocalVariable(name: "coro_hdl", scope: !16, file: !1, line: 9, type: !19) +!22 = !DILocalVariable(name: "i", scope: !23, file: !1, line: 11, type: !9) +!23 = distinct !DILexicalBlock(scope: !16, file: !1, line: 11, column: 3) +!24 = !DILocalVariable(name: "coro_mem", scope: !16, file: !1, line: 16, type: !19) +!26 = !DILocation(line: 9, column: 3, scope: !16) +!27 = !DILocation(line: 10, column: 8, scope: !23) +!33 = !DILocation(line: 11, column: 6, scope: !23) +!34 = !DILocation(line: 12, column: 6, scope: !23) +!35 = !DILocation(line: 13, column: 6, scope: !23) +!36 = !DILocation(line: 14, column: 6, scope: !23) +!37 = !DILocation(line: 16, column: 3, scope: !16) +!40 = !DILocation(line: 16, column: 3, scope: !16) +!41 = !DILocation(line: 17, column: 1, scope: !16) diff --git a/llvm/test/Transforms/Coroutines/coro-split-no-lieftime.ll b/llvm/test/Transforms/Coroutines/coro-split-no-lifetime.ll similarity index 100% rename from llvm/test/Transforms/Coroutines/coro-split-no-lieftime.ll rename to llvm/test/Transforms/Coroutines/coro-split-no-lifetime.ll diff --git a/llvm/unittests/IR/IRBuilderTest.cpp b/llvm/unittests/IR/IRBuilderTest.cpp index 520735dfc3268..4f2ede3321080 100644 --- a/llvm/unittests/IR/IRBuilderTest.cpp +++ b/llvm/unittests/IR/IRBuilderTest.cpp @@ -920,9 +920,11 @@ TEST_F(IRBuilderTest, DIBuilder) { // -------------------------- DILocation *LabelLoc = DILocation::get(Ctx, 1, 0, BarScope); DILabel *AlwaysPreserveLabel = DIB.createLabel( - BarScope, "meles_meles", File, 1, /*AlwaysPreserve*/ true); - DILabel *Label = - DIB.createLabel(BarScope, "badger", File, 1, /*AlwaysPreserve*/ false); + BarScope, "meles_meles", File, 1, /*Column*/ 0, /*IsArtificial*/ false, + /*CoroSuspendIdx*/ std::nullopt, /*AlwaysPreserve*/ true); + DILabel *Label = DIB.createLabel( + BarScope, "badger", File, 1, /*Column*/ 0, /*IsArtificial*/ false, + /*CoroSuspendIdx*/ std::nullopt, /*AlwaysPreserve*/ false); { /* dbg.label | DbgLabelRecord */ // Insert before I and check order. diff --git a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp index 2af3ae0bd7f4f..a55445deddc2d 100644 --- a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp @@ -221,7 +221,9 @@ llvm::DIFile *DebugTranslation::translateImpl(DIFileAttr attr) { llvm::DILabel *DebugTranslation::translateImpl(DILabelAttr attr) { return llvm::DILabel::get(llvmCtx, translate(attr.getScope()), getMDStringOrNull(attr.getName()), - translate(attr.getFile()), attr.getLine()); + translate(attr.getFile()), attr.getLine(), + /*Column=*/0, /*IsArtificial=*/false, + /*CoroSuspendIdx=*/std::nullopt); } llvm::DILexicalBlock *DebugTranslation::translateImpl(DILexicalBlockAttr attr) {