1 //===- CoroCleanup.cpp - Coroutine Cleanup Pass ---------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 // This pass lowers all remaining coroutine intrinsics.
10 //===----------------------------------------------------------------------===//
11 
12 #include "CoroInternal.h"
13 #include "llvm/IR/InstIterator.h"
14 #include "llvm/IR/LegacyPassManager.h"
15 #include "llvm/Pass.h"
16 #include "llvm/Transforms/Scalar.h"
17 
18 using namespace llvm;
19 
20 #define DEBUG_TYPE "coro-cleanup"
21 
22 namespace {
23 // Created on demand if CoroCleanup pass has work to do.
24 struct Lowerer : coro::LowererBase {
25   Lowerer(Module &M) : LowererBase(M) {}
26   bool lowerRemainingCoroIntrinsics(Function &F);
27 };
28 }
29 
30 static void simplifyCFG(Function &F) {
31   llvm::legacy::FunctionPassManager FPM(F.getParent());
32   FPM.add(createCFGSimplificationPass());
33 
34   FPM.doInitialization();
35   FPM.run(F);
36   FPM.doFinalization();
37 }
38 
39 bool Lowerer::lowerRemainingCoroIntrinsics(Function &F) {
40   bool Changed = false;
41 
42   for (auto IB = inst_begin(F), E = inst_end(F); IB != E;) {
43     Instruction &I = *IB++;
44     if (auto *II = dyn_cast<IntrinsicInst>(&I)) {
45       switch (II->getIntrinsicID()) {
46       default:
47         continue;
48       case Intrinsic::coro_begin:
49         II->replaceAllUsesWith(II->getArgOperand(1));
50         break;
51       case Intrinsic::coro_free:
52         II->replaceAllUsesWith(II->getArgOperand(1));
53         break;
54       case Intrinsic::coro_alloc:
55         II->replaceAllUsesWith(ConstantInt::getTrue(Context));
56         break;
57       case Intrinsic::coro_id:
58         II->replaceAllUsesWith(ConstantTokenNone::get(Context));
59         break;
60       }
61       II->eraseFromParent();
62       Changed = true;
63     }
64   }
65 
66   if (Changed) {
67     // After replacement were made we can cleanup the function body a little.
68     simplifyCFG(F);
69   }
70   return Changed;
71 }
72 
73 //===----------------------------------------------------------------------===//
74 //                              Top Level Driver
75 //===----------------------------------------------------------------------===//
76 
77 namespace {
78 
79 struct CoroCleanup : FunctionPass {
80   static char ID; // Pass identification, replacement for typeid
81 
82   CoroCleanup() : FunctionPass(ID) {}
83 
84   std::unique_ptr<Lowerer> L;
85 
86   // This pass has work to do only if we find intrinsics we are going to lower
87   // in the module.
88   bool doInitialization(Module &M) override {
89     if (coro::declaresIntrinsics(M, {"llvm.coro.alloc", "llvm.coro.begin",
90                                      "llvm.coro.free", "llvm.coro.id"}))
91       L = llvm::make_unique<Lowerer>(M);
92     return false;
93   }
94 
95   bool runOnFunction(Function &F) override {
96     if (L)
97       return L->lowerRemainingCoroIntrinsics(F);
98     return false;
99   }
100   void getAnalysisUsage(AnalysisUsage &AU) const override {
101     if (!L)
102       AU.setPreservesAll();
103   }
104 };
105 }
106 
107 char CoroCleanup::ID = 0;
108 INITIALIZE_PASS(CoroCleanup, "coro-cleanup",
109                 "Lower all coroutine related intrinsics", false, false)
110 
111 Pass *llvm::createCoroCleanupPass() { return new CoroCleanup(); }
112