https://github.com/amanmaurya92 updated https://github.com/llvm/llvm-project/pull/232280
>From 29ca56a4f16688f7e4840bef2609dc142d0f7cb6 Mon Sep 17 00:00:00 2001 From: amanmaurya92 <[email protected]> Date: Wed, 21 Oct 2026 02:08:00 +0530 Subject: [PATCH 1/4] [CIR] Support CoawaitExpr in emitLValue (#232232) In CIRGenFunction::emitLValue, Expr::CoawaitExprClass previously called errorNYI. When a coroutine awaits an expression whose await_resume() returns an lvalue reference (for example, int &x = co_await awaiter; or (co_await awaiter) = 42;), Clang evaluates the CoawaitExpr as an lvalue. The resume pointer is spilled and reloaded across cir.await to maintain MLIR SSA dominance in the parent scope. Fixes #232232. --- clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp | 27 ++++++- clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 3 +- clang/lib/CIR/CodeGen/CIRGenFunction.h | 1 + .../test/CIR/CodeGenCoroutines/coro-await.cpp | 72 +++++++++++++++++++ 4 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 clang/test/CIR/CodeGenCoroutines/coro-await.cpp diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp index 3ca0a29db565c1..77fc82cce6a700 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp @@ -822,7 +822,9 @@ emitSuspendExpression(CIRGenFunction &cgf, CGCoroData &coro, assert(awaitRes.lv.isSimple() && "expected simple lvalue for coroutine resume"); mlir::Value ptr = awaitRes.lv.getPointer(); - llvm::StringRef tmpName = "__coyield_resume_lval"; + llvm::StringRef tmpName = kind == cir::AwaitKind::Yield + ? "__coyield_resume_lval" + : "__coawait_resume_lval"; tmpResumeRValAddr = cgf.emitAlloca( tmpName, ptr.getType(), loc, cgf.getPointerAlign(), builder.getBestAllocaInsertPoint(scopeParentBlock)); @@ -928,6 +930,29 @@ getCoroutineSuspendExprReturnType(const ASTContext &ctx, } #endif +LValue CIRGenFunction::emitCoawaitLValue(const CoawaitExpr *e) { + assert( + getCoroutineSuspendExprReturnType(getContext(), e)->isReferenceType() && + "Can't have a scalar return unless the return type is a " + "reference type!"); + mlir::Location scopeLoc = getLoc(e->getSourceRange()); + mlir::Block *currEntryBlock = curLexScope->getEntryBlock(); + mlir::Value tmpResumeLValAddr; + LValue lv = emitSuspendExpression(*this, *curCoro.data, *e, + curCoro.data->currentAwaitKind, + AggValueSlot::ignored(), + /*ignoreResult=*/false, currEntryBlock, + tmpResumeLValAddr, /*forLValue=*/true) + .lv; + if (tmpResumeLValAddr) { + Address addr = lv.getAddress(); + mlir::Value loadedPtr = cir::LoadOp::create( + getBuilder(), scopeLoc, addr.getPointer().getType(), tmpResumeLValAddr); + lv.setAddress(addr.withPointer(loadedPtr)); + } + return lv; +} + LValue CIRGenFunction::emitCoyieldLValue(const CoyieldExpr *e) { assert( getCoroutineSuspendExprReturnType(getContext(), e)->isReferenceType() && diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index e5f20f7dec01d1..409a94b9acff8f 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -1373,8 +1373,7 @@ LValue CIRGenFunction::emitLValue(const Expr *e) { case Expr::MaterializeTemporaryExprClass: return emitMaterializeTemporaryExpr(cast<MaterializeTemporaryExpr>(e)); case Expr::CoawaitExprClass: - getCIRGenModule().errorNYI(e->getSourceRange(), "emitLValue: CoawaitExpr"); - return LValue(); + return emitCoawaitLValue(cast<CoawaitExpr>(e)); case Expr::CoyieldExprClass: return emitCoyieldLValue(cast<CoyieldExpr>(e)); case Expr::PackIndexingExprClass: diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index a143483d49391e..b97b0fe1f700c1 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -2316,6 +2316,7 @@ class CIRGenFunction : public CIRGenTypeCache { RValue emitCoawaitExpr(const CoawaitExpr &e, AggValueSlot aggSlot = AggValueSlot::ignored(), bool ignoreResult = false); + LValue emitCoawaitLValue(const CoawaitExpr *e); RValue emitCoyieldExpr(const CoyieldExpr &e, AggValueSlot aggSlot = AggValueSlot::ignored(), diff --git a/clang/test/CIR/CodeGenCoroutines/coro-await.cpp b/clang/test/CIR/CodeGenCoroutines/coro-await.cpp new file mode 100644 index 00000000000000..a592dd1db10d28 --- /dev/null +++ b/clang/test/CIR/CodeGenCoroutines/coro-await.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 +// 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" + +struct Task { + struct promise_type { + Task get_return_object() { return {}; } + std::suspend_never initial_suspend() noexcept { return {}; } + std::suspend_never final_suspend() noexcept { return {}; } + void return_void() {} + void unhandled_exception() {} + }; +}; + +struct Awaiter { + bool await_ready() { return false; } + void await_suspend(std::coroutine_handle<>) {} + int &await_resume() { return value; } + int value; +}; + +// CIR-LABEL: cir.func coroutine {{.*}} @_Z17test_await_assignv +// OGCG-LABEL: define dso_local void @_Z17test_await_assignv +Task test_await_assign() { + // CIR: %[[VAL:.*]] = cir.const #cir.int<42> : !s32i + // CIR: cir.await(user, ready : { + // CIR: %[[READY:.*]] = cir.call @_ZN7Awaiter11await_readyEv(%{{.*}}) : (!cir.ptr<!rec_Awaiter>{{.*}}) -> (!cir.bool{{.*}}) + // CIR: cir.condition(%[[READY]]) + // CIR: }, suspend : { + // CIR: cir.call @_ZN7Awaiter13await_suspendESt16coroutine_handleIvE(%{{.*}}) + // CIR: cir.coro.suspend_point + // CIR: }, resume : { + // CIR: %[[RES:.*]] = cir.call @_ZN7Awaiter12await_resumeEv(%{{.*}}) : (!cir.ptr<!rec_Awaiter>{{.*}}) -> (!cir.ptr<!s32i>{{.*}}) + // CIR: cir.store %[[RES]], %[[TMP_ADDR:.*]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> + // CIR: cir.yield + // CIR: },) + // CIR: %[[LOADED_PTR:.*]] = cir.load %[[TMP_ADDR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i> + // CIR: cir.store align(4) %[[VAL]], %[[LOADED_PTR]] : !s32i, !cir.ptr<!s32i> + + // OGCG: %[[RES_OGCG:.*]] = call noundef nonnull align 4 dereferenceable(4) ptr @_ZN7Awaiter12await_resumeEv(ptr {{.*}}) + // OGCG: store i32 42, ptr %[[RES_OGCG]], align 4 + Awaiter a; + (co_await a) = 42; +} + +// CIR-LABEL: cir.func coroutine {{.*}} @_Z14test_await_refv +// OGCG-LABEL: define dso_local void @_Z14test_await_refv +Task test_await_ref() { + // CIR: %[[R_ADDR:.*]] = cir.alloca "r" align(8) init const : !cir.ptr<!cir.ptr<!s32i>> + // CIR: cir.await(user, ready : { + // CIR: %[[READY:.*]] = cir.call @_ZN7Awaiter11await_readyEv(%{{.*}}) : (!cir.ptr<!rec_Awaiter>{{.*}}) -> (!cir.bool{{.*}}) + // CIR: cir.condition(%[[READY]]) + // CIR: }, suspend : { + // CIR: cir.call @_ZN7Awaiter13await_suspendESt16coroutine_handleIvE(%{{.*}}) + // CIR: cir.coro.suspend_point + // CIR: }, resume : { + // CIR: %[[RES:.*]] = cir.call @_ZN7Awaiter12await_resumeEv(%{{.*}}) : (!cir.ptr<!rec_Awaiter>{{.*}}) -> (!cir.ptr<!s32i>{{.*}}) + // CIR: cir.store %[[RES]], %[[TMP_ADDR:.*]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> + // CIR: cir.yield + // CIR: },) + // CIR: %[[LOADED_PTR:.*]] = cir.load %[[TMP_ADDR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i> + // CIR: cir.store align(8) %[[LOADED_PTR]], %[[R_ADDR]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> + + // OGCG: %[[R_ADDR_OGCG:.*]] = alloca ptr, align 8 + // OGCG: %[[RES_OGCG:.*]] = call noundef nonnull align 4 dereferenceable(4) ptr @_ZN7Awaiter12await_resumeEv(ptr {{.*}}) + // OGCG: store ptr %[[RES_OGCG]], ptr %[[R_ADDR_OGCG]], align 8 + Awaiter a; + int &r = co_await a; +} >From 0d9ad5face04131189bc0a5bc27dc06cd14d7b7a Mon Sep 17 00:00:00 2001 From: amanmaurya92 <[email protected]> Date: Wed, 21 Oct 2026 10:13:52 +0530 Subject: [PATCH 2/4] [CIR] Address review comments for CoawaitExpr emitLValue - Merge emitCoawaitLValue and emitCoyieldLValue into emitSuspendLValue helper. - Add assertion and return null pointer lvalue when tmpResumeLValAddr is null. - Add exception-enabled RUN lines to coro-await.cpp test. --- clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp | 65 +++++++++---------- .../test/CIR/CodeGenCoroutines/coro-await.cpp | 4 ++ 2 files changed, 33 insertions(+), 36 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp index 77fc82cce6a700..41c1ab1abfcc56 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp @@ -920,7 +920,6 @@ RValue CIRGenFunction::emitCoyieldExpr(const CoyieldExpr &e, ignoreResult); } -#ifndef NDEBUG static QualType getCoroutineSuspendExprReturnType(const ASTContext &ctx, const CoroutineSuspendExpr *e) { @@ -928,52 +927,46 @@ getCoroutineSuspendExprReturnType(const ASTContext &ctx, assert(isa<CallExpr>(re) && "unexpected suspend expression type"); return cast<CallExpr>(re)->getCallReturnType(ctx); } -#endif -LValue CIRGenFunction::emitCoawaitLValue(const CoawaitExpr *e) { - assert( - getCoroutineSuspendExprReturnType(getContext(), e)->isReferenceType() && - "Can't have a scalar return unless the return type is a " - "reference type!"); - mlir::Location scopeLoc = getLoc(e->getSourceRange()); - mlir::Block *currEntryBlock = curLexScope->getEntryBlock(); +static LValue emitSuspendLValue(CIRGenFunction &cgf, + const CoroutineSuspendExpr *e, + cir::AwaitKind kind) { + QualType retTy = getCoroutineSuspendExprReturnType(cgf.getContext(), e); + assert(retTy->isReferenceType() && + "Can't have a scalar return unless the return type is a " + "reference type!"); + mlir::Location scopeLoc = cgf.getLoc(e->getSourceRange()); + mlir::Block *currEntryBlock = cgf.curLexScope->getEntryBlock(); mlir::Value tmpResumeLValAddr; - LValue lv = emitSuspendExpression(*this, *curCoro.data, *e, - curCoro.data->currentAwaitKind, + LValue lv = emitSuspendExpression(cgf, *cgf.curCoro.data, *e, kind, AggValueSlot::ignored(), /*ignoreResult=*/false, currEntryBlock, tmpResumeLValAddr, /*forLValue=*/true) .lv; - if (tmpResumeLValAddr) { - Address addr = lv.getAddress(); - mlir::Value loadedPtr = cir::LoadOp::create( - getBuilder(), scopeLoc, addr.getPointer().getType(), tmpResumeLValAddr); - lv.setAddress(addr.withPointer(loadedPtr)); + if (!tmpResumeLValAddr) { + assert(isResumeExprInTryCatch(*cgf.curCoro.data, kind, *e) && + "expected resume in try/catch"); + QualType pointeeTy = retTy->getPointeeType(); + mlir::Type elemTy = cgf.convertType(pointeeTy); + mlir::Value nullPtr = cgf.getBuilder().getNullPtr( + cgf.getBuilder().getPointerTo(elemTy), scopeLoc); + return cgf.makeNaturalAlignAddrLValue(nullPtr, pointeeTy); } + + Address addr = lv.getAddress(); + mlir::Value loadedPtr = + cir::LoadOp::create(cgf.getBuilder(), scopeLoc, + addr.getPointer().getType(), tmpResumeLValAddr); + lv.setAddress(addr.withPointer(loadedPtr)); return lv; } +LValue CIRGenFunction::emitCoawaitLValue(const CoawaitExpr *e) { + return emitSuspendLValue(*this, e, curCoro.data->currentAwaitKind); +} + LValue CIRGenFunction::emitCoyieldLValue(const CoyieldExpr *e) { - assert( - getCoroutineSuspendExprReturnType(getContext(), e)->isReferenceType() && - "Can't have a scalar return unless the return type is a " - "reference type!"); - mlir::Location scopeLoc = getLoc(e->getSourceRange()); - mlir::Block *currEntryBlock = curLexScope->getEntryBlock(); - mlir::Value tmpResumeLValAddr; - LValue lv = - emitSuspendExpression(*this, *curCoro.data, *e, cir::AwaitKind::Yield, - AggValueSlot::ignored(), - /*ignoreResult=*/false, currEntryBlock, - tmpResumeLValAddr, /*forLValue=*/true) - .lv; - if (tmpResumeLValAddr) { - Address addr = lv.getAddress(); - mlir::Value loadedPtr = cir::LoadOp::create( - getBuilder(), scopeLoc, addr.getPointer().getType(), tmpResumeLValAddr); - lv.setAddress(addr.withPointer(loadedPtr)); - } - return lv; + return emitSuspendLValue(*this, e, cir::AwaitKind::Yield); } mlir::LogicalResult CIRGenFunction::emitCoreturnStmt(CoreturnStmt const &s) { diff --git a/clang/test/CIR/CodeGenCoroutines/coro-await.cpp b/clang/test/CIR/CodeGenCoroutines/coro-await.cpp index a592dd1db10d28..dedde25f11b8b8 100644 --- a/clang/test/CIR/CodeGenCoroutines/coro-await.cpp +++ b/clang/test/CIR/CodeGenCoroutines/coro-await.cpp @@ -1,7 +1,11 @@ // 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 -fclangir -fcxx-exceptions -fexceptions -Wno-coroutine-missing-unhandled-exception -emit-cir %s -o %t.eh.cir +// RUN: FileCheck --input-file=%t.eh.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 +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fcxx-exceptions -fexceptions -emit-llvm -disable-llvm-passes -Wno-coroutine-missing-unhandled-exception %s -o %t.eh.ll +// RUN: FileCheck --input-file=%t.eh.ll %s -check-prefix=OGCG #include "Inputs/coroutine.h" >From 197e14887c59259cca825307634fc80237b0977a Mon Sep 17 00:00:00 2001 From: amanmaurya92 <[email protected]> Date: Thu, 22 Oct 2026 17:09:14 +0530 Subject: [PATCH 3/4] [CIR] Mark Awaiter::await_resume as noexcept in coro-await.cpp --- clang/test/CIR/CodeGenCoroutines/coro-await.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/CIR/CodeGenCoroutines/coro-await.cpp b/clang/test/CIR/CodeGenCoroutines/coro-await.cpp index dedde25f11b8b8..bc6cc8b6ce1bcf 100644 --- a/clang/test/CIR/CodeGenCoroutines/coro-await.cpp +++ b/clang/test/CIR/CodeGenCoroutines/coro-await.cpp @@ -22,7 +22,7 @@ struct Task { struct Awaiter { bool await_ready() { return false; } void await_suspend(std::coroutine_handle<>) {} - int &await_resume() { return value; } + int &await_resume() noexcept { return value; } int value; }; >From 34f78ed5b429b1c4d1617ea08e3bcb6c5080cd6f Mon Sep 17 00:00:00 2001 From: amanmaurya92 <[email protected]> Date: Thu, 22 Oct 2026 19:17:12 +0530 Subject: [PATCH 4/4] [CIR] Fix check patterns in coro-await.cpp for noexcept await_resume --- clang/test/CIR/CodeGenCoroutines/coro-await.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/clang/test/CIR/CodeGenCoroutines/coro-await.cpp b/clang/test/CIR/CodeGenCoroutines/coro-await.cpp index bc6cc8b6ce1bcf..4cd3bb9a9df454 100644 --- a/clang/test/CIR/CodeGenCoroutines/coro-await.cpp +++ b/clang/test/CIR/CodeGenCoroutines/coro-await.cpp @@ -37,7 +37,7 @@ Task test_await_assign() { // CIR: cir.call @_ZN7Awaiter13await_suspendESt16coroutine_handleIvE(%{{.*}}) // CIR: cir.coro.suspend_point // CIR: }, resume : { - // CIR: %[[RES:.*]] = cir.call @_ZN7Awaiter12await_resumeEv(%{{.*}}) : (!cir.ptr<!rec_Awaiter>{{.*}}) -> (!cir.ptr<!s32i>{{.*}}) + // CIR: %[[RES:.*]] = cir.call @_ZN7Awaiter12await_resumeEv(%{{.*}}) nothrow : (!cir.ptr<!rec_Awaiter>{{.*}}) -> (!cir.ptr<!s32i>{{.*}}) // CIR: cir.store %[[RES]], %[[TMP_ADDR:.*]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> // CIR: cir.yield // CIR: },) @@ -61,16 +61,15 @@ Task test_await_ref() { // CIR: cir.call @_ZN7Awaiter13await_suspendESt16coroutine_handleIvE(%{{.*}}) // CIR: cir.coro.suspend_point // CIR: }, resume : { - // CIR: %[[RES:.*]] = cir.call @_ZN7Awaiter12await_resumeEv(%{{.*}}) : (!cir.ptr<!rec_Awaiter>{{.*}}) -> (!cir.ptr<!s32i>{{.*}}) + // CIR: %[[RES:.*]] = cir.call @_ZN7Awaiter12await_resumeEv(%{{.*}}) nothrow : (!cir.ptr<!rec_Awaiter>{{.*}}) -> (!cir.ptr<!s32i>{{.*}}) // CIR: cir.store %[[RES]], %[[TMP_ADDR:.*]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> // CIR: cir.yield // CIR: },) // CIR: %[[LOADED_PTR:.*]] = cir.load %[[TMP_ADDR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i> // CIR: cir.store align(8) %[[LOADED_PTR]], %[[R_ADDR]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> - // OGCG: %[[R_ADDR_OGCG:.*]] = alloca ptr, align 8 // OGCG: %[[RES_OGCG:.*]] = call noundef nonnull align 4 dereferenceable(4) ptr @_ZN7Awaiter12await_resumeEv(ptr {{.*}}) - // OGCG: store ptr %[[RES_OGCG]], ptr %[[R_ADDR_OGCG]], align 8 + // OGCG: store ptr %[[RES_OGCG]], ptr %{{.*}}, align 8 Awaiter a; int &r = co_await a; } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
