[Coroutines][6/6] Clang schedules new passes

Summary:
Depends on https://reviews.llvm.org/D71902.

The last in a series of six patches that ports the LLVM coroutines
passes to the new pass manager infrastructure.

This patch has Clang schedule the new coroutines passes when the
`-fexperimental-new-pass-manager` option is used. With this and the
previous 5 patches, Clang is capable of building and successfully
running the test suite of large coroutines projects such as
https://github.com/lewissbaker/cppcoro with
`ENABLE_EXPERIMENTAL_NEW_PASS_MANAGER=On`.

Reviewers: GorNishanov, lewissbaker, chandlerc, junparser

Subscribers: EricWF, cfe-commits, llvm-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D71903
This commit is contained in:
Brian Gesiak
2019-12-26 08:00:00 -05:00
parent 72961071f3
commit 048239e46e
2 changed files with 79 additions and 0 deletions

View File

@@ -49,6 +49,10 @@
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Transforms/Coroutines.h"
#include "llvm/Transforms/Coroutines/CoroCleanup.h"
#include "llvm/Transforms/Coroutines/CoroEarly.h"
#include "llvm/Transforms/Coroutines/CoroElide.h"
#include "llvm/Transforms/Coroutines/CoroSplit.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/AlwaysInliner.h"
#include "llvm/Transforms/IPO/LowerTypeTests.h"
@@ -957,6 +961,22 @@ static PassBuilder::OptimizationLevel mapToLevel(const CodeGenOptions &Opts) {
}
}
static void addCoroutinePassesAtO0(ModulePassManager &MPM,
const LangOptions &LangOpts,
const CodeGenOptions &CodeGenOpts) {
if (!LangOpts.Coroutines)
return;
MPM.addPass(createModuleToFunctionPassAdaptor(CoroEarlyPass()));
CGSCCPassManager CGPM(CodeGenOpts.DebugPassManager);
CGPM.addPass(CoroSplitPass());
CGPM.addPass(createCGSCCToFunctionPassAdaptor(CoroElidePass()));
MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
MPM.addPass(createModuleToFunctionPassAdaptor(CoroCleanupPass()));
}
static void addSanitizersAtO0(ModulePassManager &MPM,
const Triple &TargetTriple,
const LangOptions &LangOpts,
@@ -1076,6 +1096,7 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
PTO.LoopInterleaving = CodeGenOpts.UnrollLoops;
PTO.LoopVectorization = CodeGenOpts.VectorizeLoop;
PTO.SLPVectorization = CodeGenOpts.VectorizeSLP;
PTO.Coroutines = LangOpts.Coroutines;
PassInstrumentationCallbacks PIC;
StandardInstrumentations SI;
@@ -1279,6 +1300,7 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
}
if (CodeGenOpts.OptimizationLevel == 0) {
addCoroutinePassesAtO0(MPM, LangOpts, CodeGenOpts);
addSanitizersAtO0(MPM, TargetTriple, LangOpts, CodeGenOpts);
}
}

View File

@@ -0,0 +1,57 @@
// Tests that coroutine passes are added to and run by the new pass manager
// pipeline, at -O0 and above.
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm-bc -o /dev/null \
// RUN: -fexperimental-new-pass-manager -fdebug-pass-manager -fcoroutines-ts \
// RUN: -O0 %s 2>&1 | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm-bc -o /dev/null \
// RUN: -fexperimental-new-pass-manager -fdebug-pass-manager -fcoroutines-ts \
// RUN: -O1 %s 2>&1 | FileCheck %s
//
// CHECK: Starting llvm::Module pass manager run.
// CHECK: Running pass:{{.*}}CoroEarlyPass
//
// The first coro-split pass enqueues a second run of the entire CGSCC pipeline.
// CHECK: Starting CGSCC pass manager run.
// CHECK: Running pass: CoroSplitPass on (_Z3foov)
// CHECK: Running pass:{{.*}}CoroElidePass{{.*}} on (_Z3foov)
// CHECK: Finished CGSCC pass manager run.
//
// The second coro-split pass splits coroutine 'foo' into funclets
// 'foo.resume', 'foo.destroy', and 'foo.cleanup'.
// CHECK: Starting CGSCC pass manager run.
// CHECK: Running pass: CoroSplitPass on (_Z3foov)
// CHECK: Running pass:{{.*}}CoroElidePass{{.*}} on (_Z3foov)
// CHECK: Finished CGSCC pass manager run.
//
// CHECK: Running pass:{{.*}}CoroCleanupPass
// CHECK: Finished llvm::Module pass manager run.
namespace std {
namespace experimental {
struct handle {};
struct awaitable {
bool await_ready() { return true; }
void await_suspend(handle) {}
bool await_resume() { return true; }
};
template <typename T> struct coroutine_handle {
static handle from_address(void *address) { return {}; }
};
template <typename T = void> struct coroutine_traits {
struct promise_type {
awaitable initial_suspend() { return {}; }
awaitable final_suspend() { return {}; }
void return_void() {}
T get_return_object() { return T(); }
void unhandled_exception() {}
};
};
} // namespace experimental
} // namespace std
void foo() { co_return; }