Skip to content

Commit 64a7628

Browse files
[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.
1 parent ace65a0 commit 64a7628

File tree

3 files changed

+56
-3
lines changed

3 files changed

+56
-3
lines changed

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ struct MissingFeatures {
153153
static bool coroEndBuiltinCall() { return false; }
154154
static bool emitBodyAndFallthrough() { return false; }
155155
static bool coroOutsideFrameMD() { return false; }
156+
static bool coroCoReturn() { return false; }
157+
static bool coroCoYield() { return false; }
156158

157159
// Various handling of deferred processing in CIRGenModule.
158160
static bool cgmRelease() { return false; }

clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ struct clang::CIRGen::CGCoroData {
3232

3333
// Stores the result of __builtin_coro_begin call.
3434
mlir::Value coroBegin = nullptr;
35+
36+
// The promise type's 'unhandled_exception' handler, if it defines one.
37+
Stmt *exceptionHandler = nullptr;
3538
};
3639

3740
// Defining these here allows to keep CGCoroData private to this file.
@@ -272,6 +275,17 @@ CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt &s) {
272275
}
273276
return mlir::success();
274277
}
278+
279+
static bool memberCallExpressionCanThrow(const Expr *e) {
280+
if (const auto *ce = dyn_cast<CXXMemberCallExpr>(e))
281+
if (const auto *proto =
282+
ce->getMethodDecl()->getType()->getAs<FunctionProtoType>())
283+
if (isNoexceptExceptionSpec(proto->getExceptionSpecType()) &&
284+
proto->canThrow() == CT_Cannot)
285+
return false;
286+
return true;
287+
}
288+
275289
// Given a suspend expression which roughly looks like:
276290
//
277291
// auto && x = CommonExpr();
@@ -333,6 +347,31 @@ emitSuspendExpression(CIRGenFunction &cgf, CGCoroData &coro,
333347
},
334348
/*resumeBuilder=*/
335349
[&](mlir::OpBuilder &b, mlir::Location loc) {
350+
// Exception handling requires additional IR. If the 'await_resume'
351+
// function is marked as 'noexcept', we avoid generating this additional
352+
// IR.
353+
CXXTryStmt *tryStmt = nullptr;
354+
if (coro.exceptionHandler && kind == cir::AwaitKind::Init &&
355+
memberCallExpressionCanThrow(s.getResumeExpr()))
356+
cgf.cgm.errorNYI("Coro resume Exception");
357+
358+
// FIXME(cir): the alloca for the resume expr should be placed in the
359+
// enclosing cir.scope instead.
360+
if (forLValue) {
361+
assert(!cir::MissingFeatures::coroCoYield());
362+
} else {
363+
awaitRes.rv =
364+
cgf.emitAnyExpr(s.getResumeExpr(), aggSlot, ignoreResult);
365+
if (!awaitRes.rv.isIgnored())
366+
// Create the alloca in the block before the scope wrapping
367+
// cir.await.
368+
assert(!cir::MissingFeatures::coroCoReturn());
369+
}
370+
371+
if (tryStmt)
372+
cgf.cgm.errorNYI("Coro tryStmt");
373+
374+
// Returns control back to parent.
336375
cir::YieldOp::create(builder, loc);
337376
});
338377

clang/test/CIR/CodeGen/coro-task.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -203,11 +203,21 @@ VoidTask silly_task() {
203203
// CIR: %[[CoroHandleVoidReload:.*]] = cir.load{{.*}} %[[CoroHandleVoidAddr]] : !cir.ptr<![[CoroHandleVoid]]>, ![[CoroHandleVoid]]
204204
// CIR: cir.call @_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SuspendAlwaysAddr]], %[[CoroHandleVoidReload]])
205205
// CIR: cir.yield
206+
207+
// Third region `resume` handles coroutine resuming logic.
208+
206209
// CIR: }, resume : {
210+
// CIR: cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SuspendAlwaysAddr]])
207211
// CIR: cir.yield
208212
// CIR: },)
209213
// CIR: }
210214

215+
// Since we already tested cir.await guts above, the remaining checks for:
216+
// - The actual user written co_await
217+
// - The promise call
218+
// - The final suspend co_await
219+
// - Return
220+
211221
folly::coro::Task<int> byRef(const std::string& s) {
212222
co_return s.size();
213223
}
@@ -245,6 +255,8 @@ folly::coro::Task<int> byRef(const std::string& s) {
245255
// CIR: %[[CoroHandleVoidReload:.*]] = cir.load{{.*}} %[[CoroHandleVoidAddr]] : !cir.ptr<![[CoroHandleVoid]]>, ![[CoroHandleVoid]]
246256
// CIR: cir.call @_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SuspendAlwaysAddr]], %[[CoroHandleVoidReload]])
247257
// CIR: cir.yield
248-
// CIR: }, resume : {
249-
// CIR: cir.yield
250-
// CIR: },)
258+
// CIR: }, resume : {
259+
// CIR: cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SuspendAlwaysAddr]])
260+
// CIR: cir.yield
261+
// CIR: },)
262+
// CIR: }

0 commit comments

Comments
 (0)