19
19
// ===----------------------------------------------------------------------===//
20
20
21
21
#include " llvm/Transforms/Coroutines/CoroSplit.h"
22
+ #include " ABI.h"
22
23
#include " CoroInstr.h"
23
24
#include " CoroInternal.h"
25
+ #include " MaterializationUtils.h"
24
26
#include " llvm/ADT/DenseMap.h"
25
27
#include " llvm/ADT/PriorityWorklist.h"
26
28
#include " llvm/ADT/SmallPtrSet.h"
@@ -1779,9 +1781,9 @@ CallInst *coro::createMustTailCall(DebugLoc Loc, Function *MustTailCallFn,
1779
1781
return TailCall;
1780
1782
}
1781
1783
1782
- static void splitAsyncCoroutine (Function &F, coro::Shape &Shape,
1783
- SmallVectorImpl<Function *> &Clones,
1784
- TargetTransformInfo &TTI) {
1784
+ void coro::AsyncABI::splitCoroutine (Function &F, coro::Shape &Shape,
1785
+ SmallVectorImpl<Function *> &Clones,
1786
+ TargetTransformInfo &TTI) {
1785
1787
assert (Shape.ABI == coro::ABI::Async);
1786
1788
assert (Clones.empty ());
1787
1789
// Reset various things that the optimizer might have decided it
@@ -1874,9 +1876,9 @@ static void splitAsyncCoroutine(Function &F, coro::Shape &Shape,
1874
1876
}
1875
1877
}
1876
1878
1877
- static void splitRetconCoroutine (Function &F, coro::Shape &Shape,
1878
- SmallVectorImpl<Function *> &Clones,
1879
- TargetTransformInfo &TTI) {
1879
+ void coro::AnyRetconABI::splitCoroutine (Function &F, coro::Shape &Shape,
1880
+ SmallVectorImpl<Function *> &Clones,
1881
+ TargetTransformInfo &TTI) {
1880
1882
assert (Shape.ABI == coro::ABI::Retcon || Shape.ABI == coro::ABI::RetconOnce);
1881
1883
assert (Clones.empty ());
1882
1884
@@ -2044,26 +2046,27 @@ static bool hasSafeElideCaller(Function &F) {
2044
2046
return false ;
2045
2047
}
2046
2048
2047
- static coro::Shape
2048
- splitCoroutine (Function &F, SmallVectorImpl<Function *> &Clones,
2049
- TargetTransformInfo &TTI, bool OptimizeFrame,
2050
- std::function< bool (Instruction &)> MaterializableCallback) {
2051
- PrettyStackTraceFunction prettyStackTrace (F);
2049
+ void coro::SwitchABI::splitCoroutine (Function &F, coro:: Shape &Shape,
2050
+ SmallVectorImpl<Function *> &Clones,
2051
+ TargetTransformInfo &TTI) {
2052
+ SwitchCoroutineSplitter::split (F, Shape, Clones, TTI);
2053
+ }
2052
2054
2053
- // The suspend-crossing algorithm in buildCoroutineFrame get tripped
2054
- // up by uses in unreachable blocks, so remove them as a first pass.
2055
- removeUnreachableBlocks (F);
2055
+ static void doSplitCoroutine (Function &F, SmallVectorImpl<Function *> &Clones,
2056
+ coro::BaseABI &ABI, TargetTransformInfo &TTI) {
2057
+ PrettyStackTraceFunction prettyStackTrace (F);
2056
2058
2057
- coro::Shape Shape (F, OptimizeFrame);
2058
- if (!Shape.CoroBegin )
2059
- return Shape;
2059
+ auto &Shape = ABI.Shape ;
2060
+ assert (Shape.CoroBegin );
2060
2061
2061
2062
lowerAwaitSuspends (F, Shape);
2062
2063
2063
2064
simplifySuspendPoints (Shape);
2065
+
2064
2066
normalizeCoroutine (F, Shape, TTI);
2065
- buildCoroutineFrame (F, Shape, MaterializableCallback );
2067
+ ABI. buildCoroutineFrame ();
2066
2068
replaceFrameSizeAndAlignment (Shape);
2069
+
2067
2070
bool isNoSuspendCoroutine = Shape.CoroSuspends .empty ();
2068
2071
2069
2072
bool shouldCreateNoAllocVariant = !isNoSuspendCoroutine &&
@@ -2075,18 +2078,7 @@ splitCoroutine(Function &F, SmallVectorImpl<Function *> &Clones,
2075
2078
if (isNoSuspendCoroutine) {
2076
2079
handleNoSuspendCoroutine (Shape);
2077
2080
} else {
2078
- switch (Shape.ABI ) {
2079
- case coro::ABI::Switch:
2080
- SwitchCoroutineSplitter::split (F, Shape, Clones, TTI);
2081
- break ;
2082
- case coro::ABI::Async:
2083
- splitAsyncCoroutine (F, Shape, Clones, TTI);
2084
- break ;
2085
- case coro::ABI::Retcon:
2086
- case coro::ABI::RetconOnce:
2087
- splitRetconCoroutine (F, Shape, Clones, TTI);
2088
- break ;
2089
- }
2081
+ ABI.splitCoroutine (F, Shape, Clones, TTI);
2090
2082
}
2091
2083
2092
2084
// Replace all the swifterror operations in the original function.
@@ -2107,8 +2099,6 @@ splitCoroutine(Function &F, SmallVectorImpl<Function *> &Clones,
2107
2099
2108
2100
if (shouldCreateNoAllocVariant)
2109
2101
SwitchCoroutineSplitter::createNoAllocVariant (F, Shape, Clones);
2110
-
2111
- return Shape;
2112
2102
}
2113
2103
2114
2104
static LazyCallGraph::SCC &updateCallGraphAfterCoroutineSplit (
@@ -2207,8 +2197,44 @@ static void addPrepareFunction(const Module &M,
2207
2197
Fns.push_back (PrepareFn);
2208
2198
}
2209
2199
2200
+ static std::unique_ptr<coro::BaseABI>
2201
+ CreateNewABI (Function &F, coro::Shape &S,
2202
+ std::function<bool (Instruction &)> IsMatCallback) {
2203
+ switch (S.ABI ) {
2204
+ case coro::ABI::Switch:
2205
+ return std::unique_ptr<coro::BaseABI>(
2206
+ new coro::SwitchABI (F, S, IsMatCallback));
2207
+ case coro::ABI::Async:
2208
+ return std::unique_ptr<coro::BaseABI>(
2209
+ new coro::AsyncABI (F, S, IsMatCallback));
2210
+ case coro::ABI::Retcon:
2211
+ return std::unique_ptr<coro::BaseABI>(
2212
+ new coro::AnyRetconABI (F, S, IsMatCallback));
2213
+ case coro::ABI::RetconOnce:
2214
+ return std::unique_ptr<coro::BaseABI>(
2215
+ new coro::AnyRetconABI (F, S, IsMatCallback));
2216
+ }
2217
+ llvm_unreachable (" Unknown ABI" );
2218
+ }
2219
+
2210
2220
CoroSplitPass::CoroSplitPass (bool OptimizeFrame)
2211
- : MaterializableCallback(coro::defaultMaterializable),
2221
+ : CreateAndInitABI([](Function &F, coro::Shape &S) {
2222
+ std::unique_ptr<coro::BaseABI> ABI =
2223
+ CreateNewABI (F, S, coro::isTriviallyMaterializable);
2224
+ ABI->init ();
2225
+ return std::move (ABI);
2226
+ }),
2227
+ OptimizeFrame (OptimizeFrame) {}
2228
+
2229
+ // For back compatibility, constructor takes a materializable callback and
2230
+ // creates a generator for an ABI with a modified materializable callback.
2231
+ CoroSplitPass::CoroSplitPass (std::function<bool (Instruction &)> IsMatCallback,
2232
+ bool OptimizeFrame)
2233
+ : CreateAndInitABI([=](Function &F, coro::Shape &S) {
2234
+ std::unique_ptr<coro::BaseABI> ABI = CreateNewABI (F, S, IsMatCallback);
2235
+ ABI->init ();
2236
+ return std::move (ABI);
2237
+ }),
2212
2238
OptimizeFrame (OptimizeFrame) {}
2213
2239
2214
2240
PreservedAnalyses CoroSplitPass::run (LazyCallGraph::SCC &C,
@@ -2241,12 +2267,23 @@ PreservedAnalyses CoroSplitPass::run(LazyCallGraph::SCC &C,
2241
2267
Function &F = N->getFunction ();
2242
2268
LLVM_DEBUG (dbgs () << " CoroSplit: Processing coroutine '" << F.getName ()
2243
2269
<< " \n " );
2270
+
2271
+ // The suspend-crossing algorithm in buildCoroutineFrame gets tripped up
2272
+ // by unreachable blocks, so remove them as a first pass. Remove the
2273
+ // unreachable blocks before collecting intrinsics into Shape.
2274
+ removeUnreachableBlocks (F);
2275
+
2276
+ coro::Shape Shape (F, OptimizeFrame);
2277
+ if (!Shape.CoroBegin )
2278
+ continue ;
2279
+
2244
2280
F.setSplittedCoroutine ();
2245
2281
2282
+ std::unique_ptr<coro::BaseABI> ABI = CreateAndInitABI (F, Shape);
2283
+
2246
2284
SmallVector<Function *, 4 > Clones;
2247
- coro::Shape Shape =
2248
- splitCoroutine (F, Clones, FAM.getResult <TargetIRAnalysis>(F),
2249
- OptimizeFrame, MaterializableCallback);
2285
+ auto &TTI = FAM.getResult <TargetIRAnalysis>(F);
2286
+ doSplitCoroutine (F, Clones, *ABI, TTI);
2250
2287
CurrentSCC = &updateCallGraphAfterCoroutineSplit (
2251
2288
*N, Shape, Clones, *CurrentSCC, CG, AM, UR, FAM);
2252
2289
0 commit comments