mirror of
https://github.com/intel/llvm.git
synced 2026-01-13 19:08:21 +08:00
[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:
@@ -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; }
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
|
||||
@@ -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: }
|
||||
|
||||
Reference in New Issue
Block a user