LLVM 17.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"
15#include "llvm/IR/IRBuilder.h"
16
17namespace llvm {
18
19class CallGraph;
20
21namespace coro {
22
23bool declaresAnyIntrinsic(const Module &M);
24bool declaresIntrinsics(const Module &M,
25 const std::initializer_list<StringRef>);
26void replaceCoroFree(CoroIdInst *CoroId, bool Elide);
27
28/// Recover a dbg.declare prepared by the frontend and emit an alloca
29/// holding a pointer to the coroutine frame.
32 DbgVariableIntrinsic *DVI, bool OptimizeFrame);
33
34// Keeps data and helper functions for lowering coroutine intrinsics.
41
43 Value *makeSubFnCall(Value *Arg, int Index, Instruction *InsertPt);
44};
45
46enum class ABI {
47 /// The "resume-switch" lowering, where there are separate resume and
48 /// destroy functions that are shared between all suspend points. The
49 /// coroutine frame implicitly stores the resume and destroy functions,
50 /// the current index, and any promise value.
51 Switch,
52
53 /// The "returned-continuation" lowering, where each suspend point creates a
54 /// single continuation function that is used for both resuming and
55 /// destroying. Does not support promises.
56 Retcon,
57
58 /// The "unique returned-continuation" lowering, where each suspend point
59 /// creates a single continuation function that is used for both resuming
60 /// and destroying. Does not support promises. The function is known to
61 /// suspend at most once during its execution, and the return value of
62 /// the continuation is void.
64
65 /// The "async continuation" lowering, where each suspend point creates a
66 /// single continuation function. The continuation function is available as an
67 /// intrinsic.
68 Async,
69};
70
71// Holds structural Coroutine Intrinsics for a particular function and other
72// values used during CoroSplit pass.
80
81 // Field indexes for special fields in the switch lowering.
83 enum {
85 Destroy
86
87 // The promise field is always at a fixed offset from the start of
88 // frame given its type, but the index isn't a constant for all
89 // possible frames.
90
91 // The switch-index field isn't at a fixed offset or index, either;
92 // we just work it in where it fits best.
93 };
94 };
95
97
103
104 /// This would only be true if optimization are enabled.
106
111 unsigned IndexField;
112 unsigned IndexAlign;
113 unsigned IndexOffset;
116 };
117
124 };
125
130 unsigned ContextArgNo;
133 uint64_t FrameOffset; // Start of the frame.
134 uint64_t ContextSize; // Includes frame size.
136
137 Align getContextAlignment() const { return Align(ContextAlignment); }
138 };
139
140 union {
144 };
145
147 assert(ABI == coro::ABI::Switch);
148 return cast<CoroIdInst>(CoroBegin->getId());
149 }
150
152 assert(ABI == coro::ABI::Retcon ||
153 ABI == coro::ABI::RetconOnce);
154 return cast<AnyCoroIdRetconInst>(CoroBegin->getId());
155 }
156
158 assert(ABI == coro::ABI::Async);
159 return cast<CoroIdAsyncInst>(CoroBegin->getId());
160 }
161
162 unsigned getSwitchIndexField() const {
163 assert(ABI == coro::ABI::Switch);
164 assert(FrameTy && "frame type not assigned");
165 return SwitchLowering.IndexField;
166 }
168 assert(ABI == coro::ABI::Switch);
169 assert(FrameTy && "frame type not assigned");
170 return cast<IntegerType>(FrameTy->getElementType(getSwitchIndexField()));
171 }
173 return ConstantInt::get(getIndexType(), Value);
174 }
175
177 assert(ABI == coro::ABI::Switch);
178 assert(FrameTy && "frame type not assigned");
179 return cast<PointerType>(FrameTy->getElementType(SwitchFieldIndex::Resume));
180 }
181
183 switch (ABI) {
184 case coro::ABI::Switch:
185 return FunctionType::get(Type::getVoidTy(FrameTy->getContext()),
186 FrameTy->getPointerTo(), /*IsVarArg*/false);
187 case coro::ABI::Retcon:
188 case coro::ABI::RetconOnce:
189 return RetconLowering.ResumePrototype->getFunctionType();
190 case coro::ABI::Async:
191 // Not used. The function type depends on the active suspend.
192 return nullptr;
193 }
194
195 llvm_unreachable("Unknown coro::ABI enum");
196 }
197
199 assert(ABI == coro::ABI::Retcon ||
200 ABI == coro::ABI::RetconOnce);
201 auto FTy = CoroBegin->getFunction()->getFunctionType();
202
203 // The safety of all this is checked by checkWFRetconPrototype.
204 if (auto STy = dyn_cast<StructType>(FTy->getReturnType())) {
205 return STy->elements().slice(1);
206 } else {
207 return ArrayRef<Type*>();
208 }
209 }
210
212 assert(ABI == coro::ABI::Retcon ||
213 ABI == coro::ABI::RetconOnce);
214
215 // The safety of all this is checked by checkWFRetconPrototype.
216 auto FTy = RetconLowering.ResumePrototype->getFunctionType();
217 return FTy->params().slice(1);
218 }
219
221 switch (ABI) {
222 case coro::ABI::Switch:
223 return CallingConv::Fast;
224
225 case coro::ABI::Retcon:
226 case coro::ABI::RetconOnce:
227 return RetconLowering.ResumePrototype->getCallingConv();
228 case coro::ABI::Async:
229 return AsyncLowering.AsyncCC;
230 }
231 llvm_unreachable("Unknown coro::ABI enum");
232 }
233
235 if (ABI == coro::ABI::Switch)
236 return SwitchLowering.PromiseAlloca;
237 return nullptr;
238 }
239
241 if (auto *I = dyn_cast<Instruction>(FramePtr))
242 return I->getNextNode();
243 return &cast<Argument>(FramePtr)->getParent()->getEntryBlock().front();
244 }
245
246 /// Allocate memory according to the rules of the active lowering.
247 ///
248 /// \param CG - if non-null, will be updated for the new call
249 Value *emitAlloc(IRBuilder<> &Builder, Value *Size, CallGraph *CG) const;
250
251 /// Deallocate memory according to the rules of the active lowering.
252 ///
253 /// \param CG - if non-null, will be updated for the new call
254 void emitDealloc(IRBuilder<> &Builder, Value *Ptr, CallGraph *CG) const;
255
256 Shape() = default;
257 explicit Shape(Function &F, bool OptimizeFrame = false)
258 : OptimizeFrame(OptimizeFrame) {
259 buildFrom(F);
260 }
261 void buildFrom(Function &F);
262};
263
264void buildCoroutineFrame(Function &F, Shape &Shape);
265CallInst *createMustTailCall(DebugLoc Loc, Function *MustTailCallFn,
267} // End namespace coro.
268} // End namespace llvm
269
270#endif
amdgpu Simplify well known AMD library false FunctionCallee Value * Arg
AMDGPU Lower Kernel Arguments
#define LLVM_LIBRARY_VISIBILITY
LLVM_LIBRARY_VISIBILITY - If a class marked with this attribute is linked into a shared library,...
Definition: Compiler.h:126
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())
static const unsigned FramePtr
an instruction to allocate memory on the stack
Definition: Instructions.h:58
This represents either the llvm.coro.id.retcon or llvm.coro.id.retcon.once instruction.
Definition: CoroInstr.h:204
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:56
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:78
A constant pointer value that points to null.
Definition: Constants.h:534
This class represents the llvm.coro.begin instruction.
Definition: CoroInstr.h:420
AnyCoroIdInst * getId() const
Definition: CoroInstr.h:424
This represents the llvm.coro.id.async instruction.
Definition: CoroInstr.h:277
This represents the llvm.coro.id instruction.
Definition: CoroInstr.h:113
This is the common base class for debug info intrinsics for variables.
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:174
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition: IRBuilder.h:2550
const Function * getFunction() const
Return the function this instruction belongs to.
Definition: Instruction.cpp:74
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:632
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
Class to represent struct types.
Definition: DerivedTypes.h:213
Type * getElementType(unsigned N) const
Definition: DerivedTypes.h:328
Multiway switch.
PointerType * getPointerTo(unsigned AddrSpace=0) const
Return a pointer to the current type.
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.
@ 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...
void salvageDebugInfo(SmallDenseMap< llvm::Value *, llvm::AllocaInst *, 4 > &DbgPtrAllocaCache, DbgVariableIntrinsic *DVI, bool OptimizeFrame)
Recover a dbg.declare prepared by the frontend and emit an alloca holding a pointer to the coroutine ...
Definition: CoroFrame.cpp:2637
void buildCoroutineFrame(Function &F, Shape &Shape)
Definition: CoroFrame.cpp:2727
bool declaresAnyIntrinsic(const Module &M)
Definition: Coroutines.cpp:105
bool declaresIntrinsics(const Module &M, const std::initializer_list< StringRef >)
Definition: Coroutines.cpp:117
void replaceCoroFree(CoroIdInst *CoroId, bool Elide)
Definition: Coroutines.cpp:130
CallInst * createMustTailCall(DebugLoc Loc, Function *MustTailCallFn, ArrayRef< Value * > Arguments, IRBuilder<> &)
Definition: CoroSplit.cpp:1675
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:38
ConstantPointerNull *const NullPtr
Definition: CoroInternal.h:40
Value * makeSubFnCall(Value *Arg, int Index, Instruction *InsertPt)
Definition: Coroutines.cpp:51
LLVMContext & Context
Definition: CoroInternal.h:37
FunctionType *const ResumeFnType
Definition: CoroInternal.h:39
AsyncLoweringStorage AsyncLowering
Definition: CoroInternal.h:143
FunctionType * getResumeFunctionType() const
Definition: CoroInternal.h:182
IntegerType * getIndexType() const
Definition: CoroInternal.h:167
StructType * FrameTy
Definition: CoroInternal.h:98
AnyCoroIdRetconInst * getRetconCoroId() const
Definition: CoroInternal.h:151
PointerType * getSwitchResumePointerType() const
Definition: CoroInternal.h:176
CoroIdInst * getSwitchCoroId() const
Definition: CoroInternal.h:146
Instruction * getInsertPtAfterFramePtr() const
Definition: CoroInternal.h:240
SmallVector< CoroSizeInst *, 2 > CoroSizes
Definition: CoroInternal.h:76
CallingConv::ID getResumeFunctionCC() const
Definition: CoroInternal.h:220
ArrayRef< Type * > getRetconResumeTypes() const
Definition: CoroInternal.h:211
SmallVector< AnyCoroSuspendInst *, 4 > CoroSuspends
Definition: CoroInternal.h:78
Shape(Function &F, bool OptimizeFrame=false)
Definition: CoroInternal.h:257
SmallVector< CallInst *, 2 > SwiftErrorOps
Definition: CoroInternal.h:79
ConstantInt * getIndex(uint64_t Value) const
Definition: CoroInternal.h:172
AllocaInst * getPromiseAlloca() const
Definition: CoroInternal.h:234
bool OptimizeFrame
This would only be true if optimization are enabled.
Definition: CoroInternal.h:105
SwitchLoweringStorage SwitchLowering
Definition: CoroInternal.h:141
CoroBeginInst * CoroBegin
Definition: CoroInternal.h:74
ArrayRef< Type * > getRetconResultTypes() const
Definition: CoroInternal.h:198
RetconLoweringStorage RetconLowering
Definition: CoroInternal.h:142
SmallVector< CoroAlignInst *, 2 > CoroAligns
Definition: CoroInternal.h:77
CoroIdAsyncInst * getAsyncCoroId() const
Definition: CoroInternal.h:157
SmallVector< AnyCoroEndInst *, 4 > CoroEnds
Definition: CoroInternal.h:75
BasicBlock * AllocaSpillBlock
Definition: CoroInternal.h:102
unsigned getSwitchIndexField() const
Definition: CoroInternal.h:162