xref: /freebsd/contrib/llvm-project/llvm/lib/Transforms/Coroutines/CoroCleanup.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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;
Lowerer__anon0fa190e30111::Lowerer26   Lowerer(Module &M) : LowererBase(M), Builder(Context) {}
27   bool lower(Function &F);
28 };
29 }
30 
lowerSubFn(IRBuilder<> & Builder,CoroSubFnInst * SubFn)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 
lower(Function & F)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 
declaresCoroCleanupIntrinsics(const Module & M)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 
run(Module & M,ModuleAnalysisManager & MAM)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