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 9 #include "llvm/Transforms/Coroutines/CoroCleanup.h" 10 #include "CoroInternal.h" 11 #include "llvm/IR/Function.h" 12 #include "llvm/IR/IRBuilder.h" 13 #include "llvm/IR/InstIterator.h" 14 #include "llvm/IR/Module.h" 15 #include "llvm/IR/PassManager.h" 16 #include "llvm/Transforms/Scalar/SimplifyCFG.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 IRBuilder<> Builder; 26 Lowerer(Module &M) : LowererBase(M), Builder(Context) {} 27 bool lower(Function &F); 28 }; 29 } 30 31 static void lowerSubFn(IRBuilder<> &Builder, CoroSubFnInst *SubFn) { 32 Builder.SetInsertPoint(SubFn); 33 Value *FramePtr = SubFn->getFrame(); 34 int Index = SubFn->getIndex(); 35 36 auto *FrameTy = StructType::get(SubFn->getContext(), 37 {Builder.getPtrTy(), Builder.getPtrTy()}); 38 39 Builder.SetInsertPoint(SubFn); 40 auto *Gep = Builder.CreateConstInBoundsGEP2_32(FrameTy, FramePtr, 0, Index); 41 auto *Load = Builder.CreateLoad(FrameTy->getElementType(Index), Gep); 42 43 SubFn->replaceAllUsesWith(Load); 44 } 45 46 bool Lowerer::lower(Function &F) { 47 bool IsPrivateAndUnprocessed = F.isPresplitCoroutine() && F.hasLocalLinkage(); 48 bool Changed = false; 49 50 for (Instruction &I : llvm::make_early_inc_range(instructions(F))) { 51 if (auto *II = dyn_cast<IntrinsicInst>(&I)) { 52 switch (II->getIntrinsicID()) { 53 default: 54 continue; 55 case Intrinsic::coro_begin: 56 II->replaceAllUsesWith(II->getArgOperand(1)); 57 break; 58 case Intrinsic::coro_free: 59 II->replaceAllUsesWith(II->getArgOperand(1)); 60 break; 61 case Intrinsic::coro_alloc: 62 II->replaceAllUsesWith(ConstantInt::getTrue(Context)); 63 break; 64 case Intrinsic::coro_async_resume: 65 II->replaceAllUsesWith( 66 ConstantPointerNull::get(cast<PointerType>(I.getType()))); 67 break; 68 case Intrinsic::coro_id: 69 case Intrinsic::coro_id_retcon: 70 case Intrinsic::coro_id_retcon_once: 71 case Intrinsic::coro_id_async: 72 II->replaceAllUsesWith(ConstantTokenNone::get(Context)); 73 break; 74 case Intrinsic::coro_subfn_addr: 75 lowerSubFn(Builder, cast<CoroSubFnInst>(II)); 76 break; 77 case Intrinsic::coro_end: 78 case Intrinsic::coro_suspend_retcon: 79 if (IsPrivateAndUnprocessed) { 80 II->replaceAllUsesWith(UndefValue::get(II->getType())); 81 } else 82 continue; 83 break; 84 case Intrinsic::coro_async_size_replace: 85 auto *Target = cast<ConstantStruct>( 86 cast<GlobalVariable>(II->getArgOperand(0)->stripPointerCasts()) 87 ->getInitializer()); 88 auto *Source = cast<ConstantStruct>( 89 cast<GlobalVariable>(II->getArgOperand(1)->stripPointerCasts()) 90 ->getInitializer()); 91 auto *TargetSize = Target->getOperand(1); 92 auto *SourceSize = Source->getOperand(1); 93 if (TargetSize->isElementWiseEqual(SourceSize)) { 94 break; 95 } 96 auto *TargetRelativeFunOffset = Target->getOperand(0); 97 auto *NewFuncPtrStruct = ConstantStruct::get( 98 Target->getType(), TargetRelativeFunOffset, SourceSize); 99 Target->replaceAllUsesWith(NewFuncPtrStruct); 100 break; 101 } 102 II->eraseFromParent(); 103 Changed = true; 104 } 105 } 106 107 return Changed; 108 } 109 110 static bool declaresCoroCleanupIntrinsics(const Module &M) { 111 return coro::declaresIntrinsics( 112 M, {"llvm.coro.alloc", "llvm.coro.begin", "llvm.coro.subfn.addr", 113 "llvm.coro.free", "llvm.coro.id", "llvm.coro.id.retcon", 114 "llvm.coro.id.async", "llvm.coro.id.retcon.once", 115 "llvm.coro.async.size.replace", "llvm.coro.async.resume"}); 116 } 117 118 PreservedAnalyses CoroCleanupPass::run(Module &M, 119 ModuleAnalysisManager &MAM) { 120 if (!declaresCoroCleanupIntrinsics(M)) 121 return PreservedAnalyses::all(); 122 123 FunctionAnalysisManager &FAM = 124 MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); 125 126 FunctionPassManager FPM; 127 FPM.addPass(SimplifyCFGPass()); 128 129 PreservedAnalyses FuncPA; 130 FuncPA.preserveSet<CFGAnalyses>(); 131 132 Lowerer L(M); 133 for (auto &F : M) { 134 if (L.lower(F)) { 135 FAM.invalidate(F, FuncPA); 136 FPM.run(F, FAM); 137 } 138 } 139 140 return PreservedAnalyses::none(); 141 } 142