LLVM 19.0.0git
CoroInternal.h
Go to the documentation of this file.
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"
16#include "llvm/IR/IRBuilder.h"
17
18namespace llvm {
19
20class CallGraph;
21
22namespace coro {
23
24bool declaresAnyIntrinsic(const Module &M);
25bool declaresIntrinsics(const Module &M,
26 const std::initializer_list<StringRef>);
27void replaceCoroFree(CoroIdInst *CoroId, bool Elide);
28
29/// Attempts to rewrite the location operand of debug intrinsics in terms of
30/// the coroutine frame pointer, folding pointer offsets into the DIExpression
31/// of the intrinsic.
32/// If the frame pointer is an Argument, store it into an alloca if
33/// OptimizeFrame is false.
36 DbgVariableIntrinsic &DVI, bool OptimizeFrame, bool IsEntryPoint);
39 DbgVariableRecord &DVR, bool OptimizeFrame, bool UseEntryValue);
40
41// Keeps data and helper functions for lowering coroutine intrinsics.
48
50 Value *makeSubFnCall(Value *Arg, int Index, Instruction *InsertPt);
51};
52
53enum class ABI {
54 /// The "resume-switch" lowering, where there are separate resume and
55 /// destroy functions that are shared between all suspend points. The
56 /// coroutine frame implicitly stores the resume and destroy functions,
57 /// the current index, and any promise value.
58 Switch,
59
60 /// The "returned-continuation" lowering, where each suspend point creates a
61 /// single continuation function that is used for both resuming and
62 /// destroying. Does not support promises.
63 Retcon,
64
65 /// The "unique returned-continuation" lowering, where each suspend point
66 /// creates a single continuation function that is used for both resuming
67 /// and destroying. Does not support promises. The function is known to
68 /// suspend at most once during its execution, and the return value of
69 /// the continuation is void.
71
72 /// The "async continuation" lowering, where each suspend point creates a
73 /// single continuation function. The continuation function is available as an
74 /// intrinsic.
75 Async,
76};
77
78// Holds structural Coroutine Intrinsics for a particular function and other
79// values used during CoroSplit pass.
88
89 // Field indexes for special fields in the switch lowering.
91 enum {
93 Destroy
94
95 // The promise field is always at a fixed offset from the start of
96 // frame given its type, but the index isn't a constant for all
97 // possible frames.
98
99 // The switch-index field isn't at a fixed offset or index, either;
100 // we just work it in where it fits best.
101 };
102 };
103
105
111
112 /// This would only be true if optimization are enabled.
114
119 unsigned IndexField;
120 unsigned IndexAlign;
121 unsigned IndexOffset;
124 };
125
132 };
133
137 unsigned ContextArgNo;
140 uint64_t FrameOffset; // Start of the frame.
141 uint64_t ContextSize; // Includes frame size.
143
144 Align getContextAlignment() const { return Align(ContextAlignment); }
145 };
146
147 union {
151 };
152
154 assert(ABI == coro::ABI::Switch);
155 return cast<CoroIdInst>(CoroBegin->getId());
156 }
157
159 assert(ABI == coro::ABI::Retcon ||
160 ABI == coro::ABI::RetconOnce);
161 return cast<AnyCoroIdRetconInst>(CoroBegin->getId());
162 }
163
165 assert(ABI == coro::ABI::Async);
166 return cast<CoroIdAsyncInst>(CoroBegin->getId());
167 }
168
169 unsigned getSwitchIndexField() const {
170 assert(ABI == coro::ABI::Switch);
171 assert(FrameTy && "frame type not assigned");
172 return SwitchLowering.IndexField;
173 }
175 assert(ABI == coro::ABI::Switch);
176 assert(FrameTy && "frame type not assigned");
177 return cast<IntegerType>(FrameTy->getElementType(getSwitchIndexField()));
178 }
180 return ConstantInt::get(getIndexType(), Value);
181 }
182
184 assert(ABI == coro::ABI::Switch);
185 assert(FrameTy && "frame type not assigned");
186 return cast<PointerType>(FrameTy->getElementType(SwitchFieldIndex::Resume));
187 }
188
190 switch (ABI) {
191 case coro::ABI::Switch:
192 return FunctionType::get(Type::getVoidTy(FrameTy->getContext()),
193 PointerType::getUnqual(FrameTy->getContext()),
194 /*IsVarArg=*/false);
195 case coro::ABI::Retcon:
196 case coro::ABI::RetconOnce:
197 return RetconLowering.ResumePrototype->getFunctionType();
198 case coro::ABI::Async:
199 // Not used. The function type depends on the active suspend.
200 return nullptr;
201 }
202
203 llvm_unreachable("Unknown coro::ABI enum");
204 }
205
207 assert(ABI == coro::ABI::Retcon ||
208 ABI == coro::ABI::RetconOnce);
209 auto FTy = CoroBegin->getFunction()->getFunctionType();
210
211 // The safety of all this is checked by checkWFRetconPrototype.
212 if (auto STy = dyn_cast<StructType>(FTy->getReturnType())) {
213 return STy->elements().slice(1);
214 } else {
215 return ArrayRef<Type*>();
216 }
217 }
218
220 assert(ABI == coro::ABI::Retcon ||
221 ABI == coro::ABI::RetconOnce);
222
223 // The safety of all this is checked by checkWFRetconPrototype.
224 auto FTy = RetconLowering.ResumePrototype->getFunctionType();
225 return FTy->params().slice(1);
226 }
227
229 switch (ABI) {
230 case coro::ABI::Switch:
231 return CallingConv::Fast;
232
233 case coro::ABI::Retcon:
234 case coro::ABI::RetconOnce:
235 return RetconLowering.ResumePrototype->getCallingConv();
236 case coro::ABI::Async:
237 return AsyncLowering.AsyncCC;
238 }
239 llvm_unreachable("Unknown coro::ABI enum");
240 }
241
243 if (ABI == coro::ABI::Switch)
244 return SwitchLowering.PromiseAlloca;
245 return nullptr;
246 }
247
249 if (auto *I = dyn_cast<Instruction>(FramePtr)) {
250 BasicBlock::iterator It = std::next(I->getIterator());
251 It.setHeadBit(true); // Copy pre-RemoveDIs behaviour.
252 return It;
253 }
254 return cast<Argument>(FramePtr)->getParent()->getEntryBlock().begin();
255 }
256
257 /// Allocate memory according to the rules of the active lowering.
258 ///
259 /// \param CG - if non-null, will be updated for the new call
260 Value *emitAlloc(IRBuilder<> &Builder, Value *Size, CallGraph *CG) const;
261
262 /// Deallocate memory according to the rules of the active lowering.
263 ///
264 /// \param CG - if non-null, will be updated for the new call
265 void emitDealloc(IRBuilder<> &Builder, Value *Ptr, CallGraph *CG) const;
266
267 Shape() = default;
268 explicit Shape(Function &F, bool OptimizeFrame = false)
269 : OptimizeFrame(OptimizeFrame) {
270 buildFrom(F);
271 }
272 void buildFrom(Function &F);
273};
274
277 Function &F, Shape &Shape, TargetTransformInfo &TTI,
278 const std::function<bool(Instruction &)> &MaterializableCallback);
279CallInst *createMustTailCall(DebugLoc Loc, Function *MustTailCallFn,
282} // End namespace coro.
283} // End namespace llvm
284
285#endif
AMDGPU Lower Kernel Arguments
#define LLVM_LIBRARY_VISIBILITY
Definition: Compiler.h:131
uint64_t Align
uint64_t Size
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This pass exposes codegen information to IR-level passes.
static const unsigned FramePtr
an instruction to allocate memory on the stack
Definition: Instructions.h:59
This represents either the llvm.coro.id.retcon or llvm.coro.id.retcon.once instruction.
Definition: CoroInstr.h:235
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
LLVM Basic Block Representation.
Definition: BasicBlock.h:60
InstListType::iterator iterator
Instruction iterators...
Definition: BasicBlock.h:164
The basic data container for the call graph of a Module of IR.
Definition: CallGraph.h:72
This class represents a function call, abstracting a target machine's calling convention.
This is the shared class of boolean and integer constants.
Definition: Constants.h:80
A constant pointer value that points to null.
Definition: Constants.h:548
This class represents the llvm.coro.begin instruction.
Definition: CoroInstr.h:451
AnyCoroIdInst * getId() const
Definition: CoroInstr.h:455
This represents the llvm.coro.id.async instruction.
Definition: CoroInstr.h:308
This represents the llvm.coro.id instruction.
Definition: CoroInstr.h:146
This is the common base class for debug info intrinsics for variables.
Record of a variable value-assignment, aka a non instruction representation of the dbg....
A debug info location.
Definition: DebugLoc.h:33
Class to represent function types.
Definition: DerivedTypes.h:103
FunctionType * getFunctionType() const
Returns the FunctionType for me.
Definition: Function.h:200
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition: IRBuilder.h:2644
const Function * getFunction() const
Return the function this instruction belongs to.
Definition: Instruction.cpp:84
Class to represent integer types.
Definition: DerivedTypes.h:40
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:67
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
Class to represent pointers.
Definition: DerivedTypes.h:646
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
Class to represent struct types.
Definition: DerivedTypes.h:216
Type * getElementType(unsigned N) const
Definition: DerivedTypes.h:342
Multiway switch.
This pass provides access to the codegen interfaces that are needed for IR-level transformations.
LLVMContext & getContext() const
Return the LLVMContext in which this type was uniqued.
Definition: Type.h:129
LLVM Value Representation.
Definition: Value.h:74
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
void salvageDebugInfo(SmallDenseMap< Argument *, AllocaInst *, 4 > &ArgToAllocaMap, DbgVariableIntrinsic &DVI, bool OptimizeFrame, bool IsEntryPoint)
Attempts to rewrite the location operand of debug intrinsics in terms of the coroutine frame pointer,...
Definition: CoroFrame.cpp:2923
@ Async
The "async continuation" lowering, where each suspend point creates a single continuation function.
@ RetconOnce
The "unique returned-continuation" lowering, where each suspend point creates a single continuation f...
@ Retcon
The "returned-continuation" lowering, where each suspend point creates a single continuation function...
@ Switch
The "resume-switch" lowering, where there are separate resume and destroy functions that are shared b...
bool defaultMaterializable(Instruction &V)
Default materializable callback.
Definition: CoroFrame.cpp:2267
bool declaresAnyIntrinsic(const Module &M)
Definition: Coroutines.cpp:103
bool declaresIntrinsics(const Module &M, const std::initializer_list< StringRef >)
Definition: Coroutines.cpp:115
void buildCoroutineFrame(Function &F, Shape &Shape, TargetTransformInfo &TTI, const std::function< bool(Instruction &)> &MaterializableCallback)
Definition: CoroFrame.cpp:3067
CallInst * createMustTailCall(DebugLoc Loc, Function *MustTailCallFn, TargetTransformInfo &TTI, ArrayRef< Value * > Arguments, IRBuilder<> &)
Definition: CoroSplit.cpp:1785
void replaceCoroFree(CoroIdInst *CoroId, bool Elide)
Definition: Coroutines.cpp:128
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39
PointerType *const Int8Ptr
Definition: CoroInternal.h:45
ConstantPointerNull *const NullPtr
Definition: CoroInternal.h:47
Value * makeSubFnCall(Value *Arg, int Index, Instruction *InsertPt)
Definition: Coroutines.cpp:50
LLVMContext & Context
Definition: CoroInternal.h:44
FunctionType *const ResumeFnType
Definition: CoroInternal.h:46
SmallVector< CoroAwaitSuspendInst *, 4 > CoroAwaitSuspends
Definition: CoroInternal.h:87
AsyncLoweringStorage AsyncLowering
Definition: CoroInternal.h:150
FunctionType * getResumeFunctionType() const
Definition: CoroInternal.h:189
IntegerType * getIndexType() const
Definition: CoroInternal.h:174
StructType * FrameTy
Definition: CoroInternal.h:106
AnyCoroIdRetconInst * getRetconCoroId() const
Definition: CoroInternal.h:158
PointerType * getSwitchResumePointerType() const
Definition: CoroInternal.h:183
CoroIdInst * getSwitchCoroId() const
Definition: CoroInternal.h:153
SmallVector< CoroSizeInst *, 2 > CoroSizes
Definition: CoroInternal.h:83
CallingConv::ID getResumeFunctionCC() const
Definition: CoroInternal.h:228
ArrayRef< Type * > getRetconResumeTypes() const
Definition: CoroInternal.h:219
SmallVector< AnyCoroSuspendInst *, 4 > CoroSuspends
Definition: CoroInternal.h:85
Shape(Function &F, bool OptimizeFrame=false)
Definition: CoroInternal.h:268
SmallVector< CallInst *, 2 > SwiftErrorOps
Definition: CoroInternal.h:86
ConstantInt * getIndex(uint64_t Value) const
Definition: CoroInternal.h:179
AllocaInst * getPromiseAlloca() const
Definition: CoroInternal.h:242
bool OptimizeFrame
This would only be true if optimization are enabled.
Definition: CoroInternal.h:113
SwitchLoweringStorage SwitchLowering
Definition: CoroInternal.h:148
CoroBeginInst * CoroBegin
Definition: CoroInternal.h:81
BasicBlock::iterator getInsertPtAfterFramePtr() const
Definition: CoroInternal.h:248
ArrayRef< Type * > getRetconResultTypes() const
Definition: CoroInternal.h:206
RetconLoweringStorage RetconLowering
Definition: CoroInternal.h:149
SmallVector< CoroAlignInst *, 2 > CoroAligns
Definition: CoroInternal.h:84
CoroIdAsyncInst * getAsyncCoroId() const
Definition: CoroInternal.h:164
SmallVector< AnyCoroEndInst *, 4 > CoroEnds
Definition: CoroInternal.h:82
BasicBlock * AllocaSpillBlock
Definition: CoroInternal.h:110
unsigned getSwitchIndexField() const
Definition: CoroInternal.h:169