• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/IRBuilder.h"
14 #include "llvm/IR/InstIterator.h"
15 #include "llvm/IR/LegacyPassManager.h"
16 #include "llvm/Pass.h"
17 #include "llvm/Transforms/Scalar.h"
18 
19 using namespace llvm;
20 
21 #define DEBUG_TYPE "coro-cleanup"
22 
23 namespace {
24 // Created on demand if CoroCleanup pass has work to do.
25 struct Lowerer : coro::LowererBase {
26   IRBuilder<> Builder;
Lowerer__anon5db007860111::Lowerer27   Lowerer(Module &M) : LowererBase(M), Builder(Context) {}
28   bool lowerRemainingCoroIntrinsics(Function &F);
29 };
30 }
31 
simplifyCFG(Function & F)32 static void simplifyCFG(Function &F) {
33   llvm::legacy::FunctionPassManager FPM(F.getParent());
34   FPM.add(createCFGSimplificationPass());
35 
36   FPM.doInitialization();
37   FPM.run(F);
38   FPM.doFinalization();
39 }
40 
lowerSubFn(IRBuilder<> & Builder,CoroSubFnInst * SubFn)41 static void lowerSubFn(IRBuilder<> &Builder, CoroSubFnInst *SubFn) {
42   Builder.SetInsertPoint(SubFn);
43   Value *FrameRaw = SubFn->getFrame();
44   int Index = SubFn->getIndex();
45 
46   auto *FrameTy = StructType::get(
47       SubFn->getContext(), {Builder.getInt8PtrTy(), Builder.getInt8PtrTy()});
48   PointerType *FramePtrTy = FrameTy->getPointerTo();
49 
50   Builder.SetInsertPoint(SubFn);
51   auto *FramePtr = Builder.CreateBitCast(FrameRaw, FramePtrTy);
52   auto *Gep = Builder.CreateConstInBoundsGEP2_32(FrameTy, FramePtr, 0, Index);
53   auto *Load = Builder.CreateLoad(Gep);
54 
55   SubFn->replaceAllUsesWith(Load);
56 }
57 
lowerRemainingCoroIntrinsics(Function & F)58 bool Lowerer::lowerRemainingCoroIntrinsics(Function &F) {
59   bool Changed = false;
60 
61   for (auto IB = inst_begin(F), E = inst_end(F); IB != E;) {
62     Instruction &I = *IB++;
63     if (auto *II = dyn_cast<IntrinsicInst>(&I)) {
64       switch (II->getIntrinsicID()) {
65       default:
66         continue;
67       case Intrinsic::coro_begin:
68         II->replaceAllUsesWith(II->getArgOperand(1));
69         break;
70       case Intrinsic::coro_free:
71         II->replaceAllUsesWith(II->getArgOperand(1));
72         break;
73       case Intrinsic::coro_alloc:
74         II->replaceAllUsesWith(ConstantInt::getTrue(Context));
75         break;
76       case Intrinsic::coro_id:
77         II->replaceAllUsesWith(ConstantTokenNone::get(Context));
78         break;
79       case Intrinsic::coro_subfn_addr:
80         lowerSubFn(Builder, cast<CoroSubFnInst>(II));
81         break;
82       }
83       II->eraseFromParent();
84       Changed = true;
85     }
86   }
87 
88   if (Changed) {
89     // After replacement were made we can cleanup the function body a little.
90     simplifyCFG(F);
91   }
92   return Changed;
93 }
94 
95 //===----------------------------------------------------------------------===//
96 //                              Top Level Driver
97 //===----------------------------------------------------------------------===//
98 
99 namespace {
100 
101 struct CoroCleanup : FunctionPass {
102   static char ID; // Pass identification, replacement for typeid
103 
CoroCleanup__anon5db007860211::CoroCleanup104   CoroCleanup() : FunctionPass(ID) {
105     initializeCoroCleanupPass(*PassRegistry::getPassRegistry());
106   }
107 
108   std::unique_ptr<Lowerer> L;
109 
110   // This pass has work to do only if we find intrinsics we are going to lower
111   // in the module.
doInitialization__anon5db007860211::CoroCleanup112   bool doInitialization(Module &M) override {
113     if (coro::declaresIntrinsics(M, {"llvm.coro.alloc", "llvm.coro.begin",
114                                      "llvm.coro.subfn.addr", "llvm.coro.free",
115                                      "llvm.coro.id"}))
116       L = llvm::make_unique<Lowerer>(M);
117     return false;
118   }
119 
runOnFunction__anon5db007860211::CoroCleanup120   bool runOnFunction(Function &F) override {
121     if (L)
122       return L->lowerRemainingCoroIntrinsics(F);
123     return false;
124   }
getAnalysisUsage__anon5db007860211::CoroCleanup125   void getAnalysisUsage(AnalysisUsage &AU) const override {
126     if (!L)
127       AU.setPreservesAll();
128   }
getPassName__anon5db007860211::CoroCleanup129   StringRef getPassName() const override { return "Coroutine Cleanup"; }
130 };
131 }
132 
133 char CoroCleanup::ID = 0;
134 INITIALIZE_PASS(CoroCleanup, "coro-cleanup",
135                 "Lower all coroutine related intrinsics", false, false)
136 
createCoroCleanupPass()137 Pass *llvm::createCoroCleanupPass() { return new CoroCleanup(); }
138