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,12 +89,26 @@ // 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", "llvm.coro.id.retcon", + "llvm.coro.id.retcon.once"}); +} + +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 { @@ -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; } 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 }