[clang] Extend `retcon.once` coroutines lowering to optionally produce a normal result (PR #66333)

via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 13 23:53:09 PDT 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir
            
<details>
<summary>Changes</summary>
One of the main user of these kind of coroutines is swift. There yield-once (`retcon.once`) coroutines are used to temporary "expose" pointers to internal fields of various objects creating borrow scopes.

However, in some cases it might be useful also to allow these coroutines to produce a normal result, however, there is no way to represent this (as compared to switched-resume kind of coroutines where C++ `co_return` is transformed to a member / callback call on promise object).

The extension is simple: we simply allow continuation function to have non-void result and accept optional extra arguments to `llvm.coro.end` intrinsic that would essentially forward them as normal results. Everything is backward compatible in terms of LLVM C++ API (as we only made `llvm.coro.end` intrinsic variadic), so no changes in downstream projects are expected.
--

Patch is 132.42 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/66333.diff

123 Files Affected:

- (modified) clang/test/CodeGenCoroutines/coro-builtins.c (+1-1) 
- (modified) clang/test/CodeGenCoroutines/coro-eh-cleanup.cpp (+2-2) 
- (modified) clang/test/CodeGenCoroutines/coro-lambda.cpp (+1-1) 
- (modified) llvm/docs/Coroutines.rst (+22-7) 
- (modified) llvm/include/llvm/IR/Intrinsics.td (+1-1) 
- (modified) llvm/lib/IR/AutoUpgrade.cpp (+12) 
- (modified) llvm/lib/Transforms/Coroutines/CoroFrame.cpp (+2-1) 
- (modified) llvm/lib/Transforms/Coroutines/CoroInstr.h (+17) 
- (modified) llvm/lib/Transforms/Coroutines/CoroSplit.cpp (+25-2) 
- (modified) llvm/test/Assembler/auto_upgrade_intrinsics.ll (+7) 
- (modified) llvm/test/Transforms/Coroutines/ArgAddr.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-align16.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-align32.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-align64-02.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-align64.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-align8-02.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-align8.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-alloc-with-param-O0.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-alloc-with-param-O2.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-alloca-01.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-alloca-02.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-alloca-03.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-alloca-04.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-alloca-05.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-alloca-06.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-alloca-07.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-alloca-08.ll (+3-3) 
- (modified) llvm/test/Transforms/Coroutines/coro-alloca-09.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-alloca-loop-carried-address.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-async-addr-lifetime-infinite-loop-bug.ll (+1-1) 
- (modified) llvm/test/Transforms/Coroutines/coro-async-addr-lifetime-start-bug.ll (+1-1) 
- (modified) llvm/test/Transforms/Coroutines/coro-async-dyn-align.ll (+1-1) 
- (modified) llvm/test/Transforms/Coroutines/coro-async.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-byval-param.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-catchswitch-cleanuppad.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-catchswitch.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-debug-O2.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-debug-coro-frame.ll (+3-3) 
- (modified) llvm/test/Transforms/Coroutines/coro-debug-dbg.values-not_used_in_frame.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-debug-dbg.values.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-debug-frame-variable.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-debug-spill-dbg.declare.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-debug.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split-00.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split-01.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split-02.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-frame-arrayalloca.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-00.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-01.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-02.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-03.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-04.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-05.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-frame-unreachable.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-frame.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-materialize.ll (+6-6) 
- (modified) llvm/test/Transforms/Coroutines/coro-noalias-param.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-padding.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-param-copy.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-preserve-final.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-readnone-02.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-readnone.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-retcon-alloca-opaque-ptr.ll (+3-3) 
- (modified) llvm/test/Transforms/Coroutines/coro-retcon-alloca.ll (+6-6) 
- (modified) llvm/test/Transforms/Coroutines/coro-retcon-frame.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-retcon-once-private.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-retcon-once-value.ll (+162-27) 
- (modified) llvm/test/Transforms/Coroutines/coro-retcon-once-value2.ll (+111-8) 
- (modified) llvm/test/Transforms/Coroutines/coro-retcon-opaque-ptr.ll (+3-3) 
- (modified) llvm/test/Transforms/Coroutines/coro-retcon-remat.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-retcon-resume-values2.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-retcon-unreachable.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-retcon-value.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-retcon.ll (+4-4) 
- (modified) llvm/test/Transforms/Coroutines/coro-spill-after-phi.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-spill-corobegin.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-spill-defs-before-corobegin.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-spill-promise-02.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-spill-promise.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-00.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-01.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-02.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-alloc.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-dbg.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-eh-00.ll (+3-3) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-eh-01.ll (+3-3) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-final-suspend.ll (+4-4) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-hidden.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-musttail-ppc64le.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-musttail.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-musttail1.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-musttail10.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-musttail11.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-musttail12.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-musttail13.ll (+3-3) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-musttail2.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-musttail3.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-musttail4.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-musttail5.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-musttail6.ll (+3-3) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-musttail7.ll (+3-3) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-musttail8.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-musttail9.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-no-lieftime.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-01.ll (+3-3) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-02.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-03.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-04.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-swifterror.ll (+3-3) 
- (modified) llvm/test/Transforms/Coroutines/coro-zero-alloca.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/ex0.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/ex1.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/ex2.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/ex3.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/ex4.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/ex5.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/no-suspend.ll (+9-9) 
- (modified) llvm/test/Transforms/Coroutines/phi-coro-end.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/remarks.ll (+2-2) 
- (modified) llvm/test/Transforms/FunctionAttrs/noreturn.ll (+2-2) 
- (modified) llvm/test/Transforms/LICM/sink-with-coroutine.ll (+5-5) 
- (modified) mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir (+2-2) 


<pre>
diff --git a/clang/test/CodeGenCoroutines/coro-builtins.c b/clang/test/CodeGenCoroutines/coro-builtins.c
index e58820db6783987..a329200aa548dc0 100644
--- a/clang/test/CodeGenCoroutines/coro-builtins.c
+++ b/clang/test/CodeGenCoroutines/coro-builtins.c
@@ -37,7 +37,7 @@ void f(int n) {
   // CHECK-NEXT: call ptr @llvm.coro.free(token %[[COROID]], ptr %[[FRAME]])
   __builtin_coro_free(__builtin_coro_frame());
 
-  // CHECK-NEXT: call i1 @llvm.coro.end(ptr %[[FRAME]], i1 false)
+  // CHECK-NEXT: call i1 (ptr, i1, ...) @llvm.coro.end(ptr %[[FRAME]], i1 false)
   __builtin_coro_end(__builtin_coro_frame(), 0);
 
   // CHECK-NEXT: call i8 @llvm.coro.suspend(token none, i1 true)
diff --git a/clang/test/CodeGenCoroutines/coro-eh-cleanup.cpp b/clang/test/CodeGenCoroutines/coro-eh-cleanup.cpp
index c4a6ae96f551e19..e055c4d7561b2c3 100644
--- a/clang/test/CodeGenCoroutines/coro-eh-cleanup.cpp
+++ b/clang/test/CodeGenCoroutines/coro-eh-cleanup.cpp
@@ -60,7 +60,7 @@ coro_t f() {
 
 // CHECK: [[COROENDBB]]:
 // CHECK-NEXT: %[[CLPAD:.+]] = cleanuppad within none
-// CHECK-NEXT: call i1 @llvm.coro.end(ptr null, i1 true) [ &quot;funclet&quot;(token %[[CLPAD]]) ]
+// CHECK-NEXT: call i1 (ptr, i1, ...) @llvm.coro.end(ptr null, i1 true) [ &quot;funclet&quot;(token %[[CLPAD]]) ]
 // CHECK-NEXT: cleanupret from %[[CLPAD]] unwind label
 
 // CHECK-LPAD: @_Z1fv(
@@ -76,7 +76,7 @@ coro_t f() {
 // CHECK-LPAD:             to label %{{.+}} unwind label %[[UNWINDBB:.+]]
 
 // CHECK-LPAD: [[UNWINDBB]]:
-// CHECK-LPAD:   %[[I1RESUME:.+]] = call i1 @llvm.coro.end(ptr null, i1 true)
+// CHECK-LPAD:   %[[I1RESUME:.+]] = call i1 (ptr, i1, ...) @llvm.coro.end(ptr null, i1 true)
 // CHECK-LPAD:   br i1  %[[I1RESUME]], label %[[EHRESUME:.+]], label
 // CHECK-LPAD: [[EHRESUME]]:
 // CHECK-LPAD-NEXT:  %[[exn:.+]] = load ptr, ptr %exn.slot, align 8
diff --git a/clang/test/CodeGenCoroutines/coro-lambda.cpp b/clang/test/CodeGenCoroutines/coro-lambda.cpp
index 26c51070f9e2d05..06c18ddb8f640c8 100644
--- a/clang/test/CodeGenCoroutines/coro-lambda.cpp
+++ b/clang/test/CodeGenCoroutines/coro-lambda.cpp
@@ -55,4 +55,4 @@ void f() {
 //   CHECK: alloca %&quot;struct.Task::promise_type&quot;
 //   CHECK: call token @llvm.coro.id(
 //   CHECK: call i8 @llvm.coro.suspend(
-//   CHECK: call i1 @llvm.coro.end(
+//   CHECK: call i1 (ptr, i1, ...) @llvm.coro.end(
diff --git a/llvm/docs/Coroutines.rst b/llvm/docs/Coroutines.rst
index 0a65a39119fd83c..109d8a7f9971928 100644
--- a/llvm/docs/Coroutines.rst
+++ b/llvm/docs/Coroutines.rst
@@ -303,7 +303,7 @@ The LLVM IR for this coroutine looks like this:
     call void @free(ptr %mem)
     br label %suspend
   suspend:
-    %unused = call i1 @llvm.coro.end(ptr %hdl, i1 false)
+    %unused = call i1 (ptr, i1, ...) @llvm.coro.end(ptr %hdl, i1 false)
     ret ptr %hdl
   }
 
@@ -630,7 +630,7 @@ store the current value produced by a coroutine.
     call void @free(ptr %mem)
     br label %suspend
   suspend:
-    %unused = call i1 @llvm.coro.end(ptr %hdl, i1 false)
+    %unused = call i1 (ptr, i1, ...) @llvm.coro.end(ptr %hdl, i1 false)
     ret ptr %hdl
   }
 
@@ -1312,8 +1312,8 @@ Arguments:
 &quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;
 
 As for ``llvm.core.id.retcon``, except that the return type of the
-continuation prototype must be `void` instead of matching the
-coroutine&#x27;s return type.
+continuation prototype must represent the normal return type of the continuation
+(instead of matching the coroutine&#x27;s return type).
 
 Semantics:
 &quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;
@@ -1326,7 +1326,7 @@ A frontend should emit function attribute `presplitcoroutine` for the coroutine.
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 ::
 
-  declare i1 @llvm.coro.end(ptr &lt;handle&gt;, i1 &lt;unwind&gt;)
+  declare i1 @llvm.coro.end(ptr &lt;handle&gt;, i1 &lt;unwind&gt;, ...)
 
 Overview:
 &quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;
@@ -1347,6 +1347,21 @@ The second argument should be `true` if this coro.end is in the block that is
 part of the unwind sequence leaving the coroutine body due to an exception and
 `false` otherwise.
 
+Other arguments can only be specified for unique-suspend returned-continuation
+coroutines where they will be normal returns of a coroutine continuation
+function. The number of arguments must match the return type of the continuation
+function:
+
+- if the return type of the continuation function is ``void`` there must be no
+  extra argumets
+
+- if the return type of the continuation function is a ``struct``, the arguments
+  will be element types of that ``struct`` in order;
+
+- otherwise, it is just the return value of the continuation function.
+
+No extra arguments are allowed for coro.end calls in unwind sections
+
 Semantics:
 &quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;
 The purpose of this intrinsic is to allow frontends to mark the cleanup and
@@ -1378,7 +1393,7 @@ For landingpad based exception model, it is expected that frontend uses the
 .. code-block:: llvm
 
     ehcleanup:
-      %InResumePart = call i1 @llvm.coro.end(ptr null, i1 true)
+      %InResumePart = call i1 (ptr, i1, ...) @llvm.coro.end(ptr null, i1 true)
       br i1 %InResumePart, label %eh.resume, label %cleanup.cont
 
     cleanup.cont:
@@ -1403,7 +1418,7 @@ referring to an enclosing cleanuppad as follows:
 
     ehcleanup:
       %tok = cleanuppad within none []
-      %unused = call i1 @llvm.coro.end(ptr null, i1 true) [ &quot;funclet&quot;(token %tok) ]
+      %unused = call i1 (ptr, i1, ...) @llvm.coro.end(ptr null, i1 true) [ &quot;funclet&quot;(token %tok) ]
       cleanupret from %tok unwind label %RestOfTheCleanup
 
 The `CoroSplit` pass, if the funclet bundle is present, will insert
diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index cd6061a190fbbc0..da186dec2cbca10 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -1643,7 +1643,7 @@ def int_coro_free : Intrinsic&lt;[llvm_ptr_ty], [llvm_token_ty, llvm_ptr_ty],
                               [IntrReadMem, IntrArgMemOnly,
                                ReadOnly&lt;ArgIndex&lt;1&gt;&gt;,
                                NoCapture&lt;ArgIndex&lt;1&gt;&gt;]&gt;;
-def int_coro_end : Intrinsic&lt;[llvm_i1_ty], [llvm_ptr_ty, llvm_i1_ty], []&gt;;
+def int_coro_end : Intrinsic&lt;[llvm_i1_ty], [llvm_ptr_ty, llvm_i1_ty, llvm_vararg_ty], []&gt;;
 def int_coro_end_async
     : Intrinsic&lt;[llvm_i1_ty], [llvm_ptr_ty, llvm_i1_ty, llvm_vararg_ty], []&gt;;
 
diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp
index eedde64203e09cc..cca7649c7a61e43 100644
--- a/llvm/lib/IR/AutoUpgrade.cpp
+++ b/llvm/lib/IR/AutoUpgrade.cpp
@@ -951,6 +951,12 @@ static bool UpgradeIntrinsicFunction1(Function *F, Function *&amp;NewFn) {
                                         F-&gt;arg_begin()-&gt;getType());
       return true;
     }
+    if (Name.equals(&quot;coro.end&quot;) &amp;&amp; !F-&gt;isVarArg()) {
+      rename(F);
+      NewFn = Intrinsic::getDeclaration(F-&gt;getParent(), Intrinsic::coro_end);
+      return true;
+    }
+
     break;
   }
   case &#x27;d&#x27;:
@@ -4207,6 +4213,12 @@ void llvm::UpgradeIntrinsicCall(CallBase *CI, Function *NewFn) {
     break;
   }
 
+  case Intrinsic::coro_end: {
+    SmallVector&lt;Value *, 2&gt; Args(CI-&gt;args());
+    NewCall = Builder.CreateCall(NewFn, Args);
+    break;
+  }
+
   case Intrinsic::vector_extract: {
     StringRef Name = F-&gt;getName();
     Name = Name.substr(5); // Strip llvm
diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp
index a12dd710174f3f8..2ab0d7d5854d7bb 100644
--- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp
@@ -3046,7 +3046,8 @@ void coro::buildCoroutineFrame(
   // Collect the spills for arguments and other not-materializable values.
   for (Argument &amp;A : F.args())
     for (User *U : A.users())
-      if (Checker.isDefinitionAcrossSuspend(A, U))
+      if (Checker.isDefinitionAcrossSuspend(A, U) ||
+          isa&lt;CoroEndInst&gt;(U))
         FrameData.Spills[&amp;A].push_back(cast&lt;Instruction&gt;(U));
 
   const DominatorTree DT(F);
diff --git a/llvm/lib/Transforms/Coroutines/CoroInstr.h b/llvm/lib/Transforms/Coroutines/CoroInstr.h
index 014938c15a0a3e0..98fa03c68fc2e02 100644
--- a/llvm/lib/Transforms/Coroutines/CoroInstr.h
+++ b/llvm/lib/Transforms/Coroutines/CoroInstr.h
@@ -633,6 +633,23 @@ class LLVM_LIBRARY_VISIBILITY AnyCoroEndInst : public IntrinsicInst {
 /// This represents the llvm.coro.end instruction.
 class LLVM_LIBRARY_VISIBILITY CoroEndInst : public AnyCoroEndInst {
 public:
+  op_iterator retval_begin() { return std::next(arg_begin(), 2); }
+  const_op_iterator retval_begin() const { return std::next(arg_begin(), 2); }
+
+  op_iterator retval_end() { return arg_end(); }
+  const_op_iterator retval_end() const { return arg_end(); }
+
+  iterator_range&lt;op_iterator&gt; return_values() {
+    return make_range(retval_begin(), retval_end());
+  }
+  iterator_range&lt;const_op_iterator&gt; return_values() const {
+    return make_range(retval_begin(), retval_end());
+  }
+
+  unsigned numReturns() const {
+    return std::distance(retval_begin(), retval_end());
+  }
+
   // Methods to support type inquiry through isa, cast, and dyn_cast:
   static bool classof(const IntrinsicInst *I) {
     return I-&gt;getIntrinsicID() == Intrinsic::coro_end;
diff --git a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
index 933771c2d08984a..5b3f37a10a9d830 100644
--- a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
@@ -234,6 +234,8 @@ static void replaceFallthroughCoroEnd(AnyCoroEndInst *End,
   switch (Shape.ABI) {
   // The cloned functions in switch-lowering always return void.
   case coro::ABI::Switch:
+    assert(cast&lt;CoroEndInst&gt;(End)-&gt;numReturns() == 0 &amp;&amp;
+           &quot;switch coroutine should not return any values&quot;);
     // coro.end doesn&#x27;t immediately end the coroutine in the main function
     // in this lowering, because we need to deallocate the coroutine.
     if (!InResume)
@@ -251,14 +253,35 @@ static void replaceFallthroughCoroEnd(AnyCoroEndInst *End,
 
   // In unique continuation lowering, the continuations always return void.
   // But we may have implicitly allocated storage.
-  case coro::ABI::RetconOnce:
+  case coro::ABI::RetconOnce: {
     maybeFreeRetconStorage(Builder, Shape, FramePtr, CG);
-    Builder.CreateRetVoid();
+    auto *CoroEnd = cast&lt;CoroEndInst&gt;(End);
+    auto *RetTy = Shape.getResumeFunctionType()-&gt;getReturnType();
+    unsigned NumReturns = CoroEnd-&gt;numReturns();
+
+    if (auto ...
<truncated>
</pre>
</details>


https://github.com/llvm/llvm-project/pull/66333


More information about the cfe-commits mailing list