public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* C PATCH to kill c_save_expr or towards delayed folding for the C FE
@ 2017-05-12 19:48 Marek Polacek
  2017-05-12 19:51 ` Jakub Jelinek
  2017-05-12 21:20 ` Joseph Myers
  0 siblings, 2 replies; 8+ messages in thread
From: Marek Polacek @ 2017-05-12 19:48 UTC (permalink / raw)
  To: GCC Patches, Joseph Myers, Jakub Jelinek

[ This patch depends on my previous patch that removes the fold call from
  save_expr. ]

In the effort of reducing early folding, we should avoid calling c_fully_fold
blithely, except when needed for e.g. initializers.  This is a teeny tiny step
down that path.  This patch does away with c_save_expr, which always fully
folded the expression.  Instead, I moved the SAVE_EXPR folding to c_fully_fold.
The new flag SAVE_EXPR_FOLDED_P ensures we only fold the contents once.  Also,
if the contents of the SAVE_EXPR are tree_invariant_p, we don't have to wrap
the expression with SAVE_EXPR.  I wonder if I should instead introduce a hash
map, much like C++; if we fold the contents of a SAVE_EXPR to an invariant, I
think we'll fold the expression multiple times, because in that case we cannot
check the SAVE_EXPR_FOLDED_P flag.

Comments/future directions very much appreciated.

Bootstrapped/regtested on x86_64-linux, ok for trunk once the other patch makes
it in?

2017-05-12  Marek Polacek  <polacek@redhat.com>

	* c-common.c (c_save_expr): Remove.
	(c_common_truthvalue_conversion): Remove a call to c_save_expr.
	* c-common.h (c_save_expr): Remove declaration.

	* c-convert.c (convert): Replace c_save_expr with save_expr.  Don't
	call c_fully_fold.
	* c-decl.c (grokdeclarator): Replace c_save_expr with save_expr. 
	* c-fold.c (c_fully_fold_internal): Handle SAVE_EXPR.
	* c-parser.c (c_parser_declaration_or_fndef): Replace c_save_expr with
	save_expr.
	(c_parser_conditional_expression): Likewise.
	* c-tree.h (SAVE_EXPR_FOLDED_P): Define.
	* c-typeck.c (build_modify_expr): Replace c_save_expr with save_expr.
	(process_init_element): Likewise.
	(build_binary_op): Likewise.
	(handle_omp_array_sections_1): Likewise.

diff --git gcc/c-family/c-common.c gcc/c-family/c-common.c
index ad686d2..f606e94 100644
--- gcc/c-family/c-common.c
+++ gcc/c-family/c-common.c
@@ -3164,24 +3164,6 @@ c_wrap_maybe_const (tree expr, bool non_const)
   return expr;
 }
 
-/* Wrap a SAVE_EXPR around EXPR, if appropriate.  Like save_expr, but
-   for C folds the inside expression and wraps a C_MAYBE_CONST_EXPR
-   around the SAVE_EXPR if needed so that c_fully_fold does not need
-   to look inside SAVE_EXPRs.  */
-
-tree
-c_save_expr (tree expr)
-{
-  bool maybe_const = true;
-  if (c_dialect_cxx ())
-    return save_expr (expr);
-  expr = c_fully_fold (expr, false, &maybe_const);
-  expr = save_expr (expr);
-  if (!maybe_const)
-    expr = c_wrap_maybe_const (expr, true);
-  return expr;
-}
-
 /* Return whether EXPR is a declaration whose address can never be
    NULL.  */
 
@@ -3436,7 +3418,7 @@ c_common_truthvalue_conversion (location_t location, tree expr)
 
   if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE)
     {
-      tree t = (in_late_binary_op ? save_expr (expr) : c_save_expr (expr));
+      tree t = save_expr (expr);
       expr = (build_binary_op
 	      (EXPR_LOCATION (expr),
 	       (TREE_SIDE_EFFECTS (expr)
diff --git gcc/c-family/c-common.h gcc/c-family/c-common.h
index 9e3982d..3981544 100644
--- gcc/c-family/c-common.h
+++ gcc/c-family/c-common.h
@@ -836,7 +836,6 @@ extern enum conversion_safety unsafe_conversion_p (location_t, tree, tree,
 extern bool decl_with_nonnull_addr_p (const_tree);
 extern tree c_fully_fold (tree, bool, bool *);
 extern tree c_wrap_maybe_const (tree, bool);
-extern tree c_save_expr (tree);
 extern tree c_common_truthvalue_conversion (location_t, tree);
 extern void c_apply_type_quals_to_decl (int, tree);
 extern tree c_sizeof_or_alignof_type (location_t, tree, bool, bool, int);
diff --git gcc/c/c-convert.c gcc/c/c-convert.c
index 163feff..a7764f0 100644
--- gcc/c/c-convert.c
+++ gcc/c/c-convert.c
@@ -111,13 +111,7 @@ convert (tree type, tree expr)
 	  && COMPLETE_TYPE_P (type)
 	  && do_ubsan_in_current_function ())
 	{
-	  if (in_late_binary_op)
-	    expr = save_expr (expr);
-	  else
-	    {
-	      expr = c_save_expr (expr);
-	      expr = c_fully_fold (expr, false, NULL);
-	    }
+	  expr = save_expr (expr);
 	  tree check = ubsan_instrument_float_cast (loc, type, expr);
 	  expr = fold_build1 (FIX_TRUNC_EXPR, type, expr);
 	  if (check == NULL_TREE)
@@ -146,8 +140,7 @@ convert (tree type, tree expr)
 
     case COMPLEX_TYPE:
       /* If converting from COMPLEX_TYPE to a different COMPLEX_TYPE
-	 and e is not COMPLEX_EXPR, convert_to_complex uses save_expr,
-	 but for the C FE c_save_expr needs to be called instead.  */
+	 and E is not COMPLEX_EXPR, convert_to_complex uses save_expr.  */
       if (TREE_CODE (TREE_TYPE (e)) == COMPLEX_TYPE)
 	{
 	  if (TREE_CODE (e) != COMPLEX_EXPR)
@@ -155,10 +148,7 @@ convert (tree type, tree expr)
 	      tree subtype = TREE_TYPE (type);
 	      tree elt_type = TREE_TYPE (TREE_TYPE (e));
 
-	      if (in_late_binary_op)
-		e = save_expr (e);
-	      else
-		e = c_save_expr (e);
+	      e = save_expr (e);
 	      ret
 		= fold_build2_loc (loc, COMPLEX_EXPR, type,
 				   convert (subtype,
diff --git gcc/c/c-decl.c gcc/c/c-decl.c
index b779d37..8ae09c4 100644
--- gcc/c/c-decl.c
+++ gcc/c/c-decl.c
@@ -6076,7 +6076,7 @@ grokdeclarator (const struct c_declarator *declarator,
 			&& do_ubsan_in_current_function ())
 		      {
 			/* Evaluate the array size only once.  */
-			size = c_save_expr (size);
+			size = save_expr (size);
 			size = c_fully_fold (size, false, NULL);
 		        size = fold_build2 (COMPOUND_EXPR, TREE_TYPE (size),
 					    ubsan_instrument_vla (loc, size),
diff --git gcc/c/c-fold.c gcc/c/c-fold.c
index b060d76..1baee44 100644
--- gcc/c/c-fold.c
+++ gcc/c/c-fold.c
@@ -120,12 +120,11 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
   bool unused_p;
   source_range old_range;
 
-  /* Constants, declarations, statements, errors, SAVE_EXPRs and
-     anything else not counted as an expression cannot usefully be
-     folded further at this point.  */
+  /* Constants, declarations, statements, errors, and anything else not
+     counted as an expression cannot usefully be folded further at this
+     point.  */
   if (!IS_EXPR_CODE_CLASS (kind)
-      || kind == tcc_statement
-      || code == SAVE_EXPR)
+      || kind == tcc_statement)
     return expr;
 
   if (IS_EXPR_CODE_CLASS (kind))
@@ -565,6 +564,25 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
 	 appropriate in any particular case.  */
       gcc_unreachable ();
 
+    case SAVE_EXPR:
+      /* Make sure to fold the contents of a SAVE_EXPR exactly once.  */
+      if (!SAVE_EXPR_FOLDED_P (expr))
+	{
+	  op0 = TREE_OPERAND (expr, 0);
+	  op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
+				       maybe_const_itself, for_int_const);
+	  /* Don't wrap the folded tree in a SAVE_EXPR if we don't
+	     have to.  */
+	  if (tree_invariant_p (op0))
+	    ret = op0;
+	  else
+	    {
+	      TREE_OPERAND (expr, 0) = op0;
+	      SAVE_EXPR_FOLDED_P (expr) = true;
+	    }
+	}
+      goto out;
+
     default:
       /* Various codes may appear through folding built-in functions
 	 and their arguments.  */
diff --git gcc/c/c-parser.c gcc/c/c-parser.c
index 90d2d17..96c0749 100644
--- gcc/c/c-parser.c
+++ gcc/c/c-parser.c
@@ -1880,7 +1880,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 		  bool vm_type = variably_modified_type_p (init_type,
 							   NULL_TREE);
 		  if (vm_type)
-		    init.value = c_save_expr (init.value);
+		    init.value = save_expr (init.value);
 		  finish_init ();
 		  specs->typespec_kind = ctsk_typeof;
 		  specs->locations[cdw_typedef] = init_loc;
@@ -6500,7 +6500,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after,
 	e = TREE_OPERAND (e, 1);
       warn_for_omitted_condop (middle_loc, e);
       /* Make sure first operand is calculated only once.  */
-      exp1.value = c_save_expr (default_conversion (cond.value));
+      exp1.value = save_expr (default_conversion (cond.value));
       if (eptype)
 	exp1.value = build1 (EXCESS_PRECISION_EXPR, eptype, exp1.value);
       exp1.original_type = NULL;
diff --git gcc/c/c-tree.h gcc/c/c-tree.h
index 8d232a4..a27a2c7 100644
--- gcc/c/c-tree.h
+++ gcc/c/c-tree.h
@@ -113,6 +113,10 @@ along with GCC; see the file COPYING3.  If not see
    subexpression meaning it is not a constant expression.  */
 #define CONSTRUCTOR_NON_CONST(EXPR) TREE_LANG_FLAG_1 (CONSTRUCTOR_CHECK (EXPR))
 
+/* For a SAVE_EXPR, nonzero if the contents of the SAVE_EXPR have already
+   been folded.  */
+#define SAVE_EXPR_FOLDED_P(EXP)	TREE_LANG_FLAG_1 (SAVE_EXPR_CHECK (EXP))
+
 /* Record parser information about an expression that is irrelevant
    for code generation alongside a tree representing its value.  */
 struct c_expr
diff --git gcc/c/c-typeck.c gcc/c/c-typeck.c
index 6f9909c..1edf521 100644
--- gcc/c/c-typeck.c
+++ gcc/c/c-typeck.c
@@ -5777,7 +5777,7 @@ build_modify_expr (location_t location, tree lhs, tree lhs_origtype,
 	     that modify LHS.  */
 	  if (TREE_SIDE_EFFECTS (rhs))
 	    {
-	      newrhs = in_late_binary_op ? save_expr (rhs) : c_save_expr (rhs);
+	      newrhs = save_expr (rhs);
 	      rhseval = newrhs;
 	    }
 	  newrhs = build_binary_op (location,
@@ -9301,7 +9301,7 @@ process_init_element (location_t loc, struct c_expr value, bool implicit,
 	      semantic_type = TREE_TYPE (value.value);
 	      value.value = TREE_OPERAND (value.value, 0);
 	    }
-	  value.value = c_save_expr (value.value);
+	  value.value = save_expr (value.value);
 	  if (semantic_type)
 	    value.value = build1 (EXCESS_PRECISION_EXPR, semantic_type,
 				  value.value);
@@ -11621,7 +11621,7 @@ build_binary_op (location_t location, enum tree_code code,
 	    return error_mark_node;
 	  if (first_complex)
 	    {
-	      op0 = c_save_expr (op0);
+	      op0 = save_expr (op0);
 	      real = build_unary_op (EXPR_LOCATION (orig_op0), REALPART_EXPR,
 				     op0, true);
 	      imag = build_unary_op (EXPR_LOCATION (orig_op0), IMAGPART_EXPR,
@@ -11630,7 +11630,7 @@ build_binary_op (location_t location, enum tree_code code,
 		{
 		case MULT_EXPR:
 		case TRUNC_DIV_EXPR:
-		  op1 = c_save_expr (op1);
+		  op1 = save_expr (op1);
 		  imag = build2 (resultcode, real_type, imag, op1);
 		  /* Fall through.  */
 		case PLUS_EXPR:
@@ -11643,7 +11643,7 @@ build_binary_op (location_t location, enum tree_code code,
 	    }
 	  else
 	    {
-	      op1 = c_save_expr (op1);
+	      op1 = save_expr (op1);
 	      real = build_unary_op (EXPR_LOCATION (orig_op1), REALPART_EXPR,
 				     op1, true);
 	      imag = build_unary_op (EXPR_LOCATION (orig_op1), IMAGPART_EXPR,
@@ -11651,7 +11651,7 @@ build_binary_op (location_t location, enum tree_code code,
 	      switch (code)
 		{
 		case MULT_EXPR:
-		  op0 = c_save_expr (op0);
+		  op0 = save_expr (op0);
 		  imag = build2 (resultcode, real_type, op0, imag);
 		  /* Fall through.  */
 		case PLUS_EXPR:
@@ -11835,8 +11835,8 @@ build_binary_op (location_t location, enum tree_code code,
       && !require_constant_value)
     {
       /* OP0 and/or OP1 might have side-effects.  */
-      op0 = c_save_expr (op0);
-      op1 = c_save_expr (op1);
+      op0 = save_expr (op0);
+      op1 = save_expr (op1);
       op0 = c_fully_fold (op0, false, NULL);
       op1 = c_fully_fold (op1, false, NULL);
       if (doing_div_or_mod && (flag_sanitize & (SANITIZE_DIVIDE
@@ -12435,7 +12435,7 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
       /* For [lb:] we will need to evaluate lb more than once.  */
       if (length == NULL_TREE && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND)
 	{
-	  tree lb = c_save_expr (low_bound);
+	  tree lb = save_expr (low_bound);
 	  if (lb != low_bound)
 	    {
 	      TREE_PURPOSE (t) = lb;
@@ -12480,7 +12480,7 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
   if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND)
     types.safe_push (TREE_TYPE (ret));
   /* We will need to evaluate lb more than once.  */
-  tree lb = c_save_expr (low_bound);
+  tree lb = save_expr (low_bound);
   if (lb != low_bound)
     {
       TREE_PURPOSE (t) = lb;

	Marek

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: C PATCH to kill c_save_expr or towards delayed folding for the C FE
  2017-05-12 19:48 C PATCH to kill c_save_expr or towards delayed folding for the C FE Marek Polacek
@ 2017-05-12 19:51 ` Jakub Jelinek
  2017-05-15  9:52   ` Marek Polacek
  2017-05-22 19:38   ` [committed] " Jakub Jelinek
  2017-05-12 21:20 ` Joseph Myers
  1 sibling, 2 replies; 8+ messages in thread
From: Jakub Jelinek @ 2017-05-12 19:51 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Joseph Myers

On Fri, May 12, 2017 at 09:37:27PM +0200, Marek Polacek wrote:
> @@ -565,6 +564,25 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
>  	 appropriate in any particular case.  */
>        gcc_unreachable ();
>  
> +    case SAVE_EXPR:
> +      /* Make sure to fold the contents of a SAVE_EXPR exactly once.  */
> +      if (!SAVE_EXPR_FOLDED_P (expr))
> +	{
> +	  op0 = TREE_OPERAND (expr, 0);
> +	  op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
> +				       maybe_const_itself, for_int_const);
> +	  /* Don't wrap the folded tree in a SAVE_EXPR if we don't
> +	     have to.  */
> +	  if (tree_invariant_p (op0))
> +	    ret = op0;
> +	  else
> +	    {
> +	      TREE_OPERAND (expr, 0) = op0;
> +	      SAVE_EXPR_FOLDED_P (expr) = true;
> +	    }
> +	}

Wouldn't it be better to guard with if (!SAVE_EXPR_FOLDED_P (expr))
only c_fully_fold_internal recursion on the operand
and then use if (tree_invariant_p (op0)) unconditionally?

> @@ -113,6 +113,10 @@ along with GCC; see the file COPYING3.  If not see
>     subexpression meaning it is not a constant expression.  */
>  #define CONSTRUCTOR_NON_CONST(EXPR) TREE_LANG_FLAG_1 (CONSTRUCTOR_CHECK (EXPR))
>  
> +/* For a SAVE_EXPR, nonzero if the contents of the SAVE_EXPR have already
> +   been folded.  */

s/contents/operand/;s/have/has/ ?

Otherwise I'm all for this, but would like to give you and Joseph as C FE
maintainers the last word on this.

	Jakub

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: C PATCH to kill c_save_expr or towards delayed folding for the C FE
  2017-05-12 19:48 C PATCH to kill c_save_expr or towards delayed folding for the C FE Marek Polacek
  2017-05-12 19:51 ` Jakub Jelinek
@ 2017-05-12 21:20 ` Joseph Myers
  2017-05-13  7:58   ` Jakub Jelinek
  2017-05-15 14:21   ` Marek Polacek
  1 sibling, 2 replies; 8+ messages in thread
From: Joseph Myers @ 2017-05-12 21:20 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jakub Jelinek

On Fri, 12 May 2017, Marek Polacek wrote:

> In the effort of reducing early folding, we should avoid calling c_fully_fold
> blithely, except when needed for e.g. initializers.  This is a teeny tiny step

Note there are several reasons for early folding in the C front end: at 
least (a) cases where logically needed (initializers and other places 
where constants are needed), (b) because warnings need a folded 
expression, (c) when the expression will go somewhere c_fully_fold does 
not recurse inside.  Also (d) convert, at least, folds regardless of 
whether it's actually necessary.

There is a case for avoiding (b) by putting the necessary information in 
the IR so the warnings can happen later from c_fully_fold, though there 
may be other possible approaches.

> @@ -146,8 +140,7 @@ convert (tree type, tree expr)
>  
>      case COMPLEX_TYPE:
>        /* If converting from COMPLEX_TYPE to a different COMPLEX_TYPE
> -	 and e is not COMPLEX_EXPR, convert_to_complex uses save_expr,
> -	 but for the C FE c_save_expr needs to be called instead.  */
> +	 and E is not COMPLEX_EXPR, convert_to_complex uses save_expr.  */
>        if (TREE_CODE (TREE_TYPE (e)) == COMPLEX_TYPE)
>  	{
>  	  if (TREE_CODE (e) != COMPLEX_EXPR)

The point of this comment is to explain why we don't just call 
convert_to_complex here (see PR 47150).  So with your changes it would 
seem appropriate to change c-convert.c back to calling convert_to_complex 
here.

The changes seem otherwise OK.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: C PATCH to kill c_save_expr or towards delayed folding for the C FE
  2017-05-12 21:20 ` Joseph Myers
@ 2017-05-13  7:58   ` Jakub Jelinek
  2017-05-15 14:21   ` Marek Polacek
  1 sibling, 0 replies; 8+ messages in thread
From: Jakub Jelinek @ 2017-05-13  7:58 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Marek Polacek, GCC Patches

On Fri, May 12, 2017 at 08:28:38PM +0000, Joseph Myers wrote:
> On Fri, 12 May 2017, Marek Polacek wrote:
> 
> > In the effort of reducing early folding, we should avoid calling c_fully_fold
> > blithely, except when needed for e.g. initializers.  This is a teeny tiny step
> 
> Note there are several reasons for early folding in the C front end: at 
> least (a) cases where logically needed (initializers and other places 
> where constants are needed), (b) because warnings need a folded 
> expression, (c) when the expression will go somewhere c_fully_fold does 
> not recurse inside.  Also (d) convert, at least, folds regardless of 
> whether it's actually necessary.

The C++ FE has here a folding cache.  For (a) I think one usually just
performs that once (to fold e.g. the initializer), for (b) one might want
to fold many times, when wanting to test for some warning and then finally
when folding everything (which is where a cache can help, the first time you
fold something for a warning or when folding everything if never fold
something for a warning you cache the result and then just look it up).
(c) we should fix, (d) too, or convert to (b) kind of tests - fold something
in a test to see which path should be taken, but then actually defer
folding till later.

	Jakub

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: C PATCH to kill c_save_expr or towards delayed folding for the C FE
  2017-05-12 19:51 ` Jakub Jelinek
@ 2017-05-15  9:52   ` Marek Polacek
  2017-05-22 19:38   ` [committed] " Jakub Jelinek
  1 sibling, 0 replies; 8+ messages in thread
From: Marek Polacek @ 2017-05-15  9:52 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: GCC Patches, Joseph Myers

On Fri, May 12, 2017 at 09:48:28PM +0200, Jakub Jelinek wrote:
> On Fri, May 12, 2017 at 09:37:27PM +0200, Marek Polacek wrote:
> > @@ -565,6 +564,25 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
> >  	 appropriate in any particular case.  */
> >        gcc_unreachable ();
> >  
> > +    case SAVE_EXPR:
> > +      /* Make sure to fold the contents of a SAVE_EXPR exactly once.  */
> > +      if (!SAVE_EXPR_FOLDED_P (expr))
> > +	{
> > +	  op0 = TREE_OPERAND (expr, 0);
> > +	  op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
> > +				       maybe_const_itself, for_int_const);
> > +	  /* Don't wrap the folded tree in a SAVE_EXPR if we don't
> > +	     have to.  */
> > +	  if (tree_invariant_p (op0))
> > +	    ret = op0;
> > +	  else
> > +	    {
> > +	      TREE_OPERAND (expr, 0) = op0;
> > +	      SAVE_EXPR_FOLDED_P (expr) = true;
> > +	    }
> > +	}
> 
> Wouldn't it be better to guard with if (!SAVE_EXPR_FOLDED_P (expr))
> only c_fully_fold_internal recursion on the operand
> and then use if (tree_invariant_p (op0)) unconditionally?
 
I don't see why that would be better.  It would mean calling tree_invariant_p
on even folded SAVE_EXPRs, and I can't see when it could be true in that case?

> > @@ -113,6 +113,10 @@ along with GCC; see the file COPYING3.  If not see
> >     subexpression meaning it is not a constant expression.  */
> >  #define CONSTRUCTOR_NON_CONST(EXPR) TREE_LANG_FLAG_1 (CONSTRUCTOR_CHECK (EXPR))
> >  
> > +/* For a SAVE_EXPR, nonzero if the contents of the SAVE_EXPR have already
> > +   been folded.  */
> 
> s/contents/operand/;s/have/has/ ?
 
Ok, if you prefer ;).

> Otherwise I'm all for this, but would like to give you and Joseph as C FE
> maintainers the last word on this.

Thanks,

	Marek

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: C PATCH to kill c_save_expr or towards delayed folding for the C FE
  2017-05-12 21:20 ` Joseph Myers
  2017-05-13  7:58   ` Jakub Jelinek
@ 2017-05-15 14:21   ` Marek Polacek
  2017-05-15 14:32     ` Joseph Myers
  1 sibling, 1 reply; 8+ messages in thread
From: Marek Polacek @ 2017-05-15 14:21 UTC (permalink / raw)
  To: Joseph Myers; +Cc: GCC Patches, Jakub Jelinek

On Fri, May 12, 2017 at 08:28:38PM +0000, Joseph Myers wrote:
> On Fri, 12 May 2017, Marek Polacek wrote:
> 
> > In the effort of reducing early folding, we should avoid calling c_fully_fold
> > blithely, except when needed for e.g. initializers.  This is a teeny tiny step
> 
> Note there are several reasons for early folding in the C front end: at 
> least (a) cases where logically needed (initializers and other places 
> where constants are needed), (b) because warnings need a folded 
> expression, (c) when the expression will go somewhere c_fully_fold does 
> not recurse inside.  Also (d) convert, at least, folds regardless of 
> whether it's actually necessary.
> 
> There is a case for avoiding (b) by putting the necessary information in 
> the IR so the warnings can happen later from c_fully_fold, though there 
> may be other possible approaches.
> 
> > @@ -146,8 +140,7 @@ convert (tree type, tree expr)
> >  
> >      case COMPLEX_TYPE:
> >        /* If converting from COMPLEX_TYPE to a different COMPLEX_TYPE
> > -	 and e is not COMPLEX_EXPR, convert_to_complex uses save_expr,
> > -	 but for the C FE c_save_expr needs to be called instead.  */
> > +	 and E is not COMPLEX_EXPR, convert_to_complex uses save_expr.  */
> >        if (TREE_CODE (TREE_TYPE (e)) == COMPLEX_TYPE)
> >  	{
> >  	  if (TREE_CODE (e) != COMPLEX_EXPR)
> 
> The point of this comment is to explain why we don't just call 
> convert_to_complex here (see PR 47150).  So with your changes it would 
> seem appropriate to change c-convert.c back to calling convert_to_complex 
> here.
 
Thanks for pointing this out!  The new version:

Bootstrapped/regtested on x86_64-linux.

2017-05-15  Marek Polacek  <polacek@redhat.com>

	* c-common.c (c_save_expr): Remove.
	(c_common_truthvalue_conversion): Remove a call to c_save_expr.
	* c-common.h (c_save_expr): Remove declaration.

	* c-convert.c (convert): Replace c_save_expr with save_expr.  Don't
	call c_fully_fold.
	(convert) <case COMPLEX_TYPE>: Remove special handling of COMPLEX_TYPEs.
	* c-decl.c (grokdeclarator): Replace c_save_expr with save_expr. 
	* c-fold.c (c_fully_fold_internal): Handle SAVE_EXPR.
	* c-parser.c (c_parser_declaration_or_fndef): Replace c_save_expr with
	save_expr.
	(c_parser_conditional_expression): Likewise.
	* c-tree.h (SAVE_EXPR_FOLDED_P): Define.
	* c-typeck.c (build_modify_expr): Replace c_save_expr with save_expr.
	(process_init_element): Likewise.
	(build_binary_op): Likewise.
	(handle_omp_array_sections_1): Likewise.

diff --git gcc/c-family/c-common.c gcc/c-family/c-common.c
index ad686d2..f606e94 100644
--- gcc/c-family/c-common.c
+++ gcc/c-family/c-common.c
@@ -3164,24 +3164,6 @@ c_wrap_maybe_const (tree expr, bool non_const)
   return expr;
 }
 
-/* Wrap a SAVE_EXPR around EXPR, if appropriate.  Like save_expr, but
-   for C folds the inside expression and wraps a C_MAYBE_CONST_EXPR
-   around the SAVE_EXPR if needed so that c_fully_fold does not need
-   to look inside SAVE_EXPRs.  */
-
-tree
-c_save_expr (tree expr)
-{
-  bool maybe_const = true;
-  if (c_dialect_cxx ())
-    return save_expr (expr);
-  expr = c_fully_fold (expr, false, &maybe_const);
-  expr = save_expr (expr);
-  if (!maybe_const)
-    expr = c_wrap_maybe_const (expr, true);
-  return expr;
-}
-
 /* Return whether EXPR is a declaration whose address can never be
    NULL.  */
 
@@ -3436,7 +3418,7 @@ c_common_truthvalue_conversion (location_t location, tree expr)
 
   if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE)
     {
-      tree t = (in_late_binary_op ? save_expr (expr) : c_save_expr (expr));
+      tree t = save_expr (expr);
       expr = (build_binary_op
 	      (EXPR_LOCATION (expr),
 	       (TREE_SIDE_EFFECTS (expr)
diff --git gcc/c-family/c-common.h gcc/c-family/c-common.h
index 9e3982d..3981544 100644
--- gcc/c-family/c-common.h
+++ gcc/c-family/c-common.h
@@ -836,7 +836,6 @@ extern enum conversion_safety unsafe_conversion_p (location_t, tree, tree,
 extern bool decl_with_nonnull_addr_p (const_tree);
 extern tree c_fully_fold (tree, bool, bool *);
 extern tree c_wrap_maybe_const (tree, bool);
-extern tree c_save_expr (tree);
 extern tree c_common_truthvalue_conversion (location_t, tree);
 extern void c_apply_type_quals_to_decl (int, tree);
 extern tree c_sizeof_or_alignof_type (location_t, tree, bool, bool, int);
diff --git gcc/c/c-convert.c gcc/c/c-convert.c
index 163feff..b8117b4 100644
--- gcc/c/c-convert.c
+++ gcc/c/c-convert.c
@@ -111,13 +111,7 @@ convert (tree type, tree expr)
 	  && COMPLETE_TYPE_P (type)
 	  && do_ubsan_in_current_function ())
 	{
-	  if (in_late_binary_op)
-	    expr = save_expr (expr);
-	  else
-	    {
-	      expr = c_save_expr (expr);
-	      expr = c_fully_fold (expr, false, NULL);
-	    }
+	  expr = save_expr (expr);
 	  tree check = ubsan_instrument_float_cast (loc, type, expr);
 	  expr = fold_build1 (FIX_TRUNC_EXPR, type, expr);
 	  if (check == NULL_TREE)
@@ -145,31 +139,6 @@ convert (tree type, tree expr)
       goto maybe_fold;
 
     case COMPLEX_TYPE:
-      /* If converting from COMPLEX_TYPE to a different COMPLEX_TYPE
-	 and e is not COMPLEX_EXPR, convert_to_complex uses save_expr,
-	 but for the C FE c_save_expr needs to be called instead.  */
-      if (TREE_CODE (TREE_TYPE (e)) == COMPLEX_TYPE)
-	{
-	  if (TREE_CODE (e) != COMPLEX_EXPR)
-	    {
-	      tree subtype = TREE_TYPE (type);
-	      tree elt_type = TREE_TYPE (TREE_TYPE (e));
-
-	      if (in_late_binary_op)
-		e = save_expr (e);
-	      else
-		e = c_save_expr (e);
-	      ret
-		= fold_build2_loc (loc, COMPLEX_EXPR, type,
-				   convert (subtype,
-					    fold_build1 (REALPART_EXPR,
-							 elt_type, e)),
-				   convert (subtype,
-					    fold_build1 (IMAGPART_EXPR,
-							 elt_type, e)));
-	      goto maybe_fold;
-	    }
-	}
       ret = convert_to_complex (type, e);
       goto maybe_fold;
 
diff --git gcc/c/c-decl.c gcc/c/c-decl.c
index b779d37..8ae09c4 100644
--- gcc/c/c-decl.c
+++ gcc/c/c-decl.c
@@ -6076,7 +6076,7 @@ grokdeclarator (const struct c_declarator *declarator,
 			&& do_ubsan_in_current_function ())
 		      {
 			/* Evaluate the array size only once.  */
-			size = c_save_expr (size);
+			size = save_expr (size);
 			size = c_fully_fold (size, false, NULL);
 		        size = fold_build2 (COMPOUND_EXPR, TREE_TYPE (size),
 					    ubsan_instrument_vla (loc, size),
diff --git gcc/c/c-fold.c gcc/c/c-fold.c
index b060d76..1baee44 100644
--- gcc/c/c-fold.c
+++ gcc/c/c-fold.c
@@ -120,12 +120,11 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
   bool unused_p;
   source_range old_range;
 
-  /* Constants, declarations, statements, errors, SAVE_EXPRs and
-     anything else not counted as an expression cannot usefully be
-     folded further at this point.  */
+  /* Constants, declarations, statements, errors, and anything else not
+     counted as an expression cannot usefully be folded further at this
+     point.  */
   if (!IS_EXPR_CODE_CLASS (kind)
-      || kind == tcc_statement
-      || code == SAVE_EXPR)
+      || kind == tcc_statement)
     return expr;
 
   if (IS_EXPR_CODE_CLASS (kind))
@@ -565,6 +564,25 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
 	 appropriate in any particular case.  */
       gcc_unreachable ();
 
+    case SAVE_EXPR:
+      /* Make sure to fold the contents of a SAVE_EXPR exactly once.  */
+      if (!SAVE_EXPR_FOLDED_P (expr))
+	{
+	  op0 = TREE_OPERAND (expr, 0);
+	  op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
+				       maybe_const_itself, for_int_const);
+	  /* Don't wrap the folded tree in a SAVE_EXPR if we don't
+	     have to.  */
+	  if (tree_invariant_p (op0))
+	    ret = op0;
+	  else
+	    {
+	      TREE_OPERAND (expr, 0) = op0;
+	      SAVE_EXPR_FOLDED_P (expr) = true;
+	    }
+	}
+      goto out;
+
     default:
       /* Various codes may appear through folding built-in functions
 	 and their arguments.  */
diff --git gcc/c/c-parser.c gcc/c/c-parser.c
index 90d2d17..96c0749 100644
--- gcc/c/c-parser.c
+++ gcc/c/c-parser.c
@@ -1880,7 +1880,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 		  bool vm_type = variably_modified_type_p (init_type,
 							   NULL_TREE);
 		  if (vm_type)
-		    init.value = c_save_expr (init.value);
+		    init.value = save_expr (init.value);
 		  finish_init ();
 		  specs->typespec_kind = ctsk_typeof;
 		  specs->locations[cdw_typedef] = init_loc;
@@ -6500,7 +6500,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after,
 	e = TREE_OPERAND (e, 1);
       warn_for_omitted_condop (middle_loc, e);
       /* Make sure first operand is calculated only once.  */
-      exp1.value = c_save_expr (default_conversion (cond.value));
+      exp1.value = save_expr (default_conversion (cond.value));
       if (eptype)
 	exp1.value = build1 (EXCESS_PRECISION_EXPR, eptype, exp1.value);
       exp1.original_type = NULL;
diff --git gcc/c/c-tree.h gcc/c/c-tree.h
index 8d232a4..42172f8 100644
--- gcc/c/c-tree.h
+++ gcc/c/c-tree.h
@@ -113,6 +113,10 @@ along with GCC; see the file COPYING3.  If not see
    subexpression meaning it is not a constant expression.  */
 #define CONSTRUCTOR_NON_CONST(EXPR) TREE_LANG_FLAG_1 (CONSTRUCTOR_CHECK (EXPR))
 
+/* For a SAVE_EXPR, nonzero if the operand of the SAVE_EXPR has already
+   been folded.  */
+#define SAVE_EXPR_FOLDED_P(EXP)	TREE_LANG_FLAG_1 (SAVE_EXPR_CHECK (EXP))
+
 /* Record parser information about an expression that is irrelevant
    for code generation alongside a tree representing its value.  */
 struct c_expr
diff --git gcc/c/c-typeck.c gcc/c/c-typeck.c
index 6f9909c..1edf521 100644
--- gcc/c/c-typeck.c
+++ gcc/c/c-typeck.c
@@ -5777,7 +5777,7 @@ build_modify_expr (location_t location, tree lhs, tree lhs_origtype,
 	     that modify LHS.  */
 	  if (TREE_SIDE_EFFECTS (rhs))
 	    {
-	      newrhs = in_late_binary_op ? save_expr (rhs) : c_save_expr (rhs);
+	      newrhs = save_expr (rhs);
 	      rhseval = newrhs;
 	    }
 	  newrhs = build_binary_op (location,
@@ -9301,7 +9301,7 @@ process_init_element (location_t loc, struct c_expr value, bool implicit,
 	      semantic_type = TREE_TYPE (value.value);
 	      value.value = TREE_OPERAND (value.value, 0);
 	    }
-	  value.value = c_save_expr (value.value);
+	  value.value = save_expr (value.value);
 	  if (semantic_type)
 	    value.value = build1 (EXCESS_PRECISION_EXPR, semantic_type,
 				  value.value);
@@ -11621,7 +11621,7 @@ build_binary_op (location_t location, enum tree_code code,
 	    return error_mark_node;
 	  if (first_complex)
 	    {
-	      op0 = c_save_expr (op0);
+	      op0 = save_expr (op0);
 	      real = build_unary_op (EXPR_LOCATION (orig_op0), REALPART_EXPR,
 				     op0, true);
 	      imag = build_unary_op (EXPR_LOCATION (orig_op0), IMAGPART_EXPR,
@@ -11630,7 +11630,7 @@ build_binary_op (location_t location, enum tree_code code,
 		{
 		case MULT_EXPR:
 		case TRUNC_DIV_EXPR:
-		  op1 = c_save_expr (op1);
+		  op1 = save_expr (op1);
 		  imag = build2 (resultcode, real_type, imag, op1);
 		  /* Fall through.  */
 		case PLUS_EXPR:
@@ -11643,7 +11643,7 @@ build_binary_op (location_t location, enum tree_code code,
 	    }
 	  else
 	    {
-	      op1 = c_save_expr (op1);
+	      op1 = save_expr (op1);
 	      real = build_unary_op (EXPR_LOCATION (orig_op1), REALPART_EXPR,
 				     op1, true);
 	      imag = build_unary_op (EXPR_LOCATION (orig_op1), IMAGPART_EXPR,
@@ -11651,7 +11651,7 @@ build_binary_op (location_t location, enum tree_code code,
 	      switch (code)
 		{
 		case MULT_EXPR:
-		  op0 = c_save_expr (op0);
+		  op0 = save_expr (op0);
 		  imag = build2 (resultcode, real_type, op0, imag);
 		  /* Fall through.  */
 		case PLUS_EXPR:
@@ -11835,8 +11835,8 @@ build_binary_op (location_t location, enum tree_code code,
       && !require_constant_value)
     {
       /* OP0 and/or OP1 might have side-effects.  */
-      op0 = c_save_expr (op0);
-      op1 = c_save_expr (op1);
+      op0 = save_expr (op0);
+      op1 = save_expr (op1);
       op0 = c_fully_fold (op0, false, NULL);
       op1 = c_fully_fold (op1, false, NULL);
       if (doing_div_or_mod && (flag_sanitize & (SANITIZE_DIVIDE
@@ -12435,7 +12435,7 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
       /* For [lb:] we will need to evaluate lb more than once.  */
       if (length == NULL_TREE && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND)
 	{
-	  tree lb = c_save_expr (low_bound);
+	  tree lb = save_expr (low_bound);
 	  if (lb != low_bound)
 	    {
 	      TREE_PURPOSE (t) = lb;
@@ -12480,7 +12480,7 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
   if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND)
     types.safe_push (TREE_TYPE (ret));
   /* We will need to evaluate lb more than once.  */
-  tree lb = c_save_expr (low_bound);
+  tree lb = save_expr (low_bound);
   if (lb != low_bound)
     {
       TREE_PURPOSE (t) = lb;

	Marek

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: C PATCH to kill c_save_expr or towards delayed folding for the C FE
  2017-05-15 14:21   ` Marek Polacek
@ 2017-05-15 14:32     ` Joseph Myers
  0 siblings, 0 replies; 8+ messages in thread
From: Joseph Myers @ 2017-05-15 14:32 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jakub Jelinek

On Mon, 15 May 2017, Marek Polacek wrote:

> Thanks for pointing this out!  The new version:
> 
> Bootstrapped/regtested on x86_64-linux.
> 
> 2017-05-15  Marek Polacek  <polacek@redhat.com>
> 
> 	* c-common.c (c_save_expr): Remove.
> 	(c_common_truthvalue_conversion): Remove a call to c_save_expr.
> 	* c-common.h (c_save_expr): Remove declaration.
> 
> 	* c-convert.c (convert): Replace c_save_expr with save_expr.  Don't
> 	call c_fully_fold.
> 	(convert) <case COMPLEX_TYPE>: Remove special handling of COMPLEX_TYPEs.
> 	* c-decl.c (grokdeclarator): Replace c_save_expr with save_expr. 
> 	* c-fold.c (c_fully_fold_internal): Handle SAVE_EXPR.
> 	* c-parser.c (c_parser_declaration_or_fndef): Replace c_save_expr with
> 	save_expr.
> 	(c_parser_conditional_expression): Likewise.
> 	* c-tree.h (SAVE_EXPR_FOLDED_P): Define.
> 	* c-typeck.c (build_modify_expr): Replace c_save_expr with save_expr.
> 	(process_init_element): Likewise.
> 	(build_binary_op): Likewise.
> 	(handle_omp_array_sections_1): Likewise.

This is OK (given the save_expr folding change it depends on).

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [committed] Re: C PATCH to kill c_save_expr or towards delayed folding for the C FE
  2017-05-12 19:51 ` Jakub Jelinek
  2017-05-15  9:52   ` Marek Polacek
@ 2017-05-22 19:38   ` Jakub Jelinek
  1 sibling, 0 replies; 8+ messages in thread
From: Jakub Jelinek @ 2017-05-22 19:38 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Joseph Myers

Hi!

On Fri, May 12, 2017 at 09:48:28PM +0200, Jakub Jelinek wrote:
> On Fri, May 12, 2017 at 09:37:27PM +0200, Marek Polacek wrote:
> > @@ -565,6 +564,25 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
> >  	 appropriate in any particular case.  */
> >        gcc_unreachable ();
> >  
> > +    case SAVE_EXPR:
> > +      /* Make sure to fold the contents of a SAVE_EXPR exactly once.  */
> > +      if (!SAVE_EXPR_FOLDED_P (expr))
> > +	{
> > +	  op0 = TREE_OPERAND (expr, 0);
> > +	  op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
> > +				       maybe_const_itself, for_int_const);
> > +	  /* Don't wrap the folded tree in a SAVE_EXPR if we don't
> > +	     have to.  */
> > +	  if (tree_invariant_p (op0))
> > +	    ret = op0;
> > +	  else
> > +	    {
> > +	      TREE_OPERAND (expr, 0) = op0;
> > +	      SAVE_EXPR_FOLDED_P (expr) = true;
> > +	    }
> > +	}
> 
> Wouldn't it be better to guard with if (!SAVE_EXPR_FOLDED_P (expr))
> only c_fully_fold_internal recursion on the operand
> and then use if (tree_invariant_p (op0)) unconditionally?

After discussions on IRC with Marek, we concluded the above is bad, because
if there is a huge SAVE_EXPR operand that c_fully_fold_internal folds into
an invariant (worse if it contains many other SAVE_EXPRs with such
properties), the current trunk code will fold it over and over again.

Fixed thusly, acked by Marek on IRC, bootstrapped/regtested on x86_64-linux
and i686-linux, committed to trunk.

2017-05-22  Jakub Jelinek  <jakub@redhat.com>

	* c-fold.c (c_fully_fold_internal): Save the c_fully_fold_internal
	result for SAVE_EXPR operand and set SAVE_EXPR_FOLDED_P even if
	it returned invariant.  Call tree_invariant_p unconditionally
	afterwards to decide whether to return expr or op0.

--- gcc/c/c-fold.c	2017-05-22 10:49:38.669161353 +0200
+++ gcc/c/c-fold.c	2017-05-22 18:09:49.358107221 +0200
@@ -566,21 +566,17 @@ c_fully_fold_internal (tree expr, bool i
 
     case SAVE_EXPR:
       /* Make sure to fold the contents of a SAVE_EXPR exactly once.  */
+      op0 = TREE_OPERAND (expr, 0);
       if (!SAVE_EXPR_FOLDED_P (expr))
 	{
-	  op0 = TREE_OPERAND (expr, 0);
 	  op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
 				       maybe_const_itself, for_int_const);
-	  /* Don't wrap the folded tree in a SAVE_EXPR if we don't
-	     have to.  */
-	  if (tree_invariant_p (op0))
-	    ret = op0;
-	  else
-	    {
-	      TREE_OPERAND (expr, 0) = op0;
-	      SAVE_EXPR_FOLDED_P (expr) = true;
-	    }
+	  TREE_OPERAND (expr, 0) = op0;
+	  SAVE_EXPR_FOLDED_P (expr) = true;
 	}
+      /* Return the SAVE_EXPR operand if it is invariant.  */
+      if (tree_invariant_p (op0))
+	ret = op0;
       goto out;
 
     default:


	Jakub

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2017-05-22 19:09 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-12 19:48 C PATCH to kill c_save_expr or towards delayed folding for the C FE Marek Polacek
2017-05-12 19:51 ` Jakub Jelinek
2017-05-15  9:52   ` Marek Polacek
2017-05-22 19:38   ` [committed] " Jakub Jelinek
2017-05-12 21:20 ` Joseph Myers
2017-05-13  7:58   ` Jakub Jelinek
2017-05-15 14:21   ` Marek Polacek
2017-05-15 14:32     ` Joseph Myers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).