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; 27 Lowerer(Module &M) : LowererBase(M), Builder(Context) {} 28 bool lowerRemainingCoroIntrinsics(Function &F); 29 }; 30 } 31 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 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 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 104 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. 112 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 120 bool runOnFunction(Function &F) override { 121 if (L) 122 return L->lowerRemainingCoroIntrinsics(F); 123 return false; 124 } 125 void getAnalysisUsage(AnalysisUsage &AU) const override { 126 if (!L) 127 AU.setPreservesAll(); 128 } 129 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 137 Pass *llvm::createCoroCleanupPass() { return new CoroCleanup(); } 138