1 //===- CoroCleanup.cpp - Coroutine Cleanup Pass ---------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
8 // This pass lowers all remaining coroutine intrinsics.
9 //===----------------------------------------------------------------------===//
11 #include "CoroInternal.h"
12 #include "llvm/IR/IRBuilder.h"
13 #include "llvm/IR/InstIterator.h"
14 #include "llvm/IR/LegacyPassManager.h"
15 #include "llvm/Pass.h"
16 #include "llvm/Transforms/Scalar.h"
20 #define DEBUG_TYPE "coro-cleanup"
23 // Created on demand if CoroCleanup pass has work to do.
24 struct Lowerer
: coro::LowererBase
{
26 Lowerer(Module
&M
) : LowererBase(M
), Builder(Context
) {}
27 bool lowerRemainingCoroIntrinsics(Function
&F
);
31 static void simplifyCFG(Function
&F
) {
32 llvm::legacy::FunctionPassManager
FPM(F
.getParent());
33 FPM
.add(createCFGSimplificationPass());
35 FPM
.doInitialization();
40 static void lowerSubFn(IRBuilder
<> &Builder
, CoroSubFnInst
*SubFn
) {
41 Builder
.SetInsertPoint(SubFn
);
42 Value
*FrameRaw
= SubFn
->getFrame();
43 int Index
= SubFn
->getIndex();
45 auto *FrameTy
= StructType::get(
46 SubFn
->getContext(), {Builder
.getInt8PtrTy(), Builder
.getInt8PtrTy()});
47 PointerType
*FramePtrTy
= FrameTy
->getPointerTo();
49 Builder
.SetInsertPoint(SubFn
);
50 auto *FramePtr
= Builder
.CreateBitCast(FrameRaw
, FramePtrTy
);
51 auto *Gep
= Builder
.CreateConstInBoundsGEP2_32(FrameTy
, FramePtr
, 0, Index
);
52 auto *Load
= Builder
.CreateLoad(FrameTy
->getElementType(Index
), Gep
);
54 SubFn
->replaceAllUsesWith(Load
);
57 bool Lowerer::lowerRemainingCoroIntrinsics(Function
&F
) {
60 for (auto IB
= inst_begin(F
), E
= inst_end(F
); IB
!= E
;) {
61 Instruction
&I
= *IB
++;
62 if (auto *II
= dyn_cast
<IntrinsicInst
>(&I
)) {
63 switch (II
->getIntrinsicID()) {
66 case Intrinsic::coro_begin
:
67 II
->replaceAllUsesWith(II
->getArgOperand(1));
69 case Intrinsic::coro_free
:
70 II
->replaceAllUsesWith(II
->getArgOperand(1));
72 case Intrinsic::coro_alloc
:
73 II
->replaceAllUsesWith(ConstantInt::getTrue(Context
));
75 case Intrinsic::coro_id
:
76 II
->replaceAllUsesWith(ConstantTokenNone::get(Context
));
78 case Intrinsic::coro_subfn_addr
:
79 lowerSubFn(Builder
, cast
<CoroSubFnInst
>(II
));
82 II
->eraseFromParent();
88 // After replacement were made we can cleanup the function body a little.
94 //===----------------------------------------------------------------------===//
96 //===----------------------------------------------------------------------===//
100 struct CoroCleanup
: FunctionPass
{
101 static char ID
; // Pass identification, replacement for typeid
103 CoroCleanup() : FunctionPass(ID
) {
104 initializeCoroCleanupPass(*PassRegistry::getPassRegistry());
107 std::unique_ptr
<Lowerer
> L
;
109 // This pass has work to do only if we find intrinsics we are going to lower
111 bool doInitialization(Module
&M
) override
{
112 if (coro::declaresIntrinsics(M
, {"llvm.coro.alloc", "llvm.coro.begin",
113 "llvm.coro.subfn.addr", "llvm.coro.free",
115 L
= llvm::make_unique
<Lowerer
>(M
);
119 bool runOnFunction(Function
&F
) override
{
121 return L
->lowerRemainingCoroIntrinsics(F
);
124 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
126 AU
.setPreservesAll();
128 StringRef
getPassName() const override
{ return "Coroutine Cleanup"; }
132 char CoroCleanup::ID
= 0;
133 INITIALIZE_PASS(CoroCleanup
, "coro-cleanup",
134 "Lower all coroutine related intrinsics", false, false)
136 Pass
*llvm::createCoroCleanupPass() { return new CoroCleanup(); }