diff --git a/llvm/include/llvm/Transforms/Coroutines/CoroConditionalWrapper.h b/llvm/include/llvm/Transforms/Coroutines/CoroConditionalWrapper.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Transforms/Coroutines/CoroConditionalWrapper.h @@ -0,0 +1,30 @@ +//===---- CoroConditionalWrapper.h ------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_COROUTINES_COROCONDITIONALWRAPPER_H +#define LLVM_TRANSFORMS_COROUTINES_COROCONDITIONALWRAPPER_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +class Module; + +// Only runs passes in the contained pass manager if the module contains any +// coroutine intrinsic declarations. +struct CoroConditionalWrapper : PassInfoMixin { + CoroConditionalWrapper(ModulePassManager &&); + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); + static bool isRequired() { return true; } + +private: + ModulePassManager PM; +}; +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_COROUTINES_COROCONDITIONALWRAPPER_H diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp --- a/llvm/lib/Passes/PassBuilderPipelines.cpp +++ b/llvm/lib/Passes/PassBuilderPipelines.cpp @@ -32,6 +32,7 @@ #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/AggressiveInstCombine/AggressiveInstCombine.h" #include "llvm/Transforms/Coroutines/CoroCleanup.h" +#include "llvm/Transforms/Coroutines/CoroConditionalWrapper.h" #include "llvm/Transforms/Coroutines/CoroEarly.h" #include "llvm/Transforms/Coroutines/CoroElide.h" #include "llvm/Transforms/Coroutines/CoroSplit.h" @@ -1816,11 +1817,14 @@ MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } - MPM.addPass(createModuleToFunctionPassAdaptor(CoroEarlyPass())); + ModulePassManager CoroPM; + CoroPM.addPass(createModuleToFunctionPassAdaptor(CoroEarlyPass())); CGSCCPassManager CGPM; CGPM.addPass(CoroSplitPass()); - MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); - MPM.addPass(createModuleToFunctionPassAdaptor(CoroCleanupPass())); + CoroPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); + CoroPM.addPass(createModuleToFunctionPassAdaptor(CoroCleanupPass())); + CoroPM.addPass(GlobalDCEPass()); + MPM.addPass(CoroConditionalWrapper(std::move(CoroPM))); for (auto &C : OptimizerLastEPCallbacks) C(MPM, Level); diff --git a/llvm/lib/Transforms/Coroutines/CMakeLists.txt b/llvm/lib/Transforms/Coroutines/CMakeLists.txt --- a/llvm/lib/Transforms/Coroutines/CMakeLists.txt +++ b/llvm/lib/Transforms/Coroutines/CMakeLists.txt @@ -1,6 +1,7 @@ add_llvm_component_library(LLVMCoroutines Coroutines.cpp CoroCleanup.cpp + CoroConditionalWrapper.cpp CoroEarly.cpp CoroElide.cpp CoroFrame.cpp diff --git a/llvm/lib/Transforms/Coroutines/CoroConditionalWrapper.cpp b/llvm/lib/Transforms/Coroutines/CoroConditionalWrapper.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Transforms/Coroutines/CoroConditionalWrapper.cpp @@ -0,0 +1,24 @@ +//===- CoroConditionalWrapper.cpp -----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Coroutines/CoroConditionalWrapper.h" +#include "CoroInternal.h" +#include "llvm/IR/Module.h" + +using namespace llvm; + +CoroConditionalWrapper::CoroConditionalWrapper(ModulePassManager &&PM) + : PM(std::move(PM)) {} + +PreservedAnalyses CoroConditionalWrapper::run(Module &M, + ModuleAnalysisManager &AM) { + if (!coro::declaresAnyIntrinsic(M)) + return PreservedAnalyses::all(); + + return PM.run(M, AM); +} diff --git a/llvm/lib/Transforms/Coroutines/CoroInternal.h b/llvm/lib/Transforms/Coroutines/CoroInternal.h --- a/llvm/lib/Transforms/Coroutines/CoroInternal.h +++ b/llvm/lib/Transforms/Coroutines/CoroInternal.h @@ -50,6 +50,7 @@ namespace coro { +bool declaresAnyIntrinsic(const Module &M); bool declaresIntrinsics(const Module &M, const std::initializer_list); void replaceCoroFree(CoroIdInst *CoroId, bool Elide); diff --git a/llvm/lib/Transforms/Coroutines/Coroutines.cpp b/llvm/lib/Transforms/Coroutines/Coroutines.cpp --- a/llvm/lib/Transforms/Coroutines/Coroutines.cpp +++ b/llvm/lib/Transforms/Coroutines/Coroutines.cpp @@ -119,44 +119,55 @@ return Bitcast; } +static const char *const CoroIntrinsics[] = { + "llvm.coro.align", + "llvm.coro.alloc", + "llvm.coro.async.context.alloc", + "llvm.coro.async.context.dealloc", + "llvm.coro.async.resume", + "llvm.coro.async.size.replace", + "llvm.coro.async.store_resume", + "llvm.coro.begin", + "llvm.coro.destroy", + "llvm.coro.done", + "llvm.coro.end", + "llvm.coro.end.async", + "llvm.coro.frame", + "llvm.coro.free", + "llvm.coro.id", + "llvm.coro.id.async", + "llvm.coro.id.retcon", + "llvm.coro.id.retcon.once", + "llvm.coro.noop", + "llvm.coro.prepare.async", + "llvm.coro.prepare.retcon", + "llvm.coro.promise", + "llvm.coro.resume", + "llvm.coro.save", + "llvm.coro.size", + "llvm.coro.subfn.addr", + "llvm.coro.suspend", + "llvm.coro.suspend.async", + "llvm.coro.suspend.retcon", +}; + #ifndef NDEBUG static bool isCoroutineIntrinsicName(StringRef Name) { // NOTE: Must be sorted! - static const char *const CoroIntrinsics[] = { - "llvm.coro.align", - "llvm.coro.alloc", - "llvm.coro.async.context.alloc", - "llvm.coro.async.context.dealloc", - "llvm.coro.async.resume", - "llvm.coro.async.size.replace", - "llvm.coro.async.store_resume", - "llvm.coro.begin", - "llvm.coro.destroy", - "llvm.coro.done", - "llvm.coro.end", - "llvm.coro.end.async", - "llvm.coro.frame", - "llvm.coro.free", - "llvm.coro.id", - "llvm.coro.id.async", - "llvm.coro.id.retcon", - "llvm.coro.id.retcon.once", - "llvm.coro.noop", - "llvm.coro.prepare.async", - "llvm.coro.prepare.retcon", - "llvm.coro.promise", - "llvm.coro.resume", - "llvm.coro.save", - "llvm.coro.size", - "llvm.coro.subfn.addr", - "llvm.coro.suspend", - "llvm.coro.suspend.async", - "llvm.coro.suspend.retcon", - }; return Intrinsic::lookupLLVMIntrinsicByName(CoroIntrinsics, Name) != -1; } #endif +bool coro::declaresAnyIntrinsic(const Module &M) { + for (StringRef Name : CoroIntrinsics) { + assert(isCoroutineIntrinsicName(Name) && "not a coroutine intrinsic"); + if (M.getNamedValue(Name)) + return true; + } + + return false; +} + // Verifies if a module has named values listed. Also, in debug mode verifies // that names are intrinsic names. bool coro::declaresIntrinsics(const Module &M, diff --git a/llvm/test/Other/new-pm-O0-defaults.ll b/llvm/test/Other/new-pm-O0-defaults.ll --- a/llvm/test/Other/new-pm-O0-defaults.ll +++ b/llvm/test/Other/new-pm-O0-defaults.ll @@ -38,14 +38,7 @@ ; CHECK-DEFAULT-NEXT: Running analysis: ProfileSummaryAnalysis ; CHECK-MATRIX: Running pass: LowerMatrixIntrinsicsPass ; CHECK-MATRIX-NEXT: Running analysis: TargetIRAnalysis -; CHECK-CORO-NEXT: Running pass: CoroEarlyPass -; CHECK-CORO-NEXT: Running analysis: InnerAnalysisManagerProxy -; CHECK-CORO-NEXT: Running analysis: LazyCallGraphAnalysis -; CHECK-CORO-NEXT: Running analysis: TargetLibraryAnalysis -; CHECK-CORO-NEXT: Running analysis: FunctionAnalysisManagerCGSCCProxy -; CHECK-CORO-NEXT: Running analysis: OuterAnalysisManagerProxy -; CHECK-CORO-NEXT: Running pass: CoroSplitPass -; CHECK-CORO-NEXT: Running pass: CoroCleanupPass +; CHECK-CORO-NEXT: Running pass: CoroConditionalWrapper ; CHECK-PRE-LINK: Running pass: CanonicalizeAliasesPass ; CHECK-PRE-LINK-NEXT: Running pass: NameAnonGlobalPass ; CHECK-THINLTO: Running pass: Annotation2MetadataPass @@ -59,6 +52,7 @@ ; CHECK-LTO-NEXT: Running pass: LowerTypeTestsPass ; CHECK-LTO-NEXT: Running pass: LowerTypeTestsPass ; CHECK-CORO-NEXT: Running pass: AnnotationRemarksPass +; CHECK-CORO-NEXT: Running analysis: TargetLibraryAnalysis ; CHECK-LTO-NEXT: Running pass: AnnotationRemarksPass ; CHECK-LTO-NEXT: Running analysis: TargetLibraryAnalysis ; CHECK-NEXT: Running pass: PrintModulePass diff --git a/llvm/test/Transforms/Coroutines/coro-internal-O0.ll b/llvm/test/Transforms/Coroutines/coro-internal-O0.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/Coroutines/coro-internal-O0.ll @@ -0,0 +1,10 @@ +; RUN: opt -passes='default' -S < %s | FileCheck %s + +; CHECK-NOT: call .*llvm.coro.size + +declare i64 @llvm.coro.size.i64() +define internal i64 @f() { + %a = call i64 @llvm.coro.size.i64() + ret i64 %a +} + diff --git a/llvm/test/Transforms/Coroutines/coro-retcon-once-private.ll b/llvm/test/Transforms/Coroutines/coro-retcon-once-private.ll --- a/llvm/test/Transforms/Coroutines/coro-retcon-once-private.ll +++ b/llvm/test/Transforms/Coroutines/coro-retcon-once-private.ll @@ -3,9 +3,7 @@ target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.12.0" -; CHECK: define internal { i8*, i32 } @f(i8* %buffer, i32* %array) -; CHECK-NEXT: entry: -; CHECK-NEXT: unreachable +; CHECK-NOT: define define internal {i8*, i32} @f(i8* %buffer, i32* %array) { entry: diff --git a/llvm/test/Transforms/Coroutines/smoketest.ll b/llvm/test/Transforms/Coroutines/smoketest.ll --- a/llvm/test/Transforms/Coroutines/smoketest.ll +++ b/llvm/test/Transforms/Coroutines/smoketest.ll @@ -22,6 +22,8 @@ ; CHECK-ALL: CoroSplitPass ; CHECK-ALL: CoroCleanupPass +declare token @llvm.coro.id(i32, i8*, i8*, i8*) + define void @foo() { ret void } diff --git a/llvm/utils/gn/secondary/llvm/lib/Transforms/Coroutines/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/Transforms/Coroutines/BUILD.gn --- a/llvm/utils/gn/secondary/llvm/lib/Transforms/Coroutines/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/lib/Transforms/Coroutines/BUILD.gn @@ -11,6 +11,7 @@ ] sources = [ "CoroCleanup.cpp", + "CoroConditionalWrapper.cpp", "CoroEarly.cpp", "CoroElide.cpp", "CoroFrame.cpp",