diff --git a/clang/docs/DebuggingCoroutines.rst b/clang/docs/DebuggingCoroutines.rst index 80df321340724..9fc3785a0622b 100644 --- a/clang/docs/DebuggingCoroutines.rst +++ b/clang/docs/DebuggingCoroutines.rst @@ -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_`. -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++ diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp index 2f5f1089067bf..b8d355f5cdfd1 100644 --- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp @@ -689,9 +689,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 f9a6c70fedc2d..ae5f84dab3ee5 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. @@ -1492,6 +1493,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 @@ -1514,6 +1527,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); @@ -1552,6 +1566,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 // @@ -1574,11 +1589,23 @@ 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()); + DBuilder.insertLabel(ResumeLabel, &DILoc, ResumeBB->begin()); + } + } + ++SuspendIndex; } Builder.SetInsertPoint(UnreachBB); Builder.CreateUnreachable(); + DBuilder.finalize(); Shape.SwitchLowering.ResumeEntryBlock = NewEntry; }