llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: None (Andres-Salamanca) <details> <summary>Changes</summary> This PR upstreams the emission of the `cir.await` resume branch. Handling the case where the return value of `co_await` is not ignored is deferred to a future PR, which will be added once `co_return` is upstreamed. Additionally, the `forLValue` variable is always `false` in the current implementation. When support for emitting `coro_yield` is added, this variable will be set to `true`, so that work is also deferred to a future PR. --- Full diff: https://github.com/llvm/llvm-project/pull/169864.diff 3 Files Affected: - (modified) clang/include/clang/CIR/MissingFeatures.h (+2) - (modified) clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp (+39) - (modified) clang/test/CIR/CodeGen/coro-task.cpp (+15-3) ``````````diff diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 1427c677d0f34..3d3251adae279 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -153,6 +153,8 @@ 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; } // Various handling of deferred processing in CIRGenModule. static bool cgmRelease() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp index f7df811a67c26..35a6354b19705 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp @@ -32,6 +32,9 @@ struct clang::CIRGen::CGCoroData { // Stores the result of __builtin_coro_begin call. mlir::Value coroBegin = nullptr; + + // The promise type's 'unhandled_exception' handler, if it defines one. + Stmt *exceptionHandler = nullptr; }; // Defining these here allows to keep CGCoroData private to this file. @@ -272,6 +275,17 @@ CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt &s) { } return mlir::success(); } + +static bool memberCallExpressionCanThrow(const Expr *e) { + if (const auto *ce = dyn_cast<CXXMemberCallExpr>(e)) + if (const FunctionProtoType *proto = + ce->getMethodDecl()->getType()->getAs<FunctionProtoType>()) + if (isNoexceptExceptionSpec(proto->getExceptionSpecType()) && + proto->canThrow() == CT_Cannot) + return false; + return true; +} + // Given a suspend expression which roughly looks like: // // auto && x = CommonExpr(); @@ -333,6 +347,31 @@ emitSuspendExpression(CIRGenFunction &cgf, CGCoroData &coro, }, /*resumeBuilder=*/ [&](mlir::OpBuilder &b, mlir::Location loc) { + // Exception handling requires additional IR. If the 'await_resume' + // function is marked as 'noexcept', we avoid generating this additional + // IR. + CXXTryStmt *tryStmt = nullptr; + if (coro.exceptionHandler && kind == cir::AwaitKind::Init && + memberCallExpressionCanThrow(s.getResumeExpr())) + cgf.cgm.errorNYI("Coro resume Exception"); + + // FIXME(cir): the alloca for the resume expr should be placed in the + // enclosing cir.scope instead. + if (forLValue) { + assert(!cir::MissingFeatures::coroCoYield()); + } else { + awaitRes.rv = + cgf.emitAnyExpr(s.getResumeExpr(), aggSlot, ignoreResult); + if (!awaitRes.rv.isIgnored()) + // Create the alloca in the block before the scope wrapping + // cir.await. + assert(!cir::MissingFeatures::coroCoReturn()); + } + + if (tryStmt) + cgf.cgm.errorNYI("Coro tryStmt"); + + // Returns control back to parent. cir::YieldOp::create(builder, loc); }); diff --git a/clang/test/CIR/CodeGen/coro-task.cpp b/clang/test/CIR/CodeGen/coro-task.cpp index 4843f2433fa64..6cafe3fd0c419 100644 --- a/clang/test/CIR/CodeGen/coro-task.cpp +++ b/clang/test/CIR/CodeGen/coro-task.cpp @@ -203,11 +203,21 @@ VoidTask silly_task() { // CIR: %[[CoroHandleVoidReload:.*]] = cir.load{{.*}} %[[CoroHandleVoidAddr]] : !cir.ptr<![[CoroHandleVoid]]>, ![[CoroHandleVoid]] // CIR: cir.call @_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SuspendAlwaysAddr]], %[[CoroHandleVoidReload]]) // CIR: cir.yield + +// Third region `resume` handles coroutine resuming logic. + // CIR: }, resume : { +// CIR: cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SuspendAlwaysAddr]]) // CIR: cir.yield // CIR: },) // CIR: } +// Since we already tested cir.await guts above, the remaining checks for: +// - The actual user written co_await +// - The promise call +// - The final suspend co_await +// - Return + folly::coro::Task<int> byRef(const std::string& s) { co_return s.size(); } @@ -245,6 +255,8 @@ folly::coro::Task<int> byRef(const std::string& s) { // CIR: %[[CoroHandleVoidReload:.*]] = cir.load{{.*}} %[[CoroHandleVoidAddr]] : !cir.ptr<![[CoroHandleVoid]]>, ![[CoroHandleVoid]] // CIR: cir.call @_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SuspendAlwaysAddr]], %[[CoroHandleVoidReload]]) // CIR: cir.yield -// CIR: }, resume : { -// CIR: cir.yield -// CIR: },) +// CIR: }, resume : { +// CIR: cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SuspendAlwaysAddr]]) +// CIR: cir.yield +// CIR: },) +// CIR: } `````````` </details> https://github.com/llvm/llvm-project/pull/169864 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
