diff mbox

RFC: PATCH to genericize C++ loops to LOOP_EXPR instead of gotos

Message ID 54683066.40704@redhat.com
State New
Headers show

Commit Message

Jason Merrill Nov. 16, 2014, 5:04 a.m. UTC
I've had a TODO in genericize_cp_loop for a long time suggesting that we 
should genericize to LOOP_EXPR rather than gotos, and now that I need to 
interpret the function body for constexpr evaluation, making this change 
will also simplify that handling.

This change also does away with canonicalizing the condition to the 
bottom of the loop, to avoid the extra goto.  It seems to me that this 
is unnecessary nowadays, since the optimizers are very capable of making 
any necessary transformations, but I'm interested in feedback from other 
people.

Tested x86_64-pc-linux-gnu.

Opinions?

Comments

Richard Biener Nov. 17, 2014, 10:26 a.m. UTC | #1
On Sun, Nov 16, 2014 at 6:04 AM, Jason Merrill <jason@redhat.com> wrote:
> I've had a TODO in genericize_cp_loop for a long time suggesting that we
> should genericize to LOOP_EXPR rather than gotos, and now that I need to
> interpret the function body for constexpr evaluation, making this change
> will also simplify that handling.
>
> This change also does away with canonicalizing the condition to the bottom
> of the loop, to avoid the extra goto.  It seems to me that this is
> unnecessary nowadays, since the optimizers are very capable of making any
> necessary transformations, but I'm interested in feedback from other people.
>
> Tested x86_64-pc-linux-gnu.
>
> Opinions?

Lowering less is always nice though I didn't even know GENERIC has
LOOP_EXPR...

Fortran seems to use it though.

Did you inspect generated code for a few testcases?

Thanks,
Richard.
Jason Merrill Nov. 17, 2014, 3:25 p.m. UTC | #2
On 11/17/2014 05:26 AM, Richard Biener wrote:
> Did you inspect generated code for a few testcases?

The generated code for g++.dg/torture/pr37922.C is pretty different at 
-O2, but it's hard for me to tell whether the changes are good, bad, or 
neutral.

Jason
Richard Biener Nov. 17, 2014, 3:27 p.m. UTC | #3
On Mon, Nov 17, 2014 at 4:25 PM, Jason Merrill <jason@redhat.com> wrote:
> On 11/17/2014 05:26 AM, Richard Biener wrote:
>>
>> Did you inspect generated code for a few testcases?
>
>
> The generated code for g++.dg/torture/pr37922.C is pretty different at -O2,
> but it's hard for me to tell whether the changes are good, bad, or neutral.

There is always the possibility of running the C++ portion of SPEC CPU 2006...

Richard.

> Jason
>
Jason Merrill Nov. 17, 2014, 6:21 p.m. UTC | #4
On 11/17/2014 10:27 AM, Richard Biener wrote:
>> The generated code for g++.dg/torture/pr37922.C is pretty different at -O2,
>> but it's hard for me to tell whether the changes are good, bad, or neutral.
>
> There is always the possibility of running the C++ portion of SPEC CPU 2006...

I ran the tramp3d benchmark over 500 iterations before and after the 
change and couldn't see any measurable difference in runtime.  The 
binary with my change was 0.4% smaller.

I'm going to go ahead and check it in; if a performance hit shows up on 
the automated testing we can revisit the choice.
diff mbox

Patch

commit 1a45860e7757ee054f6bf98bee4ebe5c661dfb90
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Nov 13 23:54:48 2014 -0500

    	* cp-gimplify.c (genericize_cp_loop): Use LOOP_EXPR.
    	(genericize_for_stmt): Handle null statement-list.

diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index e5436bb..81b26d2 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -208,7 +208,7 @@  genericize_cp_loop (tree *stmt_p, location_t start_locus, tree cond, tree body,
 		    void *data)
 {
   tree blab, clab;
-  tree entry = NULL, exit = NULL, t;
+  tree exit = NULL;
   tree stmt_list = NULL;
 
   blab = begin_bc_block (bc_break, start_locus);
@@ -222,64 +222,46 @@  genericize_cp_loop (tree *stmt_p, location_t start_locus, tree cond, tree body,
   cp_walk_tree (&incr, cp_genericize_r, data, NULL);
   *walk_subtrees = 0;
 
-  /* If condition is zero don't generate a loop construct.  */
-  if (cond && integer_zerop (cond))
+  if (cond && TREE_CODE (cond) != INTEGER_CST)
     {
-      if (cond_is_first)
-	{
-	  t = build1_loc (start_locus, GOTO_EXPR, void_type_node,
-			  get_bc_label (bc_break));
-	  append_to_statement_list (t, &stmt_list);
-	}
-    }
-  else
-    {
-      /* Expand to gotos, just like c_finish_loop.  TODO: Use LOOP_EXPR.  */
-      tree top = build1 (LABEL_EXPR, void_type_node,
-			 create_artificial_label (start_locus));
-
-      /* If we have an exit condition, then we build an IF with gotos either
-	 out of the loop, or to the top of it.  If there's no exit condition,
-	 then we just build a jump back to the top.  */
-      exit = build1 (GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL (top));
-
-      if (cond && !integer_nonzerop (cond))
-	{
-	  /* Canonicalize the loop condition to the end.  This means
-	     generating a branch to the loop condition.  Reuse the
-	     continue label, if possible.  */
-	  if (cond_is_first)
-	    {
-	      if (incr)
-		{
-		  entry = build1 (LABEL_EXPR, void_type_node,
-				  create_artificial_label (start_locus));
-		  t = build1_loc (start_locus, GOTO_EXPR, void_type_node,
-				  LABEL_EXPR_LABEL (entry));
-		}
-	      else
-		t = build1_loc (start_locus, GOTO_EXPR, void_type_node,
-				get_bc_label (bc_continue));
-	      append_to_statement_list (t, &stmt_list);
-	    }
-
-	  t = build1 (GOTO_EXPR, void_type_node, get_bc_label (bc_break));
-	  exit = fold_build3_loc (start_locus,
-				  COND_EXPR, void_type_node, cond, exit, t);
-	}
-
-      append_to_statement_list (top, &stmt_list);
+      /* If COND is constant, don't bother building an exit.  If it's false,
+	 we won't build a loop.  If it's true, any exits are in the body.  */
+      location_t cloc = EXPR_LOC_OR_LOC (cond, start_locus);
+      exit = build1_loc (cloc, GOTO_EXPR, void_type_node,
+			 get_bc_label (bc_break));
+      exit = fold_build3_loc (cloc, COND_EXPR, void_type_node, cond,
+			      build_empty_stmt (cloc), exit);
     }
 
+  if (exit && cond_is_first)
+    append_to_statement_list (exit, &stmt_list);
   append_to_statement_list (body, &stmt_list);
   finish_bc_block (&stmt_list, bc_continue, clab);
   append_to_statement_list (incr, &stmt_list);
-  append_to_statement_list (entry, &stmt_list);
-  append_to_statement_list (exit, &stmt_list);
+  if (exit && !cond_is_first)
+    append_to_statement_list (exit, &stmt_list);
+
+  if (!stmt_list)
+    stmt_list = build_empty_stmt (start_locus);
+
+  tree loop;
+  if (cond && integer_zerop (cond))
+    {
+      if (cond_is_first)
+	loop = fold_build3_loc (start_locus, COND_EXPR,
+				void_type_node, cond, stmt_list,
+				build_empty_stmt (start_locus));
+      else
+	loop = stmt_list;
+    }
+  else
+    loop = build1_loc (start_locus, LOOP_EXPR, void_type_node, stmt_list);
+
+  stmt_list = NULL;
+  append_to_statement_list (loop, &stmt_list);
   finish_bc_block (&stmt_list, bc_break, blab);
-
-  if (stmt_list == NULL_TREE)
-    stmt_list = build1 (NOP_EXPR, void_type_node, integer_zero_node);
+  if (!stmt_list)
+    stmt_list = build_empty_stmt (start_locus);
 
   *stmt_p = stmt_list;
 }
@@ -303,6 +285,8 @@  genericize_for_stmt (tree *stmt_p, int *walk_subtrees, void *data)
   genericize_cp_loop (&loop, EXPR_LOCATION (stmt), FOR_COND (stmt),
 		      FOR_BODY (stmt), FOR_EXPR (stmt), 1, walk_subtrees, data);
   append_to_statement_list (loop, &expr);
+  if (expr == NULL_TREE)
+    expr = loop;
   *stmt_p = expr;
 }