diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index acfc937a11993..78199adec1a05 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 coroCoYield() { return false; } static bool coroutineExceptions() { return false; }; diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp index 9251106a641b1..b636022251f0c 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 367c56f07f734..77cff8d3c3f59 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp @@ -722,7 +722,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 6cd494317f2d8..2c4686e27a460 100644 --- a/clang/test/CIR/CodeGen/coro-task.cpp +++ b/clang/test/CIR/CodeGen/coro-task.cpp @@ -322,3 +322,88 @@ folly::coro::Task silly_coro() { // CIR: cir.call @_ZN5folly4coro4TaskIvE12promise_type11return_voidEv // CIR-NOT: cir.call @_ZN5folly4coro4TaskIvE12promise_type11return_voidEv // CIR: cir.await(final, ready : { + +folly::coro::Task go(int const& val); +folly::coro::Task go1() { + auto task = go(1); + co_return co_await task; +} + +// CIR: cir.func coroutine {{.*}} @_Z3go1v() {{.*}} ![[IntTask]] +// CIR: %[[IntTaskAddr:.*]] = cir.alloca ![[IntTask]], !cir.ptr, ["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, ["ref.tmp1", init] {alignment = 4 : i64} +// CIR: %[[One:.*]] = cir.const #cir.int<1> : !s32i +// CIR: cir.store{{.*}} %[[One]], %[[OneAddr]] : !s32i, !cir.ptr +// CIR: %[[IntTaskTmp:.*]] = cir.call @_Z2goRKi(%[[OneAddr]]) : (!cir.ptr) -> ![[IntTask]] +// CIR: cir.store{{.*}} %[[IntTaskTmp]], %[[IntTaskAddr]] : ![[IntTask]], !cir.ptr +// CIR: } + +// CIR: %[[CoReturnValAddr:.*]] = cir.alloca !s32i, !cir.ptr, ["__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 +// CIR: },) +// CIR: %[[V:.*]] = cir.load{{.*}} %[[CoReturnValAddr]] : !cir.ptr, !s32i +// CIR: cir.call @_ZN5folly4coro4TaskIiE12promise_type12return_valueEi({{.*}}, %[[V]]) + + +folly::coro::Task go1_lambda() { + auto task = []() -> folly::coro::Task { + 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 go4() { + auto* fn = +[](int const& i) -> folly::coro::Task { 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, ["ref.tmp1"] {alignment = 1 : i64} + +// Get the lambda invoker ptr via `lambda operator folly::coro::Task (*)(int const&)()` +// CIR: %[[INVOKER:.*]] = cir.call @_ZZ3go4vENK3$_0cvPFN5folly4coro4TaskIiEERKiEEv(%[[LAMBDA]]) nothrow : (!cir.ptr) -> !cir.ptr) -> ![[IntTask]]>> +// CIR: %[[PLUS:.*]] = cir.unary(plus, %[[INVOKER]]) : !cir.ptr) -> ![[IntTask]]>>, !cir.ptr) -> ![[IntTask]]>> +// CIR: cir.yield %[[PLUS]] : !cir.ptr) -> ![[IntTask]]>> +// CIR: } +// CIR: cir.store{{.*}} %[[RES]], %[[PTR_TASK:.*]] : !cir.ptr) -> ![[IntTask]]>>, !cir.ptr) -> ![[IntTask]]>>> +// CIR: cir.scope { +// CIR: %[[ARG:.*]] = cir.alloca !s32i, !cir.ptr, ["ref.tmp2", init] {alignment = 4 : i64} +// CIR: %[[LAMBDA2:.*]] = cir.load{{.*}} %[[PTR_TASK]] : !cir.ptr) -> ![[IntTask]]>>>, !cir.ptr) -> ![[IntTask]]>> +// CIR: %[[THREE:.*]] = cir.const #cir.int<3> : !s32i +// CIR: cir.store{{.*}} %[[THREE]], %[[ARG]] : !s32i, !cir.ptr + +// Call invoker, which calls operator() indirectly. +// CIR: %[[RES:.*]] = cir.call %[[LAMBDA2]](%[[ARG]]) : (!cir.ptr) -> ![[IntTask]]>>, !cir.ptr) -> ![[IntTask]] +// CIR: cir.store{{.*}} %[[RES]], %4 : ![[IntTask]], !cir.ptr +// 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, ["ref.tmp0"] // CIR: %[[WITH_ARG:.*]] = cir.get_global @withArg : !cir.ptr -// CIR: %[[ZERO:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.double -// CIR: cir.store{{.*}} %[[ZERO]], %[[TMP0]] : !cir.double, !cir.ptr -// CIR: cir.call @_ZN17StructWithCtorArgC1ERKd(%[[WITH_ARG]], %[[TMP0]]) : (!cir.ptr, !cir.ptr) -> () +// CIR: cir.scope { +// CIR: %[[TMP0:.*]] = cir.alloca !cir.double, !cir.ptr, ["ref.tmp0"] +// CIR: %[[ZERO:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.double +// CIR: cir.store{{.*}} %[[ZERO]], %[[TMP0]] : !cir.double, !cir.ptr +// CIR: cir.call @_ZN17StructWithCtorArgC1ERKd(%[[WITH_ARG]], %[[TMP0]]) : (!cir.ptr, !cir.ptr) -> () +// CIR: } // LLVM: define {{.*}} void @__cxx_global_var_init() // LLVM: %[[TMP0:.*]] = alloca double