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