This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Patch: Add #pragma ivdep support to the ME and C FE


Dear all,

attached is a new version of the patch. Changes:
* "#pragma GCC ivdep" instead of "#pragma ivdep"
* Corrections to the error message in c-parser.c and a test case for it
* New wording in the .texi and examples

I am still not completely happy with the wording – and I am open for suggestions. In the example, I played safe and mention k < -m and k >=m; even if k >= 0 probably works.

I also didn't know how to best state the reason for requiring a condition. (Internal reason: The annotation is attached to the condition - thus, it has to be present. External reason: For vectorization, there shouldn't be a branching in the body of the loop and without a condition in either the "for" header or in its body, one has an endless loop.)

Do you have suggestions for a better wording? If not, is the patch okay for the trunk? Built and regtested (C only). [An all-language bootstrap + regtesting is underway.]


Crossrefs: C review comments: http://gcc.gnu.org/ml/gcc-patches/2013-10/msg00803.html OpenMPv4's "omp simd" wording, see bottom of the email at http://gcc.gnu.org/ml/gcc-patches/2013-10/msg01194.html

Tobias
2013-08-21  Tobias Burnus  <burnus@net-b.de>

	PR other/33426
        * c-pragma.c (init_pragma) Add #pragma ivdep handling.
        * c-pragma.h (pragma_kind): Add PRAGMA_IVDEP.

	PR other/33426
        * c-parser.c (c_parser_pragma, c_parser_for_statement):
        Handle PRAGMA_IVDEP.
        (c_parser_statement_after_labels): Update call.

	PR other/33426
        * cfgloop.c (flow_loops_find): Search for IFN_ANNOTATE
        and set safelen.
        * gimplify.c (gimple_boolify, gimplify_expr): Handle ANNOTATE_EXPR.
        * internal-fn.c (expand_ANNOTATE): New function.
        * internal-fn.def (ANNOTATE): Define as new internal function.
        * tree-core.h (tree_node_kind): Add annot_expr_ivdep_kind.
        (tree_base) Update a comment.
        * tree-pretty-print.c (dump_generic_node): Handle ANNOTATE_EXPR.
        * tree.def (ANNOTATE_EXPR): New DEFTREECODE.
        * tree.h (ANNOTATE_EXPR_ID, SET_ANNOTATE_EXPR_ID): New macros.
	* doc/extend.texi (Pragmas): Document #pragma ivdep.

	PR other/33426
	* testsuite/gcc.dg/ivdep.c: New.
	* testsuite/gcc.dg/vect/vect-ivdep-1.c: New.

diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c
index be5748b..1656000 100644
--- a/gcc/c-family/c-pragma.c
+++ b/gcc/c-family/c-pragma.c
@@ -1362,6 +1362,8 @@ init_pragma (void)
     cpp_register_deferred_pragma (parse_in, "GCC", "pch_preprocess",
 				  PRAGMA_GCC_PCH_PREPROCESS, false, false);
 
+  cpp_register_deferred_pragma (parse_in, "GCC", "ivdep", PRAGMA_IVDEP, false,
+				false);
 #ifdef HANDLE_PRAGMA_PACK_WITH_EXPANSION
   c_register_pragma_with_expansion (0, "pack", handle_pragma_pack);
 #else
diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h
index c421284..705bcb4 100644
--- a/gcc/c-family/c-pragma.h
+++ b/gcc/c-family/c-pragma.h
@@ -53,6 +53,7 @@ typedef enum pragma_kind {
   PRAGMA_OMP_TEAMS,
 
   PRAGMA_GCC_PCH_PREPROCESS,
+  PRAGMA_IVDEP,
 
   PRAGMA_FIRST_EXTERNAL
 } pragma_kind;
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 9b6abe0..c721f8a 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1159,7 +1159,7 @@ 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_for_statement (c_parser *);
+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 *);
 static tree c_parser_asm_goto_operands (c_parser *);
@@ -4580,7 +4580,7 @@ c_parser_statement_after_labels (c_parser *parser)
 	  c_parser_do_statement (parser);
 	  break;
 	case RID_FOR:
-	  c_parser_for_statement (parser);
+	  c_parser_for_statement (parser, false);
 	  break;
 	case RID_GOTO:
 	  c_parser_consume_token (parser);
@@ -5033,7 +5033,7 @@ c_parser_do_statement (c_parser *parser)
 */
 
 static void
-c_parser_for_statement (c_parser *parser)
+c_parser_for_statement (c_parser *parser, bool ivdep)
 {
   tree block, cond, incr, save_break, save_cont, body;
   /* The following are only used when parsing an ObjC foreach statement.  */
@@ -5139,8 +5139,17 @@ c_parser_for_statement (c_parser *parser)
 	{
 	  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
 	    {
-	      c_parser_consume_token (parser);
-	      cond = NULL_TREE;
+	      if (ivdep)
+		{
+		  c_parser_error (parser, "missing loop condition in loop with "
+				  "%<GCC ivdep%> pragma");
+		  cond = error_mark_node;
+		}
+	      else
+		{
+		  c_parser_consume_token (parser);
+		  cond = NULL_TREE;
+		}
 	    }
 	  else
 	    {
@@ -5154,6 +5163,12 @@ c_parser_for_statement (c_parser *parser)
 	      c_parser_skip_until_found (parser, CPP_SEMICOLON,
 					 "expected %<;%>");
 	    }
+	  if (ivdep && cond != error_mark_node)
+	    {
+	      cond = build1 (ANNOTATE_EXPR, TREE_TYPE (cond), cond);
+	      SET_ANNOTATE_EXPR_ID (cond, annot_expr_ivdep_kind);
+	    }
+
 	}
       /* Parse the increment expression (the third expression in a
 	 for-statement).  In the case of a foreach-statement, this is
@@ -9081,6 +9096,16 @@ c_parser_pragma (c_parser *parser, enum pragma_context context)
     case PRAGMA_OMP_DECLARE_REDUCTION:
       c_parser_omp_declare (parser, context);
       return false;
+    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))
+	{
+	  c_parser_error (parser, "for statement expected");
+	  return false;
+	}
+      c_parser_for_statement (parser, true);
+      return false;
 
     case PRAGMA_GCC_PCH_PREPROCESS:
       c_parser_error (parser, "%<#pragma GCC pch_preprocess%> must be first");
diff --git a/gcc/cfgloop.c b/gcc/cfgloop.c
index 3babf77..f17b360 100644
--- a/gcc/cfgloop.c
+++ b/gcc/cfgloop.c
@@ -507,6 +507,35 @@ flow_loops_find (struct loops *loops)
 	      loop->latch = latch;
 	    }
 	}
+      /* Search for ANNOTATE call with annot_expr_ivdep_kind; if found, remove
+	 it and set loop->safelen to INT_MAX.  We assume that the annotation
+	 comes immediately before the condition.  */
+      if (loop->latch && !(loop->latch->flags & BB_RTL))
+	FOR_EACH_EDGE (e, ei, loop->latch->succs)
+	  {
+	    gimple_stmt_iterator gsi = gsi_last_bb (e->dest);
+	    gimple stmt = gsi_stmt (gsi);
+	    if (stmt && gimple_code (stmt) == GIMPLE_COND)
+	      {
+		gsi_prev_nondebug (&gsi);
+		if (gsi_end_p (gsi))
+		  continue;
+		stmt = gsi_stmt (gsi);
+		if (gimple_code (stmt) != GIMPLE_CALL)
+		  continue;
+		if (!gimple_call_internal_p (stmt)
+		    || gimple_call_internal_fn (stmt) != IFN_ANNOTATE)
+		  continue;
+		if ((annot_expr_kind) tree_low_cst (gimple_call_arg (stmt, 1),
+								     0)
+		    != annot_expr_ivdep_kind)
+		  continue;
+		stmt = gimple_build_assign (gimple_call_lhs (stmt),
+					    gimple_call_arg (stmt, 0));
+		gsi_replace (&gsi, stmt, true);
+		loop->safelen = INT_MAX;
+	      }
+	  }
     }
 
   larray.release ();
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 562b676..7623a5e 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -15473,6 +15473,7 @@ for further explanation.
 * Visibility Pragmas::
 * Push/Pop Macro Pragmas::
 * Function Specific Option Pragmas::
+* Loop-Specific Pragmas::
 @end menu
 
 @node ARM Pragmas
@@ -15995,6 +15996,48 @@ The @samp{#pragma GCC reset_options} pragma is not implemented in GCC
 versions earlier than 4.4.
 @end table
 
+@node Loop-Specific Pragmas
+@subsection Loop-Specific Pragmas
+
+@table @code
+@item #pragma GCC ivdep
+@cindex pragma GCC ivdep
+@end table
+
+With this pragma, the programmer asserts that there are no loop-carried
+dependencies which would prevent that consecutive iterations of
+the following loop can be executed concurrently with SIMD
+(single instruction multiple data) instructions.
+
+For example, the compiler can only unconditionally vectorize the following
+loop with the pragma:
+
+@smallexample
+void foo (int n, int *a, int *b, int *c)
+@{
+  int i, j;
+#pragma GCC ivdep
+  for (i = 0; i < n; ++i)
+    a[i] = b[i] + c[i];
+@}
+@end smallexample
+
+@noindent
+In this example, using the @code{restrict} qualifier had the same
+effect. In the following example, that would not be possible. Assume
+@math{k < -m} or @math{k >= m}. Only with the pragma, the compiler knows
+that it can unconditionally vectorize the following loop:
+
+@smallexample
+void ignore_vec_dep (int *a, int k, int c, int m)
+@{
+#pragma GCC ivdep
+  for (int i = 0; i < m; i++)
+    a[i] = a[i + k] * c;
+@}
+@end smallexample
+
+
 @node Unnamed Fields
 @section Unnamed struct/union fields within structs/unions
 @cindex @code{struct}
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 193e017..5c55571 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -3072,6 +3072,16 @@ gimple_boolify (tree expr)
 	TREE_TYPE (expr) = boolean_type_node;
       return expr;
 
+    case ANNOTATE_EXPR:
+      if (ANNOTATE_EXPR_ID (expr) == annot_expr_ivdep_kind)
+	{
+	  TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0));
+	  if (TREE_CODE (type) != BOOLEAN_TYPE)
+	    TREE_TYPE (expr) = boolean_type_node;
+	  return expr;
+	}
+      /* FALLTHRU */
+
     default:
       if (COMPARISON_CLASS_P (expr))
 	{
@@ -7727,6 +7737,22 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 	  ret = gimplify_addr_expr (expr_p, pre_p, post_p);
 	  break;
 
+	case ANNOTATE_EXPR:
+	  {
+	    tree cond = TREE_OPERAND (*expr_p, 0);
+	    tree id = build_int_cst (integer_type_node,
+				     ANNOTATE_EXPR_ID (*expr_p));
+	    tree tmp = create_tmp_var_raw (TREE_TYPE(cond), NULL);
+	    gimplify_arg (&cond, pre_p, EXPR_LOCATION (*expr_p));
+	    gimple call = gimple_build_call_internal (IFN_ANNOTATE, 2,
+						      cond, id);
+	    gimple_call_set_lhs (call, tmp);
+	    gimplify_seq_add_stmt (pre_p, call);
+	    *expr_p = tmp;
+	    ret = GS_ALL_DONE;
+	    break;
+	  }
+
 	case VA_ARG_EXPR:
 	  ret = gimplify_va_arg_expr (expr_p, pre_p, post_p);
 	  break;
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index 983efeb..a22f222 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -109,6 +109,12 @@ expand_STORE_LANES (gimple stmt)
   expand_insn (get_multi_vector_move (type, vec_store_lanes_optab), 2, ops);
 }
 
+static void
+expand_ANNOTATE (gimple stmt ATTRIBUTE_UNUSED)
+{
+  gcc_unreachable ();
+}
+
 /* This should get expanded in adjust_simduid_builtins.  */
 
 static void
diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
index 5427664..0f5cc3c 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -43,3 +43,4 @@ DEF_INTERNAL_FN (STORE_LANES, ECF_CONST | ECF_LEAF)
 DEF_INTERNAL_FN (GOMP_SIMD_LANE, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW)
 DEF_INTERNAL_FN (GOMP_SIMD_VF, ECF_CONST | ECF_LEAF | ECF_NOTHROW)
 DEF_INTERNAL_FN (GOMP_SIMD_LAST_LANE, ECF_CONST | ECF_LEAF | ECF_NOTHROW)
+DEF_INTERNAL_FN (ANNOTATE,  ECF_CONST | ECF_LEAF | ECF_NOTHROW)
diff --git a/gcc/testsuite/gcc.dg/ivdep.c b/gcc/testsuite/gcc.dg/ivdep.c
new file mode 100644
index 0000000..23d51de
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ivdep.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+
+/* PR other/33426 */
+
+void foo(int n, int *a, int *b, int *c, int *d, int *e) {
+  int i, j;
+#pragma GCC ivdep
+  for (i = 0; ; ++i) { /* { dg-error "missing loop condition in loop with 'GCC ivdep' pragma before ';' token" } */
+    a[i] = b[i] + c[i];
+  }
+}
diff --git a/gcc/testsuite/gcc.dg/vect/vect-ivdep-1.c b/gcc/testsuite/gcc.dg/vect/vect-ivdep-1.c
new file mode 100644
index 0000000..8767bb8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-ivdep-1.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_float } */
+/* { dg-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 *d, int *e) {
+  int i, j;
+#pragma GCC ivdep
+  for (i = 0; i < n; ++i) {
+    a[i] = b[i] + c[i];
+  }
+}
+
+/* { 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/tree-core.h b/gcc/tree-core.h
index c7fc84f..eb6d13e 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -647,6 +647,10 @@ enum tree_node_kind {
   all_kinds
 };
 
+enum annot_expr_kind {
+  annot_expr_ivdep_kind
+};
+
 
 /*---------------------------------------------------------------------------
                                 Type definitions
@@ -746,7 +750,8 @@ struct GTY(()) tree_base {
        make better use of the 4-byte sized word.  */
     /* VEC length.  This field is only used with TREE_VEC.  */
     int length;
-    /* SSA version number.  This field is only used with SSA_NAME.  */
+    /* SSA version number or the ID of an ANNOTATE_EXPR.  This field is only
+       used with SSA_NAME and ANNOTATE_EXPR.  */
     unsigned int version;
   } GTY((skip(""))) u;
 };
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index f8a0342..8a63781 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -2094,6 +2094,18 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
       pp_string (buffer, " predictor.");
       break;
 
+    case ANNOTATE_EXPR:
+      pp_string (buffer, "ANNOTATE_EXPR <");
+      switch (ANNOTATE_EXPR_ID (node))
+	{
+	case annot_expr_ivdep_kind:
+	  pp_string (buffer, "ivdep, ");
+	  break;
+	}
+      dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
+      pp_greater (buffer);
+      break;
+
     case RETURN_EXPR:
       pp_string (buffer, "return");
       op0 = TREE_OPERAND (node, 0);
diff --git a/gcc/tree.def b/gcc/tree.def
index 88c850a..6791a3b 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -1261,6 +1261,12 @@ DEFTREECODE (OPTIMIZATION_NODE, "optimization_node", tcc_exceptional, 0)
 /* TARGET_OPTION_NODE.  Node to store the target specific options.  */
 DEFTREECODE (TARGET_OPTION_NODE, "target_option_node", tcc_exceptional, 0)
 
+/* ANNOTATE_EXPR.
+   Operand 0 is the expression.  ....
+   Operand 1 is the annotation id, FIXME */
+DEFTREECODE (ANNOTATE_EXPR, "annotate_expr", tcc_expression, 1)
+
+
 /*
 Local variables:
 mode:c
diff --git a/gcc/tree.h b/gcc/tree.h
index 2f4514d..080927a 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -591,6 +591,11 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
 #define PREDICT_EXPR_PREDICTOR(NODE) \
   ((enum br_predictor)tree_low_cst (TREE_OPERAND (PREDICT_EXPR_CHECK (NODE), 0), 0))
 
+#define ANNOTATE_EXPR_ID(NODE) \
+  ((enum annot_expr_kind) ANNOTATE_EXPR_CHECK (NODE)->base.u.version)
+#define SET_ANNOTATE_EXPR_ID(NODE, ID) \
+  (ANNOTATE_EXPR_CHECK (NODE)->base.u.version = (unsigned int) (ID))
+
 /* In a VAR_DECL, nonzero means allocate static storage.
    In a FUNCTION_DECL, nonzero if function has been defined.
    In a CONSTRUCTOR, nonzero means allocate static storage.  */

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]