https://github.com/amanmaurya92 updated 
https://github.com/llvm/llvm-project/pull/225412

>From 1089bc4d9f013586a97f5f357974c9ed86b2a04a Mon Sep 17 00:00:00 2001
From: amanmaurya92 <[email protected]>
Date: Tue, 22 Sep 2026 20:04:50 +0530
Subject: [PATCH 1/2] [CIR] Support aggregate co_await / co_yield in
 AggExprEmitter

Implement support for evaluating co_await and co_yield expressions whose result 
is an aggregate type in AggExprEmitter.

Assisted by Antigravity.

Reviewed by amanmaurya92.

Fixes #225317
---
 clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp     | 37 +++++-----
 clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp |  8 +--
 clang/test/CIR/CodeGenCoroutines/coro-agg.cpp | 72 +++++++++++++++++++
 3 files changed, 93 insertions(+), 24 deletions(-)
 create mode 100644 clang/test/CIR/CodeGenCoroutines/coro-agg.cpp

diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
index 6f2c0e33ce1d96..2fa9bd19a62f3c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
@@ -707,25 +707,20 @@ emitSuspendExpression(CIRGenFunction &cgf, CGCoroData 
&coro,
           awaitRes.rv =
               cgf.emitAnyExpr(s.getResumeExpr(), aggSlot, ignoreResult);
           if (!awaitRes.rv.isIgnored()) {
-            // Create the alloca in the block before the scope wrapping
-            // cir.await.
-            mlir::Value value;
             RValue rv = awaitRes.rv;
-            if (rv.isScalar()) {
-              value = rv.getValue();
-            } else if (rv.isComplex()) {
-              value = rv.getComplexValue();
+            if (rv.isScalar() || rv.isComplex()) {
+              mlir::Value value =
+                  rv.isScalar() ? rv.getValue() : rv.getComplexValue();
+              tmpResumeRValAddr = cgf.emitAlloca(
+                  "__coawait_resume_rval", value.getType(), loc,
+                  CharUnits::One(),
+                  builder.getBestAllocaInsertPoint(scopeParentBlock));
+              // Store the rvalue so we can reload it before the promise call.
+              builder.CIRBaseBuilderTy::createStore(loc, value,
+                                                    tmpResumeRValAddr);
             } else {
-              cgf.cgm.errorNYI("emitSuspendExpression: Aggregate value");
-              return;
+              assert(rv.isAggregate() && "unexpected rvalue kind");
             }
-
-            tmpResumeRValAddr = cgf.emitAlloca(
-                "__coawait_resume_rval", value.getType(), loc, 
CharUnits::One(),
-                builder.getBestAllocaInsertPoint(scopeParentBlock));
-            // Store the rvalue so we can reload it before the promise call.
-            builder.CIRBaseBuilderTy::createStore(loc, value,
-                                                  tmpResumeRValAddr);
           }
         }
 
@@ -744,6 +739,12 @@ static RValue emitSuspendExpr(CIRGenFunction &cgf,
   RValue rval;
   mlir::Location scopeLoc = cgf.getLoc(e.getSourceRange());
 
+  if (!ignoreResult && aggSlot.isIgnored() &&
+      cgf.getEvaluationKind(e.getType()) == cir::TEK_Aggregate) {
+    aggSlot = cgf.createAggTemp(e.getType(), scopeLoc,
+                                cgf.getCounterAggTmpAsString());
+  }
+
   // Since we model suspend / resume as an inner region, we must store
   // resume scalar results in a tmp alloca, and load it after we build the
   // suspend expression. An alternative way to do this would be to make
@@ -768,9 +769,7 @@ static RValue emitSuspendExpr(CIRGenFunction &cgf,
                                            rval.getValue().getType(),
                                            tmpResumeRValAddr));
   } else if (rval.isAggregate()) {
-    // This is probably already handled via AggSlot, remove this assertion
-    // once we have a testcase and prove all pieces work.
-    cgf.cgm.errorNYI("emitSuspendExpr Aggregate");
+    return rval;
   } else { // complex
     rval = RValue::getComplex(cir::LoadOp::create(
         cgf.getBuilder(), scopeLoc, rval.getComplexValue().getType(),
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index 2fb66232d806cd..e6ce32390d2c63 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -392,14 +392,12 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> 
{
     Visit(ge->getResultExpr());
   }
   void VisitCoawaitExpr(CoawaitExpr *e) {
-    cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitCoawaitExpr");
+    cgf.emitCoawaitExpr(*e, dest, dest.isIgnored());
   }
   void VisitCoyieldExpr(CoyieldExpr *e) {
-    cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitCoyieldExpr");
-  }
-  void VisitUnaryCoawait(UnaryOperator *e) {
-    cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitUnaryCoawait");
+    cgf.emitCoyieldExpr(*e, dest, dest.isIgnored());
   }
+  void VisitUnaryCoawait(UnaryOperator *e) { Visit(e->getSubExpr()); }
   void VisitUnaryExtension(UnaryOperator *e) { Visit(e->getSubExpr()); }
   void VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *e) {
     Visit(e->getReplacement());
diff --git a/clang/test/CIR/CodeGenCoroutines/coro-agg.cpp 
b/clang/test/CIR/CodeGenCoroutines/coro-agg.cpp
new file mode 100644
index 00000000000000..5b31f07b0aea3f
--- /dev/null
+++ b/clang/test/CIR/CodeGenCoroutines/coro-agg.cpp
@@ -0,0 +1,72 @@
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir 
-Wno-coroutine-missing-unhandled-exception -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+
+#include "Inputs/coroutine.h"
+
+struct B {
+  int x;
+  int y;
+  bool await_ready() { return true; }
+  B await_resume() { return {}; }
+  template <typename F> void await_suspend(F) {}
+};
+
+struct coro_t {
+  struct promise_type {
+    coro_t get_return_object() { return {}; }
+    std::suspend_never initial_suspend() { return {}; }
+    std::suspend_never final_suspend() noexcept { return {}; }
+    void return_void() {}
+    static void unhandled_exception() {}
+    B yield_value(int) { return {}; }
+  };
+};
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z22aggregate_coawait_exprv
+coro_t aggregate_coawait_expr() {
+  // CIR: %[[VAL:.*]] = cir.alloca "val" align(4) init : !cir.ptr<!rec_B>
+  // CIR: cir.await(user, ready : {
+  // CIR: }, suspend : {
+  // CIR: }, resume : {
+  // CIR:   cir.call @_ZN1B12await_resumeEv(%{{.*}})
+  // CIR:   cir.store align(4) %{{.*}}, %[[VAL]] : !rec_B, !cir.ptr<!rec_B>
+  // CIR:   cir.yield
+  // CIR: },)
+  B val = co_await B{};
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z29aggregate_coawait_expr_unusedv
+coro_t aggregate_coawait_expr_unused() {
+  // CIR: cir.await(user, ready : {
+  // CIR: }, suspend : {
+  // CIR: }, resume : {
+  // CIR:   cir.call @_ZN1B12await_resumeEv(%{{.*}})
+  // CIR:   cir.yield
+  // CIR: },)
+  co_await B{};
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z22aggregate_coyield_exprv
+coro_t aggregate_coyield_expr() {
+  // CIR: %[[VAL:.*]] = cir.alloca "val" align(4) init : !cir.ptr<!rec_B>
+  // CIR: cir.await(yield, ready : {
+  // CIR: }, suspend : {
+  // CIR: }, resume : {
+  // CIR:   cir.call @_ZN1B12await_resumeEv(%{{.*}})
+  // CIR:   cir.store align(4) %{{.*}}, %[[VAL]] : !rec_B, !cir.ptr<!rec_B>
+  // CIR:   cir.yield
+  // CIR: },)
+  B val = co_yield 42;
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z29aggregate_coyield_expr_unusedv
+coro_t aggregate_coyield_expr_unused() {
+  // CIR: cir.await(yield, ready : {
+  // CIR: }, suspend : {
+  // CIR: }, resume : {
+  // CIR:   cir.call @_ZN1B12await_resumeEv(%{{.*}})
+  // CIR:   cir.yield
+  // CIR: },)
+  co_yield 42;
+}
+

>From 6e4df09f8fe0dea4a3a10be8dadd398ad9ffb0eb Mon Sep 17 00:00:00 2001
From: amanmaurya92 <[email protected]>
Date: Wed, 23 Sep 2026 12:54:24 +0530
Subject: [PATCH 2/2] [CIR] Address review comments on aggregate co_await /
 co_yield

- Remove redundant aggregate temporary allocation in emitSuspendExpr, as 
emitAnyExpr already provisions one when dest is ignored and AggExprEmitter 
passes dest.isIgnored() as ignoreResult.

- Add OGCG test coverage comparing classic Clang CodeGen side-by-side with CIR 
in coro-agg.cpp.
---
 clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp     |  6 ------
 clang/test/CIR/CodeGenCoroutines/coro-agg.cpp | 21 ++++++++++++++++++-
 2 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
index 2fa9bd19a62f3c..b0e03ce10d5a61 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
@@ -739,12 +739,6 @@ static RValue emitSuspendExpr(CIRGenFunction &cgf,
   RValue rval;
   mlir::Location scopeLoc = cgf.getLoc(e.getSourceRange());
 
-  if (!ignoreResult && aggSlot.isIgnored() &&
-      cgf.getEvaluationKind(e.getType()) == cir::TEK_Aggregate) {
-    aggSlot = cgf.createAggTemp(e.getType(), scopeLoc,
-                                cgf.getCounterAggTmpAsString());
-  }
-
   // Since we model suspend / resume as an inner region, we must store
   // resume scalar results in a tmp alloca, and load it after we build the
   // suspend expression. An alternative way to do this would be to make
diff --git a/clang/test/CIR/CodeGenCoroutines/coro-agg.cpp 
b/clang/test/CIR/CodeGenCoroutines/coro-agg.cpp
index 5b31f07b0aea3f..7f3d7775729044 100644
--- a/clang/test/CIR/CodeGenCoroutines/coro-agg.cpp
+++ b/clang/test/CIR/CodeGenCoroutines/coro-agg.cpp
@@ -1,5 +1,7 @@
 // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir 
-Wno-coroutine-missing-unhandled-exception -emit-cir %s -o %t.cir
 // RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm 
-disable-llvm-passes -Wno-coroutine-missing-unhandled-exception %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
 
 #include "Inputs/coroutine.h"
 
@@ -23,6 +25,7 @@ struct coro_t {
 };
 
 // CIR-LABEL: cir.func coroutine {{.*}} @_Z22aggregate_coawait_exprv
+// OGCG-LABEL: define dso_local void @_Z22aggregate_coawait_exprv
 coro_t aggregate_coawait_expr() {
   // CIR: %[[VAL:.*]] = cir.alloca "val" align(4) init : !cir.ptr<!rec_B>
   // CIR: cir.await(user, ready : {
@@ -32,10 +35,15 @@ coro_t aggregate_coawait_expr() {
   // CIR:   cir.store align(4) %{{.*}}, %[[VAL]] : !rec_B, !cir.ptr<!rec_B>
   // CIR:   cir.yield
   // CIR: },)
+  // OGCG: %[[VAL:.*]] = alloca %struct.B, align 4
+  // OGCG: await.ready:
+  // OGCG:   %[[RES:.*]] = call i64 @_ZN1B12await_resumeEv(ptr {{.*}})
+  // OGCG:   store i64 %[[RES]], ptr %[[VAL]], align 4
   B val = co_await B{};
 }
 
 // CIR-LABEL: cir.func coroutine {{.*}} @_Z29aggregate_coawait_expr_unusedv
+// OGCG-LABEL: define dso_local void @_Z29aggregate_coawait_expr_unusedv
 coro_t aggregate_coawait_expr_unused() {
   // CIR: cir.await(user, ready : {
   // CIR: }, suspend : {
@@ -43,10 +51,14 @@ coro_t aggregate_coawait_expr_unused() {
   // CIR:   cir.call @_ZN1B12await_resumeEv(%{{.*}})
   // CIR:   cir.yield
   // CIR: },)
+  // OGCG: await.ready:
+  // OGCG:   %[[RES:.*]] = call i64 @_ZN1B12await_resumeEv(ptr {{.*}})
+  // OGCG:   store i64 %[[RES]], ptr %{{.*}}, align 4
   co_await B{};
 }
 
 // CIR-LABEL: cir.func coroutine {{.*}} @_Z22aggregate_coyield_exprv
+// OGCG-LABEL: define dso_local void @_Z22aggregate_coyield_exprv
 coro_t aggregate_coyield_expr() {
   // CIR: %[[VAL:.*]] = cir.alloca "val" align(4) init : !cir.ptr<!rec_B>
   // CIR: cir.await(yield, ready : {
@@ -56,10 +68,15 @@ coro_t aggregate_coyield_expr() {
   // CIR:   cir.store align(4) %{{.*}}, %[[VAL]] : !rec_B, !cir.ptr<!rec_B>
   // CIR:   cir.yield
   // CIR: },)
+  // OGCG: %[[VAL:.*]] = alloca %struct.B, align 4
+  // OGCG: yield.ready:
+  // OGCG:   %[[RES:.*]] = call i64 @_ZN1B12await_resumeEv(ptr {{.*}})
+  // OGCG:   store i64 %[[RES]], ptr %[[VAL]], align 4
   B val = co_yield 42;
 }
 
 // CIR-LABEL: cir.func coroutine {{.*}} @_Z29aggregate_coyield_expr_unusedv
+// OGCG-LABEL: define dso_local void @_Z29aggregate_coyield_expr_unusedv
 coro_t aggregate_coyield_expr_unused() {
   // CIR: cir.await(yield, ready : {
   // CIR: }, suspend : {
@@ -67,6 +84,8 @@ coro_t aggregate_coyield_expr_unused() {
   // CIR:   cir.call @_ZN1B12await_resumeEv(%{{.*}})
   // CIR:   cir.yield
   // CIR: },)
+  // OGCG: yield.ready:
+  // OGCG:   %[[RES:.*]] = call i64 @_ZN1B12await_resumeEv(ptr {{.*}})
+  // OGCG:   store i64 %[[RES]], ptr %{{.*}}, align 4
   co_yield 42;
 }
-

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

Reply via email to