[clang] [CIR] Implement CoawaitExpr for ComplexType (PR #194027)
Amr Hesham via cfe-commits
cfe-commits at lists.llvm.org
Thu May 7 10:57:56 PDT 2026
https://github.com/AmrDeveloper updated https://github.com/llvm/llvm-project/pull/194027
>From 7ba981f976cf0ef4d7b982409ed526c2111ba276 Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Fri, 24 Apr 2026 21:07:58 +0200
Subject: [PATCH 1/2] [CIR] Implement CoawaitExpr for ComplexType
---
clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp | 10 ++--
clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp | 3 +-
clang/lib/CIR/CodeGen/CIRGenValue.h | 2 +
clang/test/CIR/CodeGen/coro-task.cpp | 59 +++++++++++++++++++++
4 files changed, 68 insertions(+), 6 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
index 12408b7c59458..0bc198f07e8d8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
@@ -558,12 +558,12 @@ emitSuspendExpression(CIRGenFunction &cgf, CGCoroData &coro,
if (!awaitRes.rv.isIgnored()) {
// Create the alloca in the block before the scope wrapping
// cir.await.
+ mlir::Value value = awaitRes.rv.getAnyValue();
tmpResumeRValAddr = cgf.emitAlloca(
- "__coawait_resume_rval", awaitRes.rv.getValue().getType(), loc,
- CharUnits::One(),
+ "__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, awaitRes.rv.getValue(),
+ builder.CIRBaseBuilderTy::createStore(loc, value,
tmpResumeRValAddr);
}
}
@@ -614,7 +614,9 @@ static RValue emitSuspendExpr(CIRGenFunction &cgf,
// once we have a testcase and prove all pieces work.
cgf.cgm.errorNYI("emitSuspendExpr Aggregate");
} else { // complex
- cgf.cgm.errorNYI("emitSuspendExpr Complex");
+ rval = RValue::getComplex(cir::LoadOp::create(
+ cgf.getBuilder(), scopeLoc, rval.getComplexValue().getType(),
+ tmpResumeRValAddr));
}
return rval;
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
index b359c2bd719e4..6a26b2c987f3e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
@@ -86,8 +86,7 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
return Visit(pe->getReplacement());
}
mlir::Value VisitCoawaitExpr(CoawaitExpr *s) {
- cgf.cgm.errorNYI(s->getExprLoc(), "ComplexExprEmitter VisitCoawaitExpr");
- return {};
+ return cgf.emitCoawaitExpr(*s).getComplexValue();
}
mlir::Value VisitCoyieldExpr(CoyieldExpr *s) {
cgf.cgm.errorNYI(s->getExprLoc(), "ComplexExprEmitter VisitCoyieldExpr");
diff --git a/clang/lib/CIR/CodeGen/CIRGenValue.h b/clang/lib/CIR/CodeGen/CIRGenValue.h
index e70dac5851189..89e25927ef792 100644
--- a/clang/lib/CIR/CodeGen/CIRGenValue.h
+++ b/clang/lib/CIR/CodeGen/CIRGenValue.h
@@ -59,6 +59,8 @@ class RValue {
return value;
}
+ mlir::Value getAnyValue() const { return value; }
+
/// Return the value of this complex value.
mlir::Value getComplexValue() const {
assert(isComplex() && "Not a complex!");
diff --git a/clang/test/CIR/CodeGen/coro-task.cpp b/clang/test/CIR/CodeGen/coro-task.cpp
index 2874009157f88..46d7cde18b047 100644
--- a/clang/test/CIR/CodeGen/coro-task.cpp
+++ b/clang/test/CIR/CodeGen/coro-task.cpp
@@ -839,3 +839,62 @@ folly::coro::Task<int> co_return_with_dtor(int flag) {
// OGCG: cleanup4:
// OGCG: call void @_ZN7HasDtorD1Ev({{.*}} %[[LOCAL]])
// OGCG: br label %coro.final
+
+folly::coro::Task<int __complex__> fetchData() noexcept {
+ int __complex__ a;
+ co_return a;
+}
+
+folly::coro::Task<int __complex__> complex_co_await() noexcept {
+ co_await fetchData();
+}
+
+// CIR: cir.func coroutine {{.*}} @_Z16complex_co_awaitv
+
+// CIR: %[[COMPLEX_ADDR:.*]] = cir.alloca !rec_folly3A3Acoro3A3ATask3C_Complex_int3E, !cir.ptr<!rec_folly3A3Acoro3A3ATask3C_Complex_int3E>, ["ref.tmp1"]
+// CIR: %[[RESUME_VAL_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["__coawait_resume_rval"]
+
+// CIR: cir.cleanup.scope {
+// CIR: cir.await(init, ready : {
+// CIR: }, suspend : {
+// CIR: }, resume : {
+// CIR: },)
+
+// CIR: cir.coro.body {
+// CIR: %[[CALL:.*]] = cir.call @_Z9fetchDatav() nothrow : () -> !rec_folly3A3Acoro3A3ATask3C_Complex_int3E
+// CIR: cir.store {{.*}} %[[CALL]], %[[COMPLEX_ADDR]] : !rec_folly3A3Acoro3A3ATask3C_Complex_int3E, !cir.ptr<!rec_folly3A3Acoro3A3ATask3C_Complex_int3E>
+
+// CIR: cir.await(user, ready : {
+// CIR: }, suspend : {
+// CIR: }, resume : {
+// CIR: %[[RESUME_VAL:.*]] = cir.call @_ZN5folly4coro4TaskICiE12await_resumeEv(%[[COMPLEX_ADDR]]) : (!cir.ptr<!rec_folly3A3Acoro3A3ATask3C_Complex_int3E> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nonnull, llvm.noundef}) -> (!cir.complex<!s32i> {llvm.noundef})
+// CIR: cir.store %[[RESUME_VAL]], %[[RESUME_VAL_ADDR]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>
+// CIR: },)
+// CIR: %[[V:.*]] = cir.load %[[RESUME_VAL_ADDR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
+// CIR: cir.yield
+// CIR: }
+
+// CIR: } cleanup normal {
+// CIR: }
+
+// OGCG: define dso_local void @_Z16complex_co_awaitv()
+
+// OGCG: %[[RESUME_VAL_ADDR:.*]] = alloca { i32, i32 }, align 4
+// OGCG: %[[RESUME_REAL_ADDR:.*]] = alloca i32, align 4
+// OGCG: %[[RESUME_IMAG_ADDR:.*]] = alloca i32, align 4
+
+// OGCG: coro.init:
+// OGCG: await.ready:
+// OGCG: %[[RESUME_VAL:.*]] = call noundef i64 @_ZN5folly4coro4TaskICiE12await_resumeEv(ptr noundef nonnull align 1 dereferenceable(1) %{{.*}})
+// OGCG: store i64 %[[RESUME_VAL]], ptr %[[RESUME_VAL_ADDR]], align 4
+// OGCG: %[[RESUME_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[RESUME_VAL_ADDR]], i32 0, i32 0
+// OGCG: %[[RESUME_REAL:.*]] = load i32, ptr %[[RESUME_REAL_PTR]], align 4
+// OGCG: store i32 %[[RESUME_REAL]], ptr %[[RESUME_REAL_ADDR]], align 4
+// OGCG: %[[RESUME_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[RESUME_VAL_ADDR]], i32 0, i32 1
+// OGCG: %[[RESUME_IMAG:.*]] = load i32, ptr %[[RESUME_IMAG_PTR]], align 4
+// OGCG: store i32 %[[RESUME_IMAG]], ptr %[[RESUME_IMAG_ADDR]], align 4
+// OGCG: br label %[[CLEANUP_FROM_AWAIT_READY:.*]]
+
+// OGCG: [[CLEANUP_CONT:.*]]:
+// OGCG: %[[RESUME_REAL:.*]] = load i32, ptr %[[RESUME_REAL_ADDR]], align 4
+// OGCG: %[[RESUME_IMAG:.*]] = load i32, ptr %[[RESUME_IMAG_ADDR]], align 4
>From c9e465939b099c5d574b78fe0057641f35a39a6c Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Thu, 7 May 2026 19:48:03 +0200
Subject: [PATCH 2/2] Remove anyValue and switch on the kind
---
clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp | 12 +++++++++++-
clang/lib/CIR/CodeGen/CIRGenValue.h | 2 --
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
index 0bc198f07e8d8..870015c844a6d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
@@ -558,7 +558,17 @@ emitSuspendExpression(CIRGenFunction &cgf, CGCoroData &coro,
if (!awaitRes.rv.isIgnored()) {
// Create the alloca in the block before the scope wrapping
// cir.await.
- mlir::Value value = awaitRes.rv.getAnyValue();
+ mlir::Value value;
+ RValue rv = awaitRes.rv;
+ if (rv.isScalar()) {
+ value = rv.getValue();
+ } else if (rv.isComplex()) {
+ value = rv.getComplexValue();
+ } else {
+ cgf.cgm.errorNYI("emitSuspendExpression: Aggregate value");
+ return;
+ }
+
tmpResumeRValAddr = cgf.emitAlloca(
"__coawait_resume_rval", value.getType(), loc, CharUnits::One(),
builder.getBestAllocaInsertPoint(scopeParentBlock));
diff --git a/clang/lib/CIR/CodeGen/CIRGenValue.h b/clang/lib/CIR/CodeGen/CIRGenValue.h
index 89e25927ef792..e70dac5851189 100644
--- a/clang/lib/CIR/CodeGen/CIRGenValue.h
+++ b/clang/lib/CIR/CodeGen/CIRGenValue.h
@@ -59,8 +59,6 @@ class RValue {
return value;
}
- mlir::Value getAnyValue() const { return value; }
-
/// Return the value of this complex value.
mlir::Value getComplexValue() const {
assert(isComplex() && "Not a complex!");
More information about the cfe-commits
mailing list