LLVM  12.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"
17 
18 namespace llvm {
19 
20 class CallGraph;
21 class CallGraphSCC;
22 class PassRegistry;
23 
24 void initializeCoroEarlyLegacyPass(PassRegistry &);
25 void initializeCoroSplitLegacyPass(PassRegistry &);
26 void initializeCoroElideLegacyPass(PassRegistry &);
27 void initializeCoroCleanupLegacyPass(PassRegistry &);
28 
29 // CoroEarly pass marks every function that has coro.begin with a string
30 // attribute "coroutine.presplit"="0". CoroSplit pass processes the coroutine
31 // twice. First, it lets it go through complete IPO optimization pipeline as a
32 // single function. It forces restart of the pipeline by inserting an indirect
33 // call to an empty function "coro.devirt.trigger" which is devirtualized by
34 // CoroElide pass that triggers a restart of the pipeline by CGPassManager.
35 // When CoroSplit pass sees the same coroutine the second time, it splits it up,
36 // adds coroutine subfunctions to the SCC to be processed by IPO pipeline.
37 // Async lowering similarily triggers a restart of the pipeline after it has
38 // split the coroutine.
39 #define CORO_PRESPLIT_ATTR "coroutine.presplit"
40 #define UNPREPARED_FOR_SPLIT "0"
41 #define PREPARED_FOR_SPLIT "1"
42 #define ASYNC_RESTART_AFTER_SPLIT "2"
43 
44 #define CORO_DEVIRT_TRIGGER_FN "coro.devirt.trigger"
45 
46 namespace coro {
47 
48 bool declaresIntrinsics(const Module &M,
49  const std::initializer_list<StringRef>);
50 void replaceCoroFree(CoroIdInst *CoroId, bool Elide);
52  CallGraph &CG, CallGraphSCC &SCC);
53 
54 // Keeps data and helper functions for lowering coroutine intrinsics.
55 struct LowererBase {
61 
62  LowererBase(Module &M);
63  Value *makeSubFnCall(Value *Arg, int Index, Instruction *InsertPt);
64 };
65 
66 enum class ABI {
67  /// The "resume-switch" lowering, where there are separate resume and
68  /// destroy functions that are shared between all suspend points. The
69  /// coroutine frame implicitly stores the resume and destroy functions,
70  /// the current index, and any promise value.
71  Switch,
72 
73  /// The "returned-continuation" lowering, where each suspend point creates a
74  /// single continuation function that is used for both resuming and
75  /// destroying. Does not support promises.
76  Retcon,
77 
78  /// The "unique returned-continuation" lowering, where each suspend point
79  /// creates a single continuation function that is used for both resuming
80  /// and destroying. Does not support promises. The function is known to
81  /// suspend at most once during its execution, and the return value of
82  /// the continuation is void.
83  RetconOnce,
84 
85  /// The "async continuation" lowering, where each suspend point creates a
86  /// single continuation function. The continuation function is available as an
87  /// intrinsic.
88  Async,
89 };
90 
91 // Holds structural Coroutine Intrinsics for a particular function and other
92 // values used during CoroSplit pass.
99 
100  // Field indexes for special fields in the switch lowering.
102  enum {
104  Destroy
105 
106  // The promise field is always at a fixed offset from the start of
107  // frame given its type, but the index isn't a constant for all
108  // possible frames.
109 
110  // The switch-index field isn't at a fixed offset or index, either;
111  // we just work it in where it fits best.
112  };
113  };
114 
116 
119  uint64_t FrameSize;
122 
124 
129  unsigned IndexField;
131  };
132 
139  };
140 
144  unsigned ContextArgNo;
147  uint64_t FrameOffset; // Start of the frame.
148  uint64_t ContextSize; // Includes frame size.
150 
151  Align getContextAlignment() const { return Align(ContextAlignment); }
152  };
153 
154  union {
158  };
159 
162  return cast<CoroIdInst>(CoroBegin->getId());
163  }
164 
168  return cast<AnyCoroIdRetconInst>(CoroBegin->getId());
169  }
170 
173  return cast<CoroIdAsyncInst>(CoroBegin->getId());
174  }
175 
176  unsigned getSwitchIndexField() const {
178  assert(FrameTy && "frame type not assigned");
179  return SwitchLowering.IndexField;
180  }
183  assert(FrameTy && "frame type not assigned");
184  return cast<IntegerType>(FrameTy->getElementType(getSwitchIndexField()));
185  }
186  ConstantInt *getIndex(uint64_t Value) const {
187  return ConstantInt::get(getIndexType(), Value);
188  }
189 
192  assert(FrameTy && "frame type not assigned");
193  return cast<PointerType>(FrameTy->getElementType(SwitchFieldIndex::Resume));
194  }
195 
197  switch (ABI) {
198  case coro::ABI::Switch: {
199  auto *FnPtrTy = getSwitchResumePointerType();
200  return cast<FunctionType>(FnPtrTy->getPointerElementType());
201  }
202  case coro::ABI::Retcon:
204  return RetconLowering.ResumePrototype->getFunctionType();
205  case coro::ABI::Async:
206  return AsyncLowering.AsyncFuncTy;
207  }
208 
209  llvm_unreachable("Unknown coro::ABI enum");
210  }
211 
215  auto FTy = CoroBegin->getFunction()->getFunctionType();
216 
217  // The safety of all this is checked by checkWFRetconPrototype.
218  if (auto STy = dyn_cast<StructType>(FTy->getReturnType())) {
219  return STy->elements().slice(1);
220  } else {
221  return ArrayRef<Type*>();
222  }
223  }
224 
228 
229  // The safety of all this is checked by checkWFRetconPrototype.
230  auto FTy = RetconLowering.ResumePrototype->getFunctionType();
231  return FTy->params().slice(1);
232  }
233 
235  switch (ABI) {
236  case coro::ABI::Switch:
237  return CallingConv::Fast;
238 
239  case coro::ABI::Retcon:
241  return RetconLowering.ResumePrototype->getCallingConv();
242  case coro::ABI::Async:
243  return CallingConv::Swift;
244  }
245  llvm_unreachable("Unknown coro::ABI enum");
246  }
247 
249  if (ABI == coro::ABI::Switch)
250  return SwitchLowering.PromiseAlloca;
251  return nullptr;
252  }
253 
254  /// Allocate memory according to the rules of the active lowering.
255  ///
256  /// \param CG - if non-null, will be updated for the new call
257  Value *emitAlloc(IRBuilder<> &Builder, Value *Size, CallGraph *CG) const;
258 
259  /// Deallocate memory according to the rules of the active lowering.
260  ///
261  /// \param CG - if non-null, will be updated for the new call
262  void emitDealloc(IRBuilder<> &Builder, Value *Ptr, CallGraph *CG) const;
263 
264  Shape() = default;
265  explicit Shape(Function &F, bool ReuseFrameSlot = false)
266  : ReuseFrameSlot(ReuseFrameSlot) {
267  buildFrom(F);
268  }
269  void buildFrom(Function &F);
270 };
271 
272 void buildCoroutineFrame(Function &F, Shape &Shape);
273 CallInst *createMustTailCall(DebugLoc Loc, Function *MustTailCallFn,
275 } // End namespace coro.
276 } // End namespace llvm
277 
278 #endif
The "returned-continuation" lowering, where each suspend point creates a single continuation function...
Instruction * FramePtr
Definition: CoroInternal.h:120
This represents the llvm.coro.id.async instruction.
Definition: CoroInstr.h:277
The "resume-switch" lowering, where there are separate resume and destroy functions that are shared b...
The "unique returned-continuation" lowering, where each suspend point creates a single continuation f...
void initializeCoroElideLegacyPass(PassRegistry &)
CoroBeginInst * CoroBegin
Definition: CoroInternal.h:94
This represents the llvm.coro.id instruction.
Definition: CoroInstr.h:113
This class represents lattice values for constants.
Definition: AllocatorList.h:23
Type * getElementType(unsigned N) const
Definition: DerivedTypes.h:327
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:67
PointerType * getSwitchResumePointerType() const
Definition: CoroInternal.h:190
IntegerType * getIndexType() const
Definition: CoroInternal.h:181
AsyncLoweringStorage AsyncLowering
Definition: CoroInternal.h:157
This class represents a function call, abstracting a target machine's calling convention.
SmallVector< CallInst *, 2 > SwiftErrorOps
Definition: CoroInternal.h:98
RetconLoweringStorage RetconLowering
Definition: CoroInternal.h:156
A debug info location.
Definition: DebugLoc.h:33
F(f)
FunctionType * getResumeFunctionType() const
Definition: CoroInternal.h:196
PointerType *const Int8Ptr
Definition: CoroInternal.h:58
Class to represent struct types.
Definition: DerivedTypes.h:212
unsigned getSwitchIndexField() const
Definition: CoroInternal.h:176
void updateCallGraph(Function &Caller, ArrayRef< Function * > Funcs, CallGraph &CG, CallGraphSCC &SCC)
Definition: Coroutines.cpp:214
ConstantInt * getIndex(uint64_t Value) const
Definition: CoroInternal.h:186
Class to represent function types.
Definition: DerivedTypes.h:102
FunctionType *const ResumeFnType
Definition: CoroInternal.h:59
CoroIdInst * getSwitchCoroId() const
Definition: CoroInternal.h:160
SmallVector< CoroSizeInst *, 2 > CoroSizes
Definition: CoroInternal.h:96
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: APInt.h:32
AnyCoroIdRetconInst * getRetconCoroId() const
Definition: CoroInternal.h:165
This represents either the llvm.coro.id.retcon or llvm.coro.id.retcon.once instruction.
Definition: CoroInstr.h:204
Class to represent pointers.
Definition: DerivedTypes.h:655
LLVM Basic Block Representation.
Definition: BasicBlock.h:58
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:68
The "async continuation" lowering, where each suspend point creates a single continuation function.
void initializeCoroEarlyLegacyPass(PassRegistry &)
AMDGPU Lower Kernel Arguments
amdgpu Simplify well known AMD library false FunctionCallee Value * Arg
Fast - This calling convention attempts to make calls as fast as possible (e.g.
Definition: CallingConv.h:42
#define LLVM_LIBRARY_VISIBILITY
LLVM_LIBRARY_VISIBILITY - If a class marked with this attribute is linked into a shared library,...
Definition: Compiler.h:130
Class to represent integer types.
Definition: DerivedTypes.h:40
const Function * getFunction() const
Return the function this instruction belongs to.
Definition: Instruction.cpp:69
assume Assume Builder
uint64_t Align
AllocaInst * getPromiseAlloca() const
Definition: CoroInternal.h:248
CallInst * createMustTailCall(DebugLoc Loc, Function *MustTailCallFn, ArrayRef< Value * > Arguments, IRBuilder<> &)
Definition: CoroSplit.cpp:1438
LLVMContext & Context
Definition: CoroInternal.h:57
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39
CoroIdAsyncInst * getAsyncCoroId() const
Definition: CoroInternal.h:171
SwitchLoweringStorage SwitchLowering
Definition: CoroInternal.h:155
AnyCoroIdInst * getId() const
Definition: CoroInstr.h:412
StructType * FrameTy
Definition: CoroInternal.h:117
bool declaresIntrinsics(const Module &M, const std::initializer_list< StringRef >)
Definition: Coroutines.cpp:160
This is the shared class of boolean and integer constants.
Definition: Constants.h:77
ArrayRef< Type * > getRetconResumeTypes() const
Definition: CoroInternal.h:225
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1116
A constant pointer value that points to null.
Definition: Constants.h:550
uint32_t Index
ConstantPointerNull *const NullPtr
Definition: CoroInternal.h:60
void buildCoroutineFrame(Function &F, Shape &Shape)
Definition: CoroFrame.cpp:2163
static Constant * get(Type *Ty, uint64_t V, bool isSigned=false)
If Ty is a vector type, return a Constant with a splat of the given value.
Definition: Constants.cpp:867
CallingConv::ID getResumeFunctionCC() const
Definition: CoroInternal.h:234
FunctionType * getFunctionType() const
Returns the FunctionType for me.
Definition: Function.h:165
This class represents the llvm.coro.begin instruction.
Definition: CoroInstr.h:408
Value * makeSubFnCall(Value *Arg, int Index, Instruction *InsertPt)
Definition: Coroutines.cpp:107
SmallVector< AnyCoroSuspendInst *, 4 > CoroSuspends
Definition: CoroInternal.h:97
The basic data container for the call graph of a Module of IR.
Definition: CallGraph.h:73
void replaceCoroFree(CoroIdInst *CoroId, bool Elide)
Definition: Coroutines.cpp:173
Multiway switch.
void initializeCoroCleanupLegacyPass(PassRegistry &)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
LLVM Value Representation.
Definition: Value.h:75
CallGraphSCC - This is a single SCC that a CallGraphSCCPass is run on.
SmallVector< AnyCoroEndInst *, 4 > CoroEnds
Definition: CoroInternal.h:95
BasicBlock * AllocaSpillBlock
Definition: CoroInternal.h:121
void initializeCoroSplitLegacyPass(PassRegistry &)
Shape(Function &F, bool ReuseFrameSlot=false)
Definition: CoroInternal.h:265
an instruction to allocate memory on the stack
Definition: Instructions.h:61
ArrayRef< Type * > getRetconResultTypes() const
Definition: CoroInternal.h:212