https://github.com/Andres-Salamanca updated https://github.com/llvm/llvm-project/pull/173174
>From f2e917e35c7bf84525e196487572387f2ea6ed44 Mon Sep 17 00:00:00 2001 From: Andres Salamanca <[email protected]> Date: Sat, 20 Dec 2025 18:56:53 -0500 Subject: [PATCH 1/2] [CIR] Upstream support co_return of values from co_await --- clang/include/clang/CIR/MissingFeatures.h | 1 - clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp | 11 ++- clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp | 16 +++- clang/test/CIR/CodeGen/coro-task.cpp | 86 ++++++++++++++++++- .../CIR/CodeGen/trivial-ctor-const-init.cpp | 10 ++- 5 files changed, 115 insertions(+), 9 deletions(-) diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 39818417fc3d0..c5247d5aa19b4 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -152,7 +152,6 @@ struct MissingFeatures { static bool coroEndBuiltinCall() { return false; } static bool emitBodyAndFallthrough() { return false; } static bool coroOutsideFrameMD() { return false; } - static bool coroCoReturn() { return false; } static bool coroutineExceptions() { return false; }; // Various handling of deferred processing in CIRGenModule. diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp index db3bdec436b94..f060568e8db61 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp @@ -422,10 +422,17 @@ emitSuspendExpression(CIRGenFunction &cgf, CGCoroData &coro, } else { awaitRes.rv = cgf.emitAnyExpr(s.getResumeExpr(), aggSlot, ignoreResult); - if (!awaitRes.rv.isIgnored()) + if (!awaitRes.rv.isIgnored()) { // Create the alloca in the block before the scope wrapping // cir.await. - assert(!cir::MissingFeatures::coroCoReturn()); + tmpResumeRValAddr = cgf.emitAlloca( + "__coawait_resume_rval", awaitRes.rv.getValue().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(), + tmpResumeRValAddr); + } } if (tryStmt) diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp index 8fcff6d0f9b84..a6814382edce2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp @@ -761,7 +761,21 @@ void AggExprEmitter::VisitLambdaExpr(LambdaExpr *e) { void AggExprEmitter::VisitExprWithCleanups(ExprWithCleanups *e) { CIRGenFunction::RunCleanupsScope cleanups(cgf); - Visit(e->getSubExpr()); + auto &builder = cgf.getBuilder(); + auto scopeLoc = cgf.getLoc(e->getSourceRange()); + mlir::OpBuilder::InsertPoint scopeBegin; + cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location loc) { + scopeBegin = b.saveInsertionPoint(); + }); + + { + mlir::OpBuilder::InsertionGuard guard(builder); + builder.restoreInsertionPoint(scopeBegin); + CIRGenFunction::LexicalScope lexScope{cgf, scopeLoc, + builder.getInsertionBlock()}; + Visit(e->getSubExpr()); + } } void AggExprEmitter::VisitCallExpr(const CallExpr *e) { diff --git a/clang/test/CIR/CodeGen/coro-task.cpp b/clang/test/CIR/CodeGen/coro-task.cpp index d7b06e1f61aa7..b98c866de524b 100644 --- a/clang/test/CIR/CodeGen/coro-task.cpp +++ b/clang/test/CIR/CodeGen/coro-task.cpp @@ -323,7 +323,6 @@ folly::coro::Task<void> silly_coro() { // CIR-NOT: cir.call @_ZN5folly4coro4TaskIvE12promise_type11return_voidEv // CIR: cir.await(final, ready : { - folly::coro::Task<void> yield(); folly::coro::Task<void> yield1() { auto t = yield(); @@ -372,3 +371,88 @@ folly::coro::Task<void> yield1() { // CIR: },) // CHECK: } + +folly::coro::Task<int> go(int const& val); +folly::coro::Task<int> go1() { + auto task = go(1); + co_return co_await task; +} + +// CIR: cir.func coroutine {{.*}} @_Z3go1v() {{.*}} ![[IntTask]] +// CIR: %[[IntTaskAddr:.*]] = cir.alloca ![[IntTask]], !cir.ptr<![[IntTask]]>, ["task", init] + +// CIR: cir.await(init, ready : { +// CIR: }, suspend : { +// CIR: }, resume : { +// CIR: },) +// CIR: } + +// The call to go(1) has its own scope due to full-expression rules. +// CIR: cir.scope { +// CIR: %[[OneAddr:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["ref.tmp1", init] {alignment = 4 : i64} +// CIR: %[[One:.*]] = cir.const #cir.int<1> : !s32i +// CIR: cir.store{{.*}} %[[One]], %[[OneAddr]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[IntTaskTmp:.*]] = cir.call @_Z2goRKi(%[[OneAddr]]) : (!cir.ptr<!s32i>) -> ![[IntTask]] +// CIR: cir.store{{.*}} %[[IntTaskTmp]], %[[IntTaskAddr]] : ![[IntTask]], !cir.ptr<![[IntTask]]> +// CIR: } + +// CIR: %[[CoReturnValAddr:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__coawait_resume_rval"] {alignment = 1 : i64} +// CIR: cir.await(user, ready : { +// CIR: }, suspend : { +// CIR: }, resume : { +// CIR: %[[ResumeVal:.*]] = cir.call @_ZN5folly4coro4TaskIiE12await_resumeEv(%3) +// CIR: cir.store{{.*}} %[[ResumeVal]], %[[CoReturnValAddr]] : !s32i, !cir.ptr<!s32i> +// CIR: },) +// CIR: %[[V:.*]] = cir.load{{.*}} %[[CoReturnValAddr]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.call @_ZN5folly4coro4TaskIiE12promise_type12return_valueEi({{.*}}, %[[V]]) + + +folly::coro::Task<int> go1_lambda() { + auto task = []() -> folly::coro::Task<int> { + co_return 1; + }(); + co_return co_await task; +} + +// CIR: cir.func coroutine {{.*}} @_ZZ10go1_lambdavENK3$_0clEv{{.*}} ![[IntTask]] +// CIR: cir.func coroutine {{.*}} @_Z10go1_lambdav() {{.*}} ![[IntTask]] + +folly::coro::Task<int> go4() { + auto* fn = +[](int const& i) -> folly::coro::Task<int> { co_return i; }; + auto task = fn(3); + co_return co_await std::move(task); +} + +// CIR: cir.func coroutine {{.*}} @_Z3go4v() {{.*}} ![[IntTask]] + +// CIR: cir.await(init, ready : { +// CIR: }, suspend : { +// CIR: }, resume : { +// CIR: },) +// CIR: } + +// CIR: %[[RES:.*]] = cir.scope { +// CIR: %[[LAMBDA:.*]] = cir.alloca !rec_anon2E2, !cir.ptr<!rec_anon2E2>, ["ref.tmp1"] {alignment = 1 : i64} + +// Get the lambda invoker ptr via `lambda operator folly::coro::Task<int> (*)(int const&)()` +// CIR: %[[INVOKER:.*]] = cir.call @_ZZ3go4vENK3$_0cvPFN5folly4coro4TaskIiEERKiEEv(%[[LAMBDA]]) nothrow : (!cir.ptr<!rec_anon2E2>) -> !cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>> +// CIR: %[[PLUS:.*]] = cir.unary(plus, %[[INVOKER]]) : !cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>, !cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>> +// CIR: cir.yield %[[PLUS]] : !cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>> +// CIR: } +// CIR: cir.store{{.*}} %[[RES]], %[[PTR_TASK:.*]] : !cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>, !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>> +// CIR: cir.scope { +// CIR: %[[ARG:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["ref.tmp2", init] {alignment = 4 : i64} +// CIR: %[[LAMBDA2:.*]] = cir.load{{.*}} %[[PTR_TASK]] : !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>>, !cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>> +// CIR: %[[THREE:.*]] = cir.const #cir.int<3> : !s32i +// CIR: cir.store{{.*}} %[[THREE]], %[[ARG]] : !s32i, !cir.ptr<!s32i> + +// Call invoker, which calls operator() indirectly. +// CIR: %[[RES:.*]] = cir.call %[[LAMBDA2]](%[[ARG]]) : (!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>, !cir.ptr<!s32i>) -> ![[IntTask]] +// CIR: cir.store{{.*}} %[[RES]], %4 : ![[IntTask]], !cir.ptr<![[IntTask]]> +// CIR: } + +// CIR: cir.await(user, ready : { +// CIR: }, suspend : { +// CIR: }, resume : { +// CIR: },) +// CIR: } diff --git a/clang/test/CIR/CodeGen/trivial-ctor-const-init.cpp b/clang/test/CIR/CodeGen/trivial-ctor-const-init.cpp index 7429549100362..76c0dd208cb64 100644 --- a/clang/test/CIR/CodeGen/trivial-ctor-const-init.cpp +++ b/clang/test/CIR/CodeGen/trivial-ctor-const-init.cpp @@ -27,11 +27,13 @@ StructWithCtorArg withArg = 0.0; // OGCG: @withArg = global %struct.StructWithCtorArg zeroinitializer // CIR: cir.func {{.*}} @__cxx_global_var_init() -// CIR: %[[TMP0:.*]] = cir.alloca !cir.double, !cir.ptr<!cir.double>, ["ref.tmp0"] // CIR: %[[WITH_ARG:.*]] = cir.get_global @withArg : !cir.ptr<!rec_StructWithCtorArg> -// CIR: %[[ZERO:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.double -// CIR: cir.store{{.*}} %[[ZERO]], %[[TMP0]] : !cir.double, !cir.ptr<!cir.double> -// CIR: cir.call @_ZN17StructWithCtorArgC1ERKd(%[[WITH_ARG]], %[[TMP0]]) : (!cir.ptr<!rec_StructWithCtorArg>, !cir.ptr<!cir.double>) -> () +// CIR: cir.scope { +// CIR: %[[TMP0:.*]] = cir.alloca !cir.double, !cir.ptr<!cir.double>, ["ref.tmp0"] +// CIR: %[[ZERO:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.double +// CIR: cir.store{{.*}} %[[ZERO]], %[[TMP0]] : !cir.double, !cir.ptr<!cir.double> +// CIR: cir.call @_ZN17StructWithCtorArgC1ERKd(%[[WITH_ARG]], %[[TMP0]]) : (!cir.ptr<!rec_StructWithCtorArg>, !cir.ptr<!cir.double>) -> () +// CIR: } // LLVM: define {{.*}} void @__cxx_global_var_init() // LLVM: %[[TMP0:.*]] = alloca double >From feefc7dbb5012e928fce49aca3217c4c1c4cdf4f Mon Sep 17 00:00:00 2001 From: Andres Salamanca <[email protected]> Date: Tue, 13 Jan 2026 21:19:30 -0500 Subject: [PATCH 2/2] Address review comments --- clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp index a6814382edce2..11da95c996ea5 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp @@ -13,6 +13,7 @@ #include "CIRGenBuilder.h" #include "CIRGenFunction.h" #include "CIRGenValue.h" +#include "mlir/IR/Builders.h" #include "clang/CIR/Dialect/IR/CIRAttrs.h" #include "clang/AST/Expr.h" @@ -761,9 +762,16 @@ void AggExprEmitter::VisitLambdaExpr(LambdaExpr *e) { void AggExprEmitter::VisitExprWithCleanups(ExprWithCleanups *e) { CIRGenFunction::RunCleanupsScope cleanups(cgf); - auto &builder = cgf.getBuilder(); - auto scopeLoc = cgf.getLoc(e->getSourceRange()); + CIRGenBuilderTy &builder = cgf.getBuilder(); + mlir::Location scopeLoc = cgf.getLoc(e->getSourceRange()); mlir::OpBuilder::InsertPoint scopeBegin; + + // Explicitly introduce a scope for cleanup expressions, even though this + // overlaps with the RunCleanupsScope above. + // + // CIR does not yet model cleanup scopes explicitly, so a lexical scope is + // used as a temporary approximation. This is expected to be revisited once + // cleanup handling is redesigned. cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/ [&](mlir::OpBuilder &b, mlir::Location loc) { scopeBegin = b.saveInsertionPoint(); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
