Skip to content

Commit 041670d

Browse files
committed
[Pipelines] Do not run CoroSplit and CoroCleanup in ThinLTO pre-link pipeline
Skip CoroSplit and CoroCleanup in ThinLTO pre-link pipeline so that CoroElide can happen after callee coroutine is imported into caller's module in ThinLTO.
1 parent 842a332 commit 041670d

File tree

5 files changed

+91
-10
lines changed

5 files changed

+91
-10
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// REQUIRES: x86_64-linux
2+
// This tests that the coroutine elide optimization could happen succesfully with ThinLTO.
3+
// This test is adapted from coro-elide.cpp and splits functions into two files.
4+
//
5+
// RUN: split-file %s %t
6+
// RUN: %clang --target=x86_64-linux -std=c++20 -O2 -flto=thin -I %S -c %t/coro-elide-callee.cpp -o coro-elide-callee.bc
7+
// RUN: %clang --target=x86_64-linux -std=c++20 -O2 -flto=thin -I %S -c %t/coro-elide-caller.cpp -o coro-elide-caller.bc
8+
// RUN: llvm-lto --thinlto coro-elide-callee.bc coro-elide-caller.bc -o summary
9+
// RUN: %clang_cc1 -O2 -x ir coro-elide-caller.bc -fthinlto-index=summary.thinlto.bc -emit-llvm -o - | FileCheck %s
10+
//
11+
// Run asan
12+
// RUN: %clang --target=x86_64-linux -std=c++20 -O2 -flto=thin -fsanitize=address -I %S -c %t/coro-elide-callee.cpp -o coro-elide-callee.bc
13+
// RUN: %clang --target=x86_64-linux -std=c++20 -O2 -flto=thin -fsanitize=address -I %S -c %t/coro-elide-caller.cpp -o coro-elide-caller.bc
14+
// RUN: llvm-lto --thinlto coro-elide-callee.bc coro-elide-caller.bc -o summary
15+
// RUN: %clang_cc1 -O2 -x ir coro-elide-caller.bc -fthinlto-index=summary.thinlto.bc -emit-llvm -o - | FileCheck %s
16+
17+
//--- coro-elide-task.h
18+
#pragma once
19+
#include "Inputs/coroutine.h"
20+
21+
struct Task {
22+
struct promise_type {
23+
struct FinalAwaiter {
24+
bool await_ready() const noexcept { return false; }
25+
template <typename PromiseType>
26+
std::coroutine_handle<> await_suspend(std::coroutine_handle<PromiseType> h) noexcept {
27+
if (!h)
28+
return std::noop_coroutine();
29+
return h.promise().continuation;
30+
}
31+
void await_resume() noexcept {}
32+
};
33+
Task get_return_object() noexcept {
34+
return std::coroutine_handle<promise_type>::from_promise(*this);
35+
}
36+
std::suspend_always initial_suspend() noexcept { return {}; }
37+
FinalAwaiter final_suspend() noexcept { return {}; }
38+
void unhandled_exception() noexcept {}
39+
void return_value(int x) noexcept {
40+
_value = x;
41+
}
42+
std::coroutine_handle<> continuation;
43+
int _value;
44+
};
45+
46+
Task(std::coroutine_handle<promise_type> handle) : handle(handle) {}
47+
~Task() {
48+
if (handle)
49+
handle.destroy();
50+
}
51+
52+
struct Awaiter {
53+
bool await_ready() const noexcept { return false; }
54+
void await_suspend(std::coroutine_handle<void> continuation) noexcept {}
55+
int await_resume() noexcept {
56+
return 43;
57+
}
58+
};
59+
60+
auto operator co_await() {
61+
return Awaiter{};
62+
}
63+
64+
private:
65+
std::coroutine_handle<promise_type> handle;
66+
};
67+
68+
//--- coro-elide-callee.cpp
69+
#include "coro-elide-task.h"
70+
Task task0() {
71+
co_return 43;
72+
}
73+
74+
//--- coro-elide-caller.cpp
75+
#include "coro-elide-task.h"
76+
77+
Task task0();
78+
79+
Task task1() {
80+
co_return co_await task0();
81+
}
82+
83+
// CHECK-LABEL: define{{.*}} void @_Z5task1v.resume
84+
// CHECK-NOT: {{.*}}_Znwm

llvm/lib/Passes/PassBuilderPipelines.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -979,7 +979,8 @@ PassBuilder::buildInlinerPipeline(OptimizationLevel Level,
979979
MainCGPipeline.addPass(createCGSCCToFunctionPassAdaptor(
980980
RequireAnalysisPass<ShouldNotRunFunctionPassesAnalysis, Function>()));
981981

982-
MainCGPipeline.addPass(CoroSplitPass(Level != OptimizationLevel::O0));
982+
if (Phase != ThinOrFullLTOPhase::ThinLTOPreLink)
983+
MainCGPipeline.addPass(CoroSplitPass(Level != OptimizationLevel::O0));
983984

984985
// Make sure we don't affect potential future NoRerun CGSCC adaptors.
985986
MIWP.addLateModulePass(createModuleToFunctionPassAdaptor(
@@ -1021,8 +1022,9 @@ PassBuilder::buildModuleInlinerPipeline(OptimizationLevel Level,
10211022
buildFunctionSimplificationPipeline(Level, Phase),
10221023
PTO.EagerlyInvalidateAnalyses));
10231024

1024-
MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(
1025-
CoroSplitPass(Level != OptimizationLevel::O0)));
1025+
if (Phase != ThinOrFullLTOPhase::ThinLTOPreLink)
1026+
MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(
1027+
CoroSplitPass(Level != OptimizationLevel::O0)));
10261028

10271029
return MPM;
10281030
}
@@ -1219,7 +1221,8 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
12191221
// and argument promotion.
12201222
MPM.addPass(DeadArgumentEliminationPass());
12211223

1222-
MPM.addPass(CoroCleanupPass());
1224+
if (Phase != ThinOrFullLTOPhase::ThinLTOPreLink)
1225+
MPM.addPass(CoroCleanupPass());
12231226

12241227
// Optimize globals now that functions are fully simplified.
12251228
MPM.addPass(GlobalOptPass());

llvm/test/Other/new-pm-thinlto-prelink-defaults.ll

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,12 +184,10 @@
184184
; CHECK-O-NEXT: Running pass: PostOrderFunctionAttrsPass
185185
; CHECK-O-NEXT: Running pass: RequireAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
186186
; CHECK-O-NEXT: Running analysis: ShouldNotRunFunctionPassesAnalysis
187-
; CHECK-O-NEXT: Running pass: CoroSplitPass
188187
; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
189188
; CHECK-O-NEXT: Invalidating analysis: ShouldNotRunFunctionPassesAnalysis
190189
; CHECK-O-NEXT: Invalidating analysis: InlineAdvisorAnalysis
191190
; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass
192-
; CHECK-O-NEXT: Running pass: CoroCleanupPass
193191
; CHECK-O-NEXT: Running pass: GlobalOptPass
194192
; CHECK-O-NEXT: Running pass: GlobalDCEPass
195193
; CHECK-EXT: Running pass: {{.*}}::Bye

llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,12 +183,10 @@
183183
; CHECK-O-NEXT: Running pass: PostOrderFunctionAttrsPass
184184
; CHECK-O-NEXT: Running pass: RequireAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
185185
; CHECK-O-NEXT: Running analysis: ShouldNotRunFunctionPassesAnalysis
186-
; CHECK-O-NEXT: Running pass: CoroSplitPass
187186
; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
188187
; CHECK-O-NEXT: Invalidating analysis: ShouldNotRunFunctionPassesAnalysis
189188
; CHECK-O-NEXT: Invalidating analysis: InlineAdvisorAnalysis
190189
; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass
191-
; CHECK-O-NEXT: Running pass: CoroCleanupPass
192190
; CHECK-O-NEXT: Running pass: GlobalOptPass
193191
; CHECK-O-NEXT: Running analysis: TargetLibraryAnalysis on bar
194192
; CHECK-O-NEXT: Running pass: GlobalDCEPass

llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,12 +148,10 @@
148148
; CHECK-O-NEXT: Running pass: PostOrderFunctionAttrsPass
149149
; CHECK-O-NEXT: Running pass: RequireAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
150150
; CHECK-O-NEXT: Running analysis: ShouldNotRunFunctionPassesAnalysis
151-
; CHECK-O-NEXT: Running pass: CoroSplitPass
152151
; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
153152
; CHECK-O-NEXT: Invalidating analysis: ShouldNotRunFunctionPassesAnalysis
154153
; CHECK-O-NEXT: Invalidating analysis: InlineAdvisorAnalysis
155154
; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass
156-
; CHECK-O-NEXT: Running pass: CoroCleanupPass
157155
; CHECK-O-NEXT: Running pass: GlobalOptPass
158156
; CHECK-O-NEXT: Running pass: GlobalDCEPass
159157
; CHECK-O-NEXT: Running pass: AnnotationRemarksPass on foo

0 commit comments

Comments
 (0)