Patchwork [C,C++] Accept GCC ivdep for 'do' and 'while', and for C++11's range-based loops

login
register
mail settings
Submitter Tobias Burnus
Date Oct. 25, 2013, 8:46 p.m.
Message ID <526AD8A2.2050503@net-b.de>
Download mbox | patch
Permalink /patch/286197/
State New
Headers show

Comments

Tobias Burnus - Oct. 25, 2013, 8:46 p.m.
Tobias Burnus wrote:
> Jason Merrill wrote:
>> I would think that a range-based loop over an array should vectorize
>> nicely:
> [...]
> Therefore, I will send a follow up patch.

Attached is that patch [C++].

[C/C++:] Additionally, as Jakub proposed and other compilers also 
support,  the patch accepts #pragma GCC ivdep for 'do' and 'while' loops.

I did an successful all-language bootstrap followed by successful 
regstesting on x86-64-gnu-linux.
OK for committal?

Tobias
Joseph S. Myers - Oct. 25, 2013, 9:49 p.m.
On Fri, 25 Oct 2013, Tobias Burnus wrote:

> Tobias Burnus wrote:
> > Jason Merrill wrote:
> > > I would think that a range-based loop over an array should vectorize
> > > nicely:
> > [...]
> > Therefore, I will send a follow up patch.
> 
> Attached is that patch [C++].
> 
> [C/C++:] Additionally, as Jakub proposed and other compilers also support,
> the patch accepts #pragma GCC ivdep for 'do' and 'while' loops.

The C front-end changes are OK.
Jason Merrill - Oct. 28, 2013, 12:44 a.m.
On 10/25/2013 04:46 PM, Tobias Burnus wrote:
> +	do_range_for_auto_deduction (range_decl, range_expr); // FIXME:IVDEP

I think in this situation let's set a flag on the RANGE_FOR_STMT so we 
can do ivdep handling at instantiation time.

Jason

Patch

2013-10-25  Tobias Burnus  <burnus@net-b.de>

gcc/c/
	PR other/33426
	* c-parser.c (c_parser_while_statement, c_parser_while_statement,
	c_parser_pragma): Add GCC ivdep support to 'do' and 'while'.
	(c_parser_statement_after_labels): Update calls.

gcc/cp/
	PR other/33426
	* parser.c (cp_parser_for, cp_parser_range_for, cp_convert_range_for,
	cp_parser_iteration_statement, cp_parser_pragma): Add GCC ivdep
	support to 'do' and 'while' and to range-based loops.
	* cp-tree.h (cp_convert_range_for): Update prototype.
	* pt.c (tsubst_expr): Update call.

gcc/testsuite/
	PR other/33426
	* gcc.dg/vect/vect-ivdep-2.c: New.
	* g++.dg/vect/pr33426-ivdep-2.cc: New.
	* g++.dg/vect/pr33426-ivdep-3.cc: New.

diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 4f25078..9ccae3b 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1157,8 +1157,8 @@  static void c_parser_statement (c_parser *);
 static void c_parser_statement_after_labels (c_parser *);
 static void c_parser_if_statement (c_parser *);
 static void c_parser_switch_statement (c_parser *);
-static void c_parser_while_statement (c_parser *);
-static void c_parser_do_statement (c_parser *);
+static void c_parser_while_statement (c_parser *, bool);
+static void c_parser_do_statement (c_parser *, bool);
 static void c_parser_for_statement (c_parser *, bool);
 static tree c_parser_asm_statement (c_parser *);
 static tree c_parser_asm_operands (c_parser *);
@@ -4579,10 +4579,10 @@  c_parser_statement_after_labels (c_parser *parser)
 	  c_parser_switch_statement (parser);
 	  break;
 	case RID_WHILE:
-	  c_parser_while_statement (parser);
+	  c_parser_while_statement (parser, false);
 	  break;
 	case RID_DO:
-	  c_parser_do_statement (parser);
+	  c_parser_do_statement (parser, false);
 	  break;
 	case RID_FOR:
 	  c_parser_for_statement (parser, false);
@@ -4912,7 +4912,7 @@  c_parser_switch_statement (c_parser *parser)
 */
 
 static void
-c_parser_while_statement (c_parser *parser)
+c_parser_while_statement (c_parser *parser, bool ivdep)
 {
   tree block, cond, body, save_break, save_cont;
   location_t loc;
@@ -4927,6 +4927,11 @@  c_parser_while_statement (c_parser *parser)
 		"statement");
       cond = error_mark_node;
     }
+
+  if (ivdep && cond != error_mark_node)
+    cond = build2 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+		   build_int_cst (integer_type_node,
+		   annot_expr_ivdep_kind));
   save_break = c_break_label;
   c_break_label = NULL_TREE;
   save_cont = c_cont_label;
@@ -4945,7 +4950,7 @@  c_parser_while_statement (c_parser *parser)
 */
 
 static void
-c_parser_do_statement (c_parser *parser)
+c_parser_do_statement (c_parser *parser, bool ivdep)
 {
   tree block, cond, body, save_break, save_cont, new_break, new_cont;
   location_t loc;
@@ -4974,7 +4979,10 @@  c_parser_do_statement (c_parser *parser)
 		"do-while statement");
       cond = error_mark_node;
     }
-
+  if (ivdep && cond != error_mark_node)
+    cond = build2 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+		   build_int_cst (integer_type_node,
+		   annot_expr_ivdep_kind));
   if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
     c_parser_skip_to_end_of_block_or_statement (parser);
   c_finish_loop (loc, cond, NULL, body, new_break, new_cont, false);
@@ -9102,12 +9110,19 @@  c_parser_pragma (c_parser *parser, enum pragma_context context)
     case PRAGMA_IVDEP:
       c_parser_consume_pragma (parser);
       c_parser_skip_to_pragma_eol (parser);
-      if (!c_parser_next_token_is_keyword (parser, RID_FOR))
+      if (!c_parser_next_token_is_keyword (parser, RID_FOR)
+	  && !c_parser_next_token_is_keyword (parser, RID_WHILE)
+	  && !c_parser_next_token_is_keyword (parser, RID_DO))
 	{
-	  c_parser_error (parser, "for statement expected");
+	  c_parser_error (parser, "for, while or do statement expected");
 	  return false;
 	}
-      c_parser_for_statement (parser, true);
+      if (c_parser_next_token_is_keyword (parser, RID_FOR))
+	c_parser_for_statement (parser, true);
+      else if (c_parser_next_token_is_keyword (parser, RID_WHILE))
+	c_parser_while_statement (parser, true);
+      else
+	c_parser_do_statement (parser, true);
       return false;
 
     case PRAGMA_GCC_PCH_PREPROCESS:
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 507b389..692d3cc 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4321,7 +4321,7 @@  extern int comparing_specializations;
    sizeof can be nested.  */
 
 extern int cp_unevaluated_operand;
-extern tree cp_convert_range_for (tree, tree, tree);
+extern tree cp_convert_range_for (tree, tree, tree, bool);
 extern bool parsing_nsdmi (void);
 
 /* in pt.c  */
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 8deffc3..9cb260d 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -1978,7 +1978,7 @@  static tree cp_parser_for
 static tree cp_parser_c_for
   (cp_parser *, tree, tree, bool);
 static tree cp_parser_range_for
-  (cp_parser *, tree, tree, tree);
+  (cp_parser *, tree, tree, tree, bool);
 static void do_range_for_auto_deduction
   (tree, tree);
 static tree cp_parser_perform_range_for_lookup
@@ -9904,7 +9904,7 @@  cp_parser_for (cp_parser *parser, bool ivdep)
   is_range_for = cp_parser_for_init_statement (parser, &decl);
 
   if (is_range_for)
-    return cp_parser_range_for (parser, scope, init, decl);
+    return cp_parser_range_for (parser, scope, init, decl, ivdep);
   else
     return cp_parser_c_for (parser, scope, init, ivdep);
 }
@@ -9960,7 +9960,8 @@  cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep)
   regular FOR_STMT.  */
 
 static tree
-cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl)
+cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl,
+		     bool ivdep)
 {
   tree stmt, range_expr;
 
@@ -9983,12 +9984,12 @@  cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl)
       if (!type_dependent_expression_p (range_expr)
 	  /* do_auto_deduction doesn't mess with template init-lists.  */
 	  && !BRACE_ENCLOSED_INITIALIZER_P (range_expr))
-	do_range_for_auto_deduction (range_decl, range_expr);
+	do_range_for_auto_deduction (range_decl, range_expr); // FIXME:IVDEP
     }
   else
     {
       stmt = begin_for_stmt (scope, init);
-      stmt = cp_convert_range_for (stmt, range_decl, range_expr);
+      stmt = cp_convert_range_for (stmt, range_decl, range_expr, ivdep);
     }
   return stmt;
 }
@@ -10079,7 +10080,8 @@  do_range_for_auto_deduction (tree decl, tree range_expr)
    namespace.  */
 
 tree
-cp_convert_range_for (tree statement, tree range_decl, tree range_expr)
+cp_convert_range_for (tree statement, tree range_decl, tree range_expr,
+		      bool ivdep)
 {
   tree begin, end;
   tree iter_type, begin_expr, end_expr;
@@ -10136,6 +10138,10 @@  cp_convert_range_for (tree statement, tree range_decl, tree range_expr)
 				 begin, ERROR_MARK,
 				 end, ERROR_MARK,
 				 NULL, tf_warning_or_error);
+  if (ivdep)
+    condition = build2 (ANNOTATE_EXPR, TREE_TYPE (condition), condition,
+			build_int_cst (integer_type_node,
+				       annot_expr_ivdep_kind));
   finish_for_cond (condition, statement);
 
   /* The new increment expression.  */
@@ -10329,6 +10335,10 @@  cp_parser_iteration_statement (cp_parser* parser, bool ivdep)
 	cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
 	/* Parse the condition.  */
 	condition = cp_parser_condition (parser);
+	if (ivdep)
+	  condition = build2 (ANNOTATE_EXPR, TREE_TYPE (condition), condition,
+			      build_int_cst (integer_type_node,
+					     annot_expr_ivdep_kind));
 	finish_while_stmt_cond (condition, statement);
 	/* Look for the `)'.  */
 	cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
@@ -10359,6 +10369,11 @@  cp_parser_iteration_statement (cp_parser* parser, bool ivdep)
 	/* Parse the expression.  */
 	expression = cp_parser_expression (parser, /*cast_p=*/false, NULL);
 	/* We're done with the do-statement.  */
+	if (ivdep)
+	  expression = build2 (ANNOTATE_EXPR, TREE_TYPE (expression),
+			       expression,
+			       build_int_cst (integer_type_node,
+					      annot_expr_ivdep_kind));
 	finish_do_stmt (expression, statement);
 	/* Look for the `)'.  */
 	cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
@@ -30926,9 +30941,11 @@  cp_parser_pragma (cp_parser *parser, enum pragma_context context)
 	cp_parser_skip_to_pragma_eol (parser, pragma_tok);
 	cp_token *tok;
 	tok = cp_lexer_peek_token (the_parser->lexer);
-	if (tok->type != CPP_KEYWORD || tok->keyword != RID_FOR)
+	if (tok->type != CPP_KEYWORD
+	    || (tok->keyword != RID_FOR && tok->keyword != RID_WHILE
+		&& tok->keyword != RID_DO))
 	  {
-	    cp_parser_error (parser, "for statement expected");
+	    cp_parser_error (parser, "for, while or do statement expected");
 	    return false;
 	  }
 	cp_parser_iteration_statement (parser, true);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 224be8b..6a15b81 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -13333,7 +13333,7 @@  tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
         decl = tsubst (decl, args, complain, in_decl);
         maybe_push_decl (decl);
         expr = RECUR (RANGE_FOR_EXPR (t));
-        stmt = cp_convert_range_for (stmt, decl, expr);
+        stmt = cp_convert_range_for (stmt, decl, expr, false);
         RECUR (RANGE_FOR_BODY (t));
         finish_for_stmt (stmt);
       }
diff --git a/gcc/testsuite/g++.dg/vect/pr33426-ivdep-2.cc b/gcc/testsuite/g++.dg/vect/pr33426-ivdep-2.cc
new file mode 100644
index 0000000..de9097a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/vect/pr33426-ivdep-2.cc
@@ -0,0 +1,34 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_float } */
+/* { dg-additional-options "-O3 -fopt-info-vec-optimized" } */
+
+/* PR other/33426 */
+/* Testing whether #pragma ivdep is working.  */
+
+void foo(int n, int *a, int *b, int *c) {
+  int i;
+ i = 0;
+#pragma GCC ivdep
+  while(i < n)
+    {
+      a[i] = b[i] + c[i];
+      ++i;
+    }
+}
+
+void bar(int n, int *a, int *b, int *c) {
+  int i;
+ i = 0;
+#pragma GCC ivdep
+  do
+    {
+      a[i] = b[i] + c[i];
+      ++i;
+    }
+  while(i < n);
+}
+
+/* { dg-message "loop vectorized" "" { target *-*-* } 0 } */
+/* { dg-bogus " version" "" { target *-*-* } 0 } */
+/* { dg-bogus " alias" "" { target *-*-* } 0 } */
+/* { dg-final { cleanup-tree-dump "vect" } } */
diff --git a/gcc/testsuite/g++.dg/vect/pr33426-ivdep-3.cc b/gcc/testsuite/g++.dg/vect/pr33426-ivdep-3.cc
new file mode 100644
index 0000000..0317516
--- /dev/null
+++ b/gcc/testsuite/g++.dg/vect/pr33426-ivdep-3.cc
@@ -0,0 +1,20 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_float } */
+/* { dg-additional-options "-std=c++11 -O3 -fopt-info-vec-optimized" } */
+
+/* PR other/33426 */
+/* Testing whether #pragma ivdep is working.  */
+
+int ar[100];
+
+void foo(int *a) {
+#pragma GCC ivdep
+  for (auto &i : ar) {
+    i *= *a;
+  }
+}
+
+/* { dg-message "loop vectorized" "" { target *-*-* } 0 } */
+/* { dg-bogus " version" "" { target *-*-* } 0 } */
+/* { dg-bogus " alias" "" { target *-*-* } 0 } */
+/* { dg-final { cleanup-tree-dump "vect" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-ivdep-2.c b/gcc/testsuite/gcc.dg/vect/vect-ivdep-2.c
new file mode 100644
index 0000000..ff9cb20
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-ivdep-2.c
@@ -0,0 +1,35 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_float } */
+/* { dg-additional-options "-O3 -fopt-info-vec-optimized" } */
+
+/* PR other/33426 */
+/* Testing whether #pragma ivdep is working.  */
+
+void foo(int n, int *a, int *b, int *c) {
+  int i;
+ i = 0;
+#pragma GCC ivdep
+  while(i < n)
+    {
+      a[i] = b[i] + c[i];
+      ++i;
+    }
+}
+
+void bar(int n, int *a, int *b, int *c) {
+  int i;
+ i = 0;
+#pragma GCC ivdep
+  do
+    {
+      a[i] = b[i] + c[i];
+      ++i;
+    }
+  while(i < n);
+}
+
+
+/* { dg-message "loop vectorized" "" { target *-*-* } 0 } */
+/* { dg-bogus " version" "" { target *-*-* } 0 } */
+/* { dg-bogus " alias" "" { target *-*-* } 0 } */
+/* { dg-final { cleanup-tree-dump "vect" } } */