1 //===- CoroSplit.cpp - Converts a coroutine into a state machine ----------===//
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 pass builds the coroutine frame and outlines resume and destroy parts
10 // of the coroutine into separate functions.
11 //
12 // We present a coroutine to an LLVM as an ordinary function with suspension
13 // points marked up with intrinsics. We let the optimizer party on the coroutine
14 // as a single function for as long as possible. Shortly before the coroutine is
15 // eligible to be inlined into its callers, we split up the coroutine into parts
16 // corresponding to an initial, resume and destroy invocations of the coroutine,
17 // add them to the current SCC and restart the IPO pipeline to optimize the
18 // coroutine subfunctions we extracted before proceeding to the caller of the
19 // coroutine.
20 //===----------------------------------------------------------------------===//
21 
22 #include "CoroInternal.h"
23 #include "llvm/Analysis/CallGraphSCCPass.h"
24 #include "llvm/IR/DebugInfoMetadata.h"
25 #include "llvm/IR/IRBuilder.h"
26 #include "llvm/IR/LegacyPassManager.h"
27 #include "llvm/IR/Verifier.h"
28 #include "llvm/Transforms/Scalar.h"
29 #include "llvm/Transforms/Utils/Cloning.h"
30 #include "llvm/Transforms/Utils/Local.h"
31 #include "llvm/Transforms/Utils/ValueMapper.h"
32 
33 using namespace llvm;
34 
35 #define DEBUG_TYPE "coro-split"
36 
37 // Create an entry block for a resume function with a switch that will jump to
38 // suspend points.
39 static BasicBlock *createResumeEntryBlock(Function &F, coro::Shape &Shape) {
40   LLVMContext &C = F.getContext();
41 
42   // resume.entry:
43   //  %index.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0,
44   //  i32 2
45   //  % index = load i32, i32* %index.addr
46   //  switch i32 %index, label %unreachable [
47   //    i32 0, label %resume.0
48   //    i32 1, label %resume.1
49   //    ...
50   //  ]
51 
52   auto *NewEntry = BasicBlock::Create(C, "resume.entry", &F);
53   auto *UnreachBB = BasicBlock::Create(C, "unreachable", &F);
54 
55   IRBuilder<> Builder(NewEntry);
56   auto *FramePtr = Shape.FramePtr;
57   auto *FrameTy = Shape.FrameTy;
58   auto *GepIndex = Builder.CreateConstInBoundsGEP2_32(
59       FrameTy, FramePtr, 0, coro::Shape::IndexField, "index.addr");
60   auto *Index = Builder.CreateLoad(GepIndex, "index");
61   auto *Switch =
62       Builder.CreateSwitch(Index, UnreachBB, Shape.CoroSuspends.size());
63   Shape.ResumeSwitch = Switch;
64 
65   size_t SuspendIndex = 0;
66   for (CoroSuspendInst *S : Shape.CoroSuspends) {
67     ConstantInt *IndexVal = Shape.getIndex(SuspendIndex);
68 
69     // Replace CoroSave with a store to Index:
70     //    %index.addr = getelementptr %f.frame... (index field number)
71     //    store i32 0, i32* %index.addr1
72     auto *Save = S->getCoroSave();
73     Builder.SetInsertPoint(Save);
74     if (S->isFinal()) {
75       // Final suspend point is represented by storing zero in ResumeFnAddr.
76       auto *GepIndex = Builder.CreateConstInBoundsGEP2_32(FrameTy, FramePtr, 0,
77                                                           0, "ResumeFn.addr");
78       auto *NullPtr = ConstantPointerNull::get(cast<PointerType>(
79           cast<PointerType>(GepIndex->getType())->getElementType()));
80       Builder.CreateStore(NullPtr, GepIndex);
81     } else {
82       auto *GepIndex = Builder.CreateConstInBoundsGEP2_32(
83           FrameTy, FramePtr, 0, coro::Shape::IndexField, "index.addr");
84       Builder.CreateStore(IndexVal, GepIndex);
85     }
86     Save->replaceAllUsesWith(ConstantTokenNone::get(C));
87     Save->eraseFromParent();
88 
89     // Split block before and after coro.suspend and add a jump from an entry
90     // switch:
91     //
92     //  whateverBB:
93     //    whatever
94     //    %0 = call i8 @llvm.coro.suspend(token none, i1 false)
95     //    switch i8 %0, label %suspend[i8 0, label %resume
96     //                                 i8 1, label %cleanup]
97     // becomes:
98     //
99     //  whateverBB:
100     //     whatever
101     //     br label %resume.0.landing
102     //
103     //  resume.0: ; <--- jump from the switch in the resume.entry
104     //     %0 = tail call i8 @llvm.coro.suspend(token none, i1 false)
105     //     br label %resume.0.landing
106     //
107     //  resume.0.landing:
108     //     %1 = phi i8[-1, %whateverBB], [%0, %resume.0]
109     //     switch i8 % 1, label %suspend [i8 0, label %resume
110     //                                    i8 1, label %cleanup]
111 
112     auto *SuspendBB = S->getParent();
113     auto *ResumeBB =
114         SuspendBB->splitBasicBlock(S, "resume." + Twine(SuspendIndex));
115     auto *LandingBB = ResumeBB->splitBasicBlock(
116         S->getNextNode(), ResumeBB->getName() + Twine(".landing"));
117     Switch->addCase(IndexVal, ResumeBB);
118 
119     cast<BranchInst>(SuspendBB->getTerminator())->setSuccessor(0, LandingBB);
120     auto *PN = PHINode::Create(Builder.getInt8Ty(), 2, "", &LandingBB->front());
121     S->replaceAllUsesWith(PN);
122     PN->addIncoming(Builder.getInt8(-1), SuspendBB);
123     PN->addIncoming(S, ResumeBB);
124 
125     ++SuspendIndex;
126   }
127 
128   Builder.SetInsertPoint(UnreachBB);
129   Builder.CreateUnreachable();
130 
131   return NewEntry;
132 }
133 
134 // In Resumers, we replace fallthrough coro.end with ret void and delete the
135 // rest of the block.
136 static void replaceFallthroughCoroEnd(IntrinsicInst *End,
137                                       ValueToValueMapTy &VMap) {
138   auto *NewE = cast<IntrinsicInst>(VMap[End]);
139   ReturnInst::Create(NewE->getContext(), nullptr, NewE);
140 
141   // Remove the rest of the block, by splitting it into an unreachable block.
142   auto *BB = NewE->getParent();
143   BB->splitBasicBlock(NewE);
144   BB->getTerminator()->eraseFromParent();
145 }
146 
147 // Rewrite final suspend point handling. We do not use suspend index to
148 // represent the final suspend point. Instead we zero-out ResumeFnAddr in the
149 // coroutine frame, since it is undefined behavior to resume a coroutine
150 // suspended at the final suspend point. Thus, in the resume function, we can
151 // simply remove the last case (when coro::Shape is built, the final suspend
152 // point (if present) is always the last element of CoroSuspends array).
153 // In the destroy function, we add a code sequence to check if ResumeFnAddress
154 // is Null, and if so, jump to the appropriate label to handle cleanup from the
155 // final suspend point.
156 static void handleFinalSuspend(IRBuilder<> &Builder, Value *FramePtr,
157                                coro::Shape &Shape, SwitchInst *Switch,
158                                bool IsDestroy) {
159   assert(Shape.HasFinalSuspend);
160   auto FinalCase = --Switch->case_end();
161   BasicBlock *ResumeBB = FinalCase.getCaseSuccessor();
162   Switch->removeCase(FinalCase);
163   if (IsDestroy) {
164     BasicBlock *OldSwitchBB = Switch->getParent();
165     auto *NewSwitchBB = OldSwitchBB->splitBasicBlock(Switch, "Switch");
166     Builder.SetInsertPoint(OldSwitchBB->getTerminator());
167     auto *GepIndex = Builder.CreateConstInBoundsGEP2_32(Shape.FrameTy, FramePtr,
168                                                         0, 0, "ResumeFn.addr");
169     auto *Load = Builder.CreateLoad(GepIndex);
170     auto *NullPtr =
171         ConstantPointerNull::get(cast<PointerType>(Load->getType()));
172     auto *Cond = Builder.CreateICmpEQ(Load, NullPtr);
173     Builder.CreateCondBr(Cond, ResumeBB, NewSwitchBB);
174     OldSwitchBB->getTerminator()->eraseFromParent();
175   }
176 }
177 
178 // Create a resume clone by cloning the body of the original function, setting
179 // new entry block and replacing coro.suspend an appropriate value to force
180 // resume or cleanup pass for every suspend point.
181 static Function *createClone(Function &F, Twine Suffix, coro::Shape &Shape,
182                              BasicBlock *ResumeEntry, int8_t FnIndex) {
183   Module *M = F.getParent();
184   auto *FrameTy = Shape.FrameTy;
185   auto *FnPtrTy = cast<PointerType>(FrameTy->getElementType(0));
186   auto *FnTy = cast<FunctionType>(FnPtrTy->getElementType());
187 
188   Function *NewF =
189       Function::Create(FnTy, GlobalValue::LinkageTypes::InternalLinkage,
190                        F.getName() + Suffix, M);
191   NewF->addAttribute(1, Attribute::NonNull);
192   NewF->addAttribute(1, Attribute::NoAlias);
193 
194   ValueToValueMapTy VMap;
195   // Replace all args with undefs. The buildCoroutineFrame algorithm already
196   // rewritten access to the args that occurs after suspend points with loads
197   // and stores to/from the coroutine frame.
198   for (Argument &A : F.getArgumentList())
199     VMap[&A] = UndefValue::get(A.getType());
200 
201   SmallVector<ReturnInst *, 4> Returns;
202 
203   CloneFunctionInto(NewF, &F, VMap, /*ModuleLevelChanges=*/true, Returns);
204 
205   // If we have debug info, update it. ModuleLevelChanges = true above, does
206   // the heavy lifting, we just need to repoint subprogram at the same
207   // DICompileUnit as the original function F.
208   if (DISubprogram *SP = F.getSubprogram())
209     NewF->getSubprogram()->replaceUnit(SP->getUnit());
210 
211   // Remove old returns.
212   for (ReturnInst *Return : Returns)
213     changeToUnreachable(Return, /*UseLLVMTrap=*/false);
214 
215   // Remove old return attributes.
216   NewF->removeAttributes(
217       AttributeSet::ReturnIndex,
218       AttributeSet::get(
219           NewF->getContext(), AttributeSet::ReturnIndex,
220           AttributeFuncs::typeIncompatible(NewF->getReturnType())));
221 
222   // Make AllocaSpillBlock the new entry block.
223   auto *SwitchBB = cast<BasicBlock>(VMap[ResumeEntry]);
224   auto *Entry = cast<BasicBlock>(VMap[Shape.AllocaSpillBlock]);
225   Entry->moveBefore(&NewF->getEntryBlock());
226   Entry->getTerminator()->eraseFromParent();
227   BranchInst::Create(SwitchBB, Entry);
228   Entry->setName("entry" + Suffix);
229 
230   // Clear all predecessors of the new entry block.
231   auto *Switch = cast<SwitchInst>(VMap[Shape.ResumeSwitch]);
232   Entry->replaceAllUsesWith(Switch->getDefaultDest());
233 
234   IRBuilder<> Builder(&NewF->getEntryBlock().front());
235 
236   // Remap frame pointer.
237   Argument *NewFramePtr = &NewF->getArgumentList().front();
238   Value *OldFramePtr = cast<Value>(VMap[Shape.FramePtr]);
239   NewFramePtr->takeName(OldFramePtr);
240   OldFramePtr->replaceAllUsesWith(NewFramePtr);
241 
242   // Remap vFrame pointer.
243   auto *NewVFrame = Builder.CreateBitCast(
244       NewFramePtr, Type::getInt8PtrTy(Builder.getContext()), "vFrame");
245   Value *OldVFrame = cast<Value>(VMap[Shape.CoroBegin]);
246   OldVFrame->replaceAllUsesWith(NewVFrame);
247 
248   // Rewrite final suspend handling as it is not done via switch (allows to
249   // remove final case from the switch, since it is undefined behavior to resume
250   // the coroutine suspended at the final suspend point.
251   if (Shape.HasFinalSuspend) {
252     auto *Switch = cast<SwitchInst>(VMap[Shape.ResumeSwitch]);
253     bool IsDestroy = FnIndex != 0;
254     handleFinalSuspend(Builder, NewFramePtr, Shape, Switch, IsDestroy);
255   }
256 
257   // Replace coro suspend with the appropriate resume index.
258   // Replacing coro.suspend with (0) will result in control flow proceeding to
259   // a resume label associated with a suspend point, replacing it with (1) will
260   // result in control flow proceeding to a cleanup label associated with this
261   // suspend point.
262   auto *NewValue = Builder.getInt8(FnIndex ? 1 : 0);
263   for (CoroSuspendInst *CS : Shape.CoroSuspends) {
264     auto *MappedCS = cast<CoroSuspendInst>(VMap[CS]);
265     MappedCS->replaceAllUsesWith(NewValue);
266     MappedCS->eraseFromParent();
267   }
268 
269   // Remove coro.end intrinsics.
270   replaceFallthroughCoroEnd(Shape.CoroEnds.front(), VMap);
271   // FIXME: coming in upcoming patches:
272   // replaceUnwindCoroEnds(Shape.CoroEnds, VMap);
273 
274   // We only store resume(0) and destroy(1) addresses in the coroutine frame.
275   // The cleanup(2) clone is only used during devirtualization when coroutine is
276   // eligible for heap elision and thus does not participate in indirect calls
277   // and does not need its address to be stored in the coroutine frame.
278   if (FnIndex < 2) {
279     // Store the address of this clone in the coroutine frame.
280     Builder.SetInsertPoint(Shape.FramePtr->getNextNode());
281     auto *G = Builder.CreateConstInBoundsGEP2_32(Shape.FrameTy, Shape.FramePtr,
282                                                  0, FnIndex, "fn.addr");
283     Builder.CreateStore(NewF, G);
284   }
285 
286   // Eliminate coro.free from the clones, replacing it with 'null' in cleanup,
287   // to suppress deallocation code.
288   coro::replaceCoroFree(cast<CoroIdInst>(VMap[Shape.CoroBegin->getId()]),
289                         /*Elide=*/FnIndex == 2);
290 
291   NewF->setCallingConv(CallingConv::Fast);
292 
293   return NewF;
294 }
295 
296 static void removeCoroEnds(coro::Shape &Shape) {
297   for (CoroEndInst *CE : Shape.CoroEnds)
298     CE->eraseFromParent();
299 }
300 
301 static void replaceFrameSize(coro::Shape &Shape) {
302   if (Shape.CoroSizes.empty())
303     return;
304 
305   // In the same function all coro.sizes should have the same result type.
306   auto *SizeIntrin = Shape.CoroSizes.back();
307   Module *M = SizeIntrin->getModule();
308   const DataLayout &DL = M->getDataLayout();
309   auto Size = DL.getTypeAllocSize(Shape.FrameTy);
310   auto *SizeConstant = ConstantInt::get(SizeIntrin->getType(), Size);
311 
312   for (CoroSizeInst *CS : Shape.CoroSizes) {
313     CS->replaceAllUsesWith(SizeConstant);
314     CS->eraseFromParent();
315   }
316 }
317 
318 // Create a global constant array containing pointers to functions provided and
319 // set Info parameter of CoroBegin to point at this constant. Example:
320 //
321 //   @f.resumers = internal constant [2 x void(%f.frame*)*]
322 //                    [void(%f.frame*)* @f.resume, void(%f.frame*)* @f.destroy]
323 //   define void @f() {
324 //     ...
325 //     call i8* @llvm.coro.begin(i8* null, i32 0, i8* null,
326 //                    i8* bitcast([2 x void(%f.frame*)*] * @f.resumers to i8*))
327 //
328 // Assumes that all the functions have the same signature.
329 static void setCoroInfo(Function &F, CoroBeginInst *CoroBegin,
330                         std::initializer_list<Function *> Fns) {
331 
332   SmallVector<Constant *, 4> Args(Fns.begin(), Fns.end());
333   assert(!Args.empty());
334   Function *Part = *Fns.begin();
335   Module *M = Part->getParent();
336   auto *ArrTy = ArrayType::get(Part->getType(), Args.size());
337 
338   auto *ConstVal = ConstantArray::get(ArrTy, Args);
339   auto *GV = new GlobalVariable(*M, ConstVal->getType(), /*isConstant=*/true,
340                                 GlobalVariable::PrivateLinkage, ConstVal,
341                                 F.getName() + Twine(".resumers"));
342 
343   // Update coro.begin instruction to refer to this constant.
344   LLVMContext &C = F.getContext();
345   auto *BC = ConstantExpr::getPointerCast(GV, Type::getInt8PtrTy(C));
346   CoroBegin->getId()->setInfo(BC);
347 }
348 
349 static void postSplitCleanup(Function &F) {
350   removeUnreachableBlocks(F);
351   llvm::legacy::FunctionPassManager FPM(F.getParent());
352 
353   FPM.add(createVerifierPass());
354   FPM.add(createSCCPPass());
355   FPM.add(createCFGSimplificationPass());
356   FPM.add(createEarlyCSEPass());
357   FPM.add(createCFGSimplificationPass());
358 
359   FPM.doInitialization();
360   FPM.run(F);
361   FPM.doFinalization();
362 }
363 
364 static void splitCoroutine(Function &F, CallGraph &CG, CallGraphSCC &SCC) {
365   coro::Shape Shape(F);
366   if (!Shape.CoroBegin)
367     return;
368 
369   buildCoroutineFrame(F, Shape);
370   replaceFrameSize(Shape);
371 
372   auto *ResumeEntry = createResumeEntryBlock(F, Shape);
373   auto ResumeClone = createClone(F, ".resume", Shape, ResumeEntry, 0);
374   auto DestroyClone = createClone(F, ".destroy", Shape, ResumeEntry, 1);
375   auto CleanupClone = createClone(F, ".cleanup", Shape, ResumeEntry, 2);
376 
377   // We no longer need coro.end in F.
378   removeCoroEnds(Shape);
379 
380   postSplitCleanup(F);
381   postSplitCleanup(*ResumeClone);
382   postSplitCleanup(*DestroyClone);
383   postSplitCleanup(*CleanupClone);
384 
385   setCoroInfo(F, Shape.CoroBegin, {ResumeClone, DestroyClone, CleanupClone});
386   coro::updateCallGraph(F, {ResumeClone, DestroyClone, CleanupClone}, CG, SCC);
387 }
388 
389 // When we see the coroutine the first time, we insert an indirect call to a
390 // devirt trigger function and mark the coroutine that it is now ready for
391 // split.
392 static void prepareForSplit(Function &F, CallGraph &CG) {
393   Module &M = *F.getParent();
394 #ifndef NDEBUG
395   Function *DevirtFn = M.getFunction(CORO_DEVIRT_TRIGGER_FN);
396   assert(DevirtFn && "coro.devirt.trigger function not found");
397 #endif
398 
399   F.addFnAttr(CORO_PRESPLIT_ATTR, PREPARED_FOR_SPLIT);
400 
401   // Insert an indirect call sequence that will be devirtualized by CoroElide
402   // pass:
403   //    %0 = call i8* @llvm.coro.subfn.addr(i8* null, i8 -1)
404   //    %1 = bitcast i8* %0 to void(i8*)*
405   //    call void %1(i8* null)
406   coro::LowererBase Lowerer(M);
407   Instruction *InsertPt = F.getEntryBlock().getTerminator();
408   auto *Null = ConstantPointerNull::get(Type::getInt8PtrTy(F.getContext()));
409   auto *DevirtFnAddr =
410       Lowerer.makeSubFnCall(Null, CoroSubFnInst::RestartTrigger, InsertPt);
411   auto *IndirectCall = CallInst::Create(DevirtFnAddr, Null, "", InsertPt);
412 
413   // Update CG graph with an indirect call we just added.
414   CG[&F]->addCalledFunction(IndirectCall, CG.getCallsExternalNode());
415 }
416 
417 // Make sure that there is a devirtualization trigger function that CoroSplit
418 // pass uses the force restart CGSCC pipeline. If devirt trigger function is not
419 // found, we will create one and add it to the current SCC.
420 static void createDevirtTriggerFunc(CallGraph &CG, CallGraphSCC &SCC) {
421   Module &M = CG.getModule();
422   if (M.getFunction(CORO_DEVIRT_TRIGGER_FN))
423     return;
424 
425   LLVMContext &C = M.getContext();
426   auto *FnTy = FunctionType::get(Type::getVoidTy(C), Type::getInt8PtrTy(C),
427                                  /*IsVarArgs=*/false);
428   Function *DevirtFn =
429       Function::Create(FnTy, GlobalValue::LinkageTypes::PrivateLinkage,
430                        CORO_DEVIRT_TRIGGER_FN, &M);
431   DevirtFn->addFnAttr(Attribute::AlwaysInline);
432   auto *Entry = BasicBlock::Create(C, "entry", DevirtFn);
433   ReturnInst::Create(C, Entry);
434 
435   auto *Node = CG.getOrInsertFunction(DevirtFn);
436 
437   SmallVector<CallGraphNode *, 8> Nodes(SCC.begin(), SCC.end());
438   Nodes.push_back(Node);
439   SCC.initialize(Nodes);
440 }
441 
442 //===----------------------------------------------------------------------===//
443 //                              Top Level Driver
444 //===----------------------------------------------------------------------===//
445 
446 namespace {
447 
448 struct CoroSplit : public CallGraphSCCPass {
449   static char ID; // Pass identification, replacement for typeid
450   CoroSplit() : CallGraphSCCPass(ID) {}
451 
452   bool Run = false;
453 
454   // A coroutine is identified by the presence of coro.begin intrinsic, if
455   // we don't have any, this pass has nothing to do.
456   bool doInitialization(CallGraph &CG) override {
457     Run = coro::declaresIntrinsics(CG.getModule(), {"llvm.coro.begin"});
458     return CallGraphSCCPass::doInitialization(CG);
459   }
460 
461   bool runOnSCC(CallGraphSCC &SCC) override {
462     if (!Run)
463       return false;
464 
465     // Find coroutines for processing.
466     SmallVector<Function *, 4> Coroutines;
467     for (CallGraphNode *CGN : SCC)
468       if (auto *F = CGN->getFunction())
469         if (F->hasFnAttribute(CORO_PRESPLIT_ATTR))
470           Coroutines.push_back(F);
471 
472     if (Coroutines.empty())
473       return false;
474 
475     CallGraph &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph();
476     createDevirtTriggerFunc(CG, SCC);
477 
478     for (Function *F : Coroutines) {
479       Attribute Attr = F->getFnAttribute(CORO_PRESPLIT_ATTR);
480       StringRef Value = Attr.getValueAsString();
481       DEBUG(dbgs() << "CoroSplit: Processing coroutine '" << F->getName()
482                    << "' state: " << Value << "\n");
483       if (Value == UNPREPARED_FOR_SPLIT) {
484         prepareForSplit(*F, CG);
485         continue;
486       }
487       F->removeFnAttr(CORO_PRESPLIT_ATTR);
488       splitCoroutine(*F, CG, SCC);
489     }
490     return true;
491   }
492 
493   void getAnalysisUsage(AnalysisUsage &AU) const override {
494     CallGraphSCCPass::getAnalysisUsage(AU);
495   }
496 };
497 }
498 
499 char CoroSplit::ID = 0;
500 INITIALIZE_PASS(
501     CoroSplit, "coro-split",
502     "Split coroutine into a set of functions driving its state machine", false,
503     false)
504 
505 Pass *llvm::createCoroSplitPass() { return new CoroSplit(); }
506