-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[Coroutines] Respect noinline attributes when eliding heap allocation #115384
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Coroutines] Respect noinline attributes when eliding heap allocation #115384
Conversation
@llvm/pr-subscribers-coroutines Author: Yuxuan Chen (yuxuanchen1997) ChangesBecause the latest coroutine heap elision no longer depend on inlining. We can occasionally elide coroutines that are marked Full diff: https://github.com/llvm/llvm-project/pull/115384.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
index efd622123bccde..25a962ddf1b0da 100644
--- a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
@@ -2088,9 +2088,9 @@ static void doSplitCoroutine(Function &F, SmallVectorImpl<Function *> &Clones,
bool isNoSuspendCoroutine = Shape.CoroSuspends.empty();
- bool shouldCreateNoAllocVariant = !isNoSuspendCoroutine &&
- Shape.ABI == coro::ABI::Switch &&
- hasSafeElideCaller(F);
+ bool shouldCreateNoAllocVariant =
+ !isNoSuspendCoroutine && Shape.ABI == coro::ABI::Switch &&
+ hasSafeElideCaller(F) && !F.hasFnAttribute(llvm::Attribute::NoInline);
// If there are no suspend points, no split required, just remove
// the allocation and deallocation blocks, they are not needed.
diff --git a/llvm/test/Transforms/Coroutines/coro-split-noinline.ll b/llvm/test/Transforms/Coroutines/coro-split-noinline.ll
new file mode 100644
index 00000000000000..c53771570a0795
--- /dev/null
+++ b/llvm/test/Transforms/Coroutines/coro-split-noinline.ll
@@ -0,0 +1,62 @@
+; Tests that coro-split does not generate noinline variant for noinline functions
+; RUN: opt < %s -passes='cgscc(coro-split),simplifycfg,early-cse' -S | FileCheck %s
+
+; CHECK-LABEL: @cannotinline()
+define ptr @cannotinline() presplitcoroutine noinline {
+entry:
+ %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)
+ %need.alloc = call i1 @llvm.coro.alloc(token %id)
+ br i1 %need.alloc, label %dyn.alloc, label %begin
+
+dyn.alloc:
+ %size = call i32 @llvm.coro.size.i32()
+ %alloc = call ptr @malloc(i32 %size)
+ br label %begin
+
+begin:
+ %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]
+ %hdl = call ptr @llvm.coro.begin(token %id, ptr %phi)
+ call void @print(i32 0)
+ %0 = call i8 @llvm.coro.suspend(token none, i1 false)
+ switch i8 %0, label %suspend [i8 0, label %resume
+ i8 1, label %cleanup]
+resume:
+ call void @print(i32 1)
+ br label %cleanup
+
+cleanup:
+ %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)
+ call void @free(ptr %mem)
+ br label %suspend
+suspend:
+ call i1 @llvm.coro.end(ptr %hdl, i1 0, token none)
+ ret ptr %hdl
+}
+
+; CHECK-NOT-LABEL: @cannotinline.noalloc()
+
+
+; Make a safe_elide call to cannotinline
+define void @caller() presplitcoroutine {
+entry:
+ %ptr = call ptr @cannotinline() #1
+ ret void
+}
+
+
+declare ptr @llvm.coro.free(token, ptr)
+declare i32 @llvm.coro.size.i32()
+declare i8 @llvm.coro.suspend(token, i1)
+declare void @llvm.coro.resume(ptr)
+declare void @llvm.coro.destroy(ptr)
+
+declare token @llvm.coro.id(i32, ptr, ptr, ptr)
+declare i1 @llvm.coro.alloc(token)
+declare ptr @llvm.coro.begin(token, ptr)
+declare i1 @llvm.coro.end(ptr, i1, token)
+
+declare noalias ptr @malloc(i32) allockind("alloc,uninitialized") "alloc-family"="malloc"
+declare void @print(i32)
+declare void @free(ptr) willreturn allockind("free") "alloc-family"="malloc"
+
+attributes #1 = { coro_elide_safe }
|
@llvm/pr-subscribers-llvm-transforms Author: Yuxuan Chen (yuxuanchen1997) ChangesBecause the latest coroutine heap elision no longer depend on inlining. We can occasionally elide coroutines that are marked Full diff: https://github.com/llvm/llvm-project/pull/115384.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
index efd622123bccde..25a962ddf1b0da 100644
--- a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
@@ -2088,9 +2088,9 @@ static void doSplitCoroutine(Function &F, SmallVectorImpl<Function *> &Clones,
bool isNoSuspendCoroutine = Shape.CoroSuspends.empty();
- bool shouldCreateNoAllocVariant = !isNoSuspendCoroutine &&
- Shape.ABI == coro::ABI::Switch &&
- hasSafeElideCaller(F);
+ bool shouldCreateNoAllocVariant =
+ !isNoSuspendCoroutine && Shape.ABI == coro::ABI::Switch &&
+ hasSafeElideCaller(F) && !F.hasFnAttribute(llvm::Attribute::NoInline);
// If there are no suspend points, no split required, just remove
// the allocation and deallocation blocks, they are not needed.
diff --git a/llvm/test/Transforms/Coroutines/coro-split-noinline.ll b/llvm/test/Transforms/Coroutines/coro-split-noinline.ll
new file mode 100644
index 00000000000000..c53771570a0795
--- /dev/null
+++ b/llvm/test/Transforms/Coroutines/coro-split-noinline.ll
@@ -0,0 +1,62 @@
+; Tests that coro-split does not generate noinline variant for noinline functions
+; RUN: opt < %s -passes='cgscc(coro-split),simplifycfg,early-cse' -S | FileCheck %s
+
+; CHECK-LABEL: @cannotinline()
+define ptr @cannotinline() presplitcoroutine noinline {
+entry:
+ %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)
+ %need.alloc = call i1 @llvm.coro.alloc(token %id)
+ br i1 %need.alloc, label %dyn.alloc, label %begin
+
+dyn.alloc:
+ %size = call i32 @llvm.coro.size.i32()
+ %alloc = call ptr @malloc(i32 %size)
+ br label %begin
+
+begin:
+ %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]
+ %hdl = call ptr @llvm.coro.begin(token %id, ptr %phi)
+ call void @print(i32 0)
+ %0 = call i8 @llvm.coro.suspend(token none, i1 false)
+ switch i8 %0, label %suspend [i8 0, label %resume
+ i8 1, label %cleanup]
+resume:
+ call void @print(i32 1)
+ br label %cleanup
+
+cleanup:
+ %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)
+ call void @free(ptr %mem)
+ br label %suspend
+suspend:
+ call i1 @llvm.coro.end(ptr %hdl, i1 0, token none)
+ ret ptr %hdl
+}
+
+; CHECK-NOT-LABEL: @cannotinline.noalloc()
+
+
+; Make a safe_elide call to cannotinline
+define void @caller() presplitcoroutine {
+entry:
+ %ptr = call ptr @cannotinline() #1
+ ret void
+}
+
+
+declare ptr @llvm.coro.free(token, ptr)
+declare i32 @llvm.coro.size.i32()
+declare i8 @llvm.coro.suspend(token, i1)
+declare void @llvm.coro.resume(ptr)
+declare void @llvm.coro.destroy(ptr)
+
+declare token @llvm.coro.id(i32, ptr, ptr, ptr)
+declare i1 @llvm.coro.alloc(token)
+declare ptr @llvm.coro.begin(token, ptr)
+declare i1 @llvm.coro.end(ptr, i1, token)
+
+declare noalias ptr @malloc(i32) allockind("alloc,uninitialized") "alloc-family"="malloc"
+declare void @print(i32)
+declare void @free(ptr) willreturn allockind("free") "alloc-family"="malloc"
+
+attributes #1 = { coro_elide_safe }
|
Because the latest coroutine heap elision no longer depend on inlining. We can occasionally elide coroutines that are marked
__attribute__((noinline))
. Considering that we are force inlining the ramp function as of #114004, this is kind of important.