154 lines · c
1//===----------------------------------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8// Helper class for splitting a coroutine into separate functions. For example9// the returned-continuation coroutine is split into separate continuation10// functions.11//===----------------------------------------------------------------------===//12 13#ifndef LLVM_LIB_TRANSFORMS_COROUTINES_COROCLONER_H14#define LLVM_LIB_TRANSFORMS_COROUTINES_COROCLONER_H15 16#include "llvm/IR/Function.h"17#include "llvm/IR/IRBuilder.h"18#include "llvm/Support/TimeProfiler.h"19#include "llvm/Transforms/Coroutines/ABI.h"20#include "llvm/Transforms/Coroutines/CoroInstr.h"21#include "llvm/Transforms/Utils/ValueMapper.h"22 23namespace llvm::coro {24 25enum class CloneKind {26 /// The shared resume function for a switch lowering.27 SwitchResume,28 29 /// The shared unwind function for a switch lowering.30 SwitchUnwind,31 32 /// The shared cleanup function for a switch lowering.33 SwitchCleanup,34 35 /// An individual continuation function.36 Continuation,37 38 /// An async resume function.39 Async,40};41 42class BaseCloner {43protected:44 Function &OrigF;45 const Twine &Suffix;46 coro::Shape &Shape;47 CloneKind FKind;48 IRBuilder<> Builder;49 TargetTransformInfo &TTI;50 51 ValueToValueMapTy VMap;52 Function *NewF = nullptr;53 Value *NewFramePtr = nullptr;54 55 /// The active suspend instruction; meaningful only for continuation and async56 /// ABIs.57 AnyCoroSuspendInst *ActiveSuspend = nullptr;58 59 /// Create a cloner for a continuation lowering.60 BaseCloner(Function &OrigF, const Twine &Suffix, coro::Shape &Shape,61 Function *NewF, AnyCoroSuspendInst *ActiveSuspend,62 TargetTransformInfo &TTI)63 : OrigF(OrigF), Suffix(Suffix), Shape(Shape),64 FKind(Shape.ABI == ABI::Async ? CloneKind::Async65 : CloneKind::Continuation),66 Builder(OrigF.getContext()), TTI(TTI), NewF(NewF),67 ActiveSuspend(ActiveSuspend) {68 assert(Shape.ABI == ABI::Retcon || Shape.ABI == ABI::RetconOnce ||69 Shape.ABI == ABI::Async);70 assert(NewF && "need existing function for continuation");71 assert(ActiveSuspend && "need active suspend point for continuation");72 }73 74public:75 BaseCloner(Function &OrigF, const Twine &Suffix, coro::Shape &Shape,76 CloneKind FKind, TargetTransformInfo &TTI)77 : OrigF(OrigF), Suffix(Suffix), Shape(Shape), FKind(FKind),78 Builder(OrigF.getContext()), TTI(TTI) {}79 80 virtual ~BaseCloner() = default;81 82 /// Create a clone for a continuation lowering.83 static Function *createClone(Function &OrigF, const Twine &Suffix,84 coro::Shape &Shape, Function *NewF,85 AnyCoroSuspendInst *ActiveSuspend,86 TargetTransformInfo &TTI) {87 assert(Shape.ABI == ABI::Retcon || Shape.ABI == ABI::RetconOnce ||88 Shape.ABI == ABI::Async);89 TimeTraceScope FunctionScope("BaseCloner");90 91 BaseCloner Cloner(OrigF, Suffix, Shape, NewF, ActiveSuspend, TTI);92 Cloner.create();93 return Cloner.getFunction();94 }95 96 Function *getFunction() const {97 assert(NewF != nullptr && "declaration not yet set");98 return NewF;99 }100 101 virtual void create();102 103protected:104 bool isSwitchDestroyFunction() {105 switch (FKind) {106 case CloneKind::Async:107 case CloneKind::Continuation:108 case CloneKind::SwitchResume:109 return false;110 case CloneKind::SwitchUnwind:111 case CloneKind::SwitchCleanup:112 return true;113 }114 llvm_unreachable("Unknown ClonerKind enum");115 }116 117 void replaceEntryBlock();118 Value *deriveNewFramePointer();119 void replaceRetconOrAsyncSuspendUses();120 void replaceCoroSuspends();121 void replaceCoroEnds();122 void replaceCoroIsInRamp();123 void replaceSwiftErrorOps();124 void salvageDebugInfo();125 void handleFinalSuspend();126};127 128class SwitchCloner : public BaseCloner {129protected:130 /// Create a cloner for a switch lowering.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 137public:138 /// Create a clone for a switch lowering.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 llvm::coro152 153#endif // LLVM_LIB_TRANSFORMS_COROUTINES_COROCLONER_H154