Message ID | CADzB+2mdcgwCQAsUAuynyhbzYQdNdJJ5YhKbPzJV-vEgWBFb3A@mail.gmail.com |
---|---|
State | New |
Headers | show |
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: static bool is_whatever (tree t) { /* For calls, as there are side-effects, assume lhs might not be is_gimple_reg. */ if (TREE_CODE (t) == CALL_EXPR && is_gimple_reg_type (TREE_TYPE (t))) return is_gimple_val (t); /* For other side effects, also make sure those are evaluated before side-effects in lhs. */ if (TREE_THIS_VOLATILE (t)) return is_gimple_mem_rhs_or_call (t); /* Otherwise, optimistically assume lhs will be is_gimple_reg. */ return is_gimple_reg_rhs_or_call (t); } and then do in gimplify_modify_expr: ret = gimplify_expr (from_p, pre_p, post_p, is_gimple_reg (*to_p) ? is_gimple_reg_rhs_or_call : is_whatever, 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; if (!is_gimple_reg (*to_p) && !is_gimple_mem_rhs_or_call (*from_p)) { ret = gimplify_expr (from_p, pre_p, post_p, is_gimple_mem_rhs_or_call, fb_rvalue); if (ret == GS_ERROR) return ret; } Or if you want to guess if *to_p will be is_gimple_reg or not after gimplification, do it just very conservatively and let the more difficult to predict cases handled worst case by forcing something into a temporary with the above code. Jakub
On Thu, Jun 16, 2016 at 06:15:34PM +0200, Jakub Jelinek wrote: > and then do in gimplify_modify_expr: > ret = gimplify_expr (from_p, pre_p, post_p, > is_gimple_reg (*to_p) ^^^ of course even this is a prediction and wrong one for DECL_HAS_VALUE_EXPR_Ps. Conservative would be is_whatever always. > ? is_gimple_reg_rhs_or_call : is_whatever, > 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; > > if (!is_gimple_reg (*to_p) && !is_gimple_mem_rhs_or_call (*from_p)) > { > ret = gimplify_expr (from_p, pre_p, post_p, is_gimple_mem_rhs_or_call, > fb_rvalue); > if (ret == GS_ERROR) > return ret; > } > > Or if you want to guess if *to_p will be is_gimple_reg or not after > gimplification, do it just very conservatively and let the more difficult > to predict cases handled worst case by forcing something into a temporary > with the above code. Jakub
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. Richard. > static bool > is_whatever (tree t) > { > /* For calls, as there are side-effects, assume lhs might not be > is_gimple_reg. */ > if (TREE_CODE (t) == CALL_EXPR && is_gimple_reg_type (TREE_TYPE (t))) > return is_gimple_val (t); > /* For other side effects, also make sure those are evaluated before > side-effects in lhs. */ > if (TREE_THIS_VOLATILE (t)) > return is_gimple_mem_rhs_or_call (t); > /* Otherwise, optimistically assume lhs will be is_gimple_reg. */ > return is_gimple_reg_rhs_or_call (t); > } > > and then do in gimplify_modify_expr: > ret = gimplify_expr (from_p, pre_p, post_p, > is_gimple_reg (*to_p) > ? is_gimple_reg_rhs_or_call : is_whatever, > 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; > > if (!is_gimple_reg (*to_p) && !is_gimple_mem_rhs_or_call (*from_p)) > { > ret = gimplify_expr (from_p, pre_p, post_p, is_gimple_mem_rhs_or_call, > fb_rvalue); > if (ret == GS_ERROR) > return ret; > } > > Or if you want to guess if *to_p will be is_gimple_reg or not after > gimplification, do it just very conservatively and let the more difficult > to predict cases handled worst case by forcing something into a temporary > with the above code. > > Jakub
diff --git a/gcc/gimplify.c b/gcc/gimplify.c index ae8b4fc..5d51d64 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -3802,12 +3802,45 @@ gimplify_init_ctor_eval (tree object, vec<constructor_elt, va_gc> *elts, } } +/* Return true if LHS will satisfy is_gimple_reg after gimplification. */ + +static bool +will_be_gimple_reg (tree lhs) +{ + while (true) + switch (TREE_CODE (lhs)) + { + case COMPOUND_EXPR: + lhs = TREE_OPERAND (lhs, 1); + break; + + case INIT_EXPR: + case MODIFY_EXPR: + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + lhs = TREE_OPERAND (lhs, 0); + break; + + case VAR_DECL: + case PARM_DECL: + case RESULT_DECL: + if (DECL_HAS_VALUE_EXPR_P (lhs)) + { + lhs = DECL_VALUE_EXPR (lhs); + break; + } + /* else fall through. */ + default: + return is_gimple_reg (lhs); + } +} + /* Return the appropriate RHS predicate for this LHS. */ 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) diff --git a/gcc/testsuite/g++.dg/cpp1z/eval-order3.C b/gcc/testsuite/g++.dg/cpp1z/eval-order3.C index 15df903..d351219 100644 --- a/gcc/testsuite/g++.dg/cpp1z/eval-order3.C +++ b/gcc/testsuite/g++.dg/cpp1z/eval-order3.C @@ -84,7 +84,7 @@ template <class T> void f() // b @= a aref(19)=A(18); - //iref(21)=f(20); + iref(21)=f(20); aref(23)+=f(22); last = 0; @@ -123,7 +123,7 @@ void g() // b @= a aref(19)=A(18); - //iref(21)=f(20); + iref(21)=f(20); aref(23)+=f(22); last = 0;