[clang] [CIR] Add cir.coro.suspend intrinsic (PR #228310)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 7 16:00:26 PDT 2026
https://github.com/Andres-Salamanca updated https://github.com/llvm/llvm-project/pull/228310
>From 129c890ff2e43ef31e0ba51db81cac7824315f84 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Thu, 1 Oct 2026 22:09:01 -0500
Subject: [PATCH 1/3] [CIR] Add cir.coro.suspend intrinsic
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 26 +++++++++++++++++++
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 3 +--
clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp | 10 +++++++
clang/lib/CIR/CodeGen/CIRGenFunction.h | 1 +
.../CIR/CodeGenCoroutines/coro-builtins.cpp | 8 ++++--
5 files changed, 44 insertions(+), 4 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 985cc3712c581..7a10c7d9d1521 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -5137,6 +5137,32 @@ def CIR_CoroSizeOp : CIR_CoroIntrinsicOp<"size", (ins),
let llvmOp = "CoroSizeOp";
}
+//===----------------------------------------------------------------------===//
+// Coroutine intrinsic SuspendOp
+//===----------------------------------------------------------------------===//
+
+def CIR_CoroSuspendOp : CIR_CoroIntrinsicOp<"suspend",
+ (ins Token:$id, CIR_AnyBoolType: $final),
+ (outs CIR_UInt8:$result), [TokenConsumerTrait]> {
+ let summary = "Represents llvm.coro.suspend";
+ let description = [{
+ `cir.coro.suspend` represents the `llvm.coro.suspend` intrinsic.
+
+ It marks the point where execution of a switched-resume coroutine is
+ suspended and control returns to the caller. The result value indicates
+ how the coroutine should proceed: -1 if suspended, 0 if resumed, or 1
+ if destroyed.
+
+ The `id` operand is the token produced by a `cir.coro.save` that marks
+ the point when the coroutine state is prepared for suspension.
+
+ The `final` operand indicates whether this is a final suspend point.
+ If more than one suspend point is marked final, the resume and destroy
+ branches must lead to the same basic blocks.
+ }];
+ let llvmOp = "CoroSuspendOp";
+}
+
//===----------------------------------------------------------------------===//
// Coroutine intrinsic PromiseOp
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 97ce3fbcabcbc..ef00f4536fa57 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -1826,8 +1826,7 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
case Builtin::BI__builtin_coro_done:
return RValue::get(emitCoroDoneBuiltinCall(e).getResult());
case Builtin::BI__builtin_coro_suspend:
- cgm.errorNYI(e->getSourceRange(), "BI__builtin_coro_suspend NYI");
- return getUndefRValue(e->getType());
+ return RValue::get(emitCoroSuspendBuiltinCall(e).getResult());
case Builtin::BI__builtin_coro_align:
cgm.errorNYI(e->getSourceRange(), "BI__builtin_coro_align NYI");
return getUndefRValue(e->getType());
diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
index d92c65dc43c5f..ecd8e7df00614 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
@@ -287,6 +287,16 @@ cir::CoroNoopOp CIRGenFunction::emitCoroNoopBuiltinCall(const CallExpr *e) {
return cir::CoroNoopOp::create(cgm.getBuilder(), loc);
}
+cir::CoroSuspendOp
+CIRGenFunction::emitCoroSuspendBuiltinCall(const CallExpr *e) {
+ mlir::Location loc = getLoc(e->getBeginLoc());
+ llvm::SmallVector<mlir::Value, 2> args;
+ args.push_back(cir::TokenNoneOp::create(builder, loc));
+ args.push_back(emitScalarExpr(e->getArg(0)));
+
+ return cir::CoroSuspendOp::create(cgm.getBuilder(), loc, args);
+}
+
static mlir::LogicalResult
coroutineBodyExceptionHelper(CIRGenFunction &cgf, const CoroutineBodyStmt &s) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index c6427d60a3792..3abb947709c9f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -2040,6 +2040,7 @@ class CIRGenFunction : public CIRGenTypeCache {
cir::CoroResumeOp emitCoroResumeBuiltinCall(const CallExpr *e);
cir::CoroDestroyOp emitCoroDestroyBuiltinCall(const CallExpr *e);
cir::CoroNoopOp emitCoroNoopBuiltinCall(const CallExpr *e);
+ cir::CoroSuspendOp emitCoroSuspendBuiltinCall(const CallExpr *e);
cir::CoroSizeOp emitCoroSizeBuiltinCall(const CallExpr *e);
cir::CoroFreeOp emitCoroFreeBuiltin(const CallExpr *e);
diff --git a/clang/test/CIR/CodeGenCoroutines/coro-builtins.cpp b/clang/test/CIR/CodeGenCoroutines/coro-builtins.cpp
index 539151dbd633d..61e0e1fbe6b3a 100644
--- a/clang/test/CIR/CodeGenCoroutines/coro-builtins.cpp
+++ b/clang/test/CIR/CodeGenCoroutines/coro-builtins.cpp
@@ -77,6 +77,10 @@ void f(int n) {
// LLVM: call void @llvm.coro.end(ptr %[[FRAME]], i1 false, token none)
- // TODO(CIR):
- //__builtin_coro_suspend(1);
+ __builtin_coro_suspend(true);
+ // CIR: %[[TK_NONE2:.*]] = cir.token.none
+ // CIR: %[[TRUE:.*]] = cir.const #true
+ // CIR: cir.coro.intrinsic.suspend(%[[TK_NONE2]], %[[TRUE]])
+
+ // LLVM: call i8 @llvm.coro.suspend(token none, i1 true)
}
>From 7b6c16406b2da1efbce0eb5028f54e3d0f544ad0 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Tue, 6 Oct 2026 18:11:27 -0500
Subject: [PATCH 2/3] Address review comments
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 2 +-
.../CIR/CodeGenCoroutines/coro-builtins.cpp | 24 +++++++++++++++++++
2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 7a10c7d9d1521..7fb2ecbe9c091 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -5143,7 +5143,7 @@ def CIR_CoroSizeOp : CIR_CoroIntrinsicOp<"size", (ins),
def CIR_CoroSuspendOp : CIR_CoroIntrinsicOp<"suspend",
(ins Token:$id, CIR_AnyBoolType: $final),
- (outs CIR_UInt8:$result), [TokenConsumerTrait]> {
+ (outs CIR_SInt8:$result), [TokenConsumerTrait]> {
let summary = "Represents llvm.coro.suspend";
let description = [{
`cir.coro.suspend` represents the `llvm.coro.suspend` intrinsic.
diff --git a/clang/test/CIR/CodeGenCoroutines/coro-builtins.cpp b/clang/test/CIR/CodeGenCoroutines/coro-builtins.cpp
index 61e0e1fbe6b3a..507c0757af282 100644
--- a/clang/test/CIR/CodeGenCoroutines/coro-builtins.cpp
+++ b/clang/test/CIR/CodeGenCoroutines/coro-builtins.cpp
@@ -84,3 +84,27 @@ void f(int n) {
// LLVM: call i8 @llvm.coro.suspend(token none, i1 true)
}
+
+void test_suspend_switch() {
+ switch (__builtin_coro_suspend(false)) {
+ case -1:
+ return;
+ case 0:
+ break;
+ }
+}
+
+// CIR: cir.func{{.*}} @_Z19test_suspend_switchv
+// CIR: %[[TK_NONE:.*]] = cir.token.none
+// CIR: %[[FALSE:.*]] = cir.const #false
+// CIR: %[[SUSPEND:.*]] = cir.coro.intrinsic.suspend(%[[TK_NONE]], %[[FALSE]]) : (token, !cir.bool) -> !s8i
+// CIR: %[[CAST:.*]] = cir.cast integral %[[SUSPEND]] : !s8i -> !s32i
+// CIR: cir.switch(%[[CAST]] : !s32i)
+
+// LLVM: define{{.*}} void @_Z19test_suspend_switchv
+// LLVM: %[[SUSPEND:.*]] = call i8 @llvm.coro.suspend(token none, i1 false)
+// LLVM: %[[CAST:.*]] = sext i8 %[[SUSPEND]] to i32
+// LLVM: switch i32 %[[CAST]], label %{{.*}} [
+// LLVM: i32 -1, label %{{.*}}
+// LLVM: i32 0, label %{{.*}}
+// LLVM: ]
>From f3765547d50e665b22e893e2c9350ce4301f3c3f Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Wed, 7 Oct 2026 18:00:04 -0500
Subject: [PATCH 3/3] Address review comments
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 4 ++--
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 7 +++++--
clang/test/CIR/IR/coro-suspend.cir | 15 +++++++++++++++
3 files changed, 22 insertions(+), 4 deletions(-)
create mode 100644 clang/test/CIR/IR/coro-suspend.cir
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 7fb2ecbe9c091..4451065124f43 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -5142,11 +5142,11 @@ def CIR_CoroSizeOp : CIR_CoroIntrinsicOp<"size", (ins),
//===----------------------------------------------------------------------===//
def CIR_CoroSuspendOp : CIR_CoroIntrinsicOp<"suspend",
- (ins Token:$id, CIR_AnyBoolType: $final),
+ (ins Token:$save, CIR_AnyBoolType: $final),
(outs CIR_SInt8:$result), [TokenConsumerTrait]> {
let summary = "Represents llvm.coro.suspend";
let description = [{
- `cir.coro.suspend` represents the `llvm.coro.suspend` intrinsic.
+ `cir.coro.intrinsic.suspend` represents the `llvm.coro.suspend` intrinsic.
It marks the point where execution of a switched-resume coroutine is
suspended and control returns to the caller. The result value indicates
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index ef00f4536fa57..841de79fa0d2f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -1825,8 +1825,11 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
}
case Builtin::BI__builtin_coro_done:
return RValue::get(emitCoroDoneBuiltinCall(e).getResult());
- case Builtin::BI__builtin_coro_suspend:
- return RValue::get(emitCoroSuspendBuiltinCall(e).getResult());
+ case Builtin::BI__builtin_coro_suspend: {
+ mlir::Value result = emitCoroSuspendBuiltinCall(e).getResult();
+ return RValue::get(
+ builder.createIntCast(result, convertType(e->getType())));
+ }
case Builtin::BI__builtin_coro_align:
cgm.errorNYI(e->getSourceRange(), "BI__builtin_coro_align NYI");
return getUndefRValue(e->getType());
diff --git a/clang/test/CIR/IR/coro-suspend.cir b/clang/test/CIR/IR/coro-suspend.cir
new file mode 100644
index 0000000000000..2416aa263ba3c
--- /dev/null
+++ b/clang/test/CIR/IR/coro-suspend.cir
@@ -0,0 +1,15 @@
+// RUN: cir-opt %s --verify-roundtrip | FileCheck %s
+
+!void = !cir.void
+#false = #cir.bool<false> : !cir.bool
+!s8i = !cir.int<s, 8>
+
+module {
+ cir.func @test_coro_noop() {
+ %0 = cir.token.none
+ %1 = cir.const #false
+ %2 = cir.coro.intrinsic.suspend(%0, %1) : (token, !cir.bool) -> !s8i
+ // CHECK: cir.coro.intrinsic.suspend(%0, %1) : (token, !cir.bool) -> !s8i
+ cir.return
+ }
+}
More information about the cfe-commits
mailing list