Skip to content

Commit 268c065

Browse files
authored
[fatlto] Add coroutine passes when using FatLTO with ThinLTO (#134434)
When coroutines are used w/ both -ffat-lto-objects and -flto=thin, the coroutine passes are not added to the optimization pipelines. Ensure they are added before ModuleOptimization to generate a working ELF object. Fixes #134409.
1 parent b09daa4 commit 268c065

File tree

2 files changed

+56
-0
lines changed

2 files changed

+56
-0
lines changed
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// An end-to-end test to make sure coroutine passes are added for thinlto.
2+
// REQUIRES: x86-registered-target
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++23 -ffat-lto-objects -flto=thin -emit-llvm %s -O3 -o - \
4+
// RUN: | FileCheck %s
5+
6+
#include "Inputs/coroutine.h"
7+
8+
class BasicCoroutine {
9+
public:
10+
struct Promise {
11+
BasicCoroutine get_return_object() { return BasicCoroutine {}; }
12+
13+
void unhandled_exception() noexcept { }
14+
15+
void return_void() noexcept { }
16+
17+
std::suspend_never initial_suspend() noexcept { return {}; }
18+
std::suspend_never final_suspend() noexcept { return {}; }
19+
};
20+
using promise_type = Promise;
21+
};
22+
23+
// COM: match the embedded module, so we don't match something in it by accident.
24+
// CHECK: @llvm.embedded.object = {{.*}}
25+
// CHECK: @llvm.compiler.used = {{.*}}
26+
27+
BasicCoroutine coro() {
28+
// CHECK: define {{.*}} void @_Z4corov() {{.*}} {
29+
// CHECK-NEXT: entry:
30+
// CHECK-NEXT: ret void
31+
// CHECK-NEXT: }
32+
co_return;
33+
}
34+
35+
int main() {
36+
// CHECK: define {{.*}} i32 @main() {{.*}} {
37+
// CHECK-NEXT: entry:
38+
// CHECK-NEXT: tail call void @_Z4corov()
39+
// CHECK-NEXT: ret i32 0
40+
// CHECK-NEXT: }
41+
coro();
42+
}
43+

llvm/lib/Passes/PassBuilderPipelines.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -1692,6 +1692,19 @@ PassBuilder::buildFatLTODefaultPipeline(OptimizationLevel Level, bool ThinLTO,
16921692
if (ThinLTO && PGOOpt && PGOOpt->Action == PGOOptions::SampleUse)
16931693
MPM.addPass(buildThinLTODefaultPipeline(Level, /*ImportSummary=*/nullptr));
16941694
else {
1695+
// ModuleSimplification does not run the coroutine passes for
1696+
// ThinLTOPreLink, so we need the coroutine passes to run for ThinLTO
1697+
// builds, otherwise they will miscompile.
1698+
if (ThinLTO) {
1699+
// TODO: replace w/ buildCoroWrapper() when it takes phase and level into
1700+
// consideration.
1701+
CGSCCPassManager CGPM;
1702+
CGPM.addPass(CoroSplitPass(Level != OptimizationLevel::O0));
1703+
CGPM.addPass(CoroAnnotationElidePass());
1704+
MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
1705+
MPM.addPass(CoroCleanupPass());
1706+
}
1707+
16951708
// otherwise, just use module optimization
16961709
MPM.addPass(
16971710
buildModuleOptimizationPipeline(Level, ThinOrFullLTOPhase::None));

0 commit comments

Comments
 (0)