Author: Andres-Salamanca
Date: 2026-10-08T01:00:24Z
New Revision: 25da5b6127d758ebf7ce2e033479e41479653bb3

URL: 
https://github.com/llvm/llvm-project/commit/25da5b6127d758ebf7ce2e033479e41479653bb3
DIFF: 
https://github.com/llvm/llvm-project/commit/25da5b6127d758ebf7ce2e033479e41479653bb3.diff

LOG: [CIR] Add cir.coro.suspend intrinsic (#228310)

Implement `cir.coro.suspend` and lower __builtin_coro_suspend to the CIR
coroutine suspend intrinsic.

Added: 
    clang/test/CIR/IR/coro-suspend.cir

Modified: 
    clang/include/clang/CIR/Dialect/IR/CIROps.td
    clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
    clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
    clang/lib/CIR/CodeGen/CIRGenFunction.h
    clang/test/CIR/CodeGenCoroutines/coro-builtins.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 73521879937fe..42ff7a9131cfd 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -5138,6 +5138,32 @@ def CIR_CoroSizeOp : CIR_CoroIntrinsicOp<"size", (ins),
   let llvmOp = "CoroSizeOp";
 }
 
+//===----------------------------------------------------------------------===//
+// Coroutine intrinsic SuspendOp
+//===----------------------------------------------------------------------===//
+
+def CIR_CoroSuspendOp : CIR_CoroIntrinsicOp<"suspend",
+    (ins Token:$save, CIR_AnyBoolType: $final),
+    (outs CIR_SInt8:$result), [TokenConsumerTrait]> {
+  let summary = "Represents llvm.coro.suspend";
+  let description = [{
+    `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
+    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..841de79fa0d2f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -1825,9 +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:
-    cgm.errorNYI(e->getSourceRange(), "BI__builtin_coro_suspend NYI");
-    return getUndefRValue(e->getType());
+  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/lib/CIR/CodeGen/CIRGenCoroutine.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
index c2a85aab2c19d..c1f6a3732c160 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 02627b488b23d..587676cefe428 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -2058,6 +2058,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..507c0757af282 100644
--- a/clang/test/CIR/CodeGenCoroutines/coro-builtins.cpp
+++ b/clang/test/CIR/CodeGenCoroutines/coro-builtins.cpp
@@ -77,6 +77,34 @@ 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)
+}
+
+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: ]

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
+  }
+}


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

Reply via email to