1 // 2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 3 // See https://llvm.org/LICENSE.txt for license information. 4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 5 // 6 //===----------------------------------------------------------------------===// 7 // Helper class for splitting a coroutine into separate functions. For example 8 // the returned-continuation coroutine is split into separate continuation 9 // functions. 10 //===----------------------------------------------------------------------===// 11 12 #ifndef LLVM_LIB_TRANSFORMS_COROUTINES_COROCLONER_H 13 #define LLVM_LIB_TRANSFORMS_COROUTINES_COROCLONER_H 14 15 #include "llvm/IR/Function.h" 16 #include "llvm/IR/IRBuilder.h" 17 #include "llvm/Support/TimeProfiler.h" 18 #include "llvm/Transforms/Coroutines/ABI.h" 19 #include "llvm/Transforms/Coroutines/CoroInstr.h" 20 #include "llvm/Transforms/Utils/ValueMapper.h" 21 22 namespace llvm { 23 24 namespace coro { 25 26 enum class CloneKind { 27 /// The shared resume function for a switch lowering. 28 SwitchResume, 29 30 /// The shared unwind function for a switch lowering. 31 SwitchUnwind, 32 33 /// The shared cleanup function for a switch lowering. 34 SwitchCleanup, 35 36 /// An individual continuation function. 37 Continuation, 38 39 /// An async resume function. 40 Async, 41 }; 42 43 class BaseCloner { 44 protected: 45 Function &OrigF; 46 const Twine &Suffix; 47 coro::Shape &Shape; 48 CloneKind FKind; 49 IRBuilder<> Builder; 50 TargetTransformInfo &TTI; 51 52 ValueToValueMapTy VMap; 53 Function *NewF = nullptr; 54 Value *NewFramePtr = nullptr; 55 56 /// The active suspend instruction; meaningful only for continuation and async 57 /// ABIs. 58 AnyCoroSuspendInst *ActiveSuspend = nullptr; 59 60 /// Create a cloner for a continuation lowering. BaseCloner(Function & OrigF,const Twine & Suffix,coro::Shape & Shape,Function * NewF,AnyCoroSuspendInst * ActiveSuspend,TargetTransformInfo & TTI)61 BaseCloner(Function &OrigF, const Twine &Suffix, coro::Shape &Shape, 62 Function *NewF, AnyCoroSuspendInst *ActiveSuspend, 63 TargetTransformInfo &TTI) 64 : OrigF(OrigF), Suffix(Suffix), Shape(Shape), 65 FKind(Shape.ABI == ABI::Async ? CloneKind::Async 66 : CloneKind::Continuation), 67 Builder(OrigF.getContext()), TTI(TTI), NewF(NewF), 68 ActiveSuspend(ActiveSuspend) { 69 assert(Shape.ABI == ABI::Retcon || Shape.ABI == ABI::RetconOnce || 70 Shape.ABI == ABI::Async); 71 assert(NewF && "need existing function for continuation"); 72 assert(ActiveSuspend && "need active suspend point for continuation"); 73 } 74 75 public: BaseCloner(Function & OrigF,const Twine & Suffix,coro::Shape & Shape,CloneKind FKind,TargetTransformInfo & TTI)76 BaseCloner(Function &OrigF, const Twine &Suffix, coro::Shape &Shape, 77 CloneKind FKind, TargetTransformInfo &TTI) 78 : OrigF(OrigF), Suffix(Suffix), Shape(Shape), FKind(FKind), 79 Builder(OrigF.getContext()), TTI(TTI) {} 80 ~BaseCloner()81 virtual ~BaseCloner() {} 82 83 /// Create a clone for a continuation lowering. createClone(Function & OrigF,const Twine & Suffix,coro::Shape & Shape,Function * NewF,AnyCoroSuspendInst * ActiveSuspend,TargetTransformInfo & TTI)84 static Function *createClone(Function &OrigF, const Twine &Suffix, 85 coro::Shape &Shape, Function *NewF, 86 AnyCoroSuspendInst *ActiveSuspend, 87 TargetTransformInfo &TTI) { 88 assert(Shape.ABI == ABI::Retcon || Shape.ABI == ABI::RetconOnce || 89 Shape.ABI == ABI::Async); 90 TimeTraceScope FunctionScope("BaseCloner"); 91 92 BaseCloner Cloner(OrigF, Suffix, Shape, NewF, ActiveSuspend, TTI); 93 Cloner.create(); 94 return Cloner.getFunction(); 95 } 96 getFunction()97 Function *getFunction() const { 98 assert(NewF != nullptr && "declaration not yet set"); 99 return NewF; 100 } 101 102 virtual void create(); 103 104 protected: isSwitchDestroyFunction()105 bool isSwitchDestroyFunction() { 106 switch (FKind) { 107 case CloneKind::Async: 108 case CloneKind::Continuation: 109 case CloneKind::SwitchResume: 110 return false; 111 case CloneKind::SwitchUnwind: 112 case CloneKind::SwitchCleanup: 113 return true; 114 } 115 llvm_unreachable("Unknown ClonerKind enum"); 116 } 117 118 void replaceEntryBlock(); 119 Value *deriveNewFramePointer(); 120 void replaceRetconOrAsyncSuspendUses(); 121 void replaceCoroSuspends(); 122 void replaceCoroEnds(); 123 void replaceSwiftErrorOps(); 124 void salvageDebugInfo(); 125 void handleFinalSuspend(); 126 }; 127 128 class SwitchCloner : public BaseCloner { 129 protected: 130 /// Create a cloner for a switch lowering. SwitchCloner(Function & OrigF,const Twine & Suffix,coro::Shape & Shape,CloneKind FKind,TargetTransformInfo & TTI)131 SwitchCloner(Function &OrigF, const Twine &Suffix, coro::Shape &Shape, 132 CloneKind FKind, TargetTransformInfo &TTI) 133 : BaseCloner(OrigF, Suffix, Shape, FKind, TTI) {} 134 135 void create() override; 136 137 public: 138 /// Create a clone for a switch lowering. createClone(Function & OrigF,const Twine & Suffix,coro::Shape & Shape,CloneKind FKind,TargetTransformInfo & TTI)139 static Function *createClone(Function &OrigF, const Twine &Suffix, 140 coro::Shape &Shape, CloneKind FKind, 141 TargetTransformInfo &TTI) { 142 assert(Shape.ABI == ABI::Switch); 143 TimeTraceScope FunctionScope("SwitchCloner"); 144 145 SwitchCloner Cloner(OrigF, Suffix, Shape, FKind, TTI); 146 Cloner.create(); 147 return Cloner.getFunction(); 148 } 149 }; 150 151 } // end namespace coro 152 153 } // end namespace llvm 154 155 #endif // LLVM_LIB_TRANSFORMS_COROUTINES_COROCLONER_H 156