Skip to content

Commit 768f391

Browse files
[DebugInfo] Dont generate info for __swift_async_resume_project_context or __swift_async_resume_get_context
These functions are alwaysinline and their instructions are created with line 0 as a location. As a result, the instructions all get inlined with line 0 into funclets. In practice, this makes it so that the first instruction of the funclet containing a debug location happens much later. This is important because the inlined instructions do meaningful work, like overwriting the contents of `fp - 8`. If we try to set a breakpoint into this funclet, we *must* break before these instructions, by allowing the line 0 locations to propagate, we fail to do. This patch changes this by removing all debug locations from the helper functions. By doing so, when they are inlined, instructions will inherit the location of the call site.
1 parent 6a7be95 commit 768f391

File tree

2 files changed

+56
-4
lines changed

2 files changed

+56
-4
lines changed

lib/IRGen/GenFunc.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2590,8 +2590,9 @@ IRGenFunction::emitAsyncResumeProjectContext(llvm::Value *calleeContext) {
25902590
}
25912591

25922592
llvm::Function *IRGenFunction::getOrCreateResumePrjFn(bool forPrologue) {
2593-
// The prologue version lacks artificial debug info as this would cause
2594-
// verification errors when it gets inlined.
2593+
// Never emit debug info for these alwaysinline functions, as it would create
2594+
// an inline frame without any user code. These can also be involved in tail
2595+
// calls, which confuse the debugger.
25952596
auto name = forPrologue ? "__swift_async_resume_project_context_prologue"
25962597
: "__swift_async_resume_project_context";
25972598
auto Fn = cast<llvm::Function>(IGM.getOrCreateHelperFunction(
@@ -2603,7 +2604,7 @@ llvm::Function *IRGenFunction::getOrCreateResumePrjFn(bool forPrologue) {
26032604
auto callerContext = IGF.emitAsyncResumeProjectContext(addr);
26042605
Builder.CreateRet(callerContext);
26052606
},
2606-
false /*isNoInline*/, forPrologue));
2607+
false /*isNoInline*/, true/*for prologue*/));
26072608
Fn->addFnAttr(llvm::Attribute::AlwaysInline);
26082609
return Fn;
26092610
}
@@ -2694,14 +2695,17 @@ void IRGenFunction::emitSuspensionPoint(Explosion &toExecutor,
26942695
}
26952696

26962697
llvm::Function *IRGenFunction::getOrCreateResumeFromSuspensionFn() {
2698+
// Never emit debug info for these alwaysinline functions, as it would create
2699+
// an inline frame without any user code. These can also be involved in tail
2700+
// calls, which confuse the debugger.
26972701
auto name = "__swift_async_resume_get_context";
26982702
auto fn = cast<llvm::Function>(IGM.getOrCreateHelperFunction(
26992703
name, IGM.Int8PtrTy, {IGM.Int8PtrTy},
27002704
[&](IRGenFunction &IGF) {
27012705
auto &Builder = IGF.Builder;
27022706
Builder.CreateRet(&*IGF.CurFn->arg_begin());
27032707
},
2704-
false /*isNoInline*/));
2708+
false /*isNoInline*/, true /*forPrologue*/));
27052709
fn->addFnAttr(llvm::Attribute::AlwaysInline);
27062710
return fn;
27072711
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// RUN: %target-swift-frontend %s -g -emit-irgen | %IRGenFileCheck %s
2+
3+
// We don't want any debug info for these helper functions:
4+
5+
// CHECK: define {{.*}} @__swift_async_resume_project_context
6+
// CHECK-NOT: !dbg
7+
// CHECK-SAME: {
8+
// CHECK: define {{.*}} @__swift_async_resume_get_context
9+
// CHECK-NOT: !dbg
10+
// CHECK-SAME: {
11+
12+
sil_stage canonical
13+
14+
import Builtin
15+
import Swift
16+
import SwiftShims
17+
18+
@_silgen_name("some_async_func")
19+
public func some_async_func() async -> Int
20+
21+
func foo() async -> Int
22+
23+
sil_scope 1 { parent @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 }
24+
25+
sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
26+
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
27+
%2 = integer_literal $Builtin.Int32, 0, scope 1 // user: %3
28+
%3 = struct $Int32 (%2 : $Builtin.Int32), scope 1 // user: %4
29+
return %3 : $Int32, scope 1 // id: %4
30+
}
31+
32+
sil_scope 2 { loc "test.swift":4:6 parent @$s4test3fooSiyYaF : $@convention(thin) @async () -> Int }
33+
sil_scope 3 { loc "test.swift":5:16 parent 2 }
34+
sil_scope 4 { loc "test.swift":5:7 parent 2 }
35+
36+
sil @$s4test3fooSiyYaF : $@convention(thin) @async () -> Int {
37+
bb0:
38+
%0 = enum $Optional<Builtin.Executor>, #Optional.none!enumelt, loc * "test.swift":4:6, scope 2 // user: %3
39+
// function_ref some_async_func
40+
%1 = function_ref @some_async_func : $@convention(thin) @async () -> Int, loc "test.swift":5:22, scope 3 // user: %2
41+
%2 = apply %1() : $@convention(thin) @async () -> Int, loc "test.swift":5:22, scope 3 // users: %6, %4
42+
hop_to_executor %0 : $Optional<Builtin.Executor>, loc * "test.swift":5:22, scope 3 // id: %3
43+
debug_value %2 : $Int, let, name "result", loc "test.swift":5:7, scope 4 // id: %4
44+
return %2 : $Int, loc "test.swift":6:3, scope 4 // id: %13
45+
}
46+
47+
48+
sil @some_async_func : $@convention(thin) @async () -> Int

0 commit comments

Comments
 (0)