CoroInternal.h revision 360784
1//===- CoroInternal.h - Internal Coroutine interfaces ---------*- C++ -*---===// 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// Common definitions/declarations used internally by coroutine lowering passes. 9//===----------------------------------------------------------------------===// 10 11#ifndef LLVM_LIB_TRANSFORMS_COROUTINES_COROINTERNAL_H 12#define LLVM_LIB_TRANSFORMS_COROUTINES_COROINTERNAL_H 13 14#include "CoroInstr.h" 15#include "llvm/IR/IRBuilder.h" 16#include "llvm/Transforms/Coroutines.h" 17 18namespace llvm { 19 20class CallGraph; 21class CallGraphSCC; 22class PassRegistry; 23 24void initializeCoroEarlyLegacyPass(PassRegistry &); 25void initializeCoroSplitLegacyPass(PassRegistry &); 26void initializeCoroElideLegacyPass(PassRegistry &); 27void initializeCoroCleanupLegacyPass(PassRegistry &); 28 29// CoroEarly pass marks every function that has coro.begin with a string 30// attribute "coroutine.presplit"="0". CoroSplit pass processes the coroutine 31// twice. First, it lets it go through complete IPO optimization pipeline as a 32// single function. It forces restart of the pipeline by inserting an indirect 33// call to an empty function "coro.devirt.trigger" which is devirtualized by 34// CoroElide pass that triggers a restart of the pipeline by CGPassManager. 35// When CoroSplit pass sees the same coroutine the second time, it splits it up, 36// adds coroutine subfunctions to the SCC to be processed by IPO pipeline. 37 38#define CORO_PRESPLIT_ATTR "coroutine.presplit" 39#define UNPREPARED_FOR_SPLIT "0" 40#define PREPARED_FOR_SPLIT "1" 41 42#define CORO_DEVIRT_TRIGGER_FN "coro.devirt.trigger" 43 44namespace coro { 45 46bool declaresIntrinsics(const Module &M, 47 const std::initializer_list<StringRef>); 48void replaceAllCoroAllocs(CoroBeginInst *CB, bool Replacement); 49void replaceAllCoroFrees(CoroBeginInst *CB, Value *Replacement); 50void replaceCoroFree(CoroIdInst *CoroId, bool Elide); 51void updateCallGraph(Function &Caller, ArrayRef<Function *> Funcs, 52 CallGraph &CG, CallGraphSCC &SCC); 53 54// Keeps data and helper functions for lowering coroutine intrinsics. 55struct LowererBase { 56 Module &TheModule; 57 LLVMContext &Context; 58 PointerType *const Int8Ptr; 59 FunctionType *const ResumeFnType; 60 ConstantPointerNull *const NullPtr; 61 62 LowererBase(Module &M); 63 Value *makeSubFnCall(Value *Arg, int Index, Instruction *InsertPt); 64}; 65 66enum class ABI { 67 /// The "resume-switch" lowering, where there are separate resume and 68 /// destroy functions that are shared between all suspend points. The 69 /// coroutine frame implicitly stores the resume and destroy functions, 70 /// the current index, and any promise value. 71 Switch, 72 73 /// The "returned-continuation" lowering, where each suspend point creates a 74 /// single continuation function that is used for both resuming and 75 /// destroying. Does not support promises. 76 Retcon, 77 78 /// The "unique returned-continuation" lowering, where each suspend point 79 /// creates a single continuation function that is used for both resuming 80 /// and destroying. Does not support promises. The function is known to 81 /// suspend at most once during its execution, and the return value of 82 /// the continuation is void. 83 RetconOnce, 84}; 85 86// Holds structural Coroutine Intrinsics for a particular function and other 87// values used during CoroSplit pass. 88struct LLVM_LIBRARY_VISIBILITY Shape { 89 CoroBeginInst *CoroBegin; 90 SmallVector<CoroEndInst *, 4> CoroEnds; 91 SmallVector<CoroSizeInst *, 2> CoroSizes; 92 SmallVector<AnyCoroSuspendInst *, 4> CoroSuspends; 93 SmallVector<CallInst*, 2> SwiftErrorOps; 94 95 // Field indexes for special fields in the switch lowering. 96 struct SwitchFieldIndex { 97 enum { 98 Resume, 99 Destroy, 100 Promise, 101 Index, 102 /// The index of the first spill field. 103 FirstSpill 104 }; 105 }; 106 107 coro::ABI ABI; 108 109 StructType *FrameTy; 110 Instruction *FramePtr; 111 BasicBlock *AllocaSpillBlock; 112 113 struct SwitchLoweringStorage { 114 SwitchInst *ResumeSwitch; 115 AllocaInst *PromiseAlloca; 116 BasicBlock *ResumeEntryBlock; 117 bool HasFinalSuspend; 118 }; 119 120 struct RetconLoweringStorage { 121 Function *ResumePrototype; 122 Function *Alloc; 123 Function *Dealloc; 124 BasicBlock *ReturnBlock; 125 bool IsFrameInlineInStorage; 126 }; 127 128 union { 129 SwitchLoweringStorage SwitchLowering; 130 RetconLoweringStorage RetconLowering; 131 }; 132 133 CoroIdInst *getSwitchCoroId() const { 134 assert(ABI == coro::ABI::Switch); 135 return cast<CoroIdInst>(CoroBegin->getId()); 136 } 137 138 AnyCoroIdRetconInst *getRetconCoroId() const { 139 assert(ABI == coro::ABI::Retcon || 140 ABI == coro::ABI::RetconOnce); 141 return cast<AnyCoroIdRetconInst>(CoroBegin->getId()); 142 } 143 144 IntegerType *getIndexType() const { 145 assert(ABI == coro::ABI::Switch); 146 assert(FrameTy && "frame type not assigned"); 147 return cast<IntegerType>(FrameTy->getElementType(SwitchFieldIndex::Index)); 148 } 149 ConstantInt *getIndex(uint64_t Value) const { 150 return ConstantInt::get(getIndexType(), Value); 151 } 152 153 PointerType *getSwitchResumePointerType() const { 154 assert(ABI == coro::ABI::Switch); 155 assert(FrameTy && "frame type not assigned"); 156 return cast<PointerType>(FrameTy->getElementType(SwitchFieldIndex::Resume)); 157 } 158 159 FunctionType *getResumeFunctionType() const { 160 switch (ABI) { 161 case coro::ABI::Switch: { 162 auto *FnPtrTy = getSwitchResumePointerType(); 163 return cast<FunctionType>(FnPtrTy->getPointerElementType()); 164 } 165 case coro::ABI::Retcon: 166 case coro::ABI::RetconOnce: 167 return RetconLowering.ResumePrototype->getFunctionType(); 168 } 169 llvm_unreachable("Unknown coro::ABI enum"); 170 } 171 172 ArrayRef<Type*> getRetconResultTypes() const { 173 assert(ABI == coro::ABI::Retcon || 174 ABI == coro::ABI::RetconOnce); 175 auto FTy = CoroBegin->getFunction()->getFunctionType(); 176 177 // The safety of all this is checked by checkWFRetconPrototype. 178 if (auto STy = dyn_cast<StructType>(FTy->getReturnType())) { 179 return STy->elements().slice(1); 180 } else { 181 return ArrayRef<Type*>(); 182 } 183 } 184 185 ArrayRef<Type*> getRetconResumeTypes() const { 186 assert(ABI == coro::ABI::Retcon || 187 ABI == coro::ABI::RetconOnce); 188 189 // The safety of all this is checked by checkWFRetconPrototype. 190 auto FTy = RetconLowering.ResumePrototype->getFunctionType(); 191 return FTy->params().slice(1); 192 } 193 194 CallingConv::ID getResumeFunctionCC() const { 195 switch (ABI) { 196 case coro::ABI::Switch: 197 return CallingConv::Fast; 198 199 case coro::ABI::Retcon: 200 case coro::ABI::RetconOnce: 201 return RetconLowering.ResumePrototype->getCallingConv(); 202 } 203 llvm_unreachable("Unknown coro::ABI enum"); 204 } 205 206 unsigned getFirstSpillFieldIndex() const { 207 switch (ABI) { 208 case coro::ABI::Switch: 209 return SwitchFieldIndex::FirstSpill; 210 211 case coro::ABI::Retcon: 212 case coro::ABI::RetconOnce: 213 return 0; 214 } 215 llvm_unreachable("Unknown coro::ABI enum"); 216 } 217 218 AllocaInst *getPromiseAlloca() const { 219 if (ABI == coro::ABI::Switch) 220 return SwitchLowering.PromiseAlloca; 221 return nullptr; 222 } 223 224 /// Allocate memory according to the rules of the active lowering. 225 /// 226 /// \param CG - if non-null, will be updated for the new call 227 Value *emitAlloc(IRBuilder<> &Builder, Value *Size, CallGraph *CG) const; 228 229 /// Deallocate memory according to the rules of the active lowering. 230 /// 231 /// \param CG - if non-null, will be updated for the new call 232 void emitDealloc(IRBuilder<> &Builder, Value *Ptr, CallGraph *CG) const; 233 234 Shape() = default; 235 explicit Shape(Function &F) { buildFrom(F); } 236 void buildFrom(Function &F); 237}; 238 239void buildCoroutineFrame(Function &F, Shape &Shape); 240 241} // End namespace coro. 242} // End namespace llvm 243 244#endif 245