diff mbox

RFA (gimplify): PATCH to implement C++ order of evaluation paper

Message ID CADzB+2=gp37wxt+BRrGDChvsrYzJYWffxY54YvkmKZyH6cmuRw@mail.gmail.com
State New
Headers show

Commit Message

Jason Merrill July 7, 2016, 7:18 p.m. UTC
On Tue, Jun 28, 2016 at 10:00 AM, Richard Biener
<richard.guenther@gmail.com> wrote:
> On Thu, Jun 16, 2016 at 6:15 PM, Jakub Jelinek <jakub@redhat.com> wrote:
>> On Thu, Jun 16, 2016 at 11:28:48AM -0400, Jason Merrill wrote:
>>>  gimple_predicate
>>>  rhs_predicate_for (tree lhs)
>>>  {
>>> -  if (is_gimple_reg (lhs))
>>> +  if (will_be_gimple_reg (lhs))
>>>      return is_gimple_reg_rhs_or_call;
>>>    else
>>>      return is_gimple_mem_rhs_or_call;
>>> @@ -4778,10 +4811,6 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
>>>       that is what we must do here.  */
>>>    maybe_with_size_expr (from_p);
>>>
>>> -  ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
>>> -  if (ret == GS_ERROR)
>>> -    return ret;
>>> -
>>>    /* As a special case, we have to temporarily allow for assignments
>>>       with a CALL_EXPR on the RHS.  Since in GIMPLE a function call is
>>>       a toplevel statement, when gimplifying the GENERIC expression
>>> @@ -4799,6 +4828,10 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
>>>    if (ret == GS_ERROR)
>>>      return ret;
>>>
>>> +  ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
>>> +  if (ret == GS_ERROR)
>>> +    return ret;
>>> +
>>>    /* In case of va_arg internal fn wrappped in a WITH_SIZE_EXPR, add the type
>>>       size as argument to the call.  */
>>>    if (TREE_CODE (*from_p) == WITH_SIZE_EXPR)
>>
>> I wonder if instead of trying to guess early what we'll gimplify into it
>> wouldn't be better to gimplify *from_p twice, first time with a predicate
>> that would assume *to_p could be gimplified into is_gimple_ref, but
>> guarantee there are no side-effects (so that those aren't evaluated
>> after lhs side-effects), and second time if needed (if *to_p didn't end up
>> being is_gimple_reg).  So something like a new predicate like:
>
> Yes, that is what I was suggesting.

How about this?  I also have a patch to handle assignment order
entirely in the front end, but my impression has been that you wanted
to make this change for other reasons as well.

In other news, I convinced the committee to drop function arguments
from the order of evaluation paper, so we don't have to worry about
that hit on PUSH_ARGS_REVERSED targets.

Jason
commit 8dac319f5647d31568ad9278edeff3607aa1b3cc
Author: Jason Merrill <jason@redhat.com>
Date:   Sat Jun 25 19:12:42 2016 +0300

    	P0145: Refining Expression Order for C++ (assignment)
    
    	* gimplify.c (initial_rhs_predicate_for): New.
    	(gimplfy_modify_expr): Gimplify RHS before LHS.

Comments

Richard Biener July 8, 2016, 12:41 p.m. UTC | #1
On Thu, Jul 7, 2016 at 9:18 PM, Jason Merrill <jason@redhat.com> wrote:
> On Tue, Jun 28, 2016 at 10:00 AM, Richard Biener
> <richard.guenther@gmail.com> wrote:
>> On Thu, Jun 16, 2016 at 6:15 PM, Jakub Jelinek <jakub@redhat.com> wrote:
>>> On Thu, Jun 16, 2016 at 11:28:48AM -0400, Jason Merrill wrote:
>>>>  gimple_predicate
>>>>  rhs_predicate_for (tree lhs)
>>>>  {
>>>> -  if (is_gimple_reg (lhs))
>>>> +  if (will_be_gimple_reg (lhs))
>>>>      return is_gimple_reg_rhs_or_call;
>>>>    else
>>>>      return is_gimple_mem_rhs_or_call;
>>>> @@ -4778,10 +4811,6 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
>>>>       that is what we must do here.  */
>>>>    maybe_with_size_expr (from_p);
>>>>
>>>> -  ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
>>>> -  if (ret == GS_ERROR)
>>>> -    return ret;
>>>> -
>>>>    /* As a special case, we have to temporarily allow for assignments
>>>>       with a CALL_EXPR on the RHS.  Since in GIMPLE a function call is
>>>>       a toplevel statement, when gimplifying the GENERIC expression
>>>> @@ -4799,6 +4828,10 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
>>>>    if (ret == GS_ERROR)
>>>>      return ret;
>>>>
>>>> +  ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
>>>> +  if (ret == GS_ERROR)
>>>> +    return ret;
>>>> +
>>>>    /* In case of va_arg internal fn wrappped in a WITH_SIZE_EXPR, add the type
>>>>       size as argument to the call.  */
>>>>    if (TREE_CODE (*from_p) == WITH_SIZE_EXPR)
>>>
>>> I wonder if instead of trying to guess early what we'll gimplify into it
>>> wouldn't be better to gimplify *from_p twice, first time with a predicate
>>> that would assume *to_p could be gimplified into is_gimple_ref, but
>>> guarantee there are no side-effects (so that those aren't evaluated
>>> after lhs side-effects), and second time if needed (if *to_p didn't end up
>>> being is_gimple_reg).  So something like a new predicate like:
>>
>> Yes, that is what I was suggesting.
>
> How about this?  I also have a patch to handle assignment order
> entirely in the front end, but my impression has been that you wanted
> to make this change for other reasons as well.

Yes.  Looks good to me.

> In other news, I convinced the committee to drop function arguments
> from the order of evaluation paper, so we don't have to worry about
> that hit on PUSH_ARGS_REVERSED targets.

Good.

Thanks,
Richard.

> Jason
Jakub Jelinek July 8, 2016, 1:42 p.m. UTC | #2
On Thu, Jul 07, 2016 at 03:18:13PM -0400, Jason Merrill wrote:
> How about this?  I also have a patch to handle assignment order
> entirely in the front end, but my impression has been that you wanted
> to make this change for other reasons as well.

So what exactly is supposed to be the evaluation order for function calls
with lhs in C++17?
Reading
http://en.cppreference.com/w/cpp/language/eval_order
I'm confused.
struct S { S (); ~S (); ... };
S s[1024];
typedef S (*fn) (int, int);
fn a[1024];
void foo (int *i, int *j, int *k, int *l)
{
  s[i[0]++] = (a[j[0]++]) (k[0]++, l[0]++);
}
So, j[0]++ needs to happen first, then k[0]++ and l[0]++ (indeterminately
sequenced), but what about the function call vs. i[0]++?

There is the rule that for E1 = E2 all side-effects of E2 happen before all
side-effects of E1.

I mean, if the function return type is a gimple reg type, then I see no
problem in honoring that, the function call returns a temporary, then the
side-effects of the lhs are evaluated and then it is stored to that lvalue.

But, if the return type is non-POD, then we need to pass the address of the
lhs as invisible reference to the function call, how can we do it if we
can't yet evaluate the side-effects of the lhs?

Perhaps better testcase is:

int bar (int);
void baz ()
{
  s[bar (0)] = (a[bar (1)]) (bar (2), 0);
}

In which order all the 4 calls are made?

What the patch you've posted does is that it gimplifies from_p first,
and gimplify_call_expr will first evaluate bar (1), then bar (2),
but then it is a CALL_EXPR; then it gimplifies the lhs, i.e. bar (0)
call, and finally the indirect call.

> 
> In other news, I convinced the committee to drop function arguments
> from the order of evaluation paper, so we don't have to worry about
> that hit on PUSH_ARGS_REVERSED targets.
> 
> Jason

> commit 8dac319f5647d31568ad9278edeff3607aa1b3cc
> Author: Jason Merrill <jason@redhat.com>
> Date:   Sat Jun 25 19:12:42 2016 +0300
> 
>     	P0145: Refining Expression Order for C++ (assignment)
>     
>     	* gimplify.c (initial_rhs_predicate_for): New.
>     	(gimplfy_modify_expr): Gimplify RHS before LHS.
> 
> diff --git a/gcc/gimplify.c b/gcc/gimplify.c
> index 47c4d25..0276588 100644
> --- a/gcc/gimplify.c
> +++ b/gcc/gimplify.c
> @@ -3813,6 +3813,18 @@ rhs_predicate_for (tree lhs)
>      return is_gimple_mem_rhs_or_call;
>  }
>  
> +/* Return the initial guess for an appropriate RHS predicate for this LHS,
> +   before the LHS has been gimplified.  */
> +
> +static gimple_predicate
> +initial_rhs_predicate_for (tree lhs)
> +{
> +  if (is_gimple_reg_type (TREE_TYPE (lhs)))
> +    return is_gimple_reg_rhs_or_call;
> +  else
> +    return is_gimple_mem_rhs_or_call;
> +}
> +
>  /* Gimplify a C99 compound literal expression.  This just means adding
>     the DECL_EXPR before the current statement and using its anonymous
>     decl instead.  */
> @@ -4778,10 +4790,6 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
>       that is what we must do here.  */
>    maybe_with_size_expr (from_p);
>  
> -  ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
> -  if (ret == GS_ERROR)
> -    return ret;
> -
>    /* As a special case, we have to temporarily allow for assignments
>       with a CALL_EXPR on the RHS.  Since in GIMPLE a function call is
>       a toplevel statement, when gimplifying the GENERIC expression
> @@ -4794,6 +4802,16 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
>       reaches the CALL_EXPR.  On return from gimplify_expr, the newly
>       created GIMPLE_CALL <foo> will be the last statement in *PRE_P
>       and all we need to do here is set 'a' to be its LHS.  */
> +  ret = gimplify_expr (from_p, pre_p, post_p,
> +		       initial_rhs_predicate_for (*to_p), fb_rvalue);
> +  if (ret == GS_ERROR)
> +    return ret;
> +
> +  ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
> +  if (ret == GS_ERROR)
> +    return ret;
> +
> +  /* Now that the LHS is gimplified, we know what to use for the RHS.  */
>    ret = gimplify_expr (from_p, pre_p, post_p, rhs_predicate_for (*to_p),
>  		       fb_rvalue);
>    if (ret == GS_ERROR)


	Jakub
diff mbox

Patch

diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 47c4d25..0276588 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -3813,6 +3813,18 @@  rhs_predicate_for (tree lhs)
     return is_gimple_mem_rhs_or_call;
 }
 
+/* Return the initial guess for an appropriate RHS predicate for this LHS,
+   before the LHS has been gimplified.  */
+
+static gimple_predicate
+initial_rhs_predicate_for (tree lhs)
+{
+  if (is_gimple_reg_type (TREE_TYPE (lhs)))
+    return is_gimple_reg_rhs_or_call;
+  else
+    return is_gimple_mem_rhs_or_call;
+}
+
 /* Gimplify a C99 compound literal expression.  This just means adding
    the DECL_EXPR before the current statement and using its anonymous
    decl instead.  */
@@ -4778,10 +4790,6 @@  gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
      that is what we must do here.  */
   maybe_with_size_expr (from_p);
 
-  ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
-  if (ret == GS_ERROR)
-    return ret;
-
   /* As a special case, we have to temporarily allow for assignments
      with a CALL_EXPR on the RHS.  Since in GIMPLE a function call is
      a toplevel statement, when gimplifying the GENERIC expression
@@ -4794,6 +4802,16 @@  gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
      reaches the CALL_EXPR.  On return from gimplify_expr, the newly
      created GIMPLE_CALL <foo> will be the last statement in *PRE_P
      and all we need to do here is set 'a' to be its LHS.  */
+  ret = gimplify_expr (from_p, pre_p, post_p,
+		       initial_rhs_predicate_for (*to_p), fb_rvalue);
+  if (ret == GS_ERROR)
+    return ret;
+
+  ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
+  if (ret == GS_ERROR)
+    return ret;
+
+  /* Now that the LHS is gimplified, we know what to use for the RHS.  */
   ret = gimplify_expr (from_p, pre_p, post_p, rhs_predicate_for (*to_p),
 		       fb_rvalue);
   if (ret == GS_ERROR)