diff options
author | Iain Sandoe <iain@sandoe.co.uk> | 2020-03-26 21:00:25 +0000 |
---|---|---|
committer | Iain Sandoe <iain@sandoe.co.uk> | 2020-03-26 21:01:13 +0000 |
commit | 6d85947d23ab6a9b9975b2e0590db9308c5c1b07 (patch) | |
tree | ba421ba3fb1f1de402d5695da8edd6f19f2bb16d /gcc/tree-ssa-propagate.c | |
parent | 2a1f0f64160e078e23795901ff98575805d6875b (diff) | |
download | gcc-6d85947d23ab6a9b9975b2e0590db9308c5c1b07.zip gcc-6d85947d23ab6a9b9975b2e0590db9308c5c1b07.tar.gz gcc-6d85947d23ab6a9b9975b2e0590db9308c5c1b07.tar.bz2 |
coroutines: Implement n4849 recommended symmetric transfer.
Although the note in the text [expr.await] / 5.1.1 is not normative,
it is asserted by users that an implementation that is unable to
perform unlimited symmetric transfers is not terribly useful.
This relates to the following circumstance:
try {
users-function-body:
{
....
{ some suspend context
continuation_handle = await_suspend (another handle);
continuation_handle.resume ();
'return' (actually a suspension operation).
}
}
} catch (...) {}
The call to 'continuation_handle.resume ()' needs to be a tail-
call in order that an arbitrary number of coroutines can be handled
in this manner. There are two issues with this:
1. That the user's function body is wrapped in a try/catch block and
one cannot tail-call from within those.
2. That GCC doesn't usually produce tail-calls when the optimisation
level is < O2.
After considerable discussion at WG21 meetings, it has been determined
that the intent is that the operation behaves as if the resume call is
executed in the context of the caller.
So, we can remap the fragment above like this:
{
void_coroutine_handle continuation;
try {
users-function-body:
{
....
{ some suspend context
continuation = await_suspend (another handle);
<scope exit without cleanup> symmetric_transfer;
}
}
} catch (...) {}
symmetric_transfer:
continuation.resume(); [tail call] [must tail call]
}
Thus we take the call outside the try-catch block which solves
issue (1) and mark it as a tail call and as "must tail call" for
correctness which solves (2).
As bonuses, since we no longer need to differentiate handle types
returned from await_suspend() methods, nor do we need to keep them
in the coroutine frame, since they are ephemeral, we save entries in
the frame and reduce some code too.
gcc/cp/ChangeLog:
2020-03-26 Iain Sandoe <iain@sandoe.co.uk>
* coroutines.cc (coro_init_identifiers): Initialize an identifier
for the cororoutine handle 'address' method name.
(struct coro_aw_data): Add fields to cover the continuations.
(co_await_expander): Determine the kind of await_suspend in use.
If we have the case that returns a continuation handle, then save
this and make the target for 'scope exit without cleanup' be the
continuation resume label.
(expand_co_awaits): Remove.
(struct suspend_point_info): Remove fields that kept the returned
await_suspend handle type.
(transform_await_expr): Remove code tracking continuation handles.
(build_actor_fn): Add the continuation handle as an actor-function
scope var. Build the symmetric transfer continuation point. Call
the tree walk for co_await expansion directly, rather than via a
trivial shim function.
(register_await_info): Remove fields tracking continuation handles.
(get_await_suspend_return_type): Remove.
(register_awaits): Remove code tracking continuation handles.
(morph_fn_to_coro): Remove code tracking continuation handles.
gcc/testsuite/ChangeLog:
2020-03-26 Iain Sandoe <iain@sandoe.co.uk>
* g++.dg/coroutines/torture/co-ret-09-bool-await-susp.C: Amend
to n4849 behaviour.
* g++.dg/coroutines/torture/symmetric-transfer-00-basic.C: New
test.
Diffstat (limited to 'gcc/tree-ssa-propagate.c')
0 files changed, 0 insertions, 0 deletions