[Pipelines] Do not run CoroSplit and CoroCleanup in LTO pre-link pipeline (#100205)

This is re-land of #90310 after making asan skip pre-split coroutines in
#99415.

Skip CoroSplit and CoroCleanup in LTO pre-link pipeline so that
CoroElide can happen after callee coroutine is imported into caller's
module in ThinLTO.
This commit is contained in:
Wei Wang 2024-07-29 17:42:01 -07:00 committed by GitHub
parent ee6d932b4f
commit 3a9ef4e69a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 85 additions and 10 deletions

View File

@ -0,0 +1,78 @@
// REQUIRES: x86_64-linux
// This tests that the coroutine elide optimization could happen succesfully with ThinLTO.
// This test is adapted from coro-elide.cpp and splits functions into two files.
//
// RUN: split-file %s %t
// 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
// 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
// RUN: llvm-lto --thinlto coro-elide-callee.bc coro-elide-caller.bc -o summary
// RUN: %clang_cc1 -O2 -x ir coro-elide-caller.bc -fthinlto-index=summary.thinlto.bc -emit-llvm -o - | FileCheck %s
//--- coro-elide-task.h
#pragma once
#include "Inputs/coroutine.h"
struct Task {
struct promise_type {
struct FinalAwaiter {
bool await_ready() const noexcept { return false; }
template <typename PromiseType>
std::coroutine_handle<> await_suspend(std::coroutine_handle<PromiseType> h) noexcept {
if (!h)
return std::noop_coroutine();
return h.promise().continuation;
}
void await_resume() noexcept {}
};
Task get_return_object() noexcept {
return std::coroutine_handle<promise_type>::from_promise(*this);
}
std::suspend_always initial_suspend() noexcept { return {}; }
FinalAwaiter final_suspend() noexcept { return {}; }
void unhandled_exception() noexcept {}
void return_value(int x) noexcept {
_value = x;
}
std::coroutine_handle<> continuation;
int _value;
};
Task(std::coroutine_handle<promise_type> handle) : handle(handle) {}
~Task() {
if (handle)
handle.destroy();
}
struct Awaiter {
bool await_ready() const noexcept { return false; }
void await_suspend(std::coroutine_handle<void> continuation) noexcept {}
int await_resume() noexcept {
return 43;
}
};
auto operator co_await() {
return Awaiter{};
}
private:
std::coroutine_handle<promise_type> handle;
};
//--- coro-elide-callee.cpp
#include "coro-elide-task.h"
Task task0() {
co_return 43;
}
//--- coro-elide-caller.cpp
#include "coro-elide-task.h"
Task task0();
Task task1() {
co_return co_await task0();
}
// CHECK-LABEL: define{{.*}} void @_Z5task1v.resume
// CHECK-NOT: {{.*}}_Znwm

View File

@ -979,7 +979,8 @@ PassBuilder::buildInlinerPipeline(OptimizationLevel Level,
MainCGPipeline.addPass(createCGSCCToFunctionPassAdaptor(
RequireAnalysisPass<ShouldNotRunFunctionPassesAnalysis, Function>()));
MainCGPipeline.addPass(CoroSplitPass(Level != OptimizationLevel::O0));
if (Phase != ThinOrFullLTOPhase::ThinLTOPreLink)
MainCGPipeline.addPass(CoroSplitPass(Level != OptimizationLevel::O0));
// Make sure we don't affect potential future NoRerun CGSCC adaptors.
MIWP.addLateModulePass(createModuleToFunctionPassAdaptor(
@ -1021,8 +1022,9 @@ PassBuilder::buildModuleInlinerPipeline(OptimizationLevel Level,
buildFunctionSimplificationPipeline(Level, Phase),
PTO.EagerlyInvalidateAnalyses));
MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(
CoroSplitPass(Level != OptimizationLevel::O0)));
if (Phase != ThinOrFullLTOPhase::ThinLTOPreLink)
MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(
CoroSplitPass(Level != OptimizationLevel::O0)));
return MPM;
}
@ -1219,7 +1221,8 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
// and argument promotion.
MPM.addPass(DeadArgumentEliminationPass());
MPM.addPass(CoroCleanupPass());
if (Phase != ThinOrFullLTOPhase::ThinLTOPreLink)
MPM.addPass(CoroCleanupPass());
// Optimize globals now that functions are fully simplified.
MPM.addPass(GlobalOptPass());

View File

@ -184,12 +184,10 @@
; CHECK-O-NEXT: Running pass: PostOrderFunctionAttrsPass
; CHECK-O-NEXT: Running pass: RequireAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
; CHECK-O-NEXT: Running analysis: ShouldNotRunFunctionPassesAnalysis
; CHECK-O-NEXT: Running pass: CoroSplitPass
; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
; CHECK-O-NEXT: Invalidating analysis: ShouldNotRunFunctionPassesAnalysis
; CHECK-O-NEXT: Invalidating analysis: InlineAdvisorAnalysis
; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass
; CHECK-O-NEXT: Running pass: CoroCleanupPass
; CHECK-O-NEXT: Running pass: GlobalOptPass
; CHECK-O-NEXT: Running pass: GlobalDCEPass
; CHECK-EXT: Running pass: {{.*}}::Bye

View File

@ -183,12 +183,10 @@
; CHECK-O-NEXT: Running pass: PostOrderFunctionAttrsPass
; CHECK-O-NEXT: Running pass: RequireAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
; CHECK-O-NEXT: Running analysis: ShouldNotRunFunctionPassesAnalysis
; CHECK-O-NEXT: Running pass: CoroSplitPass
; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
; CHECK-O-NEXT: Invalidating analysis: ShouldNotRunFunctionPassesAnalysis
; CHECK-O-NEXT: Invalidating analysis: InlineAdvisorAnalysis
; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass
; CHECK-O-NEXT: Running pass: CoroCleanupPass
; CHECK-O-NEXT: Running pass: GlobalOptPass
; CHECK-O-NEXT: Running analysis: TargetLibraryAnalysis on bar
; CHECK-O-NEXT: Running pass: GlobalDCEPass

View File

@ -148,12 +148,10 @@
; CHECK-O-NEXT: Running pass: PostOrderFunctionAttrsPass
; CHECK-O-NEXT: Running pass: RequireAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
; CHECK-O-NEXT: Running analysis: ShouldNotRunFunctionPassesAnalysis
; CHECK-O-NEXT: Running pass: CoroSplitPass
; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
; CHECK-O-NEXT: Invalidating analysis: ShouldNotRunFunctionPassesAnalysis
; CHECK-O-NEXT: Invalidating analysis: InlineAdvisorAnalysis
; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass
; CHECK-O-NEXT: Running pass: CoroCleanupPass
; CHECK-O-NEXT: Running pass: GlobalOptPass
; CHECK-O-NEXT: Running pass: GlobalDCEPass
; CHECK-O-NEXT: Running pass: AnnotationRemarksPass on foo