|
12 | 12 | #define LLVM_LIB_TRANSFORMS_COROUTINES_COROINTERNAL_H |
13 | 13 |
|
14 | 14 | #include "CoroInstr.h" |
| 15 | +#include "CoroShape.h" |
15 | 16 | #include "llvm/Analysis/TargetTransformInfo.h" |
16 | 17 | #include "llvm/IR/IRBuilder.h" |
17 | 18 |
|
@@ -57,229 +58,6 @@ struct LowererBase { |
57 | 58 | CallInst *makeSubFnCall(Value *Arg, int Index, Instruction *InsertPt); |
58 | 59 | }; |
59 | 60 |
|
60 | | -enum class ABI { |
61 | | - /// The "resume-switch" lowering, where there are separate resume and |
62 | | - /// destroy functions that are shared between all suspend points. The |
63 | | - /// coroutine frame implicitly stores the resume and destroy functions, |
64 | | - /// the current index, and any promise value. |
65 | | - Switch, |
66 | | - |
67 | | - /// The "returned-continuation" lowering, where each suspend point creates a |
68 | | - /// single continuation function that is used for both resuming and |
69 | | - /// destroying. Does not support promises. |
70 | | - Retcon, |
71 | | - |
72 | | - /// The "unique returned-continuation" lowering, where each suspend point |
73 | | - /// creates a single continuation function that is used for both resuming |
74 | | - /// and destroying. Does not support promises. The function is known to |
75 | | - /// suspend at most once during its execution, and the return value of |
76 | | - /// the continuation is void. |
77 | | - RetconOnce, |
78 | | - |
79 | | - /// The "async continuation" lowering, where each suspend point creates a |
80 | | - /// single continuation function. The continuation function is available as an |
81 | | - /// intrinsic. |
82 | | - Async, |
83 | | -}; |
84 | | - |
85 | | -// Holds structural Coroutine Intrinsics for a particular function and other |
86 | | -// values used during CoroSplit pass. |
87 | | -struct LLVM_LIBRARY_VISIBILITY Shape { |
88 | | - CoroBeginInst *CoroBegin; |
89 | | - SmallVector<AnyCoroEndInst *, 4> CoroEnds; |
90 | | - SmallVector<CoroSizeInst *, 2> CoroSizes; |
91 | | - SmallVector<CoroAlignInst *, 2> CoroAligns; |
92 | | - SmallVector<AnyCoroSuspendInst *, 4> CoroSuspends; |
93 | | - SmallVector<CallInst*, 2> SwiftErrorOps; |
94 | | - SmallVector<CoroAwaitSuspendInst *, 4> CoroAwaitSuspends; |
95 | | - SmallVector<CallInst *, 2> SymmetricTransfers; |
96 | | - |
97 | | - // Field indexes for special fields in the switch lowering. |
98 | | - struct SwitchFieldIndex { |
99 | | - enum { |
100 | | - Resume, |
101 | | - Destroy |
102 | | - |
103 | | - // The promise field is always at a fixed offset from the start of |
104 | | - // frame given its type, but the index isn't a constant for all |
105 | | - // possible frames. |
106 | | - |
107 | | - // The switch-index field isn't at a fixed offset or index, either; |
108 | | - // we just work it in where it fits best. |
109 | | - }; |
110 | | - }; |
111 | | - |
112 | | - coro::ABI ABI; |
113 | | - |
114 | | - StructType *FrameTy; |
115 | | - Align FrameAlign; |
116 | | - uint64_t FrameSize; |
117 | | - Value *FramePtr; |
118 | | - BasicBlock *AllocaSpillBlock; |
119 | | - |
120 | | - /// This would only be true if optimization are enabled. |
121 | | - bool OptimizeFrame; |
122 | | - |
123 | | - struct SwitchLoweringStorage { |
124 | | - SwitchInst *ResumeSwitch; |
125 | | - AllocaInst *PromiseAlloca; |
126 | | - BasicBlock *ResumeEntryBlock; |
127 | | - unsigned IndexField; |
128 | | - unsigned IndexAlign; |
129 | | - unsigned IndexOffset; |
130 | | - bool HasFinalSuspend; |
131 | | - bool HasUnwindCoroEnd; |
132 | | - }; |
133 | | - |
134 | | - struct RetconLoweringStorage { |
135 | | - Function *ResumePrototype; |
136 | | - Function *Alloc; |
137 | | - Function *Dealloc; |
138 | | - BasicBlock *ReturnBlock; |
139 | | - bool IsFrameInlineInStorage; |
140 | | - }; |
141 | | - |
142 | | - struct AsyncLoweringStorage { |
143 | | - Value *Context; |
144 | | - CallingConv::ID AsyncCC; |
145 | | - unsigned ContextArgNo; |
146 | | - uint64_t ContextHeaderSize; |
147 | | - uint64_t ContextAlignment; |
148 | | - uint64_t FrameOffset; // Start of the frame. |
149 | | - uint64_t ContextSize; // Includes frame size. |
150 | | - GlobalVariable *AsyncFuncPointer; |
151 | | - |
152 | | - Align getContextAlignment() const { return Align(ContextAlignment); } |
153 | | - }; |
154 | | - |
155 | | - union { |
156 | | - SwitchLoweringStorage SwitchLowering; |
157 | | - RetconLoweringStorage RetconLowering; |
158 | | - AsyncLoweringStorage AsyncLowering; |
159 | | - }; |
160 | | - |
161 | | - CoroIdInst *getSwitchCoroId() const { |
162 | | - assert(ABI == coro::ABI::Switch); |
163 | | - return cast<CoroIdInst>(CoroBegin->getId()); |
164 | | - } |
165 | | - |
166 | | - AnyCoroIdRetconInst *getRetconCoroId() const { |
167 | | - assert(ABI == coro::ABI::Retcon || |
168 | | - ABI == coro::ABI::RetconOnce); |
169 | | - return cast<AnyCoroIdRetconInst>(CoroBegin->getId()); |
170 | | - } |
171 | | - |
172 | | - CoroIdAsyncInst *getAsyncCoroId() const { |
173 | | - assert(ABI == coro::ABI::Async); |
174 | | - return cast<CoroIdAsyncInst>(CoroBegin->getId()); |
175 | | - } |
176 | | - |
177 | | - unsigned getSwitchIndexField() const { |
178 | | - assert(ABI == coro::ABI::Switch); |
179 | | - assert(FrameTy && "frame type not assigned"); |
180 | | - return SwitchLowering.IndexField; |
181 | | - } |
182 | | - IntegerType *getIndexType() const { |
183 | | - assert(ABI == coro::ABI::Switch); |
184 | | - assert(FrameTy && "frame type not assigned"); |
185 | | - return cast<IntegerType>(FrameTy->getElementType(getSwitchIndexField())); |
186 | | - } |
187 | | - ConstantInt *getIndex(uint64_t Value) const { |
188 | | - return ConstantInt::get(getIndexType(), Value); |
189 | | - } |
190 | | - |
191 | | - PointerType *getSwitchResumePointerType() const { |
192 | | - assert(ABI == coro::ABI::Switch); |
193 | | - assert(FrameTy && "frame type not assigned"); |
194 | | - return cast<PointerType>(FrameTy->getElementType(SwitchFieldIndex::Resume)); |
195 | | - } |
196 | | - |
197 | | - FunctionType *getResumeFunctionType() const { |
198 | | - switch (ABI) { |
199 | | - case coro::ABI::Switch: |
200 | | - return FunctionType::get(Type::getVoidTy(FrameTy->getContext()), |
201 | | - PointerType::getUnqual(FrameTy->getContext()), |
202 | | - /*IsVarArg=*/false); |
203 | | - case coro::ABI::Retcon: |
204 | | - case coro::ABI::RetconOnce: |
205 | | - return RetconLowering.ResumePrototype->getFunctionType(); |
206 | | - case coro::ABI::Async: |
207 | | - // Not used. The function type depends on the active suspend. |
208 | | - return nullptr; |
209 | | - } |
210 | | - |
211 | | - llvm_unreachable("Unknown coro::ABI enum"); |
212 | | - } |
213 | | - |
214 | | - ArrayRef<Type*> getRetconResultTypes() const { |
215 | | - assert(ABI == coro::ABI::Retcon || |
216 | | - ABI == coro::ABI::RetconOnce); |
217 | | - auto FTy = CoroBegin->getFunction()->getFunctionType(); |
218 | | - |
219 | | - // The safety of all this is checked by checkWFRetconPrototype. |
220 | | - if (auto STy = dyn_cast<StructType>(FTy->getReturnType())) { |
221 | | - return STy->elements().slice(1); |
222 | | - } else { |
223 | | - return ArrayRef<Type*>(); |
224 | | - } |
225 | | - } |
226 | | - |
227 | | - ArrayRef<Type*> getRetconResumeTypes() const { |
228 | | - assert(ABI == coro::ABI::Retcon || |
229 | | - ABI == coro::ABI::RetconOnce); |
230 | | - |
231 | | - // The safety of all this is checked by checkWFRetconPrototype. |
232 | | - auto FTy = RetconLowering.ResumePrototype->getFunctionType(); |
233 | | - return FTy->params().slice(1); |
234 | | - } |
235 | | - |
236 | | - CallingConv::ID getResumeFunctionCC() const { |
237 | | - switch (ABI) { |
238 | | - case coro::ABI::Switch: |
239 | | - return CallingConv::Fast; |
240 | | - |
241 | | - case coro::ABI::Retcon: |
242 | | - case coro::ABI::RetconOnce: |
243 | | - return RetconLowering.ResumePrototype->getCallingConv(); |
244 | | - case coro::ABI::Async: |
245 | | - return AsyncLowering.AsyncCC; |
246 | | - } |
247 | | - llvm_unreachable("Unknown coro::ABI enum"); |
248 | | - } |
249 | | - |
250 | | - AllocaInst *getPromiseAlloca() const { |
251 | | - if (ABI == coro::ABI::Switch) |
252 | | - return SwitchLowering.PromiseAlloca; |
253 | | - return nullptr; |
254 | | - } |
255 | | - |
256 | | - BasicBlock::iterator getInsertPtAfterFramePtr() const { |
257 | | - if (auto *I = dyn_cast<Instruction>(FramePtr)) { |
258 | | - BasicBlock::iterator It = std::next(I->getIterator()); |
259 | | - It.setHeadBit(true); // Copy pre-RemoveDIs behaviour. |
260 | | - return It; |
261 | | - } |
262 | | - return cast<Argument>(FramePtr)->getParent()->getEntryBlock().begin(); |
263 | | - } |
264 | | - |
265 | | - /// Allocate memory according to the rules of the active lowering. |
266 | | - /// |
267 | | - /// \param CG - if non-null, will be updated for the new call |
268 | | - Value *emitAlloc(IRBuilder<> &Builder, Value *Size, CallGraph *CG) const; |
269 | | - |
270 | | - /// Deallocate memory according to the rules of the active lowering. |
271 | | - /// |
272 | | - /// \param CG - if non-null, will be updated for the new call |
273 | | - void emitDealloc(IRBuilder<> &Builder, Value *Ptr, CallGraph *CG) const; |
274 | | - |
275 | | - Shape() = default; |
276 | | - explicit Shape(Function &F, bool OptimizeFrame = false) |
277 | | - : OptimizeFrame(OptimizeFrame) { |
278 | | - buildFrom(F); |
279 | | - } |
280 | | - void buildFrom(Function &F); |
281 | | -}; |
282 | | - |
283 | 61 | bool defaultMaterializable(Instruction &V); |
284 | 62 | void normalizeCoroutine(Function &F, coro::Shape &Shape, |
285 | 63 | TargetTransformInfo &TTI); |
|
0 commit comments