diff --git a/clang/test/CodeGenCoroutines/coro-attributes.cpp b/clang/test/CodeGenCoroutines/coro-attributes.cpp index ecd298e6b4b5..8f171771a8cb 100644 --- a/clang/test/CodeGenCoroutines/coro-attributes.cpp +++ b/clang/test/CodeGenCoroutines/coro-attributes.cpp @@ -14,7 +14,9 @@ struct coro { }; // 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 index f20284a74d5a..df05d0264967 100644 --- a/llvm/docs/Coroutines.rst +++ b/llvm/docs/Coroutines.rst @@ -1555,7 +1555,9 @@ Overview: 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 index 0dceea13ea36..8bf8e9ca76ad 100644 --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -1308,7 +1308,7 @@ def int_coro_noop : Intrinsic<[llvm_ptr_ty], [], [IntrNoMem]>; 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 index 86b2128a1937..c1d9de197a6b 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -1499,10 +1499,6 @@ bool SimplifyCFGOpt::HoistThenElseCodeToIf(BranchInst *BI, 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/Coroutines/coro-save-nomerge.ll b/llvm/test/Transforms/Coroutines/coro-save-nomerge.ll new file mode 100644 index 000000000000..17dfe2c26920 --- /dev/null +++ b/llvm/test/Transforms/Coroutines/coro-save-nomerge.ll @@ -0,0 +1,75 @@ +; 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) #0 +declare i8 @llvm.coro.suspend(token, i1) + +define void @final_nonfinal_suspend(i32 %x) { +; CHECK-LABEL: @final_nonfinal_suspend( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 0 +; CHECK-NEXT: br i1 [[CMP]], label [[AWAIT_SUSPEND:%.*]], label [[FINAL_SUSPEND:%.*]] +; CHECK: await.suspend: +; CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.coro.save(ptr null) +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.coro.suspend(token [[TMP0]], i1 false) +; CHECK-NEXT: br label [[CORO_RET:%.*]] +; CHECK: final.suspend: +; CHECK-NEXT: [[TMP2:%.*]] = call token @llvm.coro.save(ptr null) +; CHECK-NEXT: [[TMP3:%.*]] = call i8 @llvm.coro.suspend(token [[TMP2]], i1 true) +; CHECK-NEXT: br label [[CORO_RET]] +; CHECK: coro.ret: +; CHECK-NEXT: ret void +; +entry: + %cmp = icmp slt i32 %x, 0 + br i1 %cmp, label %await.suspend, label %final.suspend + +await.suspend: + %0 = call token @llvm.coro.save(ptr null) + %1 = call i8 @llvm.coro.suspend(token %0, i1 false) + br label %coro.ret + +final.suspend: + %2 = call token @llvm.coro.save(ptr null) + %3 = call i8 @llvm.coro.suspend(token %2, i1 true) + br label %coro.ret + +coro.ret: + ret void +} + +define void @both_nonfinal_suspend(i32 %x) { +; CHECK-LABEL: @both_nonfinal_suspend( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 0 +; CHECK-NEXT: br i1 [[CMP]], label [[AWAIT_SUSPEND:%.*]], label [[FINAL_SUSPEND:%.*]] +; CHECK: await.suspend: +; CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.coro.save(ptr null) +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.coro.suspend(token [[TMP0]], i1 false) +; CHECK-NEXT: br label [[CORO_RET:%.*]] +; CHECK: final.suspend: +; CHECK-NEXT: [[TMP2:%.*]] = call token @llvm.coro.save(ptr null) +; CHECK-NEXT: [[TMP3:%.*]] = call i8 @llvm.coro.suspend(token [[TMP2]], i1 false) +; CHECK-NEXT: br label [[CORO_RET]] +; CHECK: coro.ret: +; CHECK-NEXT: ret void +; +entry: + %cmp = icmp slt i32 %x, 0 + br i1 %cmp, label %await.suspend, label %final.suspend + +await.suspend: + %0 = call token @llvm.coro.save(ptr null) + %1 = call i8 @llvm.coro.suspend(token %0, i1 false) + br label %coro.ret + +final.suspend: + %2 = call token @llvm.coro.save(ptr null) + %3 = call i8 @llvm.coro.suspend(token %2, i1 false) + br label %coro.ret + +coro.ret: + ret void +} + +attributes #0 = { nomerge } diff --git a/llvm/test/Transforms/SimplifyCFG/hoist-skip-token.ll b/llvm/test/Transforms/SimplifyCFG/hoist-skip-token.ll deleted file mode 100644 index 1e9dc253f198..000000000000 --- a/llvm/test/Transforms/SimplifyCFG/hoist-skip-token.ll +++ /dev/null @@ -1,39 +0,0 @@ -; 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 i8 @llvm.coro.suspend(token, i1) - -define void @f(i32 %x) { -; CHECK-LABEL: @f( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 0 -; CHECK-NEXT: br i1 [[CMP]], label [[AWAIT_SUSPEND:%.*]], label [[FINAL_SUSPEND:%.*]] -; CHECK: await.suspend: -; CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.coro.save(ptr null) -; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.coro.suspend(token [[TMP0]], i1 false) -; CHECK-NEXT: br label [[CORO_RET:%.*]] -; CHECK: final.suspend: -; CHECK-NEXT: [[TMP2:%.*]] = call token @llvm.coro.save(ptr null) -; CHECK-NEXT: [[TMP3:%.*]] = call i8 @llvm.coro.suspend(token [[TMP2]], i1 true) -; CHECK-NEXT: br label [[CORO_RET]] -; CHECK: coro.ret: -; CHECK-NEXT: ret void -; -entry: - %cmp = icmp slt i32 %x, 0 - br i1 %cmp, label %await.suspend, label %final.suspend - -await.suspend: - %0 = call token @llvm.coro.save(ptr null) - %1 = call i8 @llvm.coro.suspend(token %0, i1 false) - br label %coro.ret - -final.suspend: - %2 = call token @llvm.coro.save(ptr null) - %3 = call i8 @llvm.coro.suspend(token %2, i1 true) - br label %coro.ret - -coro.ret: - ret void -}