diff --git a/clang/test/CodeGenCoroutines/coro-attributes.cpp b/clang/test/CodeGenCoroutines/coro-attributes.cpp --- a/clang/test/CodeGenCoroutines/coro-attributes.cpp +++ b/clang/test/CodeGenCoroutines/coro-attributes.cpp @@ -14,7 +14,9 @@ }; // CHECK: void @_Z3foov() #[[FOO_ATTR_NUM:[0-9]+]] +// CHECK: declare token @llvm.coro.save(ptr) #[[SAVE_ATTR_NUM:[0-9]+]] // CHECK: attributes #[[FOO_ATTR_NUM]] = { {{.*}} presplitcoroutine +// CHECK: attributes #[[SAVE_ATTR_NUM]] = { {{.*}}nomerge coro foo() { co_await suspend_always{}; } diff --git a/llvm/docs/Coroutines.rst b/llvm/docs/Coroutines.rst --- a/llvm/docs/Coroutines.rst +++ b/llvm/docs/Coroutines.rst @@ -1555,7 +1555,9 @@ The '``llvm.coro.save``' marks the point where a coroutine need to update its state to prepare for resumption to be considered suspended (and thus eligible -for resumption). +for resumption). It is illegal to merge two '``llvm.coro.save``' calls unless their +'``llvm.coro.suspend``' users are also merged. So '``llvm.coro.save``' is currently +tagged with the `no_merge` function attribute. Arguments: """""""""" diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -1308,7 +1308,7 @@ def int_coro_size : Intrinsic<[llvm_anyint_ty], [], [IntrNoMem]>; def int_coro_align : Intrinsic<[llvm_anyint_ty], [], [IntrNoMem]>; -def int_coro_save : Intrinsic<[llvm_token_ty], [llvm_ptr_ty], []>; +def int_coro_save : Intrinsic<[llvm_token_ty], [llvm_ptr_ty], [IntrNoMerge]>; def int_coro_suspend : Intrinsic<[llvm_i8_ty], [llvm_token_ty, llvm_i1_ty], []>; def int_coro_suspend_retcon : Intrinsic<[llvm_any_ty], [llvm_vararg_ty], []>; def int_coro_prepare_retcon : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty], diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -1499,10 +1499,6 @@ if (I1->isTerminator()) goto HoistTerminator; - // Hoisting token-returning instructions would obscure the origin. - if (I1->getType()->isTokenTy()) - return Changed; - // If we're going to hoist a call, make sure that the two instructions we're // commoning/hoisting are both marked with musttail, or neither of them is // marked as such. Otherwise, we might end up in a situation where we hoist diff --git a/llvm/test/Transforms/SimplifyCFG/hoist-skip-token.ll b/llvm/test/Transforms/SimplifyCFG/hoist-skip-token.ll --- a/llvm/test/Transforms/SimplifyCFG/hoist-skip-token.ll +++ b/llvm/test/Transforms/SimplifyCFG/hoist-skip-token.ll @@ -1,7 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -passes='simplifycfg' -S | FileCheck %s -declare token @llvm.coro.save(ptr) +declare token @llvm.coro.save(ptr) #0 declare i8 @llvm.coro.suspend(token, i1) define void @f(i32 %x) { @@ -37,3 +37,5 @@ coro.ret: ret void } + +attributes #0 = { nomerge }