Skip to content

Commit 9b69b77

Browse files
committed
[Coro] [async] Disable inlining in async coroutine splitting
The call to the inlining utility does not update the call graph. Leading to assertion failures when calling the utility to update the call graph. Instead rely on an inline pass to run after coro splitting and use alwaysinline annotations. github.com/swiftlang/swift/issues/68708
1 parent c13e271 commit 9b69b77

8 files changed

+229
-81
lines changed

llvm/lib/Transforms/Coroutines/CoroSplit.cpp

+1-11
Original file line numberDiff line numberDiff line change
@@ -208,17 +208,12 @@ static bool replaceCoroEndAsync(AnyCoroEndInst *End) {
208208
// Insert the return instruction.
209209
Builder.SetInsertPoint(End);
210210
Builder.CreateRetVoid();
211-
InlineFunctionInfo FnInfo;
212211

213212
// Remove the rest of the block, by splitting it into an unreachable block.
214213
auto *BB = End->getParent();
215214
BB->splitBasicBlock(End);
216215
BB->getTerminator()->eraseFromParent();
217216

218-
auto InlineRes = InlineFunction(*MustTailCall, FnInfo);
219-
assert(InlineRes.isSuccess() && "Expected inlining to succeed");
220-
(void)InlineRes;
221-
222217
// We have cleaned up the coro.end block above.
223218
return false;
224219
}
@@ -1842,13 +1837,8 @@ static void splitAsyncCoroutine(Function &F, coro::Shape &Shape,
18421837
SmallVector<Value *, 8> Args(Suspend->args());
18431838
auto FnArgs = ArrayRef<Value *>(Args).drop_front(
18441839
CoroSuspendAsyncInst::MustTailCallFuncArg + 1);
1845-
auto *TailCall =
1846-
coro::createMustTailCall(Suspend->getDebugLoc(), Fn, FnArgs, Builder);
1840+
coro::createMustTailCall(Suspend->getDebugLoc(), Fn, FnArgs, Builder);
18471841
Builder.CreateRetVoid();
1848-
InlineFunctionInfo FnInfo;
1849-
auto InlineRes = InlineFunction(*TailCall, FnInfo);
1850-
assert(InlineRes.isSuccess() && "Expected inlining to succeed");
1851-
(void)InlineRes;
18521842

18531843
// Replace the lvm.coro.async.resume intrisic call.
18541844
replaceAsyncResumeFunction(Suspend, Continuation);

llvm/test/Transforms/Coroutines/coro-async-addr-lifetime-infinite-loop-bug.ll

+4-4
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ declare void @my_other_async_function(ptr %async.ctxt)
2222
i32 128 ; Initial async context size without space for frame
2323
}>
2424

25-
define swiftcc void @my_other_async_function_fp.apply(ptr %fnPtr, ptr %async.ctxt) {
26-
tail call swiftcc void %fnPtr(ptr %async.ctxt)
25+
define swifttailcc void @my_other_async_function_fp.apply(ptr %fnPtr, ptr %async.ctxt) alwaysinline {
26+
tail call swifttailcc void %fnPtr(ptr %async.ctxt)
2727
ret void
2828
}
2929

@@ -37,12 +37,12 @@ entry:
3737

3838
; The address of alloca escapes but the analysis based on lifetimes fails to see
3939
; that it can't localize this alloca.
40-
; CHECK: define swiftcc void @my_async_function(ptr swiftasync %async.ctxt) {
40+
; CHECK: define swifttailcc void @my_async_function(ptr swiftasync %async.ctxt) {
4141
; CHECK: entry:
4242
; CHECK-NOT: ret
4343
; CHECK-NOT: [[ESCAPED_ADDR:%.*]] = alloca i64, align 8
4444
; CHECK: ret
45-
define swiftcc void @my_async_function(ptr swiftasync %async.ctxt) {
45+
define swifttailcc void @my_async_function(ptr swiftasync %async.ctxt) {
4646
entry:
4747
%escaped_addr = alloca i64
4848

llvm/test/Transforms/Coroutines/coro-async-addr-lifetime-start-bug.ll

+3-3
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ declare void @my_other_async_function(ptr %async.ctxt)
2222
i32 128 ; Initial async context size without space for frame
2323
}>
2424

25-
define swiftcc void @my_other_async_function_fp.apply(ptr %fnPtr, ptr %async.ctxt) {
26-
tail call swiftcc void %fnPtr(ptr %async.ctxt)
25+
define swifttailcc void @my_other_async_function_fp.apply(ptr %fnPtr, ptr %async.ctxt) alwaysinline {
26+
tail call swifttailcc void %fnPtr(ptr %async.ctxt)
2727
ret void
2828
}
2929

@@ -36,7 +36,7 @@ entry:
3636
ret ptr %resume_ctxt
3737
}
3838

39-
define swiftcc void @my_async_function(ptr swiftasync %async.ctxt) {
39+
define swifttailcc void @my_async_function(ptr swiftasync %async.ctxt) {
4040
entry:
4141
%escaped_addr = alloca i64
4242

llvm/test/Transforms/Coroutines/coro-async-dyn-align.ll

+5-5
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,20 @@ declare swiftcc void @asyncReturn(ptr)
3333
declare swiftcc void @asyncSuspend(ptr)
3434
declare {ptr} @llvm.coro.suspend.async(i32, ptr, ptr, ...)
3535

36-
define swiftcc void @my_async_function.my_other_async_function_fp.apply(ptr %fnPtr, ptr %async.ctxt) {
37-
tail call swiftcc void %fnPtr(ptr %async.ctxt)
36+
define swifttailcc void @my_async_function.my_other_async_function_fp.apply(ptr %fnPtr, ptr %async.ctxt) alwaysinline {
37+
musttail call swifttailcc void %fnPtr(ptr %async.ctxt)
3838
ret void
3939
}
4040

41-
define ptr @__swift_async_resume_project_context(ptr %ctxt) {
41+
define ptr @__swift_async_resume_project_context(ptr %ctxt) alwaysinline {
4242
entry:
4343
%resume_ctxt = load ptr, ptr %ctxt, align 8
4444
ret ptr %resume_ctxt
4545
}
4646

4747

4848
; CHECK: %my_async_function.Frame = type { i64, [48 x i8], i64, i64, [16 x i8], ptr, i64, ptr }
49-
; CHECK: define swiftcc void @my_async_function
49+
; CHECK: define swifttailcc void @my_async_function
5050
; CHECK: [[T0:%.*]] = getelementptr inbounds %my_async_function.Frame, ptr %async.ctx.frameptr, i32 0, i32 3
5151
; CHECK: [[T1:%.*]] = ptrtoint ptr [[T0]] to i64
5252
; CHECK: [[T2:%.*]] = add i64 [[T1]], 31
@@ -60,7 +60,7 @@ entry:
6060
; CHECK: store i64 2, ptr [[T4]]
6161
; CHECK: store i64 3, ptr [[T9]]
6262

63-
define swiftcc void @my_async_function(ptr swiftasync %async.ctxt) presplitcoroutine {
63+
define swifttailcc void @my_async_function(ptr swiftasync %async.ctxt) presplitcoroutine {
6464
entry:
6565
%tmp = alloca i64, align 8
6666
%tmp2 = alloca i64, align 16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
; RUN: opt < %s -passes='default<O2>' -S | FileCheck --check-prefixes=CHECK %s
2+
; RUN: opt < %s -O0 -S | FileCheck --check-prefixes=CHECK-O0 %s
3+
4+
5+
; CHECK-NOT: llvm.coro.suspend.async
6+
; CHECK-O0-NOT: llvm.coro.suspend.async
7+
8+
; This test used to crash during updating the call graph in coro splitting.
9+
10+
target datalayout = "p:64:64:64"
11+
12+
%swift.async_func_pointer = type <{ i32, i32 }>
13+
14+
@"$s1d3fooyySbYaFTu" = hidden global %swift.async_func_pointer <{ i32 trunc (i64 sub (i64 ptrtoint (ptr @"$s1d3fooyySbYaF" to i64), i64 ptrtoint (ptr @"$s1d3fooyySbYaFTu" to i64)) to i32), i32 16 }>
15+
@"$s1d3baryySbYaFTu" = hidden global %swift.async_func_pointer <{ i32 trunc (i64 sub (i64 ptrtoint (ptr @"$s1d3baryySbYaF" to i64), i64 ptrtoint (ptr @"$s1d3baryySbYaFTu" to i64)) to i32), i32 16 }>
16+
17+
define swifttailcc void @"$s1d3fooyySbYaF"(ptr swiftasync %0, i1 %1) {
18+
entry:
19+
%2 = alloca ptr, align 8
20+
%c.debug = alloca i1, align 8
21+
%3 = call token @llvm.coro.id.async(i32 16, i32 16, i32 0, ptr @"$s1d3fooyySbYaFTu")
22+
%4 = call ptr @llvm.coro.begin(token %3, ptr null)
23+
store ptr %0, ptr %2, align 8
24+
call void @llvm.memset.p0.i64(ptr align 8 %c.debug, i8 0, i64 1, i1 false)
25+
store i1 %1, ptr %c.debug, align 8
26+
call void asm sideeffect "", "r"(ptr %c.debug)
27+
%5 = load i32, ptr getelementptr inbounds (%swift.async_func_pointer, ptr @"$s1d3baryySbYaFTu", i32 0, i32 1), align 8
28+
%6 = zext i32 %5 to i64
29+
%7 = call swiftcc ptr @swift_task_alloc(i64 %6) #4
30+
call void @llvm.lifetime.start.p0(i64 -1, ptr %7)
31+
%8 = load ptr, ptr %2, align 8
32+
%9 = getelementptr inbounds <{ ptr, ptr }>, ptr %7, i32 0, i32 0
33+
store ptr %8, ptr %9, align 8
34+
%10 = call ptr @llvm.coro.async.resume()
35+
%11 = getelementptr inbounds <{ ptr, ptr }>, ptr %7, i32 0, i32 1
36+
store ptr %10, ptr %11, align 8
37+
%12 = call { ptr } (i32, ptr, ptr, ...) @llvm.coro.suspend.async.sl_p0s(i32 0, ptr %10, ptr @__swift_async_resume_project_context, ptr @"$s1d3fooyySbYaF.0", ptr @"$s1d3baryySbYaF", ptr %7, i1 %1)
38+
%13 = extractvalue { ptr } %12, 0
39+
%14 = call ptr @__swift_async_resume_project_context(ptr %13)
40+
store ptr %14, ptr %2, align 8
41+
call swiftcc void @swift_task_dealloc(ptr %7) #4
42+
call void @llvm.lifetime.end.p0(i64 -1, ptr %7)
43+
%15 = load ptr, ptr %2, align 8
44+
%16 = getelementptr inbounds <{ ptr, ptr }>, ptr %15, i32 0, i32 1
45+
%17 = load ptr, ptr %16, align 8
46+
%18 = load ptr, ptr %2, align 8
47+
%19 = call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr %4, i1 false, ptr @"$s1d3fooyySbYaF.0.1", ptr %17, ptr %18)
48+
unreachable
49+
}
50+
51+
declare token @llvm.coro.id.async(i32, i32, i32, ptr) #1
52+
53+
declare void @llvm.trap() #2
54+
55+
declare ptr @llvm.coro.begin(token, ptr) #1
56+
57+
declare void @llvm.memset.p0.i64(ptr nocapture, i8, i64, i1 immarg) #3
58+
59+
define hidden swifttailcc void @"$s1d3baryySbYaF"(ptr swiftasync %0, i1 %1) {
60+
entry:
61+
%2 = alloca ptr, align 8
62+
%c.debug = alloca i1, align 8
63+
%3 = call token @llvm.coro.id.async(i32 16, i32 16, i32 0, ptr @"$s1d3baryySbYaFTu")
64+
%4 = call ptr @llvm.coro.begin(token %3, ptr null)
65+
store ptr %0, ptr %2, align 8
66+
call void @llvm.memset.p0.i64(ptr align 8 %c.debug, i8 0, i64 1, i1 false)
67+
store i1 %1, ptr %c.debug, align 8
68+
call void asm sideeffect "", "r"(ptr %c.debug)
69+
br i1 %1, label %5, label %17
70+
71+
5: ; preds = %entry
72+
%6 = xor i1 %1, true
73+
%7 = load i32, ptr getelementptr inbounds (%swift.async_func_pointer, ptr @"$s1d3fooyySbYaFTu", i32 0, i32 1), align 8
74+
%8 = zext i32 %7 to i64
75+
%9 = call swiftcc ptr @swift_task_alloc(i64 %8) #4
76+
call void @llvm.lifetime.start.p0(i64 -1, ptr %9)
77+
%10 = load ptr, ptr %2, align 8
78+
%11 = getelementptr inbounds <{ ptr, ptr }>, ptr %9, i32 0, i32 0
79+
store ptr %10, ptr %11, align 8
80+
%12 = call ptr @llvm.coro.async.resume()
81+
%13 = getelementptr inbounds <{ ptr, ptr }>, ptr %9, i32 0, i32 1
82+
store ptr %12, ptr %13, align 8
83+
%14 = call { ptr } (i32, ptr, ptr, ...) @llvm.coro.suspend.async.sl_p0s(i32 0, ptr %12, ptr @__swift_async_resume_project_context, ptr @"$s1d3baryySbYaF.0.2", ptr @"$s1d3fooyySbYaF", ptr %9, i1 %6)
84+
%15 = extractvalue { ptr } %14, 0
85+
%16 = call ptr @__swift_async_resume_project_context(ptr %15)
86+
store ptr %16, ptr %2, align 8
87+
call swiftcc void @swift_task_dealloc(ptr %9) #4
88+
call void @llvm.lifetime.end.p0(i64 -1, ptr %9)
89+
br label %18
90+
91+
17: ; preds = %entry
92+
br label %18
93+
94+
18: ; preds = %5, %17
95+
%19 = load ptr, ptr %2, align 8
96+
%20 = getelementptr inbounds <{ ptr, ptr }>, ptr %19, i32 0, i32 1
97+
%21 = load ptr, ptr %20, align 8
98+
%22 = load ptr, ptr %2, align 8
99+
%23 = call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr %4, i1 false, ptr @"$s1d3baryySbYaF.0", ptr %21, ptr %22)
100+
unreachable
101+
}
102+
103+
declare swiftcc ptr @swift_task_alloc(i64) #4
104+
105+
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #5
106+
107+
declare ptr @llvm.coro.async.resume() #6
108+
109+
define linkonce_odr hidden ptr @__swift_async_resume_project_context(ptr %0) #7 {
110+
entry:
111+
%1 = load ptr, ptr %0, align 8
112+
%2 = call ptr @llvm.swift.async.context.addr()
113+
store ptr %1, ptr %2, align 8
114+
ret ptr %1
115+
}
116+
117+
declare ptr @llvm.swift.async.context.addr() #1
118+
119+
define internal swifttailcc void @"$s1d3fooyySbYaF.0"(ptr %0, ptr %1, i1 %2) #8 {
120+
entry:
121+
musttail call swifttailcc void %0(ptr swiftasync %1, i1 %2)
122+
ret void
123+
}
124+
125+
declare { ptr } @llvm.coro.suspend.async.sl_p0s(i32, ptr, ptr, ...) #6
126+
127+
declare swiftcc void @swift_task_dealloc(ptr) #4
128+
129+
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #5
130+
131+
define internal swifttailcc void @"$s1d3fooyySbYaF.0.1"(ptr %0, ptr %1) #8 {
132+
entry:
133+
musttail call swifttailcc void %0(ptr swiftasync %1)
134+
ret void
135+
}
136+
137+
declare i1 @llvm.coro.end.async(ptr, i1, ...) #1
138+
139+
define internal swifttailcc void @"$s1d3baryySbYaF.0"(ptr %0, ptr %1) #8 {
140+
entry:
141+
musttail call swifttailcc void %0(ptr swiftasync %1)
142+
ret void
143+
}
144+
145+
define internal swifttailcc void @"$s1d3baryySbYaF.0.2"(ptr %0, ptr %1, i1 %2) #8 {
146+
entry:
147+
musttail call swifttailcc void %0(ptr swiftasync %1, i1 %2)
148+
ret void
149+
}
150+
151+
attributes #1 = { nounwind }
152+
attributes #2 = { cold noreturn nounwind }
153+
attributes #3 = { nocallback nofree nounwind willreturn}
154+
attributes #4 = { nounwind }
155+
attributes #5 = { nocallback nofree nosync nounwind willreturn }
156+
attributes #6 = { nomerge nounwind }
157+
attributes #7 = { alwaysinline nounwind }
158+
attributes #8 = { alwaysinline nounwind }

llvm/test/Transforms/Coroutines/coro-async-unreachable.ll

+5-5
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ target datalayout = "p:64:64:64"
1313
declare void @my_other_async_function(ptr %async.ctxt)
1414

1515
; Function that implements the dispatch to the callee function.
16-
define swiftcc void @my_async_function.my_other_async_function_fp.apply(ptr %fnPtr, ptr %async.ctxt, ptr %task, ptr %actor) {
17-
tail call swiftcc void %fnPtr(ptr %async.ctxt, ptr %task, ptr %actor)
16+
define swifttailcc void @my_async_function.my_other_async_function_fp.apply(ptr %fnPtr, ptr %async.ctxt, ptr %task, ptr %actor) alwaysinline {
17+
musttail call swifttailcc void %fnPtr(ptr %async.ctxt, ptr %task, ptr %actor)
1818
ret void
1919
}
2020

@@ -38,7 +38,7 @@ entry:
3838
i32 128 ; Initial async context size without space for frame
3939
}>
4040

41-
define swiftcc void @unreachable(ptr %async.ctxt, ptr %task, ptr %actor) {
41+
define swifttailcc void @unreachable(ptr %async.ctxt, ptr %task, ptr %actor) {
4242
entry:
4343
%tmp = alloca { i64, i64 }, align 8
4444
%proj.1 = getelementptr inbounds { i64, i64 }, ptr %tmp, i64 0, i32 0
@@ -77,11 +77,11 @@ entry:
7777
unreachable
7878
}
7979

80-
; CHECK: define swiftcc void @unreachable
80+
; CHECK: define swifttailcc void @unreachable
8181
; CHECK-NOT: @llvm.coro.suspend.async
8282
; CHECK: return
8383

84-
; CHECK: define internal swiftcc void @unreachable.resume.0
84+
; CHECK: define internal swifttailcc void @unreachable.resume.0
8585
; CHECK: unreachable
8686

8787
declare ptr @llvm.coro.prepare.async(ptr)

0 commit comments

Comments
 (0)