Dear all,

the attached patch adds Fortran support for the following pragmas
(loop annotations): IVDEP (ignore vector dependencies), VECTOR, and
NOVECTOR.  Furthermore, it downgrades unsupported directives from
error to warning (by default, it stays an error with -pedantic),
thus fixing the PR.

It has no effect on existing code (thus regtested cleanly on
x86_64-pc-linux-gnu), but gives users an option for fine-grained
control of optimization.  The above pragmas are supported by other
compilers (with different sentinels, e.g. !DIR$ for Intel, Cray,
sometimes with slightly different keywords).

OK for trunk, and backport to 9?

Thanks,
Harald


2019-08-26  Harald Anlauf  <anl...@gmx.de>

        PR fortran/91496
        * gfortran.h: Extend struct gfc_iterator for loop annotations.
        * array.c (gfc_copy_iterator): Copy loop annotations by IVDEP,
        VECTOR, and NOVECTOR pragmas.
        * decl.c (gfc_match_gcc_ivdep, gfc_match_gcc_vector)
        (gfc_match_gcc_novector): New matcher functions handling IVDEP,
        VECTOR, and NOVECTOR pragmas.
        * match.h: Declare prototypes of matcher functions handling IVDEP,
        VECTOR, and NOVECTOR pragmas.
        * parse.c (decode_gcc_attribute, parse_do_block)
        (parse_executable): Decode IVDEP, VECTOR, and NOVECTOR pragmas;
        emit warning for unrecognized pragmas instead of error.
        * trans-stmt.c (gfc_trans_simple_do, gfc_trans_do): Add code to
        emit annotations for IVDEP, VECTOR, and NOVECTOR pragmas.
        * gfortran.texi: Document IVDEP, VECTOR, and NOVECTOR pragmas.

2019-08-26  Harald Anlauf  <anl...@gmx.de>

        PR fortran/91496
        * gfortran.dg/pr91496.f90: New testcase.

Index: gcc/fortran/array.c
===================================================================
--- gcc/fortran/array.c (revision 274933)
+++ gcc/fortran/array.c (working copy)
@@ -2185,6 +2185,9 @@
   dest->end = gfc_copy_expr (src->end);
   dest->step = gfc_copy_expr (src->step);
   dest->unroll = src->unroll;
+  dest->ivdep = src->ivdep;
+  dest->vector = src->vector;
+  dest->novector = src->novector;

   return dest;
 }
Index: gcc/fortran/decl.c
===================================================================
--- gcc/fortran/decl.c  (revision 274933)
+++ gcc/fortran/decl.c  (working copy)
@@ -99,6 +99,11 @@
 /* Set upon parsing a !GCC$ unroll n directive for use in the next loop.  */
 int directive_unroll = -1;

+/* Set upon parsing supported !GCC$ pragmas for use in the next loop.  */
+bool directive_ivdep = false;
+bool directive_vector = false;
+bool directive_novector = false;
+
 /* Map of middle-end built-ins that should be vectorized.  */
 hash_map<nofree_string_hash, int> *gfc_vectorized_builtins;

@@ -11528,3 +11533,57 @@

   return MATCH_YES;
 }
+
+/* Match an !GCC$ IVDEP statement.
+   When we come here, we have already matched the !GCC$ IVDEP string.  */
+
+match
+gfc_match_gcc_ivdep (void)
+{
+  int value;
+
+  if (gfc_match_eos () == MATCH_YES)
+    {
+      directive_ivdep = true;
+      return MATCH_YES;
+    }
+
+  gfc_error ("Syntax error in !GCC$ IVDEP directive at %C");
+  return MATCH_ERROR;
+}
+
+/* Match an !GCC$ VECTOR statement.
+   When we come here, we have already matched the !GCC$ VECTOR string.  */
+
+match
+gfc_match_gcc_vector (void)
+{
+  int value;
+
+  if (gfc_match_eos () == MATCH_YES)
+    {
+      directive_vector = true;
+      return MATCH_YES;
+    }
+
+  gfc_error ("Syntax error in !GCC$ VECTOR directive at %C");
+  return MATCH_ERROR;
+}
+
+/* Match an !GCC$ NOVECTOR statement.
+   When we come here, we have already matched the !GCC$ NOVECTOR string.  */
+
+match
+gfc_match_gcc_novector (void)
+{
+  int value;
+
+  if (gfc_match_eos () == MATCH_YES)
+    {
+      directive_novector = true;
+      return MATCH_YES;
+    }
+
+  gfc_error ("Syntax error in !GCC$ NOVECTOR directive at %C");
+  return MATCH_ERROR;
+}
Index: gcc/fortran/gfortran.h
===================================================================
--- gcc/fortran/gfortran.h      (revision 274933)
+++ gcc/fortran/gfortran.h      (working copy)
@@ -2418,6 +2418,9 @@
 {
   gfc_expr *var, *start, *end, *step;
   unsigned short unroll;
+  bool ivdep;
+  bool vector;
+  bool novector;
 }
 gfc_iterator;

@@ -2794,6 +2797,9 @@
 bool gfc_in_match_data (void);
 match gfc_match_char_spec (gfc_typespec *);
 extern int directive_unroll;
+extern bool directive_ivdep;
+extern bool directive_vector;
+extern bool directive_novector;

 /* SIMD clause enum.  */
 enum gfc_simd_clause
Index: gcc/fortran/gfortran.texi
===================================================================
--- gcc/fortran/gfortran.texi   (revision 274933)
+++ gcc/fortran/gfortran.texi   (working copy)
@@ -3559,6 +3559,9 @@
 * ATTRIBUTES directive::
 * UNROLL directive::
 * BUILTIN directive::
+* IVDEP directive::
+* VECTOR directive::
+* NOVECTOR directive::
 @end menu

 @node ATTRIBUTES directive
@@ -3670,6 +3673,52 @@
 The purpose of the directive is to provide an API among the GCC compiler and
 the GNU C Library which would define vector implementations of math routines.

+
+@node IVDEP directive
+@subsection IVDEP directive
+
+The syntax of the directive is
+
+@code{!GCC$ ivdep}
+
+This directive tells the compiler to ignore vector dependencies in the
+following loop.  It must be placed immediately before a @code{DO} loop
+and applies only to the loop that follows.
+
+Sometimes the compiler may not have sufficient information to decide
+whether a particular loop is vectorizable due to potential
+dependencies between iterations.  The purpose of the directive is to
+tell the compiler that vectorization is safe.
+
+This directive is intended for annotation of existing code.  For new
+code it is recommended to consider OpenMP SIMD directives as potential
+alternative.
+
+
+@node VECTOR directive
+@subsection VECTOR directive
+
+The syntax of the directive is
+
+@code{!GCC$ vector}
+
+This directive tells the compiler to vectorize the following loop.  It
+must be placed immediately before a @code{DO} loop and applies only to
+the loop that follows.
+
+
+@node NOVECTOR directive
+@subsection NOVECTOR directive
+
+The syntax of the directive is
+
+@code{!GCC$ novector}
+
+This directive tells the compiler to not vectorize the following loop.
+It must be placed immediately before a @code{DO} loop and applies only
+to the loop that follows.
+
+
 @node Non-Fortran Main Program
 @section Non-Fortran Main Program

Index: gcc/fortran/match.h
===================================================================
--- gcc/fortran/match.h (revision 274933)
+++ gcc/fortran/match.h (working copy)
@@ -246,8 +246,11 @@
 match gfc_match_dimension (void);
 match gfc_match_external (void);
 match gfc_match_gcc_attributes (void);
+match gfc_match_gcc_builtin (void);
+match gfc_match_gcc_ivdep (void);
+match gfc_match_gcc_novector (void);
 match gfc_match_gcc_unroll (void);
-match gfc_match_gcc_builtin (void);
+match gfc_match_gcc_vector (void);
 match gfc_match_import (void);
 match gfc_match_intent (void);
 match gfc_match_intrinsic (void);
Index: gcc/fortran/parse.c
===================================================================
--- gcc/fortran/parse.c (revision 274933)
+++ gcc/fortran/parse.c (working copy)
@@ -1079,12 +1079,20 @@
   match ("attributes", gfc_match_gcc_attributes, ST_ATTR_DECL);
   match ("unroll", gfc_match_gcc_unroll, ST_NONE);
   match ("builtin", gfc_match_gcc_builtin, ST_NONE);
+  match ("ivdep", gfc_match_gcc_ivdep, ST_NONE);
+  match ("vector", gfc_match_gcc_vector, ST_NONE);
+  match ("novector", gfc_match_gcc_novector, ST_NONE);

   /* All else has failed, so give up.  See if any of the matchers has
      stored an error message of some sort.  */

   if (!gfc_error_check ())
-    gfc_error_now ("Unclassifiable GCC directive at %C");
+    {
+      if (pedantic)
+       gfc_error_now ("Unclassifiable GCC directive at %C");
+      else
+       gfc_warning_now (0, "Unclassifiable GCC directive at %C, ignored");
+    }

   reject_statement ();

@@ -4672,6 +4680,21 @@
          new_st.ext.iterator->unroll = directive_unroll;
          directive_unroll = -1;
        }
+      if (directive_ivdep)
+       {
+         new_st.ext.iterator->ivdep = directive_ivdep;
+         directive_ivdep = false;
+       }
+      if (directive_vector)
+       {
+         new_st.ext.iterator->vector = directive_vector;
+         directive_vector = false;
+       }
+      if (directive_novector)
+       {
+         new_st.ext.iterator->novector = directive_novector;
+         directive_novector = false;
+       }
     }
   else
     stree = NULL;
@@ -5433,6 +5456,15 @@
       if (directive_unroll != -1)
        gfc_error ("%<GCC unroll%> directive does not commence a loop at %C");

+      if (directive_ivdep)
+       gfc_error ("%<GCC ivdep%> directive does not commence a loop at %C");
+
+      if (directive_vector)
+       gfc_error ("%<GCC vector%> directive does not commence a loop at %C");
+
+      if (directive_novector)
+       gfc_error ("%<GCC novector%> directive does not commence a loop at %C");
+
       st = next_statement ();
     }
 }
Index: gcc/fortran/trans-stmt.c
===================================================================
--- gcc/fortran/trans-stmt.c    (revision 274933)
+++ gcc/fortran/trans-stmt.c    (working copy)
@@ -2173,6 +2173,19 @@
                build_int_cst (integer_type_node, annot_expr_unroll_kind),
                build_int_cst (integer_type_node, code->ext.iterator->unroll));

+  if (code->ext.iterator->ivdep && cond != error_mark_node)
+    cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+                  build_int_cst (integer_type_node, annot_expr_ivdep_kind),
+                  integer_zero_node);
+  if (code->ext.iterator->vector && cond != error_mark_node)
+    cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+                  build_int_cst (integer_type_node, annot_expr_vector_kind),
+                  integer_zero_node);
+  if (code->ext.iterator->novector && cond != error_mark_node)
+    cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+                  build_int_cst (integer_type_node, annot_expr_no_vector_kind),
+                  integer_zero_node);
+
   /* The loop exit.  */
   tmp = fold_build1_loc (loc, GOTO_EXPR, void_type_node, exit_label);
   TREE_USED (exit_label) = 1;
@@ -2503,6 +2516,20 @@
       = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
                build_int_cst (integer_type_node, annot_expr_unroll_kind),
                build_int_cst (integer_type_node, code->ext.iterator->unroll));
+
+  if (code->ext.iterator->ivdep && cond != error_mark_node)
+    cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+                  build_int_cst (integer_type_node, annot_expr_ivdep_kind),
+                  integer_zero_node);
+  if (code->ext.iterator->vector && cond != error_mark_node)
+    cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+                  build_int_cst (integer_type_node, annot_expr_vector_kind),
+                  integer_zero_node);
+  if (code->ext.iterator->novector && cond != error_mark_node)
+    cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+                  build_int_cst (integer_type_node, annot_expr_no_vector_kind),
+                  integer_zero_node);
+
   tmp = fold_build1_loc (loc, GOTO_EXPR, void_type_node, exit_label);
   tmp = fold_build3_loc (loc, COND_EXPR, void_type_node,
                         cond, tmp, build_empty_stmt (loc));
Index: gcc/testsuite/gfortran.dg/pr91496.f90
===================================================================
--- gcc/testsuite/gfortran.dg/pr91496.f90       (nonexistent)
+++ gcc/testsuite/gfortran.dg/pr91496.f90       (working copy)
@@ -0,0 +1,38 @@
+! { dg-do compile }
+! { dg-options "-fdump-tree-original" }
+!
+subroutine foo (a, b, c, n)
+  implicit none
+  real a(*), b(*), c(*)
+  integer :: i, n
+  external bar
+!DIR$ unroll (4)
+!GCC$ unroll 4
+  do i = 1, n
+     a(i) = b(i) + c(i)
+  end do
+!DIR$ ivdep
+!GCC$ ivdep
+  do i = 1, n
+     a(i) = b(i) + c(i)
+  end do
+!DIR$ vector
+!GCC$ vector
+  do i = 1, n
+     a(i) = b(i) + c(i)
+  end do
+!DIR$ novector
+!GCC$ novector
+  do i = 1, n
+     a(i) = b(i) + c(i)
+  end do
+!GCC$ ivdep
+!GCC$ vector
+  do i = 1, n
+     a(i) = b(i) + c(i)
+  end do
+!DIR$ noinline
+!GCC$ noinline          ! { dg-warning "Unclassifiable GCC directive" }
+  call bar (a)
+end subroutine foo
+! { dg-final { scan-tree-dump-times "ANNOTATE_EXPR" 6 "original" } }

Reply via email to