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-exception
6//
7//===----------------------------------------------------------------------===//
8// Helper class for splitting a coroutine into separate functions. For example
9// the returned-continuation coroutine is split into separate continuation
10// functions.
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_LIB_TRANSFORMS_COROUTINES_COROCLONER_H
14#define LLVM_LIB_TRANSFORMS_COROUTINES_COROCLONER_H
15
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 async
56 /// 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::Async
65 : 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::coro
152
153#endif // LLVM_LIB_TRANSFORMS_COROUTINES_COROCLONER_H
154