[clang] [llvm] [Coro][IR] Model memory effects of coro.alloc and coro.begin more precisely (PR #219870)
Weibo He via llvm-commits
llvm-commits at lists.llvm.org
Sun Aug 30 20:20:32 PDT 2026
https://github.com/NewSigma created https://github.com/llvm/llvm-project/pull/219870
Consider the following code:
``` LLVM
%hdl1 = call ptr @llvm.coro.begin(token %coro.outer, ptr %mem1)
store ptr %hdl1, ptr %alloca, align 8
call i1 @llvm.coro.alloc(token %coro.inner)
call ptr @llvm.coro.begin(token %coro.inner, ptr %mem2)
%hdl1.ld = load ptr, ptr %alloca, align 8
%resumer = call ptr @llvm.coro.subfn.addr(ptr %hdl1.ld, i8 0)
invoke void %resumer(ptr %hdl1.ld)
```
The pattern occurs inside nested coroutines. Adding `memory(none)` attributes allows GVN to replace the store-load with direct references to `coro.begin`, thus enabling further optimizations. We can simplify #57852 into single `ret 0` after this change.
>From 46accf7215b3b11dbe613ff461a0013f2e2794be Mon Sep 17 00:00:00 2001
From: NewSigma <NewSigma at 163.com>
Date: Sun, 23 Aug 2026 17:00:42 +0800
Subject: [PATCH] [Coro][IR] Model memory effects of coro.alloc and coro.begin
more precisely
---
.../coro-unhandled-exception.cpp | 4 ++--
llvm/include/llvm/IR/Intrinsics.td | 6 +++---
.../Transforms/Coroutines/coro-byval-param.ll | 16 +++++++++-------
.../Transforms/Coroutines/coro-split-alloc.ll | 3 +--
4 files changed, 15 insertions(+), 14 deletions(-)
diff --git a/clang/test/CodeGenCoroutines/coro-unhandled-exception.cpp b/clang/test/CodeGenCoroutines/coro-unhandled-exception.cpp
index 97ef983b7523a..ace0bbca62dbb 100644
--- a/clang/test/CodeGenCoroutines/coro-unhandled-exception.cpp
+++ b/clang/test/CodeGenCoroutines/coro-unhandled-exception.cpp
@@ -55,12 +55,12 @@ coro_t f() {
// CHECK-LPAD: invoke void @_Z9may_throwv()
// CHECK-LPAD: to label %[[CONT:.+]] unwind label %[[CLEANUP:.+]]
// CHECK-LPAD: [[CLEANUP]]:
-// CHECK-LPAD: call void @_ZN7CleanupD1Ev(ptr {{[^,]*}} %x) #2
+// CHECK-LPAD: call void @_ZN7CleanupD1Ev(ptr {{[^,]*}} %x) #[[ATTR:[0-9]+]]
// CHECK-LPAD: br label %[[CATCH:.+]]
// CHECK-LPAD: [[CATCH]]:
// CHECK-LPAD: call ptr @__cxa_begin_catch
-// CHECK-LPAD: call void @_ZN6coro_t12promise_type19unhandled_exceptionEv(ptr {{[^,]*}} %__promise) #2
+// CHECK-LPAD: call void @_ZN6coro_t12promise_type19unhandled_exceptionEv(ptr {{[^,]*}} %__promise) #[[ATTR]]
// CHECK-LPAD: invoke void @__cxa_end_catch()
// CHECK-LPAD-NEXT: to label %[[CATCHRETDEST:.+]] unwind label
// CHECK-LPAD: [[CATCHRETDEST]]:
diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index 1d960dc011a5a..0efe844900fd8 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -1986,7 +1986,7 @@ def int_coro_id_retcon_once : Intrinsic<[llvm_token_ty],
[llvm_i32_ty, llvm_i32_ty, llvm_ptr_ty,
llvm_ptr_ty, llvm_ptr_ty, llvm_ptr_ty],
[]>;
-def int_coro_alloc : Intrinsic<[llvm_i1_ty], [llvm_token_ty], []>;
+def int_coro_alloc : Intrinsic<[llvm_i1_ty], [llvm_token_ty], [IntrNoMem]>;
def int_coro_id_async : Intrinsic<[llvm_token_ty],
[llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_ptr_ty],
[]>;
@@ -2007,10 +2007,10 @@ def int_coro_suspend_async
def int_coro_prepare_async : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty],
[IntrNoMem]>;
def int_coro_begin : Intrinsic<[llvm_ptr_ty], [llvm_token_ty, llvm_ptr_ty],
- [WriteOnly<ArgIndex<1>>]>;
+ [IntrArgMemOnly, WriteOnly<ArgIndex<1>>]>;
def int_coro_begin_custom_abi : Intrinsic<[llvm_ptr_ty],
[llvm_token_ty, llvm_ptr_ty, llvm_i32_ty],
- [WriteOnly<ArgIndex<1>>]>;
+ [IntrArgMemOnly, WriteOnly<ArgIndex<1>>]>;
def int_coro_free : Intrinsic<[llvm_ptr_ty], [llvm_token_ty, llvm_ptr_ty],
[IntrReadMem, IntrArgMemOnly,
ReadOnly<ArgIndex<1>>,
diff --git a/llvm/test/Transforms/Coroutines/coro-byval-param.ll b/llvm/test/Transforms/Coroutines/coro-byval-param.ll
index 44204de99ea66..9e4f383653435 100644
--- a/llvm/test/Transforms/Coroutines/coro-byval-param.ll
+++ b/llvm/test/Transforms/Coroutines/coro-byval-param.ll
@@ -21,7 +21,7 @@ define ptr @foo(ptr nocapture readonly byval(%struct.A) align 8 %a1) #0 !prof !0
; CHECK-NEXT: [[TMP1:%.*]] = call i1 @llvm.coro.alloc(token [[TMP0]])
; CHECK-NEXT: br i1 [[TMP1]], label %[[CORO_ALLOC:.*]], label %[[CORO_INIT:.*]]
; CHECK: [[CORO_ALLOC]]:
-; CHECK-NEXT: [[CALL:%.*]] = call noalias nonnull ptr @_Znwm(i64 48) #[[ATTR10:[0-9]+]]
+; CHECK-NEXT: [[CALL:%.*]] = call noalias nonnull ptr @_Znwm(i64 48) #[[ATTR11:[0-9]+]]
; CHECK-NEXT: br label %[[CORO_INIT]]
; CHECK: [[CORO_INIT]]:
; CHECK-NEXT: [[TMP2:%.*]] = phi ptr [ [[CALL]], %[[CORO_ALLOC]] ], [ null, %[[ENTRY]] ]
@@ -37,7 +37,7 @@ define ptr @foo(ptr nocapture readonly byval(%struct.A) align 8 %a1) #0 !prof !0
; CHECK-NEXT: call void @initial_suspend(ptr nonnull dereferenceable(1) [[__PROMISE_RELOAD_ADDR]])
; CHECK-NEXT: [[INDEX_ADDR5:%.*]] = getelementptr inbounds i8, ptr [[TMP3]], i64 17
; CHECK-NEXT: store i1 false, ptr [[INDEX_ADDR5]], align 1
-; CHECK-NEXT: call fastcc void @_ZNSt12experimental13coroutines_v116coroutine_handleIN4task12promise_typeEE12from_addressEPv(ptr [[TMP3]]) #[[ATTR2:[0-9]+]]
+; CHECK-NEXT: call fastcc void @_ZNSt12experimental13coroutines_v116coroutine_handleIN4task12promise_typeEE12from_addressEPv(ptr [[TMP3]]) #[[ATTR8:[0-9]+]]
; CHECK-NEXT: ret ptr [[CALL2]]
;
entry:
@@ -159,16 +159,18 @@ attributes #10 = { noduplicate }
;.
; CHECK: attributes #[[ATTR0]] = { mustprogress noinline ssp uwtable "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "tune-cpu"="generic" }
; CHECK: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(argmem: read) }
-; CHECK: attributes #[[ATTR2]] = { nounwind }
+; CHECK: attributes #[[ATTR2:[0-9]+]] = { nounwind memory(none) }
; CHECK: attributes #[[ATTR3:[0-9]+]] = { nobuiltin nofree allocsize(0) "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "tune-cpu"="generic" }
-; CHECK: attributes #[[ATTR4:[0-9]+]] = { nounwind memory(none) }
+; CHECK: attributes #[[ATTR4:[0-9]+]] = { nounwind memory(argmem: readwrite) }
; CHECK: attributes #[[ATTR5:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
; CHECK: attributes #[[ATTR6:[0-9]+]] = { mustprogress noinline nounwind ssp willreturn uwtable "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "tune-cpu"="generic" }
; CHECK: attributes #[[ATTR7:[0-9]+]] = { nomerge nounwind }
-; CHECK: attributes #[[ATTR8:[0-9]+]] = { nobuiltin nounwind "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "tune-cpu"="generic" }
-; CHECK: attributes #[[ATTR9:[0-9]+]] = { nounwind memory(argmem: read) }
-; CHECK: attributes #[[ATTR10]] = { allocsize(0) }
+; CHECK: attributes #[[ATTR8]] = { nounwind }
+; CHECK: attributes #[[ATTR9:[0-9]+]] = { nobuiltin nounwind "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "tune-cpu"="generic" }
+; CHECK: attributes #[[ATTR10:[0-9]+]] = { nounwind memory(argmem: read) }
+; CHECK: attributes #[[ATTR11]] = { allocsize(0) }
;.
; CHECK: [[PROF0]] = !{!"function_entry_count", i64 1000}
; CHECK: [[PROF1]] = !{!"unknown", !"coro-split"}
+; CHECK: [[META2:![0-9]+]] = !{!"function_entry_count", i64 1333}
;.
diff --git a/llvm/test/Transforms/Coroutines/coro-split-alloc.ll b/llvm/test/Transforms/Coroutines/coro-split-alloc.ll
index db97cafeebbbb..3c3a2796d93ff 100644
--- a/llvm/test/Transforms/Coroutines/coro-split-alloc.ll
+++ b/llvm/test/Transforms/Coroutines/coro-split-alloc.ll
@@ -42,8 +42,7 @@ suspend:
; CHECK: %incremented = add i32 %argument, 1
; CHECK-NEXT: store i32 %incremented, ptr %argument.addr
; CHECK-LABEL: dyn.alloc:
-; CHECK: %allocator_argument = load i32, ptr %argument.addr
-; CHECK: %alloc = call ptr @custom_alloctor(i32 24, i32 %allocator_argument)
+; CHECK: %alloc = call ptr @custom_alloctor(i32 24, i32 %incremented)
; CHECK-LABEL: begin:
; CHECK: %print_argument = load i32, ptr %argument.addr
; CHECK: call void @print(i32 %print_argument)
More information about the llvm-commits
mailing list