From 627cfd4394b0c4677c8a33338d92bd92101b8ee1 Mon Sep 17 00:00:00 2001 From: Arnold Schwaighofer Date: Fri, 12 Feb 2021 10:27:31 -0800 Subject: [PATCH] [coro async] Don't promote allocas to the frame or rewrite swifterror if there are no suspend points Also don't call function to update the call graph if there are no clones. The function will fail. rdar://74277860 Differential Revision: https://reviews.llvm.org/D96620 --- llvm/lib/Transforms/Coroutines/CoroFrame.cpp | 7 ++- llvm/lib/Transforms/Coroutines/CoroSplit.cpp | 5 +- llvm/test/Transforms/Coroutines/coro-async.ll | 54 +++++++++++++++++++ 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp index 7ef69c4a99853..b3279bb5dc711 100644 --- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp @@ -2219,7 +2219,9 @@ void coro::salvageDebugInfo( } void coro::buildCoroutineFrame(Function &F, Shape &Shape) { - eliminateSwiftError(F, Shape); + // Don't eliminate swifterror in async functions that won't be split. + if (Shape.ABI != coro::ABI::Async || !Shape.CoroSuspends.empty()) + eliminateSwiftError(F, Shape); if (Shape.ABI == coro::ABI::Switch && Shape.SwitchLowering.PromiseAlloca) { @@ -2290,7 +2292,8 @@ void coro::buildCoroutineFrame(Function &F, Shape &Shape) { } sinkLifetimeStartMarkers(F, Shape, Checker); - collectFrameAllocas(F, Shape, Checker, FrameData.Allocas); + if (Shape.ABI != coro::ABI::Async || !Shape.CoroSuspends.empty()) + collectFrameAllocas(F, Shape, Checker, FrameData.Allocas); LLVM_DEBUG(dumpAllocas(FrameData.Allocas)); // Collect the spills for arguments and other not-materializable values. diff --git a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp index 04f426db84213..52c06e87c9ff2 100644 --- a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp @@ -584,6 +584,8 @@ void CoroCloner::replaceCoroEnds() { static void replaceSwiftErrorOps(Function &F, coro::Shape &Shape, ValueToValueMapTy *VMap) { + if (Shape.ABI == coro::ABI::Async && Shape.CoroSuspends.empty()) + return; Value *CachedSlot = nullptr; auto getSwiftErrorSlot = [&](Type *ValueTy) -> Value * { if (CachedSlot) { @@ -1811,7 +1813,8 @@ static void updateCallGraphAfterCoroutineSplit( case coro::ABI::RetconOnce: // Each clone in the Async/Retcon lowering references of the other clones. // Let the LazyCallGraph know about all of them at once. - CG.addSplitRefRecursiveFunctions(N.getFunction(), Clones); + if (!Clones.empty()) + CG.addSplitRefRecursiveFunctions(N.getFunction(), Clones); break; } diff --git a/llvm/test/Transforms/Coroutines/coro-async.ll b/llvm/test/Transforms/Coroutines/coro-async.ll index 6114d742575a9..aa834052d1ac6 100644 --- a/llvm/test/Transforms/Coroutines/coro-async.ll +++ b/llvm/test/Transforms/Coroutines/coro-async.ll @@ -445,6 +445,60 @@ entry: ; CHECK: bitcast i8* %3 to %async.task* ; CHECK: } +@no_coro_suspend_fp = constant <{ i32, i32 }> + <{ i32 trunc ( ; Relative pointer to async function + i64 sub ( + i64 ptrtoint (void (i8*)* @no_coro_suspend to i64), + i64 ptrtoint (i32* getelementptr inbounds (<{ i32, i32 }>, <{ i32, i32 }>* @no_coro_suspend_fp, i32 0, i32 1) to i64) + ) + to i32), + i32 128 ; Initial async context size without space for frame +}> + +define swiftcc void @no_coro_suspend(i8* %async.ctx) { +entry: + %some_alloca = alloca i64 + %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 0, + i8* bitcast (<{i32, i32}>* @no_coro_suspend_fp to i8*)) + %hdl = call i8* @llvm.coro.begin(token %id, i8* null) + call void @some_may_write(i64* %some_alloca) + call i1 (i8*, i1, ...) @llvm.coro.end.async(i8* %hdl, i1 0) + unreachable +} + +; CHECK-LABEL: define swiftcc void @no_coro_suspend +; CHECK: [[ALLOCA:%.*]] = alloca i64 +; CHECK: call void @some_may_write(i64* {{.*}}[[ALLOCA]]) + +@no_coro_suspend_swifterror_fp = constant <{ i32, i32 }> + <{ i32 trunc ( ; Relative pointer to async function + i64 sub ( + i64 ptrtoint (void (i8*)* @no_coro_suspend_swifterror to i64), + i64 ptrtoint (i32* getelementptr inbounds (<{ i32, i32 }>, <{ i32, i32 }>* @no_coro_suspend_swifterror_fp, i32 0, i32 1) to i64) + ) + to i32), + i32 128 ; Initial async context size without space for frame +}> + +declare void @do_with_swifterror(i64** swifterror) + +define swiftcc void @no_coro_suspend_swifterror(i8* %async.ctx) { +entry: + %some_alloca = alloca swifterror i64* + %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 0, + i8* bitcast (<{i32, i32}>* @no_coro_suspend_swifterror_fp to i8*)) + %hdl = call i8* @llvm.coro.begin(token %id, i8* null) + store i64* null, i64** %some_alloca, align 8 + call void @do_with_swifterror(i64** swifterror %some_alloca) + call i1 (i8*, i1, ...) @llvm.coro.end.async(i8* %hdl, i1 0) + unreachable +} + + ; CHECK-LABEL: define swiftcc void @no_coro_suspend_swifterror + ; CHECK: [[ALLOCA:%.*]] = alloca swifterror i64* + ; CHECK: store i64* null, i64** [[ALLOCA]] + ; CHECK: call void @do_with_swifterror(i64** {{.*}}swifterror{{.*}} [[ALLOCA]]) + declare { i8*, i8*, i8*, i8* } @llvm.coro.suspend.async.sl_p0i8p0i8p0i8p0i8s(i8*, i8*, ...) declare i8* @llvm.coro.prepare.async(i8*) declare token @llvm.coro.id.async(i32, i32, i32, i8*)