[PATCH] coroutines: Implement n4849 recommended symmetric transfer.

Nathan Sidwell nathan@acm.org
Tue Mar 24 13:12:26 GMT 2020


On 3/20/20 11:40 AM, Iain Sandoe via Gcc-patches wrote:

> 2020-03-20  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): Handle the continuation case.
> 	(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.
> 	(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-20  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.
> 
> 
> diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
> index abd4cac1c82..49e03f2ccea 100644
> --- a/gcc/cp/coroutines.cc
> +++ b/gcc/cp/coroutines.cc

>     tree suspend = TREE_VEC_ELT (awaiter_calls, 1); /* await_suspend().  */
> +  tree susp_type;
> +  if (TREE_CODE (suspend) == CALL_EXPR)
> +    {
> +      susp_type = CALL_EXPR_FN (suspend);
> +      if (TREE_CODE (susp_type) == ADDR_EXPR)
> +	susp_type = TREE_OPERAND (susp_type, 0);
> +      susp_type = TREE_TYPE (TREE_TYPE (susp_type));
> +    }
> +  else
> +    susp_type = TREE_TYPE (suspend);

I think:
  if (tree fndec = get_callee_fndecl_nofold (suspend))
     susp_type = TREE_TYPE (TREE_TYPE (fndecl));
  else
     susp_type = TREE_TYPE (suspend);
would do?  But how can TREE_TYPE (suspend) be different from the return 
type of the function decl?  It seems funky that the behaviour could 
depend on the form of the suspend.  What am I missing?


> @@ -1532,6 +1553,8 @@ co_await_expander (tree *stmt, int * /*do_subtree*/, void *d)
>       = build1 (ADDR_EXPR, build_reference_type (void_type_node), resume_label);
>     tree susp
>       = build1 (ADDR_EXPR, build_reference_type (void_type_node), data->cororet);
> +  tree cont
> +    = build1 (ADDR_EXPR, build_reference_type (void_type_node), data->corocont);
>     tree final_susp = build_int_cst (integer_type_node, is_final ? 1 : 0);

Wait, 'void &' is not a thing.  What's been happening here?  do you mean 
to build pointer_types?  'build_address (data->$FIELD)'

> @@ -2012,6 +2027,15 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,
>       = create_named_label_with_ctx (loc, "actor.begin", actor);
>     tree actor_frame = build1_loc (loc, INDIRECT_REF, coro_frame_type, actor_fp);
>   
> +  /* Init the continuation with a NULL ptr.  */
> +  tree zeroinit = build1 (CONVERT_EXPR, void_coro_handle_type,
> +			  integer_zero_node);
> +  tree ci = build2 (INIT_EXPR, void_coro_handle_type, continuation, zeroinit);
> +  ci = build_stmt (loc, DECL_EXPR, continuation);

This appears to be overwriting ci?

> +  ci = build1_loc (loc, CONVERT_EXPR, void_type_node, ci);
.. and still expecting it to be an EXPR node?
> +  ci = maybe_cleanup_point_expr_void (ci);
> +  add_stmt (ci);
> +
>     /* Re-write param references in the body, no code should be generated
>        here.  */
>     if (DECL_ARGUMENTS (orig))

> +
> +  /* Now we have the actual call, and we can mark it as a tail.  */
> +  CALL_EXPR_TAILCALL (resume) = true;
> +  /* ... and for optimisation levels 0..1, mark it as requiring a tail-call
> +     for correctness.  It seems that doing this for optimisation levels that
> +     normally perform tail-calling, confuses the ME (or it would be logical
> +     to put this on unilaterally).  */

  Might be worth ping a ME expert about why that is?

> +  if (optimize < 2)
> +    CALL_EXPR_MUST_TAIL_CALL (resume) = true;
> +  resume = coro_build_cvt_void_expr_stmt (resume, loc);
> +  add_stmt (resume);
> +
> +  r = build_stmt (loc, RETURN_EXPR, NULL);
> +  r = maybe_cleanup_point_expr_void (r);

Shouldn't there be no cleanups?  Perhaps assert it didn't add any?

> +  add_stmt (r);
> +
>     /* We need the resume index to work with.  */
>     tree res_idx_m
>       = lookup_member (coro_frame_type, resume_idx_name,

nathan


-- 
Nathan Sidwell


More information about the Gcc-patches mailing list