Skip to content

Commit ddcc601

Browse files
[CoroSplit][DebugInfo] Adjust heuristic for moving DIScope of funclets (#108611)
CoroSplit has a heuristic where the scope line for funclets is adjusted to match the line of the suspend intrinsic that caused the split. This is useful as it avoids a jump on the line table from the original function declaration to the line where the split happens. However, very often using the line of the split is not ideal: if we can avoid it, we should not have a line entry for the split location, as this would cause breakpoints by line to match against two functions: the funclet before and the funclet after the split. This patch adjusts the heuristics to look for the first instruction with a non-zero line number after the split. In other words, this patch makes breakpoints on `await foo()` lines behave much more like a regular function call.
1 parent d0638ed commit ddcc601

File tree

2 files changed

+49
-14
lines changed

2 files changed

+49
-14
lines changed

llvm/lib/Transforms/Coroutines/CoroSplit.cpp

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,45 @@ Value *CoroCloner::deriveNewFramePointer() {
887887
llvm_unreachable("bad ABI");
888888
}
889889

890+
/// Adjust the scope line of the funclet to the first line number after the
891+
/// suspend point. This avoids a jump in the line table from the function
892+
/// declaration (where prologue instructions are attributed to) to the suspend
893+
/// point.
894+
/// Only adjust the scope line when the files are the same.
895+
/// If no candidate line number is found, fallback to the line of ActiveSuspend.
896+
static void updateScopeLine(Instruction *ActiveSuspend,
897+
DISubprogram &SPToUpdate) {
898+
if (!ActiveSuspend)
899+
return;
900+
901+
auto *Successor = ActiveSuspend->getNextNonDebugInstruction();
902+
// Corosplit splits the BB around ActiveSuspend, so the meaningful
903+
// instructions are not in the same BB.
904+
if (auto *Branch = dyn_cast_or_null<BranchInst>(Successor);
905+
Branch && Branch->isUnconditional())
906+
Successor = Branch->getSuccessor(0)->getFirstNonPHIOrDbg();
907+
908+
// Find the first successor of ActiveSuspend with a non-zero line location.
909+
// If that matches the file of ActiveSuspend, use it.
910+
for (; Successor; Successor = Successor->getNextNonDebugInstruction()) {
911+
auto DL = Successor->getDebugLoc();
912+
if (!DL || DL.getLine() == 0)
913+
continue;
914+
915+
if (SPToUpdate.getFile() == DL->getFile()) {
916+
SPToUpdate.setScopeLine(DL.getLine());
917+
return;
918+
}
919+
920+
break;
921+
}
922+
923+
// If the search above failed, fallback to the location of ActiveSuspend.
924+
if (auto DL = ActiveSuspend->getDebugLoc())
925+
if (SPToUpdate.getFile() == DL->getFile())
926+
SPToUpdate.setScopeLine(DL->getLine());
927+
}
928+
890929
static void addFramePointerAttrs(AttributeList &Attrs, LLVMContext &Context,
891930
unsigned ParamIndex, uint64_t Size,
892931
Align Alignment, bool NoAlias) {
@@ -955,18 +994,10 @@ void CoroCloner::create() {
955994

956995
auto &Context = NewF->getContext();
957996

958-
// For async functions / continuations, adjust the scope line of the
959-
// clone to the line number of the suspend point. However, only
960-
// adjust the scope line when the files are the same. This ensures
961-
// line number and file name belong together. The scope line is
962-
// associated with all pre-prologue instructions. This avoids a jump
963-
// in the linetable from the function declaration to the suspend point.
964997
if (DISubprogram *SP = NewF->getSubprogram()) {
965998
assert(SP != OrigF.getSubprogram() && SP->isDistinct());
966-
if (ActiveSuspend)
967-
if (auto DL = ActiveSuspend->getDebugLoc())
968-
if (SP->getFile() == DL->getFile())
969-
SP->setScopeLine(DL->getLine());
999+
updateScopeLine(ActiveSuspend, *SP);
1000+
9701001
// Update the linkage name to reflect the modified symbol name. It
9711002
// is necessary to update the linkage name in Swift, since the
9721003
// mangling changes for resume functions. It might also be the

llvm/test/Transforms/Coroutines/swift-async-dbg.ll

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,17 @@ define swifttailcc void @coroutineA(ptr swiftasync %arg) !dbg !48 {
3737

3838
%i7 = call ptr @llvm.coro.async.resume(), !dbg !54
3939
%i10 = call { ptr } (i32, ptr, ptr, ...) @llvm.coro.suspend.async.sl_p0s(i32 0, ptr %i7, ptr nonnull @__swift_async_resume_get_context, ptr nonnull @coroutineA.1, ptr %i7, i64 0, i64 0, ptr %arg), !dbg !54
40-
%i11 = extractvalue { ptr } %i10, 0, !dbg !54
41-
%i12 = call ptr @__swift_async_resume_get_context(ptr %i11), !dbg !54
42-
call void @dont_optimize(ptr %var_with_dbg_value, ptr %var_with_dbg_declare)
40+
%i11 = extractvalue { ptr } %i10, 0, !dbg !55
41+
%i12 = call ptr @__swift_async_resume_get_context(ptr %i11), !dbg !55
42+
call void @dont_optimize(ptr %var_with_dbg_value, ptr %var_with_dbg_declare), !dbg !100
4343
call void @llvm.dbg.value(metadata ptr %var_with_dbg_value, metadata !50, metadata !DIExpression(DW_OP_deref)), !dbg !54
4444
%i17 = load i32, ptr getelementptr inbounds (<{i32, i32}>, ptr @coroutineBTu, i64 0, i32 1), align 8, !dbg !54
4545
call void @llvm.dbg.value(metadata !DIArgList(ptr %var_with_dbg_value, i32 %i17), metadata !501, metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_deref)), !dbg !54
4646
%i18 = zext i32 %i17 to i64, !dbg !54
4747
%i19 = call swiftcc ptr @swift_task_alloc(i64 %i18), !dbg !54
4848
; CHECK-NOT: define
4949
; CHECK-LABEL: define {{.*}} @coroutineATY0_(
50-
; CHECK-SAME: ptr swiftasync %[[frame_ptr:.*]])
50+
; CHECK-SAME: ptr swiftasync %[[frame_ptr:.*]]) !dbg ![[ATY0:[0-9]*]]
5151
; CHECK: #dbg_declare(ptr %[[frame_ptr]], {{.*}} !DIExpression(
5252
; CHECK-SAME: DW_OP_LLVM_entry_value, 1, DW_OP_plus_uconst, 24)
5353
; CHECK: #dbg_value(ptr %[[frame_ptr]], {{.*}} !DIExpression(
@@ -88,6 +88,8 @@ define swifttailcc void @coroutineA(ptr swiftasync %arg) !dbg !48 {
8888
; CHECK-SAME: DW_OP_LLVM_entry_value, 1, DW_OP_plus_uconst, 24)
8989
}
9090

91+
; CHECK: ![[ATY0]] = {{.*}}DISubprogram(linkageName: "coroutineATY0_", {{.*}} scopeLine: 42
92+
9193
; Everything from here on is just support code for the coroutines.
9294

9395
@coroutineBTu = global <{i32, i32}> <{ i32 trunc (i64 sub (i64 ptrtoint (ptr @"coroutineB" to i64), i64 ptrtoint (ptr @"coroutineBTu" to i64)) to i32), i32 16 }>, align 8
@@ -172,5 +174,7 @@ declare { ptr } @llvm.coro.suspend.async.sl_p0s(i32, ptr, ptr, ...)
172174
!71 = !DILocation(line: 0, scope: !70)
173175
!73 = !DILocation(line: 0, scope: !72)
174176
!54 = !DILocation(line: 6, scope: !48)
177+
!55 = !DILocation(line: 0, scope: !48)
175178
!42 = !DILocation(line: 3, scope: !37)
176179
!47 = !DILocation(line: 0, scope: !44)
180+
!100 = !DILocation(line: 42, scope: !48)

0 commit comments

Comments
 (0)