https://github.com/Andres-Salamanca updated https://github.com/llvm/llvm-project/pull/213191
>From e12ca364ac24d0da2c0568c9a41040dc2f9e8003 Mon Sep 17 00:00:00 2001 From: Andres Salamanca <[email protected]> Date: Mon, 13 Jul 2026 14:34:45 -0500 Subject: [PATCH 1/4] initial coro_suspend --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 36 +++++++++++++++++++ clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp | 6 +++- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 12 +++++++ .../test/CIR/CodeGenCoroutines/coro-task.cpp | 12 +++---- clang/test/CIR/IR/await.cir | 6 ++-- clang/test/CIR/IR/co-return.cir | 3 +- clang/test/CIR/IR/coro-body.cir | 3 +- clang/test/CIR/IR/func.cir | 3 +- clang/test/CIR/IR/invalid-await.cir | 18 +++++++++- clang/test/CIR/IR/invalid-coro-body.cir | 3 +- clang/test/CIR/IR/invalid-coro-suspend.cir | 17 +++++++++ 11 files changed, 105 insertions(+), 14 deletions(-) create mode 100644 clang/test/CIR/IR/invalid-coro-suspend.cir diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 49ecec207cd45..4a291cf69eaad 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -4946,6 +4946,42 @@ def CIR_CoroSizeOp : CIR_CoroIntrinsicOp<"size", (ins), }]; } +//===----------------------------------------------------------------------===// +// CoroSuspendPoint +//===----------------------------------------------------------------------===// + +def CIR_CoroSuspendPoint : CIR_Op<"coro.suspend.point", [ + Pure, Terminator, HasParent<"AwaitOp"> +]> { + let summary = ""; + let description = [{ + }]; + + let assemblyFormat = [{ + attr-dict + }]; + + let hasLLVMLowering = false; +} + +//===----------------------------------------------------------------------===// +// CoroSuspendPointDest +//===----------------------------------------------------------------------===// + +def CIR_CoroSuspendPointDest : CIR_Op<"coro.suspend.point.dest", [ + Pure +]> { + let summary = ""; + let description = [{ + }]; + + let assemblyFormat = [{ + attr-dict + }]; + + let hasLLVMLowering = false; +} + //===----------------------------------------------------------------------===// // CopyOp //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp index 9111c2ac98863..00d7a0f162380 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp @@ -15,6 +15,7 @@ #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/TargetInfo.h" +#include "clang/CIR/Dialect/IR/CIRDialect.h" #include "clang/CIR/Dialect/IR/CIRTypes.h" #include "clang/CIR/MissingFeatures.h" @@ -508,6 +509,9 @@ CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt &s) { cgm.getBuilder(), openCurlyLoc, mlir::ValueRange{builder.getNullPtr(builder.getVoidPtrTy(), openCurlyLoc), builder.getBool(false, openCurlyLoc)}); + + cir::CoroSuspendPointDest::create(builder, openCurlyLoc); + if (auto *ret = cast_or_null<ReturnStmt>(s.getReturnStmt())) { // Since we already emitted the return value above, so we shouldn't // emit it again here. @@ -589,7 +593,7 @@ emitSuspendExpression(CIRGenFunction &cgf, CGCoroData &coro, } // Signals the parent that execution flows to next region. - cir::YieldOp::create(builder, loc); + cir::CoroSuspendPoint::create(builder,loc); }, /*resumeBuilder=*/ [&](mlir::OpBuilder &b, mlir::Location loc) { diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index cd94219655e02..556d746bbd8eb 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -31,6 +31,7 @@ #include "llvm/ADT/SetOperations.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/TypeSwitch.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/LogicalResult.h" using namespace mlir; @@ -2863,6 +2864,7 @@ mlir::LogicalResult cir::FuncOp::verify() { if (!isDeclaration() && getCoroutine()) { bool foundAwait = false; int coroBodyCount = 0; + int coroSuspendPointDestCount = 0; this->walk([&](Operation *op) { if (auto await = dyn_cast<AwaitOp>(op)) { foundAwait = true; @@ -2871,6 +2873,11 @@ mlir::LogicalResult cir::FuncOp::verify() { if (coroBodyCount > 1) { return mlir::WalkResult::interrupt(); } + } else if (isa<CoroSuspendPointDest>(op)) { + coroSuspendPointDestCount++; + if (coroSuspendPointDestCount > 1) { + return mlir::WalkResult::interrupt(); + } } return mlir::WalkResult::advance(); }); @@ -2880,6 +2887,9 @@ mlir::LogicalResult cir::FuncOp::verify() { if (coroBodyCount != 1) return emitOpError() << "coroutine function must have exactly one cir.body op"; + if (coroSuspendPointDestCount != 1) + return emitOpError() + << "coroutine function must have exactly one cir.coro.suspend.point.dest"; } llvm::SmallSet<llvm::StringRef, 16> labels; @@ -3281,6 +3291,8 @@ mlir::ValueRange cir::AwaitOp::getSuccessorInputs(RegionSuccessor successor) { LogicalResult cir::AwaitOp::verify() { if (!isa<ConditionOp>(this->getReady().back().getTerminator())) return emitOpError("ready region must end with cir.condition"); + if (!isa<CoroSuspendPoint>(this->getSuspend().back().getTerminator())) + return emitOpError("ready region must end with cir.coro.suspend.point"); return success(); } diff --git a/clang/test/CIR/CodeGenCoroutines/coro-task.cpp b/clang/test/CIR/CodeGenCoroutines/coro-task.cpp index d0ba8c153bdbb..1095d8821a707 100644 --- a/clang/test/CIR/CodeGenCoroutines/coro-task.cpp +++ b/clang/test/CIR/CodeGenCoroutines/coro-task.cpp @@ -125,7 +125,7 @@ VoidTask silly_task() { // CIR: cir.call @_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIvE12promise_typeEEES_IT_E(%[[CoroHandleVoidAddr]], %[[CoroHandlePromiseReload]]) // CIR: %[[CoroHandleVoidReload:.*]] = cir.load{{.*}} %[[CoroHandleVoidAddr]] : !cir.ptr<![[CoroHandleVoid]]>, ![[CoroHandleVoid]] // CIR: cir.call @_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SuspendAlwaysAddr]], %[[CoroHandleVoidReload]]) -// CIR: cir.yield +// CIR: cir.coro.suspend.point // OGCG: init.suspend: // OGCG: %[[Save:.*]] = call token @llvm.coro.save(ptr null) @@ -258,7 +258,7 @@ folly::coro::Task<int> byRef(const std::string& s) { // CIR: cir.call @_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIiE12promise_typeEEES_IT_E(%[[CoroHandleVoidAddr]], %[[CoroHandlePromiseReload]]) // CIR: %[[CoroHandleVoidReload:.*]] = cir.load{{.*}} %[[CoroHandleVoidAddr]] : !cir.ptr<![[CoroHandleVoid]]>, ![[CoroHandleVoid]] // CIR: cir.call @_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SuspendAlwaysAddr]], %[[CoroHandleVoidReload]]) -// CIR: cir.yield +// CIR: cir.coro.suspend.point // CIR: }, resume : { // CIR: cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SuspendAlwaysAddr]]) // CIR: cir.yield @@ -349,7 +349,7 @@ folly::coro::Task<void> yield1() { // CIR: cir.call @_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIvE12promise_typeEEES_IT_E(%[[CH_VOID0]], %[[PROM_RELOAD0]]){{.*}} // CIR: %[[VOID_RELOAD0:.*]] = cir.load{{.*}} %[[CH_VOID0]] // CIR: cir.call @_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SUSP0]], %[[VOID_RELOAD0]]){{.*}} -// CIR: cir.yield +// CIR: cir.coro.suspend.point // CIR: }, resume : { // CIR: cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SUSP0]]){{.*}} // CIR: cir.yield @@ -372,7 +372,7 @@ folly::coro::Task<void> yield1() { // CIR: cir.call @_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIvE12promise_typeEEES_IT_E(%[[CH_VOID1]], %[[PROM_RELOAD1]]){{.*}} // CIR: %[[VOID_RELOAD1:.*]] = cir.load{{.*}} %[[CH_VOID1]] // CIR: cir.call @_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SUSP1]], %[[VOID_RELOAD1]]){{.*}} -// CIR: cir.yield +// CIR: cir.coro.suspend.point // CIR: }, resume : { // CIR: cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SUSP1]]){{.*}} // CIR: cir.yield @@ -394,7 +394,7 @@ folly::coro::Task<void> yield1() { // CIR: cir.call @_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIvE12promise_typeEEES_IT_E(%[[CH_VOID2]], %[[PROM_RELOAD2]]){{.*}} // CIR: %[[VOID_RELOAD2:.*]] = cir.load{{.*}} %[[CH_VOID2]] // CIR: cir.call @_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SUSP2]], %[[VOID_RELOAD2]]){{.*}} -// CIR: cir.yield +// CIR: cir.coro.suspend.point // CIR: }, resume : { // CIR: cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SUSP2]]){{.*}} // CIR: cir.yield @@ -543,7 +543,7 @@ folly::coro::Task<int> go4() { // CIR: = cir.call @_ZN5folly4coro4TaskIiE11await_readyEv(%[[TASK_ADDR]]) // CIR: cir.condition( // CIR: }, suspend : { -// CIR: cir.yield +// CIR: cir.coro.suspend.point // CIR: }, resume : { // CIR: cir.yield // CIR: },) diff --git a/clang/test/CIR/IR/await.cir b/clang/test/CIR/IR/await.cir index 06b925bcc07b3..1305c4bb31e0f 100644 --- a/clang/test/CIR/IR/await.cir +++ b/clang/test/CIR/IR/await.cir @@ -5,12 +5,13 @@ cir.func coroutine @checkPrintParse(%arg0 : !cir.bool) { cir.await(user, ready : { cir.condition(%arg0) }, suspend : { - cir.yield + cir.coro.suspend.point }, resume : { cir.yield },) cir.yield } + cir.coro.suspend.point.dest cir.return } @@ -18,7 +19,8 @@ cir.func coroutine @checkPrintParse(%arg0 : !cir.bool) { // CHECK: cir.await(user, ready : { // CHECK: cir.condition(%arg0) // CHECK: }, suspend : { -// CHECK: cir.yield +// CHECK: cir.coro.suspend.point // CHECK: }, resume : { // CHECK: cir.yield // CHECK: },) +// CHECK: cir.coro.suspend.point.dest diff --git a/clang/test/CIR/IR/co-return.cir b/clang/test/CIR/IR/co-return.cir index 613399b142650..d6c3be2da80ad 100644 --- a/clang/test/CIR/IR/co-return.cir +++ b/clang/test/CIR/IR/co-return.cir @@ -4,12 +4,13 @@ cir.func coroutine @coro_co_return(%arg0 : !cir.bool) { cir.await(user, ready : { cir.condition(%arg0) }, suspend : { - cir.yield + cir.coro.suspend.point }, resume : { cir.yield },) cir.co_return } + cir.coro.suspend.point.dest cir.return } diff --git a/clang/test/CIR/IR/coro-body.cir b/clang/test/CIR/IR/coro-body.cir index 1c0dae384691a..b1560485303b1 100644 --- a/clang/test/CIR/IR/coro-body.cir +++ b/clang/test/CIR/IR/coro-body.cir @@ -5,12 +5,13 @@ cir.func coroutine @coro_body(%arg0 : !cir.bool) { cir.await(user, ready : { cir.condition(%arg0) }, suspend : { - cir.yield + cir.coro.suspend.point }, resume : { cir.yield },) cir.co_return } + cir.coro.suspend.point.dest cir.return } diff --git a/clang/test/CIR/IR/func.cir b/clang/test/CIR/IR/func.cir index 4c6bd33b386ab..ffc3a503c8c48 100644 --- a/clang/test/CIR/IR/func.cir +++ b/clang/test/CIR/IR/func.cir @@ -115,12 +115,13 @@ cir.func coroutine @coro() { %1 = cir.load align(1) %0 : !cir.ptr<!cir.bool>, !cir.bool cir.condition(%1) }, suspend : { - cir.yield + cir.coro.suspend.point }, resume : { cir.yield },) cir.yield } + cir.coro.suspend.point.dest cir.return } // CHECK: cir.func{{.*}} coroutine @coro() diff --git a/clang/test/CIR/IR/invalid-await.cir b/clang/test/CIR/IR/invalid-await.cir index fe0fd76769e44..cc6d011718ad0 100644 --- a/clang/test/CIR/IR/invalid-await.cir +++ b/clang/test/CIR/IR/invalid-await.cir @@ -10,12 +10,28 @@ cir.func coroutine @missing_condition() { cir.await(user, ready : { // expected-error {{ready region must end with cir.condition}} cir.yield }, suspend : { - cir.yield + cir.coro.suspend.point }, resume : { cir.yield },) } cir.coro.body { } + cir.coro.suspend.point.dest + cir.return +} + +cir.func coroutine @missing_suspend(%arg0 : !cir.bool) { + cir.coro.body { + cir.await(user, ready : { // expected-error {{ready region must end with cir.coro.suspend.point}} + cir.condition(%arg0) + }, suspend : { + cir.yield + }, resume : { + cir.yield + },) + cir.yield + } + cir.coro.suspend.point.dest cir.return } diff --git a/clang/test/CIR/IR/invalid-coro-body.cir b/clang/test/CIR/IR/invalid-coro-body.cir index e08c96192e5b5..f247220c7d73d 100644 --- a/clang/test/CIR/IR/invalid-coro-body.cir +++ b/clang/test/CIR/IR/invalid-coro-body.cir @@ -11,11 +11,12 @@ cir.func coroutine @must_have_one_coro_body(%arg0 : !cir.bool) { // expected-er cir.await(user, ready : { cir.condition(%arg0) }, suspend : { - cir.yield + cir.coro.suspend.point }, resume : { cir.yield },) } cir.coro.body { } + cir.coro.suspend.point.dest } diff --git a/clang/test/CIR/IR/invalid-coro-suspend.cir b/clang/test/CIR/IR/invalid-coro-suspend.cir new file mode 100644 index 0000000000000..3a45e22433a58 --- /dev/null +++ b/clang/test/CIR/IR/invalid-coro-suspend.cir @@ -0,0 +1,17 @@ +// RUN: cir-opt %s -verify-diagnostics -split-input-file + + +cir.func coroutine @must_have_one_coro_suspend_dest(%arg0 : !cir.bool) { // expected-error {{coroutine function must have exactly one cir.coro.suspend.point.dest}} + cir.coro.body { + cir.await(user, ready : { + cir.condition(%arg0) + }, suspend : { + cir.coro.suspend.point + }, resume : { + cir.yield + },) + } + cir.coro.suspend.point.dest + cir.coro.suspend.point.dest +} + >From 8a3e7a6644abcc6630345cac7b50949bd9b0d384 Mon Sep 17 00:00:00 2001 From: Andres Salamanca <[email protected]> Date: Thu, 30 Jul 2026 21:15:54 -0500 Subject: [PATCH 2/4] [CIR] Add structured control flow for coroutine suspend points --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 78 +- clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp | 32 +- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 82 +- .../test/CIR/CodeGenCoroutines/coro-task.cpp | 709 +++++++++--------- clang/test/CIR/IR/await.cir | 25 +- clang/test/CIR/IR/co-return.cir | 26 +- clang/test/CIR/IR/coro-body.cir | 26 +- clang/test/CIR/IR/coro-ret-point.cir | 23 + clang/test/CIR/IR/func.cir | 26 +- clang/test/CIR/IR/invalid-await.cir | 36 +- clang/test/CIR/IR/invalid-coro-body.cir | 3 +- clang/test/CIR/IR/invalid-coro-ret-point.cir | 55 ++ clang/test/CIR/IR/invalid-coro-suspend.cir | 30 +- 13 files changed, 716 insertions(+), 435 deletions(-) create mode 100644 clang/test/CIR/IR/coro-ret-point.cir create mode 100644 clang/test/CIR/IR/invalid-coro-ret-point.cir diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 4a291cf69eaad..8d0ec7f0c98bb 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -936,7 +936,7 @@ def CIR_StoreOp : CIR_Op<"store", [ defvar CIR_ReturnableScopes = [ "FuncOp", "ScopeOp", "IfOp", "SwitchOp", "CaseOp", "CleanupScopeOp", - "DoWhileOp", "WhileOp", "ForOp", "TryOp" + "DoWhileOp", "WhileOp", "ForOp", "TryOp", "CoroRetPointOp" ]; def CIR_ReturnOp : CIR_Op<"return", [ @@ -1087,7 +1087,7 @@ def CIR_ConditionOp : CIR_Op<"condition", [ defvar CIR_YieldableScopes = [ "ArrayCtor", "ArrayDtor", "AwaitOp", "CaseOp", "CleanupScopeOp", "CoroBodyOp", "DoWhileOp", "ForOp", "GlobalOp", "IfOp", "LocalInitOp", "ScopeOp", "SwitchOp", - "TernaryOp", "TryOp", "WhileOp" + "TernaryOp", "TryOp", "WhileOp", "CoroRetPointOp" ]; def CIR_YieldOp : CIR_Op<"yield", [ @@ -4950,11 +4950,36 @@ def CIR_CoroSizeOp : CIR_CoroIntrinsicOp<"size", (ins), // CoroSuspendPoint //===----------------------------------------------------------------------===// -def CIR_CoroSuspendPoint : CIR_Op<"coro.suspend.point", [ - Pure, Terminator, HasParent<"AwaitOp"> +def CIR_CoroSuspendPoint : CIR_Op<"coro.suspend_point", [ + Pure, Terminator, HasParent<"AwaitOp">, HasAncestor<"CoroRetPointOp"> ]> { - let summary = ""; + let summary = "Marks the point where a coroutine actually suspends"; let description = [{ + Terminates the `suspend` region of a `cir.await` op, marking the exact + point where control returns to the caller/resumer if the coroutine + decides to suspend. + + This op must appear inside the `suspend` region of a `cir.await`, and + that `cir.await` must in turn be nested within a `cir.coro.ret_point`. + During lowering to FlattenCFG, `cir.coro.suspend_point` becomes the + branch target that routes control to one of three destinations + depending on how the coroutine resumes: the resume block (normal + continuation), the cleanup/destroy block, or the ret/exit block that + hands control back to the caller. + + Example: + ```mlir + cir.await(user, ready : { + ... + cir.condition(%ready) + }, suspend : { + ... + cir.coro.suspend_point + }, resume : { + ... + cir.yield + },) + ``` }]; let assemblyFormat = [{ @@ -4965,21 +4990,54 @@ def CIR_CoroSuspendPoint : CIR_Op<"coro.suspend.point", [ } //===----------------------------------------------------------------------===// -// CoroSuspendPointDest +// CoroRetPoint //===----------------------------------------------------------------------===// -def CIR_CoroSuspendPointDest : CIR_Op<"coro.suspend.point.dest", [ - Pure +def CIR_CoroRetPointOp : CIR_Op<"coro.ret_point", [ + DeclareOpInterfaceMethods<RegionBranchOpInterface, ["getSuccessorInputs"]>, + NoRegionArguments ]> { - let summary = ""; + + let summary = "Marks the coroutine's structured suspend/exit region"; let description = [{ + Pairs a coroutine's body its normal execution, including any + `cir.await`s and cleanups with a single, shared exit destination + (`retRegion`) that every suspend point in the body jumps to. + + Every `cir.coro.suspend_point` inside `bodyRegion` is guaranteed to have + `cir.coro.ret_point` as an ancestor, so all suspend paths converge on + the same `retRegion` regardless of where in the body they occur. This + gives the coroutine a single, well-defined place to run final teardown + (e.g. `__builtin_coro_end`) and return control to the caller. + + Example: + ```mlir + cir.coro.ret_point { + // body: awaits, cleanups, etc. + }, ret : { + // shared jump target for any suspend point in the body + cir.coro.intrinsic.end(...) + cir.return + } + ``` }]; + let regions = (region AnyRegion:$bodyRegion, + AnyRegion:$retRegion); + let skipDefaultBuilders = 1; + + let builders = [ + OpBuilder<(ins "BuilderCallbackRef":$bodyBuilder, + "BuilderCallbackRef":$retBuilder)> + ]; + let assemblyFormat = [{ + $bodyRegion `,` + `ret` `:` $retRegion attr-dict }]; - let hasLLVMLowering = false; + let hasVerifier = 1; } //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp index 00d7a0f162380..7fc59b30e8c3a 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp @@ -15,8 +15,6 @@ #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/TargetInfo.h" -#include "clang/CIR/Dialect/IR/CIRDialect.h" -#include "clang/CIR/Dialect/IR/CIRTypes.h" #include "clang/CIR/MissingFeatures.h" using namespace clang; @@ -376,11 +374,25 @@ CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt &s) { // Handle allocation failure if 'ReturnStmtOnAllocFailure' was provided. if (s.getReturnStmtOnAllocFailure()) cgm.errorNYI("handle coroutine return alloc failure"); - + cir::CoroRetPointOp coroRet = nullptr; + mlir::OpBuilder::InsertPoint coroRetRegion; { assert(!cir::MissingFeatures::generateDebugInfo()); ParamReferenceReplacerRAII paramReplacer(localDeclMap); RunCleanupsScope resumeScope(*this); + mlir::OpBuilder::InsertPoint coroRetBody; + coroRet = cir::CoroRetPointOp::create( + builder, openCurlyLoc, + /*bodyBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location) { + coroRetBody = b.saveInsertionPoint(); + }, + /*retBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location) { + coroRetRegion = b.saveInsertionPoint(); + }); + mlir::OpBuilder::InsertionGuard guard(builder); + builder.restoreInsertionPoint(coroRetBody); ehStack.pushCleanup<CallCoroDelete>(NormalAndEHCleanup, s.getDeallocate()); // Create mapping between parameters and copy-params for coroutine // function. @@ -510,7 +522,15 @@ CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt &s) { mlir::ValueRange{builder.getNullPtr(builder.getVoidPtrTy(), openCurlyLoc), builder.getBool(false, openCurlyLoc)}); - cir::CoroSuspendPointDest::create(builder, openCurlyLoc); + mlir::Block &coroRetBodyBlock = coroRet.getBodyRegion().back(); + { + mlir::OpBuilder::InsertionGuard guard(builder); + builder.setInsertionPointToEnd(&coroRetBodyBlock); + cir::YieldOp::create(builder, openCurlyLoc); + } + + mlir::OpBuilder::InsertionGuard guard(builder); + builder.restoreInsertionPoint(coroRetRegion); if (auto *ret = cast_or_null<ReturnStmt>(s.getReturnStmt())) { // Since we already emitted the return value above, so we shouldn't @@ -519,6 +539,10 @@ CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt &s) { ret->setRetValue(nullptr); if (emitStmt(ret, /*useCurrentScope=*/true).failed()) return mlir::failure(); + mlir::Block *block = builder.getInsertionBlock(); + // emitReturnStmt() always creates a new insertion block after emitting the + // return. That block is unreachable in this case, so erase it. + block->erase(); // Set the return value back. The code generator, as the AST **Consumer**, // shouldn't change the AST. ret->setRetValue(previousRetValue); diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 556d746bbd8eb..950d092c1f95d 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2864,7 +2864,7 @@ mlir::LogicalResult cir::FuncOp::verify() { if (!isDeclaration() && getCoroutine()) { bool foundAwait = false; int coroBodyCount = 0; - int coroSuspendPointDestCount = 0; + int coroRetPointCount = 0; this->walk([&](Operation *op) { if (auto await = dyn_cast<AwaitOp>(op)) { foundAwait = true; @@ -2873,9 +2873,9 @@ mlir::LogicalResult cir::FuncOp::verify() { if (coroBodyCount > 1) { return mlir::WalkResult::interrupt(); } - } else if (isa<CoroSuspendPointDest>(op)) { - coroSuspendPointDestCount++; - if (coroSuspendPointDestCount > 1) { + } else if (isa<CoroRetPointOp>(op)) { + coroRetPointCount++; + if (coroRetPointCount > 1) { return mlir::WalkResult::interrupt(); } } @@ -2887,9 +2887,9 @@ mlir::LogicalResult cir::FuncOp::verify() { if (coroBodyCount != 1) return emitOpError() << "coroutine function must have exactly one cir.body op"; - if (coroSuspendPointDestCount != 1) - return emitOpError() - << "coroutine function must have exactly one cir.coro.suspend.point.dest"; + if (coroRetPointCount != 1) + return emitOpError() << "coroutine function must have exactly one " + "cir.coro.ret_point op"; } llvm::SmallSet<llvm::StringRef, 16> labels; @@ -3292,7 +3292,7 @@ LogicalResult cir::AwaitOp::verify() { if (!isa<ConditionOp>(this->getReady().back().getTerminator())) return emitOpError("ready region must end with cir.condition"); if (!isa<CoroSuspendPoint>(this->getSuspend().back().getTerminator())) - return emitOpError("ready region must end with cir.coro.suspend.point"); + return emitOpError("suspend region must end with cir.coro.suspend_point"); return success(); } @@ -3332,6 +3332,72 @@ void cir::CoroBodyOp::build(OpBuilder &builder, OperationState &result, bodyBuilder(builder, result.location); } +//===----------------------------------------------------------------------===// +// CoroRetPoint +//===----------------------------------------------------------------------===// + +void cir::CoroRetPointOp::build(OpBuilder &builder, OperationState &result, + BuilderCallbackRef bodyBuilder, + BuilderCallbackRef retBuilder) { + { + OpBuilder::InsertionGuard guard(builder); + Region *bodyRegion = result.addRegion(); + builder.createBlock(bodyRegion); + bodyBuilder(builder, result.location); + } + + { + OpBuilder::InsertionGuard guard(builder); + Region *retRegion = result.addRegion(); + builder.createBlock(retRegion); + retBuilder(builder, result.location); + } +} + +void cir::CoroRetPointOp::getSuccessorRegions( + mlir::RegionBranchPoint point, SmallVectorImpl<RegionSuccessor> ®ions) { + if (!point.isParent()) { + regions.emplace_back(getOperation()); + return; + } + + regions.push_back(RegionSuccessor(&getBodyRegion())); + regions.push_back(RegionSuccessor(&getRetRegion())); +} + +mlir::ValueRange +cir::CoroRetPointOp::getSuccessorInputs(RegionSuccessor successor) { + return ValueRange(); +} + +LogicalResult cir::CoroRetPointOp::verify() { + + // TODO: Should we verify that the return region contains a + // `cir.coro.intrinsic.end`? Coroutine semantics require `coro.end` to mark + // the end of access to the coroutine frame before the coroutine completes. + bool hasReturn = false; + this->getBodyRegion().walk<mlir::WalkOrder::PreOrder>( + [&](mlir::Operation *op) { + if (mlir::isa<cir::ReturnOp>(op)) { + hasReturn = true; + return WalkResult::interrupt(); + } + return WalkResult::advance(); + }); + + if (hasReturn) + return emitError() + << "body region must not contain 'cir.return' operations"; + + if (!mlir::isa<cir::YieldOp>(this->getBodyRegion().back().back())) + return emitError() << "body region must terminate with 'cir.yield'"; + + if (!mlir::isa<cir::ReturnOp>(this->getRetRegion().back().back())) + return emitError() << "return region must terminate with 'cir.return'"; + + return mlir::success(); +} + //===----------------------------------------------------------------------===// // CopyOp Definitions //===----------------------------------------------------------------------===// diff --git a/clang/test/CIR/CodeGenCoroutines/coro-task.cpp b/clang/test/CIR/CodeGenCoroutines/coro-task.cpp index 1095d8821a707..ad07e8d43b333 100644 --- a/clang/test/CIR/CodeGenCoroutines/coro-task.cpp +++ b/clang/test/CIR/CodeGenCoroutines/coro-task.cpp @@ -74,11 +74,11 @@ VoidTask silly_task() { // Call promise.get_return_object() to retrieve the task object. +// CIR: cir.coro.ret_point { +// CIR: cir.cleanup.scope { -// CIR: cir.cleanup.scope { - -// CIR: %[[RetObj:.*]] = cir.call @_ZN5folly4coro4TaskIvE12promise_type17get_return_objectEv(%[[VoidPromisseAddr]]) nothrow : {{.*}} -> ![[VoidTask]] -// CIR: cir.store{{.*}} %[[RetObj]], %[[VoidTaskAddr]] : ![[VoidTask]] +// CIR: %[[RetObj:.*]] = cir.call @_ZN5folly4coro4TaskIvE12promise_type17get_return_objectEv(%[[VoidPromisseAddr]]) nothrow : {{.*}} -> ![[VoidTask]] +// CIR: cir.store{{.*}} %[[RetObj]], %[[VoidTaskAddr]] : ![[VoidTask]] // OGCG: call void @llvm.lifetime.start.p0(ptr %[[VoidPromisseAddr]]) // OGCG: call void @_ZN5folly4coro4TaskIvE12promise_type17get_return_objectEv(ptr noundef nonnull align 1 dereferenceable(1) %[[VoidPromisseAddr]]) @@ -91,8 +91,8 @@ VoidTask silly_task() { // the suspend_always struct to use for cir.await. Note that we return by-value since we defer ABI lowering // to later passes, same is done elsewhere. -// CIR: %[[Tmp0:.*]] = cir.call @_ZN5folly4coro4TaskIvE12promise_type15initial_suspendEv(%[[VoidPromisseAddr]]) -// CIR: cir.store{{.*}} %[[Tmp0:.*]], %[[SuspendAlwaysAddr]] +// CIR: %[[Tmp0:.*]] = cir.call @_ZN5folly4coro4TaskIvE12promise_type15initial_suspendEv(%[[VoidPromisseAddr]]) +// CIR: cir.store{{.*}} %[[Tmp0:.*]], %[[SuspendAlwaysAddr]] // OGCG: call void @_ZN5folly4coro4TaskIvE12promise_type15initial_suspendEv(ptr noundef nonnull align 1 dereferenceable(1) %[[VoidPromisseAddr]]) @@ -102,9 +102,9 @@ VoidTask silly_task() { // First regions `ready` has a special cir.yield code to veto suspension. -// CIR: cir.await(init, ready : { -// CIR: %[[ReadyVeto:.*]] = cir.call @_ZNSt14suspend_always11await_readyEv(%[[SuspendAlwaysAddr]]) -// CIR: cir.condition(%[[ReadyVeto]]) +// CIR: cir.await(init, ready : { +// CIR: %[[ReadyVeto:.*]] = cir.call @_ZNSt14suspend_always11await_readyEv(%[[SuspendAlwaysAddr]]) +// CIR: cir.condition(%[[ReadyVeto]]) // OGCG: %[[Tmp0:.*]] = call noundef zeroext i1 @_ZNSt14suspend_always11await_readyEv(ptr noundef nonnull align 1 dereferenceable(1) %[[SuspendAlwaysAddr]]) // OGCG: br i1 %[[Tmp0]], label %init.ready, label %init.suspend @@ -118,14 +118,14 @@ VoidTask silly_task() { // // FIXME: add veto support for non-void await_suspends. -// CIR: }, suspend : { -// CIR: %[[FromAddrRes:.*]] = cir.call @_ZNSt16coroutine_handleIN5folly4coro4TaskIvE12promise_typeEE12from_addressEPv(%[[CoroFrameAddr]]) -// CIR: cir.store{{.*}} %[[FromAddrRes]], %[[CoroHandlePromiseAddr]] : ![[CoroHandlePromiseVoid]] -// CIR: %[[CoroHandlePromiseReload:.*]] = cir.load{{.*}} %[[CoroHandlePromiseAddr]] -// CIR: cir.call @_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIvE12promise_typeEEES_IT_E(%[[CoroHandleVoidAddr]], %[[CoroHandlePromiseReload]]) -// CIR: %[[CoroHandleVoidReload:.*]] = cir.load{{.*}} %[[CoroHandleVoidAddr]] : !cir.ptr<![[CoroHandleVoid]]>, ![[CoroHandleVoid]] -// CIR: cir.call @_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SuspendAlwaysAddr]], %[[CoroHandleVoidReload]]) -// CIR: cir.coro.suspend.point +// CIR: }, suspend : { +// CIR: %[[FromAddrRes:.*]] = cir.call @_ZNSt16coroutine_handleIN5folly4coro4TaskIvE12promise_typeEE12from_addressEPv(%[[CoroFrameAddr]]) +// CIR: cir.store{{.*}} %[[FromAddrRes]], %[[CoroHandlePromiseAddr]] : ![[CoroHandlePromiseVoid]] +// CIR: %[[CoroHandlePromiseReload:.*]] = cir.load{{.*}} %[[CoroHandlePromiseAddr]] +// CIR: cir.call @_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIvE12promise_typeEEES_IT_E(%[[CoroHandleVoidAddr]], %[[CoroHandlePromiseReload]]) +// CIR: %[[CoroHandleVoidReload:.*]] = cir.load{{.*}} %[[CoroHandleVoidAddr]] : !cir.ptr<![[CoroHandleVoid]]>, ![[CoroHandleVoid]] +// CIR: cir.call @_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SuspendAlwaysAddr]], %[[CoroHandleVoidReload]]) +// CIR: cir.coro.suspend_point // OGCG: init.suspend: // OGCG: %[[Save:.*]] = call token @llvm.coro.save(ptr null) @@ -138,10 +138,10 @@ VoidTask silly_task() { // Third region `resume` handles coroutine resuming logic. -// CIR: }, resume : { -// CIR: cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SuspendAlwaysAddr]]) -// CIR: cir.yield -// CIR: },) +// CIR: }, resume : { +// CIR: cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SuspendAlwaysAddr]]) +// CIR: cir.yield +// CIR: },) // OGCG: init.ready: // OGCG: call void @_ZNSt14suspend_always12await_resumeEv(ptr noundef nonnull align 1 dereferenceable(1) %[[SuspendAlwaysAddr]] @@ -153,31 +153,31 @@ VoidTask silly_task() { // - The final suspend co_await // - Return -// CIR: cir.coro.body { +// CIR: cir.coro.body { // The actual user written co_await -// CIR: cir.await(user, ready : { -// CIR: }, suspend : { -// CIR: }, resume : { -// CIR: },) +// CIR: cir.await(user, ready : { +// CIR: }, suspend : { +// CIR: }, resume : { +// CIR: },) // OGCG: cleanup.cont // OGCG: await.suspend: // OGCG: await.ready: // The promise call -// CIR: cir.call @_ZN5folly4coro4TaskIvE12promise_type11return_voidEv(%[[VoidPromisseAddr]]) -// CIR: cir.co_return -// CIR: } +// CIR: cir.call @_ZN5folly4coro4TaskIvE12promise_type11return_voidEv(%[[VoidPromisseAddr]]) +// CIR: cir.co_return +// CIR: } // OGCG: call void @_ZN5folly4coro4TaskIvE12promise_type11return_voidEv(ptr noundef nonnull align 1 dereferenceable(1) %[[VoidPromisseAddr]]) // The final suspend co_await -// CIR: cir.await(final, ready : { -// CIR: }, suspend : { -// CIR: }, resume : { -// CIR: },) -// CIR: cir.yield +// CIR: cir.await(final, ready : { +// CIR: }, suspend : { +// CIR: }, resume : { +// CIR: },) +// CIR: cir.yield // OGCG: coro.final: // OGCG: final.suspend: @@ -189,16 +189,17 @@ VoidTask silly_task() { // If null, no dynamic allocation happened, so nothing to free. // The `if` ensures we only call delete on non-null. -// CIR: } cleanup normal { -// CIR: %[[FreeMem:.*]] = cir.coro.intrinsic.free(%[[CoroId]], %[[CoroFrameAddr]]) : (token, !cir.ptr<!void>) -> !cir.ptr<!void> -// CIR: %[[NullPtr2:.*]] = cir.const #cir.ptr<null> -// CIR: %[[Cond:.*]] = cir.cmp ne %[[FreeMem]], %[[NullPtr2]] -// CIR: cir.if %[[Cond]] { -// CIR: %[[Size:.*]] = cir.coro.intrinsic.size() -// CIR: cir.call @_ZdlPvm(%[[FreeMem]], %[[Size]]) +// CIR: } cleanup normal { +// CIR: %[[FreeMem:.*]] = cir.coro.intrinsic.free(%[[CoroId]], %[[CoroFrameAddr]]) : (token, !cir.ptr<!void>) -> !cir.ptr<!void> +// CIR: %[[NullPtr2:.*]] = cir.const #cir.ptr<null> +// CIR: %[[Cond:.*]] = cir.cmp ne %[[FreeMem]], %[[NullPtr2]] +// CIR: cir.if %[[Cond]] { +// CIR: %[[Size:.*]] = cir.call @__builtin_coro_size() +// CIR: cir.call @_ZdlPvm(%[[FreeMem]], %[[Size]]) +// CIR: } +// CIR: cir.yield // CIR: } -// CIR: cir.yield -// CIR: } +// CIR: cir.yield // OGCG: %[[FreeMem:.*]] = call ptr @llvm.coro.free(token %[[CoroId]], ptr %[[CoroFrameAddr]]) // OGCG: %[[Cond:.*]] = icmp ne ptr %[[FreeMem]], null @@ -212,13 +213,17 @@ VoidTask silly_task() { // Call builtin coro end and return -// CIR: %[[CoroEndArg0:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!void> -// CIR: %[[CoroEndArg1:.*]] = cir.const #false -// CIR: = cir.coro.intrinsic.end(%[[CoroEndArg0]], %[[CoroEndArg1]]) : (!cir.ptr<!void>, !cir.bool) -> !cir.bool -// CIR: %[[Tmp1:.*]] = cir.load{{.*}} %[[VoidTaskAddr]] -// CIR: cir.return %[[Tmp1]] -// CIR: } +// CIR: }, ret : { +// CIR: %[[CoroEndArg0:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!void> +// CIR: %[[CoroEndArg1:.*]] = cir.const #false +// CIR: = cir.coro.intrinsic.end(%[[CoroEndArg0]], %[[CoroEndArg1]]) : (!cir.ptr<!void>, !cir.bool) -> !cir.bool +// CIR: %[[Tmp1:.*]] = cir.load{{.*}} %[[VoidTaskAddr]] +// CIR: cir.return %[[Tmp1]] +// CIR: } +// CIRL } +// CIR: cir.trap +// CIR:} // OGCG: coro.ret: // OGCG: call void @llvm.coro.end(ptr null, i1 false, token none) @@ -239,46 +244,49 @@ folly::coro::Task<int> byRef(const std::string& s) { // CIR: %[[CoroHandlePromiseAddr:.*]] = cir.alloca "agg.tmp1" {{.*}} : !cir.ptr<![[CoroHandlePromiseInt]]> // CIR: cir.store %[[ARG]], %[[AllocaParam]] : !cir.ptr<![[StdString]]>, {{.*}} -// CIR: cir.cleanup.scope { +// CIR: cir.coro.ret_point { +// CIR: cir.cleanup.scope { // Call promise.get_return_object() to retrieve the task object. -// CIR: %[[LOAD:.*]] = cir.load %[[AllocaParam]] : !cir.ptr<!cir.ptr<![[StdString]]>>, !cir.ptr<![[StdString]]> -// CIR: cir.store {{.*}} %[[LOAD]], %[[AllocaFnUse]] : !cir.ptr<![[StdString]]>, !cir.ptr<!cir.ptr<![[StdString]]>> -// CIR: %[[RetObj:.*]] = cir.call @_ZN5folly4coro4TaskIiE12promise_type17get_return_objectEv(%[[IntPromisseAddr]]) nothrow : {{.*}} -> ![[IntTask]] -// CIR: cir.store {{.*}} %[[RetObj]], %[[IntTaskAddr]] : ![[IntTask]] -// CIR: %[[Tmp0:.*]] = cir.call @_ZN5folly4coro4TaskIiE12promise_type15initial_suspendEv(%[[IntPromisseAddr]]) -// CIR: cir.store{{.*}} %[[Tmp0]], %[[SuspendAlwaysAddr]] -// CIR: cir.await(init, ready : { -// CIR: %[[TmpCallRes:.*]] = cir.call @_ZNSt14suspend_always11await_readyEv(%[[SuspendAlwaysAddr]]) -// CIR: cir.condition(%[[TmpCallRes]]) -// CIR: }, suspend : { -// CIR: %[[FromAddrRes:.*]] = cir.call @_ZNSt16coroutine_handleIN5folly4coro4TaskIiE12promise_typeEE12from_addressEPv(%[[CoroFrameAddr:.*]]) -// CIR: cir.store{{.*}} %[[FromAddrRes]], %[[CoroHandlePromiseAddr]] : ![[CoroHandlePromiseInt]] -// CIR: %[[CoroHandlePromiseReload:.*]] = cir.load{{.*}} %[[CoroHandlePromiseAddr]] -// CIR: cir.call @_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIiE12promise_typeEEES_IT_E(%[[CoroHandleVoidAddr]], %[[CoroHandlePromiseReload]]) -// CIR: %[[CoroHandleVoidReload:.*]] = cir.load{{.*}} %[[CoroHandleVoidAddr]] : !cir.ptr<![[CoroHandleVoid]]>, ![[CoroHandleVoid]] -// CIR: cir.call @_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SuspendAlwaysAddr]], %[[CoroHandleVoidReload]]) -// CIR: cir.coro.suspend.point -// CIR: }, resume : { -// CIR: cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SuspendAlwaysAddr]]) -// CIR: cir.yield -// CIR: },) -// CIR: cir.coro.body { +// CIR: %[[LOAD:.*]] = cir.load %[[AllocaParam]] : !cir.ptr<!cir.ptr<![[StdString]]>>, !cir.ptr<![[StdString]]> +// CIR: cir.store {{.*}} %[[LOAD]], %[[AllocaFnUse]] : !cir.ptr<![[StdString]]>, !cir.ptr<!cir.ptr<![[StdString]]>> +// CIR: %[[RetObj:.*]] = cir.call @_ZN5folly4coro4TaskIiE12promise_type17get_return_objectEv(%[[IntPromisseAddr]]) nothrow : {{.*}} -> ![[IntTask]] +// CIR: cir.store {{.*}} %[[RetObj]], %[[IntTaskAddr]] : ![[IntTask]] +// CIR: %[[Tmp0:.*]] = cir.call @_ZN5folly4coro4TaskIiE12promise_type15initial_suspendEv(%[[IntPromisseAddr]]) +// CIR: cir.store{{.*}} %[[Tmp0]], %[[SuspendAlwaysAddr]] +// CIR: cir.await(init, ready : { +// CIR: %[[TmpCallRes:.*]] = cir.call @_ZNSt14suspend_always11await_readyEv(%[[SuspendAlwaysAddr]]) +// CIR: cir.condition(%[[TmpCallRes]]) +// CIR: }, suspend : { +// CIR: %[[FromAddrRes:.*]] = cir.call @_ZNSt16coroutine_handleIN5folly4coro4TaskIiE12promise_typeEE12from_addressEPv(%[[CoroFrameAddr:.*]]) +// CIR: cir.store{{.*}} %[[FromAddrRes]], %[[CoroHandlePromiseAddr]] : ![[CoroHandlePromiseInt]] +// CIR: %[[CoroHandlePromiseReload:.*]] = cir.load{{.*}} %[[CoroHandlePromiseAddr]] +// CIR: cir.call @_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIiE12promise_typeEEES_IT_E(%[[CoroHandleVoidAddr]], %[[CoroHandlePromiseReload]]) +// CIR: %[[CoroHandleVoidReload:.*]] = cir.load{{.*}} %[[CoroHandleVoidAddr]] : !cir.ptr<![[CoroHandleVoid]]>, ![[CoroHandleVoid]] +// CIR: cir.call @_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SuspendAlwaysAddr]], %[[CoroHandleVoidReload]]) +// CIR: cir.coro.suspend_point +// CIR: }, resume : { +// CIR: cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SuspendAlwaysAddr]]) +// CIR: cir.yield +// CIR: },) +// CIR: cir.coro.body { // can't fallthrough -// CIR-NOT: cir.await(user -// CIR: cir.call @_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[IntPromisseAddr]], %[[STRING_SIZE:.*]]) -//CIR: cir.co_return -// CIR: } +// CIR-NOT: cir.await(user +// CIR: cir.call @_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[IntPromisseAddr]], %[[STRING_SIZE:.*]]) +//CIR: cir.co_return +// CIR: } // The final suspend co_await -// CIR: cir.await(final, ready : { -// CIR: }, suspend : { -// CIR: }, resume : { -// CIR: },) +// CIR: cir.await(final, ready : { +// CIR: }, suspend : { +// CIR: }, resume : { +// CIR: },) +// CIR: cir.yield +// CIR: } cleanup normal { +// CIR: } // CIR: cir.yield -// CIR: } cleanup normal { -// CIR: } +// CIR: }, ret : { folly::coro::Task<void> silly_coro() { std::optional<folly::coro::Task<int>> task; @@ -294,22 +302,24 @@ folly::coro::Task<void> silly_coro() { // check there are not multiple co_returns emitted. // CIR: cir.func coroutine {{.*}} @_Z10silly_corov() {{.*}} ![[VoidTask]] -// CIR: cir.cleanup.scope { -// CIR: cir.await(init, ready : { -// CIR: }, suspend : { -// CIR: }, resume : { -// CIR: },) -// CIR: cir.coro.body { -// CIR: cir.call @_ZN5folly4coro4TaskIvE12promise_type11return_voidEv -// CIR: cir.co_return +// CIR: cir.coro.ret_point { +// CIR: cir.cleanup.scope { +// CIR: cir.await(init, ready : { +// CIR: }, suspend : { +// CIR: }, resume : { +// CIR: },) +// CIR: cir.coro.body { +// CIR: cir.call @_ZN5folly4coro4TaskIvE12promise_type11return_voidEv +// CIR: cir.co_return +// CIR: } +// CIR: cir.await(final, ready : { +// CIR: }, suspend : { +// CIR: }, resume : { +// CIR: },) +// CIR: cir.yield +// CIR: } cleanup normal { // CIR: } -// CIR: cir.await(final, ready : { -// CIR: }, suspend : { -// CIR: }, resume : { -// CIR: },) -// CIR: cir.yield -// CIR: } cleanup normal { -// CIR: } +// CIR: }, ret : { folly::coro::Task<void> yield(); folly::coro::Task<void> yield1() { @@ -335,78 +345,80 @@ folly::coro::Task<void> yield1() { // CIR-DAG: %[[CH_VOID2:.*]] = cir.alloca "agg.tmp5" {{.*}} : !cir.ptr<![[CoroHandleVoid]]> // CIR-DAG: %[[CH_PROM2:.*]] = cir.alloca "agg.tmp6" {{.*}} : !cir.ptr<![[CoroHandlePromiseVoid]]> -// CIR: cir.cleanup.scope { +// CIR: cir.coro.ret_point { +// CIR: cir.cleanup.scope { // initial_suspend + await(init) -// CIR: %[[INIT_SUSP:.*]] = cir.call @_ZN5folly4coro4TaskIvE12promise_type15initial_suspendEv(%[[PROMISE]]){{.*}} -// CIR: cir.store{{.*}} %[[INIT_SUSP]], %[[SUSP0]] -// CIR: cir.await(init, ready : { -// CIR: %[[READY0:.*]] = cir.call @_ZNSt14suspend_always11await_readyEv(%[[SUSP0]]){{.*}} -// CIR: cir.condition(%[[READY0]]) -// CIR: }, suspend : { -// CIR: %[[FROMADDR0:.*]] = cir.call @_ZNSt16coroutine_handleIN5folly4coro4TaskIvE12promise_typeEE12from_addressEPv(%{{.*}}){{.*}} -// CIR: cir.store{{.*}} %[[FROMADDR0]], %[[CH_PROM0]] -// CIR: %[[PROM_RELOAD0:.*]] = cir.load{{.*}} %[[CH_PROM0]] -// CIR: cir.call @_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIvE12promise_typeEEES_IT_E(%[[CH_VOID0]], %[[PROM_RELOAD0]]){{.*}} -// CIR: %[[VOID_RELOAD0:.*]] = cir.load{{.*}} %[[CH_VOID0]] -// CIR: cir.call @_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SUSP0]], %[[VOID_RELOAD0]]){{.*}} -// CIR: cir.coro.suspend.point -// CIR: }, resume : { -// CIR: cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SUSP0]]){{.*}} -// CIR: cir.yield -// CIR: },) - -// yield_value + await(yield) -// CIR: cir.coro.body { -// CIR: %[[YIELD_TASK:.*]] = cir.call @_Z5yieldv(){{.*}} -// CIR: cir.store{{.*}} %[[YIELD_TASK]], %[[T_ADDR]] -// CIR: %[[AWAITER:.*]] = cir.load{{.*}} %[[AWAITER_COPY_ADDR]] -// CIR: %[[YIELD_SUSP:.*]] = cir.call @_ZN5folly4coro4TaskIvE12promise_type11yield_valueES2_(%[[PROMISE]], %[[AWAITER]]){{.*}} -// CIR: cir.store{{.*}} %[[YIELD_SUSP]], %[[SUSP1]] -// CIR: cir.await(yield, ready : { -// CIR: %[[READY1:.*]] = cir.call @_ZNSt14suspend_always11await_readyEv(%[[SUSP1]]){{.*}} -// CIR: cir.condition(%[[READY1]]) +// CIR: %[[INIT_SUSP:.*]] = cir.call @_ZN5folly4coro4TaskIvE12promise_type15initial_suspendEv(%[[PROMISE]]){{.*}} +// CIR: cir.store{{.*}} %[[INIT_SUSP]], %[[SUSP0]] +// CIR: cir.await(init, ready : { +// CIR: %[[READY0:.*]] = cir.call @_ZNSt14suspend_always11await_readyEv(%[[SUSP0]]){{.*}} +// CIR: cir.condition(%[[READY0]]) // CIR: }, suspend : { -// CIR: %[[FROMADDR1:.*]] = cir.call @_ZNSt16coroutine_handleIN5folly4coro4TaskIvE12promise_typeEE12from_addressEPv(%{{.*}}){{.*}} -// CIR: cir.store{{.*}} %[[FROMADDR1]], %[[CH_PROM1]] -// CIR: %[[PROM_RELOAD1:.*]] = cir.load{{.*}} %[[CH_PROM1]] -// CIR: cir.call @_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIvE12promise_typeEEES_IT_E(%[[CH_VOID1]], %[[PROM_RELOAD1]]){{.*}} -// CIR: %[[VOID_RELOAD1:.*]] = cir.load{{.*}} %[[CH_VOID1]] -// CIR: cir.call @_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SUSP1]], %[[VOID_RELOAD1]]){{.*}} -// CIR: cir.coro.suspend.point +// CIR: %[[FROMADDR0:.*]] = cir.call @_ZNSt16coroutine_handleIN5folly4coro4TaskIvE12promise_typeEE12from_addressEPv(%{{.*}}){{.*}} +// CIR: cir.store{{.*}} %[[FROMADDR0]], %[[CH_PROM0]] +// CIR: %[[PROM_RELOAD0:.*]] = cir.load{{.*}} %[[CH_PROM0]] +// CIR: cir.call @_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIvE12promise_typeEEES_IT_E(%[[CH_VOID0]], %[[PROM_RELOAD0]]){{.*}} +// CIR: %[[VOID_RELOAD0:.*]] = cir.load{{.*}} %[[CH_VOID0]] +// CIR: cir.call @_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SUSP0]], %[[VOID_RELOAD0]]){{.*}} +// CIR: cir.coro.suspend_point // CIR: }, resume : { -// CIR: cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SUSP1]]){{.*}} +// CIR: cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SUSP0]]){{.*}} // CIR: cir.yield // CIR: },) -// CIR: cir.call @_ZN5folly4coro4TaskIvE12promise_type11return_voidEv(%[[PROMISE]]) -// CIR: cir.co_return -// CIR: } + +// yield_value + await(yield) +// CIR: cir.coro.body { +// CIR: %[[YIELD_TASK:.*]] = cir.call @_Z5yieldv(){{.*}} +// CIR: cir.store{{.*}} %[[YIELD_TASK]], %[[T_ADDR]] +// CIR: %[[AWAITER:.*]] = cir.load{{.*}} %[[AWAITER_COPY_ADDR]] +// CIR: %[[YIELD_SUSP:.*]] = cir.call @_ZN5folly4coro4TaskIvE12promise_type11yield_valueES2_(%[[PROMISE]], %[[AWAITER]]){{.*}} +// CIR: cir.store{{.*}} %[[YIELD_SUSP]], %[[SUSP1]] +// CIR: cir.await(yield, ready : { +// CIR: %[[READY1:.*]] = cir.call @_ZNSt14suspend_always11await_readyEv(%[[SUSP1]]){{.*}} +// CIR: cir.condition(%[[READY1]]) +// CIR: }, suspend : { +// CIR: %[[FROMADDR1:.*]] = cir.call @_ZNSt16coroutine_handleIN5folly4coro4TaskIvE12promise_typeEE12from_addressEPv(%{{.*}}){{.*}} +// CIR: cir.store{{.*}} %[[FROMADDR1]], %[[CH_PROM1]] +// CIR: %[[PROM_RELOAD1:.*]] = cir.load{{.*}} %[[CH_PROM1]] +// CIR: cir.call @_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIvE12promise_typeEEES_IT_E(%[[CH_VOID1]], %[[PROM_RELOAD1]]){{.*}} +// CIR: %[[VOID_RELOAD1:.*]] = cir.load{{.*}} %[[CH_VOID1]] +// CIR: cir.call @_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SUSP1]], %[[VOID_RELOAD1]]){{.*}} +// CIR: cir.coro.suspend_point +// CIR: }, resume : { +// CIR: cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SUSP1]]){{.*}} +// CIR: cir.yield +// CIR: },) +// CIR: cir.call @_ZN5folly4coro4TaskIvE12promise_type11return_voidEv(%[[PROMISE]]) +// CIR: cir.co_return +// CIR: } // return_void + await(final) -// CIR: %[[FINAL_SUSP:.*]] = cir.call @_ZN5folly4coro4TaskIvE12promise_type13final_suspendEv(%[[PROMISE]]){{.*}} -// CIR: cir.store{{.*}} %[[FINAL_SUSP]], %[[SUSP2]] -// CIR: cir.await(final, ready : { -// CIR: %[[READY2:.*]] = cir.call @_ZNSt14suspend_always11await_readyEv(%[[SUSP2]]){{.*}} -// CIR: cir.condition(%[[READY2]]) -// CIR: }, suspend : { -// CIR: %[[FROMADDR2:.*]] = cir.call @_ZNSt16coroutine_handleIN5folly4coro4TaskIvE12promise_typeEE12from_addressEPv(%{{.*}}){{.*}} -// CIR: cir.store{{.*}} %[[FROMADDR2]], %[[CH_PROM2]] -// CIR: %[[PROM_RELOAD2:.*]] = cir.load{{.*}} %[[CH_PROM2]] -// CIR: cir.call @_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIvE12promise_typeEEES_IT_E(%[[CH_VOID2]], %[[PROM_RELOAD2]]){{.*}} -// CIR: %[[VOID_RELOAD2:.*]] = cir.load{{.*}} %[[CH_VOID2]] -// CIR: cir.call @_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SUSP2]], %[[VOID_RELOAD2]]){{.*}} -// CIR: cir.coro.suspend.point -// CIR: }, resume : { -// CIR: cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SUSP2]]){{.*}} +// CIR: %[[FINAL_SUSP:.*]] = cir.call @_ZN5folly4coro4TaskIvE12promise_type13final_suspendEv(%[[PROMISE]]){{.*}} +// CIR: cir.store{{.*}} %[[FINAL_SUSP]], %[[SUSP2]] +// CIR: cir.await(final, ready : { +// CIR: %[[READY2:.*]] = cir.call @_ZNSt14suspend_always11await_readyEv(%[[SUSP2]]){{.*}} +// CIR: cir.condition(%[[READY2]]) +// CIR: }, suspend : { +// CIR: %[[FROMADDR2:.*]] = cir.call @_ZNSt16coroutine_handleIN5folly4coro4TaskIvE12promise_typeEE12from_addressEPv(%{{.*}}){{.*}} +// CIR: cir.store{{.*}} %[[FROMADDR2]], %[[CH_PROM2]] +// CIR: %[[PROM_RELOAD2:.*]] = cir.load{{.*}} %[[CH_PROM2]] +// CIR: cir.call @_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIvE12promise_typeEEES_IT_E(%[[CH_VOID2]], %[[PROM_RELOAD2]]){{.*}} +// CIR: %[[VOID_RELOAD2:.*]] = cir.load{{.*}} %[[CH_VOID2]] +// CIR: cir.call @_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SUSP2]], %[[VOID_RELOAD2]]){{.*}} +// CIR: cir.coro.suspend_point +// CIR: }, resume : { +// CIR: cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SUSP2]]){{.*}} +// CIR: cir.yield +// CIR: },) // CIR: cir.yield -// CIR: },) -// CIR: cir.yield -// CIR: } cleanup normal { -// CIR: } -// CIR: = cir.coro.intrinsic.end(%{{.*}}, %{{.*}}) -// CIR: %[[RETLOAD:.*]] = cir.load{{.*}} %[[RETVAL]] -// CIR: cir.return %[[RETLOAD]] -// CIR: } - +// CIR: } cleanup normal { +// CIR: } +// CIR: }, ret : { +// CIR: = cir.coro.intrinsic.end(%{{.*}}, %{{.*}}) +// CIR: %[[RETLOAD:.*]] = cir.load{{.*}} %[[RETVAL]] +// CIR: cir.return %[[RETLOAD]] +// CIR: } +// CIR: cir.trap // CHECK: } folly::coro::Task<int> go(int const& val); @@ -419,36 +431,39 @@ folly::coro::Task<int> go1() { // CIR: %[[IntTaskAddr:.*]] = cir.alloca "task" {{.*}} init : !cir.ptr<![[IntTask]]> // CIR: %[[OneAddr:.*]] = cir.alloca "ref.tmp1" align(4) init : !cir.ptr<!s32i> -// CIR: cir.cleanup.scope { -// CIR: cir.await(init, ready : { -// CIR: }, suspend : { -// CIR: }, resume : { -// CIR: },) +// CIR: cir.coro.ret_point { +// CIR: cir.cleanup.scope { +// CIR: cir.await(init, ready : { +// CIR: }, suspend : { +// CIR: }, resume : { +// CIR: },) -// CIR: cir.coro.body { -// 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.coro.body { +// 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.await(user, ready : { +// CIR: }, suspend : { +// CIR: }, resume : { +// CIR: %[[ResumeVal:.*]] = cir.call @_ZN5folly4coro4TaskIiE12await_resumeEv(%[[IntTaskAddr]]) +// 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]]) +// CIR: cir.co_return +// CIR: } -// CIR: cir.await(user, ready : { +// CIR: cir.await(final, ready : { // CIR: }, suspend : { // CIR: }, resume : { -// CIR: %[[ResumeVal:.*]] = cir.call @_ZN5folly4coro4TaskIiE12await_resumeEv(%[[IntTaskAddr]]) -// 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]]) -// CIR: cir.co_return +// CIR: cir.yield +// CIR: } cleanup normal { // CIR: } - -// CIR: cir.await(final, ready : { -// CIR: }, suspend : { -// CIR: }, resume : { -// CIR: },) -// CIR: cir.yield -// CIR: } cleanup normal { -// CIR: } +// CIR: cir.yield +// CIR: }, ret : { folly::coro::Task<int> go1_lambda() { auto task = []() -> folly::coro::Task<int> { @@ -458,45 +473,49 @@ folly::coro::Task<int> go1_lambda() { } // CIR: cir.func coroutine {{.*}} @_ZZ10go1_lambdavENK3$_0clEv{{.*}} ![[IntTask]] -// CIR: cir.cleanup.scope { -// CIR: cir.await(init, ready : { -// CIR: }, suspend : { -// CIR: }, resume : { -// CIR: },) -// CIR: cir.coro.body { -// CIR: %[[ONE:.*]] = cir.const #cir.int<1> -// CIR: cir.call @_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[PROMISE:.*]], %[[ONE]]) -// CIR: cir.co_return -// CIR: } -// CIR: cir.await(final, ready : { -// CIR: }, suspend : { -// CIR: }, resume : { -// CIR: },) -// CIR: } cleanup normal { +// CIR: cir.coro.ret_point { +// CIR: cir.cleanup.scope { +// CIR: cir.await(init, ready : { +// CIR: }, suspend : { +// CIR: }, resume : { +// CIR: },) +// CIR: cir.coro.body { +// CIR: %[[ONE:.*]] = cir.const #cir.int<1> +// CIR: cir.call @_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[PROMISE:.*]], %[[ONE]]) +// CIR: cir.co_return +// CIR: } +// CIR: cir.await(final, ready : { +// CIR: }, suspend : { +// CIR: }, resume : { +// CIR: },) +// CIR: } cleanup normal { +// CIR: }, ret : { // CIR: cir.func coroutine {{.*}} @_Z10go1_lambdav() {{.*}} ![[IntTask]] -// CIR: cir.cleanup.scope { -// CIR: cir.await(init, ready : { -// CIR: }, suspend : { -// CIR: }, resume : { -// CIR: },) -// CIR: cir.coro.body { -// CIR: cir.call @_ZZ10go1_lambdavENK3$_0clEv -// CIR: cir.await(user, ready : { +// CIR: cir.coro.ret_point { +// CIR: cir.cleanup.scope { +// CIR: cir.await(init, ready : { // CIR: }, suspend : { // CIR: }, resume : { -// CIR: %[[RESUME_RES:.*]] = cir.call @_ZN5folly4coro4TaskIiE12await_resumeEv(%[[TASK:.*]]) -// CIR: cir.store %[[RESUME_RES]], %[[resume_rval:.*]] : !s32i, !cir.ptr<!s32i> // CIR: },) -// CIR: %[[TMP1:.*]] = cir.load %[[resume_rval:.*]] : !cir.ptr<!s32i> -// CIR: cir.call @_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[PROMISE:.*]], %[[TMP1]]) -// CIR: cir.co_return -// CIR: } -// CIR: cir.await(final, ready : { -// CIR: }, suspend : { -// CIR: }, resume : { -// CIR: },) -// CIR: } cleanup normal { +// CIR: cir.coro.body { +// CIR: cir.call @_ZZ10go1_lambdavENK3$_0clEv +// CIR: cir.await(user, ready : { +// CIR: }, suspend : { +// CIR: }, resume : { +// CIR: %[[RESUME_RES:.*]] = cir.call @_ZN5folly4coro4TaskIiE12await_resumeEv(%[[TASK:.*]]) +// CIR: cir.store %[[RESUME_RES]], %[[resume_rval:.*]] : !s32i, !cir.ptr<!s32i> +// CIR: },) +// CIR: %[[TMP1:.*]] = cir.load %[[resume_rval:.*]] : !cir.ptr<!s32i> +// CIR: cir.call @_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[PROMISE:.*]], %[[TMP1]]) +// CIR: cir.co_return +// CIR: } +// CIR: cir.await(final, ready : { +// CIR: }, suspend : { +// CIR: }, resume : { +// CIR: },) +// CIR: } cleanup normal { +// CIR: }, ret : { folly::coro::Task<int> go4() { auto* fn = +[](int const& i) -> folly::coro::Task<int> { co_return i; }; @@ -505,57 +524,61 @@ folly::coro::Task<int> go4() { } // CIR: cir.func coroutine{{.*}} @_ZZ3go4vENK3$_0clERKi( -// CIR: cir.cleanup.scope { -// CIR: cir.await(init, ready : { -// CIR: }, suspend : { -// CIR: }, resume : { -// CIR: },) -// CIR: cir.coro.body { -// CIR: cir.call @_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[PROMISE:.*]], %[[I:.*]]) -// CIR: cir.co_return -// CIR: } -// CIR: cir.await(final, ready : { -// CIR: }, suspend : { -// CIR: }, resume : { -// CIR: },) -// CIR: } cleanup normal { +// CIR: cir.coro.ret_point { +// CIR: cir.cleanup.scope { +// CIR: cir.await(init, ready : { +// CIR: }, suspend : { +// CIR: }, resume : { +// CIR: },) +// CIR: cir.coro.body { +// CIR: cir.call @_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[PROMISE:.*]], %[[I:.*]]) +// CIR: cir.co_return +// CIR: } +// CIR: cir.await(final, ready : { +// CIR: }, suspend : { +// CIR: }, resume : { +// CIR: },) +// CIR: } cleanup normal { +// CIR: }, ret : { // CIR: cir.func coroutine {{.*}} @_Z3go4v() {{.*}} ![[IntTask]] -// CIR: cir.cleanup.scope { -// CIR: cir.await(init, ready : { -// CIR: }, suspend : { -// CIR: }, resume : { -// CIR: },) +// CIR: cir.coro.ret_point { +// CIR: cir.cleanup.scope { +// CIR: cir.await(init, ready : { +// CIR: }, suspend : { +// CIR: }, resume : { +// CIR: },) // Get the lambda invoker ptr via `lambda operator folly::coro::Task<int> (*)(int const&)()` -// CIR: %[[INVOKER:.*]] = cir.call @_ZZ3go4vENK3$_0cvPFN5folly4coro4TaskIiEERKiEEv(%{{.*}}) nothrow : {{.*}} -> (!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>> {llvm.noundef}) -// CIR: cir.store{{.*}} %[[INVOKER]], %[[FN_ADDR:.*]] : !cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>, !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>> -// CIR: %[[FN:.*]] = cir.load{{.*}} %[[FN_ADDR]] : !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> +// CIR: %[[INVOKER:.*]] = cir.call @_ZZ3go4vENK3$_0cvPFN5folly4coro4TaskIiEERKiEEv(%{{.*}}) nothrow : {{.*}} -> (!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>> {llvm.noundef}) +// CIR: cir.store{{.*}} %[[INVOKER]], %[[FN_ADDR:.*]] : !cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>, !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>> +// CIR: %[[FN:.*]] = cir.load{{.*}} %[[FN_ADDR]] : !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: %[[CALLRES:.*]] = cir.call %[[FN]](%[[ARG]]) : (!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>, !cir.ptr<!s32i> {{.*}}) -> ![[IntTask]] -// CIR: cir.store{{.*}} %[[CALLRES]], %[[TASK_ADDR:.*]] : ![[IntTask]], !cir.ptr<![[IntTask]]> - -// CIR: cir.await(user, ready : { -// CIR: = cir.call @_ZN5folly4coro4TaskIiE11await_readyEv(%[[TASK_ADDR]]) -// CIR: cir.condition( -// CIR: }, suspend : { -// CIR: cir.coro.suspend.point -// CIR: }, resume : { -// CIR: cir.yield -// CIR: },) -// CIR: cir.call @_ZN5folly4coro4TaskIiE12promise_type12return_valueEi -// CIR: cir.co_return -// CIR: } +// CIR: %[[CALLRES:.*]] = cir.call %[[FN]](%[[ARG]]) : (!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>, !cir.ptr<!s32i> {{.*}}) -> ![[IntTask]] +// CIR: cir.store{{.*}} %[[CALLRES]], %[[TASK_ADDR:.*]] : ![[IntTask]], !cir.ptr<![[IntTask]]> + +// CIR: cir.await(user, ready : { +// CIR: = cir.call @_ZN5folly4coro4TaskIiE11await_readyEv(%[[TASK_ADDR]]) +// CIR: cir.condition( +// CIR: }, suspend : { +// CIR: cir.coro.suspend_point +// CIR: }, resume : { +// CIR: cir.yield +// CIR: },) +// CIR: cir.call @_ZN5folly4coro4TaskIiE12promise_type12return_valueEi +// CIR: cir.co_return +// CIR: } -// CIR: cir.await(final, ready : { -// CIR: }, suspend : { -// CIR: }, resume : { -// CIR: },) -// CIR: } cleanup normal { +// CIR: cir.await(final, ready : { +// CIR: }, suspend : { +// CIR: }, resume : { +// CIR: },) +// CIR: } cleanup normal { +// CIR: }, ret : { // OGCG: define {{.*}}__await_suspend_wrapper__init(ptr noundef nonnull %[[Awaiter:.*]], ptr noundef %[[Handle:.*]]) // OGCG: entry: @@ -584,41 +607,43 @@ folly::coro::Task<int> co_returns(int x) { } // CIR: cir.func coroutine {{.*}} @_Z10co_returnsi -// CIR: cir.cleanup.scope { -// CIR: cir.await(init, ready : { -// CIR: }, suspend : { -// CIR: }, resume : { -// CIR: },) -// CIR: cir.coro.body { -// CIR: cir.scope { -// CIR: cir.if {{.*}} { -// CIR: %[[MINUS_ONE:.*]] = cir.const #cir.int<-1> -// CIR: cir.call @_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[PROMISE:.*]], %[[MINUS_ONE]]) -// CIR: cir.co_return -// CIR: } else { -// CIR: cir.if {{.*}} { -// CIR: %[[MINUS_TWO:.*]] = cir.const #cir.int<-2> - // CIR: cir.call @_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[PROMISE]], %[[MINUS_TWO]]) - // CIR: cir.co_return -// CIR: } -// CIR: } -// CIR: } -// CIR: cir.await(user, ready : { +// CIR: cir.coro.ret_point { +// CIR: cir.cleanup.scope { +// CIR: cir.await(init, ready : { // CIR: }, suspend : { // CIR: }, resume : { // CIR: },) -// CIR: %[[X_LOAD:.*]] = cir.load {{.*}} %[[X:.*]] -// CIR: %[[TWO:.*]] = cir.const #cir.int<2> -// CIR: %[[RES:.*]] = cir.mul nsw %[[X_LOAD]], %[[TWO]] -// CIR: cir.call @_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[PROMISE]], %[[RES]]) -// CIR: cir.co_return -// CIR: } -// CIR: cir.await(final, ready : { -// CIR: }, suspend : { -// CIR: }, resume : { -// CIR: },) -// CIR: cir.yield -// CIR: } cleanup normal { +// CIR: cir.coro.body { +// CIR: cir.scope { +// CIR: cir.if {{.*}} { +// CIR: %[[MINUS_ONE:.*]] = cir.const #cir.int<-1> +// CIR: cir.call @_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[PROMISE:.*]], %[[MINUS_ONE]]) +// CIR: cir.co_return +// CIR: } else { +// CIR: cir.if {{.*}} { +// CIR: %[[MINUS_TWO:.*]] = cir.const #cir.int<-2> +// CIR: cir.call @_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[PROMISE]], %[[MINUS_TWO]]) +// CIR: cir.co_return +// CIR: } +// CIR: } +// CIR: } +// CIR: cir.await(user, ready : { +// CIR: }, suspend : { +// CIR: }, resume : { +// CIR: },) +// CIR: %[[X_LOAD:.*]] = cir.load {{.*}} %[[X:.*]] +// CIR: %[[TWO:.*]] = cir.const #cir.int<2> +// CIR: %[[RES:.*]] = cir.mul nsw %[[X_LOAD]], %[[TWO]] +// CIR: cir.call @_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[PROMISE]], %[[RES]]) +// CIR: cir.co_return +// CIR: } +// CIR: cir.await(final, ready : { +// CIR: }, suspend : { +// CIR: }, resume : { +// CIR: },) +// CIR: cir.yield +// CIR: } cleanup normal { +// CIR: }, ret : { // OGCG: define {{.*}} @_Z10co_returnsi @@ -668,40 +693,42 @@ folly::coro::Task<int> co_return_with_dtor(int flag) { // CIR: cir.func coroutine {{.*}} @_Z19co_return_with_dtori // CIR: %[[LOCAL:.*]] = cir.alloca "local" {{.*}} : !cir.ptr<!rec_HasDtor> -// CIR: cir.cleanup.scope { -// CIR: cir.await(init, ready : { -// CIR: }, suspend : { -// CIR: }, resume : { -// CIR: },) +// CIR: cir.coro.ret_point { +// CIR: cir.cleanup.scope { +// CIR: cir.await(init, ready : { +// CIR: }, suspend : { +// CIR: }, resume : { +// CIR: },) -// CIR: cir.coro.body { -// CIR: cir.cleanup.scope { -// CIR: cir.scope { -// CIR: %[[CAST_FLAG:.*]] = cir.cast int_to_bool %[[FLAG:.*]] -// CIR: cir.if %[[CAST_FLAG]] { -// CIR: %[[ONE:.*]] = cir.const #cir.int<1> -// CIR: cir.call @_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[promise:.*]], %[[ONE]]) -// CIR: cir.co_return +// CIR: cir.coro.body { +// CIR: cir.cleanup.scope { +// CIR: cir.scope { +// CIR: %[[CAST_FLAG:.*]] = cir.cast int_to_bool %[[FLAG:.*]] +// CIR: cir.if %[[CAST_FLAG]] { +// CIR: %[[ONE:.*]] = cir.const #cir.int<1> +// CIR: cir.call @_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[promise:.*]], %[[ONE]]) +// CIR: cir.co_return +// CIR: } // CIR: } +// CIR: %[[TWO:.*]] = cir.const #cir.int<2> +// CIR: cir.call @_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[promise]], %[[TWO]]) +// CIR: cir.co_return +// CIR: } cleanup normal { +// CIR: cir.call @_ZN7HasDtorD1Ev(%[[LOCAL]]) +// CIR: cir.yield // CIR: } -// CIR: %[[TWO:.*]] = cir.const #cir.int<2> -// CIR: cir.call @_ZN5folly4coro4TaskIiE12promise_type12return_valueEi(%[[promise]], %[[TWO]]) -// CIR: cir.co_return -// CIR: } cleanup normal { -// CIR: cir.call @_ZN7HasDtorD1Ev(%[[LOCAL]]) // CIR: cir.yield // CIR: } + +// CIR: cir.await(final, ready : { +// CIR: }, suspend : { +// CIR: }, resume : { +// CIR: },) +// CIR: cir.yield +// CIR: } cleanup normal { // CIR: cir.yield // CIR: } - -// CIR: cir.await(final, ready : { -// CIR: }, suspend : { -// CIR: }, resume : { -// CIR: },) -// CIR: cir.yield -// CIR: } cleanup normal { -// CIR: cir.yield -// CIR: } +// CIR: }, ret : { // OGCG: define {{.*}} void @_Z19co_return_with_dtori // OGCG: %[[LOCAL:.*]] = alloca %struct.HasDtor @@ -732,28 +759,30 @@ folly::coro::Task<int __complex__> complex_co_await() noexcept { // CIR: %[[COMPLEX_ADDR:.*]] = cir.alloca "ref.tmp1" {{.*}} : !cir.ptr<!rec_folly3A3Acoro3A3ATask3C_Complex_int3E> // CIR: %[[RESUME_VAL_ADDR:.*]] = cir.alloca "__coawait_resume_rval" {{.*}} : !cir.ptr<!cir.complex<!s32i>> -// CIR: cir.cleanup.scope { -// CIR: cir.await(init, ready : { -// CIR: }, suspend : { -// CIR: }, resume : { -// CIR: },) +// CIR: cir.coro.ret_point { +// 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.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: 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: } cleanup normal { // CIR: } - -// CIR: } cleanup normal { -// CIR: } +// CIR: }, ret : { // OGCG: define dso_local void @_Z16complex_co_awaitv() diff --git a/clang/test/CIR/IR/await.cir b/clang/test/CIR/IR/await.cir index 1305c4bb31e0f..9e6a71351c42e 100644 --- a/clang/test/CIR/IR/await.cir +++ b/clang/test/CIR/IR/await.cir @@ -1,26 +1,29 @@ // RUN: cir-opt %s --verify-roundtrip | FileCheck %s cir.func coroutine @checkPrintParse(%arg0 : !cir.bool) { - cir.coro.body { - cir.await(user, ready : { - cir.condition(%arg0) - }, suspend : { - cir.coro.suspend.point - }, resume : { + cir.coro.ret_point { + cir.coro.body { + cir.await(user, ready : { + cir.condition(%arg0) + }, suspend : { + cir.coro.suspend_point + }, resume : { + cir.yield + },) cir.yield - },) + } cir.yield + }, ret : { + cir.return } - cir.coro.suspend.point.dest - cir.return + cir.trap } // CHECK: cir.func coroutine @checkPrintParse // CHECK: cir.await(user, ready : { // CHECK: cir.condition(%arg0) // CHECK: }, suspend : { -// CHECK: cir.coro.suspend.point +// CHECK: cir.coro.suspend_point // CHECK: }, resume : { // CHECK: cir.yield // CHECK: },) -// CHECK: cir.coro.suspend.point.dest diff --git a/clang/test/CIR/IR/co-return.cir b/clang/test/CIR/IR/co-return.cir index d6c3be2da80ad..833b6a27d8016 100644 --- a/clang/test/CIR/IR/co-return.cir +++ b/clang/test/CIR/IR/co-return.cir @@ -1,17 +1,21 @@ // RUN: cir-opt %s --verify-roundtrip | FileCheck %s cir.func coroutine @coro_co_return(%arg0 : !cir.bool) { - cir.coro.body { - cir.await(user, ready : { - cir.condition(%arg0) - }, suspend : { - cir.coro.suspend.point - }, resume : { - cir.yield - },) - cir.co_return + cir.coro.ret_point { + cir.coro.body { + cir.await(user, ready : { + cir.condition(%arg0) + }, suspend : { + cir.coro.suspend_point + }, resume : { + cir.yield + },) + cir.co_return + } + cir.yield + }, ret : { + cir.return } - cir.coro.suspend.point.dest - cir.return + cir.trap } // CHECK: cir.func coroutine @coro_co_return diff --git a/clang/test/CIR/IR/coro-body.cir b/clang/test/CIR/IR/coro-body.cir index b1560485303b1..30af9fc0e5d3c 100644 --- a/clang/test/CIR/IR/coro-body.cir +++ b/clang/test/CIR/IR/coro-body.cir @@ -1,18 +1,22 @@ // RUN: cir-opt %s --verify-roundtrip | FileCheck %s cir.func coroutine @coro_body(%arg0 : !cir.bool) { - cir.coro.body { - cir.await(user, ready : { - cir.condition(%arg0) - }, suspend : { - cir.coro.suspend.point - }, resume : { - cir.yield - },) - cir.co_return + cir.coro.ret_point { + cir.coro.body { + cir.await(user, ready : { + cir.condition(%arg0) + }, suspend : { + cir.coro.suspend_point + }, resume : { + cir.yield + },) + cir.co_return + } + cir.yield + }, ret : { + cir.return } - cir.coro.suspend.point.dest - cir.return + cir.trap } // CHECK: cir.func coroutine @coro_body diff --git a/clang/test/CIR/IR/coro-ret-point.cir b/clang/test/CIR/IR/coro-ret-point.cir new file mode 100644 index 0000000000000..44afdc6407931 --- /dev/null +++ b/clang/test/CIR/IR/coro-ret-point.cir @@ -0,0 +1,23 @@ +// RUN: cir-opt %s --verify-roundtrip | FileCheck %s + +cir.func coroutine @coro_ret_point(%arg0 : !cir.bool) { + cir.coro.ret_point { + cir.coro.body { + cir.await(user, ready : { + cir.condition(%arg0) + }, suspend : { + cir.coro.suspend_point + }, resume : { + cir.yield + },) + cir.yield + } + cir.yield + }, ret : { + cir.return + } + cir.trap +} + +// CHECK: cir.coro.ret_point { +// CHECK: }, ret : { diff --git a/clang/test/CIR/IR/func.cir b/clang/test/CIR/IR/func.cir index ffc3a503c8c48..dc6a14f63ac65 100644 --- a/clang/test/CIR/IR/func.cir +++ b/clang/test/CIR/IR/func.cir @@ -109,20 +109,24 @@ cir.func @ullfunc() -> !u64i { // CHECK: } cir.func coroutine @coro() { - cir.coro.body { - cir.await(init, ready : { - %0 = cir.alloca "" align(1) : !cir.ptr<!cir.bool> - %1 = cir.load align(1) %0 : !cir.ptr<!cir.bool>, !cir.bool - cir.condition(%1) - }, suspend : { - cir.coro.suspend.point - }, resume : { + cir.coro.ret_point { + cir.coro.body { + cir.await(init, ready : { + %0 = cir.alloca "" align(1) : !cir.ptr<!cir.bool> + %1 = cir.load align(1) %0 : !cir.ptr<!cir.bool>, !cir.bool + cir.condition(%1) + }, suspend : { + cir.coro.suspend_point + }, resume : { + cir.yield + },) cir.yield - },) + } cir.yield + }, ret : { + cir.return } - cir.coro.suspend.point.dest - cir.return + cir.trap } // CHECK: cir.func{{.*}} coroutine @coro() diff --git a/clang/test/CIR/IR/invalid-await.cir b/clang/test/CIR/IR/invalid-await.cir index cc6d011718ad0..8e40e0886428f 100644 --- a/clang/test/CIR/IR/invalid-await.cir +++ b/clang/test/CIR/IR/invalid-await.cir @@ -6,32 +6,38 @@ cir.func coroutine @bad_task() { // expected-error {{coroutine body must use at // ----- cir.func coroutine @missing_condition() { - cir.scope { + cir.coro.ret_point { cir.await(user, ready : { // expected-error {{ready region must end with cir.condition}} cir.yield }, suspend : { - cir.coro.suspend.point + cir.coro.suspend_point }, resume : { cir.yield },) + cir.coro.body { + } + cir.yield + }, ret : { + cir.return } - cir.coro.body { - } - cir.coro.suspend.point.dest - cir.return + cir.trap } cir.func coroutine @missing_suspend(%arg0 : !cir.bool) { - cir.coro.body { - cir.await(user, ready : { // expected-error {{ready region must end with cir.coro.suspend.point}} - cir.condition(%arg0) - }, suspend : { + cir.coro.ret_point { + cir.coro.body { + cir.await(user, ready : { // expected-error {{suspend region must end with cir.coro.suspend_point}} + cir.condition(%arg0) + }, suspend : { + cir.yield + }, resume : { + cir.yield + },) cir.yield - }, resume : { - cir.yield - },) + } cir.yield + }, ret : { + cir.return } - cir.coro.suspend.point.dest - cir.return + cir.trap } diff --git a/clang/test/CIR/IR/invalid-coro-body.cir b/clang/test/CIR/IR/invalid-coro-body.cir index f247220c7d73d..c72ec6e4450fb 100644 --- a/clang/test/CIR/IR/invalid-coro-body.cir +++ b/clang/test/CIR/IR/invalid-coro-body.cir @@ -11,12 +11,11 @@ cir.func coroutine @must_have_one_coro_body(%arg0 : !cir.bool) { // expected-er cir.await(user, ready : { cir.condition(%arg0) }, suspend : { - cir.coro.suspend.point + cir.coro.suspend_point }, resume : { cir.yield },) } cir.coro.body { } - cir.coro.suspend.point.dest } diff --git a/clang/test/CIR/IR/invalid-coro-ret-point.cir b/clang/test/CIR/IR/invalid-coro-ret-point.cir new file mode 100644 index 0000000000000..3e65f094ccb63 --- /dev/null +++ b/clang/test/CIR/IR/invalid-coro-ret-point.cir @@ -0,0 +1,55 @@ +// RUN: cir-opt %s -verify-diagnostics -split-input-file + +cir.func coroutine @coro_ret_point_body_must_end_in_yield(%arg0 : !cir.bool) { + cir.coro.ret_point { // expected-error {{body region must terminate with 'cir.yield'}} + cir.coro.body { + cir.await(user, ready : { + cir.condition(%arg0) + }, suspend : { + cir.coro.suspend_point + }, resume : { + cir.yield + },) + } + cir.trap + }, ret : { + cir.return + } + cir.trap +} + +cir.func coroutine @coro_ret_point_body_must_not_contain_return(%arg0 : !cir.bool) { + cir.coro.ret_point { // expected-error {{body region must not contain 'cir.return' operations}} + cir.coro.body { + cir.await(user, ready : { + cir.condition(%arg0) + }, suspend : { + cir.coro.suspend_point + }, resume : { + cir.yield + },) + } + cir.return + }, ret : { + cir.return + } + cir.trap +} + +cir.func coroutine @coro_ret_point_return_region_must_end_in_return(%arg0 : !cir.bool) { + cir.coro.ret_point { // expected-error {{return region must terminate with 'cir.return'}} + cir.coro.body { + cir.await(user, ready : { + cir.condition(%arg0) + }, suspend : { + cir.coro.suspend_point + }, resume : { + cir.yield + },) + } + cir.yield + }, ret : { + cir.trap + } + cir.trap +} diff --git a/clang/test/CIR/IR/invalid-coro-suspend.cir b/clang/test/CIR/IR/invalid-coro-suspend.cir index 3a45e22433a58..d03769ed66306 100644 --- a/clang/test/CIR/IR/invalid-coro-suspend.cir +++ b/clang/test/CIR/IR/invalid-coro-suspend.cir @@ -1,17 +1,23 @@ // RUN: cir-opt %s -verify-diagnostics -split-input-file -cir.func coroutine @must_have_one_coro_suspend_dest(%arg0 : !cir.bool) { // expected-error {{coroutine function must have exactly one cir.coro.suspend.point.dest}} - cir.coro.body { - cir.await(user, ready : { - cir.condition(%arg0) - }, suspend : { - cir.coro.suspend.point - }, resume : { - cir.yield - },) +cir.func coroutine @must_have_one_coro_ret_point(%arg0 : !cir.bool) { // expected-error {{coroutine function must have exactly one cir.coro.ret_point op}} + cir.coro.ret_point { + cir.coro.body { + cir.await(user, ready : { + cir.condition(%arg0) + }, suspend : { + cir.coro.suspend_point + }, resume : { + cir.yield + },) + } + cir.yield + }, ret : { + cir.return } - cir.coro.suspend.point.dest - cir.coro.suspend.point.dest + cir.coro.ret_point { + }, ret : { + } + cir.trap } - >From 226fadbc5792535527d1e7bd284f5b456a3b29b7 Mon Sep 17 00:00:00 2001 From: Andres Salamanca <[email protected]> Date: Thu, 30 Jul 2026 21:35:53 -0500 Subject: [PATCH 3/4] Fix formatting --- clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp index 7fc59b30e8c3a..67d9db2519051 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp @@ -617,7 +617,7 @@ emitSuspendExpression(CIRGenFunction &cgf, CGCoroData &coro, } // Signals the parent that execution flows to next region. - cir::CoroSuspendPoint::create(builder,loc); + cir::CoroSuspendPoint::create(builder, loc); }, /*resumeBuilder=*/ [&](mlir::OpBuilder &b, mlir::Location loc) { >From 8015805c153eebfdbdafa3a8899ce95f20a28e74 Mon Sep 17 00:00:00 2001 From: Andres Salamanca <[email protected]> Date: Tue, 4 Aug 2026 20:52:07 -0500 Subject: [PATCH 4/4] Fix after rebase. --- clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp | 9 +++++---- clang/test/CIR/CodeGenCoroutines/coro-task.cpp | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp index 67d9db2519051..44dd4f682a316 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp @@ -517,10 +517,6 @@ CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt &s) { } } } - cir::CoroEndOp::create( - cgm.getBuilder(), openCurlyLoc, - mlir::ValueRange{builder.getNullPtr(builder.getVoidPtrTy(), openCurlyLoc), - builder.getBool(false, openCurlyLoc)}); mlir::Block &coroRetBodyBlock = coroRet.getBodyRegion().back(); { @@ -532,6 +528,11 @@ CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt &s) { mlir::OpBuilder::InsertionGuard guard(builder); builder.restoreInsertionPoint(coroRetRegion); + cir::CoroEndOp::create( + cgm.getBuilder(), openCurlyLoc, + mlir::ValueRange{builder.getNullPtr(builder.getVoidPtrTy(), openCurlyLoc), + builder.getBool(false, openCurlyLoc)}); + if (auto *ret = cast_or_null<ReturnStmt>(s.getReturnStmt())) { // Since we already emitted the return value above, so we shouldn't // emit it again here. diff --git a/clang/test/CIR/CodeGenCoroutines/coro-task.cpp b/clang/test/CIR/CodeGenCoroutines/coro-task.cpp index ad07e8d43b333..2a7d743b959a7 100644 --- a/clang/test/CIR/CodeGenCoroutines/coro-task.cpp +++ b/clang/test/CIR/CodeGenCoroutines/coro-task.cpp @@ -194,7 +194,7 @@ VoidTask silly_task() { // CIR: %[[NullPtr2:.*]] = cir.const #cir.ptr<null> // CIR: %[[Cond:.*]] = cir.cmp ne %[[FreeMem]], %[[NullPtr2]] // CIR: cir.if %[[Cond]] { -// CIR: %[[Size:.*]] = cir.call @__builtin_coro_size() +// CIR: %[[Size:.*]] = cir.coro.intrinsic.size() // CIR: cir.call @_ZdlPvm(%[[FreeMem]], %[[Size]]) // CIR: } // CIR: cir.yield _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
