diff --git a/llvm/include/llvm-c/Transforms/Coroutines.h b/llvm/include/llvm-c/Transforms/Coroutines.h --- a/llvm/include/llvm-c/Transforms/Coroutines.h +++ b/llvm/include/llvm-c/Transforms/Coroutines.h @@ -40,7 +40,7 @@ /** See llvm::createCoroElideLegacyPass function. */ void LLVMAddCoroElidePass(LLVMPassManagerRef PM); -/** See llvm::createCoroCleanupPass function. */ +/** See llvm::createCoroCleanupLegacyPass function. */ void LLVMAddCoroCleanupPass(LLVMPassManagerRef PM); /** diff --git a/llvm/include/llvm/Transforms/Coroutines.h b/llvm/include/llvm/Transforms/Coroutines.h --- a/llvm/include/llvm/Transforms/Coroutines.h +++ b/llvm/include/llvm/Transforms/Coroutines.h @@ -30,7 +30,7 @@ Pass *createCoroElideLegacyPass(); /// Lower all remaining coroutine intrinsics. -Pass *createCoroCleanupPass(); +Pass *createCoroCleanupLegacyPass(); } diff --git a/llvm/include/llvm/Transforms/Coroutines/CoroCleanup.h b/llvm/include/llvm/Transforms/Coroutines/CoroCleanup.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Transforms/Coroutines/CoroCleanup.h @@ -0,0 +1,28 @@ +//===-- CoroCleanup.h - Lower all coroutine related intrinsics --*- 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 +// +//===----------------------------------------------------------------------===// +// +// \file +// This file delcares a pass that lowers all remaining coroutine intrinsics. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_COROUTINES_COROCLEANUP_H +#define LLVM_TRANSFORMS_COROUTINES_COROCLEANUP_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +class Function; + +struct CoroCleanupPass : PassInfoMixin { + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_COROUTINES_COROCLEANUP_H diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -67,6 +67,7 @@ #include "llvm/Support/Regex.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/AggressiveInstCombine/AggressiveInstCombine.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" diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -169,6 +169,7 @@ FUNCTION_PASS("chr", ControlHeightReductionPass()) FUNCTION_PASS("coro-early", CoroEarlyPass()) FUNCTION_PASS("coro-elide", CoroElidePass()) +FUNCTION_PASS("coro-cleanup", CoroCleanupPass()) FUNCTION_PASS("correlated-propagation", CorrelatedValuePropagationPass()) FUNCTION_PASS("dce", DCEPass()) FUNCTION_PASS("div-rem-pairs", DivRemPairsPass()) diff --git a/llvm/lib/Transforms/Coroutines/CoroCleanup.cpp b/llvm/lib/Transforms/Coroutines/CoroCleanup.cpp --- a/llvm/lib/Transforms/Coroutines/CoroCleanup.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroCleanup.cpp @@ -5,9 +5,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// -// This pass lowers all remaining coroutine intrinsics. -//===----------------------------------------------------------------------===// +#include "llvm/Transforms/Coroutines/CoroCleanup.h" #include "CoroInternal.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/InstIterator.h" @@ -90,20 +89,34 @@ // After replacement were made we can cleanup the function body a little. simplifyCFG(F); } + return Changed; } -//===----------------------------------------------------------------------===// -// Top Level Driver -//===----------------------------------------------------------------------===// +static bool declaresCoroCleanupIntrinsics(const Module &M) { + return coro::declaresIntrinsics(M, {"llvm.coro.alloc", + "llvm.coro.begin", + "llvm.coro.subfn.addr", + "llvm.coro.free", + "llvm.coro.id"}); +} + +PreservedAnalyses CoroCleanupPass::run(Function &F, FunctionAnalysisManager &AM) { + auto &M = *F.getParent(); + if (!declaresCoroCleanupIntrinsics(M) || + !Lowerer(M).lowerRemainingCoroIntrinsics(F)) + return PreservedAnalyses::all(); + + return PreservedAnalyses::none(); +} namespace { -struct CoroCleanup : FunctionPass { +struct CoroCleanupLegacy : FunctionPass { static char ID; // Pass identification, replacement for typeid - CoroCleanup() : FunctionPass(ID) { - initializeCoroCleanupPass(*PassRegistry::getPassRegistry()); + CoroCleanupLegacy() : FunctionPass(ID) { + initializeCoroCleanupLegacyPass(*PassRegistry::getPassRegistry()); } std::unique_ptr L; @@ -111,10 +124,7 @@ // This pass has work to do only if we find intrinsics we are going to lower // in the module. bool doInitialization(Module &M) override { - if (coro::declaresIntrinsics(M, {"llvm.coro.alloc", "llvm.coro.begin", - "llvm.coro.subfn.addr", "llvm.coro.free", - "llvm.coro.id", "llvm.coro.id.retcon", - "llvm.coro.id.retcon.once"})) + if (declaresCoroCleanupIntrinsics(M)) L = std::make_unique(M); return false; } @@ -132,8 +142,8 @@ }; } -char CoroCleanup::ID = 0; -INITIALIZE_PASS(CoroCleanup, "coro-cleanup", +char CoroCleanupLegacy::ID = 0; +INITIALIZE_PASS(CoroCleanupLegacy, "coro-cleanup", "Lower all coroutine related intrinsics", false, false) -Pass *llvm::createCoroCleanupPass() { return new CoroCleanup(); } +Pass *llvm::createCoroCleanupLegacyPass() { return new CoroCleanupLegacy(); } 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 @@ -24,7 +24,7 @@ void initializeCoroEarlyLegacyPass(PassRegistry &); void initializeCoroSplitLegacyPass(PassRegistry &); void initializeCoroElideLegacyPass(PassRegistry &); -void initializeCoroCleanupPass(PassRegistry &); +void initializeCoroCleanupLegacyPass(PassRegistry &); // CoroEarly pass marks every function that has coro.begin with a string // attribute "coroutine.presplit"="0". CoroSplit pass processes the coroutine 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 @@ -46,7 +46,7 @@ initializeCoroEarlyLegacyPass(Registry); initializeCoroSplitLegacyPass(Registry); initializeCoroElideLegacyPass(Registry); - initializeCoroCleanupPass(Registry); + initializeCoroCleanupLegacyPass(Registry); } static void addCoroutineOpt0Passes(const PassManagerBuilder &Builder, @@ -55,7 +55,7 @@ PM.add(createCoroElideLegacyPass()); PM.add(createBarrierNoopPass()); - PM.add(createCoroCleanupPass()); + PM.add(createCoroCleanupLegacyPass()); } static void addCoroutineEarlyPasses(const PassManagerBuilder &Builder, @@ -75,7 +75,7 @@ static void addCoroutineOptimizerLastPasses(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM) { - PM.add(createCoroCleanupPass()); + PM.add(createCoroCleanupLegacyPass()); } void llvm::addCoroutinePassesToExtensionPoints(PassManagerBuilder &Builder) { @@ -647,5 +647,5 @@ } void LLVMAddCoroCleanupPass(LLVMPassManagerRef PM) { - unwrap(PM)->add(createCoroCleanupPass()); + unwrap(PM)->add(createCoroCleanupLegacyPass()); } diff --git a/llvm/test/Transforms/Coroutines/coro-cleanup-lowering.ll b/llvm/test/Transforms/Coroutines/coro-cleanup-lowering.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/Coroutines/coro-cleanup-lowering.ll @@ -0,0 +1,30 @@ +; Make sure that all library helper coro intrinsics are lowered. +; RUN: opt < %s -coro-cleanup -S | FileCheck %s +; RUN: opt < %s -passes=coro-cleanup -S | FileCheck %s + +; CHECK-LABEL: @uses_library_support_coro_intrinsics( +; CHECK-NOT: @llvm.coro +; CHECK: ret void + +define void @uses_library_support_coro_intrinsics(i8* %hdl) { +entry: + %0 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0) + %1 = bitcast i8* %0 to void (i8*)* + call fastcc void %1(i8* %hdl) + %2 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1) + %3 = bitcast i8* %2 to void (i8*)* + call fastcc void %3(i8* %hdl) + %4 = bitcast i8* %hdl to i8** + %5 = load i8*, i8** %4 + %6 = icmp eq i8* %5, null + ret void +} +declare void @llvm.coro.resume(i8*) +declare void @llvm.coro.destroy(i8*) +; Function Attrs: argmemonly nounwind +declare i1 @llvm.coro.done(i8* nocapture readonly) #0 +; Function Attrs: argmemonly nounwind readonly +declare i8* @llvm.coro.subfn.addr(i8* nocapture readonly, i8) #1 + +attributes #0 = { argmemonly nounwind } +attributes #1 = { argmemonly nounwind readonly }