================
@@ -191,3 +213,476 @@ Task co_return_at_end() {
// OGCG-EH-NEXT: call void @_ZN1SD1Ev(
// OGCG-NOT: return_void
// OGCG: br label %coro.final
+
+// Statements after a co_return with no label are kept despite them being
+// unreachable. Classic codegen drops them.
+
+IntTask co_return_value(int v) {
+ co_return v + 1;
+ dead();
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z15co_return_valuei(
+// CIR: }, body : {
+// CIR-EH: cir.try {
+// CIR: cir.call @_ZN7IntTask12promise_type12return_valueEi(
+// CIR-NEXT: cir.co_return
+// CIR-NEXT: ^bb1: // no predecessors
+// CIR-NEXT: cir.call @_Z4deadv()
+// CIR-NEXT: cir.yield
+// CIR-EH-NEXT: } catch all
+// CIR: }, finalSuspend : {
+
+// CIR-FLAT-LABEL: cir.func {{.*}} @_Z15co_return_valuei(
+// CIR-FLAT: cir.call @_ZN7IntTask12promise_type12return_valueEi(
+// CIR-FLAT-NEXT: cir.co_return
+// CIR-FLAT-NEXT: ^bb{{[0-9]+}}: // no predecessors
+// CIR-FLAT-NEXT: cir.call @_Z4deadv()
+
+// OGCG-LABEL: define {{.*}} @_Z15co_return_valuei(
+// OGCG: {{call|invoke}} void
@_ZN7IntTask12promise_type12return_valueEi(
+
+// A co_return at the top level of the body still suppresses the implicit
+// co_return when unreachable statements follow it.
+
+Task co_return_void() {
+ co_return;
+ S s;
+ dead();
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z14co_return_voidv(
+// CIR: }, body : {
+// CIR-EH: cir.try {
+// CIR: cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-NEXT: cir.co_return
+// CIR-NEXT: ^bb1: // no predecessors
+// CIR-NEXT: cir.cleanup.scope {
+// CIR-NEXT: cir.call @_Z4deadv()
+// CIR-NEXT: cir.yield
+// CIR-NOEH-NEXT: } cleanup normal {
+// CIR-EH-NEXT: } cleanup all {
+// CIR-NEXT: cir.call @_ZN1SD1Ev(
+// CIR-NEXT: cir.yield
+// CIR-NEXT: }
+// CIR-NEXT: cir.yield
+// CIR-EH-NEXT: } catch all
+// CIR-NOT: @_ZN4Task12promise_type11return_voidEv
+// CIR: }, finalSuspend : {
+
+// CIR-FLAT-LABEL: cir.func {{.*}} @_Z14co_return_voidv(
+// CIR-FLAT: cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-FLAT-NEXT: cir.co_return
+// CIR-FLAT-NEXT: ^bb{{[0-9]+}}: // no predecessors
+// CIR-FLAT: cir.call @_Z4deadv()
+// CIR-FLAT-NOT: @_ZN4Task12promise_type11return_voidEv
+// CIR-FLAT: }, finalSuspend : {
+
+// OGCG-LABEL: define {{.*}} @_Z14co_return_voidv(
+// OGCG: {{call|invoke}} void @_ZN4Task12promise_type11return_voidEv(
+// OGCG-NOT: @_ZN1SD1Ev
+// OGCG: coro.final:
+
+// Without unreachable statements, the new block stays empty. It is erased at
+// the end of the body region. A cir.try terminates with a cir.yield.
+
+Task co_return_at_end_without_cleanup() {
+ co_await std::suspend_always{};
+ co_return;
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z32co_return_at_end_without_cleanupv(
+// CIR: }, body : {
+// CIR: cir.await(user,
+// CIR: cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-NEXT: cir.co_return
+// CIR-NOEH-NEXT: }, finalSuspend : {
+// CIR-EH-NEXT: ^bb1: // no predecessors
+// CIR-EH-NEXT: cir.yield
+// CIR-EH-NEXT: } catch all
+
+// CIR-FLAT-LABEL: cir.func {{.*}} @_Z32co_return_at_end_without_cleanupv(
+// CIR-FLAT: cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-FLAT-NEXT: cir.co_return
+// CIR-FLAT-NEXT: }, finalSuspend : {
+
+Task co_return_in_block() {
+ {
+ S s;
+ co_return;
+ dead();
+ }
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z18co_return_in_blockv(
+// CIR: }, body : {
+// CIR: cir.scope {
+// CIR: cir.cleanup.scope {
+// CIR-NEXT: cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-NEXT: cir.co_return
+// CIR-NEXT: ^bb1: // no predecessors
+// CIR-NEXT: cir.call @_Z4deadv()
+// CIR-NEXT: cir.yield
+// CIR-NOEH-NEXT: } cleanup normal {
+// CIR-EH-NEXT: } cleanup all {
+// CIR-NEXT: cir.call @_ZN1SD1Ev(
+// CIR-NEXT: cir.yield
+// CIR-NEXT: }
+// CIR-NEXT: }
+
+// CIR-FLAT-LABEL: cir.func {{.*}} @_Z18co_return_in_blockv(
+// CIR-FLAT: cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-FLAT-NEXT: cir.co_return
+// CIR-FLAT-NEXT: ^bb{{[0-9]+}}: // no predecessors
+// CIR-FLAT-NEXT: cir.call @_Z4deadv()
+
+// OGCG-LABEL: define {{.*}} @_Z18co_return_in_blockv(
+// OGCG: {{call|invoke}} void @_ZN4Task12promise_type11return_voidEv(
+// OGCG: call void @_ZN1SD1Ev(
+
+Task co_return_in_if_with_dead_code(bool b) {
+ if (b) {
+ co_return;
+ dead();
+ } else {
+ co_return;
+ dead();
+ }
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z30co_return_in_if_with_dead_codeb(
+// CIR: }, body : {
+// CIR: cir.if %{{.*}} {
+// CIR-NEXT: cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-NEXT: cir.co_return
+// CIR-NEXT: ^bb1: // no predecessors
+// CIR-NEXT: cir.call @_Z4deadv()
+// CIR-NEXT: cir.yield
+// CIR-NEXT: } else {
+// CIR-NEXT: cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-NEXT: cir.co_return
+// CIR-NEXT: ^bb1: // no predecessors
+// CIR-NEXT: cir.call @_Z4deadv()
+// CIR-NEXT: cir.yield
+// CIR-NEXT: }
+
+// CIR-FLAT-LABEL: cir.func {{.*}} @_Z30co_return_in_if_with_dead_codeb(
+// CIR-FLAT: cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-FLAT-NEXT: cir.co_return
+// CIR-FLAT-NEXT: ^bb{{[0-9]+}}: // no predecessors
+// CIR-FLAT-NEXT: cir.call @_Z4deadv()
+// CIR-FLAT: cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-FLAT-NEXT: cir.co_return
+// CIR-FLAT-NEXT: ^bb{{[0-9]+}}: // no predecessors
+// CIR-FLAT-NEXT: cir.call @_Z4deadv()
+
+Task co_return_in_loop(bool b) {
+ while (b) {
+ co_return;
+ dead();
+ }
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z17co_return_in_loopb(
+// CIR: }, body : {
+// CIR: cir.while {
+// CIR: } do {
+// CIR-NEXT: cir.scope {
+// CIR-NEXT: cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-NEXT: cir.co_return
+// CIR-NEXT: ^bb1: // no predecessors
+// CIR-NEXT: cir.call @_Z4deadv()
+// CIR-NEXT: cir.yield
+// CIR-NEXT: }
+
+// CIR-FLAT-LABEL: cir.func {{.*}} @_Z17co_return_in_loopb(
+// CIR-FLAT: cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-FLAT-NEXT: cir.co_return
+// CIR-FLAT-NEXT: ^bb{{[0-9]+}}: // no predecessors
+// CIR-FLAT-NEXT: cir.call @_Z4deadv()
+
+Task co_return_in_switch(int i) {
+ switch (i) {
+ case 0:
+ co_return;
+ dead();
+ default:
+ break;
+ }
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z19co_return_in_switchi(
+// CIR: }, body : {
+// CIR: cir.case(equal, [#cir.int<0> : !s32i]) {
+// CIR-NEXT: cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-NEXT: cir.co_return
+// CIR-NEXT: ^bb1: // no predecessors
+// CIR-NEXT: cir.call @_Z4deadv()
+// CIR-NEXT: cir.yield
+// CIR-NEXT: }
+
+// CIR-FLAT-LABEL: cir.func {{.*}} @_Z19co_return_in_switchi(
+// CIR-FLAT: cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-FLAT-NEXT: cir.co_return
+// CIR-FLAT-NEXT: ^bb{{[0-9]+}}: // no predecessors
+// CIR-FLAT-NEXT: cir.call @_Z4deadv()
+
+// An unreachable suspension point is emitted too.
+
+Task dead_co_await() {
+ co_return;
+ co_await std::suspend_never{};
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z13dead_co_awaitv(
+// CIR: }, body : {
+// CIR: cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-NEXT: cir.co_return
+// CIR-NEXT: ^bb1: // no predecessors
+// CIR-NEXT: cir.await(user, ready : {
+// CIR-NEXT: cir.call @_ZNSt13suspend_never11await_readyEv(
+// CIR-NOT: @_ZN4Task12promise_type11return_voidEv
+// CIR: }, finalSuspend : {
+
+// CIR-FLAT-LABEL: cir.func {{.*}} @_Z13dead_co_awaitv(
+// CIR-FLAT: cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-FLAT-NEXT: cir.co_return
+// CIR-FLAT-NEXT: ^bb{{[0-9]+}}: // no predecessors
+// CIR-FLAT-NEXT: cir.await(user, ready : {
+
+// OGCG-LABEL: define {{.*}} @_Z13dead_co_awaitv(
+// OGCG-NOT: suspend_never
+// OGCG: coro.final:
+
+// A label after a co_return makes the statements after it reachable through a
+// goto, and with them the end of the body. The implicit co_return is then
+// emitted, as in classic codegen, which calls return_void() on that path.
+
+Task label_after_co_return(bool b) {
+ if (b)
+ goto l;
+ co_return;
+l:
+ live();
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z21label_after_co_returnb(
+// CIR: }, body : {
+// CIR: cir.goto "l"
+// CIR: cir.call
@_ZN4Task12promise_type11return_voidEv(%[[PROMISE:[0-9]+]])
+// CIR-NEXT: cir.co_return
+// CIR-NEXT: ^bb1: // no predecessors
+// CIR-NEXT: cir.label "l"
+// CIR-NEXT: cir.call @_Z4livev()
+// CIR-NEXT: cir.call
@_ZN4Task12promise_type11return_voidEv(%[[PROMISE]])
+// CIR-NEXT: cir.co_return
+// CIR-NOEH-NEXT: }, finalSuspend : {
+// CIR-EH-NEXT: ^bb2: // no predecessors
+// CIR-EH-NEXT: cir.yield
+// CIR-EH-NEXT: } catch all
+
+// CIR-FLAT-LABEL: cir.func {{.*}} @_Z21label_after_co_returnb(
+// CIR-FLAT: cir.goto "l"
+// CIR-FLAT: cir.co_return
+// CIR-FLAT-NEXT: ^bb{{[0-9]+}}: // no predecessors
+// CIR-FLAT-NEXT: cir.label "l"
+// CIR-FLAT-NEXT: cir.call @_Z4livev()
+// CIR-FLAT-NEXT: cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-FLAT-NEXT: cir.co_return
+// CIR-FLAT-NEXT: }, finalSuspend : {
+
+// OGCG-LABEL: define {{.*}} @_Z21label_after_co_returnb(
+// OGCG: {{^}}l:
+// OGCG-NEXT: {{call|invoke}} void @_Z4livev()
+// OGCG: {{call|invoke}} void @_ZN4Task12promise_type11return_voidEv(
+// OGCG: br label %coro.final
+
+Task label_in_block_after_co_return(bool b) {
+ if (b)
+ goto l;
+ co_return;
+ {
+ l:
+ live();
+ }
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z30label_in_block_after_co_returnb(
+// CIR: }, body : {
+// CIR: cir.call
@_ZN4Task12promise_type11return_voidEv(%[[PROMISE:[0-9]+]])
+// CIR-NEXT: cir.co_return
+// CIR-NEXT: ^bb1: // no predecessors
+// CIR-NEXT: cir.scope {
+// CIR: cir.label "l"
+// CIR-NEXT: cir.call @_Z4livev()
+// CIR-NEXT: cir.yield
+// CIR-NEXT: }
+// CIR-NEXT: cir.call
@_ZN4Task12promise_type11return_voidEv(%[[PROMISE]])
+// CIR-NEXT: cir.co_return
+
+// OGCG-LABEL: define {{.*}} @_Z30label_in_block_after_co_returnb(
+// OGCG: {{^}}l:
+// OGCG-NEXT: {{call|invoke}} void @_Z4livev()
+// OGCG: {{call|invoke}} void @_ZN4Task12promise_type11return_voidEv(
+// OGCG: br label %coro.final
+
+Task empty_label_after_co_return(bool b) {
+ if (b)
+ goto l;
+ co_return;
+l:;
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z27empty_label_after_co_returnb(
+// CIR: }, body : {
+// CIR: cir.call
@_ZN4Task12promise_type11return_voidEv(%[[PROMISE:[0-9]+]])
+// CIR-NEXT: cir.co_return
+// CIR-NEXT: ^bb1: // no predecessors
+// CIR-NEXT: cir.label "l"
+// CIR-NEXT: cir.call
@_ZN4Task12promise_type11return_voidEv(%[[PROMISE]])
+// CIR-NEXT: cir.co_return
+
+// OGCG-LABEL: define {{.*}} @_Z27empty_label_after_co_returnb(
+// OGCG: {{^}}l:
+// OGCG-NEXT: {{call|invoke}} void @_ZN4Task12promise_type11return_voidEv(
+// OGCG: br label %coro.final
+
+// A co_return after the label makes the end of the body unreachable again.
+
+Task co_return_after_label(bool b) {
+ if (b)
+ goto l;
+ co_return;
+l:
+ live();
+ co_return;
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z21co_return_after_labelb(
+// CIR: }, body : {
+// CIR: cir.label "l"
+// CIR-NEXT: cir.call @_Z4livev()
+// CIR-NEXT: cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-NEXT: cir.co_return
+// CIR-NOT: @_ZN4Task12promise_type11return_voidEv
+// CIR: }, finalSuspend : {
+
----------------
Andres-Salamanca wrote:
Why are there no OGCG checks for the last few tests?
https://github.com/llvm/llvm-project/pull/231046
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits