Skip to content

Commit 45fdd5a

Browse files
author
tnowicki
committed
[Coroutines] Move Shape to its own header
* Plugin libraries to create custom ABIs will need access to CoroShape. * As a step in enabling plugin libraries, move Shape into its own header that will eventually be moved into include/llvm/Transforms/Coroutines
1 parent 9a9f155 commit 45fdd5a

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

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

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

0 commit comments

Comments
 (0)