1 //===-- Coroutines.cpp ----------------------------------------------------===//
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 file implements the common infrastructure for Coroutine Passes.
10 //===----------------------------------------------------------------------===//
11 
12 #include "CoroInternal.h"
13 #include "llvm/IR/LegacyPassManager.h"
14 #include "llvm/IR/Verifier.h"
15 #include "llvm/InitializePasses.h"
16 #include "llvm/Transforms/IPO.h"
17 #include "llvm/Transforms/IPO/PassManagerBuilder.h"
18 
19 using namespace llvm;
20 
21 void llvm::initializeCoroutines(PassRegistry &Registry) {
22   initializeCoroEarlyPass(Registry);
23   initializeCoroSplitPass(Registry);
24   initializeCoroElidePass(Registry);
25   initializeCoroCleanupPass(Registry);
26 }
27 
28 static void addCoroutineOpt0Passes(const PassManagerBuilder &Builder,
29                                    legacy::PassManagerBase &PM) {
30   PM.add(createCoroSplitPass());
31   PM.add(createCoroElidePass());
32 
33   PM.add(createBarrierNoopPass());
34   PM.add(createCoroCleanupPass());
35 }
36 
37 static void addCoroutineEarlyPasses(const PassManagerBuilder &Builder,
38                                     legacy::PassManagerBase &PM) {
39   PM.add(createCoroEarlyPass());
40 }
41 
42 static void addCoroutineScalarOptimizerPasses(const PassManagerBuilder &Builder,
43                                               legacy::PassManagerBase &PM) {
44   PM.add(createCoroElidePass());
45 }
46 
47 static void addCoroutineSCCPasses(const PassManagerBuilder &Builder,
48                                   legacy::PassManagerBase &PM) {
49   PM.add(createCoroSplitPass());
50 }
51 
52 static void addCoroutineOptimizerLastPasses(const PassManagerBuilder &Builder,
53                                             legacy::PassManagerBase &PM) {
54   PM.add(createCoroCleanupPass());
55 }
56 
57 void llvm::addCoroutinePassesToExtensionPoints(PassManagerBuilder &Builder) {
58   Builder.addExtension(PassManagerBuilder::EP_EarlyAsPossible,
59                        addCoroutineEarlyPasses);
60   Builder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
61                        addCoroutineOpt0Passes);
62   Builder.addExtension(PassManagerBuilder::EP_CGSCCOptimizerLate,
63                        addCoroutineSCCPasses);
64   Builder.addExtension(PassManagerBuilder::EP_ScalarOptimizerLate,
65                        addCoroutineScalarOptimizerPasses);
66   Builder.addExtension(PassManagerBuilder::EP_OptimizerLast,
67                        addCoroutineOptimizerLastPasses);
68 }
69 
70 // Construct the lowerer base class and initialize its members.
71 coro::LowererBase::LowererBase(Module &M)
72     : TheModule(M), Context(M.getContext()),
73       ResumeFnType(FunctionType::get(Type::getVoidTy(Context),
74                                      Type::getInt8PtrTy(Context),
75                                      /*isVarArg=*/false)) {}
76 
77 // Creates a sequence of instructions to obtain a resume function address using
78 // llvm.coro.subfn.addr. It generates the following sequence:
79 //
80 //    call i8* @llvm.coro.subfn.addr(i8* %Arg, i8 %index)
81 //    bitcast i8* %2 to void(i8*)*
82 
83 Value *coro::LowererBase::makeSubFnCall(Value *Arg, int Index,
84                                         Instruction *InsertPt) {
85   auto *IndexVal = ConstantInt::get(Type::getInt8Ty(Context), Index);
86   auto *Fn = Intrinsic::getDeclaration(&TheModule, Intrinsic::coro_subfn_addr);
87 
88   assert(Index >= CoroSubFnInst::IndexFirst &&
89          Index < CoroSubFnInst::IndexLast &&
90          "makeSubFnCall: Index value out of range");
91   auto *Call = CallInst::Create(Fn, {Arg, IndexVal}, "", InsertPt);
92 
93   auto *Bitcast =
94       new BitCastInst(Call, ResumeFnType->getPointerTo(), "", InsertPt);
95   return Bitcast;
96 }
97 
98 #ifndef NDEBUG
99 static bool isCoroutineIntrinsicName(StringRef Name) {
100   // NOTE: Must be sorted!
101   static const char *const CoroIntrinsics[] = {
102       "llvm.coro.alloc",   "llvm.coro.begin",   "llvm.coro.destroy",
103       "llvm.coro.done",    "llvm.coro.end",     "llvm.coro.frame",
104       "llvm.coro.free",    "llvm.coro.id",      "llvm.coro.param",
105       "llvm.coro.promise", "llvm.coro.resume",  "llvm.coro.save",
106       "llvm.coro.size",    "llvm.coro.suspend",
107   };
108   return Intrinsic::lookupLLVMIntrinsicByName(CoroIntrinsics, Name) != -1;
109 }
110 #endif
111 
112 // Verifies if a module has named values listed. Also, in debug mode verifies
113 // that names are intrinsic names.
114 bool coro::declaresIntrinsics(Module &M,
115                               std::initializer_list<StringRef> List) {
116 
117   for (StringRef Name : List) {
118     assert(isCoroutineIntrinsicName(Name) && "not a coroutine intrinsic");
119     if (M.getNamedValue(Name))
120       return true;
121   }
122 
123   return false;
124 }
125