https://github.com/Andres-Salamanca updated 
https://github.com/llvm/llvm-project/pull/213191

>From e12ca364ac24d0da2c0568c9a41040dc2f9e8003 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <[email protected]>
Date: Mon, 13 Jul 2026 14:34:45 -0500
Subject: [PATCH 1/4] initial coro_suspend

---
 clang/include/clang/CIR/Dialect/IR/CIROps.td  | 36 +++++++++++++++++++
 clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp     |  6 +++-
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp       | 12 +++++++
 .../test/CIR/CodeGenCoroutines/coro-task.cpp  | 12 +++----
 clang/test/CIR/IR/await.cir                   |  6 ++--
 clang/test/CIR/IR/co-return.cir               |  3 +-
 clang/test/CIR/IR/coro-body.cir               |  3 +-
 clang/test/CIR/IR/func.cir                    |  3 +-
 clang/test/CIR/IR/invalid-await.cir           | 18 +++++++++-
 clang/test/CIR/IR/invalid-coro-body.cir       |  3 +-
 clang/test/CIR/IR/invalid-coro-suspend.cir    | 17 +++++++++
 11 files changed, 105 insertions(+), 14 deletions(-)
 create mode 100644 clang/test/CIR/IR/invalid-coro-suspend.cir

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 49ecec207cd45..4a291cf69eaad 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4946,6 +4946,42 @@ def CIR_CoroSizeOp : CIR_CoroIntrinsicOp<"size", (ins),
   }];
 }
 
+//===----------------------------------------------------------------------===//
+// CoroSuspendPoint
+//===----------------------------------------------------------------------===//
+
+def CIR_CoroSuspendPoint : CIR_Op<"coro.suspend.point", [
+  Pure, Terminator, HasParent<"AwaitOp">
+]> {
+  let summary = "";
+  let description = [{
+  }];
+
+  let assemblyFormat = [{
+    attr-dict
+  }];
+
+  let hasLLVMLowering = false;
+}
+
+//===----------------------------------------------------------------------===//
+// CoroSuspendPointDest
+//===----------------------------------------------------------------------===//
+
+def CIR_CoroSuspendPointDest : CIR_Op<"coro.suspend.point.dest", [
+  Pure
+]> {
+  let summary = "";
+  let description = [{
+  }];
+
+  let assemblyFormat = [{
+    attr-dict
+  }];
+
+  let hasLLVMLowering = false;
+}
+
 
//===----------------------------------------------------------------------===//
 // CopyOp
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
index 9111c2ac98863..00d7a0f162380 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
@@ -15,6 +15,7 @@
 #include "clang/AST/StmtCXX.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/TargetInfo.h"
+#include "clang/CIR/Dialect/IR/CIRDialect.h"
 #include "clang/CIR/Dialect/IR/CIRTypes.h"
 #include "clang/CIR/MissingFeatures.h"
 
@@ -508,6 +509,9 @@ CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt 
&s) {
       cgm.getBuilder(), openCurlyLoc,
       mlir::ValueRange{builder.getNullPtr(builder.getVoidPtrTy(), 
openCurlyLoc),
                        builder.getBool(false, openCurlyLoc)});
+
+  cir::CoroSuspendPointDest::create(builder, openCurlyLoc);
+
   if (auto *ret = cast_or_null<ReturnStmt>(s.getReturnStmt())) {
     // Since we already emitted the return value above, so we shouldn't
     // emit it again here.
@@ -589,7 +593,7 @@ emitSuspendExpression(CIRGenFunction &cgf, CGCoroData &coro,
         }
 
         // Signals the parent that execution flows to next region.
-        cir::YieldOp::create(builder, loc);
+        cir::CoroSuspendPoint::create(builder,loc);
       },
       /*resumeBuilder=*/
       [&](mlir::OpBuilder &b, mlir::Location loc) {
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index cd94219655e02..556d746bbd8eb 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -31,6 +31,7 @@
 #include "llvm/ADT/SetOperations.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/TypeSwitch.h"
+#include "llvm/Support/Casting.h"
 #include "llvm/Support/LogicalResult.h"
 
 using namespace mlir;
@@ -2863,6 +2864,7 @@ mlir::LogicalResult cir::FuncOp::verify() {
   if (!isDeclaration() && getCoroutine()) {
     bool foundAwait = false;
     int coroBodyCount = 0;
+    int coroSuspendPointDestCount = 0;
     this->walk([&](Operation *op) {
       if (auto await = dyn_cast<AwaitOp>(op)) {
         foundAwait = true;
@@ -2871,6 +2873,11 @@ mlir::LogicalResult cir::FuncOp::verify() {
         if (coroBodyCount > 1) {
           return mlir::WalkResult::interrupt();
         }
+      } else if (isa<CoroSuspendPointDest>(op)) {
+        coroSuspendPointDestCount++;
+        if (coroSuspendPointDestCount > 1) {
+          return mlir::WalkResult::interrupt();
+        }
       }
       return mlir::WalkResult::advance();
     });
@@ -2880,6 +2887,9 @@ mlir::LogicalResult cir::FuncOp::verify() {
     if (coroBodyCount != 1)
       return emitOpError()
              << "coroutine function must have exactly one cir.body op";
+    if (coroSuspendPointDestCount != 1)
+      return emitOpError()
+             << "coroutine function must have exactly one 
cir.coro.suspend.point.dest";
   }
 
   llvm::SmallSet<llvm::StringRef, 16> labels;
@@ -3281,6 +3291,8 @@ mlir::ValueRange 
cir::AwaitOp::getSuccessorInputs(RegionSuccessor successor) {
 LogicalResult cir::AwaitOp::verify() {
   if (!isa<ConditionOp>(this->getReady().back().getTerminator()))
     return emitOpError("ready region must end with cir.condition");
+  if (!isa<CoroSuspendPoint>(this->getSuspend().back().getTerminator()))
+    return emitOpError("ready region must end with cir.coro.suspend.point");
   return success();
 }
 
diff --git a/clang/test/CIR/CodeGenCoroutines/coro-task.cpp 
b/clang/test/CIR/CodeGenCoroutines/coro-task.cpp
index d0ba8c153bdbb..1095d8821a707 100644
--- a/clang/test/CIR/CodeGenCoroutines/coro-task.cpp
+++ b/clang/test/CIR/CodeGenCoroutines/coro-task.cpp
@@ -125,7 +125,7 @@ VoidTask silly_task() {
 // CIR:     cir.call 
@_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIvE12promise_typeEEES_IT_E(%[[CoroHandleVoidAddr]],
 %[[CoroHandlePromiseReload]])
 // CIR:     %[[CoroHandleVoidReload:.*]] = cir.load{{.*}} 
%[[CoroHandleVoidAddr]] : !cir.ptr<![[CoroHandleVoid]]>, ![[CoroHandleVoid]]
 // CIR:     cir.call 
@_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SuspendAlwaysAddr]],
 %[[CoroHandleVoidReload]])
-// CIR:     cir.yield
+// CIR:     cir.coro.suspend.point
 
 // OGCG: init.suspend:
 // OGCG:   %[[Save:.*]] = call token @llvm.coro.save(ptr null)
@@ -258,7 +258,7 @@ folly::coro::Task<int> byRef(const std::string& s) {
 // CIR:       cir.call 
@_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIiE12promise_typeEEES_IT_E(%[[CoroHandleVoidAddr]],
 %[[CoroHandlePromiseReload]])
 // CIR:       %[[CoroHandleVoidReload:.*]] = cir.load{{.*}} 
%[[CoroHandleVoidAddr]] : !cir.ptr<![[CoroHandleVoid]]>, ![[CoroHandleVoid]]
 // CIR:       cir.call 
@_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SuspendAlwaysAddr]],
 %[[CoroHandleVoidReload]])
-// CIR:       cir.yield
+// CIR:       cir.coro.suspend.point
 // CIR:     }, resume : {
 // CIR:       cir.call 
@_ZNSt14suspend_always12await_resumeEv(%[[SuspendAlwaysAddr]])
 // CIR:       cir.yield
@@ -349,7 +349,7 @@ folly::coro::Task<void> yield1() {
 // CIR:     cir.call 
@_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIvE12promise_typeEEES_IT_E(%[[CH_VOID0]],
 %[[PROM_RELOAD0]]){{.*}}
 // CIR:     %[[VOID_RELOAD0:.*]] = cir.load{{.*}} %[[CH_VOID0]]
 // CIR:     cir.call 
@_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SUSP0]], 
%[[VOID_RELOAD0]]){{.*}}
-// CIR:     cir.yield
+// CIR:     cir.coro.suspend.point
 // CIR:   }, resume : {
 // CIR:     cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SUSP0]]){{.*}}
 // CIR:     cir.yield
@@ -372,7 +372,7 @@ folly::coro::Task<void> yield1() {
 // CIR:       cir.call 
@_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIvE12promise_typeEEES_IT_E(%[[CH_VOID1]],
 %[[PROM_RELOAD1]]){{.*}}
 // CIR:       %[[VOID_RELOAD1:.*]] = cir.load{{.*}} %[[CH_VOID1]]
 // CIR:       cir.call 
@_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SUSP1]], 
%[[VOID_RELOAD1]]){{.*}}
-// CIR:       cir.yield
+// CIR:       cir.coro.suspend.point
 // CIR:     }, resume : {
 // CIR:       cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SUSP1]]){{.*}}
 // CIR:       cir.yield
@@ -394,7 +394,7 @@ folly::coro::Task<void> yield1() {
 // CIR:     cir.call 
@_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIvE12promise_typeEEES_IT_E(%[[CH_VOID2]],
 %[[PROM_RELOAD2]]){{.*}}
 // CIR:     %[[VOID_RELOAD2:.*]] = cir.load{{.*}} %[[CH_VOID2]]
 // CIR:     cir.call 
@_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SUSP2]], 
%[[VOID_RELOAD2]]){{.*}}
-// CIR:     cir.yield
+// CIR:     cir.coro.suspend.point
 // CIR:   }, resume : {
 // CIR:     cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SUSP2]]){{.*}}
 // CIR:     cir.yield
@@ -543,7 +543,7 @@ folly::coro::Task<int> go4() {
 // CIR:    = cir.call @_ZN5folly4coro4TaskIiE11await_readyEv(%[[TASK_ADDR]])
 // CIR:    cir.condition(
 // CIR:  }, suspend : {
-// CIR:    cir.yield
+// CIR:    cir.coro.suspend.point
 // CIR:  }, resume : {
 // CIR:    cir.yield
 // CIR:  },)
diff --git a/clang/test/CIR/IR/await.cir b/clang/test/CIR/IR/await.cir
index 06b925bcc07b3..1305c4bb31e0f 100644
--- a/clang/test/CIR/IR/await.cir
+++ b/clang/test/CIR/IR/await.cir
@@ -5,12 +5,13 @@ cir.func coroutine @checkPrintParse(%arg0 : !cir.bool) {
     cir.await(user, ready : {
       cir.condition(%arg0)
     }, suspend : {
-      cir.yield
+      cir.coro.suspend.point
     }, resume : {
       cir.yield
     },)
     cir.yield
   }
+  cir.coro.suspend.point.dest
   cir.return
 }
 
@@ -18,7 +19,8 @@ cir.func coroutine @checkPrintParse(%arg0 : !cir.bool) {
 // CHECK:  cir.await(user, ready : {
 // CHECK:    cir.condition(%arg0)
 // CHECK:  }, suspend : {
-// CHECK:    cir.yield
+// CHECK:    cir.coro.suspend.point
 // CHECK:  }, resume : {
 // CHECK:    cir.yield
 // CHECK:  },)
+// CHECK:  cir.coro.suspend.point.dest
diff --git a/clang/test/CIR/IR/co-return.cir b/clang/test/CIR/IR/co-return.cir
index 613399b142650..d6c3be2da80ad 100644
--- a/clang/test/CIR/IR/co-return.cir
+++ b/clang/test/CIR/IR/co-return.cir
@@ -4,12 +4,13 @@ cir.func coroutine @coro_co_return(%arg0 : !cir.bool) {
     cir.await(user, ready : {
       cir.condition(%arg0)
     }, suspend : {
-      cir.yield
+      cir.coro.suspend.point
     }, resume : {
       cir.yield
     },)
     cir.co_return
   }
+  cir.coro.suspend.point.dest
   cir.return
 }
 
diff --git a/clang/test/CIR/IR/coro-body.cir b/clang/test/CIR/IR/coro-body.cir
index 1c0dae384691a..b1560485303b1 100644
--- a/clang/test/CIR/IR/coro-body.cir
+++ b/clang/test/CIR/IR/coro-body.cir
@@ -5,12 +5,13 @@ cir.func coroutine @coro_body(%arg0 : !cir.bool) {
     cir.await(user, ready : {
       cir.condition(%arg0)
     }, suspend : {
-      cir.yield
+      cir.coro.suspend.point
     }, resume : {
       cir.yield
     },)
     cir.co_return
   }
+  cir.coro.suspend.point.dest
   cir.return
 }
 
diff --git a/clang/test/CIR/IR/func.cir b/clang/test/CIR/IR/func.cir
index 4c6bd33b386ab..ffc3a503c8c48 100644
--- a/clang/test/CIR/IR/func.cir
+++ b/clang/test/CIR/IR/func.cir
@@ -115,12 +115,13 @@ cir.func coroutine @coro() {
       %1 = cir.load align(1) %0 : !cir.ptr<!cir.bool>, !cir.bool
       cir.condition(%1)
     }, suspend : {
-      cir.yield
+      cir.coro.suspend.point
     }, resume : {
       cir.yield
     },)
     cir.yield
   }
+  cir.coro.suspend.point.dest
   cir.return
 }
 // CHECK: cir.func{{.*}} coroutine @coro()
diff --git a/clang/test/CIR/IR/invalid-await.cir 
b/clang/test/CIR/IR/invalid-await.cir
index fe0fd76769e44..cc6d011718ad0 100644
--- a/clang/test/CIR/IR/invalid-await.cir
+++ b/clang/test/CIR/IR/invalid-await.cir
@@ -10,12 +10,28 @@ cir.func coroutine @missing_condition() {
     cir.await(user, ready : { // expected-error {{ready region must end with 
cir.condition}}
       cir.yield
     }, suspend : {
-      cir.yield
+      cir.coro.suspend.point
     }, resume : {
       cir.yield
     },)
   }
   cir.coro.body {
   }
+  cir.coro.suspend.point.dest
+  cir.return
+}
+
+cir.func coroutine @missing_suspend(%arg0 : !cir.bool) {
+  cir.coro.body {
+    cir.await(user, ready : { // expected-error {{ready region must end with 
cir.coro.suspend.point}}
+      cir.condition(%arg0)
+    }, suspend : {
+      cir.yield
+    }, resume : {
+      cir.yield
+    },)
+    cir.yield
+  }
+  cir.coro.suspend.point.dest
   cir.return
 }
diff --git a/clang/test/CIR/IR/invalid-coro-body.cir 
b/clang/test/CIR/IR/invalid-coro-body.cir
index e08c96192e5b5..f247220c7d73d 100644
--- a/clang/test/CIR/IR/invalid-coro-body.cir
+++ b/clang/test/CIR/IR/invalid-coro-body.cir
@@ -11,11 +11,12 @@ cir.func coroutine @must_have_one_coro_body(%arg0 : 
!cir.bool) {  // expected-er
     cir.await(user, ready : {
       cir.condition(%arg0)
     }, suspend : {
-      cir.yield
+      cir.coro.suspend.point
     }, resume : {
       cir.yield
     },)
   }
   cir.coro.body {
   }
+  cir.coro.suspend.point.dest
 }
diff --git a/clang/test/CIR/IR/invalid-coro-suspend.cir 
b/clang/test/CIR/IR/invalid-coro-suspend.cir
new file mode 100644
index 0000000000000..3a45e22433a58
--- /dev/null
+++ b/clang/test/CIR/IR/invalid-coro-suspend.cir
@@ -0,0 +1,17 @@
+// RUN: cir-opt %s -verify-diagnostics -split-input-file
+
+
+cir.func coroutine @must_have_one_coro_suspend_dest(%arg0 : !cir.bool) {  // 
expected-error {{coroutine function must have exactly one 
cir.coro.suspend.point.dest}}
+  cir.coro.body {
+    cir.await(user, ready : {
+      cir.condition(%arg0)
+    }, suspend : {
+      cir.coro.suspend.point
+    }, resume : {
+      cir.yield
+    },)
+  }
+  cir.coro.suspend.point.dest
+  cir.coro.suspend.point.dest
+}
+

>From 8a3e7a6644abcc6630345cac7b50949bd9b0d384 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <[email protected]>
Date: Thu, 30 Jul 2026 21:15:54 -0500
Subject: [PATCH 2/4] [CIR] Add structured control flow for coroutine suspend
 points

---
 clang/include/clang/CIR/Dialect/IR/CIROps.td  |  78 +-
 clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp     |  32 +-
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp       |  82 +-
 .../test/CIR/CodeGenCoroutines/coro-task.cpp  | 709 +++++++++---------
 clang/test/CIR/IR/await.cir                   |  25 +-
 clang/test/CIR/IR/co-return.cir               |  26 +-
 clang/test/CIR/IR/coro-body.cir               |  26 +-
 clang/test/CIR/IR/coro-ret-point.cir          |  23 +
 clang/test/CIR/IR/func.cir                    |  26 +-
 clang/test/CIR/IR/invalid-await.cir           |  36 +-
 clang/test/CIR/IR/invalid-coro-body.cir       |   3 +-
 clang/test/CIR/IR/invalid-coro-ret-point.cir  |  55 ++
 clang/test/CIR/IR/invalid-coro-suspend.cir    |  30 +-
 13 files changed, 716 insertions(+), 435 deletions(-)
 create mode 100644 clang/test/CIR/IR/coro-ret-point.cir
 create mode 100644 clang/test/CIR/IR/invalid-coro-ret-point.cir

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 4a291cf69eaad..8d0ec7f0c98bb 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -936,7 +936,7 @@ def CIR_StoreOp : CIR_Op<"store", [
 
 defvar CIR_ReturnableScopes = [
   "FuncOp", "ScopeOp", "IfOp", "SwitchOp", "CaseOp", "CleanupScopeOp",
-  "DoWhileOp", "WhileOp", "ForOp", "TryOp"
+  "DoWhileOp", "WhileOp", "ForOp", "TryOp", "CoroRetPointOp"
 ];
 
 def CIR_ReturnOp : CIR_Op<"return", [
@@ -1087,7 +1087,7 @@ def CIR_ConditionOp : CIR_Op<"condition", [
 defvar CIR_YieldableScopes = [
   "ArrayCtor", "ArrayDtor", "AwaitOp", "CaseOp", "CleanupScopeOp", 
"CoroBodyOp",
   "DoWhileOp", "ForOp", "GlobalOp", "IfOp", "LocalInitOp", "ScopeOp", 
"SwitchOp",
-  "TernaryOp", "TryOp", "WhileOp"
+  "TernaryOp", "TryOp", "WhileOp", "CoroRetPointOp"
 ];
 
 def CIR_YieldOp : CIR_Op<"yield", [
@@ -4950,11 +4950,36 @@ def CIR_CoroSizeOp : CIR_CoroIntrinsicOp<"size", (ins),
 // CoroSuspendPoint
 
//===----------------------------------------------------------------------===//
 
-def CIR_CoroSuspendPoint : CIR_Op<"coro.suspend.point", [
-  Pure, Terminator, HasParent<"AwaitOp">
+def CIR_CoroSuspendPoint : CIR_Op<"coro.suspend_point", [
+  Pure, Terminator, HasParent<"AwaitOp">, HasAncestor<"CoroRetPointOp">
 ]> {
-  let summary = "";
+  let summary = "Marks the point where a coroutine actually suspends";
   let description = [{
+    Terminates the `suspend` region of a `cir.await` op, marking the exact
+    point where control returns to the caller/resumer if the coroutine
+    decides to suspend.
+
+    This op must appear inside the `suspend` region of a `cir.await`, and
+    that `cir.await` must in turn be nested within a `cir.coro.ret_point`.
+    During lowering to FlattenCFG, `cir.coro.suspend_point` becomes the
+    branch target that routes control to one of three destinations
+    depending on how the coroutine resumes: the resume block (normal
+    continuation), the cleanup/destroy block, or the ret/exit block that
+    hands control back to the caller.
+
+    Example:
+    ```mlir
+    cir.await(user, ready : {
+      ...
+      cir.condition(%ready)
+    }, suspend : {
+      ...
+      cir.coro.suspend_point
+    }, resume : {
+      ...
+      cir.yield
+    },)
+    ```
   }];
 
   let assemblyFormat = [{
@@ -4965,21 +4990,54 @@ def CIR_CoroSuspendPoint : CIR_Op<"coro.suspend.point", 
[
 }
 
 
//===----------------------------------------------------------------------===//
-// CoroSuspendPointDest
+// CoroRetPoint
 
//===----------------------------------------------------------------------===//
 
-def CIR_CoroSuspendPointDest : CIR_Op<"coro.suspend.point.dest", [
-  Pure
+def CIR_CoroRetPointOp : CIR_Op<"coro.ret_point", [
+  DeclareOpInterfaceMethods<RegionBranchOpInterface, ["getSuccessorInputs"]>,
+  NoRegionArguments
 ]> {
-  let summary = "";
+
+  let summary = "Marks the coroutine's structured suspend/exit region";
   let description = [{
+    Pairs a coroutine's body its normal execution, including any
+    `cir.await`s and cleanups with a single, shared exit destination
+    (`retRegion`) that every suspend point in the body jumps to.
+
+    Every `cir.coro.suspend_point` inside `bodyRegion` is guaranteed to have
+    `cir.coro.ret_point` as an ancestor, so all suspend paths converge on
+    the same `retRegion` regardless of where in the body they occur. This
+    gives the coroutine a single, well-defined place to run final teardown
+    (e.g. `__builtin_coro_end`) and return control to the caller.
+
+    Example:
+    ```mlir
+    cir.coro.ret_point {
+      // body: awaits, cleanups, etc.
+    }, ret : {
+      // shared jump target for any suspend point in the body
+      cir.coro.intrinsic.end(...)
+      cir.return
+    }
+    ```
   }];
 
+  let regions = (region AnyRegion:$bodyRegion,
+                        AnyRegion:$retRegion);
+   let skipDefaultBuilders = 1;
+
+  let builders = [
+    OpBuilder<(ins "BuilderCallbackRef":$bodyBuilder,
+      "BuilderCallbackRef":$retBuilder)>
+  ];
+
   let assemblyFormat = [{
+    $bodyRegion `,`
+    `ret` `:` $retRegion
     attr-dict
   }];
-
   let hasLLVMLowering = false;
+  let hasVerifier = 1;
 }
 
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
index 00d7a0f162380..7fc59b30e8c3a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
@@ -15,8 +15,6 @@
 #include "clang/AST/StmtCXX.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/TargetInfo.h"
-#include "clang/CIR/Dialect/IR/CIRDialect.h"
-#include "clang/CIR/Dialect/IR/CIRTypes.h"
 #include "clang/CIR/MissingFeatures.h"
 
 using namespace clang;
@@ -376,11 +374,25 @@ CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt 
&s) {
   // Handle allocation failure if 'ReturnStmtOnAllocFailure' was provided.
   if (s.getReturnStmtOnAllocFailure())
     cgm.errorNYI("handle coroutine return alloc failure");
-
+  cir::CoroRetPointOp coroRet = nullptr;
+  mlir::OpBuilder::InsertPoint coroRetRegion;
   {
     assert(!cir::MissingFeatures::generateDebugInfo());
     ParamReferenceReplacerRAII paramReplacer(localDeclMap);
     RunCleanupsScope resumeScope(*this);
+    mlir::OpBuilder::InsertPoint coroRetBody;
+    coroRet = cir::CoroRetPointOp::create(
+        builder, openCurlyLoc,
+        /*bodyBuilder=*/
+        [&](mlir::OpBuilder &b, mlir::Location) {
+          coroRetBody = b.saveInsertionPoint();
+        },
+        /*retBuilder=*/
+        [&](mlir::OpBuilder &b, mlir::Location) {
+          coroRetRegion = b.saveInsertionPoint();
+        });
+    mlir::OpBuilder::InsertionGuard guard(builder);
+    builder.restoreInsertionPoint(coroRetBody);
     ehStack.pushCleanup<CallCoroDelete>(NormalAndEHCleanup, s.getDeallocate());
     // Create mapping between parameters and copy-params for coroutine
     // function.
@@ -510,7 +522,15 @@ CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt 
&s) {
       mlir::ValueRange{builder.getNullPtr(builder.getVoidPtrTy(), 
openCurlyLoc),
                        builder.getBool(false, openCurlyLoc)});
 
-  cir::CoroSuspendPointDest::create(builder, openCurlyLoc);
+  mlir::Block &coroRetBodyBlock = coroRet.getBodyRegion().back();
+  {
+    mlir::OpBuilder::InsertionGuard guard(builder);
+    builder.setInsertionPointToEnd(&coroRetBodyBlock);
+    cir::YieldOp::create(builder, openCurlyLoc);
+  }
+
+  mlir::OpBuilder::InsertionGuard guard(builder);
+  builder.restoreInsertionPoint(coroRetRegion);
 
   if (auto *ret = cast_or_null<ReturnStmt>(s.getReturnStmt())) {
     // Since we already emitted the return value above, so we shouldn't
@@ -519,6 +539,10 @@ CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt 
&s) {
     ret->setRetValue(nullptr);
     if (emitStmt(ret, /*useCurrentScope=*/true).failed())
       return mlir::failure();
+    mlir::Block *block = builder.getInsertionBlock();
+    // emitReturnStmt() always creates a new insertion block after emitting the
+    // return. That block is unreachable in this case, so erase it.
+    block->erase();
     // Set the return value back. The code generator, as the AST **Consumer**,
     // shouldn't change the AST.
     ret->setRetValue(previousRetValue);
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 556d746bbd8eb..950d092c1f95d 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -2864,7 +2864,7 @@ mlir::LogicalResult cir::FuncOp::verify() {
   if (!isDeclaration() && getCoroutine()) {
     bool foundAwait = false;
     int coroBodyCount = 0;
-    int coroSuspendPointDestCount = 0;
+    int coroRetPointCount = 0;
     this->walk([&](Operation *op) {
       if (auto await = dyn_cast<AwaitOp>(op)) {
         foundAwait = true;
@@ -2873,9 +2873,9 @@ mlir::LogicalResult cir::FuncOp::verify() {
         if (coroBodyCount > 1) {
           return mlir::WalkResult::interrupt();
         }
-      } else if (isa<CoroSuspendPointDest>(op)) {
-        coroSuspendPointDestCount++;
-        if (coroSuspendPointDestCount > 1) {
+      } else if (isa<CoroRetPointOp>(op)) {
+        coroRetPointCount++;
+        if (coroRetPointCount > 1) {
           return mlir::WalkResult::interrupt();
         }
       }
@@ -2887,9 +2887,9 @@ mlir::LogicalResult cir::FuncOp::verify() {
     if (coroBodyCount != 1)
       return emitOpError()
              << "coroutine function must have exactly one cir.body op";
-    if (coroSuspendPointDestCount != 1)
-      return emitOpError()
-             << "coroutine function must have exactly one 
cir.coro.suspend.point.dest";
+    if (coroRetPointCount != 1)
+      return emitOpError() << "coroutine function must have exactly one "
+                              "cir.coro.ret_point op";
   }
 
   llvm::SmallSet<llvm::StringRef, 16> labels;
@@ -3292,7 +3292,7 @@ LogicalResult cir::AwaitOp::verify() {
   if (!isa<ConditionOp>(this->getReady().back().getTerminator()))
     return emitOpError("ready region must end with cir.condition");
   if (!isa<CoroSuspendPoint>(this->getSuspend().back().getTerminator()))
-    return emitOpError("ready region must end with cir.coro.suspend.point");
+    return emitOpError("suspend region must end with cir.coro.suspend_point");
   return success();
 }
 
@@ -3332,6 +3332,72 @@ void cir::CoroBodyOp::build(OpBuilder &builder, 
OperationState &result,
   bodyBuilder(builder, result.location);
 }
 
+//===----------------------------------------------------------------------===//
+// CoroRetPoint
+//===----------------------------------------------------------------------===//
+
+void cir::CoroRetPointOp::build(OpBuilder &builder, OperationState &result,
+                                BuilderCallbackRef bodyBuilder,
+                                BuilderCallbackRef retBuilder) {
+  {
+    OpBuilder::InsertionGuard guard(builder);
+    Region *bodyRegion = result.addRegion();
+    builder.createBlock(bodyRegion);
+    bodyBuilder(builder, result.location);
+  }
+
+  {
+    OpBuilder::InsertionGuard guard(builder);
+    Region *retRegion = result.addRegion();
+    builder.createBlock(retRegion);
+    retBuilder(builder, result.location);
+  }
+}
+
+void cir::CoroRetPointOp::getSuccessorRegions(
+    mlir::RegionBranchPoint point, SmallVectorImpl<RegionSuccessor> &regions) {
+  if (!point.isParent()) {
+    regions.emplace_back(getOperation());
+    return;
+  }
+
+  regions.push_back(RegionSuccessor(&getBodyRegion()));
+  regions.push_back(RegionSuccessor(&getRetRegion()));
+}
+
+mlir::ValueRange
+cir::CoroRetPointOp::getSuccessorInputs(RegionSuccessor successor) {
+  return ValueRange();
+}
+
+LogicalResult cir::CoroRetPointOp::verify() {
+
+  // TODO: Should we verify that the return region contains a
+  // `cir.coro.intrinsic.end`? Coroutine semantics require `coro.end` to mark
+  // the end of access to the coroutine frame before the coroutine completes.
+  bool hasReturn = false;
+  this->getBodyRegion().walk<mlir::WalkOrder::PreOrder>(
+      [&](mlir::Operation *op) {
+        if (mlir::isa<cir::ReturnOp>(op)) {
+          hasReturn = true;
+          return WalkResult::interrupt();
+        }
+        return WalkResult::advance();
+      });
+
+  if (hasReturn)
+    return emitError()
+           << "body region must not contain 'cir.return' operations";
+
+  if (!mlir::isa<cir::YieldOp>(this->getBodyRegion().back().back()))
+    return emitError() << "body region must terminate with 'cir.yield'";
+
+  if (!mlir::isa<cir::ReturnOp>(this->getRetRegion().back().back()))
+    return emitError() << "return region must terminate with 'cir.return'";
+
+  return mlir::success();
+}
+
 
//===----------------------------------------------------------------------===//
 // CopyOp Definitions
 
//===----------------------------------------------------------------------===//
diff --git a/clang/test/CIR/CodeGenCoroutines/coro-task.cpp 
b/clang/test/CIR/CodeGenCoroutines/coro-task.cpp
index 1095d8821a707..ad07e8d43b333 100644
--- a/clang/test/CIR/CodeGenCoroutines/coro-task.cpp
+++ b/clang/test/CIR/CodeGenCoroutines/coro-task.cpp
@@ -74,11 +74,11 @@ VoidTask silly_task() {
 
 // Call promise.get_return_object() to retrieve the task object.
 
+// CIR: cir.coro.ret_point {
+// CIR:   cir.cleanup.scope {
 
-// CIR: cir.cleanup.scope {
-
-// CIR:   %[[RetObj:.*]] = cir.call 
@_ZN5folly4coro4TaskIvE12promise_type17get_return_objectEv(%[[VoidPromisseAddr]])
 nothrow : {{.*}} -> ![[VoidTask]]
-// CIR:   cir.store{{.*}} %[[RetObj]], %[[VoidTaskAddr]] : ![[VoidTask]]
+// CIR:     %[[RetObj:.*]] = cir.call 
@_ZN5folly4coro4TaskIvE12promise_type17get_return_objectEv(%[[VoidPromisseAddr]])
 nothrow : {{.*}} -> ![[VoidTask]]
+// CIR:     cir.store{{.*}} %[[RetObj]], %[[VoidTaskAddr]] : ![[VoidTask]]
 
 // OGCG: call void @llvm.lifetime.start.p0(ptr %[[VoidPromisseAddr]])
 // OGCG: call void 
@_ZN5folly4coro4TaskIvE12promise_type17get_return_objectEv(ptr noundef nonnull 
align 1 dereferenceable(1) %[[VoidPromisseAddr]])
@@ -91,8 +91,8 @@ VoidTask silly_task() {
 // the suspend_always struct to use for cir.await. Note that we return 
by-value since we defer ABI lowering
 // to later passes, same is done elsewhere.
 
-// CIR:   %[[Tmp0:.*]] = cir.call 
@_ZN5folly4coro4TaskIvE12promise_type15initial_suspendEv(%[[VoidPromisseAddr]])
-// CIR:   cir.store{{.*}} %[[Tmp0:.*]], %[[SuspendAlwaysAddr]]
+// CIR:     %[[Tmp0:.*]] = cir.call 
@_ZN5folly4coro4TaskIvE12promise_type15initial_suspendEv(%[[VoidPromisseAddr]])
+// CIR:     cir.store{{.*}} %[[Tmp0:.*]], %[[SuspendAlwaysAddr]]
 
 // OGCG: call void 
@_ZN5folly4coro4TaskIvE12promise_type15initial_suspendEv(ptr noundef nonnull 
align 1 dereferenceable(1) %[[VoidPromisseAddr]])
 
@@ -102,9 +102,9 @@ VoidTask silly_task() {
 
 // First regions `ready` has a special cir.yield code to veto suspension.
 
-// CIR:   cir.await(init, ready : {
-// CIR:     %[[ReadyVeto:.*]] = cir.call 
@_ZNSt14suspend_always11await_readyEv(%[[SuspendAlwaysAddr]])
-// CIR:     cir.condition(%[[ReadyVeto]])
+// CIR:     cir.await(init, ready : {
+// CIR:       %[[ReadyVeto:.*]] = cir.call 
@_ZNSt14suspend_always11await_readyEv(%[[SuspendAlwaysAddr]])
+// CIR:       cir.condition(%[[ReadyVeto]])
 
 // OGCG: %[[Tmp0:.*]] = call noundef zeroext i1 
@_ZNSt14suspend_always11await_readyEv(ptr noundef nonnull align 1 
dereferenceable(1) %[[SuspendAlwaysAddr]])
 // OGCG: br i1 %[[Tmp0]], label %init.ready, label %init.suspend
@@ -118,14 +118,14 @@ VoidTask silly_task() {
 //
 // FIXME: add veto support for non-void await_suspends.
 
-// CIR:   }, suspend : {
-// CIR:     %[[FromAddrRes:.*]] = cir.call 
@_ZNSt16coroutine_handleIN5folly4coro4TaskIvE12promise_typeEE12from_addressEPv(%[[CoroFrameAddr]])
-// CIR:     cir.store{{.*}} %[[FromAddrRes]], %[[CoroHandlePromiseAddr]] : 
![[CoroHandlePromiseVoid]]
-// CIR:     %[[CoroHandlePromiseReload:.*]] = cir.load{{.*}} 
%[[CoroHandlePromiseAddr]]
-// CIR:     cir.call 
@_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIvE12promise_typeEEES_IT_E(%[[CoroHandleVoidAddr]],
 %[[CoroHandlePromiseReload]])
-// CIR:     %[[CoroHandleVoidReload:.*]] = cir.load{{.*}} 
%[[CoroHandleVoidAddr]] : !cir.ptr<![[CoroHandleVoid]]>, ![[CoroHandleVoid]]
-// CIR:     cir.call 
@_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SuspendAlwaysAddr]],
 %[[CoroHandleVoidReload]])
-// CIR:     cir.coro.suspend.point
+// CIR:     }, suspend : {
+// CIR:       %[[FromAddrRes:.*]] = cir.call 
@_ZNSt16coroutine_handleIN5folly4coro4TaskIvE12promise_typeEE12from_addressEPv(%[[CoroFrameAddr]])
+// CIR:       cir.store{{.*}} %[[FromAddrRes]], %[[CoroHandlePromiseAddr]] : 
![[CoroHandlePromiseVoid]]
+// CIR:       %[[CoroHandlePromiseReload:.*]] = cir.load{{.*}} 
%[[CoroHandlePromiseAddr]]
+// CIR:       cir.call 
@_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIvE12promise_typeEEES_IT_E(%[[CoroHandleVoidAddr]],
 %[[CoroHandlePromiseReload]])
+// CIR:       %[[CoroHandleVoidReload:.*]] = cir.load{{.*}} 
%[[CoroHandleVoidAddr]] : !cir.ptr<![[CoroHandleVoid]]>, ![[CoroHandleVoid]]
+// CIR:       cir.call 
@_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SuspendAlwaysAddr]],
 %[[CoroHandleVoidReload]])
+// CIR:       cir.coro.suspend_point
 
 // OGCG: init.suspend:
 // OGCG:   %[[Save:.*]] = call token @llvm.coro.save(ptr null)
@@ -138,10 +138,10 @@ VoidTask silly_task() {
 
 // Third region `resume` handles coroutine resuming logic.
 
-// CIR:   }, resume : {
-// CIR:     cir.call 
@_ZNSt14suspend_always12await_resumeEv(%[[SuspendAlwaysAddr]])
-// CIR:     cir.yield
-// CIR:   },)
+// CIR:     }, resume : {
+// CIR:       cir.call 
@_ZNSt14suspend_always12await_resumeEv(%[[SuspendAlwaysAddr]])
+// CIR:       cir.yield
+// CIR:     },)
 
 // OGCG: init.ready:
 // OGCG:   call void @_ZNSt14suspend_always12await_resumeEv(ptr noundef 
nonnull align 1 dereferenceable(1) %[[SuspendAlwaysAddr]]
@@ -153,31 +153,31 @@ VoidTask silly_task() {
 // - The final suspend co_await
 // - Return
 
-// CIR:   cir.coro.body {
+// CIR:     cir.coro.body {
 
 // The actual user written co_await
-// CIR:     cir.await(user, ready : {
-// CIR:     }, suspend : {
-// CIR:     }, resume : {
-// CIR:     },)
+// CIR:       cir.await(user, ready : {
+// CIR:       }, suspend : {
+// CIR:       }, resume : {
+// CIR:       },)
 
 // OGCG: cleanup.cont
 // OGCG: await.suspend:
 // OGCG: await.ready:
 
 // The promise call
-// CIR:     cir.call 
@_ZN5folly4coro4TaskIvE12promise_type11return_voidEv(%[[VoidPromisseAddr]])
-// CIR:     cir.co_return
-// CIR:   }
+// CIR:       cir.call 
@_ZN5folly4coro4TaskIvE12promise_type11return_voidEv(%[[VoidPromisseAddr]])
+// CIR:       cir.co_return
+// CIR:     }
 
 // OGCG: call void @_ZN5folly4coro4TaskIvE12promise_type11return_voidEv(ptr 
noundef nonnull align 1 dereferenceable(1) %[[VoidPromisseAddr]])
 
 // The final suspend co_await
-// CIR:   cir.await(final, ready : {
-// CIR:   }, suspend : {
-// CIR:   }, resume : {
-// CIR:   },)
-// CIR:   cir.yield
+// CIR:     cir.await(final, ready : {
+// CIR:     }, suspend : {
+// CIR:     }, resume : {
+// CIR:     },)
+// CIR:     cir.yield
 
 // OGCG: coro.final:
 // OGCG: final.suspend:
@@ -189,16 +189,17 @@ VoidTask silly_task() {
 // If null, no dynamic allocation happened, so nothing to free.
 // The `if` ensures we only call delete on non-null.
 
-// CIR: } cleanup  normal {
-// CIR:   %[[FreeMem:.*]] = cir.coro.intrinsic.free(%[[CoroId]], 
%[[CoroFrameAddr]]) : (token, !cir.ptr<!void>) -> !cir.ptr<!void>
-// CIR:   %[[NullPtr2:.*]] = cir.const #cir.ptr<null>
-// CIR:   %[[Cond:.*]] = cir.cmp ne %[[FreeMem]], %[[NullPtr2]]
-// CIR:   cir.if %[[Cond]] {
-// CIR:     %[[Size:.*]] = cir.coro.intrinsic.size()
-// CIR:     cir.call @_ZdlPvm(%[[FreeMem]], %[[Size]])
+// CIR:   } cleanup  normal {
+// CIR:     %[[FreeMem:.*]] = cir.coro.intrinsic.free(%[[CoroId]], 
%[[CoroFrameAddr]]) : (token, !cir.ptr<!void>) -> !cir.ptr<!void>
+// CIR:     %[[NullPtr2:.*]] = cir.const #cir.ptr<null>
+// CIR:     %[[Cond:.*]] = cir.cmp ne %[[FreeMem]], %[[NullPtr2]]
+// CIR:     cir.if %[[Cond]] {
+// CIR:       %[[Size:.*]] = cir.call @__builtin_coro_size()
+// CIR:       cir.call @_ZdlPvm(%[[FreeMem]], %[[Size]])
+// CIR:     }
+// CIR:     cir.yield
 // CIR:   }
-// CIR:   cir.yield
-// CIR: }
+// CIR: cir.yield
 
 // OGCG: %[[FreeMem:.*]] = call ptr @llvm.coro.free(token %[[CoroId]], ptr 
%[[CoroFrameAddr]])
 // OGCG: %[[Cond:.*]] = icmp ne ptr %[[FreeMem]], null
@@ -212,13 +213,17 @@ VoidTask silly_task() {
 
 // Call builtin coro end and return
 
-// CIR: %[[CoroEndArg0:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!void>
-// CIR: %[[CoroEndArg1:.*]] = cir.const #false
-// CIR: = cir.coro.intrinsic.end(%[[CoroEndArg0]], %[[CoroEndArg1]]) : 
(!cir.ptr<!void>, !cir.bool) -> !cir.bool
 
-// CIR: %[[Tmp1:.*]] = cir.load{{.*}} %[[VoidTaskAddr]]
-// CIR: cir.return %[[Tmp1]]
-// CIR: }
+// CIR: }, ret : {
+// CIR:   %[[CoroEndArg0:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!void>
+// CIR:   %[[CoroEndArg1:.*]] = cir.const #false
+// CIR:   = cir.coro.intrinsic.end(%[[CoroEndArg0]], %[[CoroEndArg1]]) : 
(!cir.ptr<!void>, !cir.bool) -> !cir.bool
+// CIR:   %[[Tmp1:.*]] = cir.load{{.*}} %[[VoidTaskAddr]]
+// CIR:   cir.return %[[Tmp1]]
+// CIR:   }
+// CIRL }
+// CIR: cir.trap
+// CIR:}
 
 // OGCG: coro.ret:
 // OGCG:   call void @llvm.coro.end(ptr null, i1 false, token none)
@@ -239,46 +244,49 @@ folly::coro::Task<int> byRef(const std::string& s) {
 // CIR:    %[[CoroHandlePromiseAddr:.*]] = cir.alloca "agg.tmp1" {{.*}} : 
!cir.ptr<![[CoroHandlePromiseInt]]>
 // CIR:    cir.store %[[ARG]], %[[AllocaParam]] : !cir.ptr<![[StdString]]>, 
{{.*}}
 
-// CIR:    cir.cleanup.scope {
+// CIR:    cir.coro.ret_point {
+// CIR:     cir.cleanup.scope {
 // Call promise.get_return_object() to retrieve the task object.
 
-// CIR:     %[[LOAD:.*]] = cir.load %[[AllocaParam]] : 
!cir.ptr<!cir.ptr<![[StdString]]>>, !cir.ptr<![[StdString]]>
-// CIR:     cir.store {{.*}} %[[LOAD]], %[[AllocaFnUse]] : 
!cir.ptr<![[StdString]]>, !cir.ptr<!cir.ptr<![[StdString]]>>
-// CIR:     %[[RetObj:.*]] = cir.call 
@_ZN5folly4coro4TaskIiE12promise_type17get_return_objectEv(%[[IntPromisseAddr]])
 nothrow : {{.*}} -> ![[IntTask]]
-// CIR:     cir.store {{.*}} %[[RetObj]], %[[IntTaskAddr]] : ![[IntTask]]
-// CIR:     %[[Tmp0:.*]] = cir.call 
@_ZN5folly4coro4TaskIiE12promise_type15initial_suspendEv(%[[IntPromisseAddr]])
-// CIR:     cir.store{{.*}} %[[Tmp0]], %[[SuspendAlwaysAddr]]
-// CIR:     cir.await(init, ready : {
-// CIR:       %[[TmpCallRes:.*]] = cir.call 
@_ZNSt14suspend_always11await_readyEv(%[[SuspendAlwaysAddr]])
-// CIR:       cir.condition(%[[TmpCallRes]])
-// CIR:     }, suspend : {
-// CIR:       %[[FromAddrRes:.*]] = cir.call 
@_ZNSt16coroutine_handleIN5folly4coro4TaskIiE12promise_typeEE12from_addressEPv(%[[CoroFrameAddr:.*]])
-// CIR:       cir.store{{.*}} %[[FromAddrRes]], %[[CoroHandlePromiseAddr]] : 
![[CoroHandlePromiseInt]]
-// CIR:       %[[CoroHandlePromiseReload:.*]] = cir.load{{.*}} 
%[[CoroHandlePromiseAddr]]
-// CIR:       cir.call 
@_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIiE12promise_typeEEES_IT_E(%[[CoroHandleVoidAddr]],
 %[[CoroHandlePromiseReload]])
-// CIR:       %[[CoroHandleVoidReload:.*]] = cir.load{{.*}} 
%[[CoroHandleVoidAddr]] : !cir.ptr<![[CoroHandleVoid]]>, ![[CoroHandleVoid]]
-// CIR:       cir.call 
@_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SuspendAlwaysAddr]],
 %[[CoroHandleVoidReload]])
-// CIR:       cir.coro.suspend.point
-// CIR:     }, resume : {
-// CIR:       cir.call 
@_ZNSt14suspend_always12await_resumeEv(%[[SuspendAlwaysAddr]])
-// CIR:       cir.yield
-// CIR:     },)
-// CIR:     cir.coro.body {
+// CIR:       %[[LOAD:.*]] = cir.load %[[AllocaParam]] : 
!cir.ptr<!cir.ptr<![[StdString]]>>, !cir.ptr<![[StdString]]>
+// CIR:       cir.store {{.*}} %[[LOAD]], %[[AllocaFnUse]] : 
!cir.ptr<![[StdString]]>, !cir.ptr<!cir.ptr<![[StdString]]>>
+// CIR:       %[[RetObj:.*]] = cir.call 
@_ZN5folly4coro4TaskIiE12promise_type17get_return_objectEv(%[[IntPromisseAddr]])
 nothrow : {{.*}} -> ![[IntTask]]
+// CIR:       cir.store {{.*}} %[[RetObj]], %[[IntTaskAddr]] : ![[IntTask]]
+// CIR:       %[[Tmp0:.*]] = cir.call 
@_ZN5folly4coro4TaskIiE12promise_type15initial_suspendEv(%[[IntPromisseAddr]])
+// CIR:       cir.store{{.*}} %[[Tmp0]], %[[SuspendAlwaysAddr]]
+// CIR:       cir.await(init, ready : {
+// CIR:         %[[TmpCallRes:.*]] = cir.call 
@_ZNSt14suspend_always11await_readyEv(%[[SuspendAlwaysAddr]])
+// CIR:         cir.condition(%[[TmpCallRes]])
+// CIR:       }, suspend : {
+// CIR:         %[[FromAddrRes:.*]] = cir.call 
@_ZNSt16coroutine_handleIN5folly4coro4TaskIiE12promise_typeEE12from_addressEPv(%[[CoroFrameAddr:.*]])
+// CIR:         cir.store{{.*}} %[[FromAddrRes]], %[[CoroHandlePromiseAddr]] : 
![[CoroHandlePromiseInt]]
+// CIR:         %[[CoroHandlePromiseReload:.*]] = cir.load{{.*}} 
%[[CoroHandlePromiseAddr]]
+// CIR:         cir.call 
@_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIiE12promise_typeEEES_IT_E(%[[CoroHandleVoidAddr]],
 %[[CoroHandlePromiseReload]])
+// CIR:         %[[CoroHandleVoidReload:.*]] = cir.load{{.*}} 
%[[CoroHandleVoidAddr]] : !cir.ptr<![[CoroHandleVoid]]>, ![[CoroHandleVoid]]
+// CIR:         cir.call 
@_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SuspendAlwaysAddr]],
 %[[CoroHandleVoidReload]])
+// CIR:         cir.coro.suspend_point
+// CIR:       }, resume : {
+// CIR:         cir.call 
@_ZNSt14suspend_always12await_resumeEv(%[[SuspendAlwaysAddr]])
+// CIR:         cir.yield
+// CIR:       },)
+// CIR:       cir.coro.body {
               // can't fallthrough
-// CIR-NOT:   cir.await(user
-// CIR:       cir.call 
@_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[IntPromisseAddr]], 
%[[STRING_SIZE:.*]])
-//CIR:        cir.co_return
-// CIR:     }
+// CIR-NOT:     cir.await(user
+// CIR:         cir.call 
@_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[IntPromisseAddr]], 
%[[STRING_SIZE:.*]])
+//CIR:          cir.co_return
+// CIR:       }
 
 
 // The final suspend co_await
-// CIR:     cir.await(final, ready : {
-// CIR:     }, suspend : {
-// CIR:     }, resume : {
-// CIR:     },)
+// CIR:      cir.await(final, ready : {
+// CIR:      }, suspend : {
+// CIR:      }, resume : {
+// CIR:      },)
+// CIR:      cir.yield
+// CIR:     } cleanup  normal {
+// CIR:     }
 // CIR:     cir.yield
-// CIR:    } cleanup  normal {
-// CIR:    }
+// CIR:    }, ret : {
 
 folly::coro::Task<void> silly_coro() {
   std::optional<folly::coro::Task<int>> task;
@@ -294,22 +302,24 @@ folly::coro::Task<void> silly_coro() {
 // check there are not multiple co_returns emitted.
 
 // CIR: cir.func coroutine {{.*}} @_Z10silly_corov() {{.*}} ![[VoidTask]]
-// CIR: cir.cleanup.scope {
-// CIR:   cir.await(init, ready : {
-// CIR:   }, suspend : {
-// CIR:   }, resume : {
-// CIR:   },)
-// CIR:   cir.coro.body {
-// CIR:     cir.call @_ZN5folly4coro4TaskIvE12promise_type11return_voidEv
-// CIR:     cir.co_return
+// CIR:  cir.coro.ret_point {
+// CIR:   cir.cleanup.scope {
+// CIR:     cir.await(init, ready : {
+// CIR:     }, suspend : {
+// CIR:     }, resume : {
+// CIR:     },)
+// CIR:     cir.coro.body {
+// CIR:       cir.call @_ZN5folly4coro4TaskIvE12promise_type11return_voidEv
+// CIR:       cir.co_return
+// CIR:     }
+// CIR:     cir.await(final, ready : {
+// CIR:     }, suspend : {
+// CIR:     }, resume : {
+// CIR:     },)
+// CIR:     cir.yield
+// CIR:   } cleanup  normal {
 // CIR:   }
-// CIR:   cir.await(final, ready : {
-// CIR:   }, suspend : {
-// CIR:   }, resume : {
-// CIR:   },)
-// CIR:   cir.yield
-// CIR: } cleanup  normal {
-// CIR: }
+// CIR:  }, ret : {
 
 folly::coro::Task<void> yield();
 folly::coro::Task<void> yield1() {
@@ -335,78 +345,80 @@ folly::coro::Task<void> yield1() {
 // CIR-DAG: %[[CH_VOID2:.*]] = cir.alloca "agg.tmp5" {{.*}} : 
!cir.ptr<![[CoroHandleVoid]]>
 // CIR-DAG: %[[CH_PROM2:.*]] = cir.alloca "agg.tmp6" {{.*}} : 
!cir.ptr<![[CoroHandlePromiseVoid]]>
 
-// CIR: cir.cleanup.scope {
+// CIR:  cir.coro.ret_point {
+// CIR:   cir.cleanup.scope {
 // initial_suspend + await(init)
-// CIR:   %[[INIT_SUSP:.*]] = cir.call 
@_ZN5folly4coro4TaskIvE12promise_type15initial_suspendEv(%[[PROMISE]]){{.*}}
-// CIR:   cir.store{{.*}} %[[INIT_SUSP]], %[[SUSP0]]
-// CIR:   cir.await(init, ready : {
-// CIR:     %[[READY0:.*]] = cir.call 
@_ZNSt14suspend_always11await_readyEv(%[[SUSP0]]){{.*}}
-// CIR:     cir.condition(%[[READY0]])
-// CIR:   }, suspend : {
-// CIR:     %[[FROMADDR0:.*]] = cir.call 
@_ZNSt16coroutine_handleIN5folly4coro4TaskIvE12promise_typeEE12from_addressEPv(%{{.*}}){{.*}}
-// CIR:     cir.store{{.*}} %[[FROMADDR0]], %[[CH_PROM0]]
-// CIR:     %[[PROM_RELOAD0:.*]] = cir.load{{.*}} %[[CH_PROM0]]
-// CIR:     cir.call 
@_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIvE12promise_typeEEES_IT_E(%[[CH_VOID0]],
 %[[PROM_RELOAD0]]){{.*}}
-// CIR:     %[[VOID_RELOAD0:.*]] = cir.load{{.*}} %[[CH_VOID0]]
-// CIR:     cir.call 
@_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SUSP0]], 
%[[VOID_RELOAD0]]){{.*}}
-// CIR:     cir.coro.suspend.point
-// CIR:   }, resume : {
-// CIR:     cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SUSP0]]){{.*}}
-// CIR:     cir.yield
-// CIR:   },)
-
-// yield_value + await(yield)
-// CIR:   cir.coro.body {
-// CIR:     %[[YIELD_TASK:.*]] = cir.call @_Z5yieldv(){{.*}}
-// CIR:     cir.store{{.*}} %[[YIELD_TASK]], %[[T_ADDR]]
-// CIR:     %[[AWAITER:.*]] = cir.load{{.*}} %[[AWAITER_COPY_ADDR]]
-// CIR:     %[[YIELD_SUSP:.*]] = cir.call 
@_ZN5folly4coro4TaskIvE12promise_type11yield_valueES2_(%[[PROMISE]], 
%[[AWAITER]]){{.*}}
-// CIR:     cir.store{{.*}} %[[YIELD_SUSP]], %[[SUSP1]]
-// CIR:     cir.await(yield, ready : {
-// CIR:       %[[READY1:.*]] = cir.call 
@_ZNSt14suspend_always11await_readyEv(%[[SUSP1]]){{.*}}
-// CIR:       cir.condition(%[[READY1]])
+// CIR:     %[[INIT_SUSP:.*]] = cir.call 
@_ZN5folly4coro4TaskIvE12promise_type15initial_suspendEv(%[[PROMISE]]){{.*}}
+// CIR:     cir.store{{.*}} %[[INIT_SUSP]], %[[SUSP0]]
+// CIR:     cir.await(init, ready : {
+// CIR:       %[[READY0:.*]] = cir.call 
@_ZNSt14suspend_always11await_readyEv(%[[SUSP0]]){{.*}}
+// CIR:       cir.condition(%[[READY0]])
 // CIR:     }, suspend : {
-// CIR:       %[[FROMADDR1:.*]] = cir.call 
@_ZNSt16coroutine_handleIN5folly4coro4TaskIvE12promise_typeEE12from_addressEPv(%{{.*}}){{.*}}
-// CIR:       cir.store{{.*}} %[[FROMADDR1]], %[[CH_PROM1]]
-// CIR:       %[[PROM_RELOAD1:.*]] = cir.load{{.*}} %[[CH_PROM1]]
-// CIR:       cir.call 
@_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIvE12promise_typeEEES_IT_E(%[[CH_VOID1]],
 %[[PROM_RELOAD1]]){{.*}}
-// CIR:       %[[VOID_RELOAD1:.*]] = cir.load{{.*}} %[[CH_VOID1]]
-// CIR:       cir.call 
@_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SUSP1]], 
%[[VOID_RELOAD1]]){{.*}}
-// CIR:       cir.coro.suspend.point
+// CIR:       %[[FROMADDR0:.*]] = cir.call 
@_ZNSt16coroutine_handleIN5folly4coro4TaskIvE12promise_typeEE12from_addressEPv(%{{.*}}){{.*}}
+// CIR:       cir.store{{.*}} %[[FROMADDR0]], %[[CH_PROM0]]
+// CIR:       %[[PROM_RELOAD0:.*]] = cir.load{{.*}} %[[CH_PROM0]]
+// CIR:       cir.call 
@_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIvE12promise_typeEEES_IT_E(%[[CH_VOID0]],
 %[[PROM_RELOAD0]]){{.*}}
+// CIR:       %[[VOID_RELOAD0:.*]] = cir.load{{.*}} %[[CH_VOID0]]
+// CIR:       cir.call 
@_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SUSP0]], 
%[[VOID_RELOAD0]]){{.*}}
+// CIR:       cir.coro.suspend_point
 // CIR:     }, resume : {
-// CIR:       cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SUSP1]]){{.*}}
+// CIR:       cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SUSP0]]){{.*}}
 // CIR:       cir.yield
 // CIR:     },)
-// CIR:     cir.call 
@_ZN5folly4coro4TaskIvE12promise_type11return_voidEv(%[[PROMISE]])
-// CIR:     cir.co_return
-// CIR:   }
+
+// yield_value + await(yield)
+// CIR:     cir.coro.body {
+// CIR:       %[[YIELD_TASK:.*]] = cir.call @_Z5yieldv(){{.*}}
+// CIR:       cir.store{{.*}} %[[YIELD_TASK]], %[[T_ADDR]]
+// CIR:       %[[AWAITER:.*]] = cir.load{{.*}} %[[AWAITER_COPY_ADDR]]
+// CIR:       %[[YIELD_SUSP:.*]] = cir.call 
@_ZN5folly4coro4TaskIvE12promise_type11yield_valueES2_(%[[PROMISE]], 
%[[AWAITER]]){{.*}}
+// CIR:       cir.store{{.*}} %[[YIELD_SUSP]], %[[SUSP1]]
+// CIR:       cir.await(yield, ready : {
+// CIR:         %[[READY1:.*]] = cir.call 
@_ZNSt14suspend_always11await_readyEv(%[[SUSP1]]){{.*}}
+// CIR:         cir.condition(%[[READY1]])
+// CIR:       }, suspend : {
+// CIR:         %[[FROMADDR1:.*]] = cir.call 
@_ZNSt16coroutine_handleIN5folly4coro4TaskIvE12promise_typeEE12from_addressEPv(%{{.*}}){{.*}}
+// CIR:         cir.store{{.*}} %[[FROMADDR1]], %[[CH_PROM1]]
+// CIR:         %[[PROM_RELOAD1:.*]] = cir.load{{.*}} %[[CH_PROM1]]
+// CIR:         cir.call 
@_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIvE12promise_typeEEES_IT_E(%[[CH_VOID1]],
 %[[PROM_RELOAD1]]){{.*}}
+// CIR:         %[[VOID_RELOAD1:.*]] = cir.load{{.*}} %[[CH_VOID1]]
+// CIR:         cir.call 
@_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SUSP1]], 
%[[VOID_RELOAD1]]){{.*}}
+// CIR:         cir.coro.suspend_point
+// CIR:       }, resume : {
+// CIR:         cir.call 
@_ZNSt14suspend_always12await_resumeEv(%[[SUSP1]]){{.*}}
+// CIR:         cir.yield
+// CIR:       },)
+// CIR:       cir.call 
@_ZN5folly4coro4TaskIvE12promise_type11return_voidEv(%[[PROMISE]])
+// CIR:       cir.co_return
+// CIR:     }
 
 // return_void + await(final)
-// CIR:   %[[FINAL_SUSP:.*]] = cir.call 
@_ZN5folly4coro4TaskIvE12promise_type13final_suspendEv(%[[PROMISE]]){{.*}}
-// CIR:   cir.store{{.*}} %[[FINAL_SUSP]], %[[SUSP2]]
-// CIR:   cir.await(final, ready : {
-// CIR:     %[[READY2:.*]] = cir.call 
@_ZNSt14suspend_always11await_readyEv(%[[SUSP2]]){{.*}}
-// CIR:     cir.condition(%[[READY2]])
-// CIR:   }, suspend : {
-// CIR:     %[[FROMADDR2:.*]] = cir.call 
@_ZNSt16coroutine_handleIN5folly4coro4TaskIvE12promise_typeEE12from_addressEPv(%{{.*}}){{.*}}
-// CIR:     cir.store{{.*}} %[[FROMADDR2]], %[[CH_PROM2]]
-// CIR:     %[[PROM_RELOAD2:.*]] = cir.load{{.*}} %[[CH_PROM2]]
-// CIR:     cir.call 
@_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIvE12promise_typeEEES_IT_E(%[[CH_VOID2]],
 %[[PROM_RELOAD2]]){{.*}}
-// CIR:     %[[VOID_RELOAD2:.*]] = cir.load{{.*}} %[[CH_VOID2]]
-// CIR:     cir.call 
@_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SUSP2]], 
%[[VOID_RELOAD2]]){{.*}}
-// CIR:     cir.coro.suspend.point
-// CIR:   }, resume : {
-// CIR:     cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SUSP2]]){{.*}}
+// CIR:     %[[FINAL_SUSP:.*]] = cir.call 
@_ZN5folly4coro4TaskIvE12promise_type13final_suspendEv(%[[PROMISE]]){{.*}}
+// CIR:     cir.store{{.*}} %[[FINAL_SUSP]], %[[SUSP2]]
+// CIR:     cir.await(final, ready : {
+// CIR:       %[[READY2:.*]] = cir.call 
@_ZNSt14suspend_always11await_readyEv(%[[SUSP2]]){{.*}}
+// CIR:       cir.condition(%[[READY2]])
+// CIR:     }, suspend : {
+// CIR:       %[[FROMADDR2:.*]] = cir.call 
@_ZNSt16coroutine_handleIN5folly4coro4TaskIvE12promise_typeEE12from_addressEPv(%{{.*}}){{.*}}
+// CIR:       cir.store{{.*}} %[[FROMADDR2]], %[[CH_PROM2]]
+// CIR:       %[[PROM_RELOAD2:.*]] = cir.load{{.*}} %[[CH_PROM2]]
+// CIR:       cir.call 
@_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIvE12promise_typeEEES_IT_E(%[[CH_VOID2]],
 %[[PROM_RELOAD2]]){{.*}}
+// CIR:       %[[VOID_RELOAD2:.*]] = cir.load{{.*}} %[[CH_VOID2]]
+// CIR:       cir.call 
@_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SUSP2]], 
%[[VOID_RELOAD2]]){{.*}}
+// CIR:       cir.coro.suspend_point
+// CIR:     }, resume : {
+// CIR:       cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SUSP2]]){{.*}}
+// CIR:       cir.yield
+// CIR:     },)
 // CIR:     cir.yield
-// CIR:   },)
-// CIR:   cir.yield
-// CIR: } cleanup  normal {
-// CIR: }
-// CIR: = cir.coro.intrinsic.end(%{{.*}}, %{{.*}})
-// CIR: %[[RETLOAD:.*]] = cir.load{{.*}} %[[RETVAL]]
-// CIR: cir.return %[[RETLOAD]]
-// CIR: }
-
+// CIR:   } cleanup  normal {
+// CIR:   }
+// CIR:  }, ret : {
+// CIR:   = cir.coro.intrinsic.end(%{{.*}}, %{{.*}})
+// CIR:   %[[RETLOAD:.*]] = cir.load{{.*}} %[[RETVAL]]
+// CIR:   cir.return %[[RETLOAD]]
+// CIR:  }
+// CIR:  cir.trap
 // CHECK: }
 
 folly::coro::Task<int> go(int const& val);
@@ -419,36 +431,39 @@ folly::coro::Task<int> go1() {
 // CIR: %[[IntTaskAddr:.*]] = cir.alloca "task" {{.*}} init : 
!cir.ptr<![[IntTask]]>
 // CIR: %[[OneAddr:.*]] = cir.alloca "ref.tmp1" align(4) init : !cir.ptr<!s32i>
 
-// CIR: cir.cleanup.scope {
-// CIR:   cir.await(init, ready : {
-// CIR:   }, suspend : {
-// CIR:   }, resume : {
-// CIR:   },)
+// CIR: cir.coro.ret_point {
+// CIR:   cir.cleanup.scope {
+// CIR:     cir.await(init, ready : {
+// CIR:     }, suspend : {
+// CIR:     }, resume : {
+// CIR:     },)
 
-// CIR:   cir.coro.body {
-// CIR:     %[[One:.*]] = cir.const #cir.int<1> : !s32i
-// CIR:     cir.store{{.*}} %[[One]], %[[OneAddr]] : !s32i, !cir.ptr<!s32i>
-// CIR:     %[[IntTaskTmp:.*]] = cir.call @_Z2goRKi(%[[OneAddr]]) : 
(!cir.ptr<!s32i>{{.*}}) -> ![[IntTask]]
-// CIR:     cir.store{{.*}} %[[IntTaskTmp]], %[[IntTaskAddr]] : ![[IntTask]], 
!cir.ptr<![[IntTask]]>
+// CIR:     cir.coro.body {
+// CIR:       %[[One:.*]] = cir.const #cir.int<1> : !s32i
+// CIR:       cir.store{{.*}} %[[One]], %[[OneAddr]] : !s32i, !cir.ptr<!s32i>
+// CIR:       %[[IntTaskTmp:.*]] = cir.call @_Z2goRKi(%[[OneAddr]]) : 
(!cir.ptr<!s32i>{{.*}}) -> ![[IntTask]]
+// CIR:       cir.store{{.*}} %[[IntTaskTmp]], %[[IntTaskAddr]] : 
![[IntTask]], !cir.ptr<![[IntTask]]>
+
+// CIR:       cir.await(user, ready : {
+// CIR:       }, suspend : {
+// CIR:       }, resume : {
+// CIR:       %[[ResumeVal:.*]] = cir.call 
@_ZN5folly4coro4TaskIiE12await_resumeEv(%[[IntTaskAddr]])
+// CIR:       cir.store{{.*}} %[[ResumeVal]], %[[CoReturnValAddr:.*]] : !s32i, 
!cir.ptr<!s32i>
+// CIR:       },)
+// CIR:       %[[V:.*]] = cir.load{{.*}} %[[CoReturnValAddr]] : 
!cir.ptr<!s32i>, !s32i
+// CIR:       cir.call 
@_ZN5folly4coro4TaskIiE12promise_type12return_valueEi({{.*}}, %[[V]])
+// CIR:       cir.co_return
+// CIR:     }
 
-// CIR:     cir.await(user, ready : {
+// CIR:     cir.await(final, ready : {
 // CIR:     }, suspend : {
 // CIR:     }, resume : {
-// CIR:     %[[ResumeVal:.*]] = cir.call 
@_ZN5folly4coro4TaskIiE12await_resumeEv(%[[IntTaskAddr]])
-// CIR:     cir.store{{.*}} %[[ResumeVal]], %[[CoReturnValAddr:.*]] : !s32i, 
!cir.ptr<!s32i>
 // CIR:     },)
-// CIR:     %[[V:.*]] = cir.load{{.*}} %[[CoReturnValAddr]] : !cir.ptr<!s32i>, 
!s32i
-// CIR:     cir.call 
@_ZN5folly4coro4TaskIiE12promise_type12return_valueEi({{.*}}, %[[V]])
-// CIR:     cir.co_return
+// CIR:     cir.yield
+// CIR:   } cleanup  normal {
 // CIR:   }
-
-// CIR:   cir.await(final, ready : {
-// CIR:   }, suspend : {
-// CIR:   }, resume : {
-// CIR:   },)
-// CIR:   cir.yield
-// CIR: } cleanup  normal {
-// CIR: }
+// CIR:  cir.yield
+// CIR: }, ret : {
 
 folly::coro::Task<int> go1_lambda() {
   auto task = []() -> folly::coro::Task<int> {
@@ -458,45 +473,49 @@ folly::coro::Task<int> go1_lambda() {
 }
 
 // CIR: cir.func coroutine {{.*}} @_ZZ10go1_lambdavENK3$_0clEv{{.*}} 
![[IntTask]]
-// CIR: cir.cleanup.scope {
-// CIR:   cir.await(init, ready : {
-// CIR:   }, suspend : {
-// CIR:   }, resume : {
-// CIR:   },)
-// CIR:   cir.coro.body {
-// CIR:     %[[ONE:.*]] = cir.const #cir.int<1>
-// CIR:     cir.call 
@_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[PROMISE:.*]], %[[ONE]])
-// CIR:     cir.co_return
-// CIR:   }
-// CIR:   cir.await(final, ready : {
-// CIR:   }, suspend : {
-// CIR:   }, resume : {
-// CIR:   },)
-// CIR: } cleanup  normal {
+// CIR: cir.coro.ret_point {
+// CIR:   cir.cleanup.scope {
+// CIR:     cir.await(init, ready : {
+// CIR:     }, suspend : {
+// CIR:     }, resume : {
+// CIR:     },)
+// CIR:     cir.coro.body {
+// CIR:       %[[ONE:.*]] = cir.const #cir.int<1>
+// CIR:       cir.call 
@_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[PROMISE:.*]], %[[ONE]])
+// CIR:       cir.co_return
+// CIR:     }
+// CIR:     cir.await(final, ready : {
+// CIR:     }, suspend : {
+// CIR:     }, resume : {
+// CIR:     },)
+// CIR:   } cleanup  normal {
+// CIR: }, ret : {
 
 // CIR: cir.func coroutine {{.*}} @_Z10go1_lambdav() {{.*}} ![[IntTask]]
-// CIR: cir.cleanup.scope {
-// CIR:   cir.await(init, ready : {
-// CIR:   }, suspend : {
-// CIR:   }, resume : {
-// CIR:   },)
-// CIR:   cir.coro.body {
-// CIR:     cir.call @_ZZ10go1_lambdavENK3$_0clEv
-// CIR:     cir.await(user, ready : {
+// CIR: cir.coro.ret_point {
+// CIR:   cir.cleanup.scope {
+// CIR:     cir.await(init, ready : {
 // CIR:     }, suspend : {
 // CIR:     }, resume : {
-// CIR:       %[[RESUME_RES:.*]] = cir.call 
@_ZN5folly4coro4TaskIiE12await_resumeEv(%[[TASK:.*]])
-// CIR:       cir.store %[[RESUME_RES]], %[[resume_rval:.*]] : !s32i, 
!cir.ptr<!s32i>
 // CIR:     },)
-// CIR:     %[[TMP1:.*]] = cir.load %[[resume_rval:.*]] : !cir.ptr<!s32i>
-// CIR:     cir.call 
@_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[PROMISE:.*]], 
%[[TMP1]])
-// CIR:     cir.co_return
-// CIR:   }
-// CIR:   cir.await(final, ready : {
-// CIR:   }, suspend : {
-// CIR:   }, resume : {
-// CIR:   },)
-// CIR: } cleanup  normal {
+// CIR:     cir.coro.body {
+// CIR:       cir.call @_ZZ10go1_lambdavENK3$_0clEv
+// CIR:       cir.await(user, ready : {
+// CIR:       }, suspend : {
+// CIR:       }, resume : {
+// CIR:         %[[RESUME_RES:.*]] = cir.call 
@_ZN5folly4coro4TaskIiE12await_resumeEv(%[[TASK:.*]])
+// CIR:         cir.store %[[RESUME_RES]], %[[resume_rval:.*]] : !s32i, 
!cir.ptr<!s32i>
+// CIR:       },)
+// CIR:       %[[TMP1:.*]] = cir.load %[[resume_rval:.*]] : !cir.ptr<!s32i>
+// CIR:       cir.call 
@_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[PROMISE:.*]], 
%[[TMP1]])
+// CIR:       cir.co_return
+// CIR:     }
+// CIR:     cir.await(final, ready : {
+// CIR:     }, suspend : {
+// CIR:     }, resume : {
+// CIR:     },)
+// CIR:   } cleanup  normal {
+// CIR: }, ret : {
 
 folly::coro::Task<int> go4() {
   auto* fn = +[](int const& i) -> folly::coro::Task<int> { co_return i; };
@@ -505,57 +524,61 @@ folly::coro::Task<int> go4() {
 }
 
 // CIR: cir.func coroutine{{.*}} @_ZZ3go4vENK3$_0clERKi(
-// CIR: cir.cleanup.scope {
-// CIR:   cir.await(init, ready : {
-// CIR:   }, suspend : {
-// CIR:   }, resume : {
-// CIR:   },)
-// CIR:   cir.coro.body {
-// CIR:     cir.call 
@_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[PROMISE:.*]], 
%[[I:.*]])
-// CIR:     cir.co_return
-// CIR:   }
-// CIR:   cir.await(final, ready : {
-// CIR:   }, suspend : {
-// CIR:   }, resume : {
-// CIR:   },)
-// CIR: } cleanup  normal {
+// CIR: cir.coro.ret_point {
+// CIR:   cir.cleanup.scope {
+// CIR:     cir.await(init, ready : {
+// CIR:     }, suspend : {
+// CIR:     }, resume : {
+// CIR:     },)
+// CIR:     cir.coro.body {
+// CIR:       cir.call 
@_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[PROMISE:.*]], 
%[[I:.*]])
+// CIR:       cir.co_return
+// CIR:     }
+// CIR:     cir.await(final, ready : {
+// CIR:     }, suspend : {
+// CIR:     }, resume : {
+// CIR:     },)
+// CIR:   } cleanup  normal {
+// CIR: }, ret : {
 
 // CIR: cir.func coroutine {{.*}} @_Z3go4v() {{.*}} ![[IntTask]]
 
-// CIR: cir.cleanup.scope {
-// CIR:   cir.await(init, ready : {
-// CIR:   }, suspend : {
-// CIR:   }, resume : {
-// CIR:   },)
+// CIR: cir.coro.ret_point {
+// CIR:   cir.cleanup.scope {
+// CIR:     cir.await(init, ready : {
+// CIR:     }, suspend : {
+// CIR:     }, resume : {
+// CIR:     },)
 
 // Get the lambda invoker ptr via `lambda operator folly::coro::Task<int> 
(*)(int const&)()`
-// CIR: %[[INVOKER:.*]] = cir.call 
@_ZZ3go4vENK3$_0cvPFN5folly4coro4TaskIiEERKiEEv(%{{.*}}) nothrow : {{.*}} -> 
(!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>> {llvm.noundef})
-// CIR: cir.store{{.*}} %[[INVOKER]], %[[FN_ADDR:.*]] : 
!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>, 
!cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>>
-// CIR: %[[FN:.*]] = cir.load{{.*}} %[[FN_ADDR]] : 
!cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>>, 
!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>
-// CIR: %[[THREE:.*]] = cir.const #cir.int<3> : !s32i
-// CIR: cir.store{{.*}} %[[THREE]], %[[ARG:.*]] : !s32i, !cir.ptr<!s32i>
+// CIR:   %[[INVOKER:.*]] = cir.call 
@_ZZ3go4vENK3$_0cvPFN5folly4coro4TaskIiEERKiEEv(%{{.*}}) nothrow : {{.*}} -> 
(!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>> {llvm.noundef})
+// CIR:   cir.store{{.*}} %[[INVOKER]], %[[FN_ADDR:.*]] : 
!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>, 
!cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>>
+// CIR:   %[[FN:.*]] = cir.load{{.*}} %[[FN_ADDR]] : 
!cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>>, 
!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>
+// CIR:   %[[THREE:.*]] = cir.const #cir.int<3> : !s32i
+// CIR:   cir.store{{.*}} %[[THREE]], %[[ARG:.*]] : !s32i, !cir.ptr<!s32i>
 
 // Call invoker, which calls operator() indirectly.
-// CIR: %[[CALLRES:.*]] = cir.call %[[FN]](%[[ARG]]) : 
(!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>, !cir.ptr<!s32i> 
{{.*}}) -> ![[IntTask]]
-// CIR: cir.store{{.*}} %[[CALLRES]], %[[TASK_ADDR:.*]] : ![[IntTask]], 
!cir.ptr<![[IntTask]]>
-
-// CIR:  cir.await(user, ready : {
-// CIR:    = cir.call @_ZN5folly4coro4TaskIiE11await_readyEv(%[[TASK_ADDR]])
-// CIR:    cir.condition(
-// CIR:  }, suspend : {
-// CIR:    cir.coro.suspend.point
-// CIR:  }, resume : {
-// CIR:    cir.yield
-// CIR:  },)
-// CIR:  cir.call @_ZN5folly4coro4TaskIiE12promise_type12return_valueEi
-// CIR:  cir.co_return
-// CIR: }
+// CIR:   %[[CALLRES:.*]] = cir.call %[[FN]](%[[ARG]]) : 
(!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>, !cir.ptr<!s32i> 
{{.*}}) -> ![[IntTask]]
+// CIR:   cir.store{{.*}} %[[CALLRES]], %[[TASK_ADDR:.*]] : ![[IntTask]], 
!cir.ptr<![[IntTask]]>
+
+// CIR:    cir.await(user, ready : {
+// CIR:      = cir.call @_ZN5folly4coro4TaskIiE11await_readyEv(%[[TASK_ADDR]])
+// CIR:      cir.condition(
+// CIR:    }, suspend : {
+// CIR:      cir.coro.suspend_point
+// CIR:    }, resume : {
+// CIR:      cir.yield
+// CIR:    },)
+// CIR:    cir.call @_ZN5folly4coro4TaskIiE12promise_type12return_valueEi
+// CIR:    cir.co_return
+// CIR:   }
 
-// CIR:  cir.await(final, ready : {
-// CIR:  }, suspend : {
-// CIR:  }, resume : {
-// CIR:  },)
-// CIR: } cleanup  normal {
+// CIR:    cir.await(final, ready : {
+// CIR:    }, suspend : {
+// CIR:    }, resume : {
+// CIR:    },)
+// CIR:   } cleanup  normal {
+// CIR: }, ret : {
 
 // OGCG: define {{.*}}__await_suspend_wrapper__init(ptr noundef nonnull 
%[[Awaiter:.*]], ptr noundef %[[Handle:.*]])
 // OGCG: entry:
@@ -584,41 +607,43 @@ folly::coro::Task<int> co_returns(int x) {
 }
 
 // CIR: cir.func coroutine {{.*}} @_Z10co_returnsi
-// CIR: cir.cleanup.scope {
-// CIR:   cir.await(init, ready : {
-// CIR:   }, suspend : {
-// CIR:   }, resume : {
-// CIR:   },)
-// CIR:   cir.coro.body {
-// CIR:      cir.scope {
-// CIR:        cir.if {{.*}} {
-// CIR:          %[[MINUS_ONE:.*]] = cir.const #cir.int<-1>
-// CIR:          cir.call 
@_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[PROMISE:.*]], 
%[[MINUS_ONE]])
-// CIR:          cir.co_return
-// CIR:        } else {
-// CIR:         cir.if {{.*}} {
-// CIR:           %[[MINUS_TWO:.*]] = cir.const #cir.int<-2>
-  // CIR:          cir.call 
@_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[PROMISE]], 
%[[MINUS_TWO]])
-  // CIR:          cir.co_return
-// CIR:           }
-// CIR:        }
-// CIR:      }
-// CIR:     cir.await(user, ready : {
+// CIR: cir.coro.ret_point {
+// CIR:   cir.cleanup.scope {
+// CIR:     cir.await(init, ready : {
 // CIR:     }, suspend : {
 // CIR:     }, resume : {
 // CIR:     },)
-// CIR:     %[[X_LOAD:.*]] = cir.load {{.*}} %[[X:.*]]
-// CIR:     %[[TWO:.*]] = cir.const #cir.int<2>
-// CIR:     %[[RES:.*]] = cir.mul nsw %[[X_LOAD]], %[[TWO]]
-// CIR:     cir.call 
@_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[PROMISE]], %[[RES]])
-// CIR:     cir.co_return
-// CIR:   }
-// CIR:  cir.await(final, ready : {
-// CIR:  }, suspend : {
-// CIR:  }, resume : {
-// CIR:  },)
-// CIR:  cir.yield
-// CIR: } cleanup  normal {
+// CIR:     cir.coro.body {
+// CIR:        cir.scope {
+// CIR:          cir.if {{.*}} {
+// CIR:            %[[MINUS_ONE:.*]] = cir.const #cir.int<-1>
+// CIR:            cir.call 
@_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[PROMISE:.*]], 
%[[MINUS_ONE]])
+// CIR:            cir.co_return
+// CIR:          } else {
+// CIR:           cir.if {{.*}} {
+// CIR:             %[[MINUS_TWO:.*]] = cir.const #cir.int<-2>
+// CIR:             cir.call 
@_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[PROMISE]], 
%[[MINUS_TWO]])
+// CIR:             cir.co_return
+// CIR:             }
+// CIR:          }
+// CIR:        }
+// CIR:       cir.await(user, ready : {
+// CIR:       }, suspend : {
+// CIR:       }, resume : {
+// CIR:       },)
+// CIR:       %[[X_LOAD:.*]] = cir.load {{.*}} %[[X:.*]]
+// CIR:       %[[TWO:.*]] = cir.const #cir.int<2>
+// CIR:       %[[RES:.*]] = cir.mul nsw %[[X_LOAD]], %[[TWO]]
+// CIR:       cir.call 
@_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[PROMISE]], %[[RES]])
+// CIR:       cir.co_return
+// CIR:     }
+// CIR:    cir.await(final, ready : {
+// CIR:    }, suspend : {
+// CIR:    }, resume : {
+// CIR:    },)
+// CIR:    cir.yield
+// CIR:   } cleanup  normal {
+// CIR: }, ret : {
 
 
 // OGCG: define {{.*}} @_Z10co_returnsi
@@ -668,40 +693,42 @@ folly::coro::Task<int> co_return_with_dtor(int flag) {
 // CIR: cir.func coroutine {{.*}} @_Z19co_return_with_dtori
 
 // CIR: %[[LOCAL:.*]] = cir.alloca "local" {{.*}} : !cir.ptr<!rec_HasDtor>
-// CIR: cir.cleanup.scope {
-// CIR:   cir.await(init, ready : {
-// CIR:   }, suspend : {
-// CIR:   }, resume : {
-// CIR:   },)
+// CIR: cir.coro.ret_point {
+// CIR:   cir.cleanup.scope {
+// CIR:     cir.await(init, ready : {
+// CIR:     }, suspend : {
+// CIR:     }, resume : {
+// CIR:     },)
 
-// CIR:   cir.coro.body {
-// CIR:     cir.cleanup.scope {
-// CIR:       cir.scope {
-// CIR:         %[[CAST_FLAG:.*]] = cir.cast int_to_bool %[[FLAG:.*]]
-// CIR:         cir.if %[[CAST_FLAG]] {
-// CIR:           %[[ONE:.*]] = cir.const #cir.int<1>
-// CIR:           cir.call 
@_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[promise:.*]], %[[ONE]])
-// CIR:           cir.co_return
+// CIR:     cir.coro.body {
+// CIR:       cir.cleanup.scope {
+// CIR:         cir.scope {
+// CIR:           %[[CAST_FLAG:.*]] = cir.cast int_to_bool %[[FLAG:.*]]
+// CIR:           cir.if %[[CAST_FLAG]] {
+// CIR:             %[[ONE:.*]] = cir.const #cir.int<1>
+// CIR:             cir.call 
@_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[promise:.*]], %[[ONE]])
+// CIR:             cir.co_return
+// CIR:           }
 // CIR:         }
+// CIR:         %[[TWO:.*]] = cir.const #cir.int<2>
+// CIR:         cir.call 
@_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[promise]], %[[TWO]])
+// CIR:         cir.co_return
+// CIR:       } cleanup normal {
+// CIR:         cir.call @_ZN7HasDtorD1Ev(%[[LOCAL]])
+// CIR:         cir.yield
 // CIR:       }
-// CIR:       %[[TWO:.*]] = cir.const #cir.int<2>
-// CIR:       cir.call 
@_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[promise]], %[[TWO]])
-// CIR:       cir.co_return
-// CIR:     } cleanup normal {
-// CIR:       cir.call @_ZN7HasDtorD1Ev(%[[LOCAL]])
 // CIR:       cir.yield
 // CIR:     }
+
+// CIR:     cir.await(final, ready : {
+// CIR:     }, suspend : {
+// CIR:     }, resume : {
+// CIR:     },)
+// CIR:     cir.yield
+// CIR:   } cleanup normal {
 // CIR:     cir.yield
 // CIR:   }
-
-// CIR:   cir.await(final, ready : {
-// CIR:   }, suspend : {
-// CIR:   }, resume : {
-// CIR:   },)
-// CIR:   cir.yield
-// CIR: } cleanup normal {
-// CIR:   cir.yield
-// CIR: }
+// CIR: }, ret : {
 
 // OGCG: define {{.*}} void @_Z19co_return_with_dtori
 // OGCG:   %[[LOCAL:.*]] = alloca %struct.HasDtor
@@ -732,28 +759,30 @@ folly::coro::Task<int __complex__> complex_co_await() 
noexcept {
 // CIR: %[[COMPLEX_ADDR:.*]] = cir.alloca "ref.tmp1" {{.*}} : 
!cir.ptr<!rec_folly3A3Acoro3A3ATask3C_Complex_int3E>
 // CIR: %[[RESUME_VAL_ADDR:.*]] = cir.alloca "__coawait_resume_rval" {{.*}} : 
!cir.ptr<!cir.complex<!s32i>>
 
-// CIR: cir.cleanup.scope {
-// CIR:   cir.await(init, ready : {
-// CIR:   }, suspend : {
-// CIR:   }, resume : {
-// CIR:   },)
+// CIR: cir.coro.ret_point {
+// CIR:   cir.cleanup.scope {
+// CIR:     cir.await(init, ready : {
+// CIR:     }, suspend : {
+// CIR:     }, resume : {
+// CIR:     },)
 
-// CIR:   cir.coro.body {
-// CIR:     %[[CALL:.*]] = cir.call @_Z9fetchDatav() nothrow : () -> 
!rec_folly3A3Acoro3A3ATask3C_Complex_int3E
-// CIR:     cir.store {{.*}} %[[CALL]], %[[COMPLEX_ADDR]] : 
!rec_folly3A3Acoro3A3ATask3C_Complex_int3E, 
!cir.ptr<!rec_folly3A3Acoro3A3ATask3C_Complex_int3E>
+// CIR:     cir.coro.body {
+// CIR:       %[[CALL:.*]] = cir.call @_Z9fetchDatav() nothrow : () -> 
!rec_folly3A3Acoro3A3ATask3C_Complex_int3E
+// CIR:       cir.store {{.*}} %[[CALL]], %[[COMPLEX_ADDR]] : 
!rec_folly3A3Acoro3A3ATask3C_Complex_int3E, 
!cir.ptr<!rec_folly3A3Acoro3A3ATask3C_Complex_int3E>
+
+// CIR:         cir.await(user, ready : {
+// CIR:         }, suspend : {
+// CIR:         }, resume : {
+// CIR:           %[[RESUME_VAL:.*]] = cir.call 
@_ZN5folly4coro4TaskICiE12await_resumeEv(%[[COMPLEX_ADDR]]) : 
(!cir.ptr<!rec_folly3A3Acoro3A3ATask3C_Complex_int3E> {llvm.align = 1 : i64, 
llvm.dereferenceable = 1 : i64, llvm.nonnull, llvm.noundef}) -> 
(!cir.complex<!s32i> {llvm.noundef})
+// CIR:           cir.store %[[RESUME_VAL]], %[[RESUME_VAL_ADDR]] : 
!cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>
+// CIR:         },)
+// CIR:         %[[V:.*]] = cir.load %[[RESUME_VAL_ADDR]] : 
!cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
+// CIR:         cir.yield
+// CIR:     }
 
-// CIR:       cir.await(user, ready : {
-// CIR:       }, suspend : {
-// CIR:       }, resume : {
-// CIR:         %[[RESUME_VAL:.*]] = cir.call 
@_ZN5folly4coro4TaskICiE12await_resumeEv(%[[COMPLEX_ADDR]]) : 
(!cir.ptr<!rec_folly3A3Acoro3A3ATask3C_Complex_int3E> {llvm.align = 1 : i64, 
llvm.dereferenceable = 1 : i64, llvm.nonnull, llvm.noundef}) -> 
(!cir.complex<!s32i> {llvm.noundef})
-// CIR:         cir.store %[[RESUME_VAL]], %[[RESUME_VAL_ADDR]] : 
!cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>
-// CIR:       },)
-// CIR:       %[[V:.*]] = cir.load %[[RESUME_VAL_ADDR]] : 
!cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
-// CIR:       cir.yield
+// CIR:   } cleanup  normal {
 // CIR:   }
-
-// CIR: } cleanup  normal {
-// CIR: }
+// CIR: }, ret : {
 
 // OGCG: define dso_local void @_Z16complex_co_awaitv()
 
diff --git a/clang/test/CIR/IR/await.cir b/clang/test/CIR/IR/await.cir
index 1305c4bb31e0f..9e6a71351c42e 100644
--- a/clang/test/CIR/IR/await.cir
+++ b/clang/test/CIR/IR/await.cir
@@ -1,26 +1,29 @@
 // RUN: cir-opt %s --verify-roundtrip | FileCheck %s
 
 cir.func coroutine @checkPrintParse(%arg0 : !cir.bool) {
-  cir.coro.body {
-    cir.await(user, ready : {
-      cir.condition(%arg0)
-    }, suspend : {
-      cir.coro.suspend.point
-    }, resume : {
+  cir.coro.ret_point {
+    cir.coro.body {
+      cir.await(user, ready : {
+        cir.condition(%arg0)
+      }, suspend : {
+        cir.coro.suspend_point
+      }, resume : {
+        cir.yield
+      },)
       cir.yield
-    },)
+    }
     cir.yield
+  }, ret : {
+      cir.return
   }
-  cir.coro.suspend.point.dest
-  cir.return
+  cir.trap
 }
 
 // CHECK:  cir.func coroutine @checkPrintParse
 // CHECK:  cir.await(user, ready : {
 // CHECK:    cir.condition(%arg0)
 // CHECK:  }, suspend : {
-// CHECK:    cir.coro.suspend.point
+// CHECK:    cir.coro.suspend_point
 // CHECK:  }, resume : {
 // CHECK:    cir.yield
 // CHECK:  },)
-// CHECK:  cir.coro.suspend.point.dest
diff --git a/clang/test/CIR/IR/co-return.cir b/clang/test/CIR/IR/co-return.cir
index d6c3be2da80ad..833b6a27d8016 100644
--- a/clang/test/CIR/IR/co-return.cir
+++ b/clang/test/CIR/IR/co-return.cir
@@ -1,17 +1,21 @@
 // RUN: cir-opt %s --verify-roundtrip | FileCheck %s
 cir.func coroutine @coro_co_return(%arg0 : !cir.bool) {
-  cir.coro.body {
-    cir.await(user, ready : {
-      cir.condition(%arg0)
-    }, suspend : {
-      cir.coro.suspend.point
-    }, resume : {
-      cir.yield
-    },)
-    cir.co_return
+  cir.coro.ret_point {
+    cir.coro.body {
+      cir.await(user, ready : {
+        cir.condition(%arg0)
+      }, suspend : {
+        cir.coro.suspend_point
+      }, resume : {
+        cir.yield
+      },)
+      cir.co_return
+    }
+    cir.yield
+  }, ret : {
+      cir.return
   }
-  cir.coro.suspend.point.dest
-  cir.return
+  cir.trap
 }
 
 // CHECK: cir.func coroutine @coro_co_return
diff --git a/clang/test/CIR/IR/coro-body.cir b/clang/test/CIR/IR/coro-body.cir
index b1560485303b1..30af9fc0e5d3c 100644
--- a/clang/test/CIR/IR/coro-body.cir
+++ b/clang/test/CIR/IR/coro-body.cir
@@ -1,18 +1,22 @@
 // RUN: cir-opt %s --verify-roundtrip | FileCheck %s
 
 cir.func coroutine @coro_body(%arg0 : !cir.bool) {
-  cir.coro.body {
-    cir.await(user, ready : {
-      cir.condition(%arg0)
-    }, suspend : {
-      cir.coro.suspend.point
-    }, resume : {
-      cir.yield
-    },)
-    cir.co_return
+  cir.coro.ret_point {
+    cir.coro.body {
+      cir.await(user, ready : {
+        cir.condition(%arg0)
+      }, suspend : {
+        cir.coro.suspend_point
+      }, resume : {
+        cir.yield
+      },)
+      cir.co_return
+    }
+    cir.yield
+  }, ret : {
+      cir.return
   }
-  cir.coro.suspend.point.dest
-  cir.return
+  cir.trap
 }
 
 // CHECK: cir.func coroutine @coro_body
diff --git a/clang/test/CIR/IR/coro-ret-point.cir 
b/clang/test/CIR/IR/coro-ret-point.cir
new file mode 100644
index 0000000000000..44afdc6407931
--- /dev/null
+++ b/clang/test/CIR/IR/coro-ret-point.cir
@@ -0,0 +1,23 @@
+// RUN: cir-opt %s --verify-roundtrip | FileCheck %s
+
+cir.func coroutine @coro_ret_point(%arg0 : !cir.bool) {
+  cir.coro.ret_point {
+    cir.coro.body {
+      cir.await(user, ready : {
+        cir.condition(%arg0)
+      }, suspend : {
+        cir.coro.suspend_point
+      }, resume : {
+        cir.yield
+      },)
+      cir.yield
+    }
+    cir.yield
+  }, ret : {
+      cir.return
+  }
+  cir.trap
+}
+
+// CHECK: cir.coro.ret_point {
+// CHECK: }, ret : {
diff --git a/clang/test/CIR/IR/func.cir b/clang/test/CIR/IR/func.cir
index ffc3a503c8c48..dc6a14f63ac65 100644
--- a/clang/test/CIR/IR/func.cir
+++ b/clang/test/CIR/IR/func.cir
@@ -109,20 +109,24 @@ cir.func @ullfunc() -> !u64i {
 // CHECK: }
 
 cir.func coroutine @coro() {
-  cir.coro.body {
-    cir.await(init, ready : {
-      %0 = cir.alloca "" align(1) : !cir.ptr<!cir.bool>
-      %1 = cir.load align(1) %0 : !cir.ptr<!cir.bool>, !cir.bool
-      cir.condition(%1)
-    }, suspend : {
-      cir.coro.suspend.point
-    }, resume : {
+  cir.coro.ret_point {
+    cir.coro.body {
+      cir.await(init, ready : {
+        %0 = cir.alloca "" align(1) : !cir.ptr<!cir.bool>
+        %1 = cir.load align(1) %0 : !cir.ptr<!cir.bool>, !cir.bool
+        cir.condition(%1)
+      }, suspend : {
+        cir.coro.suspend_point
+      }, resume : {
+        cir.yield
+      },)
       cir.yield
-    },)
+    }
     cir.yield
+  }, ret : {
+      cir.return
   }
-  cir.coro.suspend.point.dest
-  cir.return
+  cir.trap
 }
 // CHECK: cir.func{{.*}} coroutine @coro()
 
diff --git a/clang/test/CIR/IR/invalid-await.cir 
b/clang/test/CIR/IR/invalid-await.cir
index cc6d011718ad0..8e40e0886428f 100644
--- a/clang/test/CIR/IR/invalid-await.cir
+++ b/clang/test/CIR/IR/invalid-await.cir
@@ -6,32 +6,38 @@ cir.func coroutine @bad_task() { // expected-error 
{{coroutine body must use at
 // -----
 
 cir.func coroutine @missing_condition() {
-  cir.scope {
+  cir.coro.ret_point {
     cir.await(user, ready : { // expected-error {{ready region must end with 
cir.condition}}
       cir.yield
     }, suspend : {
-      cir.coro.suspend.point
+      cir.coro.suspend_point
     }, resume : {
       cir.yield
     },)
+    cir.coro.body {
+    }
+    cir.yield
+  }, ret : {
+      cir.return
   }
-  cir.coro.body {
-  }
-  cir.coro.suspend.point.dest
-  cir.return
+  cir.trap
 }
 
 cir.func coroutine @missing_suspend(%arg0 : !cir.bool) {
-  cir.coro.body {
-    cir.await(user, ready : { // expected-error {{ready region must end with 
cir.coro.suspend.point}}
-      cir.condition(%arg0)
-    }, suspend : {
+  cir.coro.ret_point {
+    cir.coro.body {
+      cir.await(user, ready : { // expected-error {{suspend region must end 
with cir.coro.suspend_point}}
+        cir.condition(%arg0)
+      }, suspend : {
+        cir.yield
+      }, resume : {
+        cir.yield
+      },)
       cir.yield
-    }, resume : {
-      cir.yield
-    },)
+    }
     cir.yield
+  }, ret : {
+      cir.return
   }
-  cir.coro.suspend.point.dest
-  cir.return
+  cir.trap
 }
diff --git a/clang/test/CIR/IR/invalid-coro-body.cir 
b/clang/test/CIR/IR/invalid-coro-body.cir
index f247220c7d73d..c72ec6e4450fb 100644
--- a/clang/test/CIR/IR/invalid-coro-body.cir
+++ b/clang/test/CIR/IR/invalid-coro-body.cir
@@ -11,12 +11,11 @@ cir.func coroutine @must_have_one_coro_body(%arg0 : 
!cir.bool) {  // expected-er
     cir.await(user, ready : {
       cir.condition(%arg0)
     }, suspend : {
-      cir.coro.suspend.point
+      cir.coro.suspend_point
     }, resume : {
       cir.yield
     },)
   }
   cir.coro.body {
   }
-  cir.coro.suspend.point.dest
 }
diff --git a/clang/test/CIR/IR/invalid-coro-ret-point.cir 
b/clang/test/CIR/IR/invalid-coro-ret-point.cir
new file mode 100644
index 0000000000000..3e65f094ccb63
--- /dev/null
+++ b/clang/test/CIR/IR/invalid-coro-ret-point.cir
@@ -0,0 +1,55 @@
+// RUN: cir-opt %s -verify-diagnostics -split-input-file
+
+cir.func coroutine @coro_ret_point_body_must_end_in_yield(%arg0 : !cir.bool) {
+  cir.coro.ret_point { // expected-error {{body region must terminate with 
'cir.yield'}}
+    cir.coro.body {
+      cir.await(user, ready : {
+        cir.condition(%arg0)
+      }, suspend : {
+        cir.coro.suspend_point
+      }, resume : {
+        cir.yield
+      },)
+    }
+    cir.trap
+  }, ret : {
+      cir.return
+  }
+  cir.trap
+}
+
+cir.func coroutine @coro_ret_point_body_must_not_contain_return(%arg0 : 
!cir.bool) {
+  cir.coro.ret_point { // expected-error {{body region must not contain 
'cir.return' operations}}
+    cir.coro.body {
+      cir.await(user, ready : {
+        cir.condition(%arg0)
+      }, suspend : {
+        cir.coro.suspend_point
+      }, resume : {
+        cir.yield
+      },)
+    }
+    cir.return
+  }, ret : {
+      cir.return
+  }
+  cir.trap
+}
+
+cir.func coroutine @coro_ret_point_return_region_must_end_in_return(%arg0 : 
!cir.bool) {
+  cir.coro.ret_point { // expected-error {{return region must terminate with 
'cir.return'}}
+    cir.coro.body {
+      cir.await(user, ready : {
+        cir.condition(%arg0)
+      }, suspend : {
+        cir.coro.suspend_point
+      }, resume : {
+        cir.yield
+      },)
+    }
+    cir.yield
+  }, ret : {
+      cir.trap
+  }
+  cir.trap
+}
diff --git a/clang/test/CIR/IR/invalid-coro-suspend.cir 
b/clang/test/CIR/IR/invalid-coro-suspend.cir
index 3a45e22433a58..d03769ed66306 100644
--- a/clang/test/CIR/IR/invalid-coro-suspend.cir
+++ b/clang/test/CIR/IR/invalid-coro-suspend.cir
@@ -1,17 +1,23 @@
 // RUN: cir-opt %s -verify-diagnostics -split-input-file
 
 
-cir.func coroutine @must_have_one_coro_suspend_dest(%arg0 : !cir.bool) {  // 
expected-error {{coroutine function must have exactly one 
cir.coro.suspend.point.dest}}
-  cir.coro.body {
-    cir.await(user, ready : {
-      cir.condition(%arg0)
-    }, suspend : {
-      cir.coro.suspend.point
-    }, resume : {
-      cir.yield
-    },)
+cir.func coroutine @must_have_one_coro_ret_point(%arg0 : !cir.bool) {  // 
expected-error {{coroutine function must have exactly one cir.coro.ret_point 
op}}
+  cir.coro.ret_point {
+    cir.coro.body {
+      cir.await(user, ready : {
+        cir.condition(%arg0)
+      }, suspend : {
+        cir.coro.suspend_point
+      }, resume : {
+        cir.yield
+      },)
+    }
+  cir.yield
+  }, ret : {
+      cir.return
   }
-  cir.coro.suspend.point.dest
-  cir.coro.suspend.point.dest
+  cir.coro.ret_point {
+  }, ret : {
+  }
+  cir.trap
 }
-

>From 226fadbc5792535527d1e7bd284f5b456a3b29b7 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <[email protected]>
Date: Thu, 30 Jul 2026 21:35:53 -0500
Subject: [PATCH 3/4] Fix formatting

---
 clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
index 7fc59b30e8c3a..67d9db2519051 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
@@ -617,7 +617,7 @@ emitSuspendExpression(CIRGenFunction &cgf, CGCoroData &coro,
         }
 
         // Signals the parent that execution flows to next region.
-        cir::CoroSuspendPoint::create(builder,loc);
+        cir::CoroSuspendPoint::create(builder, loc);
       },
       /*resumeBuilder=*/
       [&](mlir::OpBuilder &b, mlir::Location loc) {

>From 8015805c153eebfdbdafa3a8899ce95f20a28e74 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <[email protected]>
Date: Tue, 4 Aug 2026 20:52:07 -0500
Subject: [PATCH 4/4] Fix after rebase.

---
 clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp      | 9 +++++----
 clang/test/CIR/CodeGenCoroutines/coro-task.cpp | 2 +-
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
index 67d9db2519051..44dd4f682a316 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
@@ -517,10 +517,6 @@ CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt 
&s) {
       }
     }
   }
-  cir::CoroEndOp::create(
-      cgm.getBuilder(), openCurlyLoc,
-      mlir::ValueRange{builder.getNullPtr(builder.getVoidPtrTy(), 
openCurlyLoc),
-                       builder.getBool(false, openCurlyLoc)});
 
   mlir::Block &coroRetBodyBlock = coroRet.getBodyRegion().back();
   {
@@ -532,6 +528,11 @@ CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt 
&s) {
   mlir::OpBuilder::InsertionGuard guard(builder);
   builder.restoreInsertionPoint(coroRetRegion);
 
+  cir::CoroEndOp::create(
+      cgm.getBuilder(), openCurlyLoc,
+      mlir::ValueRange{builder.getNullPtr(builder.getVoidPtrTy(), 
openCurlyLoc),
+                       builder.getBool(false, openCurlyLoc)});
+
   if (auto *ret = cast_or_null<ReturnStmt>(s.getReturnStmt())) {
     // Since we already emitted the return value above, so we shouldn't
     // emit it again here.
diff --git a/clang/test/CIR/CodeGenCoroutines/coro-task.cpp 
b/clang/test/CIR/CodeGenCoroutines/coro-task.cpp
index ad07e8d43b333..2a7d743b959a7 100644
--- a/clang/test/CIR/CodeGenCoroutines/coro-task.cpp
+++ b/clang/test/CIR/CodeGenCoroutines/coro-task.cpp
@@ -194,7 +194,7 @@ VoidTask silly_task() {
 // CIR:     %[[NullPtr2:.*]] = cir.const #cir.ptr<null>
 // CIR:     %[[Cond:.*]] = cir.cmp ne %[[FreeMem]], %[[NullPtr2]]
 // CIR:     cir.if %[[Cond]] {
-// CIR:       %[[Size:.*]] = cir.call @__builtin_coro_size()
+// CIR:       %[[Size:.*]] = cir.coro.intrinsic.size()
 // CIR:       cir.call @_ZdlPvm(%[[FreeMem]], %[[Size]])
 // CIR:     }
 // CIR:     cir.yield

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to