LLVM  4.0.0
Coroutines.cpp
Go to the documentation of this file.
1 //===-- Coroutines.cpp ----------------------------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 // This file implements the common infrastructure for Coroutine Passes.
10 //===----------------------------------------------------------------------===//
11 
12 #include "CoroInternal.h"
14 #include "llvm/IR/InstIterator.h"
16 #include "llvm/IR/Verifier.h"
17 #include "llvm/InitializePasses.h"
18 #include "llvm/Transforms/IPO.h"
21 
22 using namespace llvm;
23 
25  initializeCoroEarlyPass(Registry);
26  initializeCoroSplitPass(Registry);
27  initializeCoroElidePass(Registry);
28  initializeCoroCleanupPass(Registry);
29 }
30 
31 static void addCoroutineOpt0Passes(const PassManagerBuilder &Builder,
35 
38 }
39 
40 static void addCoroutineEarlyPasses(const PassManagerBuilder &Builder,
43 }
44 
48 }
49 
50 static void addCoroutineSCCPasses(const PassManagerBuilder &Builder,
53 }
54 
58 }
59 
71 }
72 
73 // Construct the lowerer base class and initialize its members.
75  : TheModule(M), Context(M.getContext()),
76  Int8Ptr(Type::getInt8PtrTy(Context)),
77  ResumeFnType(FunctionType::get(Type::getVoidTy(Context), Int8Ptr,
78  /*isVarArg=*/false)),
79  NullPtr(ConstantPointerNull::get(Int8Ptr)) {}
80 
81 // Creates a sequence of instructions to obtain a resume function address using
82 // llvm.coro.subfn.addr. It generates the following sequence:
83 //
84 // call i8* @llvm.coro.subfn.addr(i8* %Arg, i8 %index)
85 // bitcast i8* %2 to void(i8*)*
86 
88  Instruction *InsertPt) {
89  auto *IndexVal = ConstantInt::get(Type::getInt8Ty(Context), Index);
90  auto *Fn = Intrinsic::getDeclaration(&TheModule, Intrinsic::coro_subfn_addr);
91 
93  Index < CoroSubFnInst::IndexLast &&
94  "makeSubFnCall: Index value out of range");
95  auto *Call = CallInst::Create(Fn, {Arg, IndexVal}, "", InsertPt);
96 
97  auto *Bitcast =
98  new BitCastInst(Call, ResumeFnType->getPointerTo(), "", InsertPt);
99  return Bitcast;
100 }
101 
102 #ifndef NDEBUG
104  // NOTE: Must be sorted!
105  static const char *const CoroIntrinsics[] = {
106  "llvm.coro.alloc", "llvm.coro.begin", "llvm.coro.destroy",
107  "llvm.coro.done", "llvm.coro.end", "llvm.coro.frame",
108  "llvm.coro.free", "llvm.coro.id", "llvm.coro.param",
109  "llvm.coro.promise", "llvm.coro.resume", "llvm.coro.save",
110  "llvm.coro.size", "llvm.coro.subfn.addr", "llvm.coro.suspend",
111  };
112  return Intrinsic::lookupLLVMIntrinsicByName(CoroIntrinsics, Name) != -1;
113 }
114 #endif
115 
116 // Verifies if a module has named values listed. Also, in debug mode verifies
117 // that names are intrinsic names.
119  std::initializer_list<StringRef> List) {
120 
121  for (StringRef Name : List) {
122  assert(isCoroutineIntrinsicName(Name) && "not a coroutine intrinsic");
123  if (M.getNamedValue(Name))
124  return true;
125  }
126 
127  return false;
128 }
129 
130 // Replace all coro.frees associated with the provided CoroId either with 'null'
131 // if Elide is true and with its frame parameter otherwise.
132 void coro::replaceCoroFree(CoroIdInst *CoroId, bool Elide) {
134  for (User *U : CoroId->users())
135  if (auto CF = dyn_cast<CoroFreeInst>(U))
136  CoroFrees.push_back(CF);
137 
138  if (CoroFrees.empty())
139  return;
140 
141  Value *Replacement =
143  : CoroFrees.front()->getFrame();
144 
145  for (CoroFreeInst *CF : CoroFrees) {
146  CF->replaceAllUsesWith(Replacement);
147  CF->eraseFromParent();
148  }
149 }
150 
151 // FIXME: This code is stolen from CallGraph::addToCallGraph(Function *F), which
152 // happens to be private. It is better for this functionality exposed by the
153 // CallGraph.
154 static void buildCGN(CallGraph &CG, CallGraphNode *Node) {
155  Function *F = Node->getFunction();
156 
157  // Look for calls by this function.
158  for (Instruction &I : instructions(F))
159  if (CallSite CS = CallSite(cast<Value>(&I))) {
160  const Function *Callee = CS.getCalledFunction();
161  if (!Callee || !Intrinsic::isLeaf(Callee->getIntrinsicID()))
162  // Indirect calls of intrinsics are not allowed so no need to check.
163  // We can be more precise here by using TargetArg returned by
164  // Intrinsic::isLeaf.
165  Node->addCalledFunction(CS, CG.getCallsExternalNode());
166  else if (!Callee->isIntrinsic())
167  Node->addCalledFunction(CS, CG.getOrInsertFunction(Callee));
168  }
169 }
170 
171 // Rebuild CGN after we extracted parts of the code from ParentFunc into
172 // NewFuncs. Builds CGNs for the NewFuncs and adds them to the current SCC.
174  CallGraph &CG, CallGraphSCC &SCC) {
175  // Rebuild CGN from scratch for the ParentFunc
176  auto *ParentNode = CG[&ParentFunc];
177  ParentNode->removeAllCalledFunctions();
178  buildCGN(CG, ParentNode);
179 
180  SmallVector<CallGraphNode *, 8> Nodes(SCC.begin(), SCC.end());
181 
182  for (Function *F : NewFuncs) {
183  CallGraphNode *Callee = CG.getOrInsertFunction(F);
184  Nodes.push_back(Callee);
185  buildCGN(CG, Callee);
186  }
187 
188  SCC.initialize(Nodes);
189 }
190 
191 static void clear(coro::Shape &Shape) {
192  Shape.CoroBegin = nullptr;
193  Shape.CoroEnds.clear();
194  Shape.CoroSizes.clear();
195  Shape.CoroSuspends.clear();
196 
197  Shape.FrameTy = nullptr;
198  Shape.FramePtr = nullptr;
199  Shape.AllocaSpillBlock = nullptr;
200  Shape.ResumeSwitch = nullptr;
201  Shape.PromiseAlloca = nullptr;
202  Shape.HasFinalSuspend = false;
203 }
204 
206  CoroSuspendInst *SuspendInst) {
207  Module *M = SuspendInst->getModule();
208  auto *Fn = Intrinsic::getDeclaration(M, Intrinsic::coro_save);
209  auto *SaveInst =
210  cast<CoroSaveInst>(CallInst::Create(Fn, CoroBegin, "", SuspendInst));
211  assert(!SuspendInst->getCoroSave());
212  SuspendInst->setArgOperand(0, SaveInst);
213  return SaveInst;
214 }
215 
216 // Collect "interesting" coroutine intrinsics.
218  size_t FinalSuspendIndex = 0;
219  clear(*this);
221  for (Instruction &I : instructions(F)) {
222  if (auto II = dyn_cast<IntrinsicInst>(&I)) {
223  switch (II->getIntrinsicID()) {
224  default:
225  continue;
226  case Intrinsic::coro_size:
227  CoroSizes.push_back(cast<CoroSizeInst>(II));
228  break;
229  case Intrinsic::coro_frame:
230  CoroFrames.push_back(cast<CoroFrameInst>(II));
231  break;
232  case Intrinsic::coro_suspend:
233  CoroSuspends.push_back(cast<CoroSuspendInst>(II));
234  if (CoroSuspends.back()->isFinal()) {
235  if (HasFinalSuspend)
237  "Only one suspend point can be marked as final");
238  HasFinalSuspend = true;
239  FinalSuspendIndex = CoroSuspends.size() - 1;
240  }
241  break;
242  case Intrinsic::coro_begin: {
243  auto CB = cast<CoroBeginInst>(II);
244  if (CB->getId()->getInfo().isPreSplit()) {
245  if (CoroBegin)
247  "coroutine should have exactly one defining @llvm.coro.begin");
248  CB->addAttribute(AttributeSet::ReturnIndex, Attribute::NonNull);
250  CB->removeAttribute(AttributeSet::FunctionIndex,
251  Attribute::NoDuplicate);
252  CoroBegin = CB;
253  }
254  break;
255  }
256  case Intrinsic::coro_end:
257  CoroEnds.push_back(cast<CoroEndInst>(II));
258  if (CoroEnds.back()->isFallthrough()) {
259  // Make sure that the fallthrough coro.end is the first element in the
260  // CoroEnds vector.
261  if (CoroEnds.size() > 1) {
262  if (CoroEnds.front()->isFallthrough())
264  "Only one coro.end can be marked as fallthrough");
265  std::swap(CoroEnds.front(), CoroEnds.back());
266  }
267  }
268  break;
269  }
270  }
271  }
272 
273  // If for some reason, we were not able to find coro.begin, bailout.
274  if (!CoroBegin) {
275  // Replace coro.frame which are supposed to be lowered to the result of
276  // coro.begin with undef.
278  for (CoroFrameInst *CF : CoroFrames) {
279  CF->replaceAllUsesWith(Undef);
280  CF->eraseFromParent();
281  }
282 
283  // Replace all coro.suspend with undef and remove related coro.saves if
284  // present.
285  for (CoroSuspendInst *CS : CoroSuspends) {
286  CS->replaceAllUsesWith(UndefValue::get(CS->getType()));
287  CS->eraseFromParent();
288  if (auto *CoroSave = CS->getCoroSave())
289  CoroSave->eraseFromParent();
290  }
291 
292  // Replace all coro.ends with unreachable instruction.
293  for (CoroEndInst *CE : CoroEnds)
294  changeToUnreachable(CE, /*UseLLVMTrap=*/false);
295 
296  return;
297  }
298 
299  // The coro.free intrinsic is always lowered to the result of coro.begin.
300  for (CoroFrameInst *CF : CoroFrames) {
301  CF->replaceAllUsesWith(CoroBegin);
302  CF->eraseFromParent();
303  }
304 
305  // Canonicalize coro.suspend by inserting a coro.save if needed.
306  for (CoroSuspendInst *CS : CoroSuspends)
307  if (!CS->getCoroSave())
308  createCoroSave(CoroBegin, CS);
309 
310  // Move final suspend to be the last element in the CoroSuspends vector.
311  if (HasFinalSuspend &&
312  FinalSuspendIndex != CoroSuspends.size() - 1)
313  std::swap(CoroSuspends[FinalSuspendIndex], CoroSuspends.back());
314 }
Instruction * FramePtr
Definition: CoroInternal.h:83
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function. ...
Definition: Function.cpp:226
LLVMContext & Context
PassManagerBuilder - This class is used to set up a standard optimization sequence for languages like...
CoroBeginInst * CoroBegin
Definition: CoroInternal.h:68
This represents the llvm.coro.alloc instruction.
Definition: CoroInstr.h:79
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
void initializeCoroEarlyPass(PassRegistry &)
A Module instance is used to store all the information related to an LLVM module. ...
Definition: Module.h:52
void initializeCoroElidePass(PassRegistry &)
Pass * createCoroSplitPass()
Split up coroutines into multiple functions driving their state machines.
A global registry used in conjunction with static constructors to make pluggable components (like tar...
Definition: Registry.h:45
static void buildCGN(CallGraph &CG, CallGraphNode *Node)
Definition: Coroutines.cpp:154
Value * getFrame() const
Definition: CoroInstr.h:200
bool isIntrinsic() const
isIntrinsic - Returns true if the function's name starts with "llvm.".
Definition: Function.h:151
EP_ScalarOptimizerLate - This extension point allows adding optimization passes after most of the mai...
static void addCoroutineSCCPasses(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM)
Definition: Coroutines.cpp:50
virtual void add(Pass *P)=0
Add a pass to the queue of passes to run.
The two locations do not alias at all.
Definition: AliasAnalysis.h:79
Pass * createCoroEarlyPass()
Lower coroutine intrinsics that are not needed by later passes.
void initialize(ArrayRef< CallGraphNode * > NewNodes)
unsigned changeToUnreachable(Instruction *I, bool UseLLVMTrap, bool PreserveLCSSA=false)
Insert an unreachable instruction before the specified instruction, making it and the rest of the cod...
Definition: Local.cpp:1373
A node in the call graph for a module.
Definition: CallGraph.h:171
Function * getFunction() const
Returns the function that this call graph node represents.
Definition: CallGraph.h:191
static bool isCoroutineIntrinsicName(StringRef Name)
Definition: Coroutines.cpp:103
void addCalledFunction(CallSite CS, CallGraphNode *M)
Adds a function to the list of functions called by this one.
Definition: CallGraph.h:236
iterator end() const
This represents the llvm.coro.suspend instruction.
Definition: CoroInstr.h:263
void buildFrom(Function &F)
Definition: Coroutines.cpp:217
LLVM_NODISCARD bool empty() const
Definition: SmallVector.h:60
void updateCallGraph(Function &Caller, ArrayRef< Function * > Funcs, CallGraph &CG, CallGraphSCC &SCC)
Definition: Coroutines.cpp:173
Class to represent function types.
Definition: DerivedTypes.h:102
void initializeCoroSplitPass(PassRegistry &)
EP_EnabledOnOptLevel0 - This extension point allows adding passes that should not be disabled by O0 o...
#define F(x, y, z)
Definition: MD5.cpp:51
SmallVector< CoroSizeInst *, 2 > CoroSizes
Definition: CoroInternal.h:70
Function Alias Analysis false
static void addCoroutineOptimizerLastPasses(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM)
Definition: Coroutines.cpp:55
This class represents a no-op cast from one type to another.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory)...
Definition: APInt.h:33
Function * getDeclaration(Module *M, ID id, ArrayRef< Type * > Tys=None)
Create or insert an LLVM Function declaration for an intrinsic, and return it.
Definition: Function.cpp:949
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition: Value.cpp:401
CoroSaveInst * getCoroSave() const
Definition: CoroInstr.h:267
SmallVector< CoroSuspendInst *, 4 > CoroSuspends
Definition: CoroInternal.h:71
static void addCoroutineScalarOptimizerPasses(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM)
Definition: Coroutines.cpp:45
static ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
Definition: Constants.cpp:1323
bool isLeaf(ID id)
Returns true if the intrinsic is a leaf, i.e.
Definition: Function.cpp:932
The instances of the Type class are immutable: once they are created, they are never changed...
Definition: Type.h:45
Pass * createCoroCleanupPass()
Lower all remaining coroutine intrinsics.
Pass * createCoroElidePass()
Analyze coroutines use sites, devirtualize resume/destroy calls and elide heap allocation for corouti...
Definition: CoroElide.cpp:317
This represents the llvm.coro.end instruction.
Definition: CoroInstr.h:300
ModulePass * createBarrierNoopPass()
createBarrierNoopPass - This pass is purely a module pass barrier in a pass manager.
This represents the llvm.coro.save instruction.
Definition: CoroInstr.h:230
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
Definition: Constants.cpp:1337
LLVMContext & getContext() const
All values hold a context through their type.
Definition: Value.cpp:654
EP_OptimizerLast – This extension point allows adding passes that run after everything else...
static PointerType * getInt8PtrTy(LLVMContext &C, unsigned AS=0)
Definition: Type.cpp:213
EP_EarlyAsPossible - This extension point allows adding passes before any other transformations, allowing them to see the code as it is coming out of the frontend.
This represents the llvm.coro.free instruction.
Definition: CoroInstr.h:196
EP_CGSCCOptimizerLate - This extension point allows adding CallGraphSCC passes at the end of the main...
StructType * FrameTy
Definition: CoroInternal.h:82
static void addCoroutineOpt0Passes(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM)
Definition: Coroutines.cpp:31
PassManagerBase - An abstract interface to allow code to add passes to a pass manager without having ...
const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
Definition: Instruction.cpp:58
void initializeCoroutines(PassRegistry &)
Initialize all passes linked into the Coroutines library.
Definition: Coroutines.cpp:24
static CoroSaveInst * createCoroSave(CoroBeginInst *CoroBegin, CoroSuspendInst *SuspendInst)
Definition: Coroutines.cpp:205
static CallInst * Create(Value *Func, ArrayRef< Value * > Args, ArrayRef< OperandBundleDef > Bundles=None, const Twine &NameStr="", Instruction *InsertBefore=nullptr)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:843
A constant pointer value that points to null.
Definition: Constants.h:529
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:558
static void addCoroutineEarlyPasses(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM)
Definition: Coroutines.cpp:40
Intrinsic::ID getIntrinsicID() const LLVM_READONLY
getIntrinsicID - This method returns the ID number of the specified function, or Intrinsic::not_intri...
Definition: Function.h:146
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition: BitVector.h:586
This class represents the llvm.coro.begin instruction.
Definition: CoroInstr.h:212
Value * makeSubFnCall(Value *Arg, int Index, Instruction *InsertPt)
Definition: Coroutines.cpp:87
iterator begin() const
iterator_range< user_iterator > users()
Definition: Value.h:370
static void clear(coro::Shape &Shape)
Definition: Coroutines.cpp:191
void initializeCoroCleanupPass(PassRegistry &)
The basic data container for the call graph of a Module of IR.
Definition: CallGraph.h:76
SwitchInst * ResumeSwitch
Definition: CoroInternal.h:85
const NodeList & List
Definition: RDFGraph.cpp:205
#define I(x, y, z)
Definition: MD5.cpp:54
void setArgOperand(unsigned i, Value *v)
void replaceCoroFree(CoroIdInst *CoroId, bool Elide)
Definition: Coroutines.cpp:132
int lookupLLVMIntrinsicByName(ArrayRef< const char * > NameTable, StringRef Name)
Looks up Name in NameTable via binary search.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
SmallVector< CoroEndInst *, 4 > CoroEnds
Definition: CoroInternal.h:69
AllocaInst * PromiseAlloca
Definition: CoroInternal.h:86
This represents the llvm.coro.frame instruction.
Definition: CoroInstr.h:184
LLVM Value Representation.
Definition: Value.h:71
CallGraphSCC - This is a single SCC that a CallGraphSCCPass is run on.
CallGraphNode * getOrInsertFunction(const Function *F)
Similar to operator[], but this will insert a new CallGraphNode for F if one does not already exist...
Definition: CallGraph.cpp:165
void addCoroutinePassesToExtensionPoints(PassManagerBuilder &Builder)
Add all coroutine passes to appropriate extension points.
Definition: Coroutines.cpp:60
bool declaresIntrinsics(Module &M, std::initializer_list< StringRef >)
Definition: Coroutines.cpp:118
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:47
inst_range instructions(Function *F)
Definition: InstIterator.h:132
PassRegistry - This class manages the registration and intitialization of the pass subsystem as appli...
Definition: PassRegistry.h:40
BasicBlock * AllocaSpillBlock
Definition: CoroInternal.h:84
void addExtension(ExtensionPointTy Ty, ExtensionFn Fn)
static IntegerType * getInt8Ty(LLVMContext &C)
Definition: Type.cpp:167
GlobalValue * getNamedValue(StringRef Name) const
Return the global value in the module with the specified name, of arbitrary type. ...
Definition: Module.cpp:93
CallGraphNode * getCallsExternalNode() const
Definition: CallGraph.h:145