Skip to content

Commit 4c040c0

Browse files
authored
[Coroutines] Move Shape to its own header (#108242)
* To create custom ABIs plugin libraries need access to CoroShape. * As a step in enabling plugin libraries, move Shape into its own header * The header will eventually be moved into include/llvm/Transforms/Coroutines See RFC for more info: https://discourse.llvm.org/t/rfc-abi-objects-for-coroutines/81057
1 parent d4f41be commit 4c040c0

File tree

4 files changed

+252
-223
lines changed

4 files changed

+252
-223
lines changed

llvm/lib/Transforms/Coroutines/CoroEarly.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "llvm/Transforms/Coroutines/CoroEarly.h"
1010
#include "CoroInternal.h"
11+
#include "CoroShape.h"
1112
#include "llvm/IR/DIBuilder.h"
1213
#include "llvm/IR/Function.h"
1314
#include "llvm/IR/IRBuilder.h"

llvm/lib/Transforms/Coroutines/CoroInternal.h

+1-223
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#define LLVM_LIB_TRANSFORMS_COROUTINES_COROINTERNAL_H
1313

1414
#include "CoroInstr.h"
15+
#include "CoroShape.h"
1516
#include "llvm/Analysis/TargetTransformInfo.h"
1617
#include "llvm/IR/IRBuilder.h"
1718

@@ -58,229 +59,6 @@ struct LowererBase {
5859
CallInst *makeSubFnCall(Value *Arg, int Index, Instruction *InsertPt);
5960
};
6061

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-
28462
bool defaultMaterializable(Instruction &V);
28563
void normalizeCoroutine(Function &F, coro::Shape &Shape,
28664
TargetTransformInfo &TTI);

0 commit comments

Comments
 (0)