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

This PR upstreams the emission of the `cir.await` resume branch. Handling the 
case where the return value of `co_await` is not ignored is deferred to a 
future PR, which will be added once `co_return` is upstreamed. Additionally, 
the `forLValue` variable is always `false` in the current implementation. When 
support for emitting `coro_yield` is added, this variable will be set to 
`true`, so that work is also deferred to a future PR.


>From fc7e7bf1866462da004c664791987c24c23efc99 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <[email protected]>
Date: Thu, 27 Nov 2025 21:25:18 -0500
Subject: [PATCH] [CIR] Upstream Emit the resume branch for cir.await op

---
 clang/include/clang/CIR/MissingFeatures.h |  2 ++
 clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp | 39 +++++++++++++++++++++++
 clang/test/CIR/CodeGen/coro-task.cpp      | 18 +++++++++--
 3 files changed, 56 insertions(+), 3 deletions(-)

diff --git a/clang/include/clang/CIR/MissingFeatures.h 
b/clang/include/clang/CIR/MissingFeatures.h
index 1427c677d0f34..3d3251adae279 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -153,6 +153,8 @@ struct MissingFeatures {
   static bool coroEndBuiltinCall() { return false; }
   static bool emitBodyAndFallthrough() { return false; }
   static bool coroOutsideFrameMD() { return false; }
+  static bool coroCoReturn() { return false; }
+  static bool coroCoYield() { return false; }
 
   // Various handling of deferred processing in CIRGenModule.
   static bool cgmRelease() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
index f7df811a67c26..35a6354b19705 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
@@ -32,6 +32,9 @@ struct clang::CIRGen::CGCoroData {
 
   // Stores the result of __builtin_coro_begin call.
   mlir::Value coroBegin = nullptr;
+
+  // The promise type's 'unhandled_exception' handler, if it defines one.
+  Stmt *exceptionHandler = nullptr;
 };
 
 // Defining these here allows to keep CGCoroData private to this file.
@@ -272,6 +275,17 @@ CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt 
&s) {
   }
   return mlir::success();
 }
+
+static bool memberCallExpressionCanThrow(const Expr *e) {
+  if (const auto *ce = dyn_cast<CXXMemberCallExpr>(e))
+    if (const FunctionProtoType *proto =
+            ce->getMethodDecl()->getType()->getAs<FunctionProtoType>())
+      if (isNoexceptExceptionSpec(proto->getExceptionSpecType()) &&
+          proto->canThrow() == CT_Cannot)
+        return false;
+  return true;
+}
+
 // Given a suspend expression which roughly looks like:
 //
 //   auto && x = CommonExpr();
@@ -333,6 +347,31 @@ emitSuspendExpression(CIRGenFunction &cgf, CGCoroData 
&coro,
       },
       /*resumeBuilder=*/
       [&](mlir::OpBuilder &b, mlir::Location loc) {
+        // Exception handling requires additional IR. If the 'await_resume'
+        // function is marked as 'noexcept', we avoid generating this 
additional
+        // IR.
+        CXXTryStmt *tryStmt = nullptr;
+        if (coro.exceptionHandler && kind == cir::AwaitKind::Init &&
+            memberCallExpressionCanThrow(s.getResumeExpr()))
+          cgf.cgm.errorNYI("Coro resume Exception");
+
+        // FIXME(cir): the alloca for the resume expr should be placed in the
+        // enclosing cir.scope instead.
+        if (forLValue) {
+          assert(!cir::MissingFeatures::coroCoYield());
+        } else {
+          awaitRes.rv =
+              cgf.emitAnyExpr(s.getResumeExpr(), aggSlot, ignoreResult);
+          if (!awaitRes.rv.isIgnored())
+            // Create the alloca in the block before the scope wrapping
+            // cir.await.
+            assert(!cir::MissingFeatures::coroCoReturn());
+        }
+
+        if (tryStmt)
+          cgf.cgm.errorNYI("Coro tryStmt");
+
+        // Returns control back to parent.
         cir::YieldOp::create(builder, loc);
       });
 
diff --git a/clang/test/CIR/CodeGen/coro-task.cpp 
b/clang/test/CIR/CodeGen/coro-task.cpp
index 4843f2433fa64..6cafe3fd0c419 100644
--- a/clang/test/CIR/CodeGen/coro-task.cpp
+++ b/clang/test/CIR/CodeGen/coro-task.cpp
@@ -203,11 +203,21 @@ VoidTask silly_task() {
 // CIR:     %[[CoroHandleVoidReload:.*]] = cir.load{{.*}} 
%[[CoroHandleVoidAddr]] : !cir.ptr<![[CoroHandleVoid]]>, ![[CoroHandleVoid]]
 // CIR:     cir.call 
@_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SuspendAlwaysAddr]],
 %[[CoroHandleVoidReload]])
 // CIR:     cir.yield
+
+// Third region `resume` handles coroutine resuming logic.
+
 // CIR:   }, resume : {
+// CIR:     cir.call 
@_ZNSt14suspend_always12await_resumeEv(%[[SuspendAlwaysAddr]])
 // CIR:     cir.yield
 // CIR:   },)
 // CIR: }
 
+// Since we already tested cir.await guts above, the remaining checks for:
+// - The actual user written co_await
+// - The promise call
+// - The final suspend co_await
+// - Return
+
 folly::coro::Task<int> byRef(const std::string& s) {
   co_return s.size();
 }
@@ -245,6 +255,8 @@ folly::coro::Task<int> byRef(const std::string& s) {
 // 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:      },)
+// CIR:       }, resume : {
+// CIR:         cir.call 
@_ZNSt14suspend_always12await_resumeEv(%[[SuspendAlwaysAddr]])
+// CIR:         cir.yield
+// CIR:       },)
+// CIR:     }

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

Reply via email to