https://github.com/Andres-Salamanca created 
https://github.com/llvm/llvm-project/pull/168814

This PR adds codegen for `cir.await` ready and suspend. One notable difference 
from the classic codegen is that, in the suspend branch, it emits an 
`AwaitSuspendWrapper`(`.__await_suspend_wrapper__init`) function that is always 
inlined. This function wraps the suspend logic inside an internal wrapper that 
gets inlined. Example here: https://godbolt.org/z/rWYGcaaG4


>From 53a0c360454208a3b290ac460e3f2aabfc231a0b Mon Sep 17 00:00:00 2001
From: Andres Salamanca <[email protected]>
Date: Wed, 19 Nov 2025 22:01:06 -0500
Subject: [PATCH] [CIR] Emit ready and suspend branches for cir.await

---
 clang/include/clang/CIR/MissingFeatures.h |  1 -
 clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp   |  4 +--
 clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp | 25 +++++++++++--
 clang/lib/CIR/CodeGen/CIRGenFunction.h    |  1 +
 clang/test/CIR/CodeGen/coro-task.cpp      | 43 +++++++++++++++++++++--
 5 files changed, 65 insertions(+), 9 deletions(-)

diff --git a/clang/include/clang/CIR/MissingFeatures.h 
b/clang/include/clang/CIR/MissingFeatures.h
index 6b5c34d28ce2a..a6bdf11a01a4b 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -151,7 +151,6 @@ struct MissingFeatures {
 
   // Coroutines
   static bool coroEndBuiltinCall() { return false; }
-  static bool coroutineFrame() { return false; }
   static bool emitBodyAndFallthrough() { return false; }
   static bool coroOutsideFrameMD() { return false; }
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 77f19343653db..862f25cc4d3c8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -470,9 +470,7 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl 
&gd, unsigned builtinID,
     return getUndefRValue(e->getType());
 
   case Builtin::BI__builtin_coro_frame: {
-    cgm.errorNYI(e->getSourceRange(), "BI__builtin_coro_frame NYI");
-    assert(!cir::MissingFeatures::coroutineFrame());
-    return getUndefRValue(e->getType());
+    return emitCoroutineFrame();
   }
   case Builtin::BI__builtin_coro_free:
   case Builtin::BI__builtin_coro_size: {
diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
index bb55991d9366a..d105d64ea5d31 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
@@ -97,6 +97,14 @@ struct ParamReferenceReplacerRAII {
   }
 };
 } // namespace
+
+RValue CIRGenFunction::emitCoroutineFrame() {
+  if (curCoro.data && curCoro.data->coroBegin) {
+    return RValue::get(curCoro.data->coroBegin);
+  }
+  cgm.errorNYI("NYI");
+}
+
 static void createCoroData(CIRGenFunction &cgf,
                            CIRGenFunction::CGCoroInfo &curCoro,
                            cir::CallOp coroId) {
@@ -302,11 +310,24 @@ emitSuspendExpression(CIRGenFunction &cgf, CGCoroData 
&coro,
       builder, cgf.getLoc(s.getSourceRange()), kind,
       /*readyBuilder=*/
       [&](mlir::OpBuilder &b, mlir::Location loc) {
-        builder.createCondition(
-            cgf.createDummyValue(loc, cgf.getContext().BoolTy));
+        Expr *condExpr = s.getReadyExpr()->IgnoreParens();
+        builder.createCondition(cgf.evaluateExprAsBool(condExpr));
       },
       /*suspendBuilder=*/
       [&](mlir::OpBuilder &b, mlir::Location loc) {
+        // Note that differently from LLVM codegen we do not emit coro.save
+        // and coro.suspend here, that should be done as part of lowering this
+        // to LLVM dialect (or some other MLIR dialect)
+
+        // A invalid suspendRet indicates "void returning await_suspend"
+        mlir::Value suspendRet = cgf.emitScalarExpr(s.getSuspendExpr());
+
+        // Veto suspension if requested by bool returning await_suspend.
+        if (suspendRet) {
+          cgf.cgm.errorNYI("Veto await_suspend");
+        }
+
+        // Signals the parent that execution flows to next region.
         cir::YieldOp::create(builder, loc);
       },
       /*resumeBuilder=*/
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index b426f3389ff1b..d09dfbd84975a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1415,6 +1415,7 @@ class CIRGenFunction : public CIRGenTypeCache {
   cir::CallOp emitCoroAllocBuiltinCall(mlir::Location loc);
   cir::CallOp emitCoroBeginBuiltinCall(mlir::Location loc,
                                        mlir::Value coroframeAddr);
+  RValue emitCoroutineFrame();
 
   void emitDestroy(Address addr, QualType type, Destroyer *destroyer);
 
diff --git a/clang/test/CIR/CodeGen/coro-task.cpp 
b/clang/test/CIR/CodeGen/coro-task.cpp
index 01e0786fbda71..4843f2433fa64 100644
--- a/clang/test/CIR/CodeGen/coro-task.cpp
+++ b/clang/test/CIR/CodeGen/coro-task.cpp
@@ -111,6 +111,9 @@ co_invoke_fn co_invoke;
 // CIR-DAG: ![[VoidPromisse:.*]] = !cir.record<struct 
"folly::coro::Task<void>::promise_type" padded {!u8i}>
 // CIR-DAG: ![[IntPromisse:.*]] = !cir.record<struct 
"folly::coro::Task<int>::promise_type" padded {!u8i}>
 // CIR-DAG: ![[StdString:.*]] = !cir.record<struct "std::string" padded {!u8i}>
+// CIR-DAG: ![[CoroHandleVoid:.*]] = !cir.record<struct 
"std::coroutine_handle<void>" padded {!u8i}>
+// CIR-DAG: ![[CoroHandlePromiseVoid:rec_.*]]  = !cir.record<struct 
"std::coroutine_handle<folly::coro::Task<void>::promise_type>" padded {!u8i}>
+// CIR-DAG: ![[CoroHandlePromiseInt:rec_.*]] = !cir.record<struct 
"std::coroutine_handle<folly::coro::Task<int>::promise_type>" padded {!u8i}>
 // CIR-DAG: ![[SuspendAlways:.*]] = !cir.record<struct "std::suspend_always" 
padded {!u8i}>
 
 // CIR: module {{.*}} {
@@ -160,6 +163,8 @@ VoidTask silly_task() {
 
 // CIR: cir.scope {
 // CIR:   %[[SuspendAlwaysAddr:.*]] = cir.alloca ![[SuspendAlways]], {{.*}} 
["ref.tmp0"] {alignment = 1 : i64}
+// CIR:   %[[CoroHandleVoidAddr:.*]] = cir.alloca ![[CoroHandleVoid]], {{.*}} 
["agg.tmp0"] {alignment = 1 : i64}
+// CIR:   %[[CoroHandlePromiseAddr:.*]] = cir.alloca 
![[CoroHandlePromiseVoid]], {{.*}} ["agg.tmp1"] {alignment = 1 : i64}
 
 // Effectively execute `coawait promise_type::initial_suspend()` by calling 
initial_suspend() and getting
 // the suspend_always struct to use for cir.await. Note that we return 
by-value since we defer ABI lowering
@@ -175,8 +180,28 @@ VoidTask silly_task() {
 // First regions `ready` has a special cir.yield code to veto suspension.
 
 // CIR:   cir.await(init, ready : {
-// CIR:     cir.condition({{.*}})
+// CIR:     %[[ReadyVeto:.*]] = cir.scope {
+// CIR:       %[[TmpCallRes:.*]] = cir.call 
@_ZNSt14suspend_always11await_readyEv(%[[SuspendAlwaysAddr]])
+// CIR:       cir.yield %[[TmpCallRes:.*]] : !cir.bool
+// CIR:     }
+// CIR:     cir.condition(%[[ReadyVeto]])
+
+// Second region `suspend` contains the actual suspend logic.
+//
+// - Start by getting the coroutine handle using from_address().
+// - Implicit convert coroutine handle from task specific promisse
+//   specialization to a void one.
+// - Call suspend_always::await_suspend() passing the handle.
+//
+// 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.yield
 // CIR:   }, resume : {
 // CIR:     cir.yield
@@ -203,11 +228,23 @@ folly::coro::Task<int> byRef(const std::string& s) {
 // CIR:    cir.store {{.*}} %[[RetObj]], %[[IntTaskAddr]] : ![[IntTask]]
 // CIR:    cir.scope {
 // CIR:      %[[SuspendAlwaysAddr:.*]] = cir.alloca ![[SuspendAlways]], {{.*}} 
["ref.tmp0"] {alignment = 1 : i64}
+// CIR:      %[[CoroHandleVoidAddr:.*]] = cir.alloca ![[CoroHandleVoid]], 
{{.*}} ["agg.tmp0"] {alignment = 1 : i64}
+// CIR:      %[[CoroHandlePromiseAddr:.*]] = cir.alloca 
![[CoroHandlePromiseInt]], {{.*}} ["agg.tmp1"] {alignment = 1 : i64}
 // CIR:      %[[Tmp0:.*]] = cir.call 
@_ZN5folly4coro4TaskIiE12promise_type15initial_suspendEv(%[[IntPromisseAddr]])
 // CIR:      cir.await(init, ready : {
-// CIR:        cir.condition({{.*}})
+// CIR:       %[[ReadyVeto:.*]] = cir.scope {
+// CIR:         %[[TmpCallRes:.*]] = cir.call 
@_ZNSt14suspend_always11await_readyEv(%[[SuspendAlwaysAddr]])
+// CIR:         cir.yield %[[TmpCallRes:.*]] : !cir.bool
+// CIR:       }
+// CIR:       cir.condition(%[[ReadyVeto]])
 // CIR:      }, suspend : {
-// CIR:        cir.yield
+// 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.yield
 // CIR:      }, resume : {
 // CIR:        cir.yield
 // CIR:      },)

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

Reply via email to