Skip to content

Commit 81220e6

Browse files
ilovepitstellar
authored andcommitted
[fatlto] Add coroutine passes when using FatLTO with ThinLTO (llvm#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 llvm#134409. (cherry picked from commit 268c065)
1 parent edb54a7 commit 81220e6

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
@@ -1660,6 +1660,19 @@ PassBuilder::buildFatLTODefaultPipeline(OptimizationLevel Level, bool ThinLTO,
16601660
if (ThinLTO && PGOOpt && PGOOpt->Action == PGOOptions::SampleUse)
16611661
MPM.addPass(buildThinLTODefaultPipeline(Level, /*ImportSummary=*/nullptr));
16621662
else {
1663+
// ModuleSimplification does not run the coroutine passes for
1664+
// ThinLTOPreLink, so we need the coroutine passes to run for ThinLTO
1665+
// builds, otherwise they will miscompile.
1666+
if (ThinLTO) {
1667+
// TODO: replace w/ buildCoroWrapper() when it takes phase and level into
1668+
// consideration.
1669+
CGSCCPassManager CGPM;
1670+
CGPM.addPass(CoroSplitPass(Level != OptimizationLevel::O0));
1671+
CGPM.addPass(CoroAnnotationElidePass());
1672+
MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
1673+
MPM.addPass(CoroCleanupPass());
1674+
}
1675+
16631676
// otherwise, just use module optimization
16641677
MPM.addPass(
16651678
buildModuleOptimizationPipeline(Level, ThinOrFullLTOPhase::None));

0 commit comments

Comments
 (0)