[CIR] Upstream Emit the resume branch for cir.await op (#169864)

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.
This commit is contained in:
Andres-Salamanca
2025-12-01 18:48:26 -05:00
committed by GitHub
parent ace65a0a8d
commit 64a7628048
3 changed files with 56 additions and 3 deletions

View File

@@ -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; }

View File

@@ -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 auto *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);
});

View File

@@ -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: }