[clang] [CIR] Add structured control flow for coroutine suspend points (PR #213191)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Aug 4 18:52:50 PDT 2026
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 <andrealebarbaritos at gmail.com>
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 <andrealebarbaritos at gmail.com>
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> ®ions) {
+ 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 <andrealebarbaritos at gmail.com>
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 <andrealebarbaritos at gmail.com>
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
More information about the cfe-commits
mailing list