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
22namespace llvm {
23
24namespace coro {
25
26enum 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
43class BaseCloner {
44protected:
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.
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
75public:
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
81 virtual ~BaseCloner() {}
82
83 /// Create a clone for a continuation lowering.
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
97 Function *getFunction() const {
98 assert(NewF != nullptr && "declaration not yet set");
99 return NewF;
100 }
101
102 virtual void create();
103
104protected:
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
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 coro
152
153} // end namespace llvm
154
155#endif // LLVM_LIB_TRANSFORMS_COROUTINES_COROCLONER_H
156