diff mbox

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

Message ID 526EDBBA.5030900@net-b.de
State New
Headers show

Commit Message

Tobias Burnus Oct. 28, 2013, 9:48 p.m. UTC
Jason Merrill wrote:
> 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.

I am not completely sure whether you had the following in mind, but 
that's what I have now implemented:
   DEFTREECODE (RANGE_FOR_STMT, "range_for_stmt", tcc_statement, 4)
has now a 5th operator (RANGE_FOR_IVDEP), which has the value 
boolean_true_node - or NULL_TREE (via begin_range_for_stmt).

Additionally, I moved the ivdep annotation to semantics.c as one 
otherwise might get a cleanup_point_expr around the annotate expression, 
which the current algorithm in tree-cfg.c's replace_loop_annotate 
doesn't handle.

Unfortunately, the GCC ivdep annotation doesn't help with 
pr33426-ivdep-4.cc: It still versions the loop with an alias check. But 
that seems to be a middle-end problem as loop->safelen gets set.

I did an all-language bootstrap + regtesting on x86-64-gnu-linux.
Is the patch now OK?

Tobias

Comments

Jason Merrill Oct. 29, 2013, 2:45 p.m. UTC | #1
On 10/28/2013 05:48 PM, Tobias Burnus wrote:
> I am not completely sure whether you had the following in mind, but
> that's what I have now implemented:
>    DEFTREECODE (RANGE_FOR_STMT, "range_for_stmt", tcc_statement, 4)
> has now a 5th operator (RANGE_FOR_IVDEP), which has the value
> boolean_true_node - or NULL_TREE (via begin_range_for_stmt).

You don't need to add an operand, you can use one of the TREE_LANG_FLAGs 
for a boolean flag.

Jason
diff mbox

Patch

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

gcc/cp/
	PR other/33426
	* cp-tree.def (RANGE_FOR_STMT): Add RANGE_FOR_IVDEP flag.
	* cp-tree.h (RANGE_FOR_IVDEP): Define.
	(cp_convert_range_for, finish_while_stmt_cond, finish_do_stmt,
	finish_for_cond): Take 'bool ivdep' parameter.
	* cp-array-notation.c (create_an_loop): Update call.
	* init.c (build_vec_init): Ditto.
	* pt.c (tsubst_expr): Ditto.
	* parser.c (cp_parser_iteration_statement, cp_parser_for,
	cp_parser_range_for, cp_convert_range_for): Update calls.
	(cp_parser_pragma): Accept GCC ivdep for 'while' and 'do'.
	* semantics.c (finish_while_stmt_cond, finish_do_stmt,
	finish_for_cond): Optionally build ivdep annotation.
	(begin_range_for_stmt): Adapt for RANGE_FOR_STMT changes.

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

gcc/
	PR other/33426
	* gcc/tree-cfg.c (replace_loop_annotate): Replace warning by
	warning_at.

diff --git a/gcc/cp/cp-array-notation.c b/gcc/cp/cp-array-notation.c
index c700f58..e1fb0ee 100644
--- a/gcc/cp/cp-array-notation.c
+++ b/gcc/cp/cp-array-notation.c
@@ -71,7 +71,7 @@  create_an_loop (tree init, tree cond, tree incr, tree body)
   finish_expr_stmt (init);
   for_stmt = begin_for_stmt (NULL_TREE, NULL_TREE);
   finish_for_init_stmt (for_stmt);
-  finish_for_cond (cond, for_stmt);
+  finish_for_cond (cond, for_stmt, false);
   finish_for_expr (incr, for_stmt);
   finish_expr_stmt (body);
   finish_for_stmt (for_stmt);
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index bd9bfa8..93355b5 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -299,9 +299,9 @@  DEFTREECODE (IF_STMT, "if_stmt", tcc_statement, 4)
 DEFTREECODE (FOR_STMT, "for_stmt", tcc_statement, 5)
 
 /* Used to represent a range-based `for' statement. The operands are
-   RANGE_FOR_DECL, RANGE_FOR_EXPR, RANGE_FOR_BODY, and RANGE_FOR_SCOPE,
-   respectively.  Only used in templates.  */
-DEFTREECODE (RANGE_FOR_STMT, "range_for_stmt", tcc_statement, 4)
+   RANGE_FOR_DECL, RANGE_FOR_EXPR, RANGE_FOR_BODY, RANGE_FOR_SCOPE,
+   and RANGE_FOR_IVDEP, respectively.  Only used in templates.  */
+DEFTREECODE (RANGE_FOR_STMT, "range_for_stmt", tcc_statement, 5)
 
 /* Used to represent a 'while' statement. The operands are WHILE_COND
    and WHILE_BODY, respectively.  */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 507b389..0d3bc70 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4088,6 +4088,7 @@  more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
 #define RANGE_FOR_EXPR(NODE)	TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 1)
 #define RANGE_FOR_BODY(NODE)	TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 2)
 #define RANGE_FOR_SCOPE(NODE)	TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 3)
+#define RANGE_FOR_IVDEP(NODE)	TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 4)
 
 #define SWITCH_STMT_COND(NODE)	TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 0)
 #define SWITCH_STMT_BODY(NODE)	TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 1)
@@ -4321,7 +4322,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  */
@@ -5671,16 +5672,16 @@  extern void begin_else_clause			(tree);
 extern void finish_else_clause			(tree);
 extern void finish_if_stmt			(tree);
 extern tree begin_while_stmt			(void);
-extern void finish_while_stmt_cond		(tree, tree);
+extern void finish_while_stmt_cond		(tree, tree, bool);
 extern void finish_while_stmt			(tree);
 extern tree begin_do_stmt			(void);
 extern void finish_do_body			(tree);
-extern void finish_do_stmt			(tree, tree);
+extern void finish_do_stmt			(tree, tree, bool);
 extern tree finish_return_stmt			(tree);
 extern tree begin_for_scope			(tree *);
 extern tree begin_for_stmt			(tree, tree);
 extern void finish_for_init_stmt		(tree);
-extern void finish_for_cond			(tree, tree);
+extern void finish_for_cond			(tree, tree, bool);
 extern void finish_for_expr			(tree, tree);
 extern void finish_for_stmt			(tree);
 extern tree begin_range_for_stmt		(tree, tree);
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 78ea986..bfd9152 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -3667,7 +3667,7 @@  build_vec_init (tree base, tree maxindex, tree init,
       finish_for_init_stmt (for_stmt);
       finish_for_cond (build2 (NE_EXPR, boolean_type_node, iterator,
 			       build_int_cst (TREE_TYPE (iterator), -1)),
-		       for_stmt);
+		       for_stmt, false);
       elt_init = cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0,
 				    complain);
       if (elt_init == error_mark_node)
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 8deffc3..dbf2010 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);
 }
@@ -9924,20 +9924,14 @@  cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep)
 
   /* If there's a condition, process it.  */
   if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
-    {
-      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));
-    }
+    condition = cp_parser_condition (parser);
   else if (ivdep)
     {
       cp_parser_error (parser, "missing loop condition in loop with "
 		       "%<GCC ivdep%> pragma");
       condition = error_mark_node;
     }
-  finish_for_cond (condition, stmt);
+  finish_for_cond (condition, stmt, ivdep);
   /* Look for the `;'.  */
   cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
 
@@ -9960,7 +9954,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;
 
@@ -9979,6 +9974,8 @@  cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl)
       if (check_for_bare_parameter_packs (range_expr))
 	range_expr = error_mark_node;
       stmt = begin_range_for_stmt (scope, init);
+      if (ivdep)
+	RANGE_FOR_IVDEP (stmt) = boolean_true_node;
       finish_range_for_decl (stmt, range_decl, range_expr);
       if (!type_dependent_expression_p (range_expr)
 	  /* do_auto_deduction doesn't mess with template init-lists.  */
@@ -9988,7 +9985,7 @@  cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl)
   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 +10076,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,7 +10134,7 @@  cp_convert_range_for (tree statement, tree range_decl, tree range_expr)
 				 begin, ERROR_MARK,
 				 end, ERROR_MARK,
 				 NULL, tf_warning_or_error);
-  finish_for_cond (condition, statement);
+  finish_for_cond (condition, statement, ivdep);
 
   /* The new increment expression.  */
   expression = finish_unary_op_expr (input_location,
@@ -10329,7 +10327,7 @@  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);
-	finish_while_stmt_cond (condition, statement);
+	finish_while_stmt_cond (condition, statement, ivdep);
 	/* Look for the `)'.  */
 	cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
 	/* Parse the dependent statement.  */
@@ -10359,7 +10357,7 @@  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.  */
-	finish_do_stmt (expression, statement);
+	finish_do_stmt (expression, statement, ivdep);
 	/* Look for the `)'.  */
 	cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
 	/* Look for the `;'.  */
@@ -30926,9 +30924,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..1ded97a 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -13318,7 +13318,7 @@  tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
       RECUR (FOR_INIT_STMT (t));
       finish_for_init_stmt (stmt);
       tmp = RECUR (FOR_COND (t));
-      finish_for_cond (tmp, stmt);
+      finish_for_cond (tmp, stmt, false);
       tmp = RECUR (FOR_EXPR (t));
       finish_for_expr (tmp, stmt);
       RECUR (FOR_BODY (t));
@@ -13333,7 +13333,8 @@  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,
+				     RANGE_FOR_IVDEP (t) == boolean_true_node);
         RECUR (RANGE_FOR_BODY (t));
         finish_for_stmt (stmt);
       }
@@ -13342,7 +13343,7 @@  tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
     case WHILE_STMT:
       stmt = begin_while_stmt ();
       tmp = RECUR (WHILE_COND (t));
-      finish_while_stmt_cond (tmp, stmt);
+      finish_while_stmt_cond (tmp, stmt, false);
       RECUR (WHILE_BODY (t));
       finish_while_stmt (stmt);
       break;
@@ -13352,7 +13353,7 @@  tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
       RECUR (DO_BODY (t));
       finish_do_body (stmt);
       tmp = RECUR (DO_COND (t));
-      finish_do_stmt (tmp, stmt);
+      finish_do_stmt (tmp, stmt, false);
       break;
 
     case IF_STMT:
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 052746c..222bb9f 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -726,9 +726,15 @@  begin_while_stmt (void)
    WHILE_STMT.  */
 
 void
-finish_while_stmt_cond (tree cond, tree while_stmt)
+finish_while_stmt_cond (tree cond, tree while_stmt, bool ivdep)
 {
   finish_cond (&WHILE_COND (while_stmt), maybe_convert_cond (cond));
+  if (ivdep && cond != error_mark_node)
+    WHILE_COND (while_stmt) = build2 (ANNOTATE_EXPR,
+				      TREE_TYPE (WHILE_COND (while_stmt)),
+				      WHILE_COND (while_stmt),
+				      build_int_cst (integer_type_node,
+						     annot_expr_ivdep_kind));
   simplify_loop_decl_cond (&WHILE_COND (while_stmt), WHILE_BODY (while_stmt));
 }
 
@@ -771,9 +777,12 @@  finish_do_body (tree do_stmt)
    COND is as indicated.  */
 
 void
-finish_do_stmt (tree cond, tree do_stmt)
+finish_do_stmt (tree cond, tree do_stmt, bool ivdep)
 {
   cond = maybe_convert_cond (cond);
+  if (ivdep && cond != error_mark_node)
+    cond = build2 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+		   build_int_cst (integer_type_node, annot_expr_ivdep_kind));
   DO_COND (do_stmt) = cond;
 }
 
@@ -876,9 +885,15 @@  finish_for_init_stmt (tree for_stmt)
    FOR_STMT.  */
 
 void
-finish_for_cond (tree cond, tree for_stmt)
+finish_for_cond (tree cond, tree for_stmt, bool ivdep)
 {
   finish_cond (&FOR_COND (for_stmt), maybe_convert_cond (cond));
+  if (ivdep && cond != error_mark_node)
+    FOR_COND (for_stmt) = build2 (ANNOTATE_EXPR,
+				  TREE_TYPE (FOR_COND (for_stmt)),
+				  FOR_COND (for_stmt),
+				  build_int_cst (integer_type_node,
+						 annot_expr_ivdep_kind));
   simplify_loop_decl_cond (&FOR_COND (for_stmt), FOR_BODY (for_stmt));
 }
 
@@ -950,7 +965,7 @@  begin_range_for_stmt (tree scope, tree init)
   tree r;
 
   r = build_stmt (input_location, RANGE_FOR_STMT,
-		  NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE);
+		  NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE);
 
   if (scope == NULL_TREE)
     {
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/g++.dg/vect/pr33426-ivdep-4.cc b/gcc/testsuite/g++.dg/vect/pr33426-ivdep-4.cc
new file mode 100644
index 0000000..cf8a2e5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/vect/pr33426-ivdep-4.cc
@@ -0,0 +1,25 @@ 
+/* { 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.  */
+
+#include <vector>
+
+template<class T, class T2>
+void Loop(T *b, T2 c) {
+#pragma GCC ivdep
+  for (auto &i : *b) {
+    i *= *c;
+  }
+}
+
+void foo(std::vector<int> *ar, int *b) {
+ Loop<std::vector<int>, int*>(ar, b);
+}
+
+/* { dg-message "loop vectorized" "" { target *-*-* } 0 } */
+/* FIXME:     dg-bogus " version" "" { target *-*-* } 0  */
+/* FIXME:     dg-bogus " alias" "" { target *-*-* } 0  */
+/* { dg-final { cleanup-tree-dump "vect" } } */
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index cf8200a..d705657 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -307,7 +307,8 @@  replace_loop_annotate ()
       if ((annot_expr_kind) tree_low_cst (gimple_call_arg (stmt, 1), 0)
 	  != annot_expr_ivdep_kind)
 	continue;
-      warning (0, "ignoring %<GCC ivdep%> annotation");
+      warning_at (gimple_location (stmt), 0, "ignoring %<GCC ivdep%> "
+		  "annotation");
       stmt = gimple_build_assign (gimple_call_lhs (stmt),
 				  gimple_call_arg (stmt, 0));
       gsi_replace (&gsi, stmt, true);