https://github.com/llvmbot created https://github.com/llvm/llvm-project/pull/134711
Backport 268c065eab06b81a0d7256ac62c0865b3781e236 Requested by: @nikic >From 6b1ebaea68f1e2140c54cc2c4a271e2847451c08 Mon Sep 17 00:00:00 2001 From: Paul Kirth <paulki...@google.com> Date: Mon, 7 Apr 2025 08:41:49 -0700 Subject: [PATCH] [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. (cherry picked from commit 268c065eab06b81a0d7256ac62c0865b3781e236) --- clang/test/CodeGenCoroutines/pr134409.cpp | 43 +++++++++++++++++++++++ llvm/lib/Passes/PassBuilderPipelines.cpp | 13 +++++++ 2 files changed, 56 insertions(+) create mode 100644 clang/test/CodeGenCoroutines/pr134409.cpp diff --git a/clang/test/CodeGenCoroutines/pr134409.cpp b/clang/test/CodeGenCoroutines/pr134409.cpp new file mode 100644 index 0000000000000..142962d44ede4 --- /dev/null +++ b/clang/test/CodeGenCoroutines/pr134409.cpp @@ -0,0 +1,43 @@ +// An end-to-end test to make sure coroutine passes are added for thinlto. +// REQUIRES: x86-registered-target +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++23 -ffat-lto-objects -flto=thin -emit-llvm %s -O3 -o - \ +// RUN: | FileCheck %s + +#include "Inputs/coroutine.h" + +class BasicCoroutine { +public: + struct Promise { + BasicCoroutine get_return_object() { return BasicCoroutine {}; } + + void unhandled_exception() noexcept { } + + void return_void() noexcept { } + + std::suspend_never initial_suspend() noexcept { return {}; } + std::suspend_never final_suspend() noexcept { return {}; } + }; + using promise_type = Promise; +}; + +// COM: match the embedded module, so we don't match something in it by accident. +// CHECK: @llvm.embedded.object = {{.*}} +// CHECK: @llvm.compiler.used = {{.*}} + +BasicCoroutine coro() { +// CHECK: define {{.*}} void @_Z4corov() {{.*}} { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret void +// CHECK-NEXT: } + co_return; +} + +int main() { +// CHECK: define {{.*}} i32 @main() {{.*}} { +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @_Z4corov() +// CHECK-NEXT: ret i32 0 +// CHECK-NEXT: } + coro(); +} + diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp index 17ff3bd37884b..d195619f32d0b 100644 --- a/llvm/lib/Passes/PassBuilderPipelines.cpp +++ b/llvm/lib/Passes/PassBuilderPipelines.cpp @@ -1660,6 +1660,19 @@ PassBuilder::buildFatLTODefaultPipeline(OptimizationLevel Level, bool ThinLTO, if (ThinLTO && PGOOpt && PGOOpt->Action == PGOOptions::SampleUse) MPM.addPass(buildThinLTODefaultPipeline(Level, /*ImportSummary=*/nullptr)); else { + // ModuleSimplification does not run the coroutine passes for + // ThinLTOPreLink, so we need the coroutine passes to run for ThinLTO + // builds, otherwise they will miscompile. + if (ThinLTO) { + // TODO: replace w/ buildCoroWrapper() when it takes phase and level into + // consideration. + CGSCCPassManager CGPM; + CGPM.addPass(CoroSplitPass(Level != OptimizationLevel::O0)); + CGPM.addPass(CoroAnnotationElidePass()); + MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); + MPM.addPass(CoroCleanupPass()); + } + // otherwise, just use module optimization MPM.addPass( buildModuleOptimizationPipeline(Level, ThinOrFullLTOPhase::None)); _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits