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