Skip to content

Commit 86fd4d4

Browse files
[Coroutines] Fix another crash related to CallGraph update (#116756)
The previous fix c641497 failed to consider the fact that the call graph update doesn't make any sense if the caller node hasn't been populated in the LazyCallGraph yet. This patch changes to skip this CG update step when that happens.
1 parent cc70e12 commit 86fd4d4

File tree

2 files changed

+165
-3
lines changed

2 files changed

+165
-3
lines changed

llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,10 @@ PreservedAnalyses CoroAnnotationElidePass::run(LazyCallGraph::SCC &C,
146146
bool HasAttr = CB->hasFnAttr(llvm::Attribute::CoroElideSafe);
147147
if (IsCallerPresplitCoroutine && HasAttr) {
148148
auto *CallerN = CG.lookup(*Caller);
149-
auto *CallerC = CG.lookupSCC(*CallerN);
149+
auto *CallerC = CallerN ? CG.lookupSCC(*CallerN) : nullptr;
150+
// If CallerC is nullptr, it means LazyCallGraph hasn't visited Caller
151+
// yet. Skip the call graph update.
152+
auto ShouldUpdateCallGraph = !!CallerC;
150153
processCall(CB, Caller, NewCallee, FrameSize, FrameAlign);
151154

152155
ORE.emit([&]() {
@@ -158,8 +161,9 @@ PreservedAnalyses CoroAnnotationElidePass::run(LazyCallGraph::SCC &C,
158161

159162
FAM.invalidate(*Caller, PreservedAnalyses::none());
160163
Changed = true;
161-
updateCGAndAnalysisManagerForCGSCCPass(CG, *CallerC, *CallerN, AM, UR,
162-
FAM);
164+
if (ShouldUpdateCallGraph)
165+
updateCGAndAnalysisManagerForCGSCCPass(CG, *CallerC, *CallerN, AM, UR,
166+
FAM);
163167

164168
} else {
165169
ORE.emit([&]() {
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
; RUN: opt -passes="cgscc(coro-annotation-elide)" -S < %s | FileCheck %s
2+
3+
%foo.Frame = type { ptr, ptr, i1 }
4+
5+
@foo.resumers = private constant [3 x ptr] [ptr @foo.resume, ptr @foo.destroy, ptr @foo.cleanup]
6+
@foo.resumers.1 = private constant [4 x ptr] [ptr @foo.resume, ptr @foo.destroy, ptr @foo.cleanup, ptr @foo.noalloc]
7+
8+
; CHECK-LABEL: define void @foo
9+
define void @foo(ptr %agg.result, ptr %this) personality ptr null {
10+
entry:
11+
%0 = call token @llvm.coro.id(i32 0, ptr null, ptr nonnull @foo, ptr @foo.resumers.1)
12+
%1 = call noalias nonnull ptr @llvm.coro.begin(token %0, ptr null)
13+
%resume.addr = getelementptr inbounds nuw %foo.Frame, ptr %1, i32 0, i32 0
14+
store ptr @foo.resume, ptr %resume.addr, align 8
15+
%destroy.addr = getelementptr inbounds nuw %foo.Frame, ptr %1, i32 0, i32 1
16+
store ptr @foo.destroy, ptr %destroy.addr, align 8
17+
br label %AllocaSpillBB
18+
19+
AllocaSpillBB: ; preds = %entry
20+
br label %PostSpill
21+
22+
PostSpill: ; preds = %AllocaSpillBB
23+
br label %CoroSave
24+
25+
CoroSave: ; preds = %PostSpill
26+
%index.addr1 = getelementptr inbounds nuw %foo.Frame, ptr %1, i32 0, i32 2
27+
store i1 false, ptr %index.addr1, align 1
28+
br label %CoroSuspend
29+
30+
CoroSuspend: ; preds = %CoroSave
31+
br label %resume.0.landing
32+
33+
resume.0.landing: ; preds = %CoroSuspend
34+
br label %AfterCoroSuspend
35+
36+
AfterCoroSuspend: ; preds = %resume.0.landing
37+
ret void
38+
}
39+
40+
; CHECK-LABEL: define internal void @bar
41+
; Function Attrs: presplitcoroutine
42+
define internal void @bar() #0 personality ptr null {
43+
entry:
44+
; CHECK: %[[CALLEE_FRAME:.+]] = alloca [24 x i8], align 8
45+
%0 = call token @llvm.coro.id(i32 0, ptr null, ptr nonnull @bar, ptr null)
46+
%1 = call i1 @llvm.coro.alloc(token %0)
47+
call void @foo(ptr null, ptr null) #4
48+
; CHECK: %[[FOO_ID:.+]] = call token @llvm.coro.id(i32 0, ptr null, ptr nonnull @foo, ptr @foo.resumers)
49+
; CHECK-NEXT: store ptr @foo.resume, ptr %[[CALLEE_FRAME]], align 8
50+
; CHECK-NEXT: %[[DESTROY_ADDR:.+]] = getelementptr inbounds nuw %foo.Frame, ptr %[[CALLEE_FRAME]], i32 0, i32 1
51+
; CHECK-NEXT: store ptr @foo.destroy, ptr %[[DESTROY_ADDR]], align 8
52+
; CHECK-NEXT: %[[INDEX_ADDR:.+]] = getelementptr inbounds nuw %foo.Frame, ptr %[[CALLEE_FRAME]], i32 0, i32 2
53+
; CHECK-NEXT: store i1 false, ptr %[[INDEX_ADDR]], align 1
54+
; CHECK: ret void
55+
ret void
56+
}
57+
58+
; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: read)
59+
declare token @llvm.coro.id(i32, ptr readnone, ptr nocapture readonly, ptr) #1
60+
61+
; Function Attrs: nounwind
62+
declare i1 @llvm.coro.alloc(token) #2
63+
64+
; Function Attrs: nounwind
65+
declare ptr @llvm.coro.begin(token, ptr writeonly) #2
66+
67+
; Function Attrs: nomerge nounwind
68+
declare token @llvm.coro.save(ptr) #3
69+
70+
; Function Attrs: nounwind
71+
declare i8 @llvm.coro.suspend(token, i1) #2
72+
73+
define internal fastcc void @foo.resume(ptr noundef nonnull align 8 dereferenceable(24) %0) personality ptr null {
74+
entry.resume:
75+
br label %resume.entry
76+
77+
resume.0: ; preds = %resume.entry
78+
br label %resume.0.landing
79+
80+
resume.0.landing: ; preds = %resume.0
81+
br label %AfterCoroSuspend
82+
83+
AfterCoroSuspend: ; preds = %resume.0.landing
84+
unreachable
85+
86+
resume.entry: ; preds = %entry.resume
87+
br label %resume.0
88+
}
89+
90+
define internal fastcc void @foo.destroy(ptr noundef nonnull align 8 dereferenceable(24) %0) personality ptr null {
91+
entry.destroy:
92+
br label %resume.entry
93+
94+
resume.0: ; preds = %resume.entry
95+
br label %resume.0.landing
96+
97+
resume.0.landing: ; preds = %resume.0
98+
br label %AfterCoroSuspend
99+
100+
AfterCoroSuspend: ; preds = %resume.0.landing
101+
unreachable
102+
103+
resume.entry: ; preds = %entry.destroy
104+
br label %resume.0
105+
}
106+
107+
define internal fastcc void @foo.cleanup(ptr noundef nonnull align 8 dereferenceable(24) %0) personality ptr null {
108+
entry.cleanup:
109+
br label %resume.entry
110+
111+
resume.0: ; preds = %resume.entry
112+
br label %resume.0.landing
113+
114+
resume.0.landing: ; preds = %resume.0
115+
br label %AfterCoroSuspend
116+
117+
AfterCoroSuspend: ; preds = %resume.0.landing
118+
unreachable
119+
120+
resume.entry: ; preds = %entry.cleanup
121+
br label %resume.0
122+
}
123+
124+
define internal void @foo.noalloc(ptr %0, ptr %1, ptr noundef nonnull align 8 dereferenceable(24) %2) personality ptr null {
125+
entry:
126+
%3 = call token @llvm.coro.id(i32 0, ptr null, ptr nonnull @foo, ptr @foo.resumers)
127+
%resume.addr = getelementptr inbounds nuw %foo.Frame, ptr %2, i32 0, i32 0
128+
store ptr @foo.resume, ptr %resume.addr, align 8
129+
%destroy.addr = getelementptr inbounds nuw %foo.Frame, ptr %2, i32 0, i32 1
130+
store ptr @foo.destroy, ptr %destroy.addr, align 8
131+
br label %AllocaSpillBB
132+
133+
AllocaSpillBB: ; preds = %entry
134+
br label %PostSpill
135+
136+
PostSpill: ; preds = %AllocaSpillBB
137+
br label %CoroSave
138+
139+
CoroSave: ; preds = %PostSpill
140+
%index.addr1 = getelementptr inbounds nuw %foo.Frame, ptr %2, i32 0, i32 2
141+
store i1 false, ptr %index.addr1, align 1
142+
br label %CoroSuspend
143+
144+
CoroSuspend: ; preds = %CoroSave
145+
br label %resume.0.landing
146+
147+
resume.0.landing: ; preds = %CoroSuspend
148+
br label %AfterCoroSuspend
149+
150+
AfterCoroSuspend: ; preds = %resume.0.landing
151+
ret void
152+
}
153+
154+
attributes #0 = { presplitcoroutine }
155+
attributes #1 = { mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: read) }
156+
attributes #2 = { nounwind }
157+
attributes #3 = { nomerge nounwind }
158+
attributes #4 = { coro_elide_safe }

0 commit comments

Comments
 (0)