CoroCleanup.cpp revision 360784
1//===- CoroCleanup.cpp - Coroutine Cleanup Pass ---------------------------===// 2// 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 6// 7//===----------------------------------------------------------------------===// 8// This pass lowers all remaining coroutine intrinsics. 9//===----------------------------------------------------------------------===// 10 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" 17 18using namespace llvm; 19 20#define DEBUG_TYPE "coro-cleanup" 21 22namespace { 23// Created on demand if CoroCleanup pass has work to do. 24struct Lowerer : coro::LowererBase { 25 IRBuilder<> Builder; 26 Lowerer(Module &M) : LowererBase(M), Builder(Context) {} 27 bool lowerRemainingCoroIntrinsics(Function &F); 28}; 29} 30 31static void simplifyCFG(Function &F) { 32 llvm::legacy::FunctionPassManager FPM(F.getParent()); 33 FPM.add(createCFGSimplificationPass()); 34 35 FPM.doInitialization(); 36 FPM.run(F); 37 FPM.doFinalization(); 38} 39 40static void lowerSubFn(IRBuilder<> &Builder, CoroSubFnInst *SubFn) { 41 Builder.SetInsertPoint(SubFn); 42 Value *FrameRaw = SubFn->getFrame(); 43 int Index = SubFn->getIndex(); 44 45 auto *FrameTy = StructType::get( 46 SubFn->getContext(), {Builder.getInt8PtrTy(), Builder.getInt8PtrTy()}); 47 PointerType *FramePtrTy = FrameTy->getPointerTo(); 48 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); 53 54 SubFn->replaceAllUsesWith(Load); 55} 56 57bool Lowerer::lowerRemainingCoroIntrinsics(Function &F) { 58 bool Changed = false; 59 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()) { 64 default: 65 continue; 66 case Intrinsic::coro_begin: 67 II->replaceAllUsesWith(II->getArgOperand(1)); 68 break; 69 case Intrinsic::coro_free: 70 II->replaceAllUsesWith(II->getArgOperand(1)); 71 break; 72 case Intrinsic::coro_alloc: 73 II->replaceAllUsesWith(ConstantInt::getTrue(Context)); 74 break; 75 case Intrinsic::coro_id: 76 case Intrinsic::coro_id_retcon: 77 case Intrinsic::coro_id_retcon_once: 78 II->replaceAllUsesWith(ConstantTokenNone::get(Context)); 79 break; 80 case Intrinsic::coro_subfn_addr: 81 lowerSubFn(Builder, cast<CoroSubFnInst>(II)); 82 break; 83 } 84 II->eraseFromParent(); 85 Changed = true; 86 } 87 } 88 89 if (Changed) { 90 // After replacement were made we can cleanup the function body a little. 91 simplifyCFG(F); 92 } 93 return Changed; 94} 95 96//===----------------------------------------------------------------------===// 97// Top Level Driver 98//===----------------------------------------------------------------------===// 99 100namespace { 101 102struct CoroCleanupLegacy : FunctionPass { 103 static char ID; // Pass identification, replacement for typeid 104 105 CoroCleanupLegacy() : FunctionPass(ID) { 106 initializeCoroCleanupLegacyPass(*PassRegistry::getPassRegistry()); 107 } 108 109 std::unique_ptr<Lowerer> L; 110 111 // This pass has work to do only if we find intrinsics we are going to lower 112 // in the module. 113 bool doInitialization(Module &M) override { 114 if (coro::declaresIntrinsics(M, {"llvm.coro.alloc", "llvm.coro.begin", 115 "llvm.coro.subfn.addr", "llvm.coro.free", 116 "llvm.coro.id", "llvm.coro.id.retcon", 117 "llvm.coro.id.retcon.once"})) 118 L = std::make_unique<Lowerer>(M); 119 return false; 120 } 121 122 bool runOnFunction(Function &F) override { 123 if (L) 124 return L->lowerRemainingCoroIntrinsics(F); 125 return false; 126 } 127 void getAnalysisUsage(AnalysisUsage &AU) const override { 128 if (!L) 129 AU.setPreservesAll(); 130 } 131 StringRef getPassName() const override { return "Coroutine Cleanup"; } 132}; 133} 134 135char CoroCleanupLegacy::ID = 0; 136INITIALIZE_PASS(CoroCleanupLegacy, "coro-cleanup", 137 "Lower all coroutine related intrinsics", false, false) 138 139Pass *llvm::createCoroCleanupLegacyPass() { return new CoroCleanupLegacy(); } 140