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. |
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: |
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 | |
104 | protected: |
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. |
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. |
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 | |